Overall Statistics
Total Trades
343
Average Win
6.49%
Average Loss
-2.48%
Compounding Annual Return
16.856%
Drawdown
45.300%
Expectancy
1.199
Net Profit
6915.539%
Sharpe Ratio
0.759
Probabilistic Sharpe Ratio
3.788%
Loss Rate
39%
Win Rate
61%
Profit-Loss Ratio
2.62
Alpha
0.093
Beta
0.596
Annual Standard Deviation
0.171
Annual Variance
0.029
Information Ratio
0.425
Tracking Error
0.158
Treynor Ratio
0.218
Total Fees
$625.00
Estimated Strategy Capacity
$0
Lowest Capacity Asset
QQQ.QQQ 2S
# Import packages
import numpy as np
import pandas as pd
import scipy as sc
from scipy import stats

class AccelDualMomentumInOut(QCAlgorithm):
    def Initialize(self):
        
        self.SetStartDate(1995, 1, 1)  # Set Start Date
        #self.SetEndDate(2022,2,28)  # Set End Date
        self.SetCash(10000)  # Set Strategy Cash
   
        #self.aVFINX = self.AddData(VFINX, "VFINX", Resolution.Daily).Symbol
        self.aQQQ = self.AddData(QQQ, "QQQ", Resolution.Daily).Symbol

        self.aVINEX = self.AddData(VINEX, "VINEX", Resolution.Daily).Symbol
        self.aVUSTX = self.AddData(VUSTX, "VUSTX", Resolution.Daily).Symbol
        self.aVBILX = self.AddData(VBILX, "VBILX", Resolution.Daily).Symbol
        self.aRYURX = self.AddData(RYURX, "RYURX", Resolution.Daily).Symbol

        self.aLBMA = self.AddData(LBMA, "LBMA", Resolution.Daily).Symbol
        #self.aGLD = self.AddData(GLD, "GLD", Resolution.Daily).Symbol
        self.aVIPSX = self.AddData(VIPSX, "VIPSX", Resolution.Daily).Symbol
        self.aCASH = self.AddData(CASH, "CASH", Resolution.Daily).Symbol
        self.indicator = self.AddData(MOMENTUM, "MOMENTUM", Resolution.Daily).Symbol
        
        self.leverage = 1   # Set leverage | A value of 1 indicates no leverage | A value of 2 indicates 100% leverage
        #self.Securities["VFINX"].SetLeverage(self.leverage)
        self.Securities["QQQ"].SetLeverage(self.leverage)
        self.Securities["VINEX"].SetLeverage(self.leverage)
        self.Securities["VUSTX"].SetLeverage(self.leverage)
        self.Securities["LBMA"].SetLeverage(self.leverage)
        #self.Securities["GLD"].SetLeverage(self.leverage)
        self.Securities["VIPSX"].SetLeverage(self.leverage)
        self.Securities["CASH"].SetLeverage(self.leverage)
        self.Securities["VBILX"].SetLeverage(self.leverage)
        self.Securities["RYURX"].SetLeverage(self.leverage)
        
        self.basket_out = ['VUSTX', 'VBILX', 'RYURX']

        
        # Set trading frequency
        
        self.monthly = 1 
        self.annual = 0
        self.daily = 0

        self.trading_fee = 5  # Fee per trade
        
        self.trading_day = 21 # Set trading day | Value = 21 is last trading day of month
        self.GetParameter("trading_day") 
        
    def shiftAssets(self, target):
        if not (self.Portfolio[target].Invested):
            for symbol in self.Portfolio.Keys:
                self.Liquidate(symbol)
            if not self.Portfolio.Invested:
                self.SetHoldings(target, 1*self.leverage)
    
    def getMonthTradingDay(self):
        month_last_day = DateTime(self.Time.year, self.Time.month, DateTime.DaysInMonth(self.Time.year, self.Time.month))
        tradingDays = self.TradingCalendar.GetDaysByType(TradingDayType.BusinessDay, DateTime(self.Time.year, self.Time.month, 1), month_last_day)
        tradingDays = [day.Date.date() for day in tradingDays]
        return tradingDays[-22 + self.trading_day]
        
    def getYearLastTradingDay(self):
        year_last_day = DateTime(self.Time.year, 12, DateTime.DaysInMonth(self.Time.year, 12))
        tradingDays = self.TradingCalendar.GetDaysByType(TradingDayType.BusinessDay, DateTime(self.Time.year, 12, 1), year_last_day)
        tradingDays = [day.Date.date() for day in tradingDays]
        return tradingDays [-1]
        
        
    def OnData(self, data):
    
    
        if (self.daily ==1):
            if data.ContainsKey(self.indicator):
                ticker = data[self.indicator].GetProperty('Indicator')
                if (ticker =="VINEX"):
                        #self.Securities["VINEX"].SetFeeModel(MonthlyCustomFeeModel())
                        self.shiftAssets(self.aVINEX)
                elif (ticker =="QQQ"):
                        #self.Securities["QQQ"].SetFeeModel(MonthlyCustomFeeModel())
                    self.shiftAssets(self.aQQQ)
                elif (ticker =="VUSTX"):
                        #self.Securities["VUSTX"].SetFeeModel(MonthlyCustomFeeModel())
                    self.Liquidate()
                    dataframe = self.History(self.basket_out, 180, Resolution.Daily)
                    df = dataframe['close'].unstack(level=0)
                    self.adaptive_asset_allocation(df, 3, 40, 90, self.Portfolio.Cash, 1)
                    
                    #self.shiftAssets(self.aVUSTX)
                elif (ticker =="LBMA"):
                        #self.Securities["LBMA"].SetFeeModel(MonthlyCustomFeeModel())
                    self.shiftAssets(self.aLBMA)
                elif (ticker =="VIPSX"):
                        #self.Securities["VIPSX"].SetFeeModel(MonthlyCustomFeeModel())
                    self.shiftAssets(self.aVIPSX)
                elif (ticker =="CASH"):
                    #self.Securities["CASH"].SetFeeModel(MonthlyCustomFeeModel())
                    self.Liquidate()
                    dataframe = self.History(self.basket_out, 180, Resolution.Daily)
                    df = dataframe['close'].unstack(level=0)
                    self.adaptive_asset_allocation(df, 3, 40, 90, self.Portfolio.Cash, 1)

                    #self.shiftAssets(self.aCASH)
                elif (ticker =="GLD"):
                        #self.Securities["GLD"].SetFeeModel(MonthlyCustomFeeModel())
                    self.shiftAssets(self.aGLD)
        
        
        if (self.monthly ==1):
            if (self.Time.date() == self.getMonthTradingDay()):
                if data.ContainsKey(self.indicator):
                    ticker = data[self.indicator].GetProperty('Indicator')
                    if (ticker =="VINEX"):
                        self.Securities["VINEX"].SetFeeModel(MonthlyCustomFeeModel())
                        self.shiftAssets(self.aVINEX)
                    elif (ticker =="QQQ"):
                        self.Securities["QQQ"].SetFeeModel(MonthlyCustomFeeModel())
                        self.shiftAssets(self.aQQQ)
                    elif (ticker =="VUSTX"):
                        #self.Securities["VUSTX"].SetFeeModel(MonthlyCustomFeeModel())
                        self.Liquidate()
                        dataframe = self.History(self.basket_out, 180, Resolution.Daily)
                        df = dataframe['close'].unstack(level=0)
                        self.adaptive_asset_allocation(df, 3, 40, 90, self.Portfolio.Cash, 1)
                        
                    elif (ticker =="LBMA"):
                        self.Securities["LBMA"].SetFeeModel(MonthlyCustomFeeModel())
                        self.shiftAssets(self.aLBMA)
                    elif (ticker =="VIPSX"):
                        self.Securities["VIPSX"].SetFeeModel(MonthlyCustomFeeModel())
                        self.shiftAssets(self.aVIPSX)
                    elif (ticker =="CASH"):
                    #self.Securities["CASH"].SetFeeModel(MonthlyCustomFeeModel())
                        self.Liquidate()
                        dataframe = self.History(self.basket_out, 180, Resolution.Daily)
                        df = dataframe['close'].unstack(level=0)
                        self.adaptive_asset_allocation(df, 3, 40, 90, self.Portfolio.Cash, 1)

                    elif (ticker =="GLD"):
                        self.Securities["GLD"].SetFeeModel(MonthlyCustomFeeModel())
                        self.shiftAssets(self.aGLD)
                        
        if (self.annual ==1):
            if (self.Time.date() == self.getYearLastTradingDay()):
                if data.ContainsKey(self.indicator):
                    ticker = data[self.indicator].GetProperty('Indicator')
                    if (ticker =="VINEX"):
                        self.Securities["VINEX"].FeeModel = ConstantFeeModel(self.trading_fee)
                        self.shiftAssets(self.aVINEX)
                    elif (ticker =="QQQ"):
                        self.Securities["QQQ"].FeeModel = ConstantFeeModel(self.trading_fee)
                        self.shiftAssets(self.aQQQ)
                    elif (ticker =="VUSTX"):
                        self.Securities["VUSTX"].FeeModel = ConstantFeeModel(self.trading_fee)
                        self.shiftAssets(self.aVUSTX)
                    elif (ticker =="LBMA"):
                        self.Securities["LBMA"].FeeModel = ConstantFeeModel(self.trading_fee)
                        self.shiftAssets(self.aLBMA)
                    elif (ticker =="VIPSX"):
                        self.Securities["VIPSX"].FeeModel = ConstantFeeModel(self.trading_fee)
                        self.shiftAssets(self.aVIPSX)
                    elif (ticker =="CASH"):
                        self.Securities["CASH"].FeeModel = ConstantFeeModel(self.trading_fee)
                        self.shiftAssets(self.aCASH)
                    elif (ticker =="GLD"):
                        self.Securities["GLD"].FeeModel = ConstantFeeModel(self.trading_fee)
                        self.shiftAssets(self.aGLD)
                    
        # Charts
                
        self.Plot("Margin", "Remaining", self.Portfolio.MarginRemaining)
        self.Plot("Margin", "Used", self.Portfolio.TotalMarginUsed)
        self.Plot("Cash", "Remaining", self.Portfolio.Cash)
        self.Plot("Cash", "Remaining", self.Portfolio.TotalHoldingsValue)
        
        #self.Plot("VFINX", "Held", self.Portfolio["VFINX"].Quantity)
        self.Plot("VINEX", "Held", self.Portfolio["VINEX"].Quantity)
        self.Plot("VUSTX", "Held", self.Portfolio["VUSTX"].Quantity)
        self.Plot("VIPSX", "Held", self.Portfolio["VIPSX"].Quantity)
        #self.Plot("GLD", "Held", self.Portfolio["GLD"].Quantity)
        self.Plot("CASH", "Held", self.Portfolio["CASH"].Quantity)
        self.Plot("LBMA", "Held", self.Portfolio["LBMA"].Quantity)

    def adaptive_asset_allocation(self, df, nlargest, volatility_window, return_window, portfolio_value, leverage): 
        window_returns = np.log(df.iloc[-1]) - np.log(df.iloc[0])
        nlargest = list(window_returns.nlargest(nlargest).index)
        
        returns = df[nlargest].pct_change()
        returns_cov_normalized = returns[-volatility_window:].apply(lambda x: np.log(1+x)).cov()
        returns_corr_normalized = returns[-volatility_window:].apply(lambda x: np.log(1+x)).corr()
        returns_std = returns.apply(lambda x: np.log(1+x)).std()
        
        port_returns = []
        port_volatility = []
        port_weights = []
    
        num_assets = len(returns.columns)
        num_portfolios = 100
        individual_rets = window_returns[nlargest]
        
        for port in range(num_portfolios): 
            weights = np.random.random(num_assets)
            weights = weights/np.sum(weights)
            port_weights.append(weights)
    
            rets = np.dot(weights, individual_rets)
            port_returns.append(rets)
    
            var = returns_cov_normalized.mul(weights, axis=0).mul(weights, axis=1).sum().sum()
            sd = np.sqrt(var)
            ann_sd = sd * np.sqrt(256)
            port_volatility.append(ann_sd)
            
        data = {'Returns': port_returns, 'Volatility': port_volatility}
        hover_data = []
        for counter, symbol in enumerate(nlargest): 
            data[symbol] = [w[counter] for w in port_weights]
            hover_data.append(symbol)
    
        portfolios_V1 = pd.DataFrame(data)
        
        min_var_portfolio = portfolios_V1.iloc[portfolios_V1['Volatility'].idxmin()]
        max_sharpe_portfolio = portfolios_V1.iloc[(portfolios_V1['Returns'] / portfolios_V1['Volatility']).idxmax()]
        proportions = min_var_portfolio[nlargest] 
        
        index = 0
        for proportion in proportions: 
            self.SetHoldings(nlargest[index], proportion * leverage)
            self.Debug('{}% of portfolio in {}'.format(proportion * leverage, nlargest[index]))
            index += 1
        
