Category Archives: ETF / Stocks

7 Winning Trading Systems Reviewed – Pt. 2: MDD / MDU

Back in 2009 Larry Connors and Cesar Alvarez published several short term trading systems in their book “High Probability ETF Trading”. They described 7 mean reverting strategies. 
What happens, then once a strategy becomes public domain? Do they loose their edge?
All tests are performed on a set of 20 ETFs:

DIA,EEM,EFA,EWH,EWJ,EWT,EWZ,FXI,GLD,ILF,IWM,IYR,QQQQ,SPY,XHB,XLB,XLE,XLF,XLI,XLV
Tthe strategy can hold  up to 10 ETFs at any time.

Strategy 2:  MDD / MDU

The rules:
1. ETF is above MA(200)
2. ETF is below MA(5)
3. ETF has closed lower 4 days out of the last 5.

BUY on the close of the day these criteria are met.
SELL on the close of the day the ETF closes above its MA(5).
 
The exact opposite for SHORT/COVER.

“In-Sample”         2002-2009: CAR/MDD=1.22 .

Profit = 107468.13 (107.47%), CAR = 10.99%, MaxSysDD = -12050.93 (-9.00%), CAR/MDD = 1.22, 
# winners = 876 (72.76%), # losers = 328 (27.24%) 

“Out-of-sample”  2009-2012: CAR/MDD=0.55

Profit = 29002.70 (29.00%), CAR = 7.36%, MaxSysDD = -15523.51 (-13.34%), CAR/MDD = 0.55, 
# winners = 482 (68.08%), # losers = 226 (31.92%) 
The strategy brings 29% return with a maximum drawdown of 13.34%. That’s not too bad, but it’s nothing close to the pre-2009 results.

a. Simple version, 20 ETFs – Jan 1,2002 – Aug.1,2012

Jan 1,2002 – Aug.1,2012
Profit = 160048.03 (160.05%), CAR = 9.44%, MaxSysDD = -31337.40 (-13.37%), CAR/MDD = 0.71, 
# winners = 1351 (71.07%), # losers = 550 (28.93%)

Jan 1,2009- Aug.1,2012
Profit = 29002.70 (29.00%), CAR = 7.36%, MaxSysDD = -15523.51 (-13.34%), CAR/MDD = 0.55, 
# winners = 482 (68.08%), # losers = 226 (31.92%) 

b. Aggresive version, 20 ETFs – Jan 1,2002 – Aug.1,2012 (Scale In position uses up to x2 leverage)



Jan 1,2002 – Aug.1,2012:
Profit = 200653.84 (200.65%), CAR = 10.95%, MaxSysDD = -48630.97 (-18.19%), CAR/MDD = 0.60, 
# winners = 1382 (72.70%), # losers = 519 (27.30%) 

Jan 1,2009- Aug.1,2012:
Profit = 29119.88 (29.12%), CAR = 7.39%, MaxSysDD = -20885.92 (-18.17%), CAR/MDD = 0.41, 
# winners = 493 (69.63%), # losers = 215 (30.37%) 

Not impressed? You should be…

Although you might not be impressed, there is a very impressive and potentially usefull aspect of this strategy. Let’s zoom in on the 2008-2009 crash:

While SPY (SP500 ETF) crashed 52%, the strategy made 48%. 

That’s a time when most managers were wiped out. It turns out this “tail risk” protection came purely from the SHORT trades.

Let’s break down the equity to long trade equit and short trade equity:
Equity due to LONG trades (flat due to 200 Mov. Average filter)

Equity due to SHORT trades (Once prices under their 200 MA, shorts kick in) :


And here’s the Equity for the strategy Short positions only, from 2002 till 2012. Notice the Augoust 2011 mini crash that did damage to most intelligent strategies? This is what I call cheap “tail risk” insurance. This is the effect that most managers want when buying VIX futures and have to accept the roll-over cost.


