Overall Statistics
Total Trades
334
Average Win
0.01%
Average Loss
-0.02%
Compounding Annual Return
-0.254%
Drawdown
0.300%
Expectancy
-0.039
Net Profit
-0.156%
Sharpe Ratio
-0.949
Probabilistic Sharpe Ratio
6.075%
Loss Rate
49%
Win Rate
51%
Profit-Loss Ratio
0.90
Alpha
-0.003
Beta
0.001
Annual Standard Deviation
0.003
Annual Variance
0
Information Ratio
-2.129
Tracking Error
0.123
Treynor Ratio
-2.856
Total Fees
$2073.36
from pykalman import KalmanFilter
import numpy as np
from System.Drawing import Color

class VerticalCalibratedCompensator(QCAlgorithm):

    def Initialize(self):
        self.SetStartDate(2019, 5, 20)  # Set Start Date
        self.SetEndDate(2019, 12, 30)
        self.ticker1="MSFT"
        self.ticker2="SPY"
        self.SetCash(5000000)  # Set Strategy Cash
        self.AddEquity(self.ticker1, Resolution.Hour)
        self.AddEquity(self.ticker2, Resolution.Hour)
        self.delt=.05
        self.Delta=0.45
        self.TargetXQty=0
        self.TargetYQty=0
        self.current_state="A"
        self.next_state="A"
        self.counter=0
        self.state_mean = np.zeros(2)
        self.state_cov=np.ones((2, 2))
        self.delta = 1/2
        self.trans_cov = self.delta / (1 - self.delta) * np.eye(2)
        
        self.prevAvgXfillPrice=0
        self.prevAvgYfillPrice=0
        
        self.kf = KalmanFilter(n_dim_obs=1, n_dim_state=2,
                  initial_state_mean=self.state_mean,
                  initial_state_covariance=self.state_cov,
                  transition_matrices=np.eye(2),
                  observation_covariance=1.0,
                  transition_covariance=self.trans_cov)


        stockPlot2 = Chart("Beta")
        stockPlot2.AddSeries(Series('beta', SeriesType.Line,0))
        self.AddChart(stockPlot2)
        
        
        
        stockPlot3 = Chart("Intercept")
        stockPlot3.AddSeries(Series('intercept', SeriesType.Line, '$', Color.Green))
        self.AddChart(stockPlot3)

        
        stockPlot1 = Chart('Trade Plot')
        # On the Trade Plotter Chart we want 3 series: trades and price:
        stockPlot1.AddSeries(Series('Spread', SeriesType.Line, '$', Color.Green))
        stockPlot1.AddSeries(Series('Buy', SeriesType.Scatter, '$', Color.Red, ScatterMarkerSymbol.Triangle))
        stockPlot1.AddSeries(Series('Sell', SeriesType.Scatter, '$', Color.Blue, ScatterMarkerSymbol.TriangleDown))
        self.AddChart(stockPlot1)
        

    def OnData(self, data):
        if not self.IsMarketOpen(self.ticker1):
            return
        if( not(data.ContainsKey(self.ticker1)) or  not(data.ContainsKey(self.ticker2)) ):
            return
        x=data.Bars[self.ticker1].Close
        y=data.Bars[self.ticker2].Close
        self.state_mean, self.state_cov= (self.kf.filter_update(
            filtered_state_mean =self.state_mean,
            filtered_state_covariance =self.state_cov,
            observation = np.array([y]),
            observation_matrix = np.array([[x,1]])
            ))
        beta=round(self.state_mean[0],2)
        intercept=round(self.state_mean[1],2)
        y_hat=round( (x * beta) + intercept , 2)
        res=round(y-y_hat,2)
        
        self.Plot('Trade Plot' , 'Spread', 100 * res)
        self.Plot('Beta', 'beta', 100 *  beta)
        self.Plot('Intercept', 'intercept', 100 *  intercept)
        
        #self.Log(f"beta : {beta}")
        #self.Log(f"intercept : {intercept}")
        #self.Log(f"state mean {self.state_mean}")
        #self.Log(f"residue {res}")
        #self.Log(f"x {x}\ny {y}\n\n")
        
        if(-self.delt <= res and res < self.delt):
            self.next_state="A"
            
        if(self.delt<= res and res <self.Delta ):
            self.next_state="B+"
        if(self.Delta<= res and res < (2 * self.Delta) ):
            self.next_state="C+"
        if( (2 * self.Delta) <= res  and res < (3 * self.Delta) ):
            self.next_state="D+"
        if( (3 * self.Delta) <= res   and res < (4 * self.Delta) ):
            self.next_state="E+"
        
        if(  - self.delt >= res  and res > -self.Delta ):
            self.next_state="B-"
        if(- self.Delta >= res  and res > (-2 * self.Delta) ):
            self.next_state="C-"
        if( (-2 * self.Delta) >= res  and res > (-3 * self.Delta) ):
            self.next_state="D-"
        if( (-3 * self.Delta) >= res  and res > (-4 * self.Delta) ):
            self.next_state="E-"
        
        if(self.current_state != self.next_state):
            mf=-400
            if(self.next_state=="A"):
                self.TargetXQty=self.Portfolio[self.ticker1].Quantity
                self.TargetYQty=self.Portfolio[self.ticker2].Quantity
            if(self.next_state=="C+"):
                self.TargetXQty=round(beta*mf,0)
                self.TargetYQty=-mf
            if(self.next_state=="D+"):
                self.TargetXQty=round(beta*3*mf,0)
                self.TargetYQty=-3*mf
            if(self.next_state=="E+"):
                self.TargetXQty=round(beta*7*mf,0)
                self.TargetYQty=-7*mf
            
            if(self.next_state=="C-"):
                self.TargetXQty=-round(beta*1*mf,0)
                self.TargetYQty=mf
            if(self.next_state=="D-"):
                self.TargetXQty=-round(beta*3*mf,0)
                self.TargetYQty=3*mf
            if(self.next_state=="E-"):
                self.TargetXQty=-round(beta*7*mf,0)
                self.TargetYQty=7*mf
            
            self.TargetXQty=self.TargetXQty
            self.TargetYQty=self.TargetYQty
            
            oldXqty=self.Portfolio[self.ticker1].Quantity
            oldYqty=self.Portfolio[self.ticker2].Quantity
            self.xTradeQty=-(oldXqty - self.TargetXQty)
            self.yTradeQty=-(oldYqty - self.TargetYQty)
            if(abs(self.yTradeQty)>10):
                unrealizedProfit=self.Portfolio.TotalUnrealizedProfit
                orderTicketX=self.MarketOrder(self.ticker1  ,  self.xTradeQty, True, '')
                orderTicketY=self.MarketOrder(self.ticker2  ,  self.yTradeQty, True, '')
                avgXfillPrice=orderTicketX.AverageFillPrice
                avgYfillPrice=orderTicketY.AverageFillPrice
                
                #Do logging
                if orderTicketX.Status == OrderStatus.Filled and orderTicketY.Status == OrderStatus.Filled:
                    self.Log(f",{oldXqty},{oldYqty},{self.prevAvgXfillPrice},{self.prevAvgYfillPrice},{x},{y},{res},{beta},{intercept},{unrealizedProfit},{avgXfillPrice},{avgYfillPrice},{self.current_state},{self.next_state}")
                
                #update prevAvgXfillPrice prevAvgYfillPrice
                self.prevAvgXfillPrice=avgXfillPrice
                self.prevAvgYfillPrice=avgYfillPrice
                
                if(self.yTradeQty>0):
                    self.Plot('Trade Plot' , 'Buy', 100 * res)
                if(self.yTradeQty<0):
                    self.Plot('Trade Plot' , 'Sell', 100 * res)
                    
            #self.Log(f"moving from {self.current_state} state to state{self.next_state}")
            self.current_state=self.next_state
