Overall Statistics
#region imports
from AlgorithmImports import *
#endregion

# Errors To Resolve:
# 1. Rolling window is empty (Parameter 'i') in RollingWindow.cs:line 143 - For now I have commented below line in Alpha Model
        # self.algo.Debug(f"Yesterday's Date:{self.algo.Time} Nasdaq Close:{self.nasdaqYesterdayClose[0]}, Lumber Close: {self.lumberYesterdayClose[0]}")
# 2. Backtest Handled Error: Order Error: id: 5848, Insufficient buying power to complete order (Value:-41569), Reason: Id: 5848, Initial Margin: -5942.47, Free Margin: 2711.08.
# 3. Backtest Handled Error: You have exceeded maximum number of orders (10000), for unlimited orders upgrade your account.


# ToDo
# 1. Use the TAG property in Orders to fill Name of Strategy that executed that Order
# 2. For AlphaModel confidence in Insight, get 52 Week High & Low for Nasdaq in % terms and then confidence = self.percentageChange/52 Week high or Low depending on Long / Short
# 3. When checking condition to generate Long or Short Insight, make sure to get last non zero price for Bid and Ask for Lumber Quotes
# 4. 
# ToCheck/ AskQC
# 1.


# Trade Logic
 
# ALPHA Model
""" Securities :Lumber and Nasdaq
    Resolution:Tick
    
    1.Calculate NASDAQ %age change using NASDAQ yesterday Close & current* Trade Price.
    2.Compare Pre-Market LUMBER ASK/BID vs LUMBER yesterday Close
    3.Take Positions Based on Following Logic
        a. Go Long  if both True (1) >1% & (2) LUMBER ASK/BID > LUMBER yesterday Close
        b. Go Short if both True (1) <1% & (2) LUMBER ASK/BID < LUMBER yesterday Close
    4. Number of Contracts (Insight Weights) depends on %age change in Nasdaq (1): 
        a. More than 1% absolute change equates to 1 Contracts
        b. More than 2% absolute change equates to 2 Contracts & so on

*current: This is Pre-Market LUMBER (just before market opens)"""


# OrderType:LimitOrder
"""1. check if the target quantity is positive or negative.
   
   2. if negative 
        2.1 we are shorting then use the BestAsk
        2.2 calculate the sell price by increasing the BestAsk by one percent.
        2.3 place the limit order at the calculate price.
    
    3. if Positive
        2.1 we are longing (buying) then use the BestAsk
        2.2 calculate the buy price by decreasing the BestBid by one percent.
        2.3 place the limit order at the calculate price."""
from AlgorithmImports import *
import numpy as np

class MyExecution(ExecutionModel):

    def __init__(self,algo):

        self.algo=algo  # create the algo instance
        self.orderCounter = 1

    def Execute(self, algorithm: QCAlgorithm, targets: List[PortfolioTarget]) -> None:

        # update the complete set of portfolio targets with the new targets
        self.algo.targetsCollection.AddRange(targets)

        if not self.algo.targetsCollection.IsEmpty:
            
            for target in self.algo.targetsCollection.Values:
                
                # check order entry conditions
                if target.Quantity != 0: # Is this neccessary?
                    self.algo.Debug(f"target.Quantity:{target.Quantity}")

                    for _ in range(abs(int(target.Quantity))*self.algo.orderMultiplier):
                        orderPrice = self.GetOrderPrice(target, algorithm)

                        #initiate Trade class
                        trade=Trade(algorithm)
                        ticket=trade.placeMainOrder(target.Symbol, np.sign(target.Quantity)*1, orderPrice,self.algo.order_properties)
                        self.algo.tradesCollection[str(ticket.OrderId)] = trade

                    # why not creating a dict like this
                    # self.algi.ticketDict[ticket.OrderId]={"OrderType":"Main","StopLossId":None,"TakeProfitId":None}

                    # ticket = algorithm.LimitOrder(target.Symbol, target.Quantity, orderPrice,None,self.order_properties)
                    # self.algo.ticketDict[ticket.OrderId] = ['Main',[self.algo.Transactions.GetOrderTicket(ticket.OrderId)],None,0]
                    # ticket.UpdateTag('LumberCopyNasdaq' + '_ID_' + str(ticket.OrderId))
                    
            self.algo.targetsCollection.Clear()
            

    def GetOrderPrice(self, target, algorithm):
        orderPrice = None

        if target.Quantity > 0:
            # Calculate new orderPrice by reducing BestBid by 1%
            bid = algorithm.Securities[target.Symbol].BidPrice
            orderPrice = round(bid - (bid*0.01),1) # Less Competitive
            # orderPrice = round(bid + (bid*0.01),1) # More Competitive

        elif target.Quantity < 0:
            # Calculate new orderPrice by increasing BestAsk by 1%
            ask = algorithm.Securities[target.Symbol].AskPrice

            if self.orderCounter == 1:  # This is temporary so we can see 2 different Asks for 2 positions
                orderPrice = round(ask + (ask*0.01),1) # Less Competitive
            else:
                orderPrice = round(ask + (ask*0.03),1) # Less Competitive
            
            # orderPrice = round(ask - (ask*0.01),1) # More Competitive

        self.orderCounter +=1
        return orderPrice


