A Simple Rotational System Among Low Beta Stocks
June 25, 2017 | Posted by Oddmund Grotte under strategies |
I like to trade the boring stocks.
Today I picked 19 random (but liquid) low beta stocks (boring stocks) and tested a rotational system in Amibroker (of course with a bit of survivorship bias). Here is the code:
SetBacktestMode( backtestRotational );
SetOption(“initialequity”,30000);
SetOption(“commissionMode”,3);
SetOption(“commissionAmount”,0.03);
SetOption(“MaxOpenPositions”,2);
SetOption(“WorstRankHeld”,5);
SetPositionSize( 50, spspercentofequity );
PositionScore = 60 – Rsi(15);
The backtest is rotational, ie. always in the market in the best ranked stocks. Commission is set to 3 cents per share and entry and exit is on close. I hold 2 positions at all times. I exit when positions are no longer ranked among the 5 “best” among the 19 stocks. All stocks are ranked on 15 day RSI. In the positionscore i have written “60- RSI(15)” so I’m slightly tilted towards keeping more trades on the long side than the short side.
Remember this is an extremely simple system, perhaps naive. There is basically no curve fitting except backtest shows it’s better to keep a low number of positions, a “long” timeframe and let the positions “climb” on the rank before we close positions (SetOption(“WorstRankHeld”,5);).
Here are the numbers:
All months summarized:
I found your article interesting because I have been tending towards using lower volatility ETFs to avoid pain in the portfolio. I have been selecting ETFs by measuring Ulcer Performance Index and/or Ulcer Index. I tried to reproduce your AmiBroker results but do not get nearly as good results as you did. I used exactly your posted AmiBroker code. I did not know what stocks you used for the rotation. I saw in the link that you had used “boring” stocks SO, KO, PG and JNJ so I used those. To get more potential things to trade I then added 14 ETFs that match your low ATR(100)/Close criteria. Most of the ETFs I used I had previously selected with a UPI scan. I first measured ATR(100)/Close for SO, KO, PG and JNJ and found it ran from 1.13% to 0.89%. So I only used ETFs with ATR(100)/Close less than 1.13%. I found that ATR(100)/Close for QQQ is 0.84% and SPY is 0.65%. So even these non-boring ETFs have low enough volatility to match your criteria. The ETFs I used were QQQ, SPY, GLD, TLT, DVY, PGX, DIV, IGF, PID, PEJ, PKW, XLV and FV. Using those with your AmiBroker rotation code from 2/14/09 to 6/26/17 I got CAR = 7.32%, Mdd = -15.06%. And from 2/14/07 to 6/26/17 I got CAR = 3.65%, Mdd = -39.65%. So the stocks you used seem to have much better characteristics than the ETFs I used, which leads me to think that ATR(100)/Close is not the only selection criteria one should use. Would you be willing to post the symbols of the 19 stocks you used so I can learn more about how to select good stocks?
Hi,
abt,adp,cl,gis,hrl,hsy,jkhy,k,ko,mcd,mmm,payx,pg,pm,so,spy,vvc,wdfc,wmt and xom.
By mistake SPY was included.These were picked just out of my head. Perhaps my result is just a coincidence. I will test more of this later.
Thanks
Hi Oddmund,
I noticed with your code sometimes you only get one position instead of 2. I’ve noticed this issue with Amibroker before and I think its to do with the way it rounds positions. In any case adding a margin setting normally fixes this. E.g.
SetOption(“AccountMargin”, 50);
Hi,
Thanks. I noticed this myself, couldn’t (and still can’t) figure out why. I’m quite new to AB, so i have a lot to learn.
Hi,
it took me years to find it in the web.
Full of myths.
I think the idea came from Nick Radge?
// techtrader v2 amibroker version
// here we define buy conditions and name each one as a variable
PositionSize = -10; // always invest only 10% of the current Equity
cond1=Cross(H,Ref(HHV(H,10),-1)); // when todays high crosses last highest high over the last 10 periods
cond2=H > EMA(C,40); // todays high is greater than the 40 day Exp MA of closes
cond3=HHVBars(H,70) == 0; // todays high is the highest for 70 periods
cond4=EMA(V*C,21) > 500000; // ensure at least $500k of money flow
cond5=C O; // todays close higher than open
// the following line is the trigger if all conditions satisfied
Buy=cond1 AND cond2 AND cond3 AND cond4 AND cond5 AND cond6;
// here we define variables used once in the trade
ApplyStop( stopTypeLoss, stopModePercent, amount=10 );
Sell= Cross(Ref(EMA(L,180),-1),C); // close crosses below yesterdays average of the low
// here we define what gets displayed on the chart
shape = Buy * shapeUpArrow + Sell * shapeDownArrow;
PlotShapes( shape, IIf( Buy , colorYellow, colorRed ), 0, IIf( Buy , Low, High));
Filter = Buy; // lists exploration results conforming to our buy criteria
AddColumn(Buy, “buy”, 1.0); //
Filter = Sell; // lists exploration results conforming to our buy criteria
AddColumn(Sell, “sell”, 1.0); //
// This section creates the data that you can plot to see how often TT2 trades
// NOTE:- Using VOLUME array so get correct number when switching to WEEKLY or MONTHLY display
AddToComposite(Buy,”~TTBuys”,”V”);
AddToComposite(Sell,”~TTSells”,”V”);
Buy = ExRem(Buy,Sell) ;
Sell = ExRem(Sell, Buy);
Binary = Flip(Buy , Sell);