fix(okx): cache options balances and stop SSE from hammering exchange API
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -16,6 +16,8 @@ _OKX_OPTION_ERR_ZH: dict[str, str] = {
|
||||
"51019": "期权买入须使用逐仓模式(全仓模式下不能持有多头净头寸)",
|
||||
}
|
||||
|
||||
_OPTIONS_BALANCE_CACHE: dict[str, Any] = {"updated_at": 0.0, "data": None}
|
||||
|
||||
|
||||
def _okx_trade_error_message(exc: BaseException | None = None, resp: Any = None) -> str:
|
||||
row: dict[str, Any] | None = None
|
||||
@@ -199,7 +201,15 @@ def fetch_account_balances_by_type(ex: ccxt.okx, account_type: str) -> dict[str,
|
||||
return out
|
||||
|
||||
|
||||
def fetch_options_balances(ex: ccxt.okx) -> dict[str, Any]:
|
||||
def fetch_options_balances(ex: ccxt.okx, *, force: bool = False) -> dict[str, Any]:
|
||||
import os
|
||||
|
||||
ttl = float(os.getenv("OKX_OPTIONS_BALANCE_REFRESH_SEC", "30"))
|
||||
now = time.time()
|
||||
cached = _OPTIONS_BALANCE_CACHE.get("data")
|
||||
if not force and cached is not None and now - float(_OPTIONS_BALANCE_CACHE.get("updated_at") or 0) < ttl:
|
||||
return dict(cached)
|
||||
|
||||
funding = fetch_account_balances_by_type(ex, "funding")
|
||||
trading = fetch_account_balances_by_type(ex, "trading")
|
||||
# 统一账户部分 USDC 可能在 swap 类型
|
||||
@@ -207,7 +217,7 @@ def fetch_options_balances(ex: ccxt.okx) -> dict[str, Any]:
|
||||
swap_bal = fetch_account_balances_by_type(ex, "swap")
|
||||
if swap_bal.get("USDC") is not None:
|
||||
trading["USDC"] = swap_bal["USDC"]
|
||||
return {
|
||||
result = {
|
||||
"funding_usdt": funding.get("USDT"),
|
||||
"funding_usdc": funding.get("USDC"),
|
||||
"funding_usdg": funding.get("USDG"),
|
||||
@@ -215,6 +225,32 @@ def fetch_options_balances(ex: ccxt.okx) -> dict[str, Any]:
|
||||
"trading_usdc": trading.get("USDC"),
|
||||
"trading_usdg": trading.get("USDG"),
|
||||
}
|
||||
_OPTIONS_BALANCE_CACHE["updated_at"] = now
|
||||
_OPTIONS_BALANCE_CACHE["data"] = result
|
||||
return result
|
||||
|
||||
|
||||
def options_header_balances(
|
||||
ex: ccxt.okx,
|
||||
*,
|
||||
force: bool = False,
|
||||
) -> tuple[float | None, float | None, float | None]:
|
||||
"""顶栏三格:交易 USDC、资金 USDC、资金 USDT(单次拉取 + 缓存)。"""
|
||||
bal = fetch_options_balances(ex, force=force)
|
||||
|
||||
def _round(v: Any) -> float | None:
|
||||
if v is None:
|
||||
return None
|
||||
try:
|
||||
return round(float(v), 2)
|
||||
except (TypeError, ValueError):
|
||||
return None
|
||||
|
||||
return (
|
||||
_round(bal.get("trading_usdc")),
|
||||
_round(bal.get("funding_usdc")),
|
||||
_round(bal.get("funding_usdt")),
|
||||
)
|
||||
|
||||
|
||||
def fetch_index_price(ex: ccxt.okx, uly: str) -> float | None:
|
||||
@@ -525,24 +561,24 @@ def transfer_ccy(
|
||||
_OKX_ACCT_CODE = {"funding": "6", "trading": "18", "spot": "18"}
|
||||
|
||||
|
||||
def fetch_options_trading_usdc(ex: ccxt.okx) -> float | None:
|
||||
bal = fetch_options_balances(ex)
|
||||
def fetch_options_trading_usdc(ex: ccxt.okx, *, force: bool = False) -> float | None:
|
||||
bal = fetch_options_balances(ex, force=force)
|
||||
v = bal.get("trading_usdc")
|
||||
if v is None:
|
||||
return None
|
||||
return round(float(v), 2)
|
||||
|
||||
|
||||
def fetch_options_funding_usdc(ex: ccxt.okx) -> float | None:
|
||||
bal = fetch_options_balances(ex)
|
||||
def fetch_options_funding_usdc(ex: ccxt.okx, *, force: bool = False) -> float | None:
|
||||
bal = fetch_options_balances(ex, force=force)
|
||||
v = bal.get("funding_usdc")
|
||||
if v is None:
|
||||
return None
|
||||
return round(float(v), 2)
|
||||
|
||||
|
||||
def fetch_options_funding_usdt(ex: ccxt.okx) -> float | None:
|
||||
bal = fetch_options_balances(ex)
|
||||
def fetch_options_funding_usdt(ex: ccxt.okx, *, force: bool = False) -> float | None:
|
||||
bal = fetch_options_balances(ex, force=force)
|
||||
v = bal.get("funding_usdt")
|
||||
if v is None:
|
||||
return None
|
||||
|
||||
Reference in New Issue
Block a user