class Trade():

    def __init__(self,algo):
        self.mainOrderTicket=None
        self.stopLossTicket=None
        self.takeProfitTicket=None
        self.algo=algo
        self.trailingStopLoss=False
        

    def placeMainOrder(self,symbol,quantity,orderPrice,orderProperties=None):
        
        if orderProperties:      
            self.mainOrderTicket=self.algo.LimitOrder(symbol=symbol, quantity=quantity, limitPrice=orderPrice,orderProperties=orderProperties) # , orderProperties= self.algo.order_properties
        
        else:
            self.mainOrderTicket=self.algo.LimitOrder(symbol=symbol, quantity=quantity, limitPrice=orderPrice,orderProperties=orderProperties) # , orderProperties= self.algo.order_properties
        

        return self.mainOrderTicket

    
    def updateMainOrder(self, price):      
        response = self.mainOrderTicket.UpdateLimitPrice(price)
        if response.IsSuccess:
            self.algo.Debug("MainOrder with Order_id {} Updated Successfully".format(self.mainOrderTicket.OrderId))
            return True
    
    
    def updateStopOrderPrice(self, stopPrice):      
        response = self.stopLossOrderTicket.UpdateStopPrice(price)
        if response.IsSuccess:
            self.algo.Debug("Stop Price of StopLossOrder with Order_id {} Updated Successfully".format(self.stopLossTicket.OrderId))
            return True

   
    
    def getMainOrderId(self):
        self.mainOrderTicket.OrderId

    
    
    
    def placeStopLossOrder(self,quantity,stopPrice,limitPrice,orderProperties=None):
        if orderProperties:
            self.stopLossTicket=self.algo.StopLimitOrder(symbol=self.mainOrderTicket.Symbol, quantity=quantity, stopPrice=stopPrice, limitPrice=limitPrice,tag=str(self.mainOrderTicket.OrderId),orderProperties=orderProperties)
        else:
            self.stopLossTicket=self.algo.StopLimitOrder(symbol=self.mainOrderTicket.Symbol, quantity=quantity, stopPrice=stopPrice, limitPrice=limitPrice,tag=str(self.mainOrderTicket.OrderId)) 
     

        return self.stopLossTicket

    
    
    def placeTakeProfitOrder(self,quantity,limitPrice,orderProperties=None):
        if orderProperties:
             self.takeProfitTicket=self.algo.LimitOrder( symbol=self.mainOrderTicket.Symbol, quantity=quantity, limitPrice=limitPrice,tag=str(self.mainOrderTicket.OrderId),orderProperties=orderProperties)

        else:
            self.takeProfitTicket=self.algo.LimitOrder( symbol=self.mainOrderTicket.Symbol, quantity=quantity, limitPrice=limitPrice,tag=str(self.mainOrderTicket.OrderId)) #, orderProperties= self.algo.order_properties
        
        return self.takeProfitTicket 
  
    def cancelStopLoss(self):
        response=self.stopLossTicket.Cancel()
        if response.IsSuccess:
            self.algo.Debug("StopLossOrder with Order_id {} connected to main order {} Cancelled Successfully".format(self.stopLossTicket.OrderId,self.stopLossTicket.Tag))
            self.stopLossTicket=None
            return True

    def cancelTakeProfit(self):
        response=self.takeProfitTicket.Cancel()
        if response.IsSuccess:
            self.algo.Debug("TakeProfit Order with Order_id {} connected to main order {} Cancelled Successfully".format(self.takeProfitTicket.OrderId,self.takeProfitTicket.Tag))
            self.takeProfitTicket = None
            return True

    
    def cancelMainOrder(self):
        response=self.MainOrderTicket.Cancel()
        if response.IsSuccess:
            self.algo.Debug("MainOrder with Order_id {} orderStatus:{}  Cancelled Successfully".format(self.mainOrderTicket.OrderId,self.mainOrderTicket.OrderStatus))           
            # del self.algo.tradesCollection[main_id]
        return True

    
    
    def getMainOrderTicket(self):
        return self.mainOrderTicket



   
    def getStopLossOrderTicket(self):
        return self.stopLossOrderTicket




    def getTakeProfitTicket(self):
        return self.takeProfitTicket





    def adjustTrailing(self):
       
        
        if self.mainOrderTicket.Status == OrderStatus.Filled:
            
            # get main order fill price and current price
            
            mainOrderFillPrice=self.mainOrderTicket.FillPrice
            currentPrice=self.algo.Securities[self.mainOrderTicket.Symbol].Price

            # check if current price is more than fill price
            if currentPrice > mainOrderFillPrice:
                
                # calculate the  drawdown since fill price
                changeInPrice=((currentPrice-mainOrderFillPrice)/currentPrice)*100
                
                # update the stoploss stoploss stopprice
                stopPrice=self.stopLossTicket.get(OrderField.StopPrice)
                response=self.updateStopOrderPrice(stopPrice*changeInPrice)

                return response

            


from AlgorithmImports import *

class MyExecution(ExecutionModel):

    def Execute(self, algorithm: QCAlgorithm, targets: List[PortfolioTarget]) -> None:
        for target in targets:
            security = algorithm.Securities[target.Symbol]
            quantity = OrderSizing.GetUnorderedQuantity(algorithm, target, security)
            currentContract = algorithm.Securities[security.Mapped]
            algorithm.Debug(f"target in ExecutionModel-:-{security} & quantity: {quantity}")
            
            if quantity != 0:                
                aboveMinimumPortfolio = BuyingPowerModelExtensions.AboveMinimumOrderMarginPortfolioPercentage(currentContract.BuyingPowerModel, currentContract, quantity, algorithm.Portfolio, algorithm.Settings.MinimumOrderMarginPortfolioPercentage)
                if aboveMinimumPortfolio:
                    algorithm.MarketOrder(currentContract.Symbol, quantity)
                    algorithm.Debug(f"Worked in ExecutionModel")

from AlgorithmImports import *

class MyExecution(ExecutionModel):

    def Execute(self, algorithm: QCAlgorithm, targets: List[PortfolioTarget]) -> None:
        for target in targets:
            security = algorithm.Securities[target.Symbol]
            quantity = OrderSizing.GetUnorderedQuantity(algorithm, target, security)
            currentContract = algorithm.Securities[security.Mapped]
            algorithm.Debug(f"target in ExecutionModel-:-{security} & quantity: {quantity}")
            
            if quantity != 0:                
                aboveMinimumPortfolio = BuyingPowerModelExtensions.AboveMinimumOrderMarginPortfolioPercentage(currentContract.BuyingPowerModel, currentContract, quantity, algorithm.Portfolio, algorithm.Settings.MinimumOrderMarginPortfolioPercentage)
                if aboveMinimumPortfolio:
                    algorithm.MarketOrder(currentContract.Symbol, quantity)
                    algorithm.Debug(f"Worked in ExecutionModel")
            
            for prop in dir(target):
                value = getattr(target, prop)
                algorithm.Debug(f"{prop}:{value}")
        
                

