Overall Statistics |
Total Orders 1249 Average Win 0.49% Average Loss -0.47% Compounding Annual Return 10.295% Drawdown 13.100% Expectancy 0.218 Start Equity 100000 End Equity 148051.33 Net Profit 48.051% Sharpe Ratio 0.568 Sortino Ratio 0.838 Probabilistic Sharpe Ratio 35.982% Loss Rate 41% Win Rate 59% Profit-Loss Ratio 1.05 Alpha 0.001 Beta 0.522 Annual Standard Deviation 0.084 Annual Variance 0.007 Information Ratio -0.531 Tracking Error 0.078 Treynor Ratio 0.091 Total Fees $660.58 Estimated Strategy Capacity $1100000000.00 Lowest Capacity Asset SPY R735QTJ8XC9X Portfolio Turnover 15.78% |
# region imports from AlgorithmImports import * import numpy as np import pandas as pd import statsmodels.api as sm from datetime import date from sklearn.linear_model import LinearRegression # endregion class KANYEWEST(QCAlgorithm): def Initialize(self): self.SetStartDate(2020, 7, 25) self.SetEndDate(2024, 7, 25) self.SetCash(100000) self.symbol = self.AddEquity("SPY", Resolution.Daily).Symbol # symbol has to be SPY self.set_benchmark(self.symbol) self.cap = 100000 self.benchmark_chart = [] # Initialize model with past data history = self.History(self.symbol, 1800, Resolution.Daily) self.model_inter, self.model_intra = self.train(history) # Track open stop market orders self.stopMarketTicket = None def OnData(self, data: Slice): self.plot_market() if not data.ContainsKey(self.symbol): return if self.model_inter is None or self.model_intra is None: self.Log("Models are not trained. Skipping prediction.") return history = self.History(self.symbol, 35, Resolution.Daily) formatted_data = self.prepare_data(history) if formatted_data.empty: self.Log("Formatted data is empty. Skipping this OnData call.") return # Get latest features latest_data = formatted_data.iloc[[-1]][['0_inter', '0_intra', '1_inter', '1_intra', '2_inter', '2_intra', 'SMA_10', 'SMA_20']] # if date.day == 15: # self.liquidate() # Get predictions inter_pred = self.model_inter.predict(latest_data)[0] intra_pred = self.model_intra.predict(latest_data)[0] self.Log(f"Date: {self.Time.date()}, Interday Prediction: {inter_pred:.4f}, Intraday Prediction: {intra_pred:.4f}") # Cancel any existing stop market orders before making a new trade if self.stopMarketTicket is not None and self.stopMarketTicket.Status == OrderStatus.Submitted: self.Transactions.CancelOrder(self.stopMarketTicket.OrderId) self.stopMarketTicket = None # paramseters to tune buy_threshold = 0.5 sell_threshold = 0.4 short_threshold = 0.35 portfolio_weight = 0.7 short_weight = 0.7 # trading logic if inter_pred > buy_threshold and intra_pred > buy_threshold: # Strong bullish signal self.SetHoldings(self.symbol, portfolio_weight) purchase_price = self.Portfolio[self.symbol].Price self.RecordPurchase(self.Time, 0.5 * purchase_price) self.PlaceStopMarketOrder(purchase_price, direction="long") # elif inter_pred < sell_threshold and intra_pred < sell_threshold: elif inter_pred < sell_threshold and inter_pred > short_threshold and intra_pred < buy_threshold and intra_pred > short_threshold: pass elif inter_pred < short_threshold and intra_pred < short_threshold: # Strong bearish signal self.SetHoldings(self.symbol, -short_weight) #portfolio_weight) purchase_price = self.Portfolio[self.symbol].Price self.RecordPurchase(self.Time, 0.5 * purchase_price) self.PlaceStopMarketOrder(purchase_price, direction="short") def PlaceStopMarketOrder(self, purchase_price, direction): if direction == "long": stop_price = purchase_price * 0.99 # 1% below purchase price self.stopMarketTicket = self.StopMarketOrder(self.symbol, -self.Portfolio[self.symbol].Quantity, stop_price) self.Log(f"Placed stop market order to sell at ${stop_price:.2f} (0.5% below purchase price).") elif direction == "short": stop_price = purchase_price * 1.01 # 1% above purchase price self.stopMarketTicket = self.StopMarketOrder(self.symbol, -self.Portfolio[self.symbol].Quantity, stop_price) self.Log(f"Placed stop market order to cover at ${stop_price:.2f} (0.5% above purchase price).") def RecordPurchase(self, date, amount): self.Log(f"Purchase recorded: Date: {date}, Amount: ${amount:.2f}") def OnOrderEvent(self, orderEvent): # Check if the stop market order was filled if self.stopMarketTicket is not None and orderEvent.OrderId == self.stopMarketTicket.OrderId: if orderEvent.Status == OrderStatus.Filled: execution_price = orderEvent.FillPrice execution_date = self.Time self.Log(f"Stop market order executed: Date: {execution_date}, Price: ${execution_price:.2f}") # Clear the stop market ticket after execution self.stopMarketTicket = None def train(self, history): df = pd.DataFrame(history) grads = self.prepare_data(df) if grads.empty: self.Log("Training data is empty. Cannot train model.") return None, None """ Implement your own model and training here. """ # Prepare features and targets X = grads[['0_inter', '0_intra', '1_inter', '1_intra', '2_inter', '2_intra', 'SMA_10', 'SMA_20']] y_inter = grads['0_inter'].shift(1)[grads.index] y_intra = grads['0_intra'].shift(1)[grads.index] # Remove first row since it won't have target values X = X[20:] y_inter = y_inter[20:] y_intra = y_intra[20:] # Train models self.model_inter = LinearRegression() self.model_intra = LinearRegression() self.model_inter.fit(X, y_inter) self.model_intra.fit(X, y_intra) return (self.model_inter, self.model_intra) def prepare_data(self, df): df = df.reset_index() if 'index' in df.columns: df.rename(columns={'index': 'time'}, inplace=True) elif 'time' not in df.columns: df.rename(columns={'time': 'time'}, inplace=True) """ Implement your own feature engineering and data preparation here. """ df['Date'] = pd.to_datetime(df['time']) df.set_index('Date', inplace=True) df['intraday_grads'] = (df['close'] / df['open'] - 1).dropna() df['interday_grads'] = (df['open'] / df['close'].shift(1) - 1).dropna() df['intraday_grads_norm'] = (df['intraday_grads'] - df['intraday_grads'].min()) / (df['intraday_grads'].max() - df['intraday_grads'].min()) df['interday_grads_norm'] = (df['interday_grads'] - df['interday_grads'].min()) / (df['interday_grads'].max() - df['interday_grads'].min()) grads = df[['interday_grads_norm', 'intraday_grads_norm']] grads.columns = ['0_inter', '0_intra'] grads['1_inter'] = df['interday_grads_norm'].shift(-1) grads['1_intra'] = df['intraday_grads_norm'].shift(-1) grads['2_inter'] = df['interday_grads_norm'].shift(-2) grads['2_intra'] = df['intraday_grads_norm'].shift(-2) grads['SMA_10'] = df['close'].rolling(window=10).mean() # 10-day Simple Moving Average grads['SMA_20'] = df['close'].rolling(window=20).mean() return grads.dropna() def plot_market(self): #plot the market on the Startegy Equity Chart with your portfolio hist = self.History([self.symbol], 252, Resolution.Daily)['close'].unstack(level=0).dropna() self.benchmark_chart.append(hist[self.symbol].iloc[-1]) benchmark_perf = self.benchmark_chart[-1] / self.benchmark_chart[0] * self.cap self.Plot("Strategy Equity", "Buy & Hold", benchmark_perf)