| Overall Statistics |
|
Total Trades 2249 Average Win 5.45% Average Loss -0.26% Compounding Annual Return 29.503% Drawdown 34.700% Expectancy 1.093 Net Profit 1631.693% Sharpe Ratio 1.087 Probabilistic Sharpe Ratio 46.971% Loss Rate 91% Win Rate 9% Profit-Loss Ratio 21.05 Alpha 0.232 Beta -0.059 Annual Standard Deviation 0.208 Annual Variance 0.043 Information Ratio 0.456 Tracking Error 0.258 Treynor Ratio -3.8 Total Fees $193535.59 |
# Investment universe consists of SPDR S&P500 Trust ETF (SPY) and ProShares Short S&P500 ETF (SH) for long and short exposure to the
# S&P500 and iPath S&P500 VIX ST Futures ETN (VXX) and VelocityShares Daily Inverse VIX ST ETN (XIV) for long and short exposure to
# short-term VIX futures. First, the relative difference between the front-month VIX futures and spot VIX is calculated
# (contango/backwardation check). If the relative basis is above (below) an upper (lower) buy threshold, BU (BL) determined by the trader,
# it indicates that the market is in contango (backwardation) and that one should hold XIV (VXX) and hedge with SH (SPY). The position is
# closed when the relative basis falls below an upper (lower) sell-threshold, SU (SL), which may be set equal to, or lower (higher) than
# the buy-threshold. A reason why one might want the upper (lower) sell-threshold lower (higher) than the upper (lower) buy-threshold is
# to avoid too-frequent trading. The best results are with a 0% hedge ratio (trader doesn’t use SPY/SH hedging). However, it is possible
# to use multiple different hedging levels with different results (see table 10 in a source academic paper for more options).
from QuantConnect.Python import PythonQuandl
class TradingVIXETFsv2(QCAlgorithm):
def Initialize(self):
self.SetStartDate(2010, 1, 1)
self.SetCash(100000)
self.vixy = self.AddEquity('VIXY', Resolution.Daily).Symbol
# Vix futures data.
self.vix_future = self.AddFuture(Futures.Indices.VIX, Resolution.Minute)
# Vix spot.
self.vix_spot = self.AddData(QuandlVix, 'CBOE/VIX', Resolution.Daily).Symbol
# Find the front contract expiring no earlier than in 90 days.
self.vix_future.SetFilter(timedelta(0), timedelta(90))
# Vix futures actiove contract updated on expiration.
self.active_contract = None
self.Schedule.On(self.DateRules.EveryDay(self.vixy), self.TimeRules.AfterMarketOpen(self.vixy), self.Rebalance)
def Rebalance(self):
if self.active_contract:
if self.Securities.ContainsKey(self.vix_spot):
spot_price = self.Securities[self.vix_spot].Price
vix_future_price = self.active_contract.LastPrice
if spot_price == 0 or vix_future_price == 0:
return
relative_basis = vix_future_price / spot_price
# If the relative basis is above an upper buy threshold - BU, it indicates that the market is in contango and that one should hold XIV(long VIXY in our case) and hedge with SH (no hedge in our case).
# If the relative basis is below an lower buy threshold - BL, it indicates that the market is in backwardation and that one should hold VXX(short VIXY in our case) and hedge with SPY (no hedge in our case).
# BU 8%, SU 6%, BL -8%, SL -6% thresholds.
# Short volatility.
if relative_basis >= 1.08:
self.SetHoldings(self.vixy, 1)
if relative_basis >= 1.06:
if self.Portfolio[self.vixy].Invested:
self.Liquidate(self.vixy)
if relative_basis < 1.06 and relative_basis > 0.94:
if self.Portfolio[self.vixy].Invested:
self.Liquidate(self.vixy)
# Long volatility.
if relative_basis <= 0.94:
if self.Portfolio[self.vixy].Invested:
self.Liquidate(self.vixy)
if relative_basis <= 0.92:
self.SetHoldings(self.vixy, -1)
def OnData(self, slice):
chains = [x for x in slice.FutureChains]
cl_chain = None
if len(chains) > 0:
cl_chain = chains[0]
else:
return
if cl_chain.Value.Contracts.Count >= 1:
contracts = [i for i in cl_chain.Value]
contracts = sorted(contracts, key = lambda x: x.Expiry)
near_contract = contracts[0]
self.active_contract = near_contract
class QuandlVix(PythonQuandl):
def __init__(self):
self.ValueColumnName = "VIX Close"