class LBMA(PythonData):
    def GetSource(self, config, date, isLiveMode):
        return SubscriptionDataSource("https://www.dropbox.com/s/81ixmlr8cx1uxgq/LBMA.csv?dl=1", SubscriptionTransportMedium.RemoteFile)
        
    def Reader(self, config, line, date, isLive):
        if not (line.strip() and line[0].isdigit()): 
            return None
        
        index = LBMA()
        index.Symbol = config.Symbol
        
        data = line.split(',')
        index.Time = datetime.strptime(data[0], "%d/%m/%Y")
        index.EndTime = index.Time + timedelta(days=1)
        index.Value = data[1]
        index["LBMA"] = float(data[1])
        
        return index

class VIPSX(PythonData):
    def GetSource(self, config, date, isLiveMode):
        return SubscriptionDataSource("https://www.dropbox.com/s/51npkwxesct345x/VIPSX.csv?dl=1", SubscriptionTransportMedium.RemoteFile)
    def Reader(self, config, line, date, isLive):
        
        if not (line.strip() and line[0].isdigit()): 
            return None
        
        index = VIPSX()
        index.Symbol = config.Symbol
        data = line.split(',')
        index.Time = datetime.strptime(data[0], "%d/%m/%Y")
        index.EndTime = index.Time + timedelta(days=1)
        index.Value = data[4]
        index["Open"] = float(data[1])
        index["High"] = float(data[2])
        index["Low"] = float(data[3])
        index["Close"] = float(data[4])

        return index 
        
