Back to Community
Trading SPY based on the slope (zscore of) and the HiLo index of the SPY components (Tradeable?)

After 100+ back tests over different periods I'm confident that this strategy is tradeable and I'm seeking collaboration with others to either improve the drawdown or add other elements to the algo that it makes more robust.
To be in the contest we need to add a hedge to isolate Alpha but for my personal trading I'm not so interested in isolating Alpha.

Any Takers?

With algorithmic regards, Peter Bakker

Clone Algorithm
439
Loading...
Backtest from to with initial capital
Total Returns
--
Alpha
--
Beta
--
Sharpe
--
Sortino
--
Max Drawdown
--
Benchmark Returns
--
Volatility
--
Returns 1 Month 3 Month 6 Month 12 Month
Alpha 1 Month 3 Month 6 Month 12 Month
Beta 1 Month 3 Month 6 Month 12 Month
Sharpe 1 Month 3 Month 6 Month 12 Month
Sortino 1 Month 3 Month 6 Month 12 Month
Volatility 1 Month 3 Month 6 Month 12 Month
Max Drawdown 1 Month 3 Month 6 Month 12 Month
# Backtest ID: 565d73548a364c11b8042581
There was a runtime error.
34 responses

and the tearsheet

Loading notebook preview...
Notebook previews are currently unavailable.

The system does well during QE - but then everyone does well during this period. Between Jan 2006 and Jan 2009 the system makes no money at all - That's 3 YEARS of no returns.

Basically, this system has way too high a beta - I would be careful when trading it in it's current state.

I think the next step would be to add a shorting component to hedge and make it market neutral.

Correct, high beta, but some people cannot short on their account (retail investors in Australia). The question is wether the Alpha of 0.12 in this system is QE dependent and I can't hypothesise why that would be. The system looks at the slope of the price of SPY and how many stocks reach a high and a low, that doesnt seem QE dependent.

How can we improve it: clone and improve!

Congratulations on the spot-on full use of starting capital.

Peter Bakker and Jamie Lunn code combo below, where I did not make the attempt to.
Pro's: Beta is 43% lower, volatility lower, less drawdown.
Didn't spend a lot of time tinkering further so the nearly 50 percentage point loss (see PvR) might be improvable.

Clone Algorithm
107
Loading...
Backtest from to with initial capital
Total Returns
--
Alpha
--
Beta
--
Sharpe
--
Sortino
--
Max Drawdown
--
Benchmark Returns
--
Volatility
--
Returns 1 Month 3 Month 6 Month 12 Month
Alpha 1 Month 3 Month 6 Month 12 Month
Beta 1 Month 3 Month 6 Month 12 Month
Sharpe 1 Month 3 Month 6 Month 12 Month
Sortino 1 Month 3 Month 6 Month 12 Month
Volatility 1 Month 3 Month 6 Month 12 Month
Max Drawdown 1 Month 3 Month 6 Month 12 Month
# Backtest ID: 565f651edea4d61165643857
There was a runtime error.

Hi, Peter, thanks for sharing the code, are you still using this algorithm now?
According to my test, your algo is better than gary's modified version with higher return. I want to enhance your algo by adding shorting component, any ideas about how to implement that? Thanks.

As Lucas Lee suggests, let's try adding a shorting component.

We may eventually want to trade this strategy on Robinhood, which doesn't let us take a short position. But that's not too much of a problem, because we're trading SPY, an index fund with a solid inverse in SH (just like NDX has an inverse in PSQ). So whenever we want to short, we just sell the index fund and immediately buy its inverse fund.

Starting in 2006 - when the inverse funds became available - let's run some backtests. This will tell us how each strategy performs during the recession, as well as when the market rebounds afterwards.


BAKKER'S LONG ONLY
Original. Buys the market when zscor/hilo signals that it will improve. Otherwise holds cash.

  • RETURNS: 195%
  • ALPHA: 0.09
  • BETA: 0.85
  • SHARPE: 0.86
  • MAX DRAWDOWN: 44.3%