from AlgorithmImports import *

class NasdaqAlpha(AlphaModel):
    def __init__(self, algo):

        # Save an Instance of our Main Algorithm
        self.algo = algo 

        # variable to hold nasdaq percentage change
        self.algo.percentageChange=None

        # Check Entry Condition only 30 seconds prior to Market Open
        self.entryTimeStart = self.algo.Time.replace(hour=9, minute=59, second=30, microsecond=0)
        self.entryTimeEnd   = self.algo.Time.replace(hour=10, minute=2, second=  10, microsecond=0)

        # ROLLING WINDOWS TO HOLD YESTERDAY'S CLOSE
        self.nasdaqYesterdayClose = RollingWindow[float](1)
        self.lumberYesterdayClose = RollingWindow[float](1)

        #insight arguments  
        self.insightPeriod = timedelta(hours = 1)
        self.insightDailyCount = 0

        # DICT TO HOLD INSIGHT TIME
        self.insightsTimeBySymbol = {}

        #rolling window to handle latest bid and ask
        self.latestBidRolling = RollingWindow[float](1)
        self.latestAskRolling = RollingWindow[float](1)

        # LIST AND COLLECTION FOR INSIGHTS
        self.insights = []
        self.insightCollection = InsightCollection()

        
    def OnLumberOpen(self):        

        #Resetting Latest Bid And Ask Rolling Window
        self.latestAskRolling.Reset()
        self.latestBidRolling.Reset()

        # GET LUMBER YESTERDAY'S CLOSE
        lumber_history = self.algo.History(self.algo.lumberSymbol,7,Resolution.Daily)      
        for bar in lumber_history.itertuples():
            self.lumberYesterdayClose.Add(bar.close)

        # GET NASDAQ'S YESTERDAY CLOSE
        nasdaq_history = self.algo.History(self.algo.nasdaqSymbol,7,Resolution.Daily)       
        for bar in nasdaq_history.itertuples():
            self.nasdaqYesterdayClose.Add(bar.close)

        self.insightDailyCount = 0 # Reset it to 0 every morning 
        # self.algo.Debug(f"Yesterday's Date:{self.algo.Time} Nasdaq Close:{self.nasdaqYesterdayClose[0]}, Lumber Close: {self.lumberYesterdayClose[0]}")


    def OnLumberClose(self):

        # Ideally this code should be inside EndOfDay in our Main class
        # GeneratedTimeUtc : Gets the utc time this insight was generated
        # CloseTimeUtc : Gets the insight's prediction end time. This is the time when this insight prediction 
        # is expected to be fulfilled. This time takes into account market hours, weekends, as well as the symbol's data resolution

        insight_properties = ['Symbol','GeneratedTimeUtc','CloseTimeUtc','Direction','EstimatedValue','Weight','Id','Magnitude','Confidence','Period','Score','IsActive','IsExpired']      

        for insight in self.insights:
            for prop in insight_properties:
                if prop in ['GeneratedTimeUtc','CloseTimeUtc']:
                    value = getattr(insight, prop) - timedelta(hours = 5) # Converting UTC to EST
                else:
                    value = getattr(insight, prop)
                # self.algo.Debug(f"{prop}:{value}")

 
    def OnSecuritiesChanged(self, algorithm,changes):       
        for security in changes.AddedSecurities:
            if security.Symbol == self.algo.lumberSymbol:
                # schedule an event to trigger before lumber market opens to get yesterday close for both nasdaq and lumber            
                algorithm.Schedule.On(algorithm.DateRules.EveryDay(security.Symbol), algorithm.TimeRules.AfterMarketOpen(security.Symbol, -2), self.OnLumberOpen)
                # algorithm.Schedule.On(algorithm.DateRules.EveryDay(security.Symbol), algorithm.TimeRules.BeforeMarketClose(security.Symbol, 2), self.OnLumberClose)

        for security in changes.RemovedSecurities:
            if security.Symbol in self.insightsTimeBySymbol:
                # REMOVE SECURITY FROM DICT
                self.insightsTimeBySymbol.pop(security.Symbol)

 

    def Update(self, algorithm, data): 

        # CHECK IF MARKET HOURS ARE VALID         
        if algorithm.Time < self.entryTimeStart or algorithm.Time > self.entryTimeEnd:
            return []

        insight = None

        #CHECK IF YESTERDAY'S LUMBER CLOSE AND NASDAQ CLOSE IS READY        
        if self.lumberYesterdayClose.IsReady and self.nasdaqYesterdayClose.IsReady:
             for security in data.Keys:
                # algorithm.Debug(f'{security}')
                ticks=data.Ticks[security]                
                if security == self.algo.nasdaqSymbol:
                    for tick in ticks:
                        if tick.TickType == TickType.Trade:
                            self.algo.percentageChange=((tick.Price - self.nasdaqYesterdayClose[0])/self.nasdaqYesterdayClose[0])*100
                            
                            if int(self.algo.nasdaqROCP.Current.Value) != 0:
                                pass
                                # algorithm.Debug(f"self.algo.percentageChange:{self.algo.percentageChange}, \
                                # self.algo.nasdaqROCP:{self.algo.nasdaqROCP.Current.Value}, self.algo.nasdaqDailyChange52High:{self.algo.nasdaqDailyChange52High.Current.Value}, self.algo.nasdaqDailyChange52Low:{self.algo.nasdaqDailyChange52Low.Current.Value}  ")

                if security == self.algo.lumberSymbol:
                    for tick in ticks:
                        if tick.TickType == TickType.Quote:

                      


                            # algorithm.Debug(f"bid is {tick.BidPrice}  ask is {tick.AskPrice}")                     

                            # check if tick ask is  equal to 0.0 and 
                            # there is no ask price in rolling window
                            if int(tick.AskPrice) == 0 and not self.latestAskRolling.IsReady:
                                ask = algorithm.Securities[security].AskPrice
                                # algorithm.Debug(f"ask was {tick.AskPrice} so using last ask {ask}")                     
                            
                            # check if tick ask is  equal to 0.0 and 
                            # there is  ask price in rolling window
                            elif int(tick.AskPrice) == 0 and self.latestAskRolling.IsReady:
                                ask = self.latestAskRolling[0]
                                # algorithm.Debug(f"ask was {tick.AskPrice} so using last ask from rolling window {ask}")                     
                            
                            else:
                                ask = tick.AskPrice
                                self.latestAskRolling.Add(ask)

                            # check if tick bid is  equal to 0.0 and 
                            # there is no bid price in rolling window
                            if int(tick.BidPrice) == 0 and not self.latestBidRolling.IsReady:
                                bid = algorithm.Securities[security].BidPrice
                                # algorithm.Debug(f"bid was {tick.BidPrice} so using last bid {bid}")                     
                            
                            # check if tick bid is  equal to 0.0 and 
                            # there is  Bid price in rolling window
                            elif int(tick.BidPrice) == 0 and self.latestBidRolling.IsReady:
                                bid = self.latestBidRolling[0]
                                # algorithm.Debug(f"bid was {tick.BidPrice} so using last bid from rolling window {bid}")                     
                            
                            else:
                                bid = tick.BidPrice
                                # adding the bid to rolling window
                                self.latestBidRolling.Add(bid)

                            # algorithm.Debug(f'ask:{tick.AskPrice} bid:{tick.BidPrice} time:{algorithm.Time}')
                            #CHECK IF LUMBER ASK ,TRADE IS GREATER THAN YESTERDAY LUMBER CLOSE AND NASDAQ CHANGE IS MORE THAN 1
                            if ask > self.lumberYesterdayClose[0] and bid > self.lumberYesterdayClose[0] and self.algo.percentageChange and self.algo.percentageChange > 1 and self.ShouldEmitInsight(algorithm.Time,security):
                                algorithm.Debug(f"Position Up: Date{algorithm.Time} Nasdaq ∆:{self.algo.percentageChange},Lumber Yesterday Close:{self.lumberYesterdayClose[0]}, Lumber Ask:{ask}, Lumber Bid:{bid}")
                                insight = Insight(self.algo._lumberContract.Mapped,self.insightPeriod, InsightType.Price, InsightDirection.Up)
                                algorithm.Debug(f"Up Insight generated at: {algorithm.Time}")
                                self.insights.append(insight)
                                
                            #CHECK IF LUMBER ASK ,TRADE IS LESS THAN YESTERDAY LUMBER CLOSE AND NASDAQ CHANGE IS LESS THAN -1    
                            elif bid < self.lumberYesterdayClose[0] and ask < self.lumberYesterdayClose[0] and self.algo.percentageChange and self.algo.percentageChange < -1 and self.ShouldEmitInsight(algorithm.Time,security):
                                algorithm.Debug(f"Position Down: Date{algorithm.Time} Nasdaq ∆:{self.algo.percentageChange},Lumber Yesterday Close:{self.lumberYesterdayClose[0]}, Lumber Ask:{ask}, Lumber Bid:{bid}")
                                # Insight(symbol, period, type, direction, magnitude=None, confidence=None, sourceModel=None, weight=None)
                                insight = Insight(self.algo._lumberContract.Mapped,self.insightPeriod, InsightType.Price, InsightDirection.Down)
                                algorithm.Debug(f"Down Insight generated at: {algorithm.Time}")
                                self.insights.append(insight)
                            #ELSE NO CONDITION MET
                            else:
                                # algorithm.Debug(f"No Condition Met, Date:{algorithm.Time}")
                                pass
                        
                               
        if insight is not None: self.insightCollection.Add(insight)

        return self.insights


    def ShouldEmitInsight(self, utcTime, symbol):
        generatedTimeUtc = self.insightsTimeBySymbol.get(symbol)
        self.insightDailyCount +=1
        if generatedTimeUtc is not None:
            # we previously emitted a insight for this symbol, check it's period to see if we should emit another insight        
            if utcTime - generatedTimeUtc < self.insightPeriod and self.insightDailyCount > 1:
                return False

        # we either haven't emitted a insight for this symbol or the previous insight's period has expired, so emit a new insight now for this symbol
        self.insightsTimeBySymbol[symbol] = utcTime
        return True



