Overall Statistics |
Total Orders 1 Average Win 0% Average Loss 0% Compounding Annual Return 11.991% Drawdown 30.200% Expectancy 0 Start Equity 100000 End Equity 504093.25 Net Profit 404.093% Sharpe Ratio 0.577 Sortino Ratio 0.589 Probabilistic Sharpe Ratio 6.614% Loss Rate 0% Win Rate 0% Profit-Loss Ratio 0 Alpha -0.004 Beta 0.911 Annual Standard Deviation 0.131 Annual Variance 0.017 Information Ratio -0.772 Tracking Error 0.015 Treynor Ratio 0.083 Total Fees $4.35 Estimated Strategy Capacity $84000000.00 Lowest Capacity Asset SPY R735QTJ8XC9X Portfolio Turnover 0.02% |
from AlgorithmImports import * class MultiTimeframeTrendStrategy(QCAlgorithm): def Initialize(self): self.SetStartDate(2010, 1, 1) # self.SetEndDate(2015, 1, 1) self.SetCash(100_000) spy = self.AddEquity("SPY", Resolution.Hour) spy.SetDataNormalizationMode(DataNormalizationMode.Raw) self.spySymbol = spy.Symbol self.SetBenchmark("SPY") self.SetBrokerageModel(BrokerageName.InteractiveBrokersBrokerage, AccountType.Margin) # Initialize opening and previous bar prices for multiple time frames self.weeklyOpenPrice = None self.dailyOpenPrice = None self.hourlyOpenPrice = None self.lastDailyHigh = None self.lastDailyLow = None self.lastHourlyHigh = None self.lastHourlyLow = None self.lastHour = self.Time.hour # Schedule functions to update weekly, daily, and hourly opening prices self.lastTradeWeek = -1 # Initialize to an invalid week number self.Schedule.On(self.DateRules.EveryDay(self.spySymbol), self.TimeRules.AfterMarketOpen(self.spySymbol, 1), self.CheckIfNewWeek) self.Schedule.On(self.DateRules.EveryDay(self.spySymbol), self.TimeRules.At(9, 30), self.DailyOpen) def OnData(self, data): # Ensure the algorithm isn't warming up and that SPY data is available. if self.IsWarmingUp or self.spySymbol not in data or data[self.spySymbol] is None: return # Update hourly price data and track high/low for Inside Bar detection. if self.Time.hour != self.lastHour: if data.Bars.ContainsKey(self.spySymbol): self.lastHour = self.Time.hour self.insideBarDetected = False # Reset inside bar detection for the new hour bar = data.Bars[self.spySymbol] self.hourlyOpenPrice = bar.Open self.lastHourlyHigh = bar.High self.lastHourlyLow = bar.Low # Detect an Inside Bar based on the last hourly high and low. if self.lastHourlyHigh is not None and self.lastHourlyLow is not None: if self.hourlyOpenPrice < self.lastHourlyHigh and self.hourlyOpenPrice > self.lastHourlyLow: self.Debug("Detected an Inside Bar at the hourly time frame") self.insideBarDetected = True # self.Log(f' IsWarmingUp {self.IsWarmingUp}, insideBar {self.insideBarDetected}, lastHour {self.lastHour}, hourly Price: {self.hourlyOpenPrice:,.2f}, HourlyHigh {self.lastHourlyHigh:,.2f}, HourlyLow {self.lastHourlyLow:,.2f}, weeklyPrice {self.weeklyOpenPrice:,.2f}, dailyPrice {self.dailyOpenPrice:,.2f}') # Ensure all necessary prices are set before proceeding. if None in [self.weeklyOpenPrice, self.dailyOpenPrice, self.hourlyOpenPrice]: return # if 0.00 in [self.weeklyOpenPrice, self.dailyOpenPrice, self.hourlyOpenPrice]: # return # Current price from the data. price = data[self.spySymbol].Price # Execute trades based on Inside Bar breakout and trend continuity. if self.insideBarDetected: spyInvested = self.Portfolio[self.spySymbol].Invested # Entry condition for a long position when current price breaks above the Inside Bar's high self.Log(f'price {price:,.2f}, HourlyHigh {self.lastHourlyHigh:,.2f}, HourlyLow {self.lastHourlyLow:,.2f}, weeklyPrice {self.weeklyOpenPrice:,.2f}, dailyPrice {self.dailyOpenPrice:,.2f}') if price >= self.lastHourlyHigh and price > self.weeklyOpenPrice and price > self.dailyOpenPrice and price > self.hourlyOpenPrice: # if price > self.lastHourlyLow and price > self.weeklyOpenPrice and price > self.dailyOpenPrice and price > self.hourlyOpenPrice: if not spyInvested: self.Log("Inside Bar broken upwards, aligning with TFC for a long position") self.SetHoldings(self.spySymbol, 1) # Exit condition if the price breaks below the Inside Bar's low elif spyInvested and price < self.lastHourlyLow: self.Log("Inside Bar broken downwards, exiting position.") self.Liquidate(self.spySymbol) def CheckIfNewWeek(self): currentWeek = self.Time.isocalendar()[1] if currentWeek != self.lastTradeWeek: self.lastTradeWeek = currentWeek self.WeeklyOpen() def WeeklyOpen(self): self.weeklyOpenPrice = self.Securities[self.spySymbol].Price self.Log(f"Weekly open price updated on {self.Time.strftime('%Y-%m-%d')}: {self.weeklyOpenPrice}") def DailyOpen(self): bar = self.Securities[self.spySymbol] self.dailyOpenPrice = bar.Price self.lastDailyHigh = bar.High self.lastDailyLow = bar.Low self.Log(f"Daily open price updated on {self.Time.strftime('%Y-%m-%d')}: {self.dailyOpenPrice}")