Overall Statistics |
Total Trades 328 Average Win 0.29% Average Loss -0.27% Compounding Annual Return 2.735% Drawdown 2.700% Expectancy 0.222 Net Profit 10.254% Sharpe Ratio 0.845 Probabilistic Sharpe Ratio 37.338% Loss Rate 41% Win Rate 59% Profit-Loss Ratio 1.07 Alpha 0.019 Beta 0.055 Annual Standard Deviation 0.033 Annual Variance 0.001 Information Ratio -0.699 Tracking Error 0.197 Treynor Ratio 0.505 Total Fees $328.00 |
class ReverseGeorgeDouglasTaylorStrategy(QCAlgorithm): # Strategy Rules: # (1) If the market is up 2 days in a row and opens higher the third day, buy at the open. # (2) If the market is up 2 days in a row, doesn’t open higher, but closes higher, buy at the close. # (3) Exit positions on the next day's close. # Source: Perry Kaufman on the Better System Trader Podcast # https://youtu.be/cE_7ykL2ybU?t=2840 def Initialize(self): self.SetStartDate(2017, 1, 1) self.SetCash(30000) self.allocation_ratio = 0.5 tickers = ['IWM', 'QQQ'] self.symbol_data_by_symbol = {} for ticker in tickers: symbol = self.AddEquity(ticker, Resolution.Minute).Symbol self.symbol_data_by_symbol[symbol] = SymbolData(symbol, self) self.Schedule.On(self.DateRules.EveryDay("IWM"), self.TimeRules.AfterMarketOpen("IWM", 1), self.EveryDayAfterMarketOpen) self.Schedule.On(self.DateRules.EveryDay("IWM"), self.TimeRules.BeforeMarketClose("IWM", 1), self.EveryDayBeforeMarketClose) def EveryDayAfterMarketOpen(self): # Update days_held tracker for each symbol for symbol, symbol_data in self.symbol_data_by_symbol.items(): if self.Securities[symbol].Invested: symbol_data.days_held += 1 self.make_orders('open') def EveryDayBeforeMarketClose(self): self.make_orders('close') # Exit orders with days held == 1 for symbol, symbol_data in self.symbol_data_by_symbol.items(): if symbol_data.days_held == 1: symbol_data.days_held = 0 self.Liquidate(symbol) def make_orders(self, at): for symbol, symbol_data in self.symbol_data_by_symbol.items(): if at == 'open': price = self.Securities[symbol].Open else: price = self.Securities[symbol].Close signal = symbol_data.generate_signal(price, at) if signal: if self.Securities[symbol].Invested: # Extend exit date symbol_data.days_held -= 1 else: # Make order quantity = self.CalculateOrderQuantity(symbol, self.allocation_ratio / len(self.symbol_data_by_symbol)) self.MarketOrder(symbol, quantity) class SymbolData: open_price = None days_held = 0 def __init__(self, symbol, algorithm): self.symbol = symbol self.window = RollingWindow[TradeBar](3) # Warm up history history = algorithm.History(symbol, 3, Resolution.Daily) for idx, row in history.iterrows(): tradebar = TradeBar(idx, symbol, row.open, row.high, row.low, row.close, row.volume) self.window.Add(tradebar) # Setup consolidator self.consolidator = TradeBarConsolidator(timedelta(1)) self.consolidator.DataConsolidated += self.ConsolidationHandler algorithm.SubscriptionManager.AddConsolidator(symbol, self.consolidator) def ConsolidationHandler(self, sender, consolidated): self.window.Add(consolidated) def generate_signal(self, price, at): if at == 'open': self.open_price = price # If up two days in a row if self.window[2].Close < self.window[1].Close and self.window[1].Close < self.window[0].Close: # Gaps up the third day if at == 'open' and self.window[0].Close < self.open_price: return True # Short open # Doesn't gap up the third day, but the third day is an up day if at == 'close' and self.window[0].Close >= self.open_price and self.window[0].Close < price: return True # Short close