Overall Statistics
import numpy as np
import pandas as pd
import math

class NadionHorizontalCircuit(QCAlgorithm):

        ## order ticket for stop order
        stopMarketTicket = None
        stopMarketFillTime = datetime.min
        highestPrice = 0
        prevClose = 0
        

        def Initialize(self):
                self.SetStartDate(2015, 1, 2)  # Set Start Date
                self.SetEndDate(2020, 1, 28)
                self.SetCash(10000)  # Set Strategy Cash
               
                self.ziv = self.AddEquity("ZIV", Resolution.Daily)
                self.ziv.SetDataNormalizationMode(DataNormalizationMode.Raw)
            
                self.roc = self.ROC("ZIV", 5, Resolution.Daily)
                #self.SetWarmUp(5)
                self.lastOrderEvent = None ## this is for listening to order status
                
                # get ATR to use for stop loss.
                self.atr = self.ATR("ZIV", 20, Resolution.Daily)
                
                # get volatility
                self.lookback = 30
                self.SetWarmUp(self.lookback)
                
                self.roc1 = self.ROC("ZIV", 1, Resolution.Daily)
                self.std = IndicatorExtensions.Of(StandardDeviation(self.lookback), self.roc1)
                
                # define portfolio volatility
                self.target_portfolio_sigma = 0.12
        
        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 self.IsWarmingUp:
                    return
                
                # check that 1 day have passed since we hit the stop loss.
                if(self.Time - self.stopMarketFillTime).days < 2:
                    return ## this means wait
                
                if not self.Portfolio.Invested:
                    if self.roc.Current.Value > 0:
                        volatility = self.std.Current.Value * np.sqrt(252)

                        # calculate quantity to trade based on the targeted vol
                        weight = self.target_portfolio_sigma / volatility
                        quantity = (self.Portfolio.TotalPortfolioValue * weight)/self.Securities["ZIV"].Close
                        
                        self.MarketOrder("ZIV", quantity)
                        # create stop loss and track the ticket
                        self.stopMarketTicket = self.StopMarketOrder("ZIV", -quantity, self.Securities["ZIV"].Close - 2 * self.atr.Current.Value)
                else:
                    if self.roc.Current.Value > 0:
                        # check if the current price is higher than the highest closing price since we entered position
                        if self.Securities["ZIV"].Close > self.highestPrice:
                            # save the new highestPrice
                            self.highestPrice = self.Securities["ZIV"].Close
                            updateFields = UpdateOrderFields()
                            updateFields.StopPrice = self.highestPrice - 2 * self.atr.Current.Value ## updating stop price
                            self.stopMarketTicket.Update(updateFields)
                            self.Debug("ZIV: " + str(self.highestPrice) + " Stop: " + str(updateFields.StopPrice))
                    else:
                        self.Liquidate("ZIV")
                        self.highestPrice = 0
       
        def OnOrderEvent(self, orderEvent):
            if orderEvent.Status != OrderStatus.Filled:
                return ## if no orders were filled then wait and dont worry.
            
            # this checks that the stop order ticket was submitted
            if self.stopMarketTicket is not None and self.stopMarketTicket.OrderId == orderEvent.OrderId:
                self.stopMarketFillTime = self.Time
                self.Debug(self.stopMarketFillTime)