class VUSTX(PythonData):
    def GetSource(self, config, date, isLiveMode):
        return SubscriptionDataSource("https://www.dropbox.com/s/hnv2swusm9wra5w/VUSTX.csv?dl=1", SubscriptionTransportMedium.RemoteFile)
    def Reader(self, config, line, date, isLive):
        
        if not (line.strip() and line[0].isdigit()): 
            return None
        
        index = VUSTX()
        index.Symbol = config.Symbol
        data = line.split(',')
        index.Time = datetime.strptime(data[0], "%d/%m/%Y")
        index.EndTime = index.Time + timedelta(days=1)
        index.Value = data[4]
        index["Open"] = float(data[1])
        index["High"] = float(data[2])
        index["Low"] = float(data[3])
        index["Close"] = float(data[4])
        
        return index
        
class VFINX(PythonData):
    def GetSource(self, config, date, isLiveMode):
        return SubscriptionDataSource("https://www.dropbox.com/s/zzh0ydo8t8l5ds4/VFINX.csv?dl=1", SubscriptionTransportMedium.RemoteFile)
    def Reader(self, config, line, date, isLive):
        
        if not (line.strip() and line[0].isdigit()): 
            return None
        
        index = VFINX()
        index.Symbol = config.Symbol
        data = line.split(',')
        index.Time = datetime.strptime(data[0], "%d/%m/%Y")
        index.EndTime = index.Time + timedelta(days=1)
        index.Value = data[4]
        index["Open"] = float(data[1])
        index["High"] = float(data[2])
        index["Low"] = float(data[3])
        index["Close"] = float(data[4])
        
        return index
        
