October 13, 2014
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 ProcessTrade( trade )
{
global tradedSymbols;
symbol = trade.Symbol;
//
if( ! StrFind( tradedSymbols, "," + symbol + "," ) )
{
tradedSymbols += symbol + ",";
}
//
// HINT: you may replace it with GetPercentProfit if you wish
profit = trade.GetProfit();
//
if( trade.IsLong() )
{
varname = "long_" + symbol;
VarSet( varname, Nz( VarGet( varname ) ) + profit );
}
else
{
varname = "short_" + symbol;
VarSet( varname, Nz( VarGet( varname ) ) + 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( ); trade; trade = bo.GetNextTrade( ) )
{
ProcessTrade( trade );
}
//
//iterate through open positions
for ( trade = bo.GetFirstOpenPos( ); trade; trade = bo.GetNextOpenPos( ) )
{
ProcessTrade( trade );
}
//
//iterate through the list of traded symbols and generate custom metrics
for ( i = 1; ( sym = StrExtract( tradedSymbols, i ) ) != ""; i++ )
{
longprofit = VarGet( "long_" + sym );
shortprofit = VarGet( "short_" + sym );
allprofit = Nz( longprofit ) + Nz( shortprofit );
// metric uses 2 decimal points and
// 3 (calculate sum) as a "combine method" for walk forward out-of-sample
bo.AddCustomMetric( "Profit for " + sym, allprofit, longprofit, shortprofit, 2, 3 );
}
}
//
SetOption( "MaxOpenPositions", 10 );
//
Buy = Cross( MACD(), Signal() );
Sell = Cross( Signal(), MACD() );
Short = Sell;
Cover = Buy;
SetPositionSize( 10, spsPercentOfEquity )
Once we run the Backtest, we will get the following output in the report, showing individual profit/loss figures for each symbol in test.
If you prefer percent profits instead of dollar profits, just replace GetProfit() call with GetPercentProfit().
Filed by Tomasz Janeczko at 5:12 pm under Custom Backtest
Comments Off on Per-symbol profit/loss in a portfolio backtest