| 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)