Add READ_ONLY_API environment variable and enhance trading error handling
This commit is contained in:
+44
-1
@@ -4,7 +4,7 @@ import os
|
||||
from datetime import datetime, timezone
|
||||
|
||||
from fastapi import APIRouter, HTTPException, Request
|
||||
from fastapi.responses import HTMLResponse
|
||||
from fastapi.responses import HTMLResponse, JSONResponse
|
||||
from fastapi.templating import Jinja2Templates
|
||||
from ib_async import LimitOrder, MarketOrder, Stock
|
||||
|
||||
@@ -34,6 +34,18 @@ def log_trade(symbol, action, quantity, price, cursor, conn, lock):
|
||||
logger.info(f"Logged trade: {action} {quantity} {symbol} @ ${price:.2f}")
|
||||
|
||||
|
||||
def _latest_trade_message(trade) -> str:
|
||||
for entry in reversed(getattr(trade, "log", []) or []):
|
||||
message = getattr(entry, "message", "")
|
||||
if message:
|
||||
return message
|
||||
return ""
|
||||
|
||||
|
||||
def _normalized_trade_status(trade) -> str:
|
||||
return (getattr(getattr(trade, "orderStatus", None), "status", "") or "").strip()
|
||||
|
||||
|
||||
@router.get("/tradelog", response_class=HTMLResponse)
|
||||
async def tradelog(request: Request):
|
||||
cursor = dependencies.get_db_cursor()
|
||||
@@ -145,9 +157,40 @@ async def webhook(request: Request):
|
||||
primary_trade = trades_list[0]
|
||||
for _ in range(60):
|
||||
await asyncio.sleep(0.5)
|
||||
status = _normalized_trade_status(primary_trade)
|
||||
if status in {"ValidationError", "Cancelled", "ApiCancelled", "Inactive"}:
|
||||
break
|
||||
if primary_trade.isDone():
|
||||
break
|
||||
|
||||
status = _normalized_trade_status(primary_trade)
|
||||
if status == "ValidationError":
|
||||
for t in trades_list:
|
||||
try:
|
||||
ib.cancelOrder(t.order)
|
||||
except Exception:
|
||||
pass
|
||||
detail = _latest_trade_message(primary_trade) or "Order was rejected by IBKR"
|
||||
raise HTTPException(status_code=409, detail=detail)
|
||||
|
||||
if status in {"Cancelled", "ApiCancelled", "Inactive"} and not primary_trade.fills:
|
||||
detail = _latest_trade_message(primary_trade) or f"Order became {status}"
|
||||
raise HTTPException(status_code=409, detail=detail)
|
||||
|
||||
if status in {"PendingSubmit", "PreSubmitted", "Submitted"} and not primary_trade.fills:
|
||||
return JSONResponse(
|
||||
status_code=202,
|
||||
content={
|
||||
"status": "accepted",
|
||||
"symbol": symbol,
|
||||
"action": action,
|
||||
"quantity": quantity,
|
||||
"order_type": order_type,
|
||||
"order_status": status,
|
||||
"message": _latest_trade_message(primary_trade),
|
||||
},
|
||||
)
|
||||
|
||||
if not primary_trade.isDone() or not primary_trade.fills:
|
||||
for t in trades_list:
|
||||
try:
|
||||
|
||||
Reference in New Issue
Block a user