from AlgorithmImports import *

class NasdaqAlpha(AlphaModel):

    def __init__(self, algo):
        
        self.percentageChange=None # variable to hold nasdaq percentage change        
        self.algo = algo # Save an Instance of our Main Algorithm

        self.nasdaqYesterdayClose = RollingWindow[float](1)
        self.lumberYesterdayClose = RollingWindow[float](1)

        # Lumber & Nasdaq Symbols
        self.lumberSymbol  = self.algo._lumberContract.Symbol
        self.nasdaqSymbol  = self.algo._nasdaqContract.Symbol

        self.entryTimeStart = self.algo.Time.replace(hour=10, minute=0, second=0, microsecond=0)
        self.entryTimeEnd = self.algo.Time.replace(hour=15, minute=45, second=0, microsecond=0)

        #insight arguments  
        self.insightPeriod = timedelta(minutes=60)
        # self.insightPeriod = Expiry.EndOfDay(self.algo.Time) - timedelta(seconds=1)
        self.insightsTimeBySymbol = {}
        self.insights = []
        self.insightCollection = InsightCollection()


        self.count = 0

    def OnLumberOpen(self):

        # get Lumber yesterday close
        lumber_history = self.algo.History(self.lumberSymbol,1,Resolution.Daily)       
        for bar in lumber_history.itertuples():
            self.lumberYesterdayClose.Add(bar.close)

        # get nasdaq yesterday close
        nasdaq_history = self.algo.History(self.nasdaqSymbol,1,Resolution.Daily)
        for bar in nasdaq_history.itertuples():
            self.nasdaqYesterdayClose.Add(bar.close)
        
        self.algo.Debug(f"Yesterday's Date:{self.algo.Time} Nasdaq Close:{self.nasdaqYesterdayClose[0]}, Lumber Close: {self.lumberYesterdayClose[0]}")

    def OnLumberClose(self):
        # Ideally this code should be inside EndOfDay in our Main class
        # GeneratedTimeUtc : Gets the utc time this insight was generated
        # CloseTimeUtc : Gets the insight's prediction end time. This is the time when this insight prediction is expected to be fulfilled. This time takes into account market hours, weekends, as well as the symbol's data resolution
        insight_properties = ['Symbol','GeneratedTimeUtc','CloseTimeUtc','Direction','EstimatedValue','Weight','Id','Magnitude','Confidence','Period','Score','IsActive','IsExpired']       
        for insight in self.insights:
            for prop in insight_properties:
                if prop in ['GeneratedTimeUtc','CloseTimeUtc']:
                    value = getattr(insight, prop) - timedelta(hours = 5) # Converting UTC to EST
                else:
                    value = getattr(insight, prop)
                self.algo.Debug(f"{prop}:{value}")

        # Check if any Insights are Active
        self.algo.Debug(f"Active Insights: {self.insightCollection.GetActiveInsights(self.algo.UtcTime)} Time {self.algo.Time}")

        # Check if any Insights are Expired (Also Remove them)
        self.algo.Debug(f"Expired Insights: {self.insightCollection.RemoveExpiredInsights(self.algo.UtcTime)} Time {self.algo.Time}")

        
    def OnSecuritiesChanged(self, algorithm,changes):

        for security in changes.AddedSecurities:
            if security.Symbol == self.lumberSymbol:
                # schedule an event to trigger before lumber market opens to get yesterday close for both nasdaq and lumber            
                # algorithm.Schedule.On(algorithm.DateRules.EveryDay(security.Symbol), algorithm.TimeRules.AfterMarketOpen(security.Symbol, -2), self.OnLumberOpen)
                # algorithm.Schedule.On(algorithm.DateRules.EveryDay(security.Symbol), algorithm.TimeRules.BeforeMarketClose(security.Symbol, -2), self.OnLumberClose)
                pass
        for security in changes.RemovedSecurities:
            if security.Symbol in self.insightsTimeBySymbol:
                # self.insightsTimeBySymbol.pop(security.Symbol)
                pass


    def Update(self, algorithm, data):

        if algorithm.Time < self.entryTimeStart or  algorithm.Time > self.entryTimeEnd:
            return []

        
        insights = []
        for security in data.Keys:
            ticks=data.Ticks[security]
            for tick in ticks:
                if tick.TickType == TickType.Quote:
                    if tick.BidPrice != 0 and security == self.lumberSymbol and self.ShouldEmitInsight(algorithm.UtcTime, security):
                        algorithm.Debug(f"Position Up Generated: Date{algorithm.Time}")
                        if (self.count % 2) == 0: # If even
                            insights.append(Insight(security, self.insightPeriod, InsightType.Price, InsightDirection.Up, magnitude = None, confidence = None))
                        else:
                            insights.append(Insight(security, self.insightPeriod, InsightType.Price, InsightDirection.Down, magnitude = None, confidence = None))
                        self.count += 1
        return insights


    def ShouldEmitInsight(self, utcTime, symbol):

        generatedTimeUtc = self.insightsTimeBySymbol.get(symbol)
        if generatedTimeUtc is not None:
            # we previously emitted a insight for this symbol, check it's period to see if we should emit another insight        
            if utcTime - generatedTimeUtc < self.insightPeriod:
                return False

        # we either haven't emitted a insight for this symbol or the previous insight's period has expired, so emit a new insight now for this symbol
        self.insightsTimeBySymbol[symbol] = utcTime
        return True