class VINEX(PythonData):
    def GetSource(self, config, date, isLiveMode):
        return SubscriptionDataSource("https://www.dropbox.com/s/3otgob32pyl0hz8/VINEX.csv?dl=1", SubscriptionTransportMedium.RemoteFile)
    def Reader(self, config, line, date, isLive):
        
        if not (line.strip() and line[0].isdigit()): 
            return None
        
        index = VINEX()
        index.Symbol = config.Symbol
        data = line.split(',')
        index.Time = datetime.strptime(data[0], "%d/%m/%Y")
        index.EndTime = index.Time + timedelta(days=1)
        index.Value = data[4]
        index["Open"] = float(data[1])
        index["High"] = float(data[2])
        index["Low"] = float(data[3])
        index["Close"] = float(data[4])
        
        return index
        
class GLD(PythonData):
    def GetSource(self, config, date, isLiveMode):
        return SubscriptionDataSource("https://www.dropbox.com/s/c9asn799ugf8kja/GLD.csv?dl=1", SubscriptionTransportMedium.RemoteFile)
    def Reader(self, config, line, date, isLive):
        
        if not (line.strip() and line[0].isdigit()): 
            return None
        
        index = GLD()
        index.Symbol = config.Symbol
        data = line.split(',')
        index.Time = datetime.strptime(data[0], "%d/%m/%Y")
        index.EndTime = index.Time + timedelta(days=1)
        index.Value = data[4]
        index["Open"] = float(data[1])
        index["High"] = float(data[2])
        index["Low"] = float(data[3])
        index["Close"] = float(data[4])
        
        return index
        
