Overall Statistics
Total Trades
36
Average Win
0.92%
Average Loss
-0.02%
Compounding Annual Return
95.694%
Drawdown
13.500%
Expectancy
35.256
Net Profit
15.560%
Sharpe Ratio
2.695
Probabilistic Sharpe Ratio
73.168%
Loss Rate
8%
Win Rate
92%
Profit-Loss Ratio
38.28
Alpha
0.506
Beta
1.513
Annual Standard Deviation
0.238
Annual Variance
0.056
Information Ratio
4.189
Tracking Error
0.132
Treynor Ratio
0.423
Total Fees
$36.08
Estimated Strategy Capacity
$2000.00
Lowest Capacity Asset
EDOC XGLILOJXRUJP
Portfolio Turnover
4.34%
#region imports
from AlgorithmImports import *
#endregion
import numpy as np
from datetime import datetime
import talib

class NadionResistanceShield(QCAlgorithm):

    def Initialize(self):
        self.SetStartDate(2023, 1, 1)  # Set Start Date
        #self.SetEndDate(2021, 1, 1)
        self.SetCash(25000)  # Set Strategy Cash
        self.tickers =     ['SOXX','CIBR','ROBO','CLOU','BLOK',                 #Tech
                                'IHI', 'VHT', 'IHE', 'EDOC',                        #Healthcare
                                'VDE', 'OIH', 'ICLN', 'XOP','TAN',                  #Energy
                                'XLF', 'IAT', 'FINX', 'IAI',                        #Financial
                                'GDX', 'LIT', 'COPX', 'VAW', 'URNM',"WOOD",         #Materials
                                'XLY', 'XLC','XRT', 'ESPO', 'CARZ',                 #Consumer Discretionary
                                'VIS', 'PHO', 'ITA', 'IYT', 'JETS',                 #Industrials
                                'XLU', 'PAVE', 'RYU', 'GIL'                         #Utilities
                                'VNQ', 'XLRE'                                       #RealEstate        
                                'VIXM', 'VXX', 'UVXY','BITS'                                       #Volatility
                                'QQQ', 'IWM', 'MDY', 'IEMG', 'DBC', 'IWF', 'IWD' 
         ]
        #self.ROC = {}
        self.num_fine = 5
        self.symbolDataBySymbol = {}
        self.marketDataBySymbol = {}
        self.vwaps = {}
        self.stds = {}
        self.Marketvwaps = {}
        self.Marketstds = {}

        self.trade = True
        self.atr=[]


        self.MarketCaps = ["SPY","QQQ"]#, "MDY","IWM"]
        self.spy = "SPY"
        self.iwm = "IWM"
        self.mdy = "MDY"
        self.qqq = "QQQ"
        self.momentum_periods = [30, 90, 180]
        self.consolidation_periods = [10, 20, 50]
        # trade only once per day
        self.next_trade_time = self.Time

        #self.AddRiskManagement(TrailingStopRiskManagementModel(0.05))

   
        
        
        for symbolmark in self.MarketCaps:
            symbol = self.AddEquity(symbolmark, Resolution.Daily).Symbol
            
            sma50 = self.SMA(symbol, 50, Resolution.Daily, Field.Close)
            sma200 = self.SMA(symbol, 200, Resolution.Daily, Field.Close)
        
            self.marketDataBySymbol[symbol] = symbolMarkData(symbol, sma50, sma200)
        
        
        
        for symbol in self.tickers:
            self.AddEquity(symbol, Resolution.Hour)
            
            '''For the below 3 EMA's, you can convert them to 4H bars using the colidator method'''
            close = self.MIN(symbol, 1, Resolution.Daily, Field.Low)
            
            
            ema10 = self.EMA(symbol, 10, Resolution.Hour, Field.Close)
            sma200 = self.SMA(symbol, 200, Resolution.Daily, Field.Close)
            sma7 = self.SMA(symbol, 7, Resolution.Hour, Field.Close)
            sma20 = self.SMA(symbol, 20, Resolution.Daily, Field.Close)
            self.sma = self.SMA(symbol, 20, Resolution.Hour, Field.Close)
            sma50 = self.SMA(symbol, 50, Resolution.Daily, Field.Close)
            sma100 = self.SMA(symbol, 100, Resolution.Daily, Field.Close)
            ema20 = self.EMA(symbol, 20, Resolution.Hour, Field.Close)
            ema50 = self.EMA(symbol, 50, Resolution.Hour, Field.Close)
            rsi = self.RSI(symbol, 14, Resolution.Daily)
            wilr = self.WILR(symbol, 14, Resolution.Daily)
            wilr_fast = self.WILR(symbol, 10, Resolution.Daily)
            
            
            self.vwaps[symbol] = self.VWAP(symbol, 14, Resolution.Daily)
            self.stds[symbol] = self.STD(symbol, 14, Resolution.Daily)  
            
            
            atr = self.ATR(symbol, 7, Resolution.Daily)
            self.atr.append(self.ATR(symbol, 7, Resolution.Daily))
        
            self.high = self.MAX(symbol, 7, Resolution.Daily, Field.High)
            self.low = self.MIN(symbol, 5, Resolution.Daily, Field.Low)
            
            self.sma.Updated += self.OnSMA
            
            '''Consolidator method'''
            smaConsolidate = ExponentialMovingAverage(20, MovingAverageType.Simple)
            # create the 4 hour data consolidator
            fourHourConsolidator = TradeBarConsolidator(timedelta(hours=4))
            self.SubscriptionManager.AddConsolidator(symbol, fourHourConsolidator)
            # register the 4 hour consolidated bar data to automatically update the indicator
            self.RegisterIndicator(symbol, smaConsolidate, fourHourConsolidator)

            self.vwaps[symbol] = self.VWAP(symbol, 14, Resolution.Daily)
            self.stds[symbol] = self.STD(symbol, 14, Resolution.Daily)
            self.Marketvwaps[symbol] = self.VWAP(symbol, 14, Resolution.Daily)
            self.Marketstds[symbol] = self.STD(symbol, 14, Resolution.Daily)             

            
            symbolData = SymbolData(symbol, ema10, sma20, sma100, sma200, sma7, sma50, ema20, ema50, rsi, wilr, wilr_fast, atr, smaConsolidate, close)
            self.symbolDataBySymbol[symbol] = symbolData
        
        
        
        self.spy = self.AddEquity("SPY", Resolution.Daily)
        
        # Before the open
        self.Schedule.On(self.DateRules.EveryDay("SPY"), 
                self.TimeRules.AfterMarketOpen("SPY", -5), 
                Action(self.beforeTheOpen))
        
        #set the following between 1 - 4 hours depending on buy frequency    
        self.Schedule.On(self.DateRules.EveryDay("SPY"),
                 self.TimeRules.Every(timedelta(hours=6.5)),
                 self.buySignals)
                 #self.TimeRules.EveryDay,
                 #self.buySignals)
                 
        self.Schedule.On(self.DateRules.EveryDay("SPY"),
                 self.TimeRules.Every(timedelta(hours=3.2)),
                 self.sellSignals)
                 
                 
        self.Schedule.On(self.DateRules.EveryDay("SPY"),
                 self.TimeRules.AfterMarketOpen("SPY"),
                 self.tradeStart)
                 
        self.Schedule.On(self.DateRules.EveryDay("SPY"),
                 self.TimeRules.BeforeMarketClose("SPY"),
                 self.tradeEnd)

        
        self.SetWarmUp(timedelta(days=90))
    
    def beforeTheOpen(self):
        self.Log("SPY: {0}".format(self.spy.Close))
        #for i in range(len(self.tickers)):
        #    self.Log("ATR: {0}".format(self.atr[i].Current.Value))
            
    
            
    
    def OnData(self, data):
        if self.IsWarmingUp:# or not all(std.IsReady for std in self.stds.values()):
            return

        for symbol in self.tickers:
            price = self.Securities[symbol].Price
            vwap = self.vwaps[symbol].Current.Value
            std = self.stds[symbol].Current.Value
            ub1 = vwap + std 
            ub2 = vwap + 2*std
            lb1 = vwap - std 
            lb2 = vwap - 2*std 

            self.Plot(symbol, 'price', price)
            self.Plot(symbol, 'vwap', vwap)
            self.Plot(symbol, 'ub2', ub2)
            self.Plot(symbol, 'ub1', ub1)
            self.Plot(symbol, 'lb1', lb1)
            self.Plot(symbol, 'lb2', lb2)
            
            #Take Profit
            if price > ub2:
                self.Liquidate(symbol)
                return
            

    def tradeStart(self):
        self.trade = True

    def tradeEnd(self):
        self.trade = False
    
    def OnOrderEvent(self, OrderEvent):
        '''Event when the order is filled. Debug log the order fill. :OrderEvent:'''

        if OrderEvent.FillQuantity == 0:
            return

        # Get the filled order
        Order = self.Transactions.GetOrderById(OrderEvent.OrderId)
        
        # Log the filled order details
        self.Log("ORDER NOTIFICATION >> {} >> Status: {} Symbol: {}. Quantity: "
                    "{}. Direction: {}. Fill Price {}".format(str(Order.Tag),
                                                   str(OrderEvent.Status),
                                                   str(OrderEvent.Symbol),
                                                   str(OrderEvent.FillQuantity),
                                                   str(OrderEvent.Direction),
                                                   str(OrderEvent.FillPrice)))
    def buySignals(self):
        if self.trade == False:
            return
            
         # Return if benchmark is below SMA
        for symbolmark, symbolmarkData in self.marketDataBySymbol.items():
            if (self.Securities[symbolmark].Close > symbolmarkData.sma200.Current.Value):
                return
            
        for symbol, symbolData in self.symbolDataBySymbol.items():
              
           if not self.Portfolio[symbol].Invested and (self.Securities[symbol].Close < self.low.Current.Value) and (symbolData.sma100.Current.Value > symbolData.sma200.Current.Value):#  and (self.Securities[symbol].Close > symbolData.sma200.Current.Value):
                self.SetHoldings(symbol, .1, False, "Buy Signal")
                
           elif not self.Portfolio[symbol].Invested  and (self.Securities[symbol].Close < symbolData.sma20.Current.Value) and (symbolData.ema20.Current.Value > symbolData.ema50.Current.Value):
                self.SetHoldings(symbol, .1, False, "Buy Signal")
                    
            
    def sellSignals(self):
        if self.trade == False:
            return
        for symbol, symbolData in self.symbolDataBySymbol.items():
            
            if self.Portfolio[symbol].Invested and (symbolData.rsi.Current.Value > 90):
                self.StopMarketOrder(symbol, .05, self.Securities[symbol].Close, "Some Profit Signal")
            #if self.Portfolio[symbol].Invested and (self.Securities[symbol].Close > symbolData.sma200.Current.Value) and (symbolData.sma20.Current.Value < symbolData.atr.Current.Value): 
               # self.Liquidate(symbol, "Sell Signal")
            if self.Portfolio[symbol].Invested and (self.Securities[symbol].Close > self.high.Current.Value):
                self.Liquidate(symbol, "Sell New High Signal")
    
        
    def OnSMA(self, sender, updated):
        if self.sma.IsReady:
            #self.Debug(f"SMA Updated on {self.Time} with value: {self.sma.Current.Value}")
            return

    


class symbolMarkData:
    def __init__(self, symbol, sma50, sma200):
        self.Symbol = symbol
        self.sma50 = sma50
        self.sma200 = sma200

class SymbolData:
    def __init__(self, symbol, ema10, sma20, sma50, sma100, sma200, sma7, ema20, ema50, rsi, wilr, wilr_fast, atr, smaConsolidate, close):
        self.Symbol = symbol
        self.ema10 = ema10
        self.sma20 = sma20
        self.sma50 = sma50
        self.sma200 = sma200
        self.sma100 = sma100
        self.sma7 = sma7
        self.ema20 = ema20
        self.ema50 = ema50
        self.close = close 
        self.rsi = rsi
        self.wilr = wilr
        self.wilr_fast = wilr_fast
        self.atr = atr
        #self.emaConsolidate = emaConsolidate
        self.smaConsolidate = smaConsolidate