from AlgorithmImports import *
from datetime import date
class SymbolData:
def __init__(self, open_price: float, current_date: date):
self.open_price = open_price
self.bought_today = False
self.entry_price = 0.0
self.current_date = current_date
def __repr__(self) -> str:
return f"Open: {self.open_price}, Bought: {self.bought_today}, Entry: {self.entry_price}"
class GapUpBreakout(QCAlgorithm):
def initialize(self) -> None:
self.set_start_date(2025, 5, 25)
self.set_end_date(2025, 5, 29)
self.set_cash(100000)
self.add_universe(self.coarse_selection_function)
self.add_equity("SBET")
self._symbol_data = {}
self._previous_minute = -1
def coarse_selection_function(self, fundamental: List[Fundamental]) -> List[Symbol]:
selected = []
for f in fundamental:
self.debug(f"Coarse selection: {f.symbol.value}, market: {f.symbol.id.market}, has_fund: {f.has_fundamental_data}")
if f.has_fundamental_data and f.symbol.id.market in ("usa", "nys", "ase", "arca", "nasdaq"):
selected.append(f.symbol)
self.debug(f"Universe selected: {[str(s) for s in selected]}")
if any(str(s) == "SBET" for s in selected):
self.debug("SBET is present in the universe on this day.")
else:
self.debug("SBET is NOT present in the universe on this day.")
return selected
def on_data(self, data: Slice) -> None:
for symbol, bar in data.bars.items():
# Additional debug: check if symbol is SBET.
if symbol.value == "SBET":
self.debug("SBET: Entering on_data for position management.")
if symbol not in self._symbol_data:
self.debug(f"{symbol.value}: Not in symbol_data, skipping.")
continue
if symbol.value == "SBET":
self.debug("SBET: Found in symbol_data, checking if bought today.")
sd = self._symbol_data[symbol]
if not sd.bought_today:
self.debug(f"{symbol.value}: Not bought today, skipping position management.")
continue
current_price = bar.close
if sd.entry_price > 0:
take_profit_level = sd.open_price * 1.50
stop_loss_level = sd.open_price * 1.10
self.debug(
f"{symbol.value}: Managing position. Open: {sd.open_price}, "
f"Entry: {sd.entry_price}, Current: {current_price}, "
f"TP: {take_profit_level}, SL: {stop_loss_level}"
)
if current_price >= take_profit_level:
self.debug(f"{symbol.value}: Hitting take profit, liquidating.")
self.liquidate(symbol)
sd.bought_today = False
sd.entry_price = 0.0
if symbol.value == "SBET":
self.debug("SBET: Liquidated at take profit.")
elif current_price <= stop_loss_level:
self.debug(f"{symbol.value}: Hitting stop loss, liquidating.")
self.liquidate(symbol)
sd.bought_today = False
sd.entry_price = 0.0
if symbol.value == "SBET":
self.debug("SBET: Liquidated at stop loss.")
# Only run once per second
if self.time.minute != self._previous_minute:
self._previous_minute = self.time.minute
current_date = self.time.date()
for symbol in self.active_securities.keys:
# Additional debug: check if symbol is SBET.
if symbol.value == "SBET":
self.debug("SBET: Checking bar data and potential breakout.")
if symbol not in data.bars:
self.debug(f"{symbol.value}: No bar data for this second, skipping.")
continue
bar = data.bars[symbol]
current_open = bar.open
current_close = bar.close
# Additional debug for SBET.
if symbol.value == "SBET":
self.debug(f"SBET: Current Open={current_open}, Current Close={current_close}")
history = self.history(symbol, 2, Resolution.DAILY)
self.debug(f"{symbol.value}: Open: {current_open}, Close: {current_close}, History:")
if not history.empty:
self.debug(str(history))
if symbol.value == "SBET" and current_date == date(2025, 5, 27):
self.debug("SBET: History contents specifically for 5/27:")
self.debug(f"{history}")
else:
self.debug("History is empty!")
# Make sure we have data on the prior day to measure gap.
if history.empty or history.shape[0] < 2:
self.debug(f"{symbol.value}: Not enough history for previous close, skipping.")
continue
prev_close = history['close'].iloc[-2]
self.debug(f"{symbol.value}: Prev Close: {prev_close}")
if symbol.value == "SBET":
self.debug(f"SBET: Gap-up check with open={current_open} vs prev_close={prev_close}")
# If we don't have symbol_data or the date is different, we want to check the gap-up condition.
if (symbol not in self._symbol_data or self._symbol_data[symbol].current_date != current_date):
gap_up_check_1 = current_open >= 2.50
gap_up_check_2 = current_open >= prev_close * 1.10
self.debug(
f"{symbol.value}: Gap check - open >= 2.5: {gap_up_check_1}, "
f"open >= prev_close*1.10: {gap_up_check_2}"
)
if gap_up_check_1 and gap_up_check_2:
self.debug(f"{symbol.value}: PASS gap up conditions; initializing SymbolData.")
self._symbol_data[symbol] = SymbolData(current_open, current_date)
if symbol.value == "SBET":
self.debug("SBET: SymbolData initialized.")
else:
self.debug(f"{symbol.value}: FAIL gap up conditions; skipping symbol_data init.")
if symbol.value == "SBET":
self.debug("SBET: Did not meet gap up conditions, ignored.")
else:
sd = self._symbol_data[symbol]
if not sd.bought_today and sd.open_price > 0.0:
breakout_level = sd.open_price * 1.3
breakout_check = current_close > breakout_level
self.debug(f"{symbol.value}: Breakout: {current_close} > {breakout_level}? {breakout_check}")
if breakout_check:
qty = self.calculate_order_quantity(symbol, 0.1)
if qty != 0:
self.debug(f"{symbol.value}: BUY breakout triggered! Buying {qty} shares at {current_close}")
self.buy(symbol, qty)
sd.bought_today = True
sd.entry_price = current_close
if symbol.value == "SBET":
self.debug("SBET: Breakout buy order submitted.")
else:
self.debug(f"{symbol.value}: Breakout but qty=0, not buying.")
if symbol.value == "SBET":
self.debug("SBET: Breakout triggered but zero quantity, ignoring.")
else:
self.debug(f"{symbol.value}: No breakout, not buying.")
if symbol.value == "SBET":
self.debug("SBET: Current price has not breached breakout level.")
def on_end_of_day(self, symbol: Symbol) -> None:
if symbol in self._symbol_data:
sd = self._symbol_data[symbol]
if sd.bought_today:
self.debug(f"{symbol.value}: End of day, liquidating position.")
self.liquidate(symbol)
sd.bought_today = False
sd.entry_price = 0.0
if symbol.value == "SBET":
self.debug("SBET: End of day liquidation.")