Overall Statistics
Total Orders
8003
Average Win
0.18%
Average Loss
-0.13%
Compounding Annual Return
-0.694%
Drawdown
21.600%
Expectancy
0.009
Start Equity
1000000
End Equity
959583.43
Net Profit
-4.042%
Sharpe Ratio
-0.752
Sortino Ratio
-0.974
Probabilistic Sharpe Ratio
0.071%
Loss Rate
57%
Win Rate
43%
Profit-Loss Ratio
1.34
Alpha
-0.031
Beta
-0.01
Annual Standard Deviation
0.043
Annual Variance
0.002
Information Ratio
-0.657
Tracking Error
0.18
Treynor Ratio
3.08
Total Fees
$23071.01
Estimated Strategy Capacity
$4200000.00
Lowest Capacity Asset
DIA R7KVSI4AAX5X
Portfolio Turnover
47.08%
# region imports
from AlgorithmImports import *
# endregion
from datetime import datetime,timedelta
import pandas as pd
import numpy as np
import statsmodels.api as sm
from datetime import datetime, timedelta

class PairedSwitching(QCAlgorithm):
    
    def Initialize(self):
        
        self.SetStartDate(2019, 6, 1)  
        self.SetEndDate(2025,5, 1)
        self._cash = 1000000
        self.SetCash(self._cash)  
        
        self.first = self.AddEquity("SPY", Resolution.Hour, Market.USA).Symbol
        self.second = self.AddEquity("DIA", Resolution.Hour, Market.USA).Symbol
        self._benchmark = self.AddEquity("SHY", Resolution.Hour, Market.USA).Symbol
        
        self.Schedule.On(self.DateRules.MonthStart(self.first), self.TimeRules.AfterMarketOpen(self.first), self.CalculateRegression)
        
        # SET BENCHMARK AND PREPARE COMPARATIVE PLOT
        self.reference = self.History(self._benchmark, 10, Resolution.Daily)['close']
        self._initialValue = self.reference.iloc[0]
        
    def CalculateRegression(self): 
        self.df_first = self.History([self.first], 250)
        self.df_second = self.History([self.second], 250)
        self.new_second = self.df_second['close'].tolist()
        self.new_first = self.df_first['close'].tolist()
        self.new_second = sm.add_constant(self.new_second)
        model = sm.OLS(self.new_first,self.new_second, missing='drop')
        results = model.fit()
        self.paramet = results.params
        return self.paramet
            
  

    def OnData(self, data):
        self.er1 = np.sign(self.Securities["SPY"].Close-self.paramet[0]-self.paramet[1]*self.Securities["DIA"].Close)
        self.Debug(f" Parameters:{self.paramet}")
        if self.er1 > 0:
            self.SetHoldings("DIA", 0.75)
            self.SetHoldings("SPY", -0.75)
        else:
            self.SetHoldings("SPY", 0.75)
            self.SetHoldings("DIA", -0.75)
            
        self.Plot("Strategy Equity", "Benchmark", self._cash*self.Securities[self._benchmark].Close/self._initialValue)