Overall Statistics
Total Trades
588
Average Win
0.33%
Average Loss
-0.36%
Compounding Annual Return
10.343%
Drawdown
11.500%
Expectancy
0.059
Net Profit
5.717%
Sharpe Ratio
0.914
Loss Rate
45%
Win Rate
55%
Profit-Loss Ratio
0.91
Alpha
0.048
Beta
2.743
Annual Standard Deviation
0.111
Annual Variance
0.012
Information Ratio
0.74
Tracking Error
0.111
Treynor Ratio
0.037
Total Fees
$1147.86
import numpy as np
from datetime import timedelta
from QuantConnect.Securities.Option import OptionPriceModels
import pandas as pd

# A pairs trading strategy for dual listed stocks
class DualListedArb(QCAlgorithm):
    def Initialize(self):
        self.SetStartDate(2017,10,1)  
        self.SetEndDate(2017,12,1)    
        self.SetCash(10000)  
        
        self.TriggerSignal = .025
        # Adding the dual class shares of Viacom 
        self.AddEquity("VIA", Resolution.Minute)
        self.AddEquity("VIAB", Resolution.Minute)
        
        self.AddEquity("SPY", Resolution.Minute)
        # Set a benchmark at the beginning of every trading day
        self.Schedule.On(self.DateRules.EveryDay("SPY"),
                self.TimeRules.At(0,0),
                Action(self.SetBenchmark))
        self.SetWarmUp(int(6.5*60*100))

    def OnData(self, slice):
        # Called every minute
        if self.IsWarmingUp: return
        
        mainPrice = slice["VIAB"].Price 
        dualPrice = slice["VIA"].Price
        
        self.currentSpread = dualPrice - mainPrice
        self.currentSpread = float(self.currentSpread)
        self.percentDiff = (self.currentSpread-self.benchmarkSpread)/self.benchmarkSpread
        # If the current spread is >2.5% of the benchmark spread in the 
        # SetBenchmark method, buy the stock without the premium
        if self.percentDiff > .025:
            if self.Portfolio["VIAB"].Quantity <= 0:
                self.SetHoldings("VIAB", 1.0, tag="Long")
        if self.percentDiff < .025:
            if self.Portfolio["VIAB"].Quantity > 0:
                self.SetHoldings("VIAB", 0, tag="Short")
                    
    def SetBenchmark(self):
        # Returns a spread for the premium of owning VIA stock over the 
        # past 100 days
        # The mean of those 100 spreads becomes the Benchmark Spread that we base our
        # predictions off of
        self.mainHistory = self.History(["VIAB"], 100)
        self.dualHistory = self.History(["VIA"], 100)
        
        mainBars = self.mainHistory.loc["VIAB"]
        mainHistoricalClose = mainBars["close"]
        dualBars = self.dualHistory.loc["VIA"]
        dualHistoricalClose = dualBars["close"]
        
        spread = dualHistoricalClose - mainHistoricalClose
        self.benchmarkSpread = spread.mean()
        self.benchmarkSpread = float(self.benchmarkSpread)