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)