CBT independent trade specific entry/exit pairs

I want to set up entry logic that is directly associated with it's associated exit logic. I have used '-nnn' in place of 'PositionScore". Is 'Position Score' used properly or is there a better means?

Day One >> Enter MSFT-200, Enter MSFT-300
Day Two >> Exit MSFT-300, Enter MSFT-500
Day Three >> Exit MSFT-200, Exit MSFT-500

Any mistakes or suggestions about syntax or style, like a Case statement or other more direct or efficient execution is appreciated.

Questions-

  • Is the 'AND watchlist' is needed for the exit logic?
  • Once implemented, does CBT do all Amibroker processing? In other words, the chart uses CBT logic as well as back testing, optimization, etc.

Thank you any and all.

_N( Title = StrFormat( "{{NAME}} - {{INTERVAL}}  {{DATE}} Close> $%.2f,", C ) );
P = ParamField( "Price field", 3 );
Plot( P, "Price", ParamColor( "Color", colorDefault ), styleBar | ParamStyle( "Style" ) | GetPriceStyle() );
_SECTION_END();

_SECTION_BEGIN( "M4" );
M4_L_WL = InWatchListName("M4_L_30");
M4_S_WL = InWatchListName("M4_S_30");
prcM4 = ParamField( "Price field", 3 );
fM4 = Param( "M4 MA Period", 5, 1, 20, 1 ); 
fstM4 = MA( prcM4, fM4 );
Buy_M4 = prcM4 <= fstM4 AND M4_L_WL;
Short_M4 = prcM4 >= fstM4 AND M4_S_WL;
barM4_L = Param("M4 Long Exit Bars", 3, 0, 10, 1);
barM4_S = Param("M4 Short Exit Bars", 4, 0, 10, 1);
_SECTION_END();

_SECTION_BEGIN( "MV" );
MV_L_WL = InWatchListName("MV_L_30");
MV_S_WL = InWatchListName("MV_S_30");
prcMV = ParamField( "Price field", 3 );
fMV = Param( "MV MA Period", 5, 1, 20, 1 ); 
fstMV = MA( prcMV, fMV );
Buy_MV = prcMV <= fstMV AND MV_L_WL;
Short_MV = prcMV >= fstMV AND MV_S_WL;
barMV_L = Param("MV Long Exit Bars", 5, 0, 10, 1);
barMV_S = Param("MV Short Exit Bars", 6, 0, 10, 1);
_SECTION_END();

_SECTION_BEGIN( "Trade Logic" ); //%//%//%//%//%//%//%/%//%//%//%//%//%//%//%//%///%//%
//	Each symbol is processed by trade specific logic.
Buy = Buy_M4 OR Buy_MV;
Short = Short_M4 OR Short_MV;
PositionScore = IIf( Buy_M4, 200,
                IIf( Buy_MV, 300,
                IIf( Short_M4, 500,
                IIf( Short_MV, 600, 0 ))));
Sell = Cover = 0;
BuyPrice = SellPrice = ShortPrice = CoverPrice = P;
maxpos = Param("Max Open Positions", 1000, 0, 10000, 1);
SetOption( "MaxOpenPositions", maxpos );
SetOption( "InitialEquity", 10000000 );
SetPositionSize( 1, spsPercentOfEquity );
SetTradeDelays( 0, 0, 0, 0 );
SetOption("UseCustomBacktestProc", 1);

if( Status("action") == actionPortfolio )
{
    bo = GetBacktesterObject();
    
    if( !IsNull(bo) )
    {
        bo.PreProcess();
        exitCount = 0;
        for( bar = 1; bar < BarCount; bar++ )
        {
            bo.UpdateStats( bar, 0 );
            bo.HandleStops( bar );
            bo.ProcessTradeSignals( bar );
            for( pos = bo.GetFirstOpenPos(); pos; pos = bo.GetNextOpenPos() )
            {
                signalType = pos.Score;
                exitPrice = pos.GetPrice( bar, "C" );
                BarsInTrade = pos.BarsInTrade;
                if( signalType == 200 )
                {
                    if( BarsInTrade >= barM4_L )
                    {
                        bo.ExitTrade( bar, pos.Handle, exitPrice, "M4_L Time" );
                        exitCount++;
                    }
                }
                else if( signalType == 300 )
                {
                    if( BarsInTrade >= barMV_L )
                    {
                        bo.ExitTrade( bar, pos.Handle, exitPrice, "MV_L Time" );
                        exitCount++;
                    }
                }
                else if( signalType == 500 )
                {
                    if( BarsInTrade >= barM4_S )
                    {
                        bo.ExitTrade( bar, pos.Handle, exitPrice, "M4_S Time" );
                        exitCount++;
                    }
                }
                else if( signalType == 600 )
                {
                    if( BarsInTrade >= barMV_S )
                    {
                        bo.ExitTrade( bar, pos.Handle, exitPrice, "MV_S Time" );
                        exitCount++;
                    }
                }
            }
            bo.UpdateStats( bar, 2 );
        }
        bo.PostProcess();
    }
}
_SECTION_END();

I just realized I am using a simple static time to exit in my example code. I need to know how to exit using a moving average or other calculated data. Basically how to access any calculated field used to determine an Exit. Thanks!!

I misworded my request. If this CBT code is to run in real time, market data is always changing. How can CBT access the real time data to calculate exit signal criteria from what current data IB can supply, not only for charting but trading.

Thanks

A CBT replaces the default AmiBroker behavior during the second phase of a backtest. It does not affect charting, nor analyses that only have one phase, like scans and explorations.

What you're trying to achieve is possible, but it's not a trivial exercise. The basic steps go something like this:

  1. Generate entry signals in Phase 1 as usual.

  2. Make the entry type available to Phase 2, either via the PositionScore as you have done or via a symbol-specific static variable.

  3. During Phase 1, generate exit signal arrays for each entry type, but do not use these to set the Sell/Cover arrays. Instead store them in static variables, one per entry type per symbol.

  4. During Phase 2, process all the open positions on each bar. Determine the entry type, retrive the appropriate exit signal array, and exit the position if needed.

That's close to the code you provided, but there are a few things wrong in your example. First, the "reason" parameter for bo.ExitTrade is usually a number. I have never tried to use a string like you did in your code.

Second, you can't use a standard for loop with bo.GetFirstOpenPos and bo.GetNextOpenPos. The loop will terminate as soon as one trade is closed. Basically, you need to retrieve the next trade before (possibly) closing the current one.

2 Likes

Thanks, I just now understood the two pass approach more completely. It is an elegant but complex solutions to portfolio testing and processing. I have been at this for hours. I will work on this tomorrow. I believe I understand what you propose.