Amy Code PDF
Amy Code PDF
ABSTRACT
This paper relates to the use of mechanical timing signals for trading securities. In
particular, it concerns the combination of price based and non-price based signals to form
composite signals having increased performance compared to the use of either type of
signal standing alone. The composite signals are particularly adapted for trading actively
managed mutual funds and exchange traded funds (ETFs) on an intermediate term (one or
BACKGROUND
Mechanical timing signals are defined as specific buy and sell instructions
generated by applying a computer algorithm to one or more financial vector time series.
The vector can be the price of a security such as a stock or mutual fund, or it can be a
non-price indicator such as a market index internal. The latter include new highs/new
lows, advancing/declining issues and up/down volume. As the vector changes value over
time, the computer algorithm evaluates the changes and presents the trader with a
1
decision on whether or not to own a particular security. The term mechanical refers to the
non-discretionary aspect of these signals, thus the buys and sells are generated strictly by
Timing signals can be based on any time frame, from intraday tick data to
monthly data. This paper is confined to timing signals based on daily data, aka end of
day or EOD data. Daily signals tell the trader to own a particular security on a
particular day or not to own it on that particular day. All results presented herein are based
on next day trading, that is, the timing signals are generated using the current days
closing prices, and the trades take place at the next days closing. The computer
Timing signals are used in an attempt to beat the performance of buy and hold,
either on an absolute return or risk adjusted basis. The following example conceptually
illustrates the use of a simple timing strategy. FIG. 1 is a chart of SPY, the Exchange Traded
Fund (ETF) for the S&P 500 Depository Receipts (SPDR). The average buy and hold annual
return for SPY for the past 17 years has been slightly less than 8%, with a maximum
drawdown (peak to trough) of about 55%. This 55% drawdown occurred in 2008-2009.
A drawdown of 46% occurred in 2000-2002. Most would agree that periodic 45-55%
drawdowns are a steep price to pay for such a relatively low annual return.
2
Now lets compare the buy and hold performance of SPY with a timing strategy
using a 233 day and an 89 day simple moving average (SMA) crossover. Those familiar
with Fibonacci numbers will recognize 233 and 89 as members of the Fibonacci sequence.
This crossover is a slight variation on the well known Golden Cross strategy using a
50/200 day SMA, and yields similar results with slightly less whipsawing. The strategy is
to own SPY when the value of the 89 day SMA of SPY is above that of the 233 day SMA,
and to go to money market when the 89 day SMA is below the 233 day. Thus SPY is the
vector time series used to generate the timing signal, and the timing signal is used to trade
SPY. FIG. 1 illustrates the difference in performance between buy and hold (black equity
3
FIG. 1
Compared to buy and hold, the 233/89 crossover strategy increases annual return,
from approximately 7.8% to 10.8%, and cuts maximum drawdown from 55% to 19%. Using
this strategy, the drawdown in 2008-09 would have been avoided almost entirely, as the
strategy went to a sell in February 2008 after a drawdown of 19% from the peak in
October, 2007.
While the 89/233 SMA crossover strategy is a tremendous improvement over buy
and hold, the performance is still unacceptable from the standpoint of the reward to risk,
commonly measured by the ratio of compound annual return (CAR) divided by maximum
drawdown (Mdd) for the same measurement period. Thus the CAR/Mdd for SPY buy and
hold from the start date of 1/23/1993 is 7.8/55 = 0.14. For the 89/233 SMA crossover
strategy, the CAR/Mdd ratio is 10.8/19 = 0.57. While opinions vary as to what is an
acceptable reward to risk ratio, many consider a CAR/Mdd of 1.0 to be a minimum for
any trading system. Thus, for a CAR/Mdd of at least 1.0, the compound annual return must
be at least as great as the maximum drawdown for the same period. Naturally, the higher
With a CAR/Mdd of 0.57, the 89/233 SMA crossover system clearly fails the 1.0
minimum threshold requirement for consideration. One solution is to tighten the SMA
4
parameters to enable the trader to exit SPY earlier, thus avoiding more of the drawdowns.
Tighter parameters, however, increase the risk of whipsawing. FIG. 2 illustrates this.
FIG. 2
The jagged red line in FIG. 2 confirms the presence of excessive trading due to the
tighter 21/89 SMA parameters. Moreover, although no single drawdown equals the 19%
drawdown using the 89/233 SMA, the overall maximum drawdown has increased to 35%
due to the cascading effect of successive smaller drawdowns. This occurred in both the
2000-2002 and 2008-2008 bear markets, and is due to periodic bear market rallies that
5
trigger a buy in the 21/89 SMA, followed by a quick reversal back down. On the other
hand, there was a buy signal on 4/20/09 which lasted until 2/17/2010 and resulted in a
34% profit, indicating that tighter SMA parameters do work when a security is trending
strongly.
SPY is typical of many securities, experiencing periods of strong trends and periods
of weak trends or trendless oscillation. Moving average crossover strategies with tight
parameters work well only in strongly trending markets, as shown above. The less trendy
the security over a given period, the broader or looser the parameters must be to
avoid whipsawing and cascading losses. However, looser parameters increase single
trade drawdown and decrease overall return. The trend trader is thus faced with the
whipsaws.
DETAILED DISCUSSION
whipsawing. In the following example, SPY is traded first with an exponential moving
average (Ema) crossover, then with a combination of an Ema crossover and non-price
indicators as detailed hereinafter. In both studies, a walk forward analysis was performed.
Below is a screen capture of the walk forward settings as implemented in AmiBroker. The
6
walk forward studies were performed using AmiBrokers built in particle swarm optimizer
FIG. 3
The in-sample period for initial optimization was 1/1/1995 to 1/1/2002 and was
anchored going forward. The walk forward was annually with re-optimization at the start
7
of each year beginning 1/1/2002. The optimization target (objective function) was
CAR/Mdd, that is, the out of sample parameters were chosen based on the best
CAR/Mdd for the previous in-sample period. FIG. 4 summarizes the results of the walk
FIG. 4
As can be seen in FIG. 4, the highest annual drawdown was 9.92% in 2007, and
the total return (crudely summing up the Out of Sample annual returns from 1/1/2002 to
In the second study, the same walk forward analysis was performed using an Ema
8
FIG. 5
As can be seen in FIG. 5, the highest annual drawdown was 7.59 in 2007, and the
total return was 54.2%. Thus, optimizing with confirmation signals both increased return
CODE LOGIC
The non-price indicators used in the second study were NYSE and NASDAQ new
highs/new lows and up volume/down volume. The signals are generated by optimizing
Ema crossovers of the non-price indicators, with inverse Ema crossovers being used for
9
Initially it would seem counterintuitive to employ NASDAQ data to trade SPY, even
when its used in combination with NYSE data. Nevertheless, exhaustive back-testing and
trial and error with various combinations of indicators showed that the inclusion of
NASDAQ data yields significantly better results. Still more surprising is the manner in which
the signals are constructed to obtain the results. In bull markets, the best buy results occur
with a combination of new lows and down volume. In bear markets, the best buy results
are a confirmation of new highs/up volume and new lows/down volume. In other words,
new highs and up volume become significant for buys only during a countertrend rally in
bear markets. Sells are generated by either combination of new lows/down volume or
new highs/up volume. For determining a bull market for the NASDAQ, a long term Ema
crossover of the Russell 2000 is used, and for the NYSE, a long term crossover of SPY is
used. It is speculated that the Russell 2000 and SPY work better than NASDAQ or NYSE
data as long term bull/bear indicators because their equity curves are somewhat
smoother. The AmiBroker AFL code used to generate the confirmation signal is attached as
Trend trading SPY and many other ETFs is often difficult because of a lack of
trendiness in unmanaged index funds. On the other hand, many managed funds trade
very well using trend following techniques. Using confirmation signals can enhance results
further. The following example trades RYOTX (Royce Microcap) with a stand-alone Ema
crossover and in combination with non-price indicators. The AmiBroker AFL code used to
10
generate the results with RYOTX is attached as Appendix 2. Again, as with SPY, walk
forward studies were performed under the same conditions. FIG. 6 summarizes the walk
FIG. 6
The results in FIG. 6 show the highest annual drawdown in 2007 of 9.92%. The
total gain (again crudely summing up the annual CAR results) is 51.72%.
When the Ema crossover is confirmed by NASDAQ new highs/new lows and
11
FIG. 7
Using the confirmation signal, the highest annual drawdown is 7.83% in 2009 and
the total gain jumps to 149.13%, nearly triple the gain using only the Ema crossover.
CONCLUSION
Non-price indicators can be a useful addition to trend trading signals when used in
confirmation. They can be particularly welcome for securities that are otherwise resistant to
trend trading, such as many of the index funds and ETFs. Further research will include using
custom non-price indicators generated for sectors other than the NASDAQ and NYSE,
such as the Russell 2000 and emerging markets. In addition, sensitivity studies using IO
12
(Intelligent Optimizer, available as an AmiBroker add on) will be conducted to measure
robustness.
APPENDIX 1
//----------------------------------------------------------------------------------
// *** IO Directives - Parsed As Comments
// To Disable a Directive, Mark As
//xIO
// UseDefault and SaveCancelled
allows seeding a run with a previous solution
//----------------------------------------------------------------------------------
//Standard IO Setup
//IO: SenOptRanges: 3
//IO: SenOptRangeWt: 2
//IO: SenOptGoal%: 100
13
//IO: UseDefault: Y
//IO: SaveCancelled: Y
//----------------------------------------------------------------------------------
//----------------------------------------------------------------------------------
fund= Foreign("rut-i", "Close");
RUTS = Optimize("RUTS", 34, 13, 233, 1);
RUTL = Optimize("RUTL", 377, 89, 610, 1);
rutb = Cross(MyEma(fund, RUTS), MyEma(fund,RUTL));
ruts = Cross(MyEma(fund,RUTL), MyEma(fund,RUTS));
14
fund= Foreign("DVOLQ", "Close");
DVS = Optimize("DVS", 34, 3, 89, 1);
DVL = Optimize("DVL", 144, 34, 610, 1);
dvolb = Cross(MyEma(fund, DVL), MyEma(fund,DVS));
dvols = Cross(MyEma(fund,DVS), MyEma(fund,DVL));
BuyspmktState = Flip(spb,sps);
SellspmktState = Flip(sps,spb);
BuyspmktImp = ExRem(spb,sps);
SellspmktImp = ExRem(sps,spb);
15
Sellny = IIf(BuyspmktState,SellnyaState,SellnybState);
16
SellnsbState = Flip(Sellnsb, Buynsb);
Sellns1 = IIf(BuyrutmktState,SellnsaState,SellnsbState);
BuynsspyState = Flip(Buynsspy,Sellnsspy);
SellnsspyState = Flip(Sellnsspy,Buynsspy);
BuynsspyImp = ExRem(Buynsspy,Sellnsspy);
SellnsspyImp = ExRem(Sellnsspy,Buynsspy);
BuyspysigState = Flip(Buyspysig,Sellspysig);
SellspysigState = Flip(Sellspysig,Buyspysig);
Buy = Flip(BuyspysigState,SellspysigState);
17
Sell = Flip(SellspysigState,BuyspysigState);
OptimizerSetEngine("spso");
OptimizerSetOption("Runs",2);
OptimizerSetOption("MaxEval",1000);
Bars = LastValue(Cum(Status("barinrange")));
Barsreq = bars + 512;
SetBarsRequired(barsreq,0);
18
APPENDIX 2
//----------------------------------------------------------------------------------
// *** IO Directives - Parsed As Comments
// To Disable a Directive, Mark As
//xIO
// UseDefault and SaveCancelled
allows seeding a run with a previous solution
//----------------------------------------------------------------------------------
//Standard IO Setup
//IO: SenOptRanges: 3
//IO: SenOptRangeWt: 2
//IO: SenOptGoal%: 100
19
// *** IO Options page 30 - 33
//IO: UseDefault: Y
//IO: SaveCancelled: Y
//----------------------------------------------------------------------------------
//----------------------------------------------------------------------------------
fund= Foreign("ryotx", "Close");
RUTS = Optimize("RUTS", 34, 13, 233, 1);
RUTL = Optimize("RUTL", 377, 89, 610, 1);
rutb = Cross(MyEma(fund, RUTS), MyEma(fund,RUTL));
ruts = Cross(MyEma(fund,RUTL), MyEma(fund,RUTS));
20
nsnhb = Cross(MyEma(fund, NSHS), MyEma(fund,NSHL));
nsnhs = Cross(MyEma(fund,NSHL), MyEma(fund,NSHS));
BuyspmktState = Flip(spb,sps);
SellspmktState = Flip(sps,spb);
BuyspmktImp = ExRem(spb,sps);
SellspmktImp = ExRem(sps,spb);
21
Buyny = IIf(BuyspmktState,BuynyaState, BuynybState);
Sellny = IIf(BuyspmktState,SellnyaState,SellnybState);
22
Buysob5bState = Flip(Buysob5b, Sellsob5b);
Sellsob5bState = Flip(Sellsob5b, Buysob5b);
Sellsob5 = IIf(BuyrutmktState,Sellsob5aState,Sellsob5bState);
BuysobspyState = Flip(Buysobspy,Sellsobspy);
SellsobspyState = Flip(Sellsobspy,Buysobspy);
BuysobspyImp = ExRem(Buysobspy,Sellsobspy);
SellsobspyImp = ExRem(Sellsobspy,Buysobspy);
Buysob6rState = Flip(Buysob6r,Sellsob6r);
23
Sellsob6rState = Flip(Sellsob6r,Buysob6r);
Buy = Flip(Buysob6rState,Sellsob6rState);
Sell = Flip(Sellsob6rState,Buysob6rState);
OptimizerSetEngine("spso");
OptimizerSetOption("Runs",2);
OptimizerSetOption("MaxEval",1000);
Bars = LastValue(Cum(Status("barinrange")));
Barsreq = bars + 512;
24