class CASH(PythonData):
    def GetSource(self, config, date, isLiveMode):
        return SubscriptionDataSource("https://www.dropbox.com/s/496wpuy5qrlq9za/CASH.csv?dl=1", SubscriptionTransportMedium.RemoteFile)
    def Reader(self, config, line, date, isLive):
        
        if not (line.strip() and line[0].isdigit()): 
            return None
        
        index = CASH()
        index.Symbol = config.Symbol
        data = line.split(',')
        index.Time = datetime.strptime(data[0], "%d/%m/%Y")
        index.EndTime = index.Time + timedelta(days=1)
        index.Value = data[1] 
        index["Close"] = float(data[1])
        
        return index
        
class QQQ(PythonData):
    def GetSource(self, config, date, isLiveMode):
        return SubscriptionDataSource("https://www.dropbox.com/s/53tqrfh84h7h1ax/QQQ.csv?dl=1", SubscriptionTransportMedium.RemoteFile)
    def Reader(self, config, line, date, isLive):
        
        if not (line.strip() and line[0].isdigit()): 
            return None
        
        index = QQQ()
        index.Symbol = config.Symbol
        data = line.split(',')
        index.Time = datetime.strptime(data[0], "%Y-%m-%d")
        index.EndTime = index.Time + timedelta(days=1)
        index.Value = data[1]
        index["Close"] = float(data[1])

        
        return index
        
class VBILX(PythonData):
    def GetSource(self, config, date, isLiveMode):
        return SubscriptionDataSource("https://www.dropbox.com/s/sqlkx4q3w14dt90/VBILX.csv?dl=1", SubscriptionTransportMedium.RemoteFile)
    def Reader(self, config, line, date, isLive):
        
        if not (line.strip() and line[0].isdigit()): 
            return None
        
        index = VBILX()
        index.Symbol = config.Symbol
        data = line.split(',')
        index.Time = datetime.strptime(data[0], "%Y-%m-%d")
        index.EndTime = index.Time + timedelta(days=1)
        index.Value = data[5]
        index["Open"] = float(data[1])
        index["High"] = float(data[2])
        index["Low"] = float(data[3])
        index["Close"] = float(data[4])
        index["Adj Close"] = float(data[5])

        
        return index
        
class RYURX(PythonData):
    def GetSource(self, config, date, isLiveMode):
        return SubscriptionDataSource("https://www.dropbox.com/s/rtzx03fzejd36ok/RYURX.csv?dl=1", SubscriptionTransportMedium.RemoteFile)
    def Reader(self, config, line, date, isLive):
        
        if not (line.strip() and line[0].isdigit()): 
            return None
        
        index = RYURX()
        index.Symbol = config.Symbol
        data = line.split(',')
        index.Time = datetime.strptime(data[0], "%Y-%m-%d")
        index.EndTime = index.Time + timedelta(days=1)
        index.Value = data[5]
        index["Open"] = float(data[1])
        index["High"] = float(data[2])
        index["Low"] = float(data[3])
        index["Close"] = float(data[4])
        index["Adj Close"] = float(data[5])

        
        return index
        
class MOMENTUM(PythonData):
    def GetSource(self, config, date, isLiveMode):
        return SubscriptionDataSource("https://www.dropbox.com/s/t62ha5ynf3n4gge/Indicator_VFISX_FCYIX.csv?dl=1", SubscriptionTransportMedium.RemoteFile)
    def Reader(self, config, line, date, isLive):
        
        if not (line.strip() and line[0].isdigit()): 
            return None
        
        index = MOMENTUM()
        index.Symbol = config.Symbol
        data = line.split(',')
        index.Time = datetime.strptime(data[0], "%Y-%m-%d")
        index.EndTime = index.Time + timedelta(days=1)
        index.SetProperty("Indicator", str(data[1]))
        
        return index
        
class MonthlyCustomFeeModel:
    def GetOrderFee(self, parameters):
        self.margin_rate = 0.015  #Set Margin Fee
        self.trading_fee = 5    #Set fee per trade
        fee = self.trading_fee + (parameters.Security.Leverage-1)*parameters.Security.Price*parameters.Order.AbsoluteQuantity*(self.margin_rate/12)
        return OrderFee(CashAmount(fee, 'USD'))