BAKKER'S LONG + SHORT
Buys the market when zscor/hilo signals that it will improve. Otherwise shorts the market.

  • RETURNS: 279.4%
  • ALPHA: 0.18
  • BETA: 0.72
  • SHARPE: 1.20
  • MAX DRAWDOWN: 45.1%

BAKKER'S LONG + SHORT IN BEAR MARKET
Buys the market when zscor/hilo signals that it will improve. Shorts market if price below long mavg. Otherwise holds cash.

  • RETURNS: 283.1%
  • ALPHA: 0.17
  • BETA: 0.79
  • SHARPE: 1.22
  • MAX DRAWDOWN: 43.8%

Thanks, Eric. I did not notice adding short is that easy.

I just changed a little bit of code to hold short position instead of hold cash. Total return is 258.8% from 2006.6.21 to 2016.5.6.
I also tried to use SPY/SH pair to avoid short directly, total return is 180.3% for the same period.
Two questions:
1. The max drawdown is too high (more than 40%), is there anyway to improve?
2. Why the performance of using SPY/SH is much worse than long/short SPY?

Any comments? thanks.

Clone Algorithm
38
Loading...
Backtest from to with initial capital
Total Returns
--
Alpha
--
Beta
--
Sharpe
--
Sortino
--
Max Drawdown
--
Benchmark Returns
--
Volatility
--
Returns 1 Month 3 Month 6 Month 12 Month
Alpha 1 Month 3 Month 6 Month 12 Month
Beta 1 Month 3 Month 6 Month 12 Month
Sharpe 1 Month 3 Month 6 Month 12 Month
Sortino 1 Month 3 Month 6 Month 12 Month
Volatility 1 Month 3 Month 6 Month 12 Month
Max Drawdown 1 Month 3 Month 6 Month 12 Month
# Backtest ID: 572d9d42084e2d11f8af4671
There was a runtime error.

Lucas, Would it be possible to modify the SPY/SH version you speak of, to allow multiple intraday trades? Utilizing a Robinhood instant account with a 25K+ balance would remove the obstacle of settlement delays and commissions.

I would suggest altering the algo to seek out periods of the day that are more liquid. Seems like the algo is being held hostage to whatever liquidity exists in the market at the designated order time (5 minutes before close). I experimented (on the most recent algo by Lucas) by switching the order time to 45 minutes before market close. Results are below. I would posit that the better solution would be to dynamically change order times based on market depth.

Clone Algorithm
82
Loading...
Backtest from to with initial capital
Total Returns
--
Alpha
--
Beta
--
Sharpe
--
Sortino
--
Max Drawdown
--
Benchmark Returns
--
Volatility
--
Returns 1 Month 3 Month 6 Month 12 Month
Alpha 1 Month 3 Month 6 Month 12 Month
Beta 1 Month 3 Month 6 Month 12 Month
Sharpe 1 Month 3 Month 6 Month 12 Month
Sortino 1 Month 3 Month 6 Month 12 Month
Volatility 1 Month 3 Month 6 Month 12 Month
Max Drawdown 1 Month 3 Month 6 Month 12 Month
# Backtest ID: 572e83d0c89b410f8bcd7f19
There was a runtime error.

@April, to be honest, I don't know how to implement an intraday version, I attach the SPY/SH algo here, so you could try to modify yourself.
@Frank, nice try! Your total return is 291.1% comparing with my 258.8%, but max drawdown goes up to 45.4% from 40.5%. As Eric mentioned, adding a mavg check doesn't help for reducing maxdd. There might be some other ways though.

Clone Algorithm
29
Loading...
Backtest from to with initial capital
Total Returns
--
Alpha
--
Beta
--
Sharpe
--
Sortino
--
Max Drawdown
--
Benchmark Returns
--
Volatility
--
Returns 1 Month 3 Month 6 Month 12 Month
Alpha 1 Month 3 Month 6 Month 12 Month
Beta 1 Month 3 Month 6 Month 12 Month
Sharpe 1 Month 3 Month 6 Month 12 Month
Sortino 1 Month 3 Month 6 Month 12 Month
Volatility 1 Month 3 Month 6 Month 12 Month
Max Drawdown 1 Month 3 Month 6 Month 12 Month
# Backtest ID: 572d907da51de5128995dc49
There was a runtime error.

