| Overall Statistics |
|
Total Trades 812 Average Win 2.30% Average Loss -1.96% Compounding Annual Return 47.056% Drawdown 28.300% Expectancy 0.322 Net Profit 978.667% Sharpe Ratio 1.443 Loss Rate 39% Win Rate 61% Profit-Loss Ratio 1.17 Alpha 0.36 Beta -0.175 Annual Standard Deviation 0.238 Annual Variance 0.057 Information Ratio 0.879 Tracking Error 0.285 Treynor Ratio -1.967 Total Fees $60635.04 |
#
import numpy as np
import pandas as pd
import datetime
import math
import scipy.stats as stats
import re
from pandas import DataFrame,Series
class BasicTemplateAlgorithm(QCAlgorithm):
def Initialize(self):
self.lookbackPeriod = 252 # lookback period for slopes zscore
self.FlatBeforeReverse = False # if True goes flat before open new position.
self.vixFilter = 00.0 # values less that vixFilter don't open new positions.
# Set the cash we'd like to use for our backtest
# This is ignored in live trading
self.SetCash(100000)
self.SetStartDate(2011,1,1)
self.SetEndDate(2017,2,28)
# Add assets you'd like to see
self.longVol = self.AddEquity("VXX", Resolution.Minute).Symbol
self.longVolF = +0.98
self.shortVol = self.AddEquity("XIV", Resolution.Minute).Symbol
self.shortVolF = +0.98
self.longVolFactor = 0.0
self.shortVolFactor = 0.0
self.vixClose0 = 0.0
self.slope = 0.0
self.slopes = Series()
self.tradesH0 = 0
self.tradesM0 = 0
self.tradesPos0 = 0
self.Schedule.On(self.DateRules.EveryDay(self.longVol), self.TimeRules.At(8,30), Action(self.EveryDayBeforeMarketOpen))
self.newDay = False
def EveryDayBeforeMarketOpen(self):
self.newDay = True
self.todayD = str(self.Time)
self.todayD = self.todayD.split('-')
self.todayD = datetime.datetime(int(self.todayD[0]),int(self.todayD[1]),int(str(self.todayD[2].split(' ')[0])))
self.Log(str(self.todayD))
iRowVix = -1
try:
datVix = pd.read_csv('http://www.cboe.com/publish/scheduledtask/mktdata/datahouse/vixcurrent.csv', skiprows = 1)
datVix['Date']= pd.to_datetime(datVix['Date'])
for index in range(7):
lastBar = datVix.iloc[-1].copy()
lastBar.Date += datetime.timedelta(days=1)
lastBar.name += 1
datVix= datVix.append(lastBar)
datVix['VIX Open'] = datVix['VIX Open'].shift(1)
datVix['VIX High'] = datVix['VIX High'].shift(1)
datVix['VIX Low'] = datVix['VIX Low'].shift(1)
datVix['VIX Close'] = datVix['VIX Close'].shift(1)
iRowVix = datVix.loc[datVix['Date']==self.todayD].index[0]
self.vixClose0 = datVix['VIX Close'].values[iRowVix]
except Exception, e:
iRowVix = -1
iRowVxv = -1
try:
datVxv = pd.read_csv('http://www.cboe.com/publish/scheduledtask/mktdata/datahouse/vix3mdailyprices.csv', skiprows = 2)
datVxv.rename(columns={'Unnamed: 0': 'Date'}, inplace=True)
datVxv['Date']= pd.to_datetime(datVxv['Date'])
for index in range(7):
lastBar = datVxv.iloc[-1].copy()
lastBar.Date += datetime.timedelta(days=1)
lastBar.name += 1
datVxv= datVxv.append(lastBar)
datVxv['OPEN'] = datVxv['OPEN'].shift(1)
datVxv['HIGH'] = datVxv['HIGH'].shift(1)
datVxv['LOW'] = datVxv['LOW'].shift(1)
datVxv['CLOSE'] = datVxv['CLOSE'].shift(1)
iRowVxv = datVxv.loc[datVxv['Date']==self.todayD].index[0]
#self.vxvClose0 = datVxv['CLOSE'].values[iRowVxv]
except Exception, e:
iRowVxv = -1
self.slopes = Series()
j = 0
if iRowVix > 0 and iRowVxv > 0:
for i in range(len(datVix)):
cont = False
if str(datVix['Date'].values[i])[:10] <= str(self.todayD)[0:10]:
cont = True
#if str(datVix['Date'].values[i])[:10] < '2012-01-01':
# cont = False
while cont and j < len(datVxv):
if datVix['Date'].values[i] < datVxv['Date'].values[j]:
cont = False
else:
if datVix['Date'].values[i] == datVxv['Date'].values[j]:
cont = False
if not np.isnan(datVix['VIX Close'].values[i]) and not np.isnan(datVxv['CLOSE'].values[j]):
self.slope = datVxv['CLOSE'].values[j] / datVix['VIX Close'].values[i]
self.slopes = self.slopes.append(Series(self.slope, index = [datVix['Date'].values[i]]))
else:
j += 1
#self.Log(str(self.slopes[-5:]))
#if iRowVix > 0 and iRowVxv > 0 and not np.isnan(self.vixClose0) and not np.isnan(self.vxvClose0):
# self.slope = self.vxvClose0 /self.vixClose0
# self.slopes = self.slopes.append(Series(self.slope, index = [self.todayD]))
self.longVolFactor = 0.0
self.shortVolFactor = 0.0
if len(self.slopes) >= self.lookbackPeriod:
self.slopes = self.slopes[-self.lookbackPeriod:]
if len(self.slopes) >= 5:
zscore = stats.zscore(self.slopes, axis=0, ddof=1)[-1]
if (zscore*100 > 1.0):
self.shortVolFactor = 1.0
elif (zscore*100 < -1.0):
self.longVolFactor = 1.0
self.tradesH0 = 0
self.tradesM0 = 0
self.tradesPos0 = ""
iRowTrades = -1
try:
datTrades = pd.read_csv('https://www.dropbox.com/s/6oi69hlbm1yj9ba/VIXVX_trades.csv?dl=1', skiprows = 0)
#datTrades['Date']= pd.to_datetime(datTrades['Date'])
self.Log(str(datTrades.head(1)))
self.Log('*'+str(self.todayD)[0:10]+'*')
self.Log('*'+str(datTrades['Date'].values[-1])+'*')
iRowTrades = datTrades.loc[datTrades['Date']==str(self.todayD)[0:10]]
if len(iRowTrades) > 0:
iRowTrades = iRowTrades.index[0]
self.tradesH0 = datTrades['Hour'].values[iRowTrades]
self.tradesM0 = datTrades['Minute'].values[iRowTrades]
self.tradesPos0 = datTrades['Pos'].values[iRowTrades]
#self.vxvClose0 = datVxv['CLOSE'].values[iRowVxv]
except Exception, e:
iRowTrades = -1
def OnData(self, slice):
self.now= str(self.Time)
self.now = self.now.split('-')
self.now = self.now[2].split(' ')[1]
self.now = self.now.split(':')
hh = int(self.now[0])
mm = int(self.now[1])
if self.newDay and len(self.slopes) >= 5:
if self.tradesPos0 == 'Short':
if hh == self.tradesH0 and mm == self.tradesM0:
self.Log('Short')
self.SetHoldings(self.shortVol, 1,True)
self.newDay = False
if self.tradesPos0 == 'Long':
if hh == self.tradesH0 and mm == self.tradesM0:
self.Log('Long')
self.SetHoldings(self.longVol, 1,True)
self.newDay = False
if hh >= 15 and mm > 57:
self.Log("cerrar Long XIV")
self.Log(str(self.Portfolio[self.shortVol].Quantity))
if not self.newDay and self.Portfolio[self.shortVol].Quantity > 0:
self.SetHoldings(self.shortVol, 0,True)
if not self.newDay and self.Portfolio[self.longVol].Quantity > 0:
self.SetHoldings(self.longVol, 0,True)
#self.Log(str(self.longVolFactor))
#self.Log(str(self.shortVolFactor))
'''
if self.longVolFactor > 0.99999:
if self.vixClose0 >= self.vixFilter:
self.SetHoldings(self.longVol, self.longVolF * self.longVolFactor,True)
else:
self.SetHoldings(self.shortVol, 100000,True)
if self.shortVolFactor > 0.99999:
if self.vixClose0 >= self.vixFilter:
self.SetHoldings(self.shortVol, self.shortVolF * self.shortVolFactor,True)
else:
self.SetHoldings(self.longVol, 0,True)
'''