from Selection.FundamentalUniverseSelectionModel import FundamentalUniverseSelectionModel

class BankingIndustryStocks(FundamentalUniverseSelectionModel):
    '''
    This module selects the most liquid stocks listed on the Nasdaq Stock Exchange.
    '''
    def __init__(self, filterFineData = True, universeSettings = None, securityInitializer = None):
        '''Initializes a new default instance of the TechnologyUniverseModule'''
        super().__init__(filterFineData, universeSettings, securityInitializer)
        self.numberOfSymbolsCoarse = 1000
        self.numberOfSymbolsFine = 100
        self.dollarVolumeBySymbol = {}
        self.lastMonth = -1

    def SelectCoarse(self, algorithm, coarse):
        '''
        Performs a coarse selection:
        
        -The stock must have fundamental data
        -The stock must have positive previous-day close price
        -The stock must have positive volume on the previous trading day
        '''
        if algorithm.Time.month == self.lastMonth: 
            return Universe.Unchanged

        sortedByDollarVolume = sorted([x for x in coarse if x.HasFundamentalData and x.Volume > 0 and x.Price > 0],
            key = lambda x: x.DollarVolume, reverse=True)[:self.numberOfSymbolsCoarse]

        self.dollarVolumeBySymbol = {x.Symbol:x.DollarVolume for x in sortedByDollarVolume}
        
        # If no security has met the QC500 criteria, the universe is unchanged.
        if len(self.dollarVolumeBySymbol) == 0:
            return Universe.Unchanged

        return list(self.dollarVolumeBySymbol.keys())

    def SelectFine(self, algorithm, fine):
        '''
        Performs a fine selection for companies in the Morningstar Banking Sector
        '''
        # Filter stocks and sort on dollar volume
        sortedByDollarVolume = sorted([x for x in fine if (\
        x.AssetClassification.MorningstarSectorCode == MorningstarSectorCode.FinancialServices ) ],
            key = lambda x: self.dollarVolumeBySymbol[x.Symbol], reverse=True)

        if len(sortedByDollarVolume) == 0:
            return Universe.Unchanged
            
        self.lastMonth = algorithm.Time.month

        return [x.Symbol for x in sortedByDollarVolume[:self.numberOfSymbolsFine]]