Overall Statistics |
Total Trades 146 Average Win 0.39% Average Loss -0.14% Compounding Annual Return 1.252% Drawdown 16.200% Expectancy 0.499 Net Profit 0.784% Sharpe Ratio 0.141 Probabilistic Sharpe Ratio 20.733% Loss Rate 60% Win Rate 40% Profit-Loss Ratio 2.75 Alpha 0.126 Beta -0.953 Annual Standard Deviation 0.186 Annual Variance 0.034 Information Ratio -0.215 Tracking Error 0.364 Treynor Ratio -0.027 Total Fees $152.89 Estimated Strategy Capacity $830000000.00 Lowest Capacity Asset SPY R735QTJ8XC9X |
#region imports from AlgorithmImports import * import aesara import aesara.tensor as at from sklearn.model_selection import train_test_split from sklearn.preprocessing import MinMaxScaler import joblib #endregion class AeseraExampleAlgorithm(QCAlgorithm): def Initialize(self): self.SetStartDate(2022, 7, 4) self.SetCash(100000) self.symbol = self.AddEquity("SPY", Resolution.Daily).Symbol training_length = 252*2 self.training_data = RollingWindow[TradeBar](training_length) history = self.History[TradeBar](self.symbol, training_length, Resolution.Daily) for trade_bar in history: self.training_data.Add(trade_bar) if self.ObjectStore.ContainsKey("train") and self.ObjectStore.ContainsKey("predict"): train_file_name = self.ObjectStore.GetFilePath("train") predict_file_name = self.ObjectStore.GetFilePath("predict") self.predict = joblib.load(train_file_name) self.predict = joblib.load(predict_file_name) else: # Declare Aesara symbolic variables x = at.dmatrix("x") y = at.dvector("y") # initialize the weight vector w randomly # this and the following bias variable b # are shared so they keep their values # between training iterations (updates) rng = np.random.default_rng(100) w = aesara.shared(rng.standard_normal(5), name="w") # initialize the bias term b = aesara.shared(0., name="b") # Construct Aesara expression graph p_1 = 1 / (1 + at.exp(-at.dot(x, w) - b)) # Probability that target = 1 prediction = p_1 > 0.5 # The prediction thresholded xent = y * at.log(p_1) - (1-y) * at.log(1-p_1) # Cross-entropy log-loss function cost = xent.mean() + 0.01 * (w ** 2).sum() # The cost to minimize gw, gb = at.grad(cost, [w, b]) # Compute the gradient of the cost # w.r.t weight vector w and # bias term b (we shall # return to this in a # following section of this # tutorial) # Compile self.train = aesara.function( inputs=[x, y], outputs=[prediction, xent], updates=((w, w - 0.1 * gw), (b, b - 0.1 * gb))) self.predict = aesara.function(inputs=[x], outputs=prediction) self.Train(self.my_training_method) self.Train(self.DateRules.Every(DayOfWeek.Sunday), self.TimeRules.At(8,0), self.my_training_method) def get_features_and_labels(self, n_steps=5): training_df = self.PandasConverter.GetDataFrame[TradeBar](list(self.training_data)[::-1])['close'] features = [] for i in range(1, n_steps + 1): close = training_df.shift(i)[n_steps:-1] close.name = f"close-{i}" features.append(close) features = pd.concat(features, axis=1) # Normalize using the 5 day interval features = MinMaxScaler().fit_transform(features.T).T[4:] Y = training_df.pct_change().shift(-1)[n_steps*2-1:-1].reset_index(drop=True) labels = np.array([1 if y > 0 else 0 for y in Y]) # binary class return features, labels def my_training_method(self): features, labels = self.get_features_and_labels() D = (features, labels) self.train(D[0], D[1]) model_key = "model" file_name = self.ObjectStore.GetFilePath(model_key) joblib.dump(self.predict, file_name) self.ObjectStore.Save(model_key) def OnData(self, slice): if self.symbol in slice.Bars: self.training_data.Add(slice.Bars[self.symbol]) features, _ = self.get_features_and_labels() prediction = self.predict(features[-1].reshape(1, -1)) prediction = float(prediction) if prediction == 1: self.SetHoldings(self.symbol, 1) elif prediction == 0: self.SetHoldings(self.symbol, -1)