Overall Statistics
Total Trades
110
Average Win
1.29%
Average Loss
-0.53%
Compounding Annual Return
9.621%
Drawdown
30.200%
Expectancy
2.109
Net Profit
248.494%
Sharpe Ratio
0.981
Probabilistic Sharpe Ratio
40.557%
Loss Rate
9%
Win Rate
91%
Profit-Loss Ratio
2.43
Alpha
0.056
Beta
0.432
Annual Standard Deviation
0.104
Annual Variance
0.011
Information Ratio
-0.046
Tracking Error
0.129
Treynor Ratio
0.237
Total Fees
$281.00
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):
    
    # simulate buy and hold the benchmark and plot its daily value
    UpdateBenchmarkValue(self)
    self.Plot('Strategy Equity', self.benchmarkTicker, self.benchmarkValue)
    
    # plot portfolio exposures
    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)
from HelperFunctions import *
from System.Drawing import Color
import pandas as pd

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)
        
        # TICKERS ----------------------------------------------------------------------------------
        self.equityTicker = 'SPY' # equity like asset
        self.safeTicker = 'TLT' # cash/bond like asset
        
        self.benchmarkTicker = 'SPY' # select a benchmark
        
        # ALLOCATIONS ------------------------------------------------------------------
        
        # allocations = [equityTicker allocation, safeTicker allocation]
        self.allocations = [0.6, 0.4]
        
        # rebalancing (options are monthly/quarterly)
        self.rebalancingPeriod = 'quarterly'

        ### -----------------------------------------------------------------------------------------------------------------------
             
        # 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
        self.initBenchmarkPrice = 0
        self.previousPeriod = 0
        
        # initialize plots
        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
        
        # update plots
        UpdatePlots(self)
        
        # rebalancing
        if self.rebalancingPeriod == 'monthly':
            currentPeriod = self.Time.month
        elif self.rebalancingPeriod == 'quarterly':
            currentPeriod = pd.Timestamp(self.Time.date()).quarter
        else:
            raise ValueError('self.rebalancingPeriod must be either monthly or quarterly')
            
        if currentPeriod != self.previousPeriod:
            if (data.ContainsKey(self.equitySymbol) and data.ContainsKey(self.safeSymbol)
            and self.ActiveSecurities[self.equitySymbol].Price > 0
            and self.ActiveSecurities[self.safeSymbol].Price > 0):
                # set holdings
                allocationEquity = self.allocations[0]
                allocationSafe = self.allocations[1]
                self.SetHoldings([PortfolioTarget(self.equitySymbol, allocationEquity),
                                    PortfolioTarget(self.safeSymbol, allocationSafe)])
                                    
            self.previousPeriod = currentPeriod