Overall Statistics
Total Trades
2587
Average Win
0.15%
Average Loss
-0.14%
Compounding Annual Return
21.653%
Drawdown
36.800%
Expectancy
0.689
Net Profit
437.239%
Sharpe Ratio
0.85
Loss Rate
18%
Win Rate
82%
Profit-Loss Ratio
1.05
Alpha
0.409
Beta
-8.694
Annual Standard Deviation
0.276
Annual Variance
0.076
Information Ratio
0.777
Tracking Error
0.276
Treynor Ratio
-0.027
Total Fees
$2594.92
## from TestLibrary import BasicTemplateLibrary
from numpy import sort
from numpy import mean
from numpy import std
from numpy import array
from numpy import argpartition
from numpy import zeros
from scipy.stats import skew
from collections import deque

## Not using skew as defined in Lemperiere 2016 paper
## because the calculation was questionable

## Description:
## - Calculate momentum, momentum change, skew

class SkewIndicator:
    def __init__(self, name, LookBackLen):
        self.IsReady = False
        self.Name = name
        self.LookBackLen = LookBackLen
        self.Value = 0.0 # dummy for initiating
        self.price_queue = deque(maxlen = LookBackLen + 1)
        self.return_queue = deque(maxlen = LookBackLen)
    def Update(self, input):
        # Fill the queues
        self.price_queue.appendleft(input.Close)
        if len(self.price_queue) > 1:
            self.return_queue.appendleft(self.price_queue[1] / self.price_queue[0] - 1.0)
        # Check if ready, and calculate skew
        if len(self.return_queue) == self.return_queue.maxlen:
            self.IsReady = True
            self.Value = self.calculateSkew()
            
    def calculateSkew(self):
        #  Return vector
        returnVec = list(self.return_queue)
        return skew(returnVec)
        
class LongPositiveSkew(QCAlgorithm):
    LookBackLen = 150
    tradeSize = 1.0
    skewThreshold = 0.1
    selectTopN = 3
    
    def Initialize(self):
        self.SetStartDate(2010, 12, 12)  # Set Start Date
        self.SetCash(13000)  # Set Strategy Cash
        
        # Universe
        self.tickerList = ["XLP","XLU","XLK","XLV","XLY","XLI","XLF","XLB","XLE"]
        self.numTickers = len(self.tickerList)
        for i in range(self.numTickers):
            self.AddEquity(self.tickerList[i], Resolution.Daily)
        self.UniverseSettings.Resolution = Resolution.Daily
        symbols = [ Symbol.Create(self.tickerList[0], SecurityType.Equity, Market.USA), \
                    Symbol.Create(self.tickerList[1], SecurityType.Equity, Market.USA) ]
        self.SetUniverseSelection(ManualUniverseSelectionModel(symbols))
        
        # Indicator
        self.SkewIndicatorList = []
        for i in range(self.numTickers):
            self.SkewIndicatorList.append(SkewIndicator('mySkew_' + self.tickerList[i], self.LookBackLen))
            self.RegisterIndicator(self.tickerList[i], self.SkewIndicatorList[i], Resolution.Daily)
        
        # Chart
        self.chartName = "Skew Chart"
        SkewChart = Chart(self.chartName, ChartType.Stacked)
        for i in range(self.numTickers):
            SkewChart.AddSeries(Series('Skew_' + self.tickerList[i], SeriesType.Line))
        self.AddChart(SkewChart);
        
        self.SetBrokerageModel(BrokerageName.InteractiveBrokersBrokerage, AccountType.Margin)

    def OnData(self, data):
        LatestSkews = zeros(self.numTickers)
        for i in range(self.numTickers):
            self.Plot(self.chartName, 'Skew_' + self.tickerList[i], self.SkewIndicatorList[i].Value)
            LatestSkews[i] = self.SkewIndicatorList[i].Value
            
        topSkewIndices = argpartition(LatestSkews, self.numTickers - self.selectTopN)[(self.numTickers - self.selectTopN):]
        
        for i in range(self.selectTopN):
            thisIndex = topSkewIndices[i]
            if self.SkewIndicatorList[thisIndex].Value < self.skewThreshold:
                self.SetHoldings(self.tickerList[thisIndex], 0.0)
            elif self.SkewIndicatorList[thisIndex].Value > self.skewThreshold:
                self.SetHoldings(self.tickerList[thisIndex], self.tradeSize / self.selectTopN)