Overall Statistics
import math
from System.Drawing import Color


class SJMACD(QCAlgorithm):
    
    entryStopOrderTicket = {} #entry stop Market order
    slStopOrderTicket = {} #stop loss stop Market Order
    orderPlacedTime = {}
    entryPrice = {}
    stopLossPrice = {}
    quantity = {}
    

    def Initialize(self):
        self.SetStartDate(2014, 6, 15)  # Set Start Date
        self.SetEndDate(2018, 6, 25) # Set End Date
        self.SetCash(100000)  # Set Strategy Cash
        self.AddEquity("SPY", Resolution.Daily)
        self.SetWarmup(timedelta(days=365))
        self.secData = {}
        
        ##VARIABLES
        self.smaPeriod = 20
        self.macdFast = 5
        self.macdSlow = 25
        self.macdSignal = 5
        self.waitFillDuration = 3 #number of days unfilled orders stay open for
        
        #Order
        self.entryMargin = 0.2/100 # 0.08% entry Margin on market order
        self.stopLossMargin = 0.2/100 # 0.08% stoploss Margin on market order
        self.tradeRisk = 0.01/100 # % Trade Risk
        
        #Regimes
        self.regLPMA = 100 #Regime Long Period Moving Average
        self.regSPMA = 50 #Regime Short Period Moving Average
        
        #Plotting
        
        # MAIN CHART
        plotter = Chart("Chart")
        plotter.AddSeries(Series("Close", SeriesType.Line, 0))
        plotter.AddSeries(Series("SMA", SeriesType.Line, 0))
        plotter.AddSeries(Series("StopLoss", SeriesType.Scatter, 0))
        self.AddChart(plotter)
        
        # SIGNALS
        signalplotter = Chart("Signals")
        signalplotter.AddSeries(Series("Long", SeriesType.Scatter))
        signalplotter.AddSeries(Series("Short", SeriesType.Scatter))
        self.AddChart(signalplotter)
        
        # Orders
        signalplotter = Chart("Orders")
        signalplotter.AddSeries(Series("Submitted", SeriesType.Scatter, '$', Color.Red, ScatterMarkerSymbol.Triangle))
        signalplotter.AddSeries(Series("Filled", SeriesType.Scatter, '$', Color.Red, ScatterMarkerSymbol.Triangle))
        signalplotter.AddSeries(Series("Liquidate Order", SeriesType.Scatter, '$', Color.Red, ScatterMarkerSymbol.Triangle))
        self.AddChart(signalplotter)
        
        # HISTOGRAM
        secondplotter = Chart("Histogram")
        secondplotter.AddSeries(Series("Histogram", SeriesType.Bar, 0))
        self.AddChart(secondplotter)
        

    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
        '''
        
        for sec, secdata in self.secData.items():
            
            '''
            Define Variables for the loop
            '''
            #Define
            # self.Debug("{} Starting on data".format(self.Time))
            self.goLong = False
            self.goShort = False
            self.allowLong = True
            self.allowShort = True
    
            closePrice = data.Bars[sec.Symbol].Close
            openPrice = data.Bars[sec.Symbol].Open
            highPrice = data.Bars[sec.Symbol].High
            lowPrice = data.Bars[sec.Symbol].Low
            sma = self.secData[sec].sma.Current.Value
            histo = self.secData[sec].macd.Histogram.Current.Value
            
            #Regime
            regLPMA = self.secData[sec].regLPMA.Current.Value
            regSPMA = self.secData[sec].regSPMA.Current.Value
            
            #Update SecurityData
            self.secData[sec].updatedata(self.Time, closePrice, regLPMA, regSPMA,sma)    

            # Waiting for SMA and MACD to be ready
            if self.secData[sec].sma.IsReady and self.secData[sec].macd.IsReady and self.secData[sec].closeWindow.IsReady and self.secData[sec].regLPMAWindow.IsReady:
                
                prevClose = self.secData[sec].closeWindow[1]
                prevSma = self.secData[sec].smaWindow[1]
                
                # Plot Graphs
                self.Plot("Chart", "Close", closePrice)
                self.Plot("Chart", "SMA", sma)
                self.Plot("Histogram", "Histogram", histo)
                
                '''
                Check Signals
                '''
                

                # LONG #
                self.Debug("{} prevclose is {} preSma is {} sma {} closePrice {} hist {}".format(self.Time, prevClose, prevSma, sma, closePrice, histo))
                if prevClose < prevSma and closePrice > sma and histo > 0:
                    self.goLong = True
                    self.Plot("Signals", "Long", 1)
                    self.Debug("{} Long signal".format(self.Time))
                
                # SHORT #
                if prevClose > prevSma and closePrice < sma and histo < 0:
                    self.goShort = True
                    self.Plot("Signals", "Short", -1)
                    self.Debug("{} Short signal".format(self.Time))

                # self.Debug("{} self.self.goLong is {} and self.goshort is {}".format(self.Time, self.goLong, goShort))
                '''
                If the security is invested. 
                '''
                
                if self.Portfolio[sec.Symbol].Invested:
                    
                    self.Debug("{} symbol {} in portfolio is invested qty {}".format(self.Time, sec.Symbol, self.Portfolio[sec.Symbol].Quantity))
                    
                    # CHART THE STOP LOSS #
                    self.Plot("Chart", "StopLoss", self.slStopOrderTicket[sec.Symbol].Get(OrderField.StopPrice))
                    
                    '''
                    If long portfolio switches to goshort signal
                    '''
                    if self.Portfolio[sec.Symbol].IsLong and self.goShort:
                        self.Debug("{} symbol {} isLong qty {} and goShort is {}".format(self.Time, sec.Symbol, self.Portfolio[sec.Symbol].Quantity, self.goShort))
                        
                        # EXIT LONG POSITION
                        self.Liquidate(sec.Symbol)
                        self.Plot("Orders", "Liquidate Order", closePrice*1.05)
                        self.response = self.slStopOrderTicket[sec.Symbol].Cancel("Closed position and cancelled slStopOrderTicket")
                        if self.response.IsSuccess:
                            self.Debug("{} entryStopOrderTicket successfully canceled".format(self.Time))
                        
                        # SUBMIT SHORT ORDER
                        
                        if self.allowShort:
                        
                            self.Debug("{} submitting short order for {}".format(self.Time, sec.Symbol))
                                
                            #Short Variables
                            self.entryPrice[sec.Symbol] = lowPrice * (1 - self.entryMargin)
                            self.stopLossPrice[sec.Symbol] = highPrice * (1 + self.stopLossMargin)
                            self.quantity[sec.Symbol] = math.floor((self.Portfolio.TotalPortfolioValue * self.tradeRisk ) / (self.entryPrice[sec.Symbol] - self.stopLossPrice[sec.Symbol]))
                        
                            #Short Order
                            self.entryStopOrderTicket[sec.Symbol] = self.StopMarketOrder(sec.Symbol, self.quantity[sec.Symbol], self.entryPrice[sec.Symbol])
                            self.Debug("{} short entryStopOrder placed {} @ {} sl {} qty {}".format(self.Time, sec.Symbol, self.entryPrice[sec.Symbol], self.stopLossPrice[sec.Symbol], self.quantity[sec.Symbol]))
                            self.orderPlacedTime[sec.Symbol] = self.Time
    
                            #PlotOrders
                            self.Plot("Orders", "Submitted", self.entryPrice[sec.Symbol]) #would like to plot this in the OnOrderEvent but can't manage to retrieve the OrderId to match it with the orderEvent.OrderId
                        
                            
                    '''
                    If short portfolio switches to self.goLong signal
                    '''
                    if self.Portfolio[sec.Symbol].IsShort and self.goLong:
                        self.Debug("{} symbol {} isShort qty {} and goLong is {}".format(self.Time, sec.Symbol, self.Portfolio[sec.Symbol].Quantity, self.goLong))

                        # EXIT SHORT POSITION
                        self.Liquidate(sec.Symbol)
                        self.Plot("Orders", "Liquidate Order", closePrice*1.05)
                        self.response = self.slStopOrderTicket[sec.Symbol].Cancel("Closed position and cancelled slStopOrderTicket")
                        if self.response.IsSuccess:
                            self.Debug("{} entryStopOrderTicket successfully canceled".format(self.Time))
                        
                        
                        # SUBMIT LONG ORDER
                        
                        if self.allowLong:
                            
                            self.Debug("{} submitting long order for {}".format(self.Time, sec.Symbol))
                        
                            #Long Variables
                            self.entryPrice[sec.Symbol] = highPrice * (1 + self.entryMargin)
                            self.stopLossPrice[sec.Symbol] = lowPrice * (1 - self.stopLossMargin)
                            self.quantity[sec.Symbol] = math.floor((self.Portfolio.TotalPortfolioValue * self.tradeRisk ) / (self.entryPrice[sec.Symbol] - self.stopLossPrice[sec.Symbol]))
                            self.Debug("{} 2long order quantity calculation totalportfoliovalue {} tradeRisk {} entryprice {} stoplossprice {}".format(self.Time, self.Portfolio.TotalPortfolioValue, self.tradeRisk, self.entryPrice[sec.Symbol], self.stopLossPrice[sec.Symbol]))
                        
                            #Long Order
                            self.entryStopOrderTicket[sec.Symbol] = self.StopMarketOrder(sec.Symbol, self.quantity[sec.Symbol], self.entryPrice[sec.Symbol])
                            self.Debug("{} long entryStopOrder placed {} @ {} sl {} qty {}".format(self.Time, sec.Symbol, self.entryPrice[sec.Symbol], self.stopLossPrice[sec.Symbol], self.quantity[sec.Symbol]))
                            self.orderPlacedTime[sec.Symbol] = self.Time
        
                            #PlotOrders
                            self.Plot("Orders", "Submitted", self.entryPrice[sec.Symbol]) #would like to plot this in the OnOrderEvent but can't manage to retrieve the OrderId to match it with the orderEvent.OrderId
                        
                    

                '''
                If the security is not invested
                '''
                
                if not self.Portfolio[sec.Symbol].Invested:
                    
                    self.Debug("{} symbol {} in portfolio is not invested".format(self.Time, sec.Symbol))
                    self.Debug("{} golong is {} allow long is {}".format(self.Time, self.goLong, self.allowLong))
                    self.Debug("{} goShort is {} allow short is {}".format(self.Time, self.goShort, self.allowShort))
                    

                    '''
                    Cancel unfilled Orders which are older than the waitFillDuration
                    '''
                    if sec.Symbol in self.entryStopOrderTicket and not self.entryStopOrderTicket[sec.Symbol].Status == OrderStatus.Filled and (self.Time - self.orderPlacedTime[sec.Symbol]).days >= self.waitFillDuration:
                        
                        self.Debug("{} cancelling unfilled orders which are older than waitfill duration.".format(self.Time))
                        
                        #Cancel Order
                        self.response = self.entryStopOrderTicket[sec.Symbol].Cancel("Canceled entryStopOrderTicket")
                        if self.response.IsSuccess:
                            self.Debug("{} entryStopOrderTicket successfully canceled".format(self.Time))
                        self.entryStopOrderTicket.pop(sec.Symbol) #removes it from the dictionary

                    if sec.Symbol not in self.entryStopOrderTicket and self.goLong and self.allowLong:
                        
                        '''
                        Submit Long Orders if no long tickets exist
                        '''
                        self.Debug("{} submitting long order for {}".format(self.Time, sec.Symbol))
                    
                        #Long Variables
                        self.entryPrice[sec.Symbol] = highPrice * (1 + self.entryMargin)
                        self.stopLossPrice[sec.Symbol] = lowPrice * (1 - self.stopLossMargin)
                        self.quantity[sec.Symbol] = math.floor((self.Portfolio.TotalPortfolioValue * self.tradeRisk ) / (self.entryPrice[sec.Symbol] - self.stopLossPrice[sec.Symbol]))
                        self.Debug("{} 1long order quantity calculation totalportfoliovalue {} tradeRisk {} entryprice {} stoplossprice {}".format(
                            self.Time, self.Portfolio.TotalPortfolioValue, self.tradeRisk, self.entryPrice[sec.Symbol], self.stopLossPrice[sec.Symbol]))
                    
                        #Long Order
                        self.entryStopOrderTicket[sec.Symbol] = self.StopMarketOrder(sec.Symbol, self.quantity[sec.Symbol], self.entryPrice[sec.Symbol])
                        self.Debug("{} long entryStopOrder placed {} @ {} sl {} qty {}".format(self.Time, sec.Symbol, self.entryPrice[sec.Symbol], self.stopLossPrice[sec.Symbol], self.quantity[sec.Symbol]))
                        self.orderPlacedTime[sec.Symbol] = self.Time

                        #PlotOrders
                        # self.Plot("Orders", "Submitted", self.entryPrice[sec.Symbol]) #would like to plot this in the OnOrderEvent but can't manage to retrieve the OrderId to match it with the orderEvent.OrderId
                        
                    if sec.Symbol not in self.entryStopOrderTicket and self.goShort and self.allowShort:
                        
                        '''
                        Submit Short Orders if no long tickets exist
                        '''
                    
                        self.Debug("{} submitting short order for {}".format(self.Time, sec.Symbol))
                        
                        #Short Variables
                        self.entryPrice[sec.Symbol] = lowPrice * (1 - self.entryMargin)
                        self.stopLossPrice[sec.Symbol] = highPrice * (1 + self.stopLossMargin)
                        self.quantity[sec.Symbol] = math.floor((self.Portfolio.TotalPortfolioValue * self.tradeRisk ) / (self.entryPrice[sec.Symbol] - self.stopLossPrice[sec.Symbol]))
                    
                        #Short Order
                        self.entryStopOrderTicket[sec.Symbol] = self.StopMarketOrder(sec.Symbol, self.quantity[sec.Symbol], self.entryPrice[sec.Symbol])
                        self.Debug("{} short entryStopOrder placed {} @ {} sl {} qty {}".format(self.Time, sec.Symbol, self.entryPrice[sec.Symbol], self.stopLossPrice[sec.Symbol], self.quantity[sec.Symbol]))
                        self.orderPlacedTime[sec.Symbol] = self.Time

                        #PlotOrders
                        self.Plot("Orders", "Submitted", self.entryPrice[sec.Symbol]) #would like to plot this in the OnOrderEvent but can't manage to retrieve the OrderId to match it with the orderEvent.OrderId


    def OnSecuritiesChanged(self, changes):
        
        for sec in changes.AddedSecurities:
            self.secData[sec] = SecurityData(sec.Symbol, self, self.smaPeriod, self.macdFast, self.macdSlow, self.macdSignal, self.regLPMA, self.regSPMA)

    def OnOrderEvent(self, orderEvent):
        
        if orderEvent.Status == OrderStatus.Submitted:
            self.Debug("{} OnOrderEvent has been submitted {} @ {}(fill price) qty {}".format(self.Time, orderEvent.Symbol, orderEvent.FillPrice, orderEvent.Quantity))
            pass


        if orderEvent.Status == OrderStatus.Filled:
            self.Plot("Orders", "Filled", orderEvent.FillPrice)
            self.Debug("{} order has been filled {} @ {} qty {} ".format(self.Time, orderEvent.Symbol, orderEvent.FillPrice, orderEvent.Quantity))
            
            '''
            Submit the stop loss order if we are holding a position
            '''
            if self.Portfolio[orderEvent.Symbol].Invested:
                self.slStopOrderTicket[orderEvent.Symbol] = self.StopMarketOrder(orderEvent.Symbol, -orderEvent.Quantity, self.stopLossPrice[orderEvent.Symbol], "Stop Loss Order")
                
                self.Debug("{} submitting the stoploss order for {} @ {} (stop loss) qty {}".format(self.Time, orderEvent.Symbol, self.stopLossPrice[orderEvent.Symbol], -orderEvent.Quantity, ))
            

class SecurityData():
        def __init__(self, symbol, algorithm, smaPeriod, macdFast, macdSlow, macdSignal, regLPMA, regSPMA):
            
            # Indicators
            self.sma = SimpleMovingAverage(smaPeriod)
            self.macd = algorithm.MACD(symbol, macdFast, macdSlow, macdSignal, MovingAverageType.Simple, Resolution.Daily)
            self.closeWindow = RollingWindow[float](2)
            self.smaWindow = RollingWindow[float](2)
            
            # Regimes
            self.regLPMA = SimpleMovingAverage(regLPMA)
            self.regSPMA = SimpleMovingAverage(regSPMA)
            self.regLPMAWindow = RollingWindow[float](2)
            self.regSPMAWindow = RollingWindow[float](2)
            
        def updatedata(self, time, closePrice, regLPMA, regSPMA, sma):
            # Indicators
            self.sma.Update(time, closePrice)
            self.closeWindow.Add(closePrice)
            self.smaWindow.Add(sma)
            
            # Regimes
            self.regLPMA.Update(time, closePrice)
            self.regSPMA.Update(time, closePrice)
            self.regLPMAWindow.Add(regLPMA)
            self.regSPMAWindow.Add(regSPMA)