| Overall Statistics |
|
Total Trades 1020 Average Win 0.85% Average Loss -0.60% Compounding Annual Return -7.260% Drawdown 52.400% Expectancy -0.071 Net Profit -32.172% Sharpe Ratio -0.261 Probabilistic Sharpe Ratio 0.082% Loss Rate 61% Win Rate 39% Profit-Loss Ratio 1.40 Alpha -0.047 Beta 0.009 Annual Standard Deviation 0.175 Annual Variance 0.031 Information Ratio -0.824 Tracking Error 0.242 Treynor Ratio -4.849 Total Fees $2350.15 Estimated Strategy Capacity $900000000.00 Lowest Capacity Asset SPY R735QTJ8XC9X |
import numpy as np
import pandas as pd
from sklearn.neural_network import MLPClassifier
class MachineLearningSPY(QCAlgorithm):
def Initialize(self):
self.SetStartDate(2016, 5, 2)
self.SetEndDate(2021, 6, 22)
self.SetCash(100000)
self.AddEquity("SPY", Resolution.Daily)
self.SetBenchmark("SPY")
self.SetBrokerageModel(BrokerageName.AlphaStreams)
self.SetExecution(ImmediateExecutionModel())
self.SetPortfolioConstruction(EqualWeightingPortfolioConstructionModel())
self.AddUniverseSelection(ManualUniverseSelectionModel("SPY"))
self.lookback = 30
self.SetWarmup(self.lookback)
self.spyClose = RollingWindow[float](self.lookback)
self.spyMomentum = RollingWindow[float](self.lookback)
self.spyMomentum_indicator = self.MOMP("SPY", self.lookback, Resolution.Daily)
self.AddAlpha(MachineLearningSPYAlphaModel(self.spyClose, self.spyMomentum, self.spyMomentum_indicator))
class MachineLearningSPYAlphaModel:
def __init__(self, close, spyMomentum, spyMomentum_indicator):
self.period = timedelta(30)
self.spyClose = close
self.spyMomentum = spyMomentum
self.spyMomentum_indicator = spyMomentum_indicator
def GetMLModel(self):
self.MLModel = 0
self.MLModel = MLPClassifier(hidden_layer_sizes = (100, 100, 100, 100), max_iter = 1000)
def Update(self, algorithm, data):
insights = []
if data.Bars.ContainsKey("SPY"):
self.spyMomentum_indicator.Update(data["SPY"].EndTime, data["SPY"].Close)
self.spyMomentum.Add(self.spyMomentum_indicator.Current.Value)
self.spyClose.Add(data["SPY"].Close)
if not algorithm.IsWarmingUp and self.spyMomentum.IsReady and self.spyClose.IsReady:
# features dataframe
df1 = pd.DataFrame(self.spyMomentum, columns=["MOM"]).reset_index(drop=True)
df2 = pd.DataFrame(self.spyClose, columns=["Close"]).reset_index(drop=True)
self.df = pd.concat([df1, df2], axis=1)
# calculate daily SPY forward returns to be used to set Target / Signal
self.df['spyReturn'] = np.log(self.df['Close'].shift(-1)/self.df['Close'])
self.df = self.df.dropna()
# set Signal / Target
self.df['Signal'] = 0
self.df.loc[self.df['spyReturn'] > 0, 'Signal'] = 1
self.df.loc[self.df['spyReturn'] < 0, 'Signal'] = -1
# set training data
self.X = self.df.drop(['Close','Signal'], axis=1)
self.Y = self.df['Signal']
self.Y, self.X = self.Y.align(self.X, axis=0, join='inner')
self.X_train = self.X[:-1]
self.Y_train = self.Y[:-1]
self.X_train.replace([np.inf, -np.inf], np.nan, inplace=True)
self.Y_train.replace([np.inf, -np.inf], np.nan, inplace=True)
drops = []
[drops.append(i) for i in range(self.X_train.shape[0]) if self.X_train.iloc[i].isnull().any()]
[drops.append(i) for i in range(self.Y_train.shape[0]) if self.Y_train.iloc[i] == np.nan and i not in drops]
self.X_train.drop(index=self.X_train.index[drops], inplace=True)
self.Y_train.drop(index=self.Y_train.index[drops], inplace=True)
if self.X_train.empty or self.Y_train.empty: return []
# fit / train ML model
self.GetMLModel()
self.MLModel.fit(self.X_train, self.Y_train)
# predict next day signal using today's values of feature set
self.X_today = self.X.iloc[-1]
# self.X_today is Series, so convert to numpy array
self.X_today = self.X_today.to_numpy()
# reshape self.X_today because it only has 1 day's sample
self.X_today = self.X_today.reshape(1,-1)
# Y_predict will take predicted signal
self.Y_predict = self.Y.iloc[-1]
try:
self.Y_predict = self.MLModel.predict(self.X_today)
except: return []
if self.Y_predict == 1:
insights.append(Insight("SPY", self.period, InsightType.Price, InsightDirection.Up, 1, None))
elif self.Y_predict == -1:
insights.append(Insight("SPY", self.period, InsightType.Price, InsightDirection.Down, 1, None))
return insights
def OnSecuritiesChanged(self, algorithm, changes):
self.changes = changes