Hi Lucas,

Good point, but my only intention was to point out that the algo seems to be arbitrarily anchored to a 3:55 (E.T.) execution time daily. I guess I am still trying to figure out why it only makes trades at that specific time?

Perhaps we can use a SPY-based volatility index (like VIX) to exit the market during periods of unusually high risk?

https://www.quantopian.com/data/quandl/cboe_vix

Drawdown seems to occur when the VIX is high. The three VIX spikes in Oct. '08, May '10, and Aug '11 coincide with when we lose money.

At points in time the algo's here dip below $0 cash, which would reject trades in a cash account.

No, it dips below zero returns - to as much as 40% losses. So a $100 initial investment, for example, would only be worth $60 in October '08, the lowest point of drawdown. Trades will continue to execute, you're just worse off than when you started.

But you're right; ideally we wouldn't let it get to that point. We want to take our money out of the S&P during bad market conditions and instead make our returns on well-placed shorts. So I'm going to see about making the algo more cautious during times of high volatility.

Eric -

Yes. I understand your point, but what I am trying to say is that if you have a cash account (and ca not use margin, like for an IRA account, or an Australian account) and you place an order for greater than the amount of money you have in your account, it will be rejected. The algo's above are not taking rhat into consideration as leverage sometimes goes above 1. Leverage needs to be below 1 at all times.

havent seen this in real trading yet but I'll create some guards while I post it to Q2. i have some other ideas to improve the algo and will post as soon as work is less mad

Peter -

It would be great to see your algo just as it is in Q2 :)

Rafael -- I see what you mean now; you're talking about unsettled cash, which raises a really good point.

Our cash will be tied up for a three-day period in settlement (T-3) after each sale of stock, and during that time we might decide to buy the market again. If we use a SPY/SH strategy, there will definitely be times when we want to turn around and buy an inverse quickly, and the order won't fill because we have no cash.

Robinhood Instant accounts let you use unsettled funds as though they were already settled (technically, they provide 100% margin at no interest on unsettled funds, then call them in when they settle), but not everyone has Instant and it's a pretty long queue to get into the beta. For normal cash accounts, here's how to factor in T-3 into your models: https://www.quantopian.com/help#sample-robinhood.

Eric, when the drawdown is close to -40%, is it possible in the program to add cash to average down, i.e., add money? When it go back to 0% or higher withdraw the added money? I am a beginner and very interest to see your post. And I started to learn the coding. Great work. Thanks.

No, there's no way to trigger a withdrawal / deposit from the Robinhood API.

Glad you're figuring things out! Good luck and have fun!

@Tony, if you really want to do that, as a workaround, you could manually deposit money to your account when you find the draw down is too high (-40% for example), the live trading algo will automatically buy SPY for you; or you could change this algo to always keep some cash unless the high draw down really happens.

@Lucas Lee , i thought it is a good idea to keep some cash as when drawdown is high. If this algo is changed to rebalance once a day, will it do better job? I am learning programming here and about to try that later.

I am new to quantopian, just trying to figure things out. Why is it when I backtest this algo, it will produce completely different signals based on the time frame I choose? I noticed this when I started to run in live mode, it was long SPY but the backtest ended yesterday is currently short SPY. I would think if I ran a backtest from 1/1/2016 to 5/19/2016, the signals in may should match the signals in a shorter backtest ran from 5/1/2016 to 5/19/2016 and should match live signals. I tried various timeframes and always get different results. Is this expected? Is anyone running this algo live?

Thanks.

After debugging a bit more, i found that the arrays during initialization are only appended to, so these arrays build over time.

For example in the line here:
spyslope= stats.zscore(context.spyslopeindex, axis=0, ddof=1)[-1]

The context.spyslope_index an array with a length equal to the number of days the algo has been running.

Seems like a bug to me, truncating this array to say the last 22 days yields very different results.

@io trader: if I would put it live I would preload/generate a decent history.

