Throttle Binance eapi REST to avoid 429 on Plan snapshot polls.
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -3,6 +3,7 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import logging
|
||||
import time
|
||||
from typing import Any, Sequence
|
||||
|
||||
from ...config import Settings, get_settings
|
||||
@@ -14,6 +15,9 @@ from .ws import BinancePublicWs
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
# snapshot 轮询勿每 1.5s 打 REST;缺盘口时最少间隔再补
|
||||
_REST_FILL_MIN_INTERVAL_SEC = 5.0
|
||||
|
||||
|
||||
class BinanceExchange:
|
||||
name = "binance"
|
||||
@@ -39,6 +43,7 @@ class BinanceExchange:
|
||||
)
|
||||
self._started = False
|
||||
self._ct_cache: dict[str, float] = {}
|
||||
self._rest_fill_at: dict[str, float] = {}
|
||||
|
||||
async def start(self) -> None:
|
||||
if self._started:
|
||||
@@ -91,19 +96,23 @@ class BinanceExchange:
|
||||
logger.warning("binance warm book empty: %s", inst)
|
||||
except Exception as e:
|
||||
logger.warning("binance warm book %s failed: %s", inst, e)
|
||||
try:
|
||||
mp = self.rest.fetch_mark(inst)
|
||||
if mp:
|
||||
self.cache.set_mark_px(inst, mp)
|
||||
except Exception:
|
||||
pass
|
||||
# 指数
|
||||
# 期权 mark 易触发 eapi 限流;有盘口即可,永续再拉 mark
|
||||
from .parse import is_option_symbol
|
||||
|
||||
if not is_option_symbol(inst):
|
||||
try:
|
||||
mp = self.rest.fetch_mark(inst)
|
||||
if mp:
|
||||
self.cache.set_mark_px(inst, mp)
|
||||
except Exception:
|
||||
pass
|
||||
# 指数(失败则跳过,勿连环打 eapi)
|
||||
try:
|
||||
idx = self.rest.fetch_index(self.settings.index_inst_id)
|
||||
if idx:
|
||||
self.cache.set_index_px(idx)
|
||||
except Exception as e:
|
||||
logger.warning("binance index failed: %s", e)
|
||||
logger.debug("binance index failed: %s", e)
|
||||
keep = set(ids)
|
||||
self.cache.drop_except(keep)
|
||||
self.ws.set_instruments(ids)
|
||||
@@ -115,11 +124,17 @@ class BinanceExchange:
|
||||
return self.cache.get(inst_id)
|
||||
|
||||
def _refresh_quote_if_stale(self, inst_id: str) -> None:
|
||||
"""仅在买卖一都缺失时补 REST,且有最短间隔,避免 429。"""
|
||||
if not inst_id:
|
||||
return
|
||||
q = self.cache.get(inst_id)
|
||||
if q is not None and (q.bid is not None or q.ask is not None):
|
||||
if q is not None and q.bid is not None and q.ask is not None:
|
||||
return
|
||||
now = time.monotonic()
|
||||
last = self._rest_fill_at.get(inst_id, 0.0)
|
||||
if now - last < _REST_FILL_MIN_INTERVAL_SEC:
|
||||
return
|
||||
self._rest_fill_at[inst_id] = now
|
||||
try:
|
||||
bids, asks, ts = self.rest.fetch_books(inst_id, sz=10)
|
||||
if bids or asks:
|
||||
@@ -128,11 +143,10 @@ class BinanceExchange:
|
||||
logger.debug("binance refresh quote %s: %s", inst_id, e)
|
||||
|
||||
def snapshot(self, perp_inst_id: str) -> MarketSnapshot:
|
||||
# 期权 WS 偶发无推送时,用 REST/ticker 补买卖一,避免 UI 一直是 -
|
||||
# 优先吃 WS 缓存;仅缺盘口时低频 REST 补齐
|
||||
self._refresh_quote_if_stale(perp_inst_id)
|
||||
pair = None
|
||||
try:
|
||||
# BookCache 无公开 getter;从 snapshot 前先按 pair 刷新
|
||||
with self.cache._lock: # noqa: SLF001
|
||||
pair = self.cache._pair
|
||||
except Exception:
|
||||
|
||||
Reference in New Issue
Block a user