How To - Add custom metric to Backtest Tradelist Report

The Backtest Trade list displays some good info such as the symbol, Trade, Date, Price, etc.

Is there an easy way to add a custom metric (aka custom column)? For example, I want to include a calculation such as Proceeds = (close * Shares) in my formula, and then have the trade list report display the total proceeds for each sale.

1 Like

Hi,

The knowledge base has an interesting post about adding custom metrics to trade list: http://www.amibroker.com/kb/2014/11/20/how-to-show-indicator-values-in-backtest-trade-list/

I don’t know if this is exactly what you’re trying to achieve but it can be something like this:

SetCustomBacktestProc( "" );

if ( Status( "action" ) == actionPortfolio )
{
    bo = GetBacktesterObject();
    // run default backtest procedure without generating the trade list
    bo.Backtest( True );

    // iterate through closed trades
    for ( trade = bo.GetFirstTrade( ); trade; trade = bo.GetNextTrade( ) )
    {
        
        
        trade.AddCustomMetric( "proceeds", trade.Shares*trade.ExitPrice );
    }

    // iterate through open positions
    for ( trade = bo.GetFirstOpenPos( ); trade; trade = bo.GetNextOpenPos( ) )
    {
       
        trade.AddCustomMetric( "proceeds", trade.Shares*trade.ExitPrice );
    }

    // generate trade list
    bo.ListTrades( );
}

// your trading system here
Buy = Cross( MACD(), Signal() );
Sell = Cross( Signal(), MACD() );
3 Likes

pmxgs,

Thank you for the solution. It works perfectly! I now see Proceeds in my trade list.
I also want to use other metrics in my trade list. My code snippet below illustrates that I am accumulating an indicatorCount based on how many indicators trigger a Buy signal. Any idea on how to integrate this metric so I can display the IndicatorCount’s value? Thanks again!

IndicatorCount = 0;
Buy1 = Cross( MACD(), Signal() );
IndicatorCount = IndicatorCount + IIF(Buy1,1,0) ;

Buy2 = Cross(Price,MA(P,20))
IndicatorCount = IndicatorCount + IIF(Buy2,1,0) ;

Buy = Buy1 AND Buy2;

hi
i dont think you have to use cross(), for example how many crosses can be On the same bar?
just use simple logic

Ind1= rsi()<50;
Ind2= cci()>0; 
ind3 = .....;

// sum of contitions
IndicatorCount = ind1+ind2+ind3+……+ind10;

// buy if Sum is more than 6 positive 
buy = IndicatorCount > 6;
2 Likes

Thank you PanoS. Yes, I like your code snippet becasue it is simpler than mine. Thanks for the improvement. I still want to get the Indicator Count onto my Backtest Trade report (I have other metrics as well, but once I solve the indicator count, my other metrics will be easy to produce). Again, thanks!

[quote=“SwingTradeMonkey, post:1, topic:1122”]I want to include a calculation such as Proceeds = (close * Shares)
[/quote]

It is ALL (as always) in the Users’ Guide
http://www.amibroker.com/guide/a_custommetrics.html

Scroll down to Example 3

In the Example 3 you can just add single line

 trade.AddCustomMetric("Proceeds", trade.ExitPrice * trade.Shares ); 

right after R-Multiple custom metric.

Hi,

if you need to add indicator metrics you can replicate the example provided here. Just replace ATR in the example by your IndicatorCount:
http://www.amibroker.com/kb/2014/11/20/how-to-show-indicator-values-in-backtest-trade-list/

1 Like

Tomasz,
Thank you for pointing out http://www.amibroker.com/guide/a_custommetrics.html
I think it would be helpful for the user guide to reference http://www.amibroker.com/kb/2014/11/20/how-to-show-indicator-values-in-backtest-trade-list/2 because this example, as pmxgs points out, shows how to use static variables and capture custom metrics during the backtest phase.

pmxgs,

Your suggestions worked perfectly.

It took me a while to read through the Portfolio Backtester Interface Reference Guide and to understand that Static Variables (StaticVarSet()) contain an internal timestamp synchronizing the value of the static variable to the actual trade entry date.

Further, an unexpected but welcome shift to OOP Backtester model caught me a bit off guard. The advice, example and the link you provided were very helpful. I am now able to save my custom metrics captured during the backtest and display them in my trade report. I recommend anyone trying to figure out how to do this carefully read the Portfolio Backtester Inteface Reference Guide (Its in the User Guide), and reference the link you provided which I will repeat here: http://www.amibroker.com/guide/a_custommetrics.html.