from AlgorithmImports import *

class MyPortfolio(PortfolioConstructionModel):

    def __init__(self,algo,rebalancingFunc=None,portfolioBias=PortfolioBias.LongShort):
        # rebalancingFunc=Resolution.Daily

        self.algo=algo  # create the algo instance
        self.portfolioBias=portfolioBias
        self.setTargets = False

    def CreateTargets(self, algorithm, insights):
        
        tempCounter = 1
        """ This method is used to analyze the insights and determine for which insight 
        we need to create portfolio target i.e based on weight magnitude confidence etc.."""

        targets = []
        for insight in insights:
            # check if insight respects the portifolio bias
            if self.RespectPortfolioBias(insight) :
                # Fills up self.algo.positionCount
                self.GetPositionCount()

                # self.algo.Debug(f"Count of positionCount in CreateTargets of PortfolioModel: {abs(self.algo.positionCount)}")
                # Append PortfolioTargets List with One Order at a Time rather than 1 element with All Order quantity
                if not self.setTargets:
                    # self.algo.Debug(f"tempCounter in CreateTargets of PortfolioModel: {tempCounter}")
                    targets.append(PortfolioTarget(insight.Symbol,self.algo.positionCount))
                    
                    
                    # self.algo.Debug(f"Count of Insights in CreateTargets of PortfolioModel: {len(insights)} at Time: {self.algo.Time}")
                    self.setTargets = True

        # if targets and not self.setTargets:
        #     for target in targets:
        #         self.algo.Debug(f"Target in Portfolio Construction-:-{target}")
        #         pass
        
        # self.setTargets = True

        return targets



    def GetPositionCount(self):
        if np.sign(self.algo.percentageChange * 1) == -1:
            self.algo.positionCount = math.ceil(self.algo.percentageChange) * 1          
        elif np.sign(self.algo.percentageChange * 1) == 1:
            self.algo.positionCount = math.floor(self.algo.percentageChange) * 1


    def RespectPortfolioBias(self, insight):

        """method is used to check if the long,short or both position are allowed by portifolio"""
        return self.portfolioBias == PortfolioBias.LongShort or insight.Direction == PortfolioBias.Long or insight.Direction == PortfolioBias.Short


    def ShouldCreateTargetForInsight(self, insight: Insight) -> bool:

        """ This method is used to check for which insight we are supposed to generate the 
        portfolio target we can use magnitude, weight and other aspects for this"""
        return True


    def DetermineTargetPercent(self, activeInsights):
      
        """This method is used to calculate the %age of portifolio or no of stocks we want to set"""        
        pass
