Backtesting Options: Selling SPY Puts on RSI(2)

Let’s try the good old strategy for RSI(2) mean reversion.
Buy on Rsi(2)<30
Sell on Rsi(2)>60
Execution is on the Open of the next day.
This is what trading the SPY etf looks like.

How about using the same signals and selling 10, 1-point away from the floor price, front month Puts.*
Again, we sell 10 Puts right below the SPY price. 
So if SPY is at 145.7 we would sell the (floor(145.7)-1) 144 strike Put.
We sell the front month before the 11th of the month, otherwise we shift to the next month.
We cover the position on an Rsi(2) sell signal or let it expire.
All Buy and sells are on the next day Close and on the ask for buy orders and bid for sell orders.**

Of course there are money management differences: The top chart reflects %-of-equity money management (hence, the compounding), while the bottom does not (it buys 10 contracts, rain or shine) . But otherwise, I am surprised at the similarity in the shape of the equity curve. Where is the extra time premium I would expect on buying the fear? 
How about selling further out of the money Puts. 1–>5 points away from the current price:

Similar results. Any thoughts?

*Many thanks to Dave. for his help.
**I will caution the reader that backtesting options is fairly involved and may contain errors including but not limited to: historical data errors, programming errors, underestimation of slippage and execution costs, unrealistic assumptions on price fills, etc. I use EOD data, so there is no information on the open/high/low of the day. 

Dis-advantages of the Retail Investor Part 1:Follow The Money

Part 1:
From Odyssey Book XII

“‘So far so good,’ said she, when I had ended my story, ‘and now pay attention to what I am about to tell you […]
First you will come to the Sirens who enchant all who come near them. If any one unwarily draws in too close and hears the singing of the Sirens, his wife and children will never welcome him home again[…] 

Therefore pass these Sirens by, and stop your men’s ears with wax that none of them may hear; but if you like you can listen yourself, for you may get the men to bind you as you stand upright on a cross-piece half way up the mast, and they must lash the rope’s ends to the mast itself, that you may have the pleasure of listening. If you beg and pray the men to unloose you, then they must bind you faster.”

From sparknotes:
“Once they have passed the Sirens’ island, Odysseus and his men must navigate the straits between Scylla and Charybdis. Scylla is a six-headed monster who, when ships pass, swallows one sailor for each head. Charybdis is an enormous whirlpool that threatens to swallow the entire ship. As instructed by Circe, Odysseus holds his course tight against the cliffs of Scylla’s lair. As he and his men stare at Charybdis on the other side of the strait, the heads of Scylla swoop down and gobble up six of the sailors. Odysseus eventually escapes and landing on the island of Thrinacia.”

Part 2.
The film’s extras. The story never told.

Let’s consider an alternate scenario: We will assume we are back in ancient times. We will pause the story and concentrate on those six poor men, that history has so brutally ignored. Maybe they were not instantly killed. Maybe there is a sub-story that we have ignored.

Scylla, which in Greek literally translates to female dog (a.k.a. , “b….”) was a 6 headed monster. Let’s assume that one of the heads fell in love with one of the sailors and after a furious fight with the rest of the heads, it kept the sailors alive. A clear case of multiple personality disorder…

The men were thrown unconscious to shore. They found themselves in a small sunny island full of coconuts and bananas, rabbits and friendly monkeys and plenty of dumb fish to feed a small army. For many years they lived happily.

Until one day, a talking monkey appeared. He befriended the oldest of the 6 friends, Peter. The monkey and Peter would talk about all kinds of things. Interesting things. One day the monkey noticed that Peter and his friends carried all their produce back and forth to exchange it. The monkey has an idea:  Instead for exchanging fish for rabbits, they would use coconuts in exchange for everything. So instead of 10 fish = 4 rabbit = 1 monkey they would use coconuts. For example 1 monkey =100 coconuts, 1 rabbit =25 coconuts, etc. Per the monkey’s instructions, they created an open pit where they brought and sold their goods which they called the “market”.

But the monkey did not stop there. It started visiting the other 5 survivors and convinced them that Peter was very very smart. He advised them to follow Peter’s actios. If Peter bought rabbits, they would also buy rabbits. If Peter bought lots of fish they would also buy lots of fish. One could say that the monkey had some kind of magical power as the survivors followed blindly Peter’s actions. No questions asked.

Soon, Peter had all the produce and his 5 shipmates starved to death. Peter, who was now nicknamed “smart money Peter”, went on to live a few more lonely years before he died in the arms of his one and only friend: The monkey. He now stood silently on top of the six graves. He didn’t cry. He only grew taller and taller and larger and soon stood at the height of the Gods. He was Haedes the God of the Underwold (also known as Ploutos, which in Greek literally translates to “Wealth”).