Again, thank you!

2 Likes

Similar question here

I want to generate a report which shows how many of the trades had a loss greater than my position risk
I generated the custom back test for a fixed value. in the example below i used 200


        // check for number greater than stop loss
       
        if (trade.GetProfit() < -200) 
        {
        if( trade.IsLong() )
                maxlossCountLong++;
            else
                maxlossCountShort++;
                }
    }

   // add the custom metric
    bo.AddCustomMetric( "Stoploss trades", stoplossCountLong + stoplossCountShort, 
                         stoplossCountLong, stoplossCountShort, 0 );
     bo.AddCustomMetric( "nBar trades", nbarCountLong + nbarCountShort, 
                         nbarCountLong, nbarCountShort, 0 );                    
	bo.AddCustomMetric( "Normal trades", normalCountLong + normalCountShort, 
                         normalCountLong, normalCountShort, 0 ); 
    bo.AddCustomMetric( "Max loss trades", maxlossCountLong + maxlossCountShort, 
                         maxlossCountLong, maxlossCountShort, 0 );                      
                         
}

this works fine.
I want to now do this report based on a variable of position size which is determined based on account value

in the main section i set the position size here:



// risk % of entire equity on single trade
PositionRisk = 1;

// position size calculation
symbol = Name();  
PctSize =  PositionRisk * buylimitprice / range;
StaticVarSet( symbol + "PctSize", PctSize );  

SetPositionSize( Min(pctsize,20), spspercentofequity );

then in the custom backtest i try to call the variable and use it:


        // check for number greater than stop loss
        PctSize = StaticVarGet( symbol + "PctSize"  );  
        if (trade.GetProfit() < Pctsize) 
        {
        if( trade.IsLong() )
                maxlossCountLong++;
            else
                maxlossCountShort++;
                }
    }

   // add the custom metric
    bo.AddCustomMetric( "Stoploss trades", stoplossCountLong + stoplossCountShort, 
                         stoplossCountLong, stoplossCountShort, 0 );
     bo.AddCustomMetric( "nBar trades", nbarCountLong + nbarCountShort, 
                         nbarCountLong, nbarCountShort, 0 );                    
	bo.AddCustomMetric( "Normal trades", normalCountLong + normalCountShort, 
                         normalCountLong, normalCountShort, 0 ); 
    bo.AddCustomMetric( "Max loss trades", maxlossCountLong + maxlossCountShort, 
                         maxlossCountLong, maxlossCountShort, 0 );          

i get an error during the back test and i am at the limit of my coding ability!

anyone able to help?

forgot to include this

