| Overall Statistics |
|
Total Trades 0 Average Win 0% Average Loss 0% Compounding Annual Return 0% Drawdown 0% Expectancy 0 Net Profit 0% Sharpe Ratio 0 Probabilistic Sharpe Ratio 0% Loss Rate 0% Win Rate 0% Profit-Loss Ratio 0 Alpha 0 Beta 0 Annual Standard Deviation 0 Annual Variance 0 Information Ratio -0.47 Tracking Error 0.16 Treynor Ratio 0 Total Fees $0.00 Estimated Strategy Capacity $0 Lowest Capacity Asset |
#Rising Assets Strategy Rules
#1. On the last business day of every month, invest in the top 5 assets with the highest
#momentum score.
#2. Sell any asset that was previously in the top 5 but has since dropped out.
#3. Weight each asset by the inverse of its 63-day historical volatility.
#Momentum Score
#Our momentum score is the average of the last 1mo, 3mo, 6mo and 12mo trailing total
#returns.
#We opt for an unoptimized average of lookbacks. This is consistent with the method
#Momentum Score Example:SPY 1 Month Return = +2.0%
#SPY 3 Month Return = -4.0%
#SPY 6 Month Return = +11.0%
#SPY 12 Month Return = +8.0%
#Average Return = (2% - 4% + 11% + 8%) / 4 = 4.25%
#Result is a Momentum Score of 4.25%
#Inverse Volatility Asset Weights
#Asset weights are equivalent to the inverse of each asset’s trailing 3-month (63 trading
#days) historical volatility. Volatility here is measured by the standard deviation of each
#ETF’s daily returns.
#This step serves to increase diversification in the portfolio as inverse weighting every
#asset avoids one volatile asset from dominating the portfolio.
#The typical effect of this step, compared to equal weighting the assets, is a slight decrease in
#returns but a larger decrease in risk. This increases the return / risk metrics such as the
#Sharpe Ratio.
#Inverse Volatility Example:
#SPY Std Dev = 0.10
#EEM Std Dev = 0.20
#Take 1 divided by each Std Dev observations and sum the results:
#SPY 1 / 0.10 = 10
#EEM 1 / 0.20 = 5
#10 + 5 = 15
#Divide each by the sum to get percent capital allocation:
#SPY 10 / 15 = 0.666
#EEM 5 / 15 = 0.333
#Result is a 66.6% allocation to SPY and a 33.3% allocation to EEM
#region imports
from AlgorithmImports import *
#endregion
from math import ceil,floor
from datetime import datetime
import pandas as pd
import numpy as np
from sklearn.linear_model import LinearRegression
class TrendFollowingAlgorithm(QCAlgorithm):
def Initialize(self):
self.SetStartDate(2004, 11, 1)
self.SetEndDate(datetime.now())
self.SetCash(100000)
self.AddEquity("SPY", Resolution.Daily)
self.SymbolData = []
self.LastRotationTime = datetime.min
self.RotationInterval = timedelta(days=30)
self.first = True
etfs = [
# Equity
'SPY', # S&P 500
'IWM', # US Small cap
'QQQ', # NASDAQ
'EFA', #Developed Ex US
'EEM', #Emerging markets
'VNQ', #US RealEstate
'LQD', #US Inv. Grade Crops
# Fixed incomet
'GLD', # Treasury Bond
'SHY', # High yield bond
'IEF', #
'TLT', #
'AGG'
]
self.SymbolData = []
for symbol in etfs:
self.AddSecurity(SecurityType.Equity, symbol, Resolution.Minute)
self.oneMonthPerformance = self.MOMP(symbol, 30, Resolution.Daily)
self.threeMonthPerformance = self.MOMP(symbol, 90, Resolution.Daily)
self.sixMonthPerformance = self.MOMP(symbol, 180, Resolution.Daily)
self.twelveMonthPerformance = self.MOMP(symbol, 365, Resolution.Daily)
self.SymbolData.append([symbol, self.oneMonthPerformance, self.threeMonthPerformance, self.sixMonthPerformance, self.twelveMonthPerformance])
self.SetBenchmark("SPY")
# perform calculations for asset weightings
def OnData(self, data):
if self.first:
self.first = False
self.LastRotationTime = self.Time
return
delta = self.Time - self.LastRotationTime
if delta > self.RotationInterval:
self.LastRotationTime = self.Time
momentumObjScores = sorted(self.SymbolData, key=lambda x: MomentumScore(x[1].Current.Value,x[2].Current.Value,x[3].Current.Value,x[4].Current.Value).CalculateMomentumScore(), reverse=True)
for x in momentumObjScores:
self.Log(">>SCORE>>" + x[0] + ">>" + str(MomentumScore(x[1].Current.Value,x[2].Current.Value,x[3].Current.Value,x[4].Current.Value).CalculateMomentumScore()))
class MomentumScore(object):
def __init__(self,oneMonthPerformanceValue,threeMonthPerformanceValue, sixMonthPerformanceValue, twelveMonthPerformanceValue):
self.oneMonthPerformance = oneMonthPerformanceValue
self.threeMonthPerformance = threeMonthPerformanceValue
self.sixMonthPerformance = sixMonthPerformanceValue
self.twelveMonthPerformance = twelveMonthPerformanceValue
def CalculateMomentumScore(self):
weight = 4
return (self.oneMonthPerformance + self.threeMonthPerformance + self.sixMonthPerformance + self.twelveMonthPerformance) / (weight)