Skip to content

Commit 191edbc

Browse files
safe
Signed-off-by: Dinger <quantdinger@gmail.com>
1 parent be615f6 commit 191edbc

1 file changed

Lines changed: 69 additions & 1 deletion

File tree

backend_api_python/app/services/pending_order_worker.py

Lines changed: 69 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -707,7 +707,47 @@ def _sync_positions_best_effort(self, target_strategy_id: Optional[int] = None)
707707
if to_insert:
708708
logger.debug(f"position sync: inserted {len(to_insert)} new positions for strategy_id={sid}")
709709
except Exception as e:
710-
logger.error(f"position sync: strategy_id={sid} failed: {e}", exc_info=True)
710+
# Any exchange auth/config/connectivity fatal errors should stop the strategy to avoid endless spam.
711+
msg = str(e)
712+
m = msg.lower()
713+
is_fatal = any(tok in m for tok in (
714+
# Generic HTTP auth / permission failures
715+
" http 401",
716+
"unauthorized",
717+
"forbidden",
718+
"invalid api",
719+
"invalid api-key",
720+
"invalid api key",
721+
"invalid_key",
722+
"invalid key",
723+
"signature mismatch",
724+
"invalid_signature",
725+
"permission",
726+
# Common connection failures (IBKR/TWS, local gateways)
727+
"connection refused",
728+
"connect call failed",
729+
"errno 111",
730+
))
731+
if is_fatal:
732+
logger.error(f"[PositionSync] Strategy {sid} fatal error; auto-stopping. error={msg}", exc_info=True)
733+
try:
734+
from app.utils.strategy_runtime_logs import append_strategy_log
735+
append_strategy_log(int(sid), "error", f"Auto-stopped: position sync fatal error: {msg}")
736+
except Exception:
737+
pass
738+
try:
739+
with get_db_connection() as db:
740+
cur = db.cursor()
741+
cur.execute(
742+
"UPDATE qd_strategies_trading SET status = 'stopped' WHERE id = %s AND status = 'running'",
743+
(int(sid),),
744+
)
745+
db.commit()
746+
cur.close()
747+
except Exception:
748+
pass
749+
else:
750+
logger.error(f"position sync: strategy_id={sid} failed: {e}", exc_info=True)
711751

712752
def _fetch_pending_orders(self, limit: int = 50) -> List[Dict[str, Any]]:
713753
try:
@@ -2286,6 +2326,34 @@ def _execute_ibkr_order(
22862326
_console_print(f"[worker] IBKR order exception: strategy_id={strategy_id} pending_id={order_id} err={e}")
22872327
_notify_live_best_effort(status="failed", error=str(e))
22882328
append_strategy_log(strategy_id, "error", f"IBKR order exception ({symbol} {signal_type}): {e}")
2329+
# Auto-stop strategy on fatal connectivity issues (e.g. TWS/IBG not reachable).
2330+
try:
2331+
msg = str(e)
2332+
m = msg.lower()
2333+
is_fatal = any(tok in m for tok in (
2334+
"connection refused",
2335+
"connect call failed",
2336+
"errno 111",
2337+
"make sure api port on tws",
2338+
))
2339+
if is_fatal:
2340+
try:
2341+
append_strategy_log(strategy_id, "error", f"Auto-stopped: IBKR connection failed: {msg}")
2342+
except Exception:
2343+
pass
2344+
try:
2345+
with get_db_connection() as db:
2346+
cur = db.cursor()
2347+
cur.execute(
2348+
"UPDATE qd_strategies_trading SET status = 'stopped' WHERE id = %s AND status = 'running'",
2349+
(int(strategy_id),),
2350+
)
2351+
db.commit()
2352+
cur.close()
2353+
except Exception:
2354+
pass
2355+
except Exception:
2356+
pass
22892357

22902358
def _execute_mt5_order(
22912359
self,

0 commit comments

Comments
 (0)