Fix critical bugs: RSI division by zero, API price validation, order timeout, and crossover race condition

This commit is contained in:
justin committed 2026-02-04 10:06:38 -07:00
1 parent 91d9ed2e64
commit efdbcd0899
3 files changed
+23 -15

No files matched your search

+5 -1
View File
@@ -64,7 +64,7 @@ class AlpacaClient:
price_source = limit_price price_source = limit_price
else: else:
price_source = bid_price if side == "buy" else ask_price price_source = bid_price if side == "buy" else ask_price
if price_source is None: if price_source is None or price_source <= 0:
return None return None
shares = int(notional / price_source) shares = int(notional / price_source)
if shares == 0: if shares == 0:
@@ -83,7 +83,11 @@ class AlpacaClient:
return None return None
order = self.submit_order(symbol=symbol, qty=shares, side=side, type="market", time_in_force="day") order = self.submit_order(symbol=symbol, qty=shares, side=side, type="market", time_in_force="day")
status = self.get_order(order.id) status = self.get_order(order.id)
timeout = 30
start_time = time.time()
while status.status not in {"filled", "cancelled", "expired", "rejected"}: while status.status not in {"filled", "cancelled", "expired", "rejected"}:
if time.time() - start_time > timeout:
return None
time.sleep(0.5) time.sleep(0.5)
status = self.get_order(order.id) status = self.get_order(order.id)
if status.status == "filled": if status.status == "filled":
+16 -13
View File
@@ -206,6 +206,17 @@ api = AlpacaClient(
api_version='v2' api_version='v2'
) )
class SignalState:
def __init__(self):
self.last_bullish_crossover_bar = -999
self.last_bearish_crossover_bar = -999
def reset(self):
self.last_bullish_crossover_bar = -999
self.last_bearish_crossover_bar = -999
signal_state = SignalState()
def debug_print(message): def debug_print(message):
if DEBUG_MODE: if DEBUG_MODE:
debug_logger.debug(f"🔎 {message}") debug_logger.debug(f"🔎 {message}")
@@ -426,28 +437,23 @@ def advanced_signal_generator(symbol):
bearish_crossover = False bearish_crossover = False
if REQUIRE_MA_CROSSOVER and len(bars) >= LONG_WINDOW + CROSSOVER_LOOKBACK: if REQUIRE_MA_CROSSOVER and len(bars) >= LONG_WINDOW + CROSSOVER_LOOKBACK:
if not hasattr(advanced_signal_generator, 'last_bullish_crossover_bar'):
advanced_signal_generator.last_bullish_crossover_bar = -999
if not hasattr(advanced_signal_generator, 'last_bearish_crossover_bar'):
advanced_signal_generator.last_bearish_crossover_bar = -999
current_bar_index = len(bars) - 1 current_bar_index = len(bars) - 1
for i in range(1, CROSSOVER_LOOKBACK + 1): for i in range(1, CROSSOVER_LOOKBACK + 1):
bar_index = current_bar_index - i bar_index = current_bar_index - i
if short_ma_series.iloc[-i-1] <= long_ma_series.iloc[-i-1] and short_ma_series.iloc[-i] > long_ma_series.iloc[-i]: if short_ma_series.iloc[-i-1] <= long_ma_series.iloc[-i-1] and short_ma_series.iloc[-i] > long_ma_series.iloc[-i]:
if bar_index > advanced_signal_generator.last_bullish_crossover_bar: if bar_index > signal_state.last_bullish_crossover_bar:
bullish_crossover = True bullish_crossover = True
advanced_signal_generator.last_bullish_crossover_bar = bar_index signal_state.last_bullish_crossover_bar = bar_index
debug_print(f"Bullish crossover detected {i} bars ago") debug_print(f"Bullish crossover detected {i} bars ago")
break break
for i in range(1, CROSSOVER_LOOKBACK + 1): for i in range(1, CROSSOVER_LOOKBACK + 1):
bar_index = current_bar_index - i bar_index = current_bar_index - i
if short_ma_series.iloc[-i-1] >= long_ma_series.iloc[-i-1] and short_ma_series.iloc[-i] < long_ma_series.iloc[-i]: if short_ma_series.iloc[-i-1] >= long_ma_series.iloc[-i-1] and short_ma_series.iloc[-i] < long_ma_series.iloc[-i]:
if bar_index > advanced_signal_generator.last_bearish_crossover_bar: if bar_index > signal_state.last_bearish_crossover_bar:
bearish_crossover = True bearish_crossover = True
advanced_signal_generator.last_bearish_crossover_bar = bar_index signal_state.last_bearish_crossover_bar = bar_index
debug_print(f"Bearish crossover detected {i} bars ago") debug_print(f"Bearish crossover detected {i} bars ago")
break break
@@ -647,10 +653,7 @@ def main():
trades_today = 0 trades_today = 0
total_pnl = 0 total_pnl = 0
if hasattr(advanced_signal_generator, 'last_bullish_crossover_bar'): signal_state.reset()
delattr(advanced_signal_generator, 'last_bullish_crossover_bar')
if hasattr(advanced_signal_generator, 'last_bearish_crossover_bar'):
delattr(advanced_signal_generator, 'last_bearish_crossover_bar')
try: try:
existing_position = api.get_position(SYMBOL) existing_position = api.get_position(SYMBOL)
+2 -1
View File
@@ -10,7 +10,8 @@ def rsi(data, window=14):
delta = data.diff() delta = data.diff()
gain = (delta.where(delta > 0, 0)).rolling(window=window).mean() gain = (delta.where(delta > 0, 0)).rolling(window=window).mean()
loss = (-delta.where(delta < 0, 0)).rolling(window=window).mean() loss = (-delta.where(delta < 0, 0)).rolling(window=window).mean()
loss = loss.replace(0, 0.0001) loss = loss.replace(0, 1e-10)
loss = loss.clip(lower=1e-10)
rs = gain / loss rs = gain / loss
rsi_val = 100 - (100 / (1 + rs)) rsi_val = 100 - (100 / (1 + rs))
return rsi_val return rsi_val