{"id":552,"date":"2014-10-13T17:12:16","date_gmt":"2014-10-13T22:12:16","guid":{"rendered":"http:\/\/www.amibroker.com\/kb\/?p=552"},"modified":"2014-12-04T16:07:00","modified_gmt":"2014-12-04T21:07:00","slug":"per-symbol-profitloss-in-a-portfolio-backtest","status":"publish","type":"post","link":"https:\/\/www.amibroker.com\/wordpress\/kb\/2014\/10\/13\/per-symbol-profitloss-in-a-portfolio-backtest\/","title":{"rendered":"Per-symbol profit\/loss in a portfolio backtest"},"content":{"rendered":"

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.<\/p>

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.<\/p><\/span>function <\/span>ProcessTrade<\/span>( <\/span>trade <\/span>)
{
  global <\/span>tradedSymbols<\/span>;
  <\/span>symbol <\/span>= <\/span>trade<\/span>.<\/span>Symbol<\/span>;
  <\/span>\/\/
  <\/span>if( ! <\/span>StrFind<\/span>( <\/span>tradedSymbols<\/span>, <\/span>"," <\/span>+ <\/span>symbol <\/span>+ <\/span>"," <\/span>) )
  {
    <\/span>tradedSymbols <\/span>+= <\/span>symbol <\/span>+ <\/span>","<\/span>;
  }
  <\/span>\/\/
  \/\/ HINT: you may replace it with GetPercentProfit if you wish
  <\/span>profit <\/span>= <\/span>trade<\/span>.<\/span>GetProfit<\/span>();
  <\/span>\/\/
  <\/span>if( <\/span>trade<\/span>.<\/span>IsLong<\/span>() )
  {
      <\/span>varname <\/span>= <\/span>"long_" <\/span>+ <\/span>symbol<\/span>;
      <\/span>VarSet<\/span>( <\/span>varname<\/span>, <\/span>Nz<\/span>( <\/span>VarGet<\/span>( <\/span>varname <\/span>) ) + <\/span>profit <\/span>);
  }
  else
  {
      <\/span>varname <\/span>= <\/span>"short_" <\/span>+ <\/span>symbol<\/span>;
      <\/span>VarSet<\/span>( <\/span>varname<\/span>, <\/span>Nz<\/span>( <\/span>VarGet<\/span>( <\/span>varname <\/span>) ) + <\/span>profit <\/span>);
  }
}
<\/span>\/\/
<\/span>SetCustomBacktestProc<\/span>( <\/span>"" <\/span>);
<\/span>\/\/
\/* Now custom-backtest procedure follows *\/
\/\/
<\/span>if ( <\/span>Status<\/span>( <\/span>"action" <\/span>) == <\/span>actionPortfolio <\/span>)
{
    <\/span>bo <\/span>= <\/span>GetBacktesterObject<\/span>();
    <\/span>\/\/
    <\/span>bo<\/span>.<\/span>Backtest<\/span>(); <\/span>\/\/ run default backtest procedure
    \/\/
    <\/span>tradedSymbols <\/span>= <\/span>","<\/span>;
    <\/span>\/\/
    \/\/iterate through closed trades
    <\/span>for ( <\/span>trade <\/span>= <\/span>bo<\/span>.<\/span>GetFirstTrade<\/span>( ); <\/span>trade<\/span>; <\/span>trade <\/span>= <\/span>bo<\/span>.<\/span>GetNextTrade<\/span>( ) )
    {
        <\/span>ProcessTrade<\/span>( <\/span>trade <\/span>);
    }
    <\/span>\/\/
    \/\/iterate through open positions
    <\/span>for ( <\/span>trade <\/span>= <\/span>bo<\/span>.<\/span>GetFirstOpenPos<\/span>( ); <\/span>trade<\/span>; <\/span>trade <\/span>= <\/span>bo<\/span>.<\/span>GetNextOpenPos<\/span>( ) )
    {
        <\/span>ProcessTrade<\/span>( <\/span>trade <\/span>);
    }
    <\/span>\/\/
    \/\/iterate through the list of traded symbols and generate custom metrics
    <\/span>for ( <\/span>i <\/span>= <\/span>1<\/span>; ( <\/span>sym <\/span>= <\/span>StrExtract<\/span>( <\/span>tradedSymbols<\/span>, <\/span>i <\/span>) ) != <\/span>""<\/span>; <\/span>i<\/span>++ )
    {
        <\/span>longprofit <\/span>= <\/span>VarGet<\/span>( <\/span>"long_" <\/span>+ <\/span>sym <\/span>);
        <\/span>shortprofit <\/span>= <\/span>VarGet<\/span>( <\/span>"short_" <\/span>+ <\/span>sym <\/span>);
        <\/span>allprofit <\/span>= <\/span>Nz<\/span>( <\/span>longprofit <\/span>) + <\/span>Nz<\/span>( <\/span>shortprofit <\/span>);
        <\/span>\/\/ metric uses 2 decimal points and
        \/\/ 3 (calculate sum) as a \"combine method" for walk forward out-of-sample
        <\/span>bo<\/span>.<\/span>AddCustomMetric<\/span>( <\/span>"Profit for " <\/span>+ <\/span>sym<\/span>, <\/span>allprofit<\/span>, <\/span>longprofit<\/span>, <\/span>shortprofit<\/span>, <\/span>2<\/span>, <\/span>3 <\/span>);
    }
}
<\/span>\/\/
<\/span>SetOption<\/span>( <\/span>"MaxOpenPositions"<\/span>, <\/span>10 <\/span>);
<\/span>\/\/
<\/span>Buy <\/span>= <\/span>Cross<\/span>( <\/span>MACD<\/span>(), <\/span>Signal<\/span>() );
<\/span>Sell <\/span>= <\/span>Cross<\/span>( <\/span>Signal<\/span>(), <\/span>MACD<\/span>() );
<\/span>Short <\/span>= <\/span>Sell<\/span>;
<\/span>Cover <\/span>= <\/span>Buy<\/span>;
<\/span>SetPositionSize<\/span>( <\/span>10<\/span>, <\/span>spsPercentOfEquity <\/span>) <\/code>

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

\"Per-symbol<\/p>

If you prefer percent profits instead of dollar profits, just replace GetProfit() call with GetPercentProfit(). <\/p>","protected":false},"excerpt":{"rendered":"

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 […]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":[],"categories":[8],"tags":[53,14,15,30],"_links":{"self":[{"href":"https:\/\/www.amibroker.com\/wordpress\/kb\/wp-json\/wp\/v2\/posts\/552"}],"collection":[{"href":"https:\/\/www.amibroker.com\/wordpress\/kb\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.amibroker.com\/wordpress\/kb\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.amibroker.com\/wordpress\/kb\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.amibroker.com\/wordpress\/kb\/wp-json\/wp\/v2\/comments?post=552"}],"version-history":[{"count":2,"href":"https:\/\/www.amibroker.com\/wordpress\/kb\/wp-json\/wp\/v2\/posts\/552\/revisions"}],"predecessor-version":[{"id":556,"href":"https:\/\/www.amibroker.com\/wordpress\/kb\/wp-json\/wp\/v2\/posts\/552\/revisions\/556"}],"wp:attachment":[{"href":"https:\/\/www.amibroker.com\/wordpress\/kb\/wp-json\/wp\/v2\/media?parent=552"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.amibroker.com\/wordpress\/kb\/wp-json\/wp\/v2\/categories?post=552"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.amibroker.com\/wordpress\/kb\/wp-json\/wp\/v2\/tags?post=552"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}