Overall Statistics
Total Trades
28
Average Win
0.21%
Average Loss
0%
Compounding Annual Return
158040941931.419%
Drawdown
8.100%
Expectancy
0
Net Profit
2014.516%
Sharpe Ratio
8171906.675
Probabilistic Sharpe Ratio
100%
Loss Rate
0%
Win Rate
100%
Profit-Loss Ratio
0
Alpha
9938375.633
Beta
2.925
Annual Standard Deviation
1.216
Annual Variance
1.479
Information Ratio
8292864.371
Tracking Error
1.198
Treynor Ratio
3398206.492
Total Fees
$28.00
from arch import arch_model
import numpy as np

class StrategyManagerUtility:
    def __init__(self, quantScenario):
        self.quantScenario = quantScenario
    
    def setupModel(self, preference):
    # GJR GARCH mode

        # Attempt to Fit the model
        try:    
            egarch_gm = arch_model(preference.garchData, p = 1, q = 1, o = 1, vol = 'GARCH', dist = 't')
                
            egarch_result = egarch_gm.fit(disp = 'off')
                
            # Make 1-period ahead forecast
            gm_forecast = egarch_result.forecast(horizon = 1)
            preference.egarchMean = gm_forecast.mean.values[-1 ]
            if preference.egarchMean:
                preference.egarchMeanArray = np.append( preference.egarchMeanArray, preference.egarchMean)
            else:
                pass
            
            garchOutput = gm_forecast.variance[-1:].values
            
            #printing the logs
            self.genericGarchLog(preference, gm_forecast, garchOutput[0])
            
            if preference.quantScenario.IsWarmingUp:
                return
            else:
                self.setHoldingsBasedOnEGarch(garchOutput[0], preference)
        except Exception:
            return
        
        #self.Debug("----------> " + str(self.gm_result.summary()))
    
    def setHoldingsBasedOnEGarch(self, garchOutput, preference):
        
        self.multipler = 2
        
        if garchOutput[0] < preference.egarchMean:
            preference.quantScenario.SetHoldings(preference.tradedETFSymbol, 1)
        elif garchOutput[0] > preference.egarchMean*self.multipler and  garchOutput[0] > 0:
            #self.SetHoldings(self.tradedETFSymbol, (self.egarchMean)/garchOutput[0])
            sdVariance = (preference.egarchMean)/garchOutput[0]
            
            if sdVariance > 1:
                sdVariance = 1
                
            preference.quantScenario.SetHoldings(preference.tradedETFSymbol, sdVariance)
            #self.SetHoldings([PortfolioTarget("TQQQ", 0), PortfolioTarget("ETF", int(sdVariance))], True)
            
    def genericGarchLog(self, preference, inputGm_forecast, garchOutput):
        
        sdVariance = (preference.egarchMean)/garchOutput[0]
        
        preference.quantScenario.Debug(str(preference.quantScenario.Time) + " - " + str(preference.garchData[-1]))
        preference.quantScenario.Debug("SOXL Allocation: "+ str(sdVariance))
        preference.quantScenario.Debug("Mean, based on Garch Data: "+ str(preference.egarchMean))
        preference.quantScenario.Debug("Forecast Variance, based on Garch Data: "+ str(inputGm_forecast.variance[-1:].values))
        preference.quantScenario.Debug("Yesterday's Standard Deviation: "+str(preference.garchData[-1]))
        preference.quantScenario.Debug("")
        #preference.quantScenario.Debug("Element in Garch Data Array: "+ str(preference.garchData[:5]))
from InvestorPreferenceUtility import InvestorPreferenceUtility

class SOXLStandardDeviation(QCAlgorithm):
    
    #101293240057
    
    def Initialize(self):
        
        self.investorPrefernce = InvestorPreferenceUtility(self)    
    
    def OnData(self, data):
        '''OnData event is the primary entry point for your algorithm. Each new data point will be pumped in here.
            Arguments:
                data: Slice object keyed by symbol containing the stock data
        '''
        if "2021-01-22 15:" in str(self.Time):
            self.investorPrefernce.injectTodaysStandardDeviationValue(5)
