From 586469482e3229ef2a436c6d0021554e0c0bfc72 Mon Sep 17 00:00:00 2001 From: dekun Date: Sat, 25 Jul 2026 12:13:19 +0800 Subject: [PATCH] Fix Binance boot using OKX symbols after restart. Startup ignored DB exchange choice and kept OKX ATM ids under a Binance health label, so option bid/ask stayed empty. Co-authored-by: Cursor --- backend/app/exchange/binance/rest.py | 12 ++++++++--- backend/app/main.py | 6 +++++- backend/app/strategy/session.py | 8 +++++-- backend/tests/test_binance_parse.py | 32 ++++++++++++++++++++++++++++ 4 files changed, 52 insertions(+), 6 deletions(-) diff --git a/backend/app/exchange/binance/rest.py b/backend/app/exchange/binance/rest.py index cf99226..d991da4 100644 --- a/backend/app/exchange/binance/rest.py +++ b/backend/app/exchange/binance/rest.py @@ -55,19 +55,25 @@ class BinanceRestClient: return self._exchange_info def fetch_option_instruments(self, underlying: str) -> list[dict[str, Any]]: - """underlying 如 ETH / ETHUSDT。""" + """underlying 如 ETH / ETHUSDT。误传 OKX family(ETH-USD_UM)时映射到 ETHUSDT。""" info = self.fetch_option_exchange_info() rows = info.get("optionSymbols") or info.get("symbols") or [] want = (underlying or "ETHUSDT").strip().upper() - eth_mode = want in ("ETH", "ETHUSDT") or want.startswith("ETH") + # 兼容误用 OKX 期权族名 + if "USD_UM" in want or want in ("ETH-USD", "ETH-USDT", "ETHUSD"): + want = "ETHUSDT" + eth_mode = want in ("ETH", "ETHUSDT") or ( + want.startswith("ETH") and "-" not in want + ) out: list[dict[str, Any]] = [] for row in rows: if not isinstance(row, dict): continue u = str(row.get("underlying") or row.get("underlyingAsset") or "").upper() sym = str(row.get("symbol") or "").upper() + # 只收币安格式 ETH-YYMMDD-STRIKE-C/P,避免脏符号进缓存 if eth_mode: - if sym.startswith("ETH-") or u.startswith("ETH"): + if sym.startswith("ETH-") and u.startswith("ETH"): out.append(row) continue base = want.replace("USDT", "") if want.endswith("USDT") else want diff --git a/backend/app/main.py b/backend/app/main.py index 632a4f7..4f5d8df 100644 --- a/backend/app/main.py +++ b/backend/app/main.py @@ -30,9 +30,13 @@ def resolve_frontend_dist() -> Path: @asynccontextmanager async def lifespan(app: FastAPI): - settings = get_settings() db = Database() set_db(db) + # 必须在 set_db 之后读 DB 覆盖,否则会按 .env 默认 okx 起会话, + # 而 health 显示 DB 里的 binance → 合约号/盘口错乱(期权一直 -/-) + from .exchange.runtime import load_runtime_settings + + settings = load_runtime_settings() engine = StrategyEngine() set_engine(engine) engine.ensure_loop() diff --git a/backend/app/strategy/session.py b/backend/app/strategy/session.py index a8b841d..0b38389 100644 --- a/backend/app/strategy/session.py +++ b/backend/app/strategy/session.py @@ -330,10 +330,14 @@ set_gateway = set_session def bootstrap_session(settings: Settings | None = None) -> StrategySession: - """main 启动:创建交易所 + 策略会话。""" + """main 启动:创建交易所 + 策略会话。始终以 DB 覆盖后的 runtime 为准。""" from ..exchange.runtime import load_runtime_settings - s = settings or load_runtime_settings() + # 忽略裸 get_settings():重启后必须跟 DB 里选的交易所一致 + try: + s = load_runtime_settings() + except Exception: + s = settings or get_settings() ex = build_exchange(s) set_exchange(ex) sess = StrategySession(s, ex) diff --git a/backend/tests/test_binance_parse.py b/backend/tests/test_binance_parse.py index 2042e53..80b4d55 100644 --- a/backend/tests/test_binance_parse.py +++ b/backend/tests/test_binance_parse.py @@ -57,3 +57,35 @@ def test_normalize_exchange() -> None: assert normalize_exchange_name("BN") == "binance" assert normalize_exchange_name("okx") == "okx" assert normalize_exchange_name(None) == "okx" + + +def test_binance_maps_okx_family_name() -> None: + """误传 OKX family 时不应按 startswith(ETH) 乱匹配,应映射到 ETHUSDT。""" + from app.exchange.binance.rest import BinanceRestClient + + cli = BinanceRestClient.__new__(BinanceRestClient) + cli._exchange_info = { + "optionSymbols": [ + { + "symbol": "ETH-260726-1860-C", + "underlying": "ETHUSDT", + "status": "TRADING", + "strikePrice": "1860", + "side": "CALL", + "expiryDate": 1785052800000, + "unit": "1", + }, + { + "symbol": "BTC-260726-100000-C", + "underlying": "BTCUSDT", + "status": "TRADING", + "strikePrice": "100000", + "side": "CALL", + "expiryDate": 1785052800000, + "unit": "1", + }, + ] + } + rows = BinanceRestClient.fetch_option_instruments(cli, "ETH-USD_UM") + assert len(rows) == 1 + assert rows[0]["symbol"] == "ETH-260726-1860-C"