Overall Statistics |
Total Orders 1126 Average Win 0.61% Average Loss -0.26% Compounding Annual Return 14.967% Drawdown 12.900% Expectancy 0.121 Start Equity 100000 End Equity 118201.91 Net Profit 18.202% Sharpe Ratio 0.559 Sortino Ratio 0.743 Probabilistic Sharpe Ratio 52.595% Loss Rate 67% Win Rate 33% Profit-Loss Ratio 2.39 Alpha -0.068 Beta 0.794 Annual Standard Deviation 0.096 Annual Variance 0.009 Information Ratio -1.942 Tracking Error 0.051 Treynor Ratio 0.068 Total Fees $1361.55 Estimated Strategy Capacity $44000000.00 Lowest Capacity Asset SPY R735QTJ8XC9X Portfolio Turnover 255.63% |
# region imports from AlgorithmImports import * import numpy as np # endregion class SwimmingFluorescentPinkLemur(QCAlgorithm): def initialize(self): self.set_start_date(2023, 1, 1) self.set_end_date(2024, 6, 1) self.set_cash(100000) self.symbol = self.add_equity("SPY").symbol # Set up indicators self._macd = self.MACD(self.symbol, 8, 17, 9, MovingAverageType.Simple) self._bb = self.BB(self.symbol, 18, 2, MovingAverageType.Simple) self._kc = self.KCH(self.symbol, 18, 1.5, MovingAverageType.Simple) # Create a RollingWindow to store the past 3 values of the MACD Histogram self._macd_hist_window = RollingWindow[IndicatorDataPoint](3) # Consolidate the data into 5-minute bars self.Consolidate(self.symbol, timedelta(minutes=5), self.on_data_consolidated) self.register_indicator(self.symbol, self._macd, timedelta(minutes=5)) self.register_indicator(self.symbol, self._bb, timedelta(minutes=5)) self.register_indicator(self.symbol, self._kc, timedelta(minutes=5)) # Setting stoploss self.stop_loss_len = 20*5 self.stop_loss_indicator = self.MIN(self.symbol, self.stop_loss_len, Resolution.MINUTE) self.stop_loss = None # Warming up engine self.set_warm_up(5*20, Resolution.MINUTE) def on_data_consolidated(self, data: slice): # Check if the data strategy is warming up if self.is_warming_up: return # Check if the Bollinger Bands are within the Keltner Channels self.squeeze = self._bb.UpperBand.Current.Value < self._kc.UpperBand.Current.Value and self._bb.LowerBand.Current.Value > self._kc.LowerBand.Current.Value self.Log(f"Squeeze indicator: {self.squeeze}") # Check for MACD entry signal self._macd_hist_window.Add(self._macd.Histogram.Current) # Ensure we have 3 data points in the window if self._macd_hist_window.IsReady: macd_hist = self._macd_hist_window[0].Value # Current MACD Histogram value macd_hist_1 = self._macd_hist_window[1].Value # MACD Histogram value 1 bar ago macd_hist_2 = self._macd_hist_window[2].Value # MACD Histogram value 2 bars ago self.macd_long_in = (macd_hist > macd_hist_1 or macd_hist > macd_hist_2) and macd_hist > 0 self.Log(f"MACD entry: {self.macd_long_in}") # Entry if not self.portfolio.invested: if self.squeeze and self.macd_long_in: self.log(f"Price is {data.Close}") self.set_holdings(self.symbol, 1) self.stop_loss = self.stop_loss_indicator.Current.Value self.log(f"Stop loss level {self.stop_loss}") # Exit if self.portfolio.invested: if data.Close < self.stop_loss or not self.Time.hour in range(9, 16): self.log(f"Stop loss at {data.Close}") self.liquidate(self.symbol)