thanks. I have not solved it yet but probably need to use the example from 2006.
If anyone wants to give it a shot
I put the entire system without CBT below. This is a test version adding a simple system.
The issue I try to solve is that a signal is only valid if the CLOSE price crosses above the trail line (in the case of a long trade). In the chart you see the system is short and then the high price crosses the trail to the upside. Then I cover (number 1), buy (number 2) but the close closes below the trail line so then I sell (number 3) and go back short (number 4). So these are 4 trades in a single signal bar. The regular backtester does not handle all these signals. It only does a cover and goes back short. The buy and sell it does not handle. This is what I am trying to solve with the CBT. Thanks
// https://www.amibroker.com/guide/a_custombacktest.html
// https://www.amibroker.com/kb/category/analysis/backtest-analysis/custom-backtest/
per = Param( "Period", 50, 5, 100, 1 );
threshold_fact = Param( "Threshold_factor", 0, 0, 100, 1 );
showsequencenumbers = ParamToggle( "Show Sequence Numbers", "No|Yes", 1 );
ft = ParamList( "Font Type", "Tahoma Bold|Arial Black|Verdana Bold|Courier New Bold|Comic Sans MS Bold|Arial Bold|Candara Bold|Calibri Bold|Constantia Bold|Georgia Bold|Gadugi Bold|Segoe UI Bold", 1 );
sz = Param( "Font Size", 15, 8, 50, 1 );
bi = BarIndex();
fvb = FirstVisibleValue( bi );
lvb = LastVisibleValue( bi );
trailarrayup = trailarraydn = Null;
trailarraydn = Ref( HHV( H, per ), -1 );
trailarrayup = Ref( LLV( L, per ), -1 );
threshold = TickSize * threshold_fact;
// if ticksize is not set in code or information window use 0.01
if( TickSize == 0 )
{
TickSize = 0.01;
}
// test system
Buy1 = Cross( C, trailarraydn );
Short1 = Cross( trailarrayup, C );
uptrend = Ref( Flip( Buy1, Short1 ), -1 );
dntrend = Ref( Flip( Short1, Buy1 ), -1 );
// back test for futures
//SetBarsRequired( sbrAll, sbrAll );
SetBacktestMode( backtestRegularRaw2Multi );
SetTradeDelays( 0, 0, 0, 0 );
SetOption( "FuturesMode", True );
SetOption( "PriceBoundChecking", False );
SetOption( "AllowSameBarExit", True );
SetOption( "CommissionMode", 3 );
SetOption( "CommissionAmount", 2.5 );
SetPositionSize( 1, spsShares );
SetOption( "MaxOpenPositions", 1 );
Buy = Sell = Short = Cover = 0;
BuyPrice = SellPrice = ShortPrice = CoverPrice = 0;
inlong = inshort = 0;
buysequence = shortsequence = sellsequence = coversequence = 0;
for( i = 0; i < BarCount; i++ )
{
if( uptrend[i] )
{
if( L[i] < trailarrayup[i] AND inshort == 0 )
{
if( inlong == 1 )
{
// exit long
Sell[i] = 1;
SellPrice[i] = Min( O[i], trailarrayup[i] );
inlong = 0;
sellsequence[i] = 1; // if multiple signals inside one bar track the sequence number
}
// enter short
Short[i] = 1;
ShortPrice[i] = Min( O[i], trailarrayup[i] );
inshort = 1;
shortsequence[i] = 1 + sellsequence[i]; // if multiple signals inside one bar track the sequence number
// test if close of bar is below trail line
if( C[i] > trailarrayup[i] + threshold[i] )
{
// stay in long because trail is not broken to the down side (cover short and go back long)
// cover short
Cover[i] = 1;
CoverPrice[i] = C[i];
inshort = 0;
coversequence[i] = 3; // if multiple signals inside one bar track the sequence number
// get back long
Buy[i] = 1;
BuyPrice[i] = C[i];
inlong = 1;
buysequence[i] = 4; // if multiple signals inside one bar track the sequence number
}
}
else
// re-enter long when trail line is not crossed by the close price of the bar
if( C[i] > trailarrayup[i] + threshold[i] AND inshort == 1 )
{
// cover short
Cover[i] = 1;
CoverPrice[i] = C[i];
inshort = 0;
coversequence[i] = 1; // if multiple signals inside one bar track the sequence number
// get back long
Buy[i] = 1;
BuyPrice[i] = C[i];
inlong = 1;
buysequence[i] = 2; // if multiple signals inside one bar track the sequence number
}
}
else
if( dntrend[i] )
{
if( H[i] > trailarraydn[i] AND inlong == 0 )
{
if( inshort == 1 )
{
// exit short
Cover[i] = 1;
CoverPrice[i] = Max( O[i], trailarraydn[i] );
inshort = 0;
coversequence[i] = 1; // if multiple signals inside one bar track the sequence number
}
// enter long
Buy[i] = 1;
BuyPrice[i] = Max( O[i], trailarraydn[i] );
inlong = 1;
buysequence[i] = 1 + coversequence[i]; // if multiple signals inside one bar track the sequence number
// test if close of bar is above trail line
if( C[i] < trailarraydn[i] - threshold[i] )
{
// stay in short because trail is not broken to the up side (sell long and go back short)
// sell long
Sell[i] = 1;
SellPrice[i] = C[i];
inlong = 0;
sellsequence[i] = 3; // if multiple signals inside one bar track the sequence number
// get back short
Short[i] = 1;
ShortPrice[i] = C[i];
inshort = 1;
shortsequence[i] = 4; // if multiple signals inside one bar track the sequence number
}
}
else
// re-enter short when trail line is not crossed by the close price of the bar
if( C[i] < trailarraydn[i] - threshold[i] AND inlong == 1 )
{
// sell long
Sell[i] = 1;
SellPrice[i] = C[i];
inlong = 0;
sellsequence[i] = 1; // if multiple signals inside one bar track the sequence number
// get back short
Short[i] = 1;
ShortPrice[i] = C[i];
inshort = 1;
shortsequence[i] = 2; // if multiple signals inside one bar track the sequence number
}
}
}
SetChartBkColor( ColorRGB( 0, 0, 0 ) );
SetChartOptions( 0, chartShowArrows | chartShowDates );
Plot( C, "C", colorWhite, styleCandle, Null, Null, 0, 0, 1 );
Plot( trailarrayup, "trail up", colorLightBlue, styleLine | styleStaircase | styleNoRescale, Null, Null, 0, 0, 1 );
Plot( trailarraydn, "trail dn", colorLightOrange, styleLine | styleStaircase | styleNoRescale, Null, Null, 0, 0, 1 );
PlotShapes( IIf( Buy, shapeUpArrow, shapeNone ), colorBrightGreen, 0, L, -15 );
PlotShapes( IIf( Sell, shapeDownArrow, shapeNone ), colorRed, 0, H, -15 );
PlotShapes( IIf( Buy, shapeSmallCircle, shapeNone ), colorLightBlue, 0, BuyPrice, 0 );
PlotShapes( IIf( Sell, shapeSmallCircle, shapeNone ), colorLightOrange, 0, SellPrice, 0 );
PlotShapes( IIf( Short, shapeSmallDownTriangle, shapeNone ), colorRed, 0, H, IIf( Short AND Sell, -30, -15 ) );
PlotShapes( IIf( Cover, shapeSmallUpTriangle, shapeNone ), colorBrightGreen, 0, L, IIf( Cover AND Buy, -30, -15 ) );
PlotShapes( IIf( Short, shapeSmallSquare, shapeNone ), colorLightOrange, 0, ShortPrice, 0 );
PlotShapes( IIf( Cover, shapeSmallSquare, shapeNone ), colorLightBlue, 0, CoverPrice, 0 );
Plot( IIf( trailarrayup, trailarrayup + threshold, Null ), "", colorLightBlue, styleDashed | styleStaircase | styleNoRescale, Null, Null, 0, 1, 1 );
Plot( IIf( trailarraydn, trailarraydn - threshold, Null ), "", colorLightOrange, styleDashed | styleStaircase | styleNoRescale, Null, Null, 0, 1, 1 );
Plot( uptrend, "", ColorRGB( 0, 0, 30 ), styleArea | styleOwnScale | styleNoLabel, 0, 1, 0, -100 );
Plot( dntrend, "", ColorRGB( 30, 0, 0 ), styleArea | styleOwnScale | styleNoLabel, 0, 1, 0, -100 );
if( showsequencenumbers )
{
for( i = fvb + 1; i <= lvb; i++ )
{
if( buysequence[i] OR sellsequence[i] OR shortsequence[i] OR coversequence[i] )
{
if( buysequence[i] )
{
PlotTextSetFont( "" + buysequence[i], ft, sz, i, L[i], colorLightBlue, colorDarkGrey, -4.5 * sz );
}
if( sellsequence[i] )
{
PlotTextSetFont( "" + sellsequence[i], ft, sz, i, H[i], colorLightOrange, colorDarkGrey, 3.5 * sz );
}
if( coversequence[i] )
{
PlotTextSetFont( "" + coversequence[i], ft, sz, i, L[i], colorLightBlue, colorDarkGrey, -6 * sz );
}
if( shortsequence[i] )
{
PlotTextSetFont( "" + shortsequence[i], ft, sz, i, H[i], colorLightOrange, colorDarkGrey, 5 * sz );
}
}
}
}
Title = EncodeColor( colorLightOrange ) + "trailarraydn: " + trailarraydn + " | " + EncodeColor( colorLightBlue ) + "trailarrayup: " + trailarrayup + " | " + EncodeColor( colorGold ) + "Close: " + C;