Overall Statistics |
Total Trades 117 Average Win 4.59% Average Loss -1.14% Compounding Annual Return 4.606% Drawdown 25.200% Expectancy 1.082 Net Profit 84.475% Sharpe Ratio 0.457 Probabilistic Sharpe Ratio 2.262% Loss Rate 59% Win Rate 41% Profit-Loss Ratio 4.03 Alpha 0.018 Beta 0.325 Annual Standard Deviation 0.117 Annual Variance 0.014 Information Ratio -0.328 Tracking Error 0.168 Treynor Ratio 0.164 Total Fees $6779.78 |
def UpdateBenchmarkValue(self): ''' Simulate buy and hold the Benchmark ''' if self.initBenchmarkPrice == 0: self.initBenchmarkCash = self.Portfolio.Cash self.initBenchmarkPrice = self.Benchmark.Evaluate(self.Time) self.benchmarkValue = self.initBenchmarkCash else: currentBenchmarkPrice = self.Benchmark.Evaluate(self.Time) self.benchmarkValue = (currentBenchmarkPrice / self.initBenchmarkPrice) * self.initBenchmarkCash def UpdatePlots(self, currentEquitySMA, equityClosePrice): # plot close price, SMA and portfolio exposures self.Plot('Signals', 'Equity SMA', float(currentEquitySMA)) self.Plot('Signals', 'Equity Close Price', float(equityClosePrice)) portfolioValue = self.Portfolio.TotalPortfolioValue equityExposure = (self.Portfolio[self.equitySymbol].HoldingsValue / portfolioValue) * 100 safeExposure = (self.Portfolio[self.safeSymbol].HoldingsValue / portfolioValue) * 100 self.Plot('Portfolio Exposures', 'Equity Exposure', equityExposure) self.Plot('Portfolio Exposures', 'Safe Exposure', safeExposure) if not self.newSignal: return # plot signals if self.signal == 1: self.Plot('Signals', 'Equity Position', float(equityClosePrice)) elif self.signal == 2: self.Plot('Signals', 'Mix Position', float(equityClosePrice)) elif self.signal == 3: self.Plot('Signals', 'Safe Position', float(equityClosePrice)) def CustomSecurityInitializer(self, security): ''' Description: Initialize the security with different models Args: security: Security which characteristics we want to change''' security.SetLeverage(self.leverage)
### 2020_07_17 v3 ### ---------------------------------------------------------------------------- # ### ---------------------------------------------------------------------------- from HelperFunctions import * from System.Drawing import Color class TrendFollowingSystemTemplateAlgorithm(QCAlgorithm): ''' Implementation of the Pacer Trendpilot Strategy ''' def Initialize(self): ''' Initialization at beginning of backtest ''' ### USER-DEFINED INPUTS --------------------------------------------------------------------------------------------------- self.SetStartDate(2007, 1, 1) self.SetEndDate(2020, 7, 31) self.SetCash(1000000) # set account leverage self.leverage = 1 # TICKERS ---------------------------------------------------------------------------------- self.equityTicker = 'SPY' # equity like asset self.safeTicker = 'BIL' # cash/bond like asset self.benchmarkTicker = 'SPY' # select a benchmark # TECHNICAL INDICATORS --------------------------------------------------------------------- self.periodSMA = 200 # period for equity SMA # SIGNALS AND ALLOCATIONS ------------------------------------------------------------------ # parameters for step 1 ------------------------------------------------ # step 1 (equity position) equity close price is above its SMA for n consecutive days # number of days to check if price has been above its SMA for n consecutive days self.daysConsecutivePriceAboveSMA = 5 # allocations = [equityTicker allocation, safeTicker allocation] self.allocationStepOne = [1, 0] # allocation in step one # parameters for step 2 ------------------------------------------------ # step 2 (mix position) equity close price is below its SMA for n consecutive days # number of days to check if price has been below its SMA for n consecutive days self.daysConsecutivePriceBelowSMA = 5 # allocations = [equityTicker allocation, safeTicker allocation] self.allocationStepTwo = [0, 1] # allocation in step two # parameters for step 3 ------------------------------------------------ # step 3 (safe position) equity current SMA is lower than SMA n days ago # number of days to check if current SMA is lower than n days ago self.daysAgoLowerSMA = 5 # allocations = [equityTicker allocation, safeTicker allocation] self.allocationStepThree = [0, 1] # allocation in step three ### ----------------------------------------------------------------------------------------------------------------------- # apply CustomSecurityInitializer self.SetSecurityInitializer(lambda x: CustomSecurityInitializer(self, x)) # add benchmark self.SetBenchmark(self.benchmarkTicker) # add data self.equitySymbol = self.AddEquity(self.equityTicker, Resolution.Hour).Symbol self.safeSymbol = self.AddEquity(self.safeTicker, Resolution.Hour).Symbol # add indicators self.equitySMA = self.SMA(self.equitySymbol, self.periodSMA, Resolution.Daily) self.winEquitySMA = RollingWindow[float](self.daysAgoLowerSMA) # set a warm-up period to initialize the indicator self.SetWarmUp(self.periodSMA) # initialize variables self.countDaysEquityAboveSMA = 0 self.countDaysEquityBelowSMA = 0 self.signal = 0 self.initBenchmarkPrice = 0 # initialize plots signalsPlot = Chart('Signals') signalsPlot.AddSeries(Series('Equity SMA', SeriesType.Line, '$', Color.Blue)) signalsPlot.AddSeries(Series('Equity Close Price', SeriesType.Line, '$', Color.Black)) signalsPlot.AddSeries(Series('Equity Position', SeriesType.Scatter, '', Color.Green, ScatterMarkerSymbol.Triangle)) signalsPlot.AddSeries(Series('Mix Position', SeriesType.Scatter, '', Color.Orange, ScatterMarkerSymbol.Triangle)) signalsPlot.AddSeries(Series('Safe Position', SeriesType.Scatter, '', Color.Red, ScatterMarkerSymbol.Triangle)) self.AddChart(signalsPlot) portfolioExposuresPlot = Chart('Portfolio Exposures') portfolioExposuresPlot.AddSeries(Series('Equity Exposure', SeriesType.Line, '%', Color.Green)) portfolioExposuresPlot.AddSeries(Series('Safe Exposure', SeriesType.Line, '%', Color.Red)) self.AddChart(portfolioExposuresPlot) def OnData(self, data): ''' Event triggering every time there is new data ''' if self.Time.hour != 10: return if not self.equitySMA.IsReady: return # wait until winEquitySMA is ready if not self.winEquitySMA.IsReady: currentEquitySMA = self.equitySMA.Current.Value self.winEquitySMA.Add(currentEquitySMA) return if (data.ContainsKey(self.equitySymbol) and data.ContainsKey(self.safeSymbol) and self.ActiveSecurities[self.equitySymbol].Price > 0 and self.ActiveSecurities[self.safeSymbol].Price > 0): # get curent SMA value currentEquitySMA = self.equitySMA.Current.Value # get last daily close price history = self.History(self.equitySymbol, 1, Resolution.Daily) if 'close' in history: equityClosePrice = history['close'][0] else: return # check if close price is above/below indicator # add to the count or reset accordingly if equityClosePrice > currentEquitySMA: self.countDaysEquityAboveSMA += 1 self.countDaysEquityBelowSMA = 0 else: self.countDaysEquityBelowSMA += 1 self.countDaysEquityAboveSMA = 0 self.newSignal = False # equity position: we can get here from any other position if self.countDaysEquityAboveSMA == self.daysConsecutivePriceAboveSMA and self.signal != 1: # get allocations allocationEquity = self.allocationStepOne[0] allocationSafe = self.allocationStepOne[1] self.signal = 1 self.newSignal = True # reset counts self.countDaysEquityAboveSMA = 0 self.countDaysEquityBelowSMA = 0 # mix position: we can get here only from the equity position elif self.countDaysEquityBelowSMA == self.daysConsecutivePriceBelowSMA and self.signal != 2 and self.signal != 3: # get allocations allocationEquity = self.allocationStepTwo[0] allocationSafe = self.allocationStepTwo[1] self.signal = 2 self.newSignal = True # reset counts self.countDaysEquityAboveSMA = 0 self.countDaysEquityBelowSMA = 0 # safe position: we can get here from any other position elif currentEquitySMA < self.winEquitySMA[self.daysAgoLowerSMA-1] and self.signal != 3: # get allocations allocationEquity = self.allocationStepThree[0] allocationSafe = self.allocationStepThree[1] self.signal = 3 self.newSignal = True # simulate buy and hold the benchmark and plot its daily value UpdateBenchmarkValue(self) self.Plot('Strategy Equity', self.benchmarkTicker, self.benchmarkValue) # set holdings if self.newSignal: self.SetHoldings([PortfolioTarget(self.equitySymbol, allocationEquity), PortfolioTarget(self.safeSymbol, allocationSafe)]) # update plots UpdatePlots(self, currentEquitySMA, equityClosePrice) # update the rolling window self.winEquitySMA.Add(currentEquitySMA) def OnOrderEvent(self, orderEvent): ''' Event triggered every time there is a new order event ''' ticket = self.Transactions.GetOrderTicket(orderEvent.OrderId)