[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[amibroker] Re: CBT: Force full investment



PureBytes Links

Trading Reference Links

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 amibroker@xxxxxxxxxxxxxxx, Graham <kavemanperth@xxx> 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 <vlanschot@xxx> 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 amibroker@xxxxxxxxxxxxxxx, 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
> >
> >
> >
> >
>




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

<*> To visit your group on the web, go to:
    http://groups.yahoo.com/group/amibroker/

<*> Your email settings:
    Individual Email | Traditional

<*> To change settings online go to:
    http://groups.yahoo.com/group/amibroker/join
    (Yahoo! ID required)

<*> To change settings via email:
    mailto:amibroker-digest@xxxxxxxxxxxxxxx 
    mailto:amibroker-fullfeatured@xxxxxxxxxxxxxxx

<*> To unsubscribe from this group, send an email to:
    amibroker-unsubscribe@xxxxxxxxxxxxxxx

<*> Your use of Yahoo! Groups is subject to:
    http://docs.yahoo.com/info/terms/