Overall Statistics
Total Orders
894
Average Win
0.63%
Average Loss
-1.32%
Compounding Annual Return
6.003%
Drawdown
29.400%
Expectancy
0.233
Start Equity
100000
End Equity
415683.38
Net Profit
315.683%
Sharpe Ratio
0.242
Sortino Ratio
0.237
Probabilistic Sharpe Ratio
0.048%
Loss Rate
16%
Win Rate
84%
Profit-Loss Ratio
0.48
Alpha
0.013
Beta
0.304
Annual Standard Deviation
0.104
Annual Variance
0.011
Information Ratio
-0.114
Tracking Error
0.144
Treynor Ratio
0.083
Total Fees
$3083.72
Estimated Strategy Capacity
$860000.00
Lowest Capacity Asset
GSG TKH7EPK7SRC5
Portfolio Turnover
1.10%
# https://quantpedia.com/strategies/asset-class-trend-following/
#
# Use 5 ETFs (SPY - US stocks, EFA - foreign stocks, IEF - bonds, VNQ - REITs, 
# GSG - commodities), equal weight the portfolio. Hold asset class ETF only when 
# it is over its 10 month Simple Moving Average, otherwise stay in cash.
#
# QC implementation changes:
#   - SMA with period of 210 days is used.

#region imports
from AlgorithmImports import *
#endregion

class AssetClassTrendFollowing(QCAlgorithm):

    def Initialize(self):
        self.SetStartDate(2000, 1, 1)
        self.SetCash(100000)
        
        tickers: List[str] = ["SPY", "EFA", "IEF", "VNQ", "GSG"]
        period: int = 10 * 21

        self.sma: Dict[Symbol, SimpleMovingAverage] = { 
            self.AddEquity(ticker, Resolution.Minute).Symbol : self.SMA(ticker, period, Resolution.Daily) for ticker in tickers 
        }

        self.recent_month: int = -1
        self.SetWarmUp(period, Resolution.Daily)
        self.Settings.MinimumOrderMarginPortfolioPercentage = 0.
    
    def OnData(self, data: Slice) -> None:
        if self.IsWarmingUp: return

        if not (self.Time.hour == 9 and self.Time.minute == 31):
            return

        # rebalance once a month
        if self.Time.month == self.recent_month:
            return
        self.recent_month = self.Time.month
        
        long: List[Symbol] = [ symbol for symbol, sma in self.sma.items() 
            if symbol in data 
            and data[symbol] 
            and sma.IsReady 
            and data[symbol].Value > sma.Current.Value
        ]

        portfolio: List[PortfolioTarget] = [PortfolioTarget(symbol, 1. / len(long)) for symbol in long]
        self.SetHoldings(portfolio, True)