TRADERS’ TIPS
For this month’s Traders’ Tips, the focus is James Breen’s article in this issue, “Does Fully Automated Trading Software Work?” Here, we present the November 2016 Traders’ Tips code with possible implementations in various software.
The Traders’ Tips section is provided to help the reader implement a selected technique from an article in this issue or another recent issue. The entries here are contributed by software developers or programmers for software that is capable of customization.
In “Does Fully Automated Trading Software Work?” in this issue, James Breen discusses the concepts involved in using a fully automated trading system. The author describes the processes that he uses and provides the basic outline of a strategy to help users get started. Here, we are providing the TradeStation EasyLanguage code for a strategy based on Breen’s outline.
TradeStation offers a number of advanced tools and capabilities to assist traders with the design and testing of their strategies as well as to fully automate the system for trading, if desired. The TradeStation walk-forward optimizer (WFO) is an advanced strategy optimization tool that automates the complex, multistep task of carrying out the statistical walk-forward testing of a trading strategy’s optimized inputs. TradeStation Portfolio Maestro is a backtesting tool that lets you evaluate the performance of a group of strategies applied to one or more symbols that make up your portfolio.
Strategy: Trend Following System // TASC November 2016 // Does Fully Automated Trading // Software Work? // Author James Breen inputs: MovingAverageLength( 10 ), PercentPriceChange( 1 ), MaximumDailyLoss( 500 ), InitialStopLossAmount( 200 ), TrailEnableAmount( 200 ), TrailPercent( 25 ), TradeWithTrend( true ) ; variables: MovAvgValue( 0 ), MovAvgUpperBand( 0 ), MovAvgLowerBand( 0 ), MaxLossReached( false ), StartingPL( 0 ), PL( 0 ), CS( 0 ) ; once SetStopContract ; MovAvgValue = Average( Close, MovingAverageLength ) ; MovAvgUpperBand = MovAvgValue + MovAvgValue * PercentPriceChange * .01 ; MovAvgLowerBand = MovAvgValue - MovAvgValue * PercentPriceChange * .01 ; CS = CurrentSession( 0 ) ; PL = OpenPositionProfit + NetProfit ; // Max Loss For Session if CS <> CS[1] then begin StartingPL = PL[1] ; MaxLossReached = false ; end ; if StartingPL - PL >= MaximumDailyLoss then MaxLossReached = true ; if MaxLossReached = true then begin Sell ( "MaxLoss LE" ) next bar at Market ; Buy To Cover ( "MaxLoss SE" ) next bar at Market ; end else begin if TradeWithTrend then begin if Close < MovAvgUpperBand then Buy ( "MA Trend LE" ) next bar at MovAvgUpperBand Stop ; if Close > MovAvgLowerBand then Sell Short ( "MA Trend SE" ) next bar at MovAvgLowerBand Stop ; end else begin if Close < MovAvgUpperBand then SellShort ( "MA Fade SE" ) next bar at MovAvgUpperBand Limit ; if Close > MovAvgLowerBand then Buy ( "MA Fade LE" ) next bar at MovAvgLowerBand Limit ; end ; end ; SetStopLoss( InitialStopLossAmount ) ; SetPercentTrailing( TrailEnableAmount, TrailPercent ) ; SetExitOnClose ;
To download the EasyLanguage code for the strategy, please visit our TradeStation and EasyLanguage support forum. The code for this article can be found at https://community.tradestation.com/Discussions/Topic.aspx?Topic_ID=142776. The ELD filename is “TASC_NOV2016.ELD.”
For more information about EasyLanguage in general, please see https://www.tradestation.com/EL-FAQ.
A sample chart is shown in Figure 1.
FIGURE 1: TRADESTATION. Here’s a 10-minute S&P 500 emini TradeStation chart with the strategy applied.
This article is for informational purposes. No type of trading or investment recommendation, advice, or strategy is being made, given, or in any manner provided by TradeStation Securities or its affiliates.
For this month’s Traders’ Tip, we’ve provided the study Trend_Following.efs based on the formula described in James Breen’s article in this issue, “Does Fully Automated Trading Software Work?” In the article, Breen describes how to create an automated trading system.
The study contains formula parameters that may be configured through the edit chart window (right-click on the chart and select “edit chart”). A sample chart is shown in Figure 2.
FIGURE 2: eSIGNAL. Here is an example of the Trend_Following.efs study plotted on a 15-minute chart of NAVB.
/********************************* Provided By: eSignal (Copyright © eSignal), a division of Interactive Data Corporation. 2016. All rights reserved. This sample eSignal Formula Script (EFS) is for educational purposes only and may be modified and saved under a new file name. eSignal is not responsible for the functionality once modified. eSignal reserves the right to modify and overwrite this EFS file with each new release. Description: Does Fully Automated Trading Software Work? by James Breen Version: 1.00 09/06/2016 Formula Parameters: Default: MA Length 10 Entry Trigger % 3 Exit Trigger % 4 Initial Stop Loss % 2 Trailing Stop Trigger % 6 Trailing Stop % 2 Notes: The related article is copyrighted material. If you are not a subscriber of Stocks & Commodities, please visit www.traders.com. **********************************/ var fpArray = new Array(); function preMain(){ setPriceStudy(true); setStudyTitle("MA"); var x=0; fpArray[x] = new FunctionParameter("Length", FunctionParameter.NUMBER); with(fpArray[x++]){ setLowerLimit(1); setUpperLimit(1000); setDefault(10); setName("MA Length"); } fpArray[x] = new FunctionParameter("EntTrigger", FunctionParameter.NUMBER); with(fpArray[x++]){ setLowerLimit(0.1); setUpperLimit(100); setDefault(3); setName("Entry Trigger %"); } fpArray[x] = new FunctionParameter("ExtTrigger", FunctionParameter.NUMBER); with(fpArray[x++]){ setLowerLimit(0.1); setUpperLimit(100); setDefault(4); setName("Exit Trigger %"); } fpArray[x] = new FunctionParameter("InStopLoss", FunctionParameter.NUMBER); with(fpArray[x++]){ setLowerLimit(0.1); setUpperLimit(100); setDefault(2); setName("Initial Stop Loss %"); } fpArray[x] = new FunctionParameter("TrlStopTrigger", FunctionParameter.NUMBER); with(fpArray[x++]){ setLowerLimit(0.1); setUpperLimit(100); setDefault(6); setName("Trailing Stop Trigger %"); } fpArray[x] = new FunctionParameter("TrlStop", FunctionParameter.NUMBER); with(fpArray[x++]){ setLowerLimit(0.1); setUpperLimit(100); setDefault(2); setName("Trailing Stop %"); } fpArray[x] = new FunctionParameter("MaxLoss", FunctionParameter.NUMBER); with(fpArray[x++]){ setLowerLimit(0); setDefault(500); setName("Max Daily Loss $"); } } var bInit = false; var bVersion = null; var xSMA = null; var xClose = null; var xHigh = null; var xLow = null; var nInv = null; var nShares = 0; var nEntryPrice = 0; var nTrlStop = null; var nHighestHigh = null; var nLowestLow = null; var nCumProfit = 0; var bMaxLost = false; function main(Length, EntTrigger, ExtTrigger, InStopLoss, TrlStopTrigger, TrlStop, MaxLoss){ if (bVersion == null) bVersion = verify(); if (bVersion == false) return; if (getCurrentBarCount() <= Length) return; if (getBarState() == BARSTATE_ALLBARS){ xSMA = null; xClose = null; xHigh = null; xLow = null; nInv = null; nShares = 0; nEntryPrice = 0; nTrlStop = null; nHighestHigh = null; nLowestLow = null; nCumProfit = 0; bMaxLost = false; bInit = false; } if (!bInit){ xClose = close(); xHigh = high(); xLow = low(); xSMA = sma(Length, xClose); nHighestHigh = xHigh.getValue(0); nLowestLow = xLow.getValue(0); bInit = true; } var nSMA = xSMA.getValue(0); var nClose = xClose.getValue(0); var nHigh = xHigh.getValue(0); var nLow = xLow.getValue(0); var nTradeProfit = 0; if (day(0) != day(-1) && !Strategy.isInTrade()){ bMaxLost = false; nCumProfit = 0; } if (getCurrentBarIndex() != 0){ if (Strategy.isLong()) nTradeProfit = nClose * nShares - nInv; else if (Strategy.isShort()) nTradeProfit = nInv - nClose * nShares; if ((nCumProfit + nTradeProfit) <= -MaxLoss){ if (Strategy.isLong()) Strategy.doSell("Loss Limit exceeded", Strategy.CLOSE, Strategy.THISBAR, Strategy.DEFAULT); else Strategy.doCover("Loss Limit exceeded", Strategy.CLOSE, Strategy.THISBAR, Strategy.DEFAULT); nCumProfit = 0; bMaxLost = true; } if (nShares == 0) nShares = Strategy.getDefaultLotSize(); if (Strategy.isLong()){ if (nTrlStop == null && (nHigh * nShares) >= (nEntryPrice * nShares * (1 + TrlStopTrigger/100))){ nTrlStop = nHigh * (1 - TrlStop/100); nHighestHigh = nHigh; } if (nTrlStop != null && nHigh > nHighestHigh){ nHighestHigh = nHigh; nTrlStop = nHighestHigh * (1 - TrlStop/100); } if (nClose < (nSMA * (1 - ExtTrigger/100))) Strategy.doSell("Exit Long", Strategy.CLOSE, Strategy.THISBAR, Strategy.DEFAULT); else if (nClose * nShares < (nInv * (1 - InStopLoss/100))) Strategy.doSell("Stop Loss Long", Strategy.CLOSE, Strategy.THISBAR, Strategy.DEFAULT); else if (nTrlStop != null && nClose < nTrlStop) Strategy.doSell("Trl Stop Long", Strategy.CLOSE, Strategy.THISBAR, Strategy.DEFAULT); if (!Strategy.isLong()){ nCumProfit += nClose * nShares - nInv; nTrlStop = null; } } else if (Strategy.isShort()){ if (nTrlStop == null && (nLow * nShares) <= (nEntryPrice * nShares * (1 - TrlStopTrigger/100))){ nTrlStop = nLow * (1 + TrlStop/100); nLowestLow = nLow; } if (nTrlStop != null && nLow < nLowestLow){ nLowestLow = nLow; nTrlStop = nLowestLow * (1 + TrlStop/100); } if (nClose > (nSMA * (1 + ExtTrigger/100))) Strategy.doCover("Exit Short", Strategy.CLOSE, Strategy.THISBAR, Strategy.DEFAULT); else if (nClose * nShares > (nInv * (1 + InStopLoss/100))){ Strategy.doCover("Stop Loss Short", Strategy.CLOSE, Strategy.THISBAR, Strategy.DEFAULT); } else if (nTrlStop != null && nClose > nTrlStop) Strategy.doCover("Trl Stop Short", Strategy.CLOSE, Strategy.THISBAR, Strategy.DEFAULT); if (!Strategy.isShort()){ nCumProfit += nInv - nClose * nShares; nTrlStop = null; } } if (!Strategy.isInTrade() && !bMaxLost){ nTrlStop = null; if (nClose > (nSMA * (1 + EntTrigger/100))){ Strategy.doLong("Long", Strategy.CLOSE, Strategy.THISBAR, Strategy.DEFAULT); } else if (nClose < (nSMA * (1 - EntTrigger/100))){ Strategy.doShort("Short", Strategy.CLOSE, Strategy.THISBAR, Strategy.DEFAULT); } if (Strategy.isInTrade()){ nEntryPrice = nClose; nInv = nShares * nEntryPrice; } } if (Strategy.isLong()) setBarBgColor(Color.RGB(0,60,0)); else if (Strategy.isShort()) setBarBgColor(Color.RGB(170,46,46)) } if (nSMA != null) return nSMA; } function verify(){ var b = false; if (getBuildNumber() < 779){ drawTextAbsolute(5, 35, "This study requires version 10.6 or later.", Color.white, Color.blue, Text.RELATIVETOBOTTOM|Text.RELATIVETOLEFT|Text.BOLD|Text.LEFT, null, 13, "error"); drawTextAbsolute(5, 20, "Click HERE to upgrade.@URL=https://www.esignal.com/download/default.asp", Color.white, Color.blue, Text.RELATIVETOBOTTOM|Text.RELATIVETOLEFT|Text.BOLD|Text.LEFT, null, 13, "upgrade"); return b; } else b = true; return b; }
The example daytrading system described by author James Breen in his article in this issue, “Does Fully Automated Trading Software Work?” is simple enough to avoid coding in Wealth-Lab entirely. You can simply compose it from building blocks known as rules in a drag-and-drop manner. In Figure 3, we provide an example of setting it all up. Note that the condition “price crosses X% above/below an indicator” is universal, that is, it can be used with different kinds of indicators such as moving averages, filters, price bands, and channels. In addition to author’s rules, a profit target exit is installed to capitalize on big intraday moves.
FIGURE 3: WEALTH-LAB. This shows a guideline for setting up the example system in rules with drag & drop.
The red icon indicates that the parameter next to it is available as a parameter slider, enabling the user to change its value by dragging the slider on the bottom left of the screen. When you run the system on a chart of a single stock (as opposed to on a multisymbol portfolio), Wealth-Lab automatically and conveniently applies the changed parameters so you have a chance to see how entries & exits change interactively on the chart.
In “Does Fully Automated Trading Software Work?” in this issue, author James Breen presents a very simple moving average crossover system. A ready-to-use AmiBroker formula implementing his system is provided here. Please be sure to test the system before trading, because my backtest of it showed poor performance on the S&P 500, at least.
LISTING 1. // Very simple MA crossover with stops (as proposed in the article) Version( 6.10 ); upthresh = 1 + 0.01 * Optimize("Up MA cross threshold", 3, 0, 5, 0.5 ); dnthresh = 1 - 0.01 * Optimize("Down MA cross threshold", 4, 0, 5, 0.5 ); per = Optimize("MA period", 10, 5, 50, 1 ); mov = MA( C, per ); Buy = Close > upthresh * mov; // enter when close is 3% above moving average Sell = Close < dnthresh * mov; // exit when close is 4% below moving average // initial max loss stop 2% active for first 3 bars ApplyStop( stopTypeLoss, stopModePercent, 2, True, False, 0, 0, 3 ); // after 3 bars activate 2% trailing stop ApplyStop( stopTypeTrailing, stopModePercent, 2, True, False, 0, 3 );
The automated trading system described by James Breen in this article in this issue, “Does Fully Automated Trading Software Work?” can be easily implemented with a few of NeuroShell Trader’s 800+ indicators. Simply select new trading strategy from the insert menu and enter the following in the appropriate locations of the trading strategy wizard:
BUY LONG CONDITIONS: [All of which must be true] Avg Envelope High Breakout(Close,10,0.03) A>B(Sub(SystemEquity(Trading Strategy),DayOpen(Date,SystemEquity(Trading Strategy),0)),-500) LONG TRAILING STOP PRICES: PriceFloor%(Trading Strategy,2) IfThenElse(A>=B(Divide(MaxValEntryAct(Trading Strategy,High,1),EntryPrice(Trading Strategy,0)),1.06),TrailPrice%(Trading Strategy,2),*) SELL LONG CONDITIONS: [1 of which must be true] Avg Envelope Low Breakout(Close,10,0.04) A<=B(Sub(SystemEquity(Trading Strategy),DayOpen(Date,SystemEquity(Trading Strategy),0)),-500)
If you have NeuroShell Trader Professional, you can also choose whether the parameters should be optimized. After backtesting the trading strategy, use the detailed analysis button to view the backtest and trade-by-trade statistics for the strategy.
Users of NeuroShell Trader can go to the Stocks & Commodities section of the NeuroShell Trader free technical support website to download a copy of this or any previous Traders’ Tips.
A sample chart is shown in Figure 4.
FIGURE 4: NEUROSHELL TRADER. This NeuroShell Trader chart shows an S&P 500 emini automated trading system.
The basic percentage risk strategy detailed in “Does Fully Automated Trading Software Work?” by James Breen in this issue is available for download at www.ninjatrader.com/SC/November2016SC.zip.
Once it has been downloaded, from within the NinjaTrader Control Center window, select the menu File → Utilities → Import NinjaScript and select the downloaded file. This file is for NinjaTrader Version 7.
You can review the indicator’s source code by selecting the menu Tools → Edit NinjaScript → Strategy from within the NinjaTrader Control Center window and selecting the BasicPercentageRisk file.
A sample chart implementing the strategy is shown in Figure 5.
FIGURE 5: NINJATRADER. The basic percentage risk strategy’s results for an optimization on the AAPL instrument are displayed in the Strategy Analyzer of NinjaTrader 7.
Our Traders’ Tip for this month is based on the article by James Breen in this issue, “Does Fully Automated Trading Software Work?” In the article, the author develops a fully automated trading system using rules for entries & exits based on the instrument being a given percentage from its simple moving average.
Within the Updata System Optimizer, all parameters are fully optimizable to help the user select the values that better account for ongoing changes in the market, to be able to work in bull and bear markets, and to limit losses/let winners run.
A sample chart is shown in Figure 6.
FIGURE 6: UPDATA. Here is the example fully automated system applied to the ETF USO in daily resolution.
The Updata code for this article is in the Updata Library and may be downloaded by clicking the custom menu and system library. Those who cannot access the library due to a firewall may ask our helpdesk for a copy. The code is also shown below.
'FullyAutomatedTradingIdea PARAMETER "Period" #PERIOD=10 PARAMETER "Entry %" @ENTRY=3 PARAMETER "Exit %" @EXIT=4 PARAMETER "Loss %" @LOSS=2 PARAMETER "Profit %" @PROFIT=6 PARAMETER "Trail %" @TRAIL=2 DISPLAYSTYLE 4LINES INDICATORTYPE TOOL COLOUR RGB(200,0,0) COLOUR2 RGB(0,0,200) COLOUR3 RGB(100,100,100) COLOUR4 RGB(190,190,190) NAME "" "" @AVG=0 @TRIGGER=0 @CUTLEVEL=0 @PROFITTARGET=0 @SETSTOP=0 @STOP=0 FOR #CURDATE=#PERIOD TO #LASTDATE @AVG=MAVE(#PERIOD) @TRIGGER=((@ENTRY/100)+1)*@AVG @CUTLEVEL=(1-(@EXIT/100))*@AVG 'TRAILING STOP EXIT IF HASX(CLOSE,@STOP,DOWN) SELL @STOP ENDIF 'SETS TRAILING STOP AT 6% THRESHOLD IF @SETSTOP=1 @STOP=MAX(@STOP,(1-(@TRAIL/100))*HIGH) ENDIF IF ORDERISOPEN=1 AND CLOSE>@PROFITTARGET AND @SETSTOP=0 @SETSTOP=1 @STOP=(1-(@TRAIL/100))*HIGH ENDIF 'CLOSES ORDERS BELOW X% IF ORDERISOPEN=1 AND CLOSE<@CUTLEVEL SELL CLOSE @SETSTOP=0 ENDIF 'ENTRIES ABOVE X % IF CLOSE>@TRIGGER AND ORDERISOPEN=0 BUY CLOSE @PROFITTARGET=((@PROFIT/100)+1)*CLOSE @SETSTOP=0 ENDIF @PLOT=@AVG IF ORDERISOPEN=0 @PLOT2=@TRIGGER @PLOT3=-10000 ELSE @PLOT2=-10000 @PLOT3=@CUTLEVEL ENDIF IF @SETSTOP=0 OR ORDERISOPEN=0 @PLOT4=-10000 ELSE @PLOT4=@STOP ENDIF NEXT
In his article in this issue, James Breen poses the rhetorical question, “Does Fully Automated Trading Software Work?” This question could be answered by firing off orders on a fully automated system or by using thinkorswim to analyze results before making the trade.
We have recreated his strategy using our proprietary scripting language, thinkscript. We have made the loading process extremely easy—simply go to https://tos.mx/pYj2WJ and choose to view thinkscript strategy. Rename your study “TrendFollowingStratLE.” You can adjust the parameters of this strategy within the edit studies window to fine-tune your variables.
FIGURE 7: THINKORSWIM. Here you see a chart of SPY with the TrendFollowingStratLE strategy added along with StopLossSX and ProfitTargetSX.
In Figure 7, you see a chart of SPY, which is the ETF designed to track the S&P 500, with the TrendFollowingStratLE strategy added. We have also added our StopLossSX and ProfitTargetSX in order to complete the idea outlined in Breen’s article.