Overall Statistics
Total Trades
83
Average Win
30.34%
Average Loss
-9.11%
Compounding Annual Return
41.573%
Drawdown
59.500%
Expectancy
1.006
Net Profit
938.278%
Sharpe Ratio
0.765
Loss Rate
54%
Win Rate
46%
Profit-Loss Ratio
3.33
Alpha
0.206
Beta
1.777
Annual Standard Deviation
0.447
Annual Variance
0.2
Information Ratio
0.657
Tracking Error
0.404
Treynor Ratio
0.192
Total Fees
$521.06
from clr import AddReference # .NET Common Language Runtime (CLR) <- http://pythonnet.github.io/
AddReference("System")
AddReference("QuantConnect.Algorithm") # to load an assembly use AddReference
AddReference("QuantConnect.Common")

from System import * # CLR namespaces to be treatedas Python packages
from QuantConnect import *
from QuantConnect.Algorithm import *
from QuantConnect.Python import PythonQuandl # quandl data not CLOSE

from QuantConnect.Python import PythonData # custom data

import pandas as pd; import numpy as np
from collections import deque # double queue container

from my_custom_data import *  # QuandlFuture, CboeVix, CboeVxV


class VIXStrategyByRatio(QCAlgorithm):
    
    def Initialize(self):
        self.SetStartDate(2011, 1, 15)
        self.SetEndDate(datetime.now().date() - timedelta(1))
        self.SetCash(10000)
            
        self.SetBrokerageModel(BrokerageName.InteractiveBrokersBrokerage, 
                                AccountType.Margin)
        self.mx_len = 3 # <--- 1 too reactive, 3 filter 1 spikes, 5 filters 2... 
        self.perc_qnty = 1.0 # 0.3 is already fun enough

        # add the #2 ETFs (short and long VIX futures)
        self.XIV = self.AddEquity("XIV", Resolution.Daily).Symbol
        self.VXX = self.AddEquity("VXX", Resolution.Daily).Symbol

        # Define symbol and "type" of custom data: used for signal ratio
        self.AddData(CboeVix, "VIX")
        self.AddData(CboeVxV, "VXV")

        # VIX futures from Quandl (rtrn'settle' of # 1st continuous VIX fut)
#       self.VIX1 = "SCF/CBOE_VX1_ON"; self.AddData(QuandlFuture, self.VIX1, Resolution.Daily)

        # median of the ratio (#5d to filter 2 spikes)
        self.med_ratio = deque(maxlen=self.mx_len)
        
        self.SetWarmUp(timedelta(self.mx_len)) # no really need for this with median


    def OnData(self, data):
        
        if "VIX" not in data or "VXV" not in data: return
    
        ratio_d = data["VIX"].Open / data["VXV"].Open    # .Close will have look-ahead bias...
        self.med_ratio.append(ratio_d) # 5d 
        ratio = np.median(self.med_ratio)

        XIV_qnty = self.Portfolio[self.XIV].Quantity
        VXX_qnty = self.Portfolio[self.VXX].Quantity
            
        # short vol (buy XIV): backwardation and declining vol
        if (ratio < 0.95): # and (mom > 0.1):
            if (VXX_qnty !=0):   self.Liquidate(self.VXX) 
            if (XIV_qnty ==0):   
                self.SetHoldings(self.XIV, self.perc_qnty)
                self.Notify.Email("XXXXX@gmail.com", "IB Algo Execution", "long XIV"); self.Log("short VOL")
        
        # long vol (buy VXX): contango and increasing vol
        elif (ratio > 1.05): # and (mom < 0.1):
            if (XIV_qnty !=0):   self.Liquidate(self.XIV)
            if (VXX_qnty ==0):
                self.SetHoldings(self.VXX, self.perc_qnty)
                self.Notify.Email("XXXX@gmail.com", "IB Algo Execution", "long VXX"); self.Log("long VOL")
            
        # flat (no position)
        else:
            if (XIV_qnty !=0) or (VXX_qnty !=0):
                self.Liquidate()
                self.Notify.Email("xxxxxxxxxx@gmail.com", "IB Algo Execution", "Flat position"); self.Log("Flat")                        
from QuantConnect.Python import PythonQuandl # quandl data not CLOSE
from QuantConnect.Python import PythonData # custom data
from QuantConnect.Data import SubscriptionDataSource

from datetime import datetime, timedelta
import decimal

class CboeVix(PythonData):
    '''CBOE Vix Download Custom Data Class'''
    def GetSource(self, config, date, isLiveMode):
        url_vix = "http://www.cboe.com/publish/scheduledtask/mktdata/datahouse/vixcurrent.csv"
        return SubscriptionDataSource(url_vix, 
                                      SubscriptionTransportMedium.RemoteFile)
    def Reader(self, config, line, date, isLiveMode):
        if not (line.strip() and line[0].isdigit()): return None
        # New CboeVix object
        index = CboeVix();
        index.Symbol = config.Symbol
        try:
            # Example File Format:
            # Date          VIX Open    VIX High VIX Low    VIX Close
            # 01/02/2004    17.96    18.68     17.54        18.22
            #print line
            data = line.split(',')
            date = data[0].split('/')
            index.Time = datetime(int(date[2]), int(date[0]), int(date[1]))
            index.Value = decimal.Decimal(data[4])
            index["Open"] = float(data[1])
            index["High"] = float(data[2])
            index["Low"] = float(data[3])
            index["Close"] = float(data[4])
        except ValueError:
            # Do nothing
            return None
#       except KeyError, e:
#          print 'I got a KeyError - reason "%s"' % str(e)
        return index


# NB: CboeVxV class ==  CboeVix class, except for the URL
class CboeVxV(PythonData):
    '''CBOE VXV Download Custom Data Class'''
    
    def GetSource(self, config, date, isLiveMode):
        url_vxv = "http://www.cboe.com/publish/scheduledtask/mktdata/datahouse/vix3mdailyprices.csv"
        return SubscriptionDataSource(url_vxv, 
                                      SubscriptionTransportMedium.RemoteFile)
    def Reader(self, config, line, date, isLiveMode):
        if not (line.strip() and line[0].isdigit()): return None
        index = CboeVxV();
        index.Symbol = config.Symbol
        try:
        # Example File Format:
        #                 OPEN    HIGH    LOW        CLOSE
        # 12/04/2007    24.8    25.01    24.15    24.65
            data = line.split(',')
            date = data[0].split('/')
            index.Time = datetime(int(date[2]), int(date[0]), int(date[1]))
            index.Value = decimal.Decimal(data[4])
            index["Open"] = float(data[1])
            index["High"] = float(data[2])
            index["Low"] = float(data[3])
            index["Close"] = float(data[4])
        except ValueError:
                # Do nothing
                return None
        return index

# for using VIX futures settle in calc. ratios like VIX/VIX1
class QuandlFuture(PythonQuandl):
    '''Custom quandl data type for setting customized value column name. 
       Value column is used for the primary trading calculations and charting.'''
    def __init__(self):
        # Define ValueColumnName: cannot be None, Empty or non-existant column name
        # If ValueColumnName is "Close", do not use PythonQuandl, use Quandl:
        # self.AddData[QuandlFuture](self.VIX1, Resolution.Daily)
        self.ValueColumnName = "Settle"