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