Like many of the Greek gods, he too enjoyed shape-shifting and toying with the mortals.
Maybe Odysseus managed to get away. But he did nail these guys!

With a swift and powerful motion he opened the gates of hell and descended back into his dark kingdom. The deserted and barren island stood as proof of the game Ploutos played on these 6 friends.

Part 3: How the hell can we loose in the Market?

Dow Jones Industrial Average (1900 – Present Monthly)                                

Statistics show that most retail players loose in this upward-bias game. 

CBA – Quick test drive

Inspiration strategy:

Quoted from
“We propose a model that is designed to identify bull-market and bear-market regimes. We examine correlation between stocks and bonds as a signal. Our hypothesis is that negative correlation between long bonds and stocks represents a bear-market regime, and a positive, or non-existent correlation, reflects a bull market regime.The model calculates rolling 90-day correlation estimates between the S&P 500 and long-bonds. At each month end, the model computes the 60-day MA of the correlation against the 600-day MA of the correlation. If positive, the model invests in risk; if negative, the model invests in riskless.”

I will do a different kind of implementation so my results will differ due to different data and different strategy. When referring to correlation I will be referring to the correlation of the SP500 to the inverse of the 10-year Treasury yield.

The system will either be long the SP500 or be in cash.
Each month it will look at the short and long term correlations and if stocks/bonds tend to be more correlated than usual, it buys the SP500. If not, it sells it and holds cash.

I will be using yahoo free data: ^GSPC (S&P500 Index) data as the “risk” asset and (1/ ^TNX, the reverse of the 10-year Treasury Yield) to represent long-bonds.

We ‘ll keep 2 parameters optimizable and lock the long moving average period to 600, to keep things simple.
Params [90,60]
a. CorelationPeriod (default=90)
b. MAshortPeriod (default=60)

Buy=MoreCorrelated=MA(Corr,MAshortPeriod )>MA(Corr,600);

 The above graph is using params [90,60]

Just for fun let’s do the exact opposite: We will buy when the short term correlation is less than the long term one. Same parameters.

Let us optimize the parameters to get a better sense of what is happening. Is there a “general acceptable area”?
params: [10–>300 10–>300]

There seems to be a “better” area of settings than the one we are using.
Let’s try the backtest with params [40 220]. In other words we are calculating correlation using a 2-month window. We are then comparing the almost yearly moving average of that to the 600-day longer term one.

Using these optimized parameters, what would trading the 5 core etfs would look like? Risk on means buy SPY,EEM,EFA and VNQ. Risk off means buy IEF.

The equity is for the whole 5 -asset system. The lower pane shows the Emerging Markets time series (NYSEARCA:EEM).
You can see from the lower graph, this system did not buy EEM for the whole 2010-2013 period.

Going back to just trading the SP500, what would happen if we added the simple MA rule. Buy as before but only if price is above it’s 200-day moving average. Sell as before but also sell if price is less than it’s 200 moving average:

Disclaimer: This is a quick and dirty try-out of whether stock/bond correlation can help differentiate bull/bear regimes. It’s not meant to be precise but rather to get you started in performing your own tests.

Few thoughts on TAA:
I will caution the reader that when it comes to “TAA” strategies, for the past few years, holding both the S&P500 (SPY) and bonds (IEF) was an exceptional strategy whether you timed it or not. That is mostly due to the fact that IEF, the 10-year treasury proxy had both an exceptional run and a fairly uncorrelated one to the stock index. As others have mentioned, TAA systems may have a hard time delivering if Treasury yields stop dropping (below zero..?). But one way to look at the typical TAA strategy is that it is a diversified “short-the-dollar” strategy. Looking at it that way, there is room to diversify to non -U.S. denominates assets.

The code in Amibroker:

/----Code by Sanz P.-----------------------------------------------------// 
MAperiods=Param("MA Periods",200,100,400,5);
Corrperiod=Optimize("corr Period",40,10,300,10);
MAshort=Optimize("MA short period",220,10,300,10);

Buy=MoreCorrelated AND newmonth;// AND abovema;
Sell=(!MoreCorrelated /*OR !abovema*/) AND newmonth;
Buy=!MoreCorrelated AND newmonth ;
Sell=MoreCorrelated AND newmonth;
PosQty =Param("How many Positions",1,1,20,1);
SetOption("MaxOpenPositions", PosQty );
PositionSize=-96/PosQty ;

Visualizing Data

I have been looking for ways to visualize what happens to a trading system when we shift it’s parameters. I bumped into this little free tool that might help us do that. Let’s start from the beginning:

