Yes, still struggling with this one, so I would appreciate any 
guidance from the CBT-experts, like Graham, GP, and Ed (and TJ, of 
course). I've included a stripped-down version of my CBT-code (see 
below) which you may use to verify my strange observations. 

// CODE SECTION

// USE on WEEKLY DATA !!!

FullYr=52;
AnnPer=52;
QtrPer=13;
MonthPer=4;
WeekPer=1;
DayPer=1/5;

ShortTrades = ParamToggle("Short Trades?","No|Yes",1);

MaxOpenPos = 50; // maximum total positions 
//MaxShort = Param("ChoiceMaxShort",round((MaxOpenPos / 100) * 
50),0,MaxOpenPos);

SetOption("MaxOpenPositions",MaxOpenPos);

Startkapitaal = 1000000;

SetOption("InitialEquity", Startkapitaal);

if (ShortTrades==1)
{
        MaxLong = round((MaxOpenPos / 100) * 50);
        MaxShort = round((MaxOpenPos / 100) * 50);
        TypePos = "_LS";
        LongPS = ShortPS = -100/(MaxLong+MaxShort); 
}
else if (ShortTrades==0)
{
        MaxLong = MaxOpenPos;
        MaxShort = 0;
        TypePos = "_LO";
        LongPS = -100/(MaxLong+MaxShort);
        ShortPS = 0; 
}

NaamBT = "~Trial_LS_";

BM = "MSWRLD$";

BMI=Foreign(BM,"C");

MA1 = Param("MA1",AnnPer,6*MonthPer,AnnPer,MonthPer);
MA2 = Param("MA2",MonthPer,5*MonthPer,5*MonthPer,MonthPer);

Mom = ROC(C,MA1)-ROC(C,MA2);
BMMom= ROC(BMI,MA1)-ROC(BMI,MA2);
RelMom = Mom-BMMom;

Buy=RelMom>=0; Sell=RelMom<0;
PositionScore=RelMom;

if (ShortTrades==1)
{
        Short=Sell; Cover=Buy;
}
else Short=Cover=0;

PositionSize= IIf(Buy,LongPS,IIf(Short,ShortPS,0));

if (Interval()==inWeekly OR Interval() == inMonthly)
BuyPrice=SellPrice=ShortPrice=CoverPrice=Open;
else BuyPrice=SellPrice=ShortPrice=CoverPrice=Close;

TextOutput = ParamToggle("Raw Text Output?", "No|Yes");

UseCBT = ParamToggle("Use CBT?", "No|Yes",1);

FBT=LastValue(ValueWhen(Status("firstbarintest")==1,BarIndex()));
LBT=LastValue(ValueWhen(Status("lastbarintest")==1,BarIndex()));

SetOption("UseCustomBacktestProc", UseCBT ); 