The Short only stats 2002-2012:
Profit = 70574.62 (70.57%), CAR = 5.17%, MaxSysDD = -11885.08 (-7.72%), CAR/MDD = 0.67, 
# winners = 480 (69.87%), # losers = 207 (30.13%) 

So here’s a strategy that provides tail risk protection, has negative correlation to the market and historically had only a -7.72% draw-down.  That is not bad at all.

Keep in mind that there is a extra charge for being short an ETF. For example when Spain was in trouble (2012), keeping an EWP short (spain ETF) would have cost you a 7+% interest. This strategy holds an ETF short for an average of 4.66 bars and it holds up to 10 Etfs. So this would not be much of an additional cost. 




Amibroker Code:


Amibroker code:


//Code by VangelisM. (aka – sanzprophet )
//Part of Code taken by afl from Library – Paul’s “Connors TPS – ETFs.afl”

Plot( C, “Close”, ParamColor(“Color”, colorBlack ), styleNoTitle| ParamStyle(“Style”) | GetPriceStyle() ); 


aggresive=ParamToggle(“Agressive?”,”NO|YES”,0);
Buy=Sell=Cover=Short=0;
SetTradeDelays(0,0,0,0);
BuyPrice=SellPrice=CoverPrice=ShortPrice=C;
qty=Param(“Positions”,1,1,50,1);
SetOption( “MaxOpenPositions”, qty );

FirstTriggerPrice =InFirstPos=0;

if(!aggresive)
{
aboveMA=C>MA(C,220);
belowMA5=C<MA(C,5);
MDD=Sum(C<Ref(C,-1),5)>=4;

Buy1=aboveMA AND belowMA5 AND MDD;
Buy=Buy1;
Sell=!belowMA5;
Sell=ExRem(Sell,Buy);


MDU=Sum(C>Ref(C,-1),5)>=4;
Short1=C<MA(C,220) AND !belowMA5 AND MDU;
Short=Short1;
Cover=belowMA5;

PositionSize=-98/qty;
PositionScore=IIf(Buy,100-RSI(3),RSI(3));

}

if(aggresive)
{

aboveMA=C>MA(C,220);
belowMA5=C<MA(C,5);
MDD=Sum(C<Ref(C,-1),5)==4;

Buy1=aboveMA AND belowMA5 AND MDD;
Buy=Buy1;
Sell=!belowMA5;
Sell=ExRem(Sell,Buy);


MDU=Sum(C>Ref(C,-1),5)==4;
Short1=C<MA(C,220) AND !belowMA5 AND MDU;
Short=Short1;
Cover=belowMA5;
BarsSinceSell = BarsSince(Sell);
InFirstPos =Flip(Buy1,Sell);
FirstTrigger = ExRem(InFirstPos, Sell);
BarsSinceFirstTrigger = BarsSince(FirstTrigger);
FirstTriggerPrice = IIf(BarsSinceFirstTrigger < BarsSinceSell,Ref(C,-BarsSinceFirstTrigger), 0 );



SecondEntry = aboveMA AND C < FirstTriggerPrice AND InFirstPos AND Ref(InFirstPos,-1);
InSecondPos = Flip(SecondEntry, Sell);
SecondTrigger = ExRem(InSecondPos, Sell);
BarsSinceSecondTrigger = BarsSince(SecondTrigger);
SecondTriggerPrice = IIf(BarsSinceSecondTrigger < BarsSinceSell,
Ref(C,-BarsSinceSecondTrigger), 0);

BarsSinceCover = BarsSince(Cover);

FirstShortEntry = Short1; ;
InFirstShortPos = Flip(FirstShortEntry, Cover );
FirstShortTrigger = ExRem(InFirstShortPos, Cover );
BarsSinceFirstShortTrigger = BarsSince(FirstShortTrigger);
FirstShortTriggerPrice = IIf(BarsSinceFirstShortTrigger < BarsSinceCover ,Ref(C,-BarsSinceFirstShortTrigger), 0 );
//FirstTriggerPrice = IIf(BarsSinceFirstTrigger < BarsSinceSell,Ref(O,-BarsSinceFirstTrigger+1), 0 );


SecondShortEntry = !aboveMA AND C >FirstShortTriggerPrice AND InFirstShortPos AND Ref(InFirstShortPos,-1);
InSecondShortPos = Flip(SecondShortEntry, Cover );
SecondShortTrigger = ExRem(InSecondShortPos, Cover );
BarsSinceSecondShortTrigger = BarsSince(SecondShortTrigger);
SecondShortTriggerPrice = IIf(BarsSinceSecondShortTrigger < BarsSinceCover,
Ref(C,-BarsSinceSecondShortTrigger), 0);

PositionSize=-98/qty;
PositionScore=IIf(Buy OR SecondEntry ,100-RSI(3),RSI(3));

Buy=IIf(Buy1,1,IIf(SecondEntry AND Sum(Secondentry,BarsSinceSell)==1 ,sigScaleIn,0));
Short=IIf(Short1,1,IIf(SecondShortEntry AND Sum(SecondShortentry,BarsSinceCover)==1 ,sigScaleIn,0));



}
“FirstTriggerPrice “+FirstTriggerPrice ;
“InFirstPos “+InFirstPos ;
“InFirstPos -1 “+Ref(InFirstPos, -1) ;
GfxSelectPen( colorBlack, 2 ); 
GfxSelectFont(“Times New Roman”, 12, 200, False ); 
GfxTextOut(“Larry Connors MDD/MDU”,10,20);





