Page 1 of 27
Amibroker Backtester Personal ramblings, muses, tips and notes on becoming familiar with the Amibroker Backtester This document is a personal aide de memoire and not designed to replace the User Manual or Help files which can be consulted at all times. No attempt has been made to be exhaustive or complete
Abbreviations: AA = Automatic Analysis; AB = Amibroker; AFL = Amibroker Formula Language; CCY1 = First Currency of Pair; CCY2 = Second Currency of a Pair; FX = Foreign Exchange; GUI = Graphic User Interface; PnL = Profit and Loss; TJ = Tomasz Janeczko, creator of Amibroker; USD = United States Dollar
Introduction
In attempt to get to grips w ith what the backtester does, and how it does it, I have recorded some notes here together in one document for future reference, which may be of use to others. Having done this I am at last somewhat more comfortable with the prospect of making some sense of results of backtests, rather than just running some buy and sell conditions and wondering if I could believe the results, not because of any fault of Amibroker, but through ignorance on my own part as to how I could control what was happening under the bonnet as it were. This document is aimed at being one stop shop for me to come back to any time in the future, and may be of some use to other people new to the Amibroker backtester. I make no attempt to get involved wi th more advanced concepts such as the Custom Backtester interface, which has been covered elsewhere, rotational trading (fund switching) and no attempt at system creation or money management. GETTING STARTED
When we just enter some simple code into the AA window: Cross( ( Close, EMA EMA( (Close,45 45)); )); Buy = Cross = Cross( Cross ( EMA( EMA ( , 45), 45 ), Sell Close Close);
and then click Back Test we should e xpect to get some results. Therefore FIRST basic issue is we NEED buy and sell conditions, and the backtester should run. If it does not run, there are other issues in the settings or AFL that are incorrect, such as i nsufficient funds, too big a position size, or not enough information for AFL to use in its calculations. A discussion of these follows. For FX there are specific settings, which we will discuss later in the Forex section. SETTINGS CONUNDRUMS
We can backtest in one of three ways: one ticker at a time: Just select Apply to Current Symbol or do an individual Backtest which can be run on a watch li st or the whole database. This runs the buy sell code per ticker, i.e. it runs through Ticker#1 and applies all the buy sell signals, then moves to Ticker#2 and so on. This can be useful to see which Ticker a given set of Buy Sell signals works best for.
Page 2 of 27
Or we can do a Portfolio backtest which emulates real trading conditions more accurately. Here AB looks at all the tickers i n the Watch list and bases entries and exits not only according to coded buy/sell signals but also according to other rules (such as Money Management rules, and Preferred Ticker filter). So for example we can tell AB to only use a given percent of capital per trade, we can limit the number of open positions, and so on. More importantly, to make the best use of the Portfolio backtester we can tell AB which ticker to select if there are more than one buy candidates, based on user preferences. So if there are 10 Buy candidates, but only enough funds for two, which should AB choose? This is set with PositionScore. (If this is not set, then AB just chooses the available tickers alphabetically). This function can be used for example to tell AB to select in order of lower priced tickers, or volume or volatility etc. Portfolio level backtesting therefore refers to position sizing based on the current equity value of your account. We can trade more than one ticker at a time. To effect this in Amibroker we need to define TWO things: a. the maximum number of open positions. MaxOpenPositions in the AFL overrides the SETTINGS GUI b. the PositionSize variable in the AFL If we set Current Symbol in Automatic Analysis then Individual backtest gives the same results as Portfolio level backtester. If we select All Symbols or Use Filter selection, then Backtest by default is portfolio level one. Else if we click I ndividual backtest it goes through each ticker one by one. So for most purposes we should just use the Back Test button, which defaults to Portfolio level backtesting, and we need to set the rules up correctly. If we are trading Current symbol it w ill default to the current symbol. AFL SETTINGS
Let us go through the available backtest settings and see what we can do with them. The settings can be placed in one of a number of places. 1. The Backtest Settings GUI window. (Go to Analysis, Automatic Analysis, Settings) 2. The AFL code used for the Backtest (Enter code into the AFL editor) 3. Specific data related to the Ticker i nvolved, as defined in Symbol, Information menu. Some Some Some Some Some
settings can only settings can only can be set in AFL can be set in AFL can be set in AFL
be set in AFL. be set in the Settings window. and the Settings window. and Information window. and Information window and the Settings window.
In addition, once we have run a backtest we can view the trades in the Results part of the AA, but we can also view the settings we used, by clicking the Report, Settings link. These are saved with the report in the directory Program Files\Amibroker\ Reports and can be viewed from Report, View Last Report or Report, Report
Page 3 of 27
Explorer. Note, however, that not all of the settings are stored i n this Report Settings location. Let’s go through some (most) of the settings one by one and then create a summary table. SetFormulaName("TemplateBTShares"); //can be any length but no punctuation is to be included. This helps to identify systems or versions of systems, for easy reference when you review them later. SetBackTestMode(Regular); // use this for most backtests, this is the default: redundant signals are removed. Timeframeset(InDaily); // does not override the Settings Inweekly. // SO THE TIMEFRAMESET HAS TO BE SET IN THE SETTINGS WINDOW and is not something we can // code for in the AFL. T’WOULD BE GOOD TO HAVE THE ABILITY TO SET THIS IN THE AFL. BUT: This cannot be done from AFL: see TJ’s response in post #114929 of the Yahoo Groups Amibroker user group. SetOption(“InitialEquity”,10000); // this OVERRIDES the Settings value. We have to have this defined in one of these // places. AB looks for this First in the Backtester SETTINGS Graphics User Interface (GUI) // then looks for it in the AFL code. It gives precedence to the setting in the AFL code. Although the // advice given by TJ in the past is to set this to the same value in both places, in my testing the AFL setting // is given predominance. SetOption(“InterestRate”,0); // Set this to zero to show only the results of the actual trades and not interest accrued, // to accurately assess your system. SetBarsRequired(10000,0); // According to TJ this is only needed if you use dll files or other script. // If you only use pure AFL this is not needed. // Note also that the first figure references past bars. // the second parameter references future bars so if this is greater than zero, we will get a Check: // references future bars error. // therefore the second parameter needs to be set to zero. SetOption(“CommissionMode”,0); // exactly equal to, but OVERRIDES, the Settings Value SetOption(“CommissionAmount”, 15); // exactly equal to, but OVERRIDES, the Settings value SetTradeDelays(1,1,0,0); // or whatever settings we need: These OVERRIDE the Settings tab PositionSize = 1000; // does not appear in Settings GUI. Therefore must be set in AFL. If not defined in AFL // then full equity is used for each trade. SetPositionSize(value , method); // replaces the above with more advanced features. See the help files.
Page 4 of 27
setOptions(“MaxOpenPositions”,3); // changing this on its own makes no difference to the trade results. This must be used in conjunction with // PositionSize. The AFL OVERRIDES the Settings window value. // Only works with portfolio level Backtester if we choose Apply to All symbols, or Use Filter, i.e. not if we // only select one symbol. SetOption("MinShares",1); // overrides SETTINGS: defines minimal number of shares that can be bought SetOption("MinPosValue", 500); // overrides SETTINGS: defines minimal dollar value of desired position SetOption("UsePrevBarEquityForPosSizing",True); // Set to False to use current equity for Position Sizing. AFL overrides SETTINGS. SetOption(“AllowSameBarExit”,True); // AFL overrides SETTINGS. SetOption(“PriceBoundChecking”,True); // Can only be set in AFL. Leave True. Don’t see any reason at the moment // to set this to false, but I am sure others may see a need for this. SetOption(“PortfolioReportMode”,0); // defaults to the Trade list, I see no reason at present to change this. // AFL setting OVERRRIDES the Settings in GUI. RoundLotSize =1; // As per help files use 1 for shares and futures, or use fractions for mutual funds. // Per symbol setting overrides global values in SETTINGS GUI // AFL overrides SETTINGS. // 1 is needed for shares to ensure we do not buy fractional shares. // if we want to buy shares in parcels of multiples of 10, set this 1 0. // if we want to buy shares in multiples of 100, we set this 100 and so on. // if we set this 0 (zero) backtester will buy fractions of shares. TickSize = 0.01; // TickSize is a special case. Settings can be made Globally (in SETTINGS) or per symbol, but do not override // the BuyPrice or SellPrice arrays. Mainly of use therefore in conjunction with Applystops to make sure // entries and exits take place at allowed true prices and not fictitious calculated levels. If we do not use // Applystops, we should not need to specify TickSize. // See also TickSize under the Forex section for further details. SetOption(“FuturesMode”,0); // needs to be False for shares, and set to True for Futures and Forex backtesting // We need to set this in SETTINGS GUI. // This setting is not entirely consistent with the rules of AFL overriding most of the settings. The only // correct place to set this is in the SETTINGS GUI. This controls the column title (Contracts or Shares) and // the way the profit is calculated. If we use the AFL to set this to ON, then for Shares database and shares // code, it will change the way the calculation is done but will not change the Column header from Shares // to Contracts. // Advice: Do not try and set this in the AFL. If we are to use the SetOption(“FuturesMode”, ..); in AFL we
Page 5 of 27
// use this as a reminder to ourselves to switch the SETTINGS GUI tick box to the correct value. // to see what this does, see the Forex section. // This is best set in the SETTINGS GUI, under Analysis, Settings, General and (de)selecting the tick box. // This does three things: // a. When ON, the backtest column header is CONTRACTS, when OFF the header is SHARES // This is controlled from Settings. // b. Changes the way AB backtester does its calculations for profit and loss. This is primarily // // //
controlled from Settings but can be overridden with AFL setting. c. Changes the output to Report, Settings window. This is controlled from the Settings but overridden by AFL.
// Therefore to get correct calculations, column header and Report Settings output we should restrict // ourselves to the SETTINGS GUI. If we wish to add this to the AFL we can use this as a reminder to // ourselves to ALSO make the correct switch in SETTINGS GUI. // This all seems convoluted but is probably by design, so that if we leave an FX database and open a shares // database and leave the Futures Mode tick box checked, and then run a shares backtest with // SetOption(“FuturesMode”, False) in the AFL, the calculations at least will be correct but the column header // will not be: the lesser of two evils. The reverse also applies. SetOption(“AccountMargin”,100); // for shares traded with no leverage, we want to leave this at 100 // can be set in SETTINGS or AFL. // AFL settings OVERRIDE the GUI settings. // the AFL value is read into the backtester report settings window. PositionScore = 100 – RSI(); // the highest absolute value gets selected first, so this code means those tickers with the lowest RSI() // PositionScore = 1 / C; would select the tickers with the lowest price first. SUMMARY OF SETTINGS
So to summarize the available settings: Settings that can only be set in AFL
SETTINGS THAT CAN ONLY BE SET IN AFL SetBarsRequired(10000,0) SetFormulaName(“Name”) SetBackTestMode(Regular) PositionSize SetOption(“PriceBoundChecking”,1) PositionScore
Can be set in AFL ? Yes Yes Yes Yes Yes Yes
Can be set Elsewhere ? No No No No No No
Appears in Report ? Yes under Formula Yes Under Formula Yes Under Formula Yes Under Formula Yes only in Formula Yes only in Formula
Table 1.
Settings that be set in more than one place in Amibroker SETTINGS THAT CAN BE SET IN MORE THAN ONE PLACE
SETTINGS GUI
SYMBOL INFORMATION
AFL Code
Precedence
“InitialEquity”
AB looks at Settings first
N/a
Then AB looks for AFL value:
Given to AFL value
Appears in Report ? Formula and
Page 6 of 27
this takes precedence over the other two Then AB looks for AFL value
Settings
“CommissionMode”
AB looks at Settings first
N/a
“CommissionAmount”
AB looks at Settings first
N/a
Then AB looks for AFL value.
SetTradeDelays
AB looks at Settings first
N/a
Then AB looks for AFL value
“MaxOpenPositions”
AB looks at Settings first
N/a
Then AB looks for AFL value
“MinShares”
AB looks at Settings first
N/a
Then AB looks for AFL value
“MinPosValue”
AB looks at Settings first
N/a
Then AB looks for AFL value
"UsePrevBarEquityForPosSizi ng"
AB looks at Settings first
N/a
Then AB looks for AFL value
“AllowSameBarExit”
AB looks at Settings first
N/a
Then AB looks for AFL value
“AllowPositionShrinking”
AB looks at Settings first
N/a
Then AB looks for AFL value
“InterestRate”
AB looks at Settings first
N/a
Then AB looks for AFL value
“AccountMargin”
AB looks at Settings first
N/a
Then AB looks for AFL value
Given to the AFL value
MarginDeposit =
N/a
Symbol Info
Then AB looks for AFL value
RoundLotsize =
AB looks at Then it looks Settings first at Per symbol info
Given to the AFL value Given to the AFL value
“PortfolioReportMode”
AB looks at Settings First AB looks in settings first
“FuturesMode” Special case: Set in SETTINGS alone OR in both SETTINGS and AFL must match. Ticksize
AB looks here first. This is a
Then AB looks for AFL value
N/a
Then looks for AFL value
N/a
Then looks to AFL
Then AB looks here. If set this overrides
Then AB looks here
Given to AFL value Given to the AFL value Given to the AFL value Given to the AFL value Given to the AFL value Given to the AFL value Given to the AFL value Given to the AFL value Given to the AFL value Given to the AFL value
Given to the AFL value Calculation s given preference to the AFL value Given to the AFL value for
Formula and Settings Formula and Settings Formula and Settings Formula only Formula only Formula only Formula only Formula only. Formula only. Formula and settings but displays the value from the AFL Formula. The AFL value is shown in Report Settings. Formula Settings (can be wrong value if overridde n by) AFL value in Formulas Only in Formula In Formula + also in Settings. In Formula. Settings
Page 7 of 27
global “default” value
the Global value
calculations
only read from the Global value.
Table 2.
Settings that can NOT be set in AFL These can NOT be set in AFL Periodicity Positions: Long or Short
Can be set in AFL ? No No
Set Where SETTINGS GUI SETTINGS GUI
Table 3.
Positions Long or Short does not have an AFL switch but is obviously controlled by the Buy and Sell rules. However if you have Long and Short conditions in your code, you need to go to Settings and Select Positions, Long, Short or Long and Short. That way you can separate out the two to assess the results of the Long trades and Short trades i ndependently. So for all Backtests there will be some settings that need to be set via the SETTINGS GUI and some that can be set with the AFL. The last thing to be said about these is that if need be we can create an exploration to display all of these settings using the GetOption function e.g. Addcolumn(GetOption(“MinPosValue”),”MinPos”,6.0);
Controls over ENTRIES
Entries depend on the Buy conditions and are coded up in AFL in the AA window. This document does not cover AFL or system design and so no more will be said here. Controls over the EXITS
We can control our exits in one of two ways. 1. We can use the Sell Condition as coded in AFL 2. In addition, AB provides us more flexibility in setting the exits by use of stops. There are in-built stops which we can set via the Settings GUI and there are Applystops which we code up in AFL. They perform the same task. FIRST, we can use the built-in stops from the GUI in the Backtester Settings. These are self explanatory and can be looked up in the help files. These values will show up in the Backtester report page for Settings. SECOND, we can use the Applystops in the actual AFL, which gives us the ability to use Param and Optimize functions on these. [Note that although these values work in the Backtester, and they override the values set in the SETTINGS window, they do NOT show up correctly in the Records, Settings page, or at least I have not found a way to get them to do that. In addition the setting for StopTypeNBar does not appear in the Report,
Page 8 of 27
Settings link.] Applystops
The functions and commands of the Applystops can be obtained from the help files. Moreover the pattern is the same: the AFL code for any one type of stop overrides the Settings GUI. So if we have StopTypeLoss set in the AFL and StopTypeLoss set in the SETTINGS GUI, and no other stops, then control over the exits passes to the AFL code.
Fig 1.
So we see that ALL the individual ApplyStop parameters in the AFL will override those in the SETTINGS GUI. From tests we can show that: StopTypeLoss: StopModeDisable, StopTypePercent, StopTypePoint: control passes to the AFL StopTypeLoss: Amount, ExitAtStop, and ReEntryDelay: control passes to the AFL StopTypeProfit: StopModeDisable, StopTypePercent, StopTypePoint: control passes to the AFL StopTypeProfit: Amount, ExitAtStop, and ReEntryDelay: control passes to the AFL StopTypeNBar: Amount (N-Bar exit ) and ReEntryDelay: control passes to the AFL. However, if we have different types of stops in the SETTINGS GUI and the AFL, then whichever one gets hit first will be enacted by AB, simulating real trading. So for the situation in Fig 2 , where we coded StopTypeLoss in both the AFL and SETTINGS GUI, together with N-bar stop in the SETTINGS GUI, the exit for the StopTypeLoss is controlled by the AFL, unless the N-bar stop gets hit first, in which case this exit gets taken.
Page 9 of 27
Fig 2.
To avoid any confusion we may choose to set the stops in either the AFL, or the SETTINGS GUI. Using the AFL allows more control and flexibility, especially if we are looking at Optimizing the amount parameter. Remember to set ExitAtStop correctly to suit your trading plan. [As an aside, the Backtester Report Settings link seems to read the values from the SETTINGS table, EVEN IF they are disabled, OR if they are enabled. So if we need to read the ApplyStop Amounts in the Report Settings w indow then we would need to have these entered in the SETTINGS window. It will not show the AFL coded Applystops, although these are the ones used by the backtester.] Sample Code
Now that we have defined all or most of the settings that we need to get accurate backtest results, we can use all of the necessary AFL commands before our actual systems code. This may look something like the following. // // // // //
Template BT Shares.afl ChrisB Jan 2008 You can NOT select the Time Period here, Ya Haf Ta Go To SETTINGS. SetFormulaName("SharesUnNamed");//Set this in each new backtest code: can be any length but no punctuation
SetBacktestMode(backtestRegular);// removes redundant signals
Page 10 of 27
SetBarsRequired(10000,0);// only needed if you use dlls or external script SetOption("InitialEquity",10000);//overrides SETTINGS SetOption("CommissionMode",2);//overrides SETTINGS //0 = Commision Table ; 1 = percent ; 2 = $ per trade; 3 = $ per share/contract SetOption("CommissionAmount",19.95);//overrides SETTINGS; used dollar value for Shares. SetTradeDelays(1,1,0,0);//overrides SETTINGS PositionSize = 1000;// POSITIVE = dollars; NEGATIVE = Percent // CANNOT be set in SETTINGS RoundLotSize = 1;// overrides SETTINGS; use default of 1 for shares. SetOption("MaxOpenPositions", 3);//Must be used with PositionSize. //overrides the SETTINGS //only works for Portfolio level testing with > 1 symbol SetOption("MinShares",1);//overrides SETTINGS; defines minimal shares to be bought SetOption("MinPosValue", 500);//overrides SETTINGS SetOption("AllowPositionShrinking", True); //in case there is not enough cash SetOption("UsePrevBarEquityForPosSizing",True);// False to use current equity for Pos Sizing SetOption("PriceBoundChecking",True);// Always set to True. SetOption("AccountMargin",100);//100 = no margin for shares; 50 = for 50% margin //NOT the same as MarginDeposit for futures. SetOption("HoldMinBars",0);// disables exits for this number of bars SetOption("HoldMinDays",0);// disables exits for this number of Calendar days //exits SetOption("ReverseSignalForcesExit",False);//True for stop and reverse systems SetOption("AllowSameBarExit",True);//Use True as default, to allow this SetOption("ActivateStopsImmediately",True);// Needed if you enter on Open. Not needed if // you enter on Close SetOption("InterestRate",3.2);//Overrides SETTINGS SetOption("FuturesMode",False);//False for Shares, True for FX: // Set also in SETTINGS GUI. //reports SetOption("PortfolioReportMode",0);// 0-Trade list: 1- Detailed Log; 2- Summary; // 3- No output
To save time and coding we can save this as a Template file, e.g. Template_BT_Shares.afl in the chosen directory (by default C:\Program Files\Amibroker\Formulas\Include), and then just use the following code at the beginning of all our backtest files #pragma nocache #include
This will run the above settings from the named file and then we can concentrate only on coding up the system. SETTING THE PRICES AT THE BUY AND SELL
Once we have defined our rules for entries and exits, we need to tell AB backtester at what prices to open and close these trades. To do this we define BuyPrice, SellPrice, (and ShortPrice and CoverPrice for short positions). We can do this in the SETTINGS Trades Tab but also from the AFL. BuyPrice = SellPrice = ShortPrice = CoverPrice = 0pen; If this is left out it defaults to the SETTINGS values. Once again the AFL values OVERRIDE the SETTINGS values. DELAYS
Based on our trading system we should next aim to define WHEN Amibroker simulates the Buy and Sell orders: we can do so in the SETTINGS Trades GUI,
Page 11 of 27
or in AFL. We can for example use delays of Buy, Sell, Short and Cover equal to 1, meaning we effect these trades on the bar (day) after the signal. Or we can leave these set to 0 as in SetTradeDelays(0,0,0,0); and then use Ref function to tell AB to take the trade on the next bar(day), for example: Buysignal = Cross( EMA(C,30) , Close); Buy = Ref(Buysignal,-1) ;
Separating out the buysignal and the buy, allows us to be better able to plot these signals and entries on the chart for visual confirmation (see next section) Once again, the AFL values used with SetTradeDelays OVERRIDE the SETTINGS values. CHECKING THE SIGNALS ON THE CHARTS
In o r d e r t o c h e c k t h a t o u r c o d e i s t e l l i n g A B t o d o w h a t w e e x p e c t i t t o , w e need to be able to check on the charts where, when and at what level the buy signals, entries and exits occurred. There are two ways we can do this: Method 1. T h e f i r s t w a y i s t o u s e t h e i n b u i l t f e a t u r e o f A B t o d i s p l a y t h e B u y , Sell, Cover or Short arrows on the Price Chart. Method 2. S e c o n d l y , w e c a n c o d e u p s o m e a r r o w s ( o r D i g i t s ) o n t h e C h a r t s using the PlotShapes function. So Firstly, to show the inbuilt buy and sell signals on the charts we need to enable the chart settings to show arrows. We can do this in one of two ways: a. on the Price chart (or any other indicator chart) right click, Param, Axes and Grids, Show trading arrows, choose Yes. This tells AB we want to see the trading arrows on the Charts. Or … b. when you create code for a chart (as in indicator builder, now called formula editor) use SetChartOptions(0,ChartShowArrows); This sets the chart default to show Trade Arrows. This can be toggled off by going to the chart, right click, select Axes and Grids, Show trading arrows, No. In the Backtest results list, we can then right click the Results list and select a. Show arrows for all raw Signals, or b. Show arrows for actual trades, or c. Show current trade arrows. The desired arrows will then appear i n their correct place on the charts. AB displays Buy signal as lime green up arrow, and sell arrow as Red Down Arrow. (For Shorts the entry is a hollow red down arrow, and the Cover is hollow lime green up arrow) Do the arrows show only on native AB charts, or can they display on our own charts that we have code up in Formula Editor? T h e a r r o w s w i l l d i s p l a y o n A n y o r A l l c h a r t s i f a. we have run the backtester and our settings are correct or realistic b. trades were actually taken c. Show trading arrows (or SetChartOptions(0,ChartShowArrows) is enabled.
Page 12 of 27
On Price charts we just need to make sure the Show trading arrows is enabled for each chart. Then run backtest, ri ght click the reports list and select Show Arrows. If we were to add a new chart after running a Backtest, we repeat the same: just making sure that Chart has Show trading arrows enabled, go to the Reports list and select which arrows we wish to see. Note these above details are for Buy and Sell orders AND for exits based on the Applystops. No extra coding is needed for AB to show an exit based on Applystops: however, the in-built exit arrow in AB does not tell us why an exit was taken, but just points to the bar where the exit occurred. So when we have coded exits based on one of a number of Applystops (perhaps together with a regular Sell signal) these will all be displayed as the regular exit arrows in the Chart when we select Show Arrows for actual trades. Which Exit?
How then do we know why any one exit was taken? When you look at the Backtest report you can easily see why any one position was closed:
Fig 3.
The type of stop that closed the position appears in brackets in the Trade column, and is read by AB from stops set in AFL or via the SETTINGS GUI. However if we wish to see on the charts which exit rule caused the position to close, i.e. the regular Sell command or which one of the ApplyStop functions, then we need to use Method 2 by adding some extra code in the AFL. This is done by using the Equity(1) call and the PlotShapes function. This is the required sequence as per TJ: 1. 2. 3. 4.
Buy Sell signals Applystops as needed. equity(1); PlotShapes.
The Equity(1) has the purpose of looking back at the type of exit that was taken ,so that we can plot this on the charts using the PlotShapes function.
Page 13 of 27
These are the rules for PlotShapes: PlotShapes( "reason" PlotShapes( "reason" PlotShapes( "reason" use // a layer other disabled) PlotShapes( "reason" PlotShapes( "reason"
* shapeDownArrow , // say why to plot the shape . . . * shapeDownArrow , colorRed , // set color of the shape . . . * shapeDownArrow , colorRed , 0, // to the selected layer ( if we than default, we should make sure we do not have that layer * shapeDownArrow , colorRed , 0, H, // position referenced to the High * shapeDownArrow , colorRed , 0, H, -10) // 10 pixels above the High.
Remember that to view the inbuilt Buy and Sell arrows we need to Run the Backtester, have Show arrows enabled on the Chart and then Right click the results list and choose Display Arrows. Because the PlotShapes are plotted as an indicator they do so independently of the backtester, and can be displayed without having run the Backtest. To get the backtest arrows to match those we have plotted however, w e should not forget to run the backtest as well, especially once we have adjusted the PlotShapes code or ApplyStop code. The Equity(1) function l ooks at the exits based on the inbuilt stops or ApplyStop to see which type of stop w as used for the exit, and allows these to be displayed on the chart (or in an Exploration), according these rules: 2 3 4 5 6
= = = = =
StopTypeLoss StopTypeProfit StopTypeTrailing StopTypeNBar “Ruin stop”
Also from the help files, if more than one type of stop signal is received on the same bar, this is the order of precedence. If two or more different stops are triggered on the VERY SAME bar then they are evaluated in this fixed order: Fixed Ruin stop (loosing 99.96% of the starting capital) Max. loss stop Profit target stop Trailing stop N-bar stop
Therefore to make things a little easier to decipher on the charts we can plot those as actual numbers using the ShapeDigitx function, with the code looking like this: SetTradeDelays(0,0,0,0); Buysignal = Cross ( EMA (C,30) , Close); Buy = Ref (Buysignal, -1) ; Sellsignal = Cross ( RSI(21),56); Sell = Ref( Sellsignal,-1); ApplyStop ApplyStop ApplyStop ApplyStop
( ( ( (
stopTypeLoss , stopModePoint , 0.5 , 1 , 0 , 1 );// = 2 stopTypeProfit , stopModePoint , 0.9 , 1 , 0 , 1 ); // = 3 stopTypeTrailing , stopModePoint , 1 , 1 , 0 , 1 ); // =4 stopTypeNBar , stopModeBars ,10); // = 5
Equity(1); Plot (C ,"" , colorBlack , 64); Plot (EMA(C,5), "ema 5", colorRed ,1); Plot (EMA(C,30),"ema 30",colorBlue ,1); Plot (EMA(C,200), "ema 50", colorGreen ,1); PlotShapes ( Buysignal * shapeHollowUpArrow , colorBlue ,0,L,-10); PlotShapes ( Buy * shapeSmallCircle , colorLime , 0 , BuyPrice ,0);
Page 14 of 27
PlotShapes( Sellsignal * shapeHollowDownArrow , colorRed , 0 , H, -25); PlotShapes( IIf(Sell==1, shapeDigit1 , shapeNone ), colorRed , 0 , H, 35); PlotShapes( IIf(Sell==1, shapeSmallCircle , shapeNone ) , colorRed , 0 , SellPrice , 0); PlotShapes( IIf(Sell==2, shapeDigit2 , shapeNone ) , colorRed ,0,H,20); PlotShapes( IIf(Sell==2, shapeSmallCircle , shapeNone ) , colorRed ,0, SellPrice ,0); PlotShapes( IIf(Sell==3, shapeDigit3 , shapeNone ) , colorLime ,0,H,45); PlotShapes( IIf(Sell==3, shapeSmallCircle , shapeNone ) , colorLime ,0,SellPrice ,0); PlotShapes( IIf(Sell==4, shapeDigit4 , shapeNone ) , colorGreen ,0,H,50); PlotShapes( IIf(Sell==4, shapeSmallCircle , shapeNone ) , colorGreen ,0,SellPrice ,0); PlotShapes( IIf(Sell==5, shapeDigit5 , shapeNone ) , colorBlack ,0,H,38); PlotShapes( IIf(Sell==5, shapeSmallCircle , shapeNone ), colorRed , 0,SellPrice ,0);
The last value in the PlotShapes function refers to the offset. For all plotted shapes a positive value shifts the shape up and a negative value shifts the shape down, except for shapes with Down already in the name (such as shapeDownArrow, shapeDownTriangle etc) in which this is the other way around. As explained in the help fil es, when we use shapeDownArrow we need offset of –30 to place the arrow above the Hi gh, but when we use ShapeDigit we need offset of 30 to place the digit above the High. [See also Help files for ShapePositionAbove.]
Page 15 of 27
On the chart below we have separated out the buysignal and the Buy and we can see … … … … … … …
the buysignal plotted as a hollow up blue arrow, the actual Buy day has the usual Lime Green up arrow from the Backtester a shape (here a small lime cir cle) at the BuyPrice the Sell signal plotted as a hollow down red arrow the red down arrow as the actual sell day, with the small red circle at the Sell Price and above that the plotted shape to tell us the reason for the exit.
Fig 4.
So now we can look at the Chart to see if our trades taken match what we intended in the code. If we prefer to view these with an Exploration we can use this code: Filter =Buy OR Sell; AddColumn( Buy , "buy"); AddColumn( Sell ,"sell");
which gives us the type of exit thus:
Fig 5
Page 16 of 27
FOREX backtesting
These are the settings we need to address for Forex backtesting 1. Futures mode 2. RoundLotSize 3. MarginDeposit 4. PointValue 5. Position size 6. TickSize Like the other backtest settings, we can set these in one of three places: Settings GUI for global settings, Symbol Information for symbol specific information or AFL. Note that some settings can be controlled in all three places, some in only two and some in only one. To be sure of correct USD backtest results we need to make sure all values are correctly set in the AFL, the GUI SETTINGS and the information sheet. Like the other settings there is an order of precedence, and we can use Addcolumn in an exploration to reveal the order of precedence by playing with the settings. Filter = 1;
AddColumn AddColumn AddColumn AddColumn AddColumn AddColumn
( GetOption("FuturesMode"),"FM", 1.0); ( RoundLotSize ,"RLS", 1.2); ( MarginDeposit , "Marg Dep"); ( PointValue ,"Pnt Val"); ( PositionSize , "Pos Size"); ( TickSize ,"ticksize",1.4);
AB looks for these values in this order and gives precedence in ascending order like so: Forex settings
SETTINGS GUI
TICKER INFORMATION
Futures Mode
AB looks here first
N/a
RoundLotSize MarginDeposit Pointvalue PositionSize TickSize
Settings first Then Info sheet Not available Info sheet first N/a Then info sheet N/a N/a AB looks at Settings Then AB looks at first. ** ticker specific Information which overrides global value
AFL Code Set this to the same at SETTINGS GUI Then AFL dominates* Then AFL dominates* Then AFL dominates* AFL only Then AB looks for AFL value*: this overrides the other two
Table 4. * AFL always dominates the settings placed elsewhere ** This is a global setting. TickSize is better to set in AFL or in Ticker info because it varies from currency to currency Why we need Futures specific settings
FIRST it is NB to understand we are not trading shares here, and we need to tell AB this, by switching Futures mode to ON. This can be done in the Settings GUI or in the AFL. When we trade shares, the Backtester will show a column header called Shares. When we trade futures/forex and enable Futures mode, this column header changes to Contracts.
Page 17 of 27
Fig 6.
So buy paying attention the title/header in this column we can easily see if we have Futures mode ON of OFF. So switching Future Mode ON displays the Contracts column in the Backtester results, which is the same as Lots in Forex.
Fig 7.
The other thing it does is that it recognizes that we are no longer dealing with shares where a. there is 1:1 relationship between a 1 point move and 1 dollar value b. we do not generally use leverage to the same extent, if at all. Therefore with Futures Mode ON we have to tell the AB Backtester what the dollar value of a Point move is, then we need to tell the Backtester what our
Page 18 of 27
margin per contract is, and then we need to tell the AB Backtester what our Position size is going to be. So when we enable Futures Mode, AB uses MarginDeposit and PointValue in the calculations that it uses to create the Report or Results. (See Fig 12) It needs us to tell it what these values are. This is because the dollar value per point move will vary per instrument traded, and in Forex can depend on the size of our Lots (regular, mini or fractional). So just like the USD value per pip changes, so does the USD value per Point. Moreover, to complicate things note that the USD value per pip changes as the currency prices moves up and down. In shares, a 1 point move i s a move from 12.00 USD per share to 13.00 USD per share or a move from 117.58 to 118.58 and so on. There is a linear relationship here because each dollar has 100 cents. However, when USDJPY moves from 119.00 to 120.00, which is a 1 point move, this is not a move of 1 dollar. This is in fact a move of 100 pips, and the dollar value of this move will depend on the USD value of each pip. Similarly a 1 point move i n the other non-JPY pairs with tick values of 0.0001 comprises a move of 10,000 pips. The value of each pip will then depend on the exchange rate of the currency at the present moment, which currency we trade in, whether we trade standard (1 00k) lots, minilots (10k) or fractions thereof. So if we took one regular L ot of USDJPY (100 000 USD), with the USDJPY currently at around 109.90 each pip would be worth about 9.15 USD. If we take 2 lots each pip is worth 18.30 USD. Now if we trade minilots (10 000 of the Base currency pair) these values would be different: 0.915 USD and 1.83 USD respectively. Moreover if our platform allows us to trade fractional lots e.g. 0.7 regular lots or even odd lots like buying 6 650 USDJPY this introduces more variables to the calculation of the PnL (Profit and Loss) in Dollars. So we specify this information by the PointValue, w hich can be set in AFL or in the Symbol, Information field. REPORTS in Dollars
Remember when we look at the Reports page the value in the Profit column can only have the correct Dollar value if we have the following settings correctly specified: 1. Futures mode ON 2. Specify the Pointvalue 3. MarginDeposit 4. Position size 5. RoundLotSize = 1; (tells AB to only take full Lots: if you have mini account or can use fractional units you may have a reason to change this) 6. TickSize
FuturesMode ON
Best set in the SETTINGS GUI: if we want to have this in AFL then we need to ensure this matches the GUI settings. PointValue: L e t u s q u o t e t h e h e l p f i l e h e r e w i t h a d d e d e m p h a s i s t o d r i v e t h i s home:
Point-value is per-symbol setting (definable in Symbol-Information window …) that determines the
Page 19 of 27
amount of profit generated by one contract for a one point increase in price. This means that for Forex we need to specify the Dollar value of a One Point move for One Lot. So for a standard 100 000 EURUSD lot this is calculated as follows: A One Point move is from 1.0000 to 2.0000 EURUSD This equals 10 000 pips From our trading platform we read that one Pip = 10 USD. Therefore a one point move is calculated as PointValue = 10 000 pips * 10 dollars per pip = 100 000 (USD) per lot. Currently for a 10 000 minilot in USDJPY the PointValue will be 0.915 per lot. Therefore PointValue = 100 * 0.915 = 91.5 USD. As currency exchange rates change, the value of PointValue will also slowly change over time for non US pairs. So for example if we backtest the EURJPY over the last 4 years where the pri ce moved from 127 to 168 using the PointValue for today, the backtest dollar values may not be correct in the earlier part of the test. Hence we may choose to test with results displayed in Pips. If we only backtest one currency pair we can set the PointValue in the AFL. But if we wish to test a number of currencies then we should use the Symbol, Information to set this, otherwise we would have to w rite some AFL code to determine PointValue per ticker. This could be easily done with the IIF or If functions or even fed in to Parameter, but it would seem just as easy to set this in the Information field. MarginDeposit
MarginDeposit is the amount of money you need to deposit to open a trade, and will be based on your account size, your leverage or trading platform margin, and your Lot size and number of Lots. MarginDeposit can be set in the Symbol I nformation field, or in the AFL. The AFL setting takes precedence. So for a standard 100 000 EURUSD lot at Margin of 1% this means we would have to place a deposit of 1 000 to open a 100 000 position and so we would enter 1000 for MarginDeposit. Next, we have to tell AB the full position size so it can do the calculations . Position size
To allow AB to complete the calculations, we need to specify PositionSize. 1. To start off with we can choose to only trade in single Lots. Then we just set the Position size to the same value as the MarginDeposit: PositionSize = MarginDeposit; Sample code would be: SetOption("FuturesMode",1); SetOption("InitialEquity", 100000); RoundLotSize = 1; TickSize = IIf( StrRight( Name(),3) == "JPY", 0.01, 0.0001); MarginDeposit = 1000; // for example for 100:1 leverage on standard lot PointValue = 915 ;// for pairs with JPY as counter currency PositionSize = MarginDeposit ;
Page 20 of 27
The backtester will then show 1 contract/Lot having been traded:
Fig 8. 2. I f w e w a n t t o b a c k t e s t w i t h m o r e t h a n o n e l o t w e h a v e t w o c h o i c e s .
a. We tell AB how many Lots we want to trade b. We tell AB the PositionSize we want as percentage of Equity and let i t work out the Lots needed. c. We tell AB the PositionSize we want in fixed Dollar amount and let i t work out the Lots needed. Assuming a standard 100 000 account trading standard 100k lots and 1% margin requiring a 1 000 deposit: a. Tell AB how many Lots to trade SetOption("FuturesMode",1); SetOption("InitialEquity", 100000); RoundLotSize = 1; TickSize = IIf( StrRight( Name(),3) == "JPY", 0.01, 0.0001); MarginDeposit = 1000; // for example for 100:1 leverage on standard lot PointValue = 915 ;// for pairs with JPY as counter currency NumLots = 3; PositionSize = NumLots * MarginDeposit ;
Fig 9.
[Or if we wish to Optimize the position sizing we could use: NumLots = Optimize("NumLots", 1,1,10,10; PositionSize = NumLots * MarginDeposit ; ]
b. Let AB work out the required number of Lots by defining the PositionSize as percent of Equity. Sample code would be: SetOption("FuturesMode",1); SetOption("InitialEquity", 100000); RoundLotSize = 1; TickSize = IIf( StrRight( Name(),3) == "JPY", 0.01, 0.0001); MarginDeposit = 1000; // for example for 100:1 leverage on standard lot PointValue = 915 ;// for pairs with JPY as counter currency PositionSize = -10; // this means 10% of equity
Page 21 of 27
Fig 10.
AB then works out the Number of contracts as PositionSize / MarginDeposit. AB takes 10% of account, calculated as 0.1 * 100 000 = 10 000 as the Position Size in Dollars. AB then divides this by the MarginDeposit: 10 000 / 1000 = 10 Lots Or we can use PositionSize = -20; // tells AB to use 20% of equity Position size will be 100 000 * 0.2 = 20 000 Number of contracts will be 20,000 / 1000 = 20 Lots. As the Equity changes so will the number of contracts traded. C. Let AB work out the Lots by defining a fixed dollar amount to trade. Again it works out the Number of contracts as PositionSize/MarginDeposit: SetOption("FuturesMode",1); SetOption("InitialEquity", 100000); RoundLotSize = 1; TickSize = IIf( StrRight( Name(),3) == "JPY", 0.01, 0.0001); MarginDeposit = 1000; // for example for 100:1 leverage on standard lot PointValue = 915 ;// for pairs with JPY as counter currency PositionSize = 12000; // this means 12,000 dollar position
Fig 11.
Here we have specified PositionSize = 12 000; Number of contracts will be 12 000 / MarginDeposit. So if MarginDeposit is 1 000 then we will expect to see AB open 12 Lots for us: Number of contracts = PositionSize/MarginDeposit = 12 000/ 1 000 = 12 Lots The number of contracts traded stays fixed as Equity changes. [As an aside I have avoided using SetPositionSize in FX; I have not tested this but somehow suspect it internally looks at some of the other FX values and we could land up with double entries in the calculations.] Calculations
Having told AB to use Futures Mode and having given it the PointValue, the MarginDeposit and the PositionSize, the calculations are done as follows
Page 22 of 27
Fig 12. TickSize
Note that we have not specified TickSize specifically yet, and w e are still getting correct dollar values in the B acktester. TickSize is not needed for the basic PnL calculations, EXCEPT in two cases: F I R S T w h e r e t h e E x i t p r i c e i s d e fi n e d b y A p p l y S t o p o r i n - b u i l t s t o p s , i n w h i c h case it appears that AB will internally round or adjust the calculated Exit Price to match a valid ticker specific price level. The SECOND reason has to do with the way we can calculate the Forex commissions or spreads, which is discussed later. Therefore it remains important that we always specify TickSize. TickSize can be set in one of three places. a. SETTINGS in GUI b. Symbol information c. AFL The SETTINGS GUI value is the global default value which is used if no other values are set, and then this value gets used for calculations, and it is this value which is displayed in the Backtest Report Settings link. (Fig 13) The Symbol Information value supersedes the Global value and is used in any needed calculations. However the Report Settings value is still read from the Global Settings value. If we code up some AFL for the TickSize then this gets given precedence for calculations in the backtester. The actual value that gets used can be displayed with an exploration output. [Again the Report Settings link is of no use in checking the settings of the backtest parameters, but continues to display the global value.]
Page 23 of 27
Fig 13.
To use AFL in Backtester to set the TickSize for Forex, we can use the IIf function: TickSize = IIf( StrRight( Name(),3) == "JPY", 0.01, 0.0001);
GETTING THE COMMISSION AMOUNT RIGHT IN FOREX BACKTESTING
Having got the correct Dollar value for the backtest results, we next need to set the correct costs/commission. SetOption(“CommissionMode”,3);//tells AB to use a specific dollar value per contract SetOption(“CommissionAmount”, youramount); // tells AB what value to use in the calculations. So if we have one lot of 100 000 with PointValue of say 100 000, TickSize of 0.01 then the Commision Amount is set as SetOption(“CommissionAmount”, TickSize * Pointvalue); (this is because in AB the PointValue i s the dollar value of a single pip divided by the TickSize: for standard lot EURUSD in USD denominated account each pip = $10, so… PointValue = Dollar value per pip / TickSize = $10 / 0.0001 = 100 000) Multiplying the PointValue by the TickSize calculates the dollar value per pip. Different currency pairs have varying spreads per Pair, ranging form 1 to say 15 pips. So we need to arrive at
Page 24 of 27
SetOption(“CommissionAmount”, Spread * TickSize * Pointvalue); And lastly, for Currencies we only pay the Spread once per round trip, generally on entering the trade, so our final dollar calculation for the CommissionAmount will look like this: SetOption(“CommissionAmount”, 0.5 * Spread * TickSize * PointValue); This therefore shows again why we need the TickSize to be specified. If we do not specify any TickSize , its value is zero and the CommissionAmount will always be zero, leading to incorrect final dollar values. We know that the TickSize will vary per currency: this is easily set in each ticker’s Information sheet or better still with AFL like this: TickSize = IIf(StrRight(Name(),3) == “JPY”,0.01, 0.0001); and is already part of our code to get the correct Dollar value in the backtester. We also know that the spread varies per ticker, with the actual spread depending on your Broker, but can be easily done with the II F statement. So the sample code for a Forex backtest commission calculation for a pair where CCY2 is JPY would look something like this: SetFormulaName("FxCommissionCorrect"); SetOption("FuturesMode",1);// SET THIS ALSO IN GUI SETTINGS. SetOption("InitialEquity", 100000); RoundLotSize = 1; TickSize = IIf( StrRight( Name(),3) == "JPY", 0.01, 0.0001); MarginDeposit = 1000; // for example for 100:1 leverage on standard lot PointValue = 915; // for pairs with JPY as the counter currency NumLots = Param("NumLots", 1,1,10,1); PositionSize = NumLots * MarginDeposit ; Spread = 4; // current GBPJPY Spread SetOption("CommissionMode",3); // $ amount per contract SetOption("CommissionAmount", 0.5 * Spread * TickSize * PointValue ); // silly simple Buy & Sell rules Buy = Cross( Close, EMA(C,30)); Sell = BarsSince(Buy) == 4;
Now, if we wanted to run this across all currency pairs at the same time, we would have to both a. Set the correct spread with the IIF function e.g. OnePip = Name() == "EURUSD" OR Name() == "EURGBP"; TwoPip = Name() == "EURCHF" OR Name() == "EURJPY" OR Name() == "USDJPY" OR Name() == "AUDUSD"; ThreePip = Name() == "CHFJPY" OR Name() == "USDCHF" OR Name() == "GBPUSD"; FourPip = Name() == "CADJPY" OR Name() == "USDCAD" OR Name() == "AUDJPY" OR Name() == "EURCAD" OR Name() == "NZDUSD"; SevenPip = Name() == "GBPCHF" OR Name() == "GBPJPY"; Spread = IIf( OnePip, 1, IIf(TwoPip,2, IIf(ThreePip,3, IIf(FourPip,4, IIf(SevenPip,7, 5)))));
b. Set the correct PointValue for each pair: as discussed above we can best do this with the Symbol, Information field, or if we like we could code this into the AFL, also with II F function, such as PointValue = IIf ( StrRight( Name(),3) == "JPY", 915, IIf ( StrRight( Name(),3) == "CAD", 98900,
Page 25 of 27
IIf ( StrRight( Name(),3) == "CHF", 90000, IIf ( Name() == "AUDNZD", 78000, IIf ( Name() == "EURGBP", 195000, 100000)))));
These values will only need occasional changes once currency exchange rates change significantly, and can easily be obtained from your broker’s platform or a simple spreadsheet. They would also need to be adjusted if one were to have different account sizes, trade different lot sizes or had accounts in di fferent base currency. So now we are in a position to set the Commission Amount to allow the Backtester to display correct dollars amounts in the backtester. REPORTS in Pips
We note also that if have more than one account, perhaps trading different Lot sizes or in different currencies, we would have to change the PointValue for each account if we want the Backtester settings to return the Profit in Dollars. Because of this we may choose to get the Backtester to give us the results in Pips rather than Dollars. If we want to display the profit in pips, we can just set the PointValue equal to the amount of pips in a one point move: For Non Yen pairs this works well: PositionSize = MarginDeposit = 1; PointValue = 10000;
For Yen pairs we need 100 for the PointValue because there are 100 pips moved for one point. PositionSize = MarginDeposit = 1; PointValue = 100;
Now we can use the IIf Statement to define this in AFL, and then we do not need to set this in the I nformation sheet. PositionSize = MarginDeposit =1; PointValue = IIf( StrRight( Name(),3) == "JPY", 100, 10000) ;
Now we have a potentially new problem: the PnL is expressed in Pips but unless we convert the equity to Pips, then the Statistics in the backtest Report will be meaningless. So we can add this code to convert the initial Equity we start with into Pips. SetFormulaName("FxPnLinPIPS");// reminds us the results we are looking at is in pips. SetOption("FuturesMode",1);// SET this also in the SETTINGS GUI RoundLotSize = 1; MarginDeposit = 1000; PositionSize = MarginDeposit = 1; TickSize = IIf(StrRight(Name(),3)=="JPY",0.01,0.0001);
// Use these to reset Equity from Dollars to Pips PositionSize = MarginDeposit = 1; PointValue = IIf( StrRight(Name(),3)=="JPY",915, 100000); // typical JPY and USD values dollarEQUITY = 100000; // Set trading capital in dollars DollarPerPip = PointValue * TickSize ; pipEQUITY = dollarEQUITY / DollarPerPip;
Page 26 of 27
SetOption("InitialEquity", pipEQUITY); //Reset PointValue to allow for results in Pips as above PointValue = IIf( StrRight(Name(),3)=="JPY",100, 10000);
Then when we run a backtest over the same ticker, same data and same system, once with normal dollar results, and then with PipValue results, then we find that MOST, but not all of the Backtester statistics are displayed correctly. These statistics will remain valid:
Initial Capital, Ending Capital, Net Profit, Net Profit%, Annual return%; Avg Profit/Loss, Avg Bars Held; Winners number and percent, Total Profit, Avg Profit, Avg bars held, Max Consecutive, largest win, # bars in l argest win; L o s e r s N u m b e r a n d P e r c e n t , T o t a l L o s s , A v g L o ss , A v g B a r s h e l d , M a x Consecutive, Largest Loss, # bars in Largest Loss. Other statistics: Max trade drawdown, Max System Drawdown, Max System % Drawdown, Recovery Factor, CAR/MaxDD, Profit Factor, Payoff Ratio, Standard Error, Risk-Reward Ratio, Ul ce r In de x, Ul ce r Pe rf or ma nc e Index, Sharpe Ratio of trades, K-ratio. These statistics will not make sense:
Exposure%, Net Risk Adjusted Return%, Risk Adjusted Return%; Avg Profit/Loss%: Winners: Avg Profit% ; Losers: Avg Loss %; Other statistics: Max trade % drawdown, RARMaxDD, So, although not all the values will be valid we can still pl ot the Equity curve and extract the most important statistics needed to compare one strategy against another. Setting the Commission in Pips
Finally, we need to include the Commission in Pips. This is easy, where the commission amount is simply equal to the Spread, and we remember that we only pay the spread in Forex once per round trip: Spread = 4; SetOption("CommissionMode",3); SetOption("CommissionAmount",Spread / 2);
Summary
Knowledge of how the backtester does its calculations, where we set them and how to use them is the first step to developing confidence in the results the backtester displays. We have learnt the basics of the backtester, where we can use the AFL to override the SETTINGS GUI entries, which settings cannot be set in the AFL and which ones can only be set in the AFL. We have seen how the Applystops work and how they can be plotted for visual reference. We have looked at the differences between backtesting shares and forex, and which settings were needed to obtain accurate forex calculations. We have
Page 27 of 27
seen how we can express forex results in dollars or pips and shown how to obtain correct commissions to be factored into the calculations. Other Simple Tips
When testing and running these backtest AFLs, we make frequent changes to the code or settings. The next run of the backtest does not always register the new change. We can just hit the Back Test button a few times, or we can save changes to the AFL and reload the file. Reference future bars Prior to running the backtester we need to ensure the code and settings do not allow referencing future bars, or else the strategy will not be able to be traded live. Go to AA, Check or Tools, Check. If there is a reference to future bars we will need to rem out each line until we find out which is the offending code and rectify this first. Even using the next bars data to work out the position sizing can result in this error. See message #97492 in Amibroker usergroups.
References
1. 2. 3. 4.
Amibroker help file Yahoo Amibroker group Amibroker support http://www.amibroker.com/kb/2006/08/09/amibroker-for-forex/
ChrisB c/b Jan 2008 Feedback/errors/ corrections welcome via yahoo amibroker usergroup or kris45mar [at] iinet.net.au