amibroker

HomeKnowledge Base

Per-symbol profit/loss in a portfolio backtest

Backtesting engine in AmiBroker allows to add custom metrics to the report, both in the summary report and in the trade list. This is possible with Custom Backtester Interface, which allows to modify the execution of portfolio-level phase of the test and (among many other features) adjust report generation.

The example presented below shows how to retrieve individual profit/loss figures for each traded symbol in a portfolio test and add the results as custom metrics to the report. The code performs backtest, then iterates through the list of trades and stores each symbol profit in separate variables. Variables are created with VarSet function, which allows to build variable names dynamically, based on the symbol name. There are 2 variables generated per symbol, one holding profit for long trades and one for short trades. In the last part the code reads the created variables and adds input into the backtest report.

function ProcessTradetrade )
{
  global 
tradedSymbols;
  
symbol trade.Symbol;
  
//
  
if( ! StrFindtradedSymbols"," symbol "," ) )
  {
    
tradedSymbols += symbol ",";
  }
  
//
  // HINT: you may replace it with GetPercentProfit if you wish
  
profit trade.GetProfit(); 
  
//
  
if( trade.IsLong() )
  {
      
varname "long_" symbol;
      
VarSetvarnameNzVarGetvarname ) ) + profit );
  }
  else
  {
      
varname "short_" symbol;
      
VarSetvarnameNzVarGetvarname ) ) + profit );
  }

//  
SetCustomBacktestProc"" );
//
/* Now custom-backtest procedure follows */
//
if ( Status"action" ) == actionPortfolio )
{
    
bo GetBacktesterObject();
    
//
    
bo.Backtest(); // run default backtest procedure
    //
    
tradedSymbols ",";
    
//
    //iterate through closed trades
    
for ( trade bo.GetFirstTrade( ); tradetrade bo.GetNextTrade( ) )
    {
        
ProcessTradetrade );
    }
    
//
    //iterate through open positions
    
for ( trade bo.GetFirstOpenPos( ); tradetrade bo.GetNextOpenPos( ) )
    {
        
ProcessTradetrade );
    }
    
//
    //iterate through the list of traded symbols and generate custom metrics
    
for ( 1; ( sym StrExtracttradedSymbols) ) != ""i++ )
    {
        
longprofit VarGet"long_" sym );
        
shortprofit VarGet"short_" sym );
        
allprofit Nzlongprofit ) + Nzshortprofit );
        
// metric uses 2 decimal points and
        // 3 (calculate sum) as a "combine method" for walk forward out-of-sample
        
bo.AddCustomMetric"Profit for " symallprofitlongprofitshortprofit2);
    }
}
//
SetOption"MaxOpenPositions"10 );
//
Buy CrossMACD(), Signal() );
Sell CrossSignal(), MACD() );
Short Sell;
Cover Buy;
SetPositionSize10spsPercentOfEquity ) ; 

Once we run the Backtest, we will get the following output in the report, showing individual profit/loss figures for each symbol in test.

Per-symbol profit

If you prefer percent profits instead of dollar profits, just replace GetProfit() call with GetPercentProfit().

Comments are closed.