if( Status("action") == actionPortfolio )
{
        bo = GetBacktesterObject();
        
        bo.PreProcess(); // Initialize backtester
        
        for(bar=0; bar<BarCount; bar++) 
        {       
                NrOpenPos = 0;
                NrOpenLongs = 0;
                NrOpenShorts = 0;               
                NrNewLongs = 0;
                NrNewShorts = 0;
                numExits = 0;
                
                bContinueLong = bContinueShort = True;

                // First, list Exit Signals, and execute exit trades
                for ( sig=bo.GetFirstSignal(bar); sig; 
sig=bo.GetNextSignal(bar) )
                {
                        if (sig.IsExit() AND sig.Price != -1 ) 
                        {
                                // Exit Trade
                                GoExit = bo.ExitTrade
(bar,sig.symbol,sig.Price);
                                
                                if (GoExit==1) numExits = numExits + 
1;
                        }
                }
                
                if (TextOutput==1)
                {bo.RawTextOutput("Nr Exits = " + numExits ); 
bo.UpdateStats(bar,0);}
                
                //Second, establish remaining nr open positions
                for( pos = bo.GetFirstOpenPos(); pos; pos = 
bo.GetNextOpenPos() ) 
    {
        if (pos.IsLong) {LS =1; NrOpenLongs = NrOpenLongs+1;}
        else if (!pos.IsLong){ LS = -1; NrOpenShorts = NrOpenShorts + 
1;}
        // All pos are open, so pos.IsOpen not necessary
        
        NrOpenPos = NrOpenPos + 1;
    }
    
    if (TextOutput==1)
                {
                        bo.RawTextOutput("Nr Open Longs = " + 
NrOpenLongs);
                        bo.RawTextOutput("Nr Open Shorts = " + 
NrOpenShorts);
                        bo.RawTextOutput("Nr Open Posits = " + 
NrOpenPos);
                }
                
                if (NrOpenLongs>=MaxLong) bContinueLong = False;
                if (NrOpenShorts>=MaxShort) bContinueShort = False;

                
                // update stats
                bo.UpdateStats(bar,0);
                
                Kas=bo.Cash; Eq = bo.Equity;
                
                if (bar>1) NewPosSize = Nz((Kas[bar]/numExits)/Eq[bar]
*100, 100/MaxOpenPos);
                else NewPosSize = 100/MaxOpenPos ;
                
                LongPS = ShortPS = -NewPosSize;
                
                if (TextOutput==1) bo.RawTextOutput("New PosSize = " 
+ -NewPosSize );
                
                // Next, look for conditional Entry Signals
                for ( sig=bo.GetFirstSignal(bar); sig ; 
sig=bo.GetNextSignal(bar)) 
                {
                        if( sig.IsEntry() AND sig.Price != -1 AND 
IsNull( bo.FindOpenPos( sig.Symbol ) ) ) 
                        {
                                // Enter Long
                                if( sig.IsLong() AND NrNewLongs <= 
(MaxLong-NrOpenLongs) AND bContinueLong)
                                {
                                        GoLong = bo.EnterTrade(bar, 
sig.symbol, True, sig.Price, LongPS );
                                        
                                        if( GoLong == 0 ) 
bContinueLong = False;//If trade doesn't go through don't do anymore 
trades
                                        else 
                                        NrNewLongs = NrNewLongs + 1;
                                        
                                } 
                                // Enter Short
                                else if ( sig.IsLong()==0 AND 
NrNewShorts <= (MaxShort - NrOpenShorts) AND bContinueShort)
                                {
                                        GoShort = bo.EnterTrade(bar, 
sig.symbol, False, sig.Price, ShortPS);
                                        
                                        if( GoShort == 0 ) 
bContinueShort = False;//If trade doesn't go through don't do anymore 
trades
                                        else NrNewShorts = 
NrNewShorts + 1;
                                }
                        }
                }
                
                if (TextOutput==1)
                {
                        bo.RawTextOutput("Nr NewLong = " + 
NrNewLongs);
                        bo.RawTextOutput("Nr NewShort = " + 
NrNewShorts );
                        bo.RawTextOutput("Cash End = " + Kas[bar] );
                }
                
                bo.ProcessTradeSignals( bar );          
        }
        
        bo.PostProcess(1);// Finalize backtester, but (1) means: do 
NOT list trades
   // i.e. use  AddCustomMetric (see below) to add custom metrics to 
BT-report.
        
  SumProfitPerRisk = 0; 
  NumTrades = 0; 
  
  // ADDED LINE
  dt = DateTime(); 

  AddToComposite( Foreign("~~~EQUITY","C"), "~~"+NaamBT+TypePos, "C", 
atcFlagDefaults | atcFlagEnableInPortfolio );
        AddToComposite( Foreign
("~~~EQUITY","L"), "~~"+NaamBT+TypePos, "L", atcFlagDefaults | 
atcFlagEnableInPortfolio );
        
        CategoryAddSymbol("~~"+NaamBT+TypePos,  categoryGroup   ,
        250     );
        
        Eq = Foreign("~~"+NaamBT+TypePos,"C");
        
        WBM = BMI = Foreign(BM, "C"); 

  BMR=ROC(WBM,1)/100;
        PFRet=ROC(Eq,1)/100;

        ThisTestLB=LBT-FBT;
  SystPerfFullP=(Eq[LBT]/StartKapitaal-1)*100;
  
  BMPerfFullP=(BMI[LBT]/BMI[FBT]-1)*100;
  
  SystRetsFullP=PFRet;
        
  bo.AddCustomMetric("Other Stats (OTP = over test-period):","" );
        bo.AddCustomMetric("Relative Performance OTP (%)", 
SystperfFullP-BMPerfFullP);

  bo.ListTrades(); 
}

// END OF CODE

As you can see, the code:

1) executes (and counts) all exits, in order to release as much cash 
as possible;
2) determines the number of remaining long/short open positions;
3) switches the bContinueLong/-Short trigger to FALSE, as soon as the 
open-long, respectively open-short positions are equal to the 
respective prespecified maximum positions;
4) enters in the signal loop, executes long, respectively short 
trades UNTIL (again) it hits the respective maximum positions. 

In short, I would like to hold an equal number (default: 25) of long 
and short positions, and I had hoped that this code would achieve 
this. However, if you run this, it shows, for example:

Nr Exits = 1
Nr Open Longs = 23
Nr Open Shorts = 26
Nr Open Posits = 49

So, although the number of remaining open positions (49) correctly 
reflects the required maximum open positions (50) minus any exits, it 
also (and strangely) regularly shows that the number of open-longs or 
open-shorts during the backtest exceed the maximum required 
long/shorts. And this is not caused by a lack of long/short signals.

I don't understand this, although it could simply be a case of "code-
blindness" with an easy solution. Again, any help much appreciated.

PS


