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)
        '''