shape = Buy * shapeUpArrow + Sell * shapeDownArrow;

PlotShapes( shape, IIf( Buy, colorGreen, colorYellow ), 0,C );

Matlab for Amibroker Users – Backtesting Functions for Matlab

The point of this post is to provide some basic functions to non professional Matlab users that may help backtest a simple long only system the way Amibroker (and  most other software) backtest.

If you are an Amibroker user you are used to something this easy:

sma9=ma(close,9);
sma21=ma(close,21);
buy=Cross(sma9,sma21);  
sell=Cross(sma21,sma9); 
Wish you could do that in Matlab?
Here’s the Matlab Code for a simple Moving Average Crossover system using some custom functions

%START CODE
%You need these files in the “Path”  for the code to work
%sma.m, iif.m, Cross.m, backtestlongAmount.m, GetTickerV.m, stock.m
%Download SPY from Yahoo, 5 years history, daily bars. We get a “fints” object
% Function TickerV() is similar to function stock() except that 
%it adjusts for OHLC to Adjusted Close Data.

ticker_fints=GetTickerV(‘SPY’,’5y’,’d’);
%%Get the close price from fints and make it a vector
close=fts2mat(ticker_fints.close);
open=fts2mat(ticker_fints.open);
sma9=sma(close,9);
sma21=sma(close,21);
buy=Cross(sma9,sma21);  % custom function, NOT Matlab’s native cross( ) 
sell=Cross(sma21,sma9); 
%Signal should be 1 for Buy, -1 for Sell and 0 for noAction (or Hold)
signal= iif(buy==1,1,iif(sell==1,-1,0));
% Buy and Sell on next bar Open 
 [pnl,pnlvector, sh]= backtestlongAmount(close,signal,open,1,100000);
% [pnl,pnlvector, sh]= backtestlongAmount(close,signal,close,0,100000);
plot(pnl,’DisplayName’,’pnl’,’YDataSource’,’pnl’);figure(gcf)
%END CODE

You are free to copy the code and download the functions. I am not a professional coder. Most functions include pre-existing code that I combined and edited. It’s very probable that mistakes exist.
I am sharing these m files in hope others will check and improve them.

Disclaimer: This code may not provide accurate results. You will have to check yourself to make sure the code works as it should.

The function are:
sma.m
iif.m
Cross.m
backtestlongAmount.m
GetTickerV.m
stock.m

here’s the link:
Custom Functions


Basic Backtest Function for Matlab

