Overall Statistics
Total Trades
2280
Average Win
0.79%
Average Loss
-0.61%
Compounding Annual Return
103.315%
Drawdown
40.900%
Expectancy
0.601
Net Profit
3842.072%
Sharpe Ratio
2.564
Probabilistic Sharpe Ratio
92.346%
Loss Rate
30%
Win Rate
70%
Profit-Loss Ratio
1.30
Alpha
0.943
Beta
1.897
Annual Standard Deviation
0.517
Annual Variance
0.268
Information Ratio
2.705
Tracking Error
0.416
Treynor Ratio
0.699
Total Fees
$336699.39
Estimated Strategy Capacity
$2700000.00
Lowest Capacity Asset
SQQQ UK280CGTCB51
class HedgedEquityAlgo(QCAlgorithm):
    
    def Initialize(self):
        
        self.SetStartDate(2016, 7, 1)  
        self.SetEndDate(2021, 9, 3)  
        self.SetCash(1000000)  
        self.AddEquity("SPY", Resolution.Minute)
        self.SetBenchmark("SPY")
        self.SetBrokerageModel(BrokerageName.AlphaStreams)
        self.SetExecution(ImmediateExecutionModel())
        self.SetPortfolioConstruction(EqualWeightingPortfolioConstructionModel())
        self.Settings.FreePortfolioValuePercentage = 0.1
       
        symbols_one_list = ["TQQQ"]
        self.symbols_one = [self.AddEquity(symbol, Resolution.Minute, Market.USA).Symbol for symbol in symbols_one_list]
        
        symbols_two_list = ["SQQQ"]
        self.symbols_two = [self.AddEquity(symbol, Resolution.Minute, Market.USA).Symbol for symbol in symbols_two_list]
        
        self.AddUniverseSelection(ManualUniverseSelectionModel(self.symbols_one))
        self.AddUniverseSelection(ManualUniverseSelectionModel(self.symbols_two))

        self.lookback = 65
        self.SetWarmup(self.lookback)
        self.AddAlpha(LongEquityAlphaModel(self.symbols_one, self.Time, self.lookback))
        self.AddAlpha(ShortEquityAlphaModel(self.symbols_two, self.Time, self.lookback))
        
    def RebalanceFunction(self, time):
        return None
                        
class LongEquityAlphaModel(AlphaModel):
                        
    def __init__(self, symbols, Time, lookback):
        self.symbols = symbols
        self.dataBySymbol = {}
        self.rebalanceTime = Time
        self.lookback = lookback
        
    def Update(self, algorithm, data):
        insights = []
         
        if algorithm.Time < self.rebalanceTime: return []
        
        for symbol, symbolData in self.dataBySymbol.items():
            if data.Bars.ContainsKey(symbol) and symbolData.IsReady():
                if symbol in self.symbols:
                    if symbolData.slow.Current.Value < symbolData.fast.Current.Value:
                        if not algorithm.Portfolio[symbol].IsLong:
                            insights.append(Insight(symbol, timedelta(days=30), InsightType.Price, InsightDirection.Up))
                    else:
                        if algorithm.Portfolio[symbol].IsLong:
                            insights.append(Insight(symbol, timedelta(days=30), InsightType.Price, InsightDirection.Flat))
                        
        self.rebalanceTime = Expiry.EndOfDay(algorithm.Time)
        return insights
    
    def OnSecuritiesChanged(self, algorithm, changes):
        for change in changes.AddedSecurities:
            if change.Symbol not in self.symbols:
                continue
            else:
                self.dataBySymbol[change.Symbol] = SymbolData(algorithm, change.Symbol, self.lookback) 
            
        for change in changes.RemovedSecurities:
            if change.Symbol not in self.symbols:
                continue
            else:
                if change.Symbol in self.dataBySymbol:
                    del self.dataBySymbol[change.Symbol]
                
                
class ShortEquityAlphaModel(AlphaModel):
                        
    def __init__(self, symbols, Time, lookback):
        self.symbols = symbols
        self.dataBySymbol = {}
        self.rebalanceTime = Time
        self.lookback = lookback
        
    def Update(self, algorithm, data):
        insights = []
         
        if algorithm.Time < self.rebalanceTime: return []
        
        for symbol, symbolData in self.dataBySymbol.items():
            if data.Bars.ContainsKey(symbol) and symbolData.IsReady():
                if symbol in self.symbols:
                    if symbolData.slow.Current.Value > symbolData.fast.Current.Value:
                        if not algorithm.Portfolio[symbol].IsShort:
                            insights.append(Insight(symbol, timedelta(days=30), InsightType.Price, InsightDirection.Down))
                    else:
                        if algorithm.Portfolio[symbol].IsShort:
                            insights.append(Insight(symbol, timedelta(days=30), InsightType.Price, InsightDirection.Flat))
                    
        self.rebalanceTime = Expiry.EndOfDay(algorithm.Time)
        return insights
    
    def OnSecuritiesChanged(self, algorithm, changes):
        for change in changes.AddedSecurities:
            if change.Symbol not in self.symbols:
                continue
            else:
                self.dataBySymbol[change.Symbol] = SymbolData(algorithm, change.Symbol, self.lookback) 
            
        for change in changes.RemovedSecurities:
            if change.Symbol not in self.symbols:
                continue
            else:
                if change.Symbol in self.dataBySymbol:
                    del self.dataBySymbol[change.Symbol]
                
class SymbolData:
    def __init__(self, algorithm, symbol, lookback):
        
        algorithm.Consolidate(symbol, Resolution.Daily, self.DailyBarHandler)
        
        self.fast = algorithm.SMA(symbol, 5, Resolution.Daily, Field.Low)
        self.slow = algorithm.SMA(symbol, 60, Resolution.Daily, Field.High)
        
        history = algorithm.History(symbol, lookback, Resolution.Daily)
        
        if not history.empty:
            for index, tradebar in history.loc[symbol].iterrows():
                self.fast.Update(index, tradebar.low)
                self.slow.Update(index, tradebar.high)
                
            last_row = history.loc[symbol].iloc[-1]
            self.open = last_row.open
            self.close = last_row.close
            self.high = last_row.high
            self.low = last_row.low
        
    def DailyBarHandler(self, consolidated):
        self.open = consolidated.Open
        self.close = consolidated.Close
        self.high = consolidated.High
        self.low = consolidated.Low
            
    def IsReady(self):
        return self.fast.IsReady and self.slow.IsReady