We will start with a hypothetical mean reversion system and check visually what happens as the parameters change.
We will run the backtests using the SPY etf (NYSEARCA: SPY) as a proxy for the S&P500.
1. We can only buy when the close is above it’s 200 day moving average.
2. We buy when the RSI falls below 30.
3. We sell when the RSI rises above 55.

The easy case: Two parameters

We want to try different parameters. Instead of a 200-day filter we will try all moving averages periods between 10-days and 300-days, in 10 day increments.
For the RSI period we will try periods ranging from  2-days to 14-days.

So after optimizing the parameters we end up with a table listing the possible combinations of parameters and the profit they produce. In this case we are not using profit as a performance metric but Average Annual Return /Maximum drawdown (CAR/MDD).

Since we have 2 parameters we can visualize them. The higher the “mountain” (car/mdd) the better.

3D graphs by Amibroker

By visual inspection we can see that there is a fairly smooth area between 170-290 for the moving average and 2-6 for the RSI. Any choice of parameters inside those ranges would produce fair risk adjusted return.

What about 4 parameters?

Now we want to try out different thresholds for the RSI indicator. We have tried 30 as a “buy” threshold and 55 as the “sell” one. We ‘ll optimize those values as well. Now we have 4 parameters. How do we visualize them?

After optimization, we should have a table that lists the different combinations of parameters and the corresponding statistics. We ‘ll export it into a csv file*.

Now we ‘ll get this free app called XDat. It reads csv files (with headers) and produces these weird looking graphs, called Parallel Coordinates.

Each column can be tweaked. Let’s say we wanted to see the most profitable parameters. We would go to the first column (Net % Profit) and raise the little red triangle all the way up:

We see that the most profitable systems correspond to parameters: MA period  around 300, rsi period 2, Buy level at 40 and sell level at 95. This is what we would get if we just did the optimization and looked at the sorted results. These would be the “best” parameters.

Now going back and lowering the triangle, we see that the most profitable systems correspong to just a few trials. Most of the trials are below that. So we should consider these “best” parameters as “outliers” and throw them out. We do that by lowering the top red triangle and cutting the top off.

Playing around a bit more we come up with this:

The upside to this procedure is that it’s easy and understandable for a few parameters.Maybe the next step in visualizing further parameters would be to use Self-Organizing-Maps. Anyone who has experience using SOM’s is welcome to comment. Other ideas are welcome.


* I used Amibroker to optimize the parameters. Amibroker produces a table that includes many statistics as columns for each set of parameters: Profit, profit factor, k-ratio, % winning trades, etc. After exporting this table to csv, I manually deleted most of the columns (i.e., profit factor, etc…)  as well as some rows (i.e. parameters that resulted in less than 10 trades). This was done to decrease the size of the csv.


No, it’s not french and it’s not the movie.
It’s a fast-N-rough “Adaptive Multi strategy Multi Instrument” model.

Let’s assume we want to trade mean-reversion: If price moves down we buy, if it moves up we sell.

Possible Indicators from the blog-o-sphere:
DV2 here and here
BSI here or here
CRSI here
TD9 here

Question 1: Which Indicator to use?

One way to choose an indicator is to run backtests for each one (and each one’s parameters) and pick the one that has performed the best in the recent past. “Performance” can be pure profit or it can be any other metric we choose:  CAR/MDD (annual return/MaxDrawdown), Profit Factor, Expectancy or your very own “Bliss function“.
So if DV2 has performed best in the past 6 months, maybe we should use that to trade for the next few weeks.

Question 2: What should we trade? 

Just one instrument?
Why not backtest all indicators on all instrument and let the data tell us which instrument behaves best with which indicator? We can then trade that one. Did someone say “overfit”?.
Why not a bunch of instruments? A portfolio! Yes and we ‘ll throw some weights in there, too:
30% SPY 10% AAPL 10% XLU 20% IBM 30% GLD  … wightN*InstrumentN

I guess now we have to backtest the different indicators with these different weights on our instruments, too. What are we doing here? Let’s step back.

Question 3: What are we doing here?

We start with a set of selected assets (StockA, StockB,… StockN).
We bring in a  set of selected indicators (ind1, Ind2, …IndN).
We then build an “ammi” that picks and chooses from these two universes.
We optimize that “ammi” using some type of non-exhaustive optimization technique.

In other words we are creating a portfolio and trading each instrument inside the portfolio with each own indicator/strategy. So what’s the catch? There’s nothing new here. We could just trade SPY with DV2 and AAPL with RSI(3). Allocate 30% of capital to strategy “SPY” and 10% to strategy “AAPL”. Is there an advantage in mixing it all up?