[pnl,pnlvector, sh]= backtestlongAmount(data,signal,buyprice,delay,amount$$);

This is a very basic function for backtesting a strategy in Matlab.
All you need is a vector with 1s for Buy, -1’s for Sell and 0’s for Hold.

To use it we need
1. A vector of prices,i.e. SPY close prices
2. Signal: A vector of  1 for BUY, -1 for SELL and 0 for HOLD
3. Buyprice: A vector of Close prices if we buy at close or Open prices if we buy at Open
4. Delay: 0 if we buy “Today” – 1 if we buy tomorrow. So to Buy Tomorrow on Open:
backtestlongAmount(data,signal,open,1,amount$$);
4. Amount :i.e., 100,000

backtestlongAmount.m

Please report any bugs or inaccuracies you find. Improvements are welcome.

Best Day to buy Bovespa – Part 2

If you bought Bovespa on Thursday and sold on Friday every week since 2003, you would be rich (if you compounded). We know this. If one was to follow such a strategy, in real-time, would it make money?

In the following strategy an investor would buy at the Close of the “optimal” day that performed best in the 5 past years. She would buy on this day (sell on the next close) for 6 months. At the end of 6 months she would re-optimize, find the “optimal” day of the past 5 years from the current date and follow it for another 6 months. So here is a walk-forward back-test that shows how she would do.

Results are NOT compounded (hence the huge difference).
Initial Capital:   $100,000 – Profit:  $127,438.7




Begin
End No. Net Profit Net % Profit day of week Profit $$
34820 34826 1 3809.68 3.81 1
34826 35186 1 9849.84 9.85 4 13659.52
35186 35192 1 15842.02 15.84 4 29501.54
35192 35551 1 6754.01 6.75 4 36255.55
35551 35557 1 12394.78 12.39 4 48650.33
35557 35916 1 -19902.37 -19.9 4 28747.96
35916 35922 1 10016.43 10.02 1 38764.39
35922 36281 1 22435.88 22.44 1 61200.27
36281 36287 1 -16342.55 -16.34 1 44857.72
36287 36647 1 15916.31 15.92 4 60774.03
36647 36653 1 4610.77 4.61 4 65384.8
36653 37012 1 7781.22 7.78 4 73166.02
37012 37018 1 -10523.76 -10.52 4 62642.26
37018 37377 1 -12518.35 -12.52 1 50123.91
37377 37383 1 -3076.38 -3.08 4 47047.53
37383 37742 1 4480.75 4.48 4 51528.28
37742 37748 1 9594.63 9.59 4 61122.91
37748 38108 1 3838.22 3.84 4 64961.13
38108 38114 1 21109.48 21.11 4 86070.61
38114 38473 1 8833.46 8.83 4 94904.07
38473 38479 1 3687.74 3.69 4 98591.81
38479 38838 1 8690.9 8.69 4 107282.71
38838 38844 1 8881.05 8.88 4 116163.76
38844 39203 1 -4282.91 -4.28 4 111880.85
39203 39209 1 12311.72 12.31 4 124192.57
39209 39569 1 -767.54 -0.77 4 123425.03
39569 39575 1 -2413.08 -2.41 4 121011.95
39575 39934 1 -9401.48 -9.4 4 111610.47
39934 39940 1 14681.36 14.68 4 126291.83
39940 40299 1 3449.71 3.45 4 129741.54
40299 40305 1 -3704.01 -3.7 4 126037.53
40305 40664 1 1401.17 1.4 4 127438.7

Bovespa- Best day to Buy Brazil

Best Day to Buy Brazil Index :Thursday
Worst Day to Buy Brazil Index :Friday

1993-2011 –  Buy on Close of Day. Sell on Close next day.
Commissions =Slippage=0.

Buying On Thursday  Sell next Day. $1,000 growth.

——————————————

Buying on Friday. Sell next Day $ 10,000  growth.

——————–
Note to myself:
Best EOM buy Days: Monday or Tuesday.