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 <cursoragent@cursor.com>
This commit is contained in:
@@ -55,19 +55,25 @@ class BinanceRestClient:
|
|||||||
return self._exchange_info
|
return self._exchange_info
|
||||||
|
|
||||||
def fetch_option_instruments(self, underlying: str) -> list[dict[str, Any]]:
|
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()
|
info = self.fetch_option_exchange_info()
|
||||||
rows = info.get("optionSymbols") or info.get("symbols") or []
|
rows = info.get("optionSymbols") or info.get("symbols") or []
|
||||||
want = (underlying or "ETHUSDT").strip().upper()
|
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]] = []
|
out: list[dict[str, Any]] = []
|
||||||
for row in rows:
|
for row in rows:
|
||||||
if not isinstance(row, dict):
|
if not isinstance(row, dict):
|
||||||
continue
|
continue
|
||||||
u = str(row.get("underlying") or row.get("underlyingAsset") or "").upper()
|
u = str(row.get("underlying") or row.get("underlyingAsset") or "").upper()
|
||||||
sym = str(row.get("symbol") or "").upper()
|
sym = str(row.get("symbol") or "").upper()
|
||||||
|
# 只收币安格式 ETH-YYMMDD-STRIKE-C/P,避免脏符号进缓存
|
||||||
if eth_mode:
|
if eth_mode:
|
||||||
if sym.startswith("ETH-") or u.startswith("ETH"):
|
if sym.startswith("ETH-") and u.startswith("ETH"):
|
||||||
out.append(row)
|
out.append(row)
|
||||||
continue
|
continue
|
||||||
base = want.replace("USDT", "") if want.endswith("USDT") else want
|
base = want.replace("USDT", "") if want.endswith("USDT") else want
|
||||||
|
|||||||
+5
-1
@@ -30,9 +30,13 @@ def resolve_frontend_dist() -> Path:
|
|||||||
|
|
||||||
@asynccontextmanager
|
@asynccontextmanager
|
||||||
async def lifespan(app: FastAPI):
|
async def lifespan(app: FastAPI):
|
||||||
settings = get_settings()
|
|
||||||
db = Database()
|
db = Database()
|
||||||
set_db(db)
|
set_db(db)
|
||||||
|
# 必须在 set_db 之后读 DB 覆盖,否则会按 .env 默认 okx 起会话,
|
||||||
|
# 而 health 显示 DB 里的 binance → 合约号/盘口错乱(期权一直 -/-)
|
||||||
|
from .exchange.runtime import load_runtime_settings
|
||||||
|
|
||||||
|
settings = load_runtime_settings()
|
||||||
engine = StrategyEngine()
|
engine = StrategyEngine()
|
||||||
set_engine(engine)
|
set_engine(engine)
|
||||||
engine.ensure_loop()
|
engine.ensure_loop()
|
||||||
|
|||||||
@@ -330,10 +330,14 @@ set_gateway = set_session
|
|||||||
|
|
||||||
|
|
||||||
def bootstrap_session(settings: Settings | None = None) -> StrategySession:
|
def bootstrap_session(settings: Settings | None = None) -> StrategySession:
|
||||||
"""main 启动:创建交易所 + 策略会话。"""
|
"""main 启动:创建交易所 + 策略会话。始终以 DB 覆盖后的 runtime 为准。"""
|
||||||
from ..exchange.runtime import load_runtime_settings
|
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)
|
ex = build_exchange(s)
|
||||||
set_exchange(ex)
|
set_exchange(ex)
|
||||||
sess = StrategySession(s, ex)
|
sess = StrategySession(s, ex)
|
||||||
|
|||||||
@@ -57,3 +57,35 @@ def test_normalize_exchange() -> None:
|
|||||||
assert normalize_exchange_name("BN") == "binance"
|
assert normalize_exchange_name("BN") == "binance"
|
||||||
assert normalize_exchange_name("okx") == "okx"
|
assert normalize_exchange_name("okx") == "okx"
|
||||||
assert normalize_exchange_name(None) == "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"
|
||||||
|
|||||||
Reference in New Issue
Block a user