from AlgorithmImports import *

class MyPortfolio(PortfolioConstructionModel):

    def __init__(self, algo):
        
        # super().__init__()
        self.algo = algo # Save an Instance of our Main Algorithm

    def CreateTargets(self, algorithm, insights):
        targets = []
        for insight in insights:            
            self.algo.Debug(f"insight in Portfolio Construction:{insight}")
            targets.append(PortfolioTarget(insight.Symbol, insight.Direction*1))

        if targets:
            for target in targets:
                self.algo.Debug(f"target in Portfolio Construction-:-{target}")

        return targets

    def DetermineTargetPercent(self, activeInsights):
        self.algo.Debug(f"Inside DetermineTargetPercent in Portfolio Construction:{insight}")

        for insight in activeInsights:
            self.algo.Debug(f"active insight in DetermineTargetPercent:{insight}")
        # result = {}
        
        # # give equal weighting to each security
        # count = sum(x.Direction != InsightDirection.Flat for x in activeInsights)
        # self.algo.Debug(f"count in DetermineTargetPercent:{count}")

        # percent = 0.2 if count == 0 else 1.0 / count
        # for insight in activeInsights:
        #     self.algo.Debug(f"active insight in DetermineTargetPercent:{insight}")
        #     result[insight] = (InsightDirection.Up) * percent
        # return result

    def RespectPortfolioBias(self, insight):
        return True

    def ShouldCreateTargetForInsight(self, insight: Insight) -> bool:
        return True
from AlgorithmImports import *
import numpy as np

class MyPortfolio(PortfolioConstructionModel):

    def __init__(self,algo,rebalancingFunc=None,portfolioBias=PortfolioBias.LongShort):
        # rebalancingFunc=Resolution.Daily

        self.algo=algo  # create the algo instance
        self.portfolioBias=portfolioBias
        self.setTargets = False
        

    def CreateTargets(self, algorithm, insights):
        
        tempCounter = 1
        """ This method is used to analyze the insights and determine for which insight 
        we need to create portfolio target i.e based on weight magnitude confidence etc.."""

        targets = [] # list to hold targets
         
        for insight in insights:
            # check if insight respects the portifolio bias
            if self.RespectPortfolioBias(insight) :            
                # self.algo.Debug(f"Insight in Portfolio Construction:{insight}")
                # targets.append(PortfolioTarget(insight.Symbol,insight.Direction*1))
                
                # Fills up self.algo.positionCount
                self.GetPositionCount()
                
                # self.algo.Debug(f"Count of positionCount in CreateTargets of PortfolioModel: {abs(self.algo.positionCount)}")
                # Append PortfolioTargets List with One Order at a Time rather than 1 element with All Order quantity
                if not self.setTargets:
                    for _ in range(abs(self.algo.positionCount)):
                        # self.algo.Debug(f"tempCounter in CreateTargets of PortfolioModel: {tempCounter}")
                        targets.append(PortfolioTarget(insight.Symbol,np.sign(self.algo.positionCount)*1))
                        tempCounter +=1
                    
                    # self.algo.Debug(f"Count of Insights in CreateTargets of PortfolioModel: {len(insights)} at Time: {self.algo.Time}")

                    self.setTargets = True


        # if targets and not self.setTargets:
        #     for target in targets:
        #         self.algo.Debug(f"Target in Portfolio Construction-:-{target}")
        #         pass
        
        # self.setTargets = True

        return targets
        
    def GetPositionCount(self):
        if np.sign(self.algo.percentageChange * 1) == -1:
            self.algo.positionCount = math.ceil(self.algo.percentageChange) * 1          
        elif np.sign(self.algo.percentageChange * 1) == 1:
            self.algo.positionCount = math.floor(self.algo.percentageChange) * 1


    def RespectPortfolioBias(self, insight):

        """method is used to check if the long,short or both position are allowed by portifolio"""
        return self.portfolioBias == PortfolioBias.LongShort or insight.Direction == PortfolioBias.Long or insight.Direction == PortfolioBias.Short


    def ShouldCreateTargetForInsight(self, insight: Insight) -> bool:

        """ This method is used to check for which insight we are supposed to generate the 
        portfolio target we can use magnitude, weight and other aspects for this"""
        return True


    def DetermineTargetPercent(self, activeInsights):
      
        """This method is used to calculate the %age of portifolio or no of stocks we want to set"""        
        pass

from AlgorithmImports import *

class MyRiskManagementModel(RiskManagementModel):
    
    def __init__(self, algo):
        self.algo = algo # Save an Instance of our Main Algorithm
        self.count = 0
        self.target_modified = []


    # Adjust the portfolio targets and return them. If no changes emit nothing.
    def ManageRisk(self, algorithm: QCAlgorithm, targets: List[PortfolioTarget]) -> List[PortfolioTarget]:
        for target in targets:
            # self.algo.Debug(f"target in RiskManagamenet-:-{target}")
            pass
        return targets

from AlgorithmImports import *

