Overall Statistics |
Total Trades 520 Average Win 1.09% Average Loss -1.51% Compounding Annual Return -3.188% Drawdown 26.300% Expectancy -0.031 Net Profit -15.803% Sharpe Ratio -0.173 Probabilistic Sharpe Ratio 0.116% Loss Rate 44% Win Rate 56% Profit-Loss Ratio 0.73 Alpha -0.016 Beta -0.044 Annual Standard Deviation 0.114 Annual Variance 0.013 Information Ratio -0.465 Tracking Error 0.209 Treynor Ratio 0.45 Total Fees $520.26 |
import numpy as np import pandas as pd from datetime import datetime, timedelta class ZIVTradingStrategy(QCAlgorithm): ## order ticket for stop order stopMarketTicket = None stopMarketFillTime = datetime.min highestPrice = 0 def Initialize(self): self.SetStartDate(2015, 1, 2) # Set Start Date self.SetCash(10000) # Set Strategy Cash self.ziv = self.AddEquity("ZIV", Resolution.Daily) self.ziv.SetDataNormalizationMode(DataNormalizationMode.Raw) # Creates an indicator and adds to a rolling window when it is updated self.rocfiveday = self.ROC("ZIV", 5, Resolution.Daily) self.rocfiveday.Updated += self.ROCFiveDayUpdated self.rocfiveDayWindow = RollingWindow[IndicatorDataPoint](5) self.roctenday = self.ROC("ZIV", 10, Resolution.Daily) self.roctenday.Updated += self.ROCTenDayUpdated self.roctenDayWindow = RollingWindow[IndicatorDataPoint](5) self.momfiveday = self.MOM("ZIV", 5, Resolution.Daily) self.momfiveday.Updated += self.MOMFiveDayUpdated self.momfiveDayWindow = RollingWindow[IndicatorDataPoint](5) self.momtenday = self.MOM("ZIV", 10, Resolution.Daily) self.momtenday.Updated += self.MOMTenDayUpdated self.momtenDayWindow = RollingWindow[IndicatorDataPoint](5) # get ATR to use for stop loss. self.atr = self.ATR("ZIV", 20, Resolution.Daily) # get volatility lookback self.lookback = 30 self.SetWarmUp(self.lookback) # set up volatility calculation. this is more efficient instead of calling historical data in onData 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.15 # this is for listening to order status self.lastOrderEvent = None self.ticket = None # Flag for position status 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 ## comparing the signal to 0 does not work. long_signal_1 = self.momfiveDayWindow[0] > self.momfiveDayWindow[2] #long_signal_1 = self.momfiveDayWindow[0] > float(0) ## THIS DOES NOT WORK. if not self.Portfolio.Invested: if long_signal_1 == True: volatility = volatility = self.std.Current.Value * np.sqrt(252) # get vol. weight = self.target_portfolio_sigma / volatility # get weight. quantity = (self.Portfolio.TotalPortfolioValue * weight)/self.Securities["ZIV"].Close # get quantity. self.ticket = self.MarketOrder("ZIV", quantity) #self.MarketOrder("ZIV", quantity) self.stopMarketTicket = self.StopMarketOrder("ZIV", -quantity, self.Securities["ZIV"].Close - 2 * self.atr.Current.Value) elif self.Portfolio.Invested 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 - 2 * self.atr.Current.Value ## updating stop price self.stopMarketTicket.Update(updateFields) self.Debug("ZIV: " + str(self.highestPrice) + " Stop: " + str(updateFields.StopPrice)) elif self.Portfolio.Invested and self.UtcTime >= self.ticket.Time + timedelta(days = 3): self.Liquidate("ZIV") self.highestPrice = 0 self.ticket = None # define methods to add indicator values to a rolling window. def MOMFiveDayUpdated(self, sender, updated): self.momfiveDayWindow.Add(updated) def MOMTenDayUpdated(self, sender, updated): self.momtenDayWindow.Add(updated) # Adds updated values to rolling window def ROCFiveDayUpdated(self, sender, updated): self.rocfiveDayWindow.Add(updated) def ROCTenDayUpdated(self, sender, updated): self.roctenDayWindow.Add(updated) 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)