// iterate through closed trades
    for( trade = bo.GetFirstTrade(); trade; trade = bo.GetNextTrade() )
    {
        symbol = trade.Symbol ;  

Hi Guys

In my backtest list in the Analysis window i want to add a custom column that prints the Low price of the entry bar.

I have tried adapting some of the above code but without any luck, i was wondering if this is possible?

Thanks

Hi Roller

In the regular part of the code, you’ll need to store the low array for all the symbols processed in static variables, then retrieve it in the trade loop of the CBT. Then you can Lookup the value in the array when the trade entry happened.

The (untested) code below should get you on your way.

// In regular code
StaticVarSet("Low" + Name(), Low);

// In High Level CBT
for( trade = bo.GetFirstTrade(); trade; trade = bo.GetNextTrade() )
{
	LowArray = StaticVarGet("Low" + trade.Symbol);
	LowAtEntry = Lookup(LowArray, trade.EntryDateTime);
	trade.AddCustomMetric("Low At Entry", LowAtEntry);
}
1 Like

@roller,

Have you not seen the link to example above given by pmxgs?
If so then what is it that you have tried to adapt (as you have said) that has worked out without any luck?
If you don’t show then readers can not give hints to what may be wrong.

Here is example to your issue.

// 2nd phase (CBT) ##################
SetCustomBacktestProc( "" );
if ( Status( "action" ) == actionPortfolio ) {
    bo = GetBacktesterObject();
    bo.Backtest( 1 );

    // iterating closed trades
    for ( trade = bo.GetFirstTrade( ); trade; trade = bo.GetNextTrade( ) ) {
        _LOW = StaticVarGet( trade.Symbol + "_LOW" );// retrieving set symbol's var of 1st phase
        trade.AddCustomMetric( "Low@Entry", Lookup( _LOW, trade.EntryDateTime ), dec = 2 );
    }
    
    // iterating open positions
    for ( trade = bo.GetFirstOpenPos( ); trade; trade = bo.GetNextOpenPos( ) ) {
        _LOW = StaticVarGet( trade.Symbol + "_LOW" );// retrieving set symbol's var of 1st phase
        trade.AddCustomMetric( "Low@Entry", Lookup( _LOW, trade.EntryDateTime ), dec = 2 );
    }

    bo.ListTrades();
}

//1st Phase  ##################
StaticVarSet( Name() + "_LOW", Low );

// your trading system here 
Buy = Cross( MACD(), Signal() ); 
Sell = Cross( Signal(), MACD() );

Short = Cover = 0;
1 Like

Thanks for that works well. The StaticVarSet function was what i needed.

Next time will post code with the question,

Cheers guys

Hi

i have been printing the bars since last equity high in the backtest report with no issues. Now i want to print the days since equity high. The code below is where im at currently.

Basically it is printing days since 1900.

StaticVarSet("Low" + Name(), Low); // In regular code

eq = Foreign("~~~EQUITY", "C");
cash = Foreign("~~~EQUITY", "L");
dr = eq - Highest(eq);
bslh = HighestBars(eq);
//---------------------------------------------------------------------------------
lh = StaticVarSet("High", bslh == DaysSince1900());
 // trying to set lh to the day when equity was highest


//-------------------------------------------------------------------------------------

SetCustomBacktestProc( "" );

if ( Status( "action" ) == actionPortfolio )
{
    bo = GetBacktesterObject();
    // run default backtest procedure without generating the trade list
    bo.Backtest( True );

    // iterate through closed trades
	for( trade = bo.GetFirstTrade(); trade; trade = bo.GetNextTrade() )
	{
	LowArray = StaticVarGet("Low" + trade.Symbol);
	LowAtEntry = Lookup(LowArray, trade.EntryDateTime);
	trade.AddCustomMetric("Low At Entry", LowAtEntry);
	bs = Lookup(bslh,trade.ExitDateTime);
	trade.AddCustomMetric("Bslh",bs);
	dayshigh = Lookup(DaysSince1900()-lh,trade.ExitDateTime); // trying  to calculate days since eq high
	trade.AddCustomMetric("Days since eq High",dayshigh);
	}

    // generate trade list
    bo.ListTrades( );

}

Thanks

Hi, I’m trying to print some values in the Backtest Trade list using the code snipped in the link http://www.amibroker.com/kb/2014/11/20/how-to-show-indicator-values-in-backtest-trade-list/. I don’t know why but the first line
SetCustomBacktestProc( “” );
gives me the error:
“Syntax error, unexpected $end, expecting ‘)’ or ‘,’ (Ln:1, Col:23).”

So, I’m using instead
SetOption(“UseCustomBacktestProc”, True );
which as far as I know should be synonymous with the previous one…

After making this change, I get an error on the third line:
“if ( Status( “action” ) == actionPortfolio )”.
The error message is:
“Syntax error, unexpected $end, expecting ‘)’ or ‘,’ (Ln:3, Col:3).”

Anyone has any idea of what’s happening and what can I do to make the code work properly?

I don’t know if this is relevant, buy I’m using the Trial version of Amibroker.

Thanks.

I already solved the problem… It was the Double quotation problem! I used copy and paste and this spoiled everything. I should have suspected, because the keyworks weren’t bold…

Hi.

I have some trouble with AddCustomMetric… If I use bo.Backtest( false) the Analysis backtest shows duplicated trade line results. If I use bo.Backtest( true ) it shows no results at all! Is there any way to show only the trade lines affected by AddCustomMetric, i.e., with additional columns?

Thanks.

In order to display trade level custom metrics in the trade list, use Backtest(True) and then ListTrades() at the end.

if (Status("action") == actionPortfolio)
{
	bo = GetBacktesterObject();
	bo.backtest(True);  
	// Your trade level custom metric processing here
	bo.ListTrades();
}

Reference: the bottom of this page: https://www.amibroker.com/guide/a_custommetrics.html

1 Like