--- In [email protected], Graham <[EMAIL PROTECTED]> wrote:
>
> You need to actually check how many open positions you have after 
the
> exits and thus how many new trades you need to enter. You can do 
this
> with openpos loop
> Then use bo.Cash to determine the position size for the new entries
> 
> -- 
> Cheers
> Graham Kav
> AFL Writing Service
> http://www.aflwriting.com
> 
> 
> On 01/02/2008, vlanschot <[EMAIL PROTECTED]> wrote:
> > Thanks Graham,
> >
> > A follow-up question if I may.
> >
> > Indeed, in my CBT-loops, I first execute the exits, and keep 
track of
> > the number of exits. Based on this, and after bo.UpdateStats, I've
> > added the following:
> >
> > (FYI: Cash = bo.Cash Eq = bo.Equity)
> >
> > if (bar>1) NewPosSize = Nz((Kas[bar]/numExits)/Eq[bar],
> > MaxOpenPos/100);
> > else NewPosSize = MaxOpenPos/100 ;
> >
> > LongPS = ShortPS = -NewPosSize*100;
> >
> > I then run through my entry signals.
> >
> > In other words, I assume the CBT re-calculates the cash amount 
after
> > exits, which I subsequently divide evenly over the potential new
> > positions.
> >
> > However, for some reason I end up with less than 50 positions (my
> > MaxOpenPos) at the end of the backtest. Whereas if I "delete" the
> > above code, I do end up with 50 positions, but then with too much
> > cash occassionally. Iow, the system generates enough valid 
signals to
> > fill any exits.
> >
> > Any clarification appreciated, although I realize I'm not giving 
you
> > much detail.
> >
> > PS
> >
> > --- In [email protected], Graham <kavemanperth@> wrote:
> > >
> > > In advanced backtest code you exit the trades, update the 
values,
> > then
> > > enter signals with amended posSize
> > >
> > > --
> > > Cheers
> > > Graham Kav
> > > AFL Writing Service
> > > http://www.aflwriting.com
> > >
> > >
> > > On 01/02/2008, vlanschot <vlanschot@> wrote:
> > > > Perhaps somebody has a straightforward way to solve the
> > following, or
> > > > point out the error in my interpretation of AFL/CBT:
> > > >
> > > > My system keeps a constant number of 50 positions, based on a
> > ranking
> > > > (although I do not use rotational trading.) At the start the
> > > > positions are equally weighted, i.e. PositionSize is defined 
as
> > 2%.
> > > > As time moves on, some do very well, and reach, say, a weight 
of
> > 3%
> > > > of equity. When the exit signal arrives, these positions are
> > replaced
> > > > by new ones, but now back to the 2% of equity as defined in
> > > > PositionSize.
> > > >
> > > > The resulting problem is that at times I find I have too much 
cash
> > > > left. Now, I know that I can rebalance open positions (by 
scaling
> > > > in/out, for example via TJ's code
> > > > http://www.amibroker.com/kb/2006/03/06/re-balancing-open-
> > positions/).
> > > > However, apart from the extra costs involved, I have found 
that
> > there
> > > > is no way to determine/access the amount of cash BEFORE
> > > > entering/rebalancing the new positions. In other words, 
bo.Cash
> > gives
> > > > you the amount of cash "at the end of the bar". You can, of
> > course,
> > > > use the amount of cash of the previous bar, but you keep 
lagging
> > the
> > > > actual trades.
> > > >
> > > > In short, I would like to force the backtester to always make 
the
> > > > system fully invested (except for round lots, etc.) It would 
be
> > > > great, for example, if there would be an option to 
automatically
> > > > assign the amount of cash which becomes available from the 
first
> > > > exited trade to the first new trade, etc. In my system this is
> > very
> > > > applicable, as I always have other trades to replace the 
exited
> > one.
> > > >
> > > > Any thoughts/suggestions welcome. If none, I'll forward this 
to
> > > > support.
> > > >
> > > > Thx.
> > > >
> > > > PS
> > > >
> > > >
> > > >
> > > > Please note that this group is for discussion between users 
only.
> > > >
> > > > To get support from AmiBroker please send an e-mail directly 
to
> > > > SUPPORT {at} amibroker.com
> > > >
> > > > For NEW RELEASE ANNOUNCEMENTS and other news always check 
DEVLOG:
> > > > http://www.amibroker.com/devlog/
> > > >
> > > > For other support material please check also:
> > > > http://www.amibroker.com/support.html
> > > >
> > > > Yahoo! Groups Links
> > > >
> > > >
> > > >
> > > >
> > >
> >
> >
> >
> >
> > Please note that this group is for discussion between users only.
> >
> > To get support from AmiBroker please send an e-mail directly to
> > SUPPORT {at} amibroker.com
> >
> > For NEW RELEASE ANNOUNCEMENTS and other news always check DEVLOG:
> > http://www.amibroker.com/devlog/
> >
> > For other support material please check also:
> > http://www.amibroker.com/support.html
> >
> > Yahoo! Groups Links
> >
> >
> >
> >
>


Reply via email to