Hello Mike, I appreciate the suggestion.
Your approach may not work since "y" in your example was generated by using atc function, thus cutting of the "needed information" (i.e.digits). For example: AtrExpLag (before using atc) was 3.115. Then I transfered it into atc function, thus becoming 3. If I used your code, it would become prec (3+0.005, 2), thus 3.01 whereas it actually was 3.115 Reading your suggestion, I just thought of another approach: Multiplying the variable ATRExpLag (BEFORE using atc) with 1000 to get rid of the digits, then creating atc, thereafter dividing it by 1000 once again "to get the digits right". This is a pain, but it might work. I´ll try. If I don´t succeed, "I´ll be back". Many thanks to all for your assistance!!!!!!! Markus ----- Original Message ----- From: Mike To: amibroker@yahoogroups.com Sent: Saturday, July 25, 2009 5:30 AM Subject: [amibroker] Re: Still - using CBT the first time If you don't find what you're looking for, you can use the Prec function. e.g. to round 'y' to 2 decimal places such that 3rd decimal at or above 0.005 bumps up 2nd decimal place, 3rd decimal below 0.005 leaves 2nd decimal unchanged: x = Prec(y + 0.005, 2); Mike --- In amibroker@yahoogroups.com, "Markus Witzler" <funny...@...> wrote: > > Hello TJ et al., > > may I ask once again? > > Thanks > > Markus > ----- Original Message ----- > From: Markus Witzler > To: amibroker@yahoogroups.com > Sent: Thursday, July 23, 2009 1:36 PM > Subject: Re: [amibroker] Still - using CBT the first time > > > > Hello Tomasz, > > thanks for the heads up. > > Floor () doesn´t do want I want: rounding down if first digit is smaller than 5, rounding up if it´s equal to or bigger than 5. > > Anyway, I found the flaw in my code but I don´t know how to correct it: > > In regular AFL code, I use the following to compute "ATRExpLag". Then I round it to the 3rd digit ("ATRExpLagRounded"). Thereafter, I create an artificial ticker, labeled "test" to be later able to call it in CBT: > for( i = 1; i < BarCount; i++ ) // here, the Average True Range (20 days) is coded by using a loop > > { > > trhelp[i]= Max(High[i]-Low[i],High[i]-Close[i-1]); //trhelp is a helping variable for calculating ATRcombined. ATR() function cannot be used. > > TRcombined[i]= Max(Close[i-1]-Low[i],trhelp[i]); //TRcombined is the actual TrueRange. > > ATRExpLag[i]=ATRExpLag [i-1]+ (TRcombined[i]-ATRExpLag[i-1])/x; // This is the 20-day expon. moving average of the ATR > > } > > ATRExpLagRounded=round(ATRExpLag*1000)/1000; //here, I round on the 3rd digit. > > test=AddToComposite(ATRExpLagRounded, "~ATRExpLagRounded_"+Name(), "V", atcFlagDefaults | atcFlagEnableInBacktest); > > > Here comes the CBT part. When I run an Exploration to see what´s in "test", it always returns "1" instead of the values it got from "ATRExpLagRounded". But it should hold the values of "ATRExpLagRounded", right?! Incidentally, I introduced "y" to be able to use previous days values for ATRExpLagRounded except for the first day (otherwhise value would be out of range). The "-200-sharesize" thing works fine though: > > for (sig = bo.GetFirstSignal(i); sig; sig = bo.GetNextSignal(i)) > > { // Loop through all signals at this bar > > // Long trades > > ATRexRounded = Foreign("~ATRExpLagRounded_"+sig.Symbol, "V"); // Get symbol's AtrExpLagRounded array > > ATRex = ATRexRounded[i]; // Reference a value in the array > > > { > > if (i<=0) > > y=ATRexRounded[i]; > > else > > y=ATRexRounded[i-1]; > > > } > > if (sig.IsEntry() && sig.IsLong()) // Process long entries > > > { > > sharesize=round(((Heat*bo.cash)/(y*ATRmultiplier))/250)*250; // i.e. computing # of shares/contracts > > // sig.possize=sharesize*sig.price; > > > //Sharesize formula needs to be modified for stocks if lot size differs!! > > > sig.possize=-2000 - sharesize; // i.e. setting back # of shares into signal object!! Possize must be < "-2000" > > // to mean # of shares (see "Setpositionsize")!! > > bo.EnterTrade(i, sig.Symbol, True, sig.Price, sig.PosSize); > > > > ----- Original Message ----- > From: Tomasz Janeczko > To: amibroker@yahoogroups.com > Sent: Wednesday, July 22, 2009 7:33 PM > Subject: Re: [amibroker] Still - using CBT the first time > > > > > Use floor() function instead of round(). > > http://www.amibroker.com/f?floor > > Best regards, > Tomasz Janeczko > amibroker.com > ----- Original Message ----- > From: Markus Witzler > To: amibroker@yahoogroups.com > Sent: Wednesday, July 22, 2009 7:17 PM > Subject: [amibroker] Still - using CBT the first time > > > Hello all, > > I intend to use CBT to compute proprietary position size (number shares instead of percentage of equity or amount of money) as I wrote before. > > Now that AB has been told (thru assistance of Bruce, Mike and TJ ) to use "number of shares", I still don´t know why it doesn´t output the proper size: > > The formula for computing sharesize is as follows (entire code see further below): > > sharesize=round(((Heat*bo.cash)/(y*ATRmultiplier))/250)*250 > > According to my data, I read for a specific day > > where y=3.115 ATR multiplier=5 heat=0.1 bo.cash=1000000.00 > > which should result in a sharesize of 6,500. But instead, AB computes a sharesize of 6,750. Thus, I´m off by one unit of 250 lots. > > Maybe it´s due to the calculation of y? Could someone please help me with this? It probably caused by the AB´s rounding but I just can´t figure it out. > > If so, I will provide the data for the S&P contract I use so that the results I get could be reproduced. > > Thanks very much > > Markus > > - - - - - - - - - - - - - - - - - - - - - - - - - - > > /*Setting different options to clarify or override backtester settings*/ > > //SetOption("InitialEquity", 1000000.00); > > SetOption("UsePrevBarEquityForPosSizing", True); > > //SetOption("MinShares", 250); > > SetOption("CommissionMode", 2); //$$ per trade > > SetOption("Marginrequirement", 100); > > SetOption("InterestRate",0); // account doesn´t earn interest for cash balance! > > SetTradeDelays( 1, 1, 1, 1 ); > > > > //RoundLotSize = 250; > > Heat= 0.1; // provided by ED > > ATRMultiplier=5; //provided by ED > > TC150=150; > > TC15=15; > > n=20; // Time Constant used in ATR lag computation > > x=(n+1)/2; > > > > /* Calculation of TC150 EMA and TC15 EMA*/ > > SetBarsRequired( sbrAll, sbrAll ); > > EMA150[0]=Close[0]; > > EMA15[0]=Close[0]; > > for( i = 1; i < BarCount; i++ ) > > { > > EMA150[i]=EMA150[i-1]+(Close[i]-EMA150[i-1])*2/(TC150+1); > > EMA15[i]=EMA15[i-1]+(Close[i]-EMA15[i-1])*2/(TC15+1); > > > > } > > > > /* Controlling trade price*/ > > BuyPrice=Open+(High-Open)/2; //i.e. 50% slippage > > SellPrice=Open-(Open-Low)/2; //i.e. 50% slippage > > > > /*Trading rules and optimization*/ > > > > Buy= Cum(1)>=25 AND Cross(EMA15, EMA150); > > Sell= Cross(EMA150, EMA15); > > /* Graphic output*/ > > Plot(EMA150, "My expon. Lag 150", colorGreen, styleLine); > > Plot(EMA15, "My expon. Lag 15", colorRed, styleLine); > > Plot (Close, "Bar Chart", colorBlue, styleBar); > > EMA15 = Optimize("EMASlow", 50, 1, 150, 1 ); > > EMA150 = Optimize("EMAFast", 150, 20,400, 1); > > Buy = ExRem( Buy, Sell ); // to exclude redundant signals > > Sell = ExRem( Sell, Buy );// to exclude redundant signals > > > > /* Position sizing - volatility based*/ > > trhelp[0]=0; // trhelp is being initialized > > TRcombined[0]=0; // TRcombined is being initialized > > ATRExpLag[0]=High[0]-Low[0]; // ATRExpLag is being initialized; seed value is the 1st day´s high-low range per Ed´s definition > > > > for( i = 1; i < BarCount; i++ ) // here, the Average True Range (20 days) is coded by using a loop > > { > > trhelp[i]= Max(High[i]-Low[i],High[i]-Close[i-1]); //trhelp is a helping variable for calculating ATRcombined. ATR() function cannot be used. > > TRcombined[i]= Max(Close[i-1]-Low[i],trhelp[i]); //TRcombined is the actual TrueRange. > > ATRExpLag[i]=ATRExpLag [i-1]+ (TRcombined[i]-ATRExpLag[i-1])/x; // This is the 20-day expon. moving average of the ATR > > > > } > > ATRExpLagRounded=round(ATRExpLag*1000)/1000; //here, I round on the 3rd digit. > > AddToComposite(ATRExpLagRounded, "~ATRExpLagRounded_"+Name(), "V", atcFlagDefaults | atcFlagEnableInBacktest); > > > > Filter = GroupID() != 253; // Exclude "group 253" in which composites are being saved/ > > > > SetCustomBacktestProc(""); > > if (Status("action") == actionPortfolio) > > { > > bo = GetBacktesterObject(); // Get backtester object > > bo.PreProcess(); // Do pre-processing > > > bo.cash=1000000; // muß das hier stehen oder im indexierten loop; dann aber wäre doch bei jeder iteration das > > // initial equity UND DAMIT auch das old cash immer wieder 1000000.00!!?? > > My_total_equity=0; > > Value_open_positions=0; > > Heat=0.1; > > ATRmultiplier=5; > > > for (i = 0; i < BarCount; i++) // Loop through all bars > > > { > > for (sig = bo.GetFirstSignal(i); sig; sig = bo.GetNextSignal(i)) > > { // Loop through all signals at this bar > > // Long trades > > ATRexRounded = Foreign("~ATRExpLagRounded_"+sig.Symbol, "V"); // Get symbol's AtrExpLagRounded array > > ATRex = ATRexRounded[i]; // Reference a value in the array > > > { > > if (i<=0) > > y=ATRexRounded[i]; > > else > > y=ATRexRounded[i-1]; > > > } > > if (sig.IsEntry() && sig.IsLong()) // Process long entries > > > { > > sharesize=round(((Heat*bo.cash)/(y*ATRmultiplier))/250)*250; // i.e. computing # of shares/contracts > > > > // sig.possize=sharesize*sig.price; > > > //Sharesize formula needs to be modified for stocks if lot size differs!! > > > sig.possize=-2000 - sharesize; // i.e. setting back # of shares into signal object!! Possize must be < "-2000" > > // to mean # of shares (see "Setpositionsize")!! > > > bo.EnterTrade(i, sig.Symbol, True, sig.Price, sig.PosSize); > > // wird hier die cash position durch Eingehen des Trades bereits autom. auf neuen Stand gebrachtoder muß das eigens codiert werden? > > //Das mittels addcustometric (cash position prüfen)! > > // oder müßten die Adcustommetric erst nach sämtl. long- und short signalen stehen?? > > /* > > trade.AddCustomMetric("initial equity", initial_equity); //zur Kontrolle und graphische Aufbereitung > > trade.AddCustomMetric("Cash position", bo.cash); > > trade.AddcustomMetric("Position size [shares]", trade.shares); > > trade.AddCustomMetric("Position Value", sig.possize); > > */ > > > } > > else > > { if (sig.IsExit() && sig.IsLong()) // Process long exits (cover longs) > > > //die position size muß doch hier nicht angegeben werden, da vom system bekannt, oder? > > > bo.ExitTrade(i, sig.Symbol, sig.Price); > > // Achtung, daß bei Exits die Cash position korrekt ausgewiesen wird, oder ob man das manuell codieren muß > > } > > > // bo.HandleStops(i); // Process programmed stops or applystop at this bar > > } // End of for loop over signals at this bar > > > bo.UpdateStats(i, 1); // Update MAE/MFE stats for bar > > bo.UpdateStats(i, 2); // Update stats at bar's end > > } // End of for loop over bars > > bo.PostProcess(); // Do post-processing > > /*AddToComposite( My_total_equity, "~~~My_total_equity", "X", atcFlagEnableInPortfolio | atcFlagDefaults ); > > AddToComposite( trade.shares,"~~~Position size [shares]", "X", atcFlagEnableInPortfolio | atcFlagDefaults ); > > AddToComposite( sig.possize, "~~~Position Value", "X", atcFlagEnableInPortfolio | atcFlagDefaults ); > > AddToComposite( bo.cash, "~~~Cash position", "X", atcFlagEnableInPortfolio | atcFlagDefaults ); > > AddToComposite( Value_open_positions, "~~~Value of open positions", "X", atcFlagEnableInPortfolio | atcFlagDefaults ); > > */ > > } > > /* Exploration output*/ > > AddColumn(ATRExpLagRounded,"ATRExpLagRounded",1.5); >