Fix amp-stats long-range candles via OKX history endpoints.
Recent candles cap near 60d; continue with history-index/history candles and color profit green/red. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -40,7 +40,9 @@ PERIOD_DAYS: dict[str, int] = {
|
||||
}
|
||||
|
||||
OKX_INDEX_CANDLES = "https://www.okx.com/api/v5/market/index-candles"
|
||||
OKX_HISTORY_INDEX_CANDLES = "https://www.okx.com/api/v5/market/history-index-candles"
|
||||
OKX_SWAP_CANDLES = "https://www.okx.com/api/v5/market/candles"
|
||||
OKX_HISTORY_SWAP_CANDLES = "https://www.okx.com/api/v5/market/history-candles"
|
||||
|
||||
|
||||
def normalize_symbol(raw: str) -> str:
|
||||
@@ -408,8 +410,13 @@ def fetch_okx_candles(
|
||||
bar: str = "1H",
|
||||
client: Optional[httpx.Client] = None,
|
||||
timeout: float = 30.0,
|
||||
history_url: Optional[str] = None,
|
||||
max_pages: int = 200,
|
||||
) -> list[dict[str, Any]]:
|
||||
"""拉取 [since_ms, until_ms] 覆盖的 K 线(含边界).OKX 返回新→旧."""
|
||||
"""拉取 [since_ms, until_ms] 覆盖的 K 线(含边界).
|
||||
|
||||
OKX 近期接口约仅 1440 根;更早需 history_* 端点续拉.
|
||||
"""
|
||||
own = client is None
|
||||
client = client or httpx.Client(
|
||||
timeout=timeout,
|
||||
@@ -419,25 +426,42 @@ def fetch_okx_candles(
|
||||
try:
|
||||
out: dict[int, dict[str, Any]] = {}
|
||||
after: Optional[str] = None
|
||||
for _ in range(80):
|
||||
active_url = url
|
||||
switched_history = False
|
||||
empty_streak = 0
|
||||
for _ in range(max(20, int(max_pages))):
|
||||
params: dict[str, str] = {"instId": inst_id, "bar": bar, "limit": "100"}
|
||||
if after:
|
||||
params["after"] = after
|
||||
r = client.get(url, params=params)
|
||||
r = client.get(active_url, params=params)
|
||||
r.raise_for_status()
|
||||
body = r.json()
|
||||
if str(body.get("code") or "") not in ("0", "0.0", ""):
|
||||
raise RuntimeError(body.get("msg") or f"OKX error {body.get('code')}")
|
||||
data = body.get("data") or []
|
||||
if not data:
|
||||
empty_streak += 1
|
||||
# 近期接口到头 → 切历史端点再试
|
||||
if (
|
||||
history_url
|
||||
and not switched_history
|
||||
and after is not None
|
||||
):
|
||||
active_url = history_url
|
||||
switched_history = True
|
||||
empty_streak = 0
|
||||
continue
|
||||
break
|
||||
empty_streak = 0
|
||||
oldest_ts = None
|
||||
newest_in_page = None
|
||||
for row in data:
|
||||
parsed = _parse_okx_candle_row(row)
|
||||
if not parsed:
|
||||
continue
|
||||
ts = int(parsed["ts"])
|
||||
oldest_ts = ts if oldest_ts is None else min(oldest_ts, ts)
|
||||
newest_in_page = ts if newest_in_page is None else max(newest_in_page, ts)
|
||||
if ts < since_ms - 3600 * 1000:
|
||||
continue
|
||||
if ts > until_ms + 3600 * 1000:
|
||||
@@ -447,7 +471,23 @@ def fetch_okx_candles(
|
||||
break
|
||||
if oldest_ts <= since_ms:
|
||||
break
|
||||
# 无新进度时避免死循环
|
||||
if after is not None and str(oldest_ts) == after:
|
||||
if history_url and not switched_history:
|
||||
active_url = history_url
|
||||
switched_history = True
|
||||
continue
|
||||
break
|
||||
after = str(oldest_ts)
|
||||
# 近期接口返回变少且仍未覆盖 since → 切历史
|
||||
if (
|
||||
history_url
|
||||
and not switched_history
|
||||
and len(data) < 100
|
||||
and oldest_ts > since_ms
|
||||
):
|
||||
active_url = history_url
|
||||
switched_history = True
|
||||
return [out[k] for k in sorted(out.keys())]
|
||||
finally:
|
||||
if own:
|
||||
@@ -471,6 +511,7 @@ def fetch_symbol_bars(
|
||||
try:
|
||||
bars = fetch_okx_candles(
|
||||
url=OKX_INDEX_CANDLES,
|
||||
history_url=OKX_HISTORY_INDEX_CANDLES,
|
||||
inst_id=meta["index_inst"],
|
||||
since_ms=since_ms,
|
||||
until_ms=until_ms,
|
||||
@@ -482,6 +523,7 @@ def fetch_symbol_bars(
|
||||
|
||||
bars = fetch_okx_candles(
|
||||
url=OKX_SWAP_CANDLES,
|
||||
history_url=OKX_HISTORY_SWAP_CANDLES,
|
||||
inst_id=meta["swap_inst"],
|
||||
since_ms=since_ms,
|
||||
until_ms=until_ms,
|
||||
|
||||
Reference in New Issue
Block a user