class MyRiskManagementModel(RiskManagementModel):
    
    def __init__(self, algo):
        self.algo = algo # Save an Instance of our Main Algorithm
        self.count = 0
        self.target_modified = []


    # Adjust the portfolio targets and return them. If no changes emit nothing.
    def ManageRisk(self, algorithm: QCAlgorithm, targets: List[PortfolioTarget]) -> List[PortfolioTarget]:
        for target in targets:
            self.algo.Debug(f"target in RiskManagamenet-:-{target}")
        return targets

from AlgorithmImports import *
from NasdaqAlpha import *
from PortfolioModel import *
from ExecutionModel import *
from RiskModel import *
from orderEnum import *
import numpy as np

class NasdaqStrategy(QCAlgorithm):

    def Initialize(self):

        self.SetBrokerageModel(BrokerageName.InteractiveBrokersBrokerage, AccountType.Margin)
        self.DefaultOrderProperties = InteractiveBrokersOrderProperties()
        
        # Set a Limit Order to be good until market close
        self.DefaultOrderProperties.TimeInForce = TimeInForce.Day

        # Set a Limit Order to be good until noon
        self.order_properties = OrderProperties()
        self.order_properties.TimeInForce = TimeInForce.GoodTilDate(self.Time.replace(hour=16, minute=0, second=  0, microsecond=0))

        # self.DefaultOrderProperties.OutsideRegularTradingHours = True
        
        # Set start and end time for backtest
        self.SetStartDate(2022, 12, 22)
        self.SetEndDate(2022,12,23)
        # self.SetEndDate(datetime.now() - timedelta(2))        
        self.SetCash(1000000)
        
        # Lumber security
        self._lumberContract=self.AddFuture(Futures.Forestry.RandomLengthLumber,
        Resolution.Tick,dataMappingMode=DataMappingMode.FirstDayMonth,contractDepthOffset=0,
        dataNormalizationMode=DataNormalizationMode.Raw,extendedMarketHours=True, fillDataForward = True)

        # Nasdaq security
        self._nasdaqContract=self.AddFuture(Futures.Indices.MicroNASDAQ100EMini,
        Resolution.Tick,dataMappingMode = DataMappingMode.OpenInterest, contractDepthOffset=0,
        dataNormalizationMode = DataNormalizationMode.Raw, extendedMarketHours=True)
        
        # Set security initializer
        seeder = FuncSecuritySeeder(self.GetLastKnownPrices)
        self.SetSecurityInitializer(lambda security: seeder.SeedSecurity(security))

        # Symbols for securities:
        self.lumberSymbol = self._lumberContract.Symbol
        self.nasdaqSymbol = self._nasdaqContract.Symbol

        # Get 52 Week High and 52 Week Low of Nasdaq       
        self.nasdaqROCP = self.ROCP(self.nasdaqSymbol,1, Resolution.Daily)
        self.nasdaqDailyChange52High = IndicatorExtensions.MAX(self.nasdaqROCP, 252)
        self.RegisterIndicator(self.nasdaqSymbol, self.nasdaqDailyChange52High, Resolution.Daily)
        self.nasdaqDailyChange52Low = IndicatorExtensions.MIN(self.nasdaqROCP, 252)
        self.RegisterIndicator(self.nasdaqSymbol, self.nasdaqDailyChange52Low, Resolution.Daily)
        
        # Warm-Up the algorithm
        self.SetWarmup(timedelta(253),resolution=Resolution.Minute)

        self.positionCount = 0
        self.orderMultiplier = 1
        
        # example for buy orders
        self.TARGET_LIMIT_OFFSET = 10
        self.STOPLOSS_STOP_OFFSET = 5 # This will be the actual stop loss - this is called the stop price of the stop loss order
        self.STOPLOSS_LIMIT_OFFSET = 2 # Maximum allowed below stop loss so its called Limit price of the stop loss
        self.targetsCollection = PortfolioTargetCollection()
        self.tradesCollection = {}

        # Set portifolio consruction model
        self.SetPortfolioConstruction(MyPortfolio(self))
        
        # Set risk management model
        # self.AddRiskManagement(TrailingStopRiskManagementModel(maximumDrawdownPercent=0.05))
        # self.AddRiskManagement(MaximumUnrealizedProfitPercentPerSecurity(maximumUnrealizedProfitPercent	= 0.05))
        
        self.AddRiskManagement(NullRiskManagementModel()) # Default
        
        # Set execution model
        # self.SetExecution(ImmediateExecutionModel())    
        self.SetExecution(MyExecution(self))
        
        # Set  alpha model
        self.alpha= NasdaqAlpha(self)
        self.SetAlpha(self.alpha)


    def OnData(self, slice: Slice) -> None:
        
        #code to adjust trailing stop loss
        for security in slice.Keys:
            if security == self.lumberSymbol and security in slice.Ticks :
                ticks=slice.Ticks[security]
                for tick in ticks:
                    
                    if tick.TickType == TickType.Trade and len(self.tradesCollection) > 0:
                        
                        for key in self.tradesCollection.keys():
                            trade = self.tradesCollection[str(key)]

                            # can set the argument to pass the current tick price 
                            # for adjustment
                            response=trade.adjustTrailing()

                            if response == True:
                                self.Debug(f"trailing stop loss adjusted at time {self.Time}")
                



        for changed_event in slice.SymbolChangedEvents.Values:
            self.Log(f"Contract rollover from {changed_event.OldSymbol} to {changed_event.NewSymbol}")

        for key in self.tradesCollection.keys():

            ticket = self.Transactions.GetOrderTicket(key)
            trade = self.tradesCollection[str(key)]
            
            if ticket.Status == OrderStatus.Submitted:
                LimitPrice = ticket.Get(OrderField.LimitPrice)

                # To Check if this Ask & Bid Prices are consistent with Tick Data
                LatestAsk = self.Securities[ticket.Symbol].AskPrice 
                LatestBid = self.Securities[ticket.Symbol].BidPrice

                # Update LimitPrice if we are Long and Best Bid has Changed    
                if np.sign(ticket.Quantity * 1) == 1: # Its a buy order
                    if LimitPrice != LatestBid:
                        self.Debug(f"Updating order since LatestBid {LatestBid} ≠ LimitPrice {LimitPrice}")
                        trade.updateMainOrder(round(LatestBid))
                
                # Update LimitPrice if we are Short and Best Ask has Changed    
                elif np.sign(ticket.Quantity * 1) == -1: # Its a Sell order
                    if LimitPrice != LatestAsk:
                        self.Debug(f"Updating order since LatestAsk {LatestAsk} ≠ LimitPrice {LimitPrice}")
                        trade.updateMainOrder(round(LatestAsk)*0.98)
    
                else:
                    #  self.Debug(f"Not Updating order: LatestAsk:{LatestAsk}, LatestBid:{LatestBid} ,LimitPrice:{LimitPrice}")
                     pass


                


    # OnEndOfDay notifies when (Time) each security has finished trading for the day
    def OnEndOfDay(self, symbol: Symbol) -> None:
        # self.Debug(f"Finished Trading on {self.Time} for security {symbol}")
        pass
        
    # When your algorithm stops executing, LEAN calls the OnEndOfAlgorithm method.
    def OnEndOfAlgorithm(self) -> None:
        self.Debug("Printing tradesCollection")
        for key,value in self.tradesCollection.items():
            self.Debug(f"key:{key}, Value:{value}")
            
        self.Debug("Algorithm done")

    #     key = orderEvent.OrderId
    #     order = self.Transactions.GetOrderById(key)
    #     ticket = self.Transactions.GetOrderTicket(key) # Get Order Ticket
    #     self.Debug("{} In PreCheck OnOrderEvent: A {} order to {} was {} with quantity:{}, ticketDict {}, OrderType:{}".format(
    #     self.Time,  get_order_type_name(order.Type), get_order_direction_name(order.Direction),
    #     get_order_status_name(orderEvent.Status), order.Quantity,self.ticketDict.get(key),get_order_type_name(ticket.OrderType)))
        
    #     # LimitPrice:{} & StopPrice:{} - , ticket.Get(OrderField.LimitPrice),ticket.Get(OrderField.StopPrice)

    #     if ticket.Quantity != 0:
    #         if extractedOrder[0] == 'Main':
    #             if orderEvent.Status == OrderStatus.Filled:

    def OnOrderEvent(self, orderEvent):
        ticket=self.Transactions.GetOrderTicket(orderEvent.OrderId)

        self.Debug(f"OrderType:{get_order_type_name(ticket.OrderType)},OrderId:{ticket.OrderId},tradesCollection:{self.tradesCollection}")

        # If order is main
        if ticket.OrderType == OrderType.Limit and str(orderEvent.OrderId) in self.tradesCollection:
            
            # get trade  
            trade=self.tradesCollection[str(orderEvent.OrderId)]
              
            if ticket.Status == OrderStatus.Filled:
                self.Debug("Main Order Filled")
                
                # Calculate TakeProfit and Stop - Limit & Stop price
                fillPrice = orderEvent.FillPrice
                stopLossStopPrice = fillPrice- np.sign(ticket.Quantity * 1) * self.STOPLOSS_STOP_OFFSET
                stopLossLimitPrice = stopLossStopPrice - np.sign(ticket.Quantity * 1) * self.STOPLOSS_LIMIT_OFFSET
                takeProfitPrice = fillPrice+ np.sign(ticket.Quantity * 1) * self.TARGET_LIMIT_OFFSET
                
                # Place stoploss order
                trade.placeStopLossOrder(-ticket.Quantity,stopLossStopPrice,stopLossLimitPrice,self.order_properties)

                # Place Take Profit                
                trade.placeTakeProfitOrder(-ticket.Quantity,takeProfitPrice,self.order_properties)
            
            elif ticket.Status == OrderStatus.UpdateSubmitted:
                self.Debug(f"Order UpdateSubmitted")
                pass
            
            elif ticket.Status == OrderStatus.Submitted:
                self.Debug(f"Order Submitted")
                pass

        # If order is Take Profit
        elif  ticket.OrderType == OrderType.Limit and ticket.Tag in self.tradesCollection:
            if ticket.Status == OrderStatus.Filled:
                # self.Debug(f"tradesCollection in TakeProfit:{self.tradesCollection}")
                self.Debug(f"take profit placed with order_id {ticket.OrderId}")
                
                # get Main trade & Cancel StopLoss as Take Profit Filled
                trade=self.tradesCollection[str(ticket.Tag)]
                trade.cancelStopLoss()
        
        # If order is StopLoss
        elif  ticket.OrderType == OrderType.StopLimit:           
            if ticket.Status == OrderStatus.Filled:
                # self.Debug(f"tradesCollection in StopLoss:{self.tradesCollection}")
                self.Debug(f"Stop loss placed with order_id={ticket.OrderId}")
                
                # get Main trade & Cancel Take Profit as StopLoss Filled
                trade=self.tradesCollection[str(ticket.Tag)]
                trade.cancelTakeProfit()





from AlgorithmImports import *
# https://github.com/QuantConnect/Lean/blob/master/Common/Orders/OrderTypes.cs#L87

def get_order_status_name(index):
   return { 
       0: 'New',
       1: 'Submitted',
       2: 'PartiallyFilled',
       3: 'Filled',
       4: 'None',
       5: 'Canceled',
       6: 'None',
       7: 'Invalid',
       8: 'CancelPending',
       9: 'UpdateSubmitted '
    }[index]


def get_order_direction_name(index):
    return {
        0: 'Buy',
        1: 'Sell',
        2: 'Hold',
    }[index]


def get_order_type_name(index):
    return {
        0: 'Market',
        1: 'Limit',
        2: 'StopMarket',
        3: 'StopLimit',
        4: 'MarketOnOpen',
        5: 'MarketOnClose',
        6: 'OptionExercise',
        7: 'LimitIfTouched'
    }[index]