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)