| Overall Statistics |
|
Total Trades 268 Average Win 0.10% Average Loss -0.12% Compounding Annual Return 3.942% Drawdown 47.400% Expectancy 0.087 Net Profit 21.346% Sharpe Ratio 0.298 Probabilistic Sharpe Ratio 5.678% Loss Rate 41% Win Rate 59% Profit-Loss Ratio 0.83 Alpha 0.025 Beta 0.756 Annual Standard Deviation 0.212 Annual Variance 0.045 Information Ratio 0.121 Tracking Error 0.107 Treynor Ratio 0.084 Total Fees $274.90 |
from clr import AddReference
AddReference("QuantConnect.Common")
AddReference("QuantConnect.Algorithm")
AddReference("QuantConnect.Algorithm.Framework")
AddReference("QuantConnect.Indicators")
from QuantConnect import *
from QuantConnect.Indicators import *
from QuantConnect.Algorithm import *
from QuantConnect.Algorithm.Framework import *
from QuantConnect.Algorithm.Framework.Alphas import *
class SmaAlphaModel(AlphaModel):
'''Alpha model that uses an EMA cross to create insights'''
def __init__(self, smaLength = 200, resolution = Resolution.Daily, predictionInterval = 31):
'''Initializes a new instance of the SmaAlphaModel class
Args:
period: The SMA period
resolution: The reolution for the SMA'''
self.smaLength = smaLength
self.resolution = resolution
self.predictionInterval = predictionInterval
self.symbolDataBySymbol = {}
def Update(self, algorithm, data):
'''This is called each time the algorithm receives data for (@resolution of) subscribed securities
Returns:
The new insights generated'''
insights = []
for symbol, symbolData in self.symbolDataBySymbol.items():
insights.append(Insight.Price(symbolData.Symbol, timedelta(days=self.predictionInterval), InsightDirection.Up))
return insights
def OnSecuritiesChanged(self, algorithm, changes):
'''Event fired each time the we add/remove securities from the data feed
Args:
algorithm: The algorithm instance that experienced the change in securities
changes: The security additions and removals from the algorithm'''
for added in changes.AddedSecurities:
# Get historical data & check for existence in symbolData
history = algorithm.History([added.Symbol], self.smaLength, self.resolution)
symbolData = self.symbolDataBySymbol.get(added.Symbol)
if symbolData is None:
# Create an instance, initialise Indicator, pump in history
symbolData = SymbolData(added)
symbolData.MovingAverage = algorithm.SMA(added.Symbol, self.smaLength, self.resolution)
for time, row in history.loc[added.Symbol].iterrows():
symbolData.MovingAverage.Update(time, row["close"])
self.symbolDataBySymbol[added.Symbol] = symbolData
else:
# The security existed: reset indicators, restore history
symbolData.MovingAverage.Reset()
for time, row in history.loc[added.Symbol].iterrows():
symbolData.MovingAverage.Update(time, row["close"])
# TODO: has not been added to self.symbolDataBySymbol!
class SymbolData:
'''Contains data specific to a symbol required by this model'''
def __init__(self, security):
self.Security = security
self.Symbol = security.Symbol
self.MovingAverage = None'''An implementation of Meb Faber's base model: Global Tactical Asset Allocation model (GTAA)(5)
Buy&Hold portfolio (monthly rebalance), as found in the paper:
"A Quantitative Approach to Tactical Asset Allocation" published May 2006.
'''
from SmaAlphaModel import *
class GlobalTacticalAssetAllocationBase(QCAlgorithm):
def Initialize(self):
backtestDuration = 365*10
self.SetStartDate(2008, 1, 1) # (datetime.now() - timedelta(backtestDuration))
self.SetEndDate(2013,1,1) # (datetime.now())
self.SetCash(100000)
self.SetBrokerageModel(BrokerageName.InteractiveBrokersBrokerage, AccountType.Margin)
self.UniverseSettings.Resolution = Resolution.Minute
symbols = [Symbol.Create(ticker, SecurityType.Equity, Market.USA)
for ticker in [ "SPY", # US Large Cap ETF
"VEA", # Developed Foreign Stocks (TradedSince: 2007/8)ETF
"IEF", # US 10Y Gov.Bonds ETF
"DBC", # GSCI Commodities ETF (TradedSince: 2006/3)
"VNQ" # US RealEstate ETF
]]
self.AddUniverseSelection(ManualUniverseSelectionModel(symbols))
# self.AddAlpha( SmaAlphaModel() )
self.AddAlpha(ConstantAlphaModel(InsightType.Price, InsightDirection.Up, timedelta(days = backtestDuration), None, None))
self.Settings.RebalancePortfolioOnInsightChanges = False
self.Settings.RebalancePortfolioOnSecurityChanges = False
self.SetPortfolioConstruction( EqualWeightingPortfolioConstructionModel(self.DateRules.MonthEnd("SPY")) )
self.SetExecution( ImmediateExecutionModel() )
self.AddRiskManagement( NullRiskManagementModel() )
# 1) Setting a Benchmark to plot with equity
self.benchmarkTicker = 'SPY'
self.SetBenchmark(self.benchmarkTicker)
self.initBenchmarkPrice = None
def UpdateBenchmarkValue(self):
''' Simulate buy and hold the Benchmark '''
if self.initBenchmarkPrice is None:
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 OnData(self, data):
# 2) simulate buy and hold the benchmark and plot its daily value as we are using daily data.
# Otherwise schedule when to call this function!
self.UpdateBenchmarkValue()
self.Plot('Strategy Equity', self.benchmarkTicker, self.benchmarkValue)