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:
dekun
2026-07-23 02:53:36 +08:00
parent b64c742fc9
commit 0a9e3aa95c
6 changed files with 101 additions and 7 deletions
+45 -3
View File
@@ -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,