Portfolio Backtesting with symbol sequence

Hi,

I want to run a portfolio backtest where outcome of SYM1 & SYM2 will decide the trade size of SYM3 (but not vice-versa).

I tried it by using StaticVarAdd and portfolio backtest on a watchlist. My code works fine if backtester works on SYM1 and SYM2 before working on SYM3.

The problem I am facing is that, there is no way to define the sequence in which backtest will run on the given symbols in watchlist. So sometimes my code works fine, and sometime it gives wrong results.

Please help!

Perhaps you should read about PositionScore: https://www.amibroker.com/guide/h_portfolio.html

1 Like

The order of starting threads is known - alphabetical by symbol.

If you have more than one core then they will run in parallel. You can either use critical section to sequence them as described in manual http://www.amibroker.com/guide/h_multithreading.html or limit number of threads using #pragma maxthreads 1

Thank you, I tried using both position score and limiting maxthreads… BUT the result is intriguing (does not works).

I am attaching code. Without limiting multithreads the result is inconsistent. By limiting the multithreads, it always seem to backtest first SYM3, even though it comes later alphabetically and has lower positon score. @Tomasz @mradtke please suggest but what is wrong. BTW I am registered user of Amibroker.

#pragma maxthreads 1

_SECTION_BEGIN( "Price" );
SetChartOptions( 0, chartShowArrows | chartShowDates );
_N( Title = StrFormat( "{{NAME}} - {{INTERVAL}} {{DATE}} Open %g, Hi %g, Lo %g, Close %g (%.1f%%) {{VALUES}}", O, H, L, C, SelectedValue( ROC( C, 1 ) ) ) );
Plot( C, "Close", ParamColor( "Color", colorDefault ), styleNoTitle | ParamStyle( "Style" ) | GetPriceStyle() );
_SECTION_END();

Short = Cover = 0;
dd = DaysSince1900();
time = TimeNum();

if( Name() == "SYM1" ) PositionScore = -3;
if( Name() == "SYM2" ) PositionScore = -2;
if( Name() == "SYM2" ) PositionScore = -1;

sell0 = Name() == "SYM1" OR Name() == "SYM2";
sell1 = Name() == "SYM3";
qty = 0;
StaticVarSet( "Exposure", 0 );
sp = 0;
flag = 0;

for( i = 0; i < BarCount; i++ )
{
    if( dd[i] == 43038 AND time[i] == 93000 AND sell0[i] )
    {
        Short[i] = 1;
        sp = ShortPrice = O[i];
        flag = 1;
        qty[i] = 100;
    }
    if( H[i] > sp + 10 AND flag )
    {
        Cover[i] = 1;
        flag = 0;
        qty[i] = 100;
        CoverPrice[i] = sp + 10;
        StaticVarAdd( "Exposure", ( sp + 10 )*qty[i] );
    }
    if( sell1[i] AND time[i] == 100000 AND dd[i] == 43038 )
    {
        Short[i] = 1;
        ShortPrice[i] = O[i];
        qty[i] = floor( StaticVarGet( "Exposure" ) / O[i] );
        PopupWindow( "Current Exposure is: " + StaticVarGet( "Exposure" ), "Alert", 20, 640 * mtRandom(), 480 * mtRandom() );
    }
}

SetPositionSize( qty, spsShares );
Title = Title + "\nDD " + dd + " sell0 " + time;

Sorry this is the code I am testing with:

#pragma maxthreads 1

_SECTION_BEGIN( "Price" );
SetChartOptions( 0, chartShowArrows | chartShowDates );
_N( Title = StrFormat( "{{NAME}} - {{INTERVAL}} {{DATE}} Open %g, Hi %g, Lo %g, Close %g (%.1f%%) {{VALUES}}", O, H, L, C, SelectedValue( ROC( C, 1 ) ) ) );
Plot( C, "Close", ParamColor( "Color", colorDefault ), styleNoTitle | ParamStyle( "Style" ) | GetPriceStyle() );
_SECTION_END();

Short = Cover = 0;
dd = DaysSince1900();
time = TimeNum();

if( Name() == "SYM1" ) PositionScore = 3;
if( Name() == "SYM2" ) PositionScore = 2;
if( Name() == "SYM3" ) PositionScore = 1;

sell0 = Name() == "SYM1" OR Name() == "SYM2";
sell1 = Name() == "SYM3";
qty = 0;
StaticVarSet( "Exposure", 0 );
sp = 0;
flag = 0;

for( i = 0; i < BarCount; i++ )
{
    if( dd[i] == 43038 AND time[i] == 93000 AND sell0[i] )
    {
        Short[i] = 1;
        sp = ShortPrice = O[i];
        flag = 1;
        qty[i] = 100;
    }
    if( H[i] > sp + 10 AND flag )
    {
        Cover[i] = 1;
        flag = 0;
        qty[i] = 100;
        CoverPrice[i] = sp + 10;
        StaticVarAdd( "Exposure", ( sp + 10 )*qty[i] );
    }
    if( sell1[i] AND time[i] == 100000 AND dd[i] == 43038 )
    {
        Short[i] = 1;
        ShortPrice[i] = O[i];
        qty[i] = floor( StaticVarGet( "Exposure" ) / O[i] );
        PopupWindow( "Current Exposure is: " + StaticVarGet( "Exposure" ), "Alert", 20, 640 * mtRandom(), 480 * mtRandom() );
    }
}

SetPositionSize( qty, spsShares );
Title = Title + "\nDD " + dd + " sell0 " + time;

Yet another case of loop abuse. You should not call StaticVarAdd/StaticVarGet in a bar-by-bar loop. ALWAYS think array-wise and always write array code http://www.amibroker.com/guide/h_understandafl.html

Also there is no room for “it seems”. You need to learn how to debug your formula to KNOW FACTS instead of guessing.

PopupWindow is NOT a debug tool. Use tools that are proper for debugging.

Also in principle the code should be written using completely different way. Instead of doing static var trickery, relying on alphabetical order and pragmas it would be easier just to use custom backtester as example in the KB shows: http://www.amibroker.com/kb/2006/03/06/re-balancing-open-positions/

2 Likes

@Tomasz advise how do I implement custom trail stop without using loop? I am following this approach because my stop is combination of ATR (at trade entry) and another custom indicator.