fix: handle 404 errors by checking portfolio for filled/closed positions

This commit is contained in:
pie
2026-05-04 15:37:34 +01:00
parent ede9933c88
commit d1a141a669
+51 -10
View File
@@ -53,6 +53,17 @@ class ExecutionManager:
logger.error(f"Failed to place entry order: {e}") logger.error(f"Failed to place entry order: {e}")
return False return False
def _is_ticker_in_portfolio(self, ticker: str) -> bool:
"""Helper to check if a ticker currently has an open position."""
try:
positions = self.client.get_all_open_positions()
for pos in positions:
if pos.get('ticker') == ticker:
return True
except Exception as e:
logger.error(f"Error checking portfolio: {e}")
return False
def monitor_and_bracket(self, params: Dict[str, Any]): def monitor_and_bracket(self, params: Dict[str, Any]):
"""Polls the entry order and places SL/TP once filled.""" """Polls the entry order and places SL/TP once filled."""
if not self.current_order_id: if not self.current_order_id:
@@ -87,6 +98,15 @@ class ExecutionManager:
logger.warning(f"Entry order was {status}. Aborting.") logger.warning(f"Entry order was {status}. Aborting.")
return False return False
except Exception as e: except Exception as e:
# Trading212 404s if an order is no longer active (filled or cancelled)
if "404" in str(e):
if self._is_ticker_in_portfolio(ticker):
self.is_in_position = True
logger.info(f"Order {self.current_order_id} disappeared but position detected. Assuming filled.")
break
else:
logger.warning(f"Order {self.current_order_id} disappeared and no position found. Assuming cancelled/rejected.")
return False
logger.error(f"Error checking order status: {e}") logger.error(f"Error checking order status: {e}")
time.sleep(10) # Poll every 10 seconds time.sleep(10) # Poll every 10 seconds
@@ -118,20 +138,41 @@ class ExecutionManager:
if not self.is_in_position: if not self.is_in_position:
return False, "", 0.0 return False, "", 0.0
ticker = self.params.get('ticker')
try: try:
if self.tp_order_id: if self.tp_order_id:
tp_info = self.client.get_order_status(self.tp_order_id) try:
if tp_info.get('status') == "FILLED": tp_info = self.client.get_order_status(self.tp_order_id)
fill_price = tp_info.get('filledPrice', tp_info.get('limitPrice', self.params.get('target_price'))) if tp_info.get('status') == "FILLED":
self.is_in_position = False fill_price = tp_info.get('filledPrice', tp_info.get('limitPrice', self.params.get('target_price')))
return True, "TP Hit", float(fill_price) self.is_in_position = False
return True, "TP Hit", float(fill_price)
except Exception as e:
if "404" in str(e):
if not self._is_ticker_in_portfolio(ticker):
self.is_in_position = False
logger.info(f"TP order {self.tp_order_id} disappeared and position closed. Assuming TP hit.")
return True, "TP Hit", float(self.params.get('target_price'))
else:
raise e
if self.sl_order_id: if self.sl_order_id:
sl_info = self.client.get_order_status(self.sl_order_id) try:
if sl_info.get('status') == "FILLED": sl_info = self.client.get_order_status(self.sl_order_id)
fill_price = sl_info.get('filledPrice', sl_info.get('stopPrice', self.params.get('stop_loss'))) if sl_info.get('status') == "FILLED":
self.is_in_position = False fill_price = sl_info.get('filledPrice', sl_info.get('stopPrice', self.params.get('stop_loss')))
return True, "SL Hit", float(fill_price) self.is_in_position = False
return True, "SL Hit", float(fill_price)
except Exception as e:
if "404" in str(e):
if not self._is_ticker_in_portfolio(ticker):
self.is_in_position = False
logger.info(f"SL order {self.sl_order_id} disappeared and position closed. Assuming SL hit.")
return True, "SL Hit", float(self.params.get('stop_loss'))
else:
raise e
except Exception as e: except Exception as e:
logger.error(f"Error checking exit status: {e}") logger.error(f"Error checking exit status: {e}")