I have further developed my original strategy that I posted here to be less aggressive in order to become more suitable for the average investor in terms of risk tolerance. Since I want to compare my strategy to the typical retail investor's moderately conservative allocation of 40% stocks and 60% bonds, I am using $AOM (iShares Core Moderate Allocation ETF) as my benchmark.
Instead of shorting $VXX (or long $XIV) with 100% of the portfolio's cash every time there's a bullish WVF signal, the algo only does so with 20% of the portfolio's cash and the remaining 80% balance is parked in $AGG to hedge as well as collect yield. When there's a bearish WVF signal, the algo dumps everything and moves the entire portfolio in $TLT, which is considered a safe-haven asset. If less risk/volatility is desired, simply reduce the short-$VXX/long-$XIV portion and increase the $AGG portion. If more risk/performance is desired, do the opposite.
As you can see, for the returns generated, the algo has very impressive Beta, Sharpe, Max Drawdown, and Volatility ratings.
28-day WVF cross> 14 = sell $TLT + short $VXX + buy $AGG
28-day WVF cross< 14 = cover $VXX + sell $AGG + buy $TLT
|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|
import pandas as pd def initialize(context): context.stock1 = symbol('VXX') #VXX context.stock2 = symbol('XIV') #XIV context.stock3 = symbol('TLT') #safe haven asset context.stock4 = symbol('AGG') #bond schedule_function(func = alloc, date_rule = date_rules.every_day(), time_rule = time_rules.market_open(minutes = 15)) set_benchmark(symbol('AOM')) #moderate allocation benchmark set_commission(commission.PerShare(cost = 0.0050, min_trade_cost = 1.00)) set_slippage(slippage.VolumeShareSlippage(volume_limit = 0.025, price_impact = 0.1)) def handle_data(context, data): pass def alloc(context, data): vxx = context.stock1 xiv = context.stock2 safe_haven = context.stock3 bond = context.stock4 n = 28 vxx_prices = data.history(vxx, "price", n + 2, "1d")[:-1] vxx_lows = data.history(vxx, "low", n + 2, "1d")[:-1] vxx_highest = pd.rolling_max(vxx_prices, window = n) WVF = ((vxx_highest - vxx_lows)/(vxx_highest)) * 100 #William's VIX Fix indicator aka. the Synthetic VIX if(WVF[-2] < 14 and WVF[-1] >= 14): #bullish WVF signal order_target(safe_haven, 0.00) order_target_percent(vxx, -0.20) order_target_percent(bond, 0.80) elif(WVF[-2] > 14 and WVF[-1] <= 14): #bearish WVF signal order_target(vxx, 0) order_target(bond, 0) order_target_percent(safe_haven, 1.00) record (WVF = WVF[-1]) #Plot WVF record (trigger = 14) #Plot WVF trigger record(leverage = context.account.leverage)