from StrategyManagerUtility import StrategyManagerUtility
import numpy as np
    
class InvestorPreferenceUtility:
    
    def __init__(self, quantconnectObject):
        self.quantScenario = quantconnectObject
        self.strategyManager = StrategyManagerUtility(self)
        
        self.initalizeAttributes()
        self.setupIndicators()
        self.setupScheduler()
        
    def initalizeAttributes(self):
        self.quantScenario.SetStartDate(2020, 12, 1)
        self.quantScenario.SetEndDate(2021, 1, 25) 
        self.quantScenario.SetCash(2000)  # Set Strategy Cash
        self.leveragedETFSymbol = "TQQQ"
        self.tradedETFSymbol = "SOXL"
        self.minutesBeforeMarketClose = 1
        self.counter = 0
        self.investmentInterval = 14
        self.indicatorPeriod = 7
        self.garchData = []
        self.egarchMean = 0
        list = []
        self.egarchMeanArray = np.array(list)
        self.resolution = Resolution.Daily
        
    def setupIndicators(self):
        #Warming up the function
        self.warmUpTimeForBacktestScenario = self.indicatorPeriod
        self.quantScenario.SetWarmUp(timedelta(days=self.indicatorPeriod))
        
        self.leveragedETF = self.quantScenario.AddEquity(self.leveragedETFSymbol, self.resolution)
        self.leveragedETF.SetDataNormalizationMode(DataNormalizationMode.Raw)
        
        self.tradedETF = self.quantScenario.AddEquity(self.tradedETFSymbol, self.resolution)
        self.tradedETF.SetDataNormalizationMode(DataNormalizationMode.Raw)
        
        self.forceQuantToCallOnDataEachHour = self.quantScenario.AddEquity("VOO", Resolution.Hour)
        
        #Setup standard deviation indicator
        self.quantScenario.stdIndicator = self.quantScenario.STD(self.leveragedETFSymbol, self.indicatorPeriod, Resolution.Daily)
    
    def setupScheduler(self):
        self.quantScenario.Schedule.On(self.quantScenario.DateRules.EveryDay(self.leveragedETFSymbol), self.quantScenario.TimeRules.AfterMarketOpen(self.leveragedETFSymbol, 1), self.dailyComputation)
        
        self.quantScenario.Schedule.On(self.quantScenario.DateRules.EveryDay(self.leveragedETFSymbol), self.quantScenario.TimeRules.BeforeMarketClose(self.leveragedETFSymbol, self.minutesBeforeMarketClose), self.dollarCostAverage)

    def dollarCostAverage(self):
        self.counter += 1
        
        if self.counter % self.investmentInterval:
            investment = 1000
            self.quantScenario.Portfolio.SetCash(self.quantScenario.Portfolio.Cash + investment)
    
    def normalizeGarchDataFromStockSplit(self):
        #This is a temporary conditional statement to account for the price split on 1/22/2021, please remove this conditional statement after 60 days from 1/22/2021 -------------------------------------------------------------
        if self.quantScenario.stdIndicator.Current.Value == 29.7251056536802:
            self.garchData.append(4.75123456789)
        else:
            self.garchData.append(self.quantScenario.stdIndicator.Current.Value)
        
    
    def dailyComputation(self):
        
        self.normalizeGarchDataFromStockSplit() #--------------------------------remove this line with a conditional
            
        self.counter += 1
        
        self.strategyManager.setupModel(self)
        
        if len(self.garchData) > 60:
            self.garchData.pop(0)
        
        #self.Debug("Garch Data: " + str(data))
    
    def injectTodaysStandardDeviationValue(self, inputStandardDeviation):
        
        self.quantScenario.Debug("----------->Injecting Stardard Deviation Data for the next day")
        self.garchData.append(inputStandardDeviation)
        self.strategyManager.setupModel(self)
        #mean =  np.mean(preference.egarchMeanArray)
        #preference.quantScenario.Debug("egarch mean: " + str(mean))