Add READ_ONLY_API environment variable and enhance trading error handling
This commit is contained in:
@@ -24,13 +24,66 @@ class ChartState:
|
||||
def __init__(self):
|
||||
self.latest_tick = None
|
||||
self.current_ticker = None
|
||||
self.current_symbol = None
|
||||
self.current_minute = None
|
||||
self.current_ohlc = None
|
||||
self.history_poll_task = None
|
||||
self.last_realtime_update = 0.0
|
||||
|
||||
|
||||
chart_state = ChartState()
|
||||
|
||||
|
||||
async def _stop_history_poll_task() -> None:
|
||||
task = chart_state.history_poll_task
|
||||
chart_state.history_poll_task = None
|
||||
if task is None or task.done():
|
||||
return
|
||||
task.cancel()
|
||||
try:
|
||||
await task
|
||||
except asyncio.CancelledError:
|
||||
pass
|
||||
|
||||
|
||||
async def _history_fallback_loop(symbol: str, contract) -> None:
|
||||
ib = dependencies.get_ib()
|
||||
try:
|
||||
while chart_state.current_symbol == symbol:
|
||||
# Only fall back when real-time bars have not updated recently.
|
||||
if chart_state.last_realtime_update and (
|
||||
time.monotonic() - chart_state.last_realtime_update
|
||||
) < 20:
|
||||
await asyncio.sleep(15)
|
||||
continue
|
||||
|
||||
try:
|
||||
bars = await ib.reqHistoricalDataAsync(
|
||||
contract,
|
||||
endDateTime="",
|
||||
durationStr="1 D",
|
||||
barSizeSetting="1 min",
|
||||
whatToShow="TRADES",
|
||||
useRTH=True,
|
||||
formatDate=1,
|
||||
)
|
||||
if bars:
|
||||
last_bar = bars[-1]
|
||||
chart_state.latest_tick = {
|
||||
"time": int(last_bar.date.timestamp()),
|
||||
"open": last_bar.open,
|
||||
"high": last_bar.high,
|
||||
"low": last_bar.low,
|
||||
"close": last_bar.close,
|
||||
}
|
||||
except Exception as exc:
|
||||
logger.warning(f"Historical fallback update failed for {symbol}: {exc}")
|
||||
|
||||
await asyncio.sleep(15)
|
||||
except asyncio.CancelledError:
|
||||
pass
|
||||
|
||||
|
||||
@router.get("/", response_class=HTMLResponse)
|
||||
async def index(request: Request, symbol: str = ""):
|
||||
return templates.TemplateResponse(request, "index.html", {"symbol": symbol})
|
||||
@@ -115,8 +168,13 @@ async def subscribe(request: Request):
|
||||
except Exception as e:
|
||||
print(f"Error cancelling real-time bars: {e}")
|
||||
|
||||
await _stop_history_poll_task()
|
||||
|
||||
chart_state.current_symbol = symbol
|
||||
chart_state.latest_tick = None
|
||||
chart_state.current_minute = None
|
||||
chart_state.current_ohlc = None
|
||||
chart_state.last_realtime_update = 0.0
|
||||
|
||||
ticker = ib.reqRealTimeBars(qualified[0], barSize=5, whatToShow="TRADES", useRTH=True)
|
||||
chart_state.current_ticker = ticker
|
||||
@@ -152,9 +210,13 @@ async def subscribe(request: Request):
|
||||
"close": bar.close,
|
||||
}
|
||||
|
||||
chart_state.last_realtime_update = time.monotonic()
|
||||
chart_state.latest_tick = chart_state.current_ohlc.copy()
|
||||
|
||||
ticker.updateEvent += on_bar
|
||||
chart_state.history_poll_task = asyncio.create_task(
|
||||
_history_fallback_loop(symbol, qualified[0])
|
||||
)
|
||||
|
||||
return {"status": "ok", "symbol": symbol}
|
||||
except Exception as e:
|
||||
|
||||
Reference in New Issue
Block a user