| Overall Statistics |
|
Total Trades 44 Average Win 3.16% Average Loss -2.10% Compounding Annual Return 17.181% Drawdown 3.000% Expectancy 0.368 Net Profit 17.181% Sharpe Ratio 1.325 Probabilistic Sharpe Ratio 77.951% Loss Rate 45% Win Rate 55% Profit-Loss Ratio 1.51 Alpha 0.094 Beta -0.011 Annual Standard Deviation 0.072 Annual Variance 0.005 Information Ratio 0.881 Tracking Error 0.16 Treynor Ratio -8.34 Total Fees $1306.50 Estimated Strategy Capacity $170000000.00 Lowest Capacity Asset GOOCV VP83T1ZUHROL Portfolio Turnover 5.96% |
# region imports
from AlgorithmImports import *
# endregion
class LiquidUniverseSelection(QCAlgorithm):
filteredByPrice = None
def Initialize(self):
self.SetStartDate(2018, 1, 1)
self.SetEndDate(2019, 1, 1)
self.SetCash(1000000)
# Addiing a universe based on two joint selections: self.CoarseSelectionFilter and self.FineSelectionFunction
# The second argument is option,that is, to have fundamental filter, you still need the first filter
self.AddUniverse(self.CoarseSelectionFilter, self.FineSelectionFunction)
#self.AddUniverse(coarse,self.FineSelectionFunction)
self.UniverseSettings.Resolution = Resolution.Daily
self.SetSecurityInitializer(lambda x: x.SetDataNormalizationMode(DataNormalizationMode.Raw))
#1. Set the leverage to 2
# self.UniverseSettings.Leverage = 2
# self.Liquidate()
self.counter = 0
self.Debug("Start time " + str(self.StartDate))
# see document here https://www.quantconnect.com/docs/data-library/fundamentals#Fundamentals-Asset-Classification
def CoarseSelectionFilter(self, coarse):
sortedByDollarVolume = sorted(coarse, key=lambda c: c.DollarVolume, reverse=True)
filteredByPrice = [c.Symbol for c in sortedByDollarVolume if c.Price>10]
self.filter_coarse = filteredByPrice[:100]
return self.filter_coarse
def FineSelectionFunction(self, fine):
fine1 = [x for x in fine if x.AssetClassification.MorningstarSectorCode == MorningstarSectorCode.CommunicationServices]
#ranked by the market cap
sortedByMarketCap = sorted(fine1, key=lambda c: c.MarketCap, reverse=True)
filteredFine = [i.Symbol for i in sortedByMarketCap]
self.filter_fine = filteredFine[:5]
return self.filter_fine
# def OnSecuritiesChanged(self, changes):
# self.changes = changes
#for security in self.changes.RemovedSecurities:
#List of securities that are removed from the filter
#if security.Invested:
#self.Liquidate(security.Symbol)
#self.Debug(str(security.Symbol) + " is removed")
#for security in self.changes.AddedSecurities:
#list of securities that are added to the filter
# self.SetHoldings(security.Symbol, ...)
#self.Debug(str(security.Symbol) + " is added ")
#if not self.Portfolio[security.Symbol].Invested:
#self.SetHoldings(security.Symbol, 0.05)
#if self.Portfolio[security.Symbol].Quantity != 0:
#self.Debug(str(security.Symbol) + " is added with positions " + str(self.Portfolio[security.Symbol].Quantity))
def OnData(self, data):
#self.Log(f"OnData({self.UtcTime}): Keys: {', '.join([key.Value for key in data.Keys])}")
# if we have no changes, do nothing
#if self._changes is None: return"Invested - "+ str(self.Portfolio[security.Symbol].Invested)
# liquidate removed securities
#for security in self._changes.RemovedSecurities:
#if security.Invested:
#self.Liquidate(security.Symbol)
if self.counter==0:
for ticker in self.filter_fine:
#if not ticker in self.filter_fine:
string = "- " + str(ticker)
#string = str(self.Securities[ticker].Fundamentals.DollarVolume)
#string = "Time " + str(self.Time) + " Symbol " + str(ticker) + "Invested - " + str(self.Portfolio[ticker].Quantity)
#string = string + " PE Ratio - " + str(self.Securities[ticker].Fundamentals.ValuationRatios.PERatio)
self.Debug (string) # print to see in the Console
#self.Log(string) # print to a file with full details. Link to the file is at the bottom of Console screen
self.counter += 1#region imports
from AlgorithmImports import *
#endregion
import numpy as np
import pandas as pd
from datetime import timedelta, datetime
import math
import statsmodels.api as sm
from statsmodels.tsa.stattools import coint, adfuller
'''
This is an example of implementation of the pairs trading strategy discussed in lecture8
'''
class PairsTradingAlgorithm(QCAlgorithm):
def Initialize(self):
self.SetStartDate(2018, 1, 1)
self.SetEndDate(2019,1,1)
self.SetCash(1000000)
self.enter = 2 # Set the enter threshold
self.exit = 0 # Set the exit threshold
self.lookback = 20 # Set the lookback period 90 days
self.pairs =['FB','GOOG']
self.symbols =[]
for ticker in self.pairs:
self.AddEquity(ticker, Resolution.Daily)
self.symbols.append(self.Symbol(ticker))
self.sym1 = self.symbols[0]
self.sym2 = self.symbols[1]
def stats(self, symbols):
#Use Statsmodels package to compute linear regression and ADF statistics
self.df = self.History(symbols, self.lookback)
self.dg = self.df["open"].unstack(level=0)
#self.Debug(self.dg)
ticker1= str(symbols[0])
ticker2= str(symbols[1])
Y = self.dg[ticker1].apply(lambda x: math.log(x))
X = self.dg[ticker2].apply(lambda x: math.log(x))
X = sm.add_constant(X)
model = sm.OLS(Y,X)
results = model.fit()
sigma = math.sqrt(results.mse_resid) # standard deviation of the residual
slope = results.params[1]
intercept = results.params[0]
res = results.resid #regression residual mean of res =0 by definition
zscore = res/sigma
adf = adfuller (res)
return [adf, zscore, slope]
def OnData(self, data):
self.IsInvested = (self.Portfolio[self.sym1].Invested) or (self.Portfolio[self.sym2].Invested)
self.ShortSpread = self.Portfolio[self.sym1].IsShort
self.LongSpread = self.Portfolio[self.sym1].IsLong
stats = self.stats([self.sym1, self.sym2])
self.beta = stats[2]
zscore= stats[1][-1]
self.wt1 = 1/(1+self.beta)
self.wt2 = self.beta/(1+self.beta)
self.pos1 = self.Portfolio[self.sym1].Quantity
self.px1 = self.Portfolio[self.sym1].Price
self.pos2 = self.Portfolio[self.sym2].Quantity
self.px2 = self.Portfolio[self.sym2].Price
self.equity =self.Portfolio.TotalPortfolioValue
if self.IsInvested:
if self.ShortSpread and zscore <= self.exit or \
self.LongSpread and zscore >= self.exit:
self.Liquidate()
else:
if zscore > self.enter:
#short spread
#rememebr SetHoldings take a Symbol as its first variable.
self.SetHoldings(self.sym1, -self.wt1)
self.SetHoldings(self.sym2, self.wt2)
if zscore < - self.enter:
#long the spread
self.SetHoldings(self.sym1, self.wt1)
self.SetHoldings(self.sym2, -self.wt2)
self.pos1 = self.Portfolio[self.sym1].Quantity
self.pos2 = self.Portfolio[self.sym2].Quantity
self.Debug("sym1 " + str(self.sym1.Value) + " /w "+ str(self.pos1) + " sym2 " +str(self.sym2.Value) + " /w "+str(self.pos2))
self.Debug("Total Account Equity: "+ str( self.equity) + "Total Marginused: "+ str( self.Portfolio.TotalMarginUsed))#region imports
from AlgorithmImports import *
#endregion
import numpy as np
import pandas as pd
from datetime import timedelta, datetime
import math
import statsmodels.api as sm
from statsmodels.tsa.stattools import coint, adfuller
'''
This is an example of implementation of the pairs trading strategy discussed in lecture8
'''
class PairsTradingAlgorithm(QCAlgorithm):
def Initialize(self):
self.SetStartDate(2018, 1, 1)
self.SetEndDate(2019,1,1)
self.SetCash(1000000)
self.enter = 2 # Set the enter threshold
self.exit = 0 # Set the exit threshold
self.lookback = 20 # Set the lookback period 90 days
self.pairs =['FB','GOOG']
self.symbols =[]
for ticker in self.pairs:
self.AddEquity(ticker, Resolution.Daily)
self.symbols.append(self.Symbol(ticker))
self.sym1 = self.symbols[0]
self.sym2 = self.symbols[1]
def stats(self, symbols):
#Use Statsmodels package to compute linear regression and ADF statistics
self.df = self.History(symbols, self.lookback)
self.dg = self.df["open"].unstack(level=0)
#self.Debug(self.dg)
ticker1= str(symbols[0])
ticker2= str(symbols[1])
Y = self.dg[ticker1].apply(lambda x: math.log(x))
X = self.dg[ticker2].apply(lambda x: math.log(x))
X = sm.add_constant(X)
model = sm.OLS(Y,X)
results = model.fit()
sigma = math.sqrt(results.mse_resid) # standard deviation of the residual
slope = results.params[1]
intercept = results.params[0]
res = results.resid #regression residual mean of res =0 by definition
zscore = res/sigma
adf = adfuller (res)
return [adf, zscore, slope]
def OnData(self, data):
self.IsInvested = (self.Portfolio[self.sym1].Invested) or (self.Portfolio[self.sym2].Invested)
self.ShortSpread = self.Portfolio[self.sym1].IsShort
self.LongSpread = self.Portfolio[self.sym1].IsLong
stats = self.stats([self.sym1, self.sym2])
self.beta = stats[2]
zscore= stats[1][-1]
self.wt1 = 1/(1+self.beta)
self.wt2 = self.beta/(1+self.beta)
self.pos1 = self.Portfolio[self.sym1].Quantity
self.px1 = self.Portfolio[self.sym1].Price
self.pos2 = self.Portfolio[self.sym2].Quantity
self.px2 = self.Portfolio[self.sym2].Price
self.equity =self.Portfolio.TotalPortfolioValue
if self.IsInvested:
if self.ShortSpread and zscore <= self.exit or \
self.LongSpread and zscore >= self.exit or \
abs(zscore) >= 3:
if abs(zscore) >= 3:
self.Debug(f'risk control: {zscore:.4f}')
self.Liquidate()
else:
if abs(zscore) < 3:
if zscore > self.enter:
#short spread
#rememebr SetHoldings take a Symbol as its first variable.
self.SetHoldings(self.sym1, -self.wt1)
self.SetHoldings(self.sym2, self.wt2)
if zscore < - self.enter:
#long the spread
self.SetHoldings(self.sym1, self.wt1)
self.SetHoldings(self.sym2, -self.wt2)
self.pos1 = self.Portfolio[self.sym1].Quantity
self.pos2 = self.Portfolio[self.sym2].Quantity
self.Debug("sym1 " + str(self.sym1.Value) + " /w "+ str(self.pos1) + " sym2 " +str(self.sym2.Value) + " /w "+str(self.pos2))
self.Debug("Total Account Equity: "+ str( self.equity) + "Total Marginused: "+ str( self.Portfolio.TotalMarginUsed))#region imports
from AlgorithmImports import *
#endregion
import numpy as np
import pandas as pd
from datetime import timedelta, datetime
import math
import statsmodels.api as sm
from statsmodels.tsa.stattools import coint, adfuller
'''
This is an example of implementation of the pairs trading strategy discussed in lecture8
'''
class PairsTradingAlgorithm(QCAlgorithm):
def Initialize(self):
self.SetStartDate(2018, 1, 1)
self.SetEndDate(2019,1,1)
self.SetCash(1000000)
self.enter = 2 # Set the enter threshold
self.exit = 0 # Set the exit threshold
self.lookback = 20 # Set the lookback period 90 days
self.pairs =['GOOG','FB']
self.symbols =[]
for ticker in self.pairs:
self.AddEquity(ticker, Resolution.Daily)
self.symbols.append(self.Symbol(ticker))
self.sym1 = self.symbols[0]
self.sym2 = self.symbols[1]
def stats(self, symbols):
#Use Statsmodels package to compute linear regression and ADF statistics
self.df = self.History(symbols, self.lookback)
self.dg = self.df["open"].unstack(level=0)
#self.Debug(self.dg)
ticker1= str(symbols[0])
ticker2= str(symbols[1])
Y = self.dg[ticker1].apply(lambda x: math.log(x))
X = self.dg[ticker2].apply(lambda x: math.log(x))
X = sm.add_constant(X)
model = sm.OLS(Y,X)
results = model.fit()
sigma = math.sqrt(results.mse_resid) # standard deviation of the residual
slope = results.params[1]
intercept = results.params[0]
res = results.resid #regression residual mean of res =0 by definition
zscore = res/sigma
adf = adfuller (res)
return [adf, zscore, slope]
def OnData(self, data):
self.IsInvested = (self.Portfolio[self.sym1].Invested) or (self.Portfolio[self.sym2].Invested)
self.ShortSpread = self.Portfolio[self.sym1].IsShort
self.LongSpread = self.Portfolio[self.sym1].IsLong
stats = self.stats([self.sym1, self.sym2])
self.beta = stats[2]
zscore= stats[1][-1]
self.wt1 = 1/(1+self.beta)
self.wt2 = self.beta/(1+self.beta)
self.pos1 = self.Portfolio[self.sym1].Quantity
self.px1 = self.Portfolio[self.sym1].Price
self.pos2 = self.Portfolio[self.sym2].Quantity
self.px2 = self.Portfolio[self.sym2].Price
self.equity =self.Portfolio.TotalPortfolioValue
if self.IsInvested:
if self.ShortSpread and zscore <= self.exit or \
self.LongSpread and zscore >= self.exit:
self.Liquidate()
else:
if zscore > self.enter:
#short spread
#rememebr SetHoldings take a Symbol as its first variable.
self.SetHoldings(self.sym1, -self.wt1)
self.SetHoldings(self.sym2, self.wt2)
if zscore < - self.enter:
#long the spread
self.SetHoldings(self.sym1, self.wt1)
self.SetHoldings(self.sym2, -self.wt2)
self.pos1 = self.Portfolio[self.sym1].Quantity
self.pos2 = self.Portfolio[self.sym2].Quantity
self.Debug("sym1 " + str(self.sym1.Value) + " /w "+ str(self.pos1) + " sym2 " +str(self.sym2.Value) + " /w "+str(self.pos2))
self.Debug("Total Account Equity: "+ str( self.equity) + "Total Marginused: "+ str( self.Portfolio.TotalMarginUsed))#region imports
from AlgorithmImports import *
#endregion
import numpy as np
import pandas as pd
from datetime import timedelta, datetime
import math
import statsmodels.api as sm
from statsmodels.tsa.stattools import coint, adfuller
'''
This is an example of implementation of the pairs trading strategy discussed in lecture8
'''
class PairsTradingAlgorithm(QCAlgorithm):
def Initialize(self):
self.SetStartDate(2018, 1, 1)
self.SetEndDate(2019,1,1)
self.SetCash(1000000)
self.enter = 2 # Set the enter threshold
self.exit = 0 # Set the exit threshold
self.lookback = 20 # Set the lookback period 90 days
self.pairs =['FB','GOOG']
self.symbols =[]
for ticker in self.pairs:
self.AddEquity(ticker, Resolution.Daily)
self.symbols.append(self.Symbol(ticker))
self.sym1 = self.symbols[0]
self.sym2 = self.symbols[1]
def stats(self, symbols):
#Use Statsmodels package to compute linear regression and ADF statistics
self.df = self.History(symbols, self.lookback)
self.dg = self.df["open"].unstack(level=0)
#self.Debug(self.dg)
ticker1= str(symbols[0])
ticker2= str(symbols[1])
Y = self.dg[ticker1].apply(lambda x: math.log(x))
X = self.dg[ticker2].apply(lambda x: math.log(x))
X = sm.add_constant(X)
model = sm.OLS(Y,X)
results = model.fit()
sigma = math.sqrt(results.mse_resid) # standard deviation of the residual
slope = results.params[1]
intercept = results.params[0]
res = results.resid #regression residual mean of res =0 by definition
zscore = res/sigma
adf = adfuller (res)
return [adf, zscore, slope]
def OnData(self, data):
self.IsInvested = (self.Portfolio[self.sym1].Invested) or (self.Portfolio[self.sym2].Invested)
self.ShortSpread = self.Portfolio[self.sym1].IsShort
self.LongSpread = self.Portfolio[self.sym1].IsLong
stats = self.stats([self.sym1, self.sym2])
self.beta = stats[2]
zscore= stats[1][-1]
self.wt1 = 1/(1+self.beta)
self.wt2 = self.beta/(1+self.beta)
self.pos1 = self.Portfolio[self.sym1].Quantity
self.px1 = self.Portfolio[self.sym1].Price
self.pos2 = self.Portfolio[self.sym2].Quantity
self.px2 = self.Portfolio[self.sym2].Price
self.equity =self.Portfolio.TotalPortfolioValue
if self.IsInvested:
if self.ShortSpread and zscore <= self.exit or \
self.LongSpread and zscore >= self.exit or \
abs(zscore) >= 3:
self.Liquidate()
else:
if abs(zscore) < 3:
if zscore > self.enter:
#short spread
#rememebr SetHoldings take a Symbol as its first variable.
self.SetHoldings(self.sym1, -self.wt1)
self.SetHoldings(self.sym2, self.wt2)
if zscore < - self.enter:
#long the spread
self.SetHoldings(self.sym1, self.wt1)
self.SetHoldings(self.sym2, -self.wt2)
self.pos1 = self.Portfolio[self.sym1].Quantity
self.pos2 = self.Portfolio[self.sym2].Quantity
self.Debug("sym1 " + str(self.sym1.Value) + " /w "+ str(self.pos1) + " sym2 " +str(self.sym2.Value) + " /w "+str(self.pos2))
self.Debug("Total Account Equity: "+ str( self.equity) + "Total Marginused: "+ str( self.Portfolio.TotalMarginUsed))