Add Binance live trading, anti-stuck open/close recovery, and configurable rate limits.
OKX/Binance LIVE share half_open and option_closed_perp_pending repair paths; private REST throttles default to 1s and are tunable in settings. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -15,6 +15,7 @@ import httpx
|
||||
|
||||
from ..config import Settings, get_settings
|
||||
from ..exchange.okx.parse import safe_float
|
||||
from .rate_limit import RateLimitError, get_throttle, parse_retry_after_header
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -41,6 +42,7 @@ class OkxTradeClient:
|
||||
headers={"Accept": "application/json", "User-Agent": "eth-hedge-live/0.1"},
|
||||
)
|
||||
self._ct_val_cache: dict[str, float] = {}
|
||||
self._throttle = get_throttle("okx_trade", min_interval_sec=1.0)
|
||||
|
||||
def close(self) -> None:
|
||||
self._client.close()
|
||||
@@ -70,6 +72,7 @@ class OkxTradeClient:
|
||||
def _request(
|
||||
self, method: str, path: str, body: dict[str, Any] | None = None
|
||||
) -> list[dict[str, Any]]:
|
||||
self._throttle.before_request()
|
||||
payload = "" if body is None else json.dumps(body, separators=(",", ":"))
|
||||
ts = self._ts()
|
||||
sign = self._sign(ts, method, path, payload)
|
||||
@@ -78,11 +81,31 @@ class OkxTradeClient:
|
||||
r = self._client.get(path, headers=headers)
|
||||
else:
|
||||
r = self._client.request(method.upper(), path, content=payload, headers=headers)
|
||||
r.raise_for_status()
|
||||
if r.status_code in (418, 429):
|
||||
ra = parse_retry_after_header(r.headers)
|
||||
self._throttle.mark_http(r.status_code, ra)
|
||||
raise RateLimitError(
|
||||
f"OKX HTTP {r.status_code}: {r.text[:200]}",
|
||||
retry_after=self._throttle.remaining_cooldown(),
|
||||
)
|
||||
try:
|
||||
r.raise_for_status()
|
||||
except httpx.HTTPStatusError as e:
|
||||
raise RuntimeError(f"OKX HTTP {r.status_code}: {r.text[:300]}") from e
|
||||
data = r.json()
|
||||
if str(data.get("code")) != "0":
|
||||
code = str(data.get("code") or "")
|
||||
msg = str(data.get("msg") or "")
|
||||
# OKX 业务层频率类错误
|
||||
if code != "0":
|
||||
low = f"{code} {msg}".lower()
|
||||
if code in ("50011", "50061") or "too many" in low or "频率" in msg:
|
||||
self._throttle.mark_seconds(20.0)
|
||||
raise RateLimitError(
|
||||
f"OKX trade rate-limited code={code} msg={msg}",
|
||||
retry_after=self._throttle.remaining_cooldown(),
|
||||
)
|
||||
raise RuntimeError(
|
||||
f"OKX trade error code={data.get('code')} msg={data.get('msg')} data={data.get('data')}"
|
||||
f"OKX trade error code={code} msg={msg} data={data.get('data')}"
|
||||
)
|
||||
rows = data.get("data") or []
|
||||
return [x for x in rows if isinstance(x, dict)]
|
||||
|
||||
Reference in New Issue
Block a user