For the purposes of this post we will assume:
1. Our optimizing target  is % profit.
2. We are investing a fixed percentage of current equity on each trade (i.e., 10% of Equity). In other words we are compounding.

By optimizing one instrument and one strategy, the optimizer will look for the most consistent “timing” to enter and exit trades.

By optimizing the whole AMMI, the optimizer is handed one more tool. Since it wants to maximize compound profit it can do so by minimizing max drawdown which in turn gets accomplished by minimizing correlations between the “weighted and traded” equity curves. So, in theory, the optimizer should not necessarily choose the best timing of each instrument/indicator but rather the best combination of instruments/strategies that are somewhat profitable and least correlated*. We hope that this criterion is more robust criterion than just timing.

Almost forgot! We also want to be able to change both the “instrument” and the “strategy” as time passes. That means we re-optimize every x days and trade with the fresh settings. Hence, the “Adaptive Multi strategy Multi Instrument” , a.k.a, AMMI, nick-name.

For the sake of simplicity, we will consider indicators RSI(2), RSI(3) and RSI(4). Possible thresholds are 0–>50 for a Buy signal and 50–>100 for a Sell signal. We will use 10 instruments that can have weights ranging from 5% –> 100%. We assume the standard 2x leverage can be used.

Let’s run an Out Of Sample test. In_Sample (IS) Optimization period is 2 years, Out_Of_Sample trading period (OOS) is 3 months.**
Optimization is done using Amibroker’s non-exhaustive CMAE plug-in set to run very few “runs” so as not to overfit (and not wait too long…). Target for the optimization is pure % Profit (hence the huge draw-downs).

Here’s the  result trading a few instruments and using RSI(2), RSI(3) and RSI(4) as possible indicators with varied thresholds. This is an OOS (out of sample, i.e., realistic) equity. At 40%+ (in the “good” version) draw-downs, it’s not something I would trade***. It’s just for illustration purposes.

Again. this is a rough “model”. It is best used as a starting point to get ideas going. It might also help to get a sense of how different data groups react to different indicators.  Instead of mean reverting indicators you could have trend following , or pattern based indicators. And instead of optimizing precise values you could fuzzify them.

* Adding a losing strategy to a profitable strategy may increased the Sharpe Ratio of the system.

**The In-Sample optimization will gives us the weights on the instruments as well as the indicator and the thresholds that were used to produce the best performance. An example would be 5% InstrA, 0% InstrB, 0%InsrC,70% InstrD,100% InstrE, 25% InstrF, etc. Indicator would be RSI(4) and lower and upper thresholds would be 30 and 70. Those set of parameters whould then be used to trade “live” (Out-Of-Sample) for the next three months. After that we would re-optimize (inclusive of the 3 months that were traded) and change param for the next 3 months.

***Unless you know what you are doing, optimizing a system for Max Profit, is a fairly bad idea. It will tend to pick few winners and not diversify (i.e., in hindsight it will tend to pick 100% APPLE). 


The code in Amibroker:

//----Code by Sanz P.-----------------------------------------------------//
//----Place the instruments on a watchlist and select it under Parameters
//----Optimize/Walk Forward on that watchlist
function Set2D( tablename, x, y, value )
{VarSet( tablename + StrFormat("%03.0f%03.0f", x, y ), value );}
function Get2D( tablename, x, y )
{return VarGet( tablename + StrFormat("%03.0f%03.0f", x, y ) );}
OptimizerSetOption("Runs", 3 );
OptimizerSetOption("MaxEval", 300 );
WatchlistNumber =Param("Choose Watchlist with Tickers",12,0,30,1);
TickerList= CategoryGetSymbols( categoryWatchlist , WatchlistNumber ) ;
for( n=0; (instrument=StrExtract( TickerList, n)) != ""; n++)
set2d( tablename, n, 0, n );
for( n=0; (instrument=StrExtract( TickerList, n)) != ""; n++)
set2d( tablename, n, 1 , Optimize("Ticker"+n+ "Position",20,0,50,5) ); //pos
set2d( tablename, n, 2 , Optimize("Ind"+n,2,0,2,1) ); //ind
set2d( tablename, n, 3 , Optimize("Thrsh"+n,20,0,100,5) ); //thr
for( n=0; (instrument=StrExtract( TickerList, n)) != ""; n++)
if (Name()== instrument)
indicatorcode=get2d( tablename, n, 2 );
case 0:
case 1:
case 2:
PositionSize= - get2d( tablename, n, 1 );
thresh=get2d( tablename, n, 3 );