SetBacktestMode( backtestRotational ); // 1 ###### BACKTESTER SETTINGS - 1. GENERAL TAB SetOption("InitialEquity", 100000); SetOption("MinShares", 1); SetOption("MinPosValue", 0); SetOption("FuturesMode", False); SetOption("AllowPositionShrinking", False); SetOption("ActivateStopsImmediately", False); SetOption("ReverseSignalForcesExit", False); SetOption("AllowSameBarExit", False); RoundLotSize = 0; TickSize = 0; MarginDeposit = 0; PointValue = 1; SetOption("CommissionMode", 2); SetOption("CommissionAmount", 7.95); SetOption("InterestRate", 0); SetOption("AccountMargin", 100); SetOption("MarginRequirement", 100); // 2 ###### BACKTESTER SETTINGS - 2. TRADES TAB BuyPrice = SellPrice = ShortPrice = CoverPrice = Close; SetTradeDelays( 1, 1, 1, 1); // 5 ###### BACKTESTER SETTINGS - 5. PORTFOLIO TAB //SetOption("MaxOpenPositions", 1); // check the box to "Add artificial future bar..." // Limit trade size as % - use 10 for live trading // check the box to "Disable trade size limit..." SetOption("UsePrevBarEquityForPosSizing", False); SetOption("UseCustomBacktestProc", False); // 6 ###### BACKTESTER SETTINGS - 6. WALK FORWARD TAB //SetOption("WorstRankHeld", 1); Totalpositions = 1; SetOption("WorstRankHeld", 1); SetOption("MaxOpenPositions", Totalpositions ); PositionSize = -100 / Totalpositions ; LastDayOfMonth = IIf( (Month() == Ref( Month(), 1) AND (Month() != Ref( Month(), 2)) ), 1, 0); TradeDay = LastDayOfMonth ; Score = ROC(Close, 60); PositionScore = IIf(Score < 0, 0, Score ); // Long only PositionScore = IIf(TradeDay , PositionScore , scoreNoRotate); //Exploration Filter = 1; AddColumn(Score ,"Score",1.1); AddColumn(PositionScore ,"PositionScore ",1.1); AddColumn(PositionSize ,"Position Size",1.1);You can download the AFL code above from my Google Drive: 00_60DayMomentum.afl
It is fairly straight forward AFL code, but I've highlighted four key areas:
- Line 1 - Rotational trading needs to be activated for this system
- Line 24 - Trade delays are set to 1, which means trades are entered one day after the signal is generated
- Line 43 - The LastDayOfMonth variable actually stores the second to last day of the month. This causes the rotation ranking signal to be calculated on the second to last day of the month. Since our trade delay is one, the trade occurs the following day, the last day of the month
- Line 47 - If the ROC(60) is negative, then the PositionScore is set to 0, otherwise the PositionScore is set to the ROC(60)
On the second to last trading day of the month, this strategy calculates the 60 day ROC for each product in the portfolio based on closing prices on that day. If the 60 day ROC is negative, the system sets the PositionScore to 0 for that product. It then ranks all of the products in the portfolio, selecting the product with the highest rank. If all products have a rank of 0, the system will move to cash. On the last trading day of the month, it executes the buy and sell orders at the close - "market on close" orders in live trading.
In addition to the AFL code above, I used the AB settings shown below. To replicate my results, you'll need to update your AB settings to match mine.
AmiBroker Backtester Settings - General Tab
(click to enlarge) |
AmiBroker Backtester Settings - Trades Tab
(click to enlarge) |
AmiBroker Backtester Settings - Stops Tab
(click to enlarge) |
AmiBroker Backtester Settings - Report Tab
(click to enlarge) |
AmiBroker Backtester Settings - Portfolio Tab
(click to enlarge) |
AmiBroker Backtester Settings - Walk Forward Tab
(click to enlarge) |
AmiBroker Backtester Settings - Monte Carlo Tab
(click to enlarge) |
AmiBroker Backtester Filter Settings
(click to enlarge) |
To run my AFL in your installation of AmiBroker:
- Download my AFL file
- Open an AB Analysis tab
- Select my AFL file in the Formula field on the Analysis tab
- Update the filter settings (shown above) to only run this strategy against a specific Watch List
- Change the range to "From-To dates", and then select a date range
- Finally, select the Backtest button to run the strategy
After you have backtesting configured and running, the next step is to automate quote updates and signal generation. I use the Windows Task Scheduler utility to call JS scripts, that in turn launch AB and AmiQuote. This topic is beyond the scope of this article, but I may discuss it in the future.
Also, since my last blog post, there have been several articles on momentum trading, and the poor performance of these systems lately. Here are a few worth reading:
- Alpha Architect: Is Momentum Investing Dead? Or Is It Just Painful?
- ETF.com: Why Momentum Is Struggling
- ETF.com: Is Momentum Really Dead?
Follow my blog by email, RSS feed or Twitter (@DTRTrading). All options are available on the top of the right hand navigation column under the headings "Subscribe To RSS Feed", "Follow By Email", and "Twitter".