I ported the algo to Q2 and I added a Market Bias indicator and fixed and documented the code. I didn't optimise the parameters yet and I didn't align them ... I leave that for someone who thinks that makes a difference. The current parameters are a bit standard, a trading week and a half, a monthly period and a 200 day period, works for me

Happy to see improvements!

Clone Algorithm
261
Loading...
Backtest from to with initial capital
Total Returns
--
Alpha
--
Beta
--
Sharpe
--
Sortino
--
Max Drawdown
--
Benchmark Returns
--
Volatility
--
Returns 1 Month 3 Month 6 Month 12 Month
Alpha 1 Month 3 Month 6 Month 12 Month
Beta 1 Month 3 Month 6 Month 12 Month
Sharpe 1 Month 3 Month 6 Month 12 Month
Sortino 1 Month 3 Month 6 Month 12 Month
Volatility 1 Month 3 Month 6 Month 12 Month
Max Drawdown 1 Month 3 Month 6 Month 12 Month
# Backtest ID: 57540193b970870f83363f22
There was a runtime error.

last version

Clone Algorithm
261
Loading...
Backtest from to with initial capital
Total Returns
--
Alpha
--
Beta
--
Sharpe
--
Sortino
--
Max Drawdown
--
Benchmark Returns
--
Volatility
--
Returns 1 Month 3 Month 6 Month 12 Month
Alpha 1 Month 3 Month 6 Month 12 Month
Beta 1 Month 3 Month 6 Month 12 Month
Sharpe 1 Month 3 Month 6 Month 12 Month
Sortino 1 Month 3 Month 6 Month 12 Month
Volatility 1 Month 3 Month 6 Month 12 Month
Max Drawdown 1 Month 3 Month 6 Month 12 Month
# Backtest ID: 57541bb8eef29b0f8f761fca
There was a runtime error.

@Peter Bakker, some awesome improvement in the max draw-down and the initial first years of performance without a huge hit to the ending performance. I am interested in the modifications that you made and plan to go through the algo as much as possible. Great job!

@Peter, thanks a lot, brilliant idea to use market bias indicator to control maxdd. I will try to add short and do some optimization.

What about buying SH instead of going all to cash?

@Dave: In one of my own variants, I've modified each SPY buy order to also zero out SH:

order_target_percent(context.sh, 0)

And each SPY sell order to buy up SH at the same time:

order_target_percent(context.sh, 1)

I'm currently testing whether this works with real money trading via Robinhood Instant. If you're interested in getting in on the strategy, be sure to get in line for Robinhood Instant (otherwise you'll have to wait 3 days for settlement before switching funds between SPY and SH, which may impact returns).

Thanks for the advice Eric. I have Robinhood Instant. I'm new to coding Python though, but know Perl, PHP, BASH very well, so I'm hoping it won't take me long to learn.

Here's a combination of SPY/SH using one of Bakker's earlier versions (v2) of the momentum algo. It's a pure long-inverse combination which never holds cash - you're either with the market or against it.

It doesn't perform as well as a variant of v3, since there are a much larger number of conditions in which we sell SPY (like market bias), some of which don't always make sense to short.

Comment out 238 and/or 235 if you only want it to pick up SH when long mavg is on a negative trend, not during short-term downturns.

Clone Algorithm
79
Loading...
Backtest from to with initial capital
Total Returns
--
Alpha
--
Beta
--
Sharpe
--
Sortino
--
Max Drawdown
--
Benchmark Returns
--
Volatility
--
Returns 1 Month 3 Month 6 Month 12 Month
Alpha 1 Month 3 Month 6 Month 12 Month
Beta 1 Month 3 Month 6 Month 12 Month
Sharpe 1 Month 3 Month 6 Month 12 Month
Sortino 1 Month 3 Month 6 Month 12 Month
Volatility 1 Month 3 Month 6 Month 12 Month
Max Drawdown 1 Month 3 Month 6 Month 12 Month
# Backtest ID: 5775449da613ea0f9950d9da
There was a runtime error.

Thanks Eric. I'll take a look.

FYI, buy TLT instead of SH have good performance while reducing the maxdd