Overall Statistics |
Total Trades 9490 Average Win 0.59% Average Loss -0.35% Compounding Annual Return 74.827% Drawdown 91.400% Expectancy 0.205 Net Profit 1505.965% Sharpe Ratio 1.265 Probabilistic Sharpe Ratio 39.943% Loss Rate 55% Win Rate 45% Profit-Loss Ratio 1.68 Alpha -0.057 Beta 0.763 Annual Standard Deviation 0.708 Annual Variance 0.501 Information Ratio -0.669 Tracking Error 0.529 Treynor Ratio 1.174 Total Fees $70266745.95 Estimated Strategy Capacity $280000.00 Lowest Capacity Asset BALUSD XJ |
import numpy as np import pandas as pd from sklearn.linear_model import RidgeClassifier from AlgorithmImports import * class MachineLearningAlgo(QCAlgorithm): def Initialize(self): self.SetStartDate(2016, 6, 2) self.SetEndDate(2021, 5, 20) self.SetCash(10000000) self.Settings.FreePortfolioValuePercentage = 0.1 self.SetBrokerageModel(BrokerageName.AlphaStreams) self.SetExecution(ImmediateExecutionModel()) self.SetPortfolioConstruction(EqualWeightingPortfolioConstructionModel()) self.lookback = 30 symbol_list = ["BTCUSD","ETHUSD","LTCUSD","BALUSD","DAIUSD","KNCUSD", "OXTUSD","RENUSD","UMAUSD","XRPUSD","ZRXUSD"] self.symbols = [self.AddCrypto(symbol, Resolution.Minute, Market.GDAX).Symbol for symbol in symbol_list] self.SetBenchmark("BTCUSD") self.AddAlpha(MachineLearningAlphaModel(self.Time, self.lookback)) class MachineLearningAlphaModel(AlphaModel): def __init__(self, Time, lookback): self.dataBySymbol = {} self.rebalanceTime = Time self.lookback = lookback def GetMLModel(self): self.MLModel = RidgeClassifier(random_state=18) def Update(self, algorithm, data): insights = [] if algorithm.Time < self.rebalanceTime: return [] for symbol, symbolData in self.dataBySymbol.items(): if data.Bars.ContainsKey(symbol) and not algorithm.IsWarmingUp: symbolData.Update(data, symbol) if symbolData.Close_rolling.IsReady: self.df = pd.DataFrame(symbolData.Close_rolling, columns=["Close"])[::-1].reset_index(drop=True) # calculate daily forward returns to be used to set Target / Signal self.df['Return'] = np.log(self.df["Close"].shift(-1)/self.df["Close"]) self.df = self.df.dropna() # set Signal / Target self.df["Signal"] = 0 self.df['Signal'][self.df["Return"] > 0] = 1 self.df['Signal'][self.df["Return"] < 0] = -1 # set training data self.X = self.df.drop(["Return", "Signal"], axis=1) self.Y = self.df['Signal'] # align feature set & 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] 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.MLModel.predict(self.X_today) # set insight based on predicted signal # We cannot short crypto in GDAX # if not all([algorithm.IsMarketOpen(x[symbol]) for x in symbolData.Close_rolling]): # return [] direction = InsightDirection.Up if self.Y_predict == 1 else InsightDirection.Flat insights.append(Insight(symbol, timedelta(days=30), InsightType.Price, direction)) self.rebalanceTime = Expiry.EndOfDay(algorithm.Time) return insights def OnSecuritiesChanged(self, algorithm, changes): for change in changes.AddedSecurities: self.dataBySymbol[change.Symbol] = SymbolData(algorithm, change.Symbol, self.lookback) for change in changes.RemovedSecurities: if change.Symbol in self.dataBySymbol: del self.dataBySymbol[change.Symbol] class SymbolData: def __init__(self, algorithm, symbol, lookback): self.lookback = lookback algorithm.Consolidate(symbol, Resolution.Daily, lambda x: None) self.Close_rolling = RollingWindow[float](self.lookback) history = algorithm.History(symbol, self.lookback, Resolution.Daily) if not history.empty: for index, bar in history.loc[symbol].iterrows(): self.Close_rolling.Add(bar.close) def Update(self, data, symbol): self.Close_rolling.Add(data[symbol].Close)