Statistical Arbitrage based on Divergence (Version 2)

This is a corrected version of the strategy I posted earlier (https://www.quantopian.com/posts/statistical-arbitrage-based-on-divergence).
Also, I have changed the entry and exit rules. The aim is to create a beta neutral position when divergence is observed.

For back-testing, I have used 6 IT stocks from S&P 500 companies, namely

1. Apple Inc. (AAPL)
2. Microsoft Corporation (MSFT)
3. Amazon.com Inc. (AMZN)
4. Alphabet Inc. Class A (GOOGL)
5. Accenture (ACN)

Following are the steps for the strategy:

Calculations required
Every day, at market open, I calculate the historical volatility of the stocks as well as the benchmark (SPY) based on last one month's data, and calculate beta with respect to the benchmark for every stock.

Every day, 5 minutes before the market closes, I compute the divergence of every stock. Divergence is calculated is the difference between the stock's daily percentage return and the expected return of the stock based on its beta (Expected Return = (Benchmark Return*Stock Beta)).

Entry Rules
Once I have the divergence for every stock, I find the stock with maximum divergence values. Then I find the stock with minimum positive divergence. In case all the other stocks have a negative divergence, I select the stock with maximum negative divergence.
Then, I short the stock with maximum divergence if the divergence value is more than 1% and long the stock with minimum positive (or maximum negative) divergence value.

Exit and Stop Loss Rule
I square off my positions when the divergence of the stock with maximum divergence (at the time of entry) becomes less than or equal to 1/4th of divergence at the time of entry or when the the divergence of the stock with maximum divergence (at the time of entry) becomes more than or equal to 1.5 times the divergence at the time of entry.

12
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: 5a242ab0f5dc6040ff66c7ae
There was a runtime error.
4 responses

Max Lvrg: 7.82 2008-01-03
Max Lvrg: 11.90 2008-01-16
Usually due to partial fills. For example, tracking GOOG_L ...

2008-01-02 06:31 ti:261 INFO 2008-01-02 to 2017-11-30  $100000 2017-12-03 10:23 US/Pacific 2008-01-02 12:50 _t:433 INFO 380 Buy 1000 GOOG_L 681.66 _ 0 0.00 6da5 100000 2008-01-02 12:51 _t:433 INFO 381 Bot 379|0|1000 GOOG_L 682.06 379 -17 3.19 6da5 -98088 2008-01-02 12:52 _t:433 INFO 382 Bot 503|379|1000 GOOG_L 683.00 882 318 6.61 6da5 -441659 2008-01-02 12:53 _t:433 INFO 383 Bot all 118|882|1000 GOOG_L 683.57 1000 820 7.39 6da5 -522320 2008-01-03 12:50 _t:433 INFO 380 Sell -1000 GOOG_L 682.54 1000 -210 7.41 5788 -522320 2008-01-03 12:51 _t:433 INFO 381 Sold -628|0|-1000 GOOG_L 682.58 372 -64 2.54 5788 -153835 2008-01-03 12:52 _t:433 INFO 382 Sold all -372|-628|-1000 GOOG_L 683.20 _ [+98] 0.00 5788 100306 2008-01-08 13:00 _ti:967 INFO 5 trading days 0 hr 0.0 min 2017-12-03 10:23 US/Pacific Portfolio: 101325 2008-01-02 to 2017-11-30 Alpha: Initial Cash: 100000 Buys: 5 (2 partial) Beta: 0.82 Unused Cash: 0 Sells: 5 (1 partial) Sharpe: Max Margin: -522321 Commissions: 9 Drawdown: 9.2 Max Risk: 622321 (622%) Shares Now: 1866 Stability: 0.030 Cash Profit: 38224 Shares Val: -36899 Sortino: Total Profit: 1325 Cash Now: 138224 Shrt/Lng Now: 1.94 Q Return: 1.33% Profit/Init Max Lvrg: 7.82 2008-01-03 Max Shorts: -76139 PvR Return: 0.21% Profit/Risk PvR %/day: 0.04 Max Longs: 686590 2008-01-08 13:00 ti:1139 INFO . 2008-01-08 13:00 _ti:967 INFO Sort column 1 Positions: 2 of 5 traded Profit Max Return Return Buy Price Buy|Sell Max Shares Shares Symbol PnL Risked % %/day Hold Init|Now Orders Shrt|Lng Now % ACN 1008 34939 2.89 1.44 -0.0 35|34 1|1 -1000|0 0 0 MSFT 231 27592 0.84 0.42 -0.0 34|33 1|1 0|803 0 0 AMZN 178 76317 0.23 0.12 -0.1 96|88 1|2 -866|0 -866 -0.7514 GOOG_L 98 682712 0.01 0.01 -0.1 682|631 1|1 0|1000 0 0 ADBE -111 39351 -0.28 -0.28 -0.0 39|39 1|0 0|1000 1000 0.3873 Trading Minute Action Fild|Prv|Ordr Sym Prc Shrs PnL Lvrg Oid Cash 2008-01-14 12:50 _t:433 INFO 380 Buy 1000 GOOG_L 653.91 _ 0 0.00 c32f 104272 2008-01-14 12:51 _t:433 INFO 381 Bot 375|0|1000 GOOG_L 654.71 375 -16 2.96 c32f -77748 2008-01-14 12:52 _t:433 INFO 382 Bot 245|375|1000 GOOG_L 654.14 620 -240 4.51 c32f -238023 2008-01-14 12:53 _t:433 INFO 383 Bot all 380|620|1000 GOOG_L 653.61 1000 -576 6.90 c32f -486402 2008-01-16 12:50 _t:433 INFO 380 Sell -1000 GOOG_L 617.48 1000 -36706 9.77 3da8 -486402 2008-01-16 12:51 _t:433 INFO 381 Sold -783|0|-1000 GOOG_L 616.88 217 -8096 1.94 3da8 -65008 2008-01-16 12:52 _t:433 INFO 382 Sold all -217|-783|-1000 GOOG_L 617.97 _ [-36940] 0.00 3da8 69090 2008-02-05 12:50 _t:433 INFO 380 Sell -587 GOOG_L 507.79 _ 0 0.00 cb48 66228 2008-02-05 12:51 _t:433 INFO 381 Sold -587 GOOG_L 508.28 -587 -3 4.57 cb48 360237 2008-02-06 12:50 _t:433 INFO 380 Buy 587 GOOG_L 501.83 -587 3783 4.66 0231 331119 2008-02-06 12:51 _t:433 INFO 381 Bot 587 GOOG_L 501.50 _ [-32961] 0.32 0231 47926 2008-02-07 12:50 _t:433 INFO 380 Sell -38 GOOG_L 503.30 _ 0 0.00 9378 70448 2008-02-07 12:51 _t:433 INFO 381 Sold -38 GOOG_L 504.49 -38 -0 1.23 9378 157314 2008-02-08 12:50 _t:433 INFO 380 Buy 38 GOOG_L 517.15 -38 -481 1.39 ace8 160649 2008-02-08 12:51 _t:433 INFO 381 Bot 38 GOOG_L 516.99 _ [-33437] 0.03 ace8 69283 2008-02-26 12:50 _t:433 INFO 380 Sell -468 GOOG_L 462.21 _ 0 0.00 afec 71931 2008-02-26 12:51 _t:433 INFO 381 Sold -468 GOOG_L 462.78 -468 -1 3.52 afec 325007 2008-02-28 12:50 _t:433 INFO 380 Buy 468 GOOG_L 474.14 -468 -5318 3.90 d9dd 325007 2008-02-28 12:51 _t:433 INFO 381 Bot 468 GOOG_L 474.77 _ [-39050] 0.22 d9dd 80375 2008-03-03 13:00 _ti:967 INFO 42 trading days 0 hr 0.4 min 2017-12-03 10:23 US/Pacific Portfolio: 66027 2008-01-02 to 2017-11-30 Alpha: Initial Cash: 100000 Buys: 37 (15 partial) Beta: -0.30 Unused Cash: 0 Sells: 37 (20 partial) Sharpe: Max Margin: -522321 Commissions: 49 Drawdown: 52.0 Max Risk: 622321 (622%) Shares Now: 0 Stability: 0.546 Cash Profit: -33973 Shares Val: 0 Sortino: Total Profit: -33973 Cash Now: 66027 Shrt/Lng Now: Q Return: -33.97% Profit/Init Max Lvrg: 11.90 2008-01-16 Max Shorts: -299188 PvR Return: -5.46% Profit/Risk PvR %/day: -0.13 Max Longs: 686590 2008-03-03 13:00 ti:1139 INFO . 2008-03-03 13:00 _ti:967 INFO Sort column 1 Positions: 0 of 6 traded Profit Max Return Return Buy Price Buy|Sell Max Shares Shares Symbol PnL Risked % %/day Hold Init|Now Orders Shrt|Lng Now % AMZN 9008 83311 10.8 0.9 -0.3 96|62 10|10 -1000|0 0 0 ACN 2860 39632 7.22 0.56 -0.0 35|35 9|9 -1000|1000 0 0 ADBE 1684 39351 4.28 0.86 -0.2 39|33 4|4 0|1000 0 0 MSFT 231 27592 0.84 0.42 -0.2 34|27 1|1 0|803 0 0 AAPL -8475 159219 -5.32 -0.89 -0.2 159|122 3|3 -1000|0 0 0 GOOG_L -39050 682712 -5.72 -0.71 -0.3 682|457 5|5 -587|1000 0 0  Hi, Thanks for pointing that out. I ran the backtest again with a capital of$400,000.
That brought down the leverage to 2x.

PFA the backtest for the same and let me know your views on it.

Thanks

12
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: 5a2459ef0089f540792e7284
There was a runtime error.

Sure. Couple thoughts.

You can be certain of the max leverage this way since it watches every minute although it will slow things down a bit:

def initialize(context):
context.mx_lvrg = 0
...
def handle_data(context, data):
if context.account.leverage > context.mx_lvrg:
context.mx_lvrg = context.account.leverage
record(MxLv = context.mx_lvrg)       # Record maximum leverage encountered


With the goal in mind of not needing to worry about leverage, if you could distribute each stock's orders at different times so they won't overlap each other, could be one thing to try. The essential deal is when selling (including short), and incomplete, and buying complete, that's when the leverage is occurring here probably. Although leverage can also happen quickly with an increase in price in short shares.

Another route (since there are only six stocks here so far) that is difficult and requires a lot of code would be to hold each stock's order until the previous is complete. Dealing with them in a loop perhaps, and rechecking for get_open_orders(), only proceeding to the next when any partial fills are done, or only buying with available cash. Or maybe schedule a few times and change ratio*1000 to a lower number, distributing in that way. That would be the simplest I think, although I haven't delved into it to wrap my head around your code very well. Previously all I did is drop some code into it and take a look at the output.

Hi,

Thanks for the suggestion. I will surely try running the back-test using your methodology for controlling the leverage.