Overall Statistics
import numpy as np
import pandas as pd
from datetime import datetime, timedelta

class UncoupledTransdimensionalAntennaArray(QCAlgorithm):

    def Initialize(self):
       
        stopMarketTicket = None
        stopMarketFillTime = datetime.min
        highestPrice = 0
        
        self.SetStartDate(2015, 1, 1)  # Set Start Date
        self.SetCash(10000)  # Set Strategy Cash
        self.asset =  self.AddEquity("ZIV", Resolution.Minute)
        self.asset.SetDataNormalizationMode(DataNormalizationMode.Raw)
        
        # define the n period indicators with indicator constructors.
        self.rocfiveDay = RateOfChange(5)
        self.rocfiveDay.Updated += self.ROCFiveDayUpdated
        self.rocfiveDayWindow = RollingWindow[IndicatorDataPoint](6)
        
        # for volatility.
        self.roc1 = RateOfChange(1)
        
        # for stop loss
        self.atr = AverageTrueRange(20)
        
        # this is for listening to order status
        self.lastOrderEvent = None 
        self.ticket = None # Flag for position status
        
        # define portfolio volatility
        self.target_portfolio_sigma = 0.25
       
        self.Schedule.On(self.DateRules.EveryDay("ZIV"), self.TimeRules.BeforeMarketClose("ZIV", 5), self.Rebalance)

    def Rebalance(self):
        
        # this is to warm up indicators.
        if not self.rocfiveDay.IsReady:
            history = self.History("ZIV", 5, Resolution.Daily)
            for bar in history:
                self.rocfiveDay.Update(bar.EndTime, bar.Close)
        self.rocfiveDay.Update(self.Time, self.Securities["ZIV"].Close)
        
        # wait is indicators are not ready.
        if not self.rocfiveDayWindow.IsReady:
            return
        
        # voltaility calculator. one day return.
        if not self.roc1.IsReady:
            history = self.History("ZIV", 1, Resolution.Daily)
            for bar in history: 
                self.roc1.Update(bar.EndTime, bar.Close)
        self.roc1.Update(self.Time, self.Securities["ZIV"].Close)
        self.std = IndicatorExtensions.Of(StandardDeviation(30), self.roc1)
        
        '''
        # ATR for Stop Loss.
        if not self.atr.IsReady:
            history = self.History("ZIV", 20, Resolution.Daily)
            for bar in history: 
                self.atr.Update(bar.EndTime, bar.Close)
        self.atr.Update(self.Time, self.Securities["ZIV"].Close)
        '''
        
        long_signal_1 = self.rocfiveDayWindow[0] > self.rocfiveDayWindow[1]
        if not self.Portfolio.Invested:
            if long_signal_1 == True:
                volatility = self.std.Current.Value * np.sqrt(252) # get vol.
                self.Debug("Volatility " + str(volatility))
                weight = self.target_portfolio_sigma / volatility # get weight.
                #quantity = (self.Portfolio.TotalPortfolioValue * weight)/self.Securities["ZIV"].Close # get quantity.
                quantity = self.Portfolio.TotalPortfolioValue / self.Securities["ZIV"].Close
                self.ticket = self.MarketOrder("ZIV", quantity) #self.MarketOrder("ZIV", quantity)
                self.stopMarketTicket = self.StopMarketOrder("ZIV", -quantity, 0.9 * self.Securities["ZIV"].Close) ## TODO update to 2 times ATR
                self.Debug("Volatility " + str(volatility))
                self.Debug("Portfolio Size " + str(self.Portfolio.TotalPortfolioValue ))
                self.Debug("Quantity " + str(quantity))
                # self.Log() # add log messaging
        elif self.ticket is not None and (self.UtcTime - self.ticket.Time).days < 3: ## to update stop loss.
            if self.Securities["ZIV"].Close > self.highestPrice:
                self.highestPrice = self.Securities["ZIV"].Close # save the new highestPrice
                updateFields = UpdateOrderFields()
                updateFields.StopPrice =  self.highestPrice * 0.9 # TODO self.highestPrice - 2 * self.atr.Current.Value ## updating stop price
                self.stopMarketTicket.Update(updateFields)
                self.Debug("ZIV: " + str(self.highestPrice) + " Stop: " + str(updateFields.StopPrice))
        elif self.ticket is not None and self.UtcTime >= self.ticket.Time + timedelta(days = 3):
                self.Liquidate("ZIV")
                self.highestPrice = 0
                self.ticket = None
        
    
    def ROCFiveDayUpdated(self, sender, updated):
        self.rocfiveDayWindow.Add(updated)