diff --git a/docs/振幅统计说明.md b/docs/振幅统计说明.md index 4ed6d23..a29538a 100644 --- a/docs/振幅统计说明.md +++ b/docs/振幅统计说明.md @@ -51,7 +51,8 @@ 汇总必含:最大振幅(及日期)、开→高/开→低的最大与均值等。 -K 线粒度:**1H**(与整点对齐);价源优先 OKX 指数(ETH-USD / BTC-USD),失败再降级永续标记。 +K 线粒度:**1H**(与整点对齐);价源优先 OKX 指数(ETH-USD / BTC-USD),失败再降级永续标记。 +近期 K 线接口约仅 **1440** 根(1H≈60 天);更长周期自动续拉 `history-index-candles` / `history-candles`。 --- @@ -106,3 +107,4 @@ K 线粒度:**1H**(与整点对齐);价源优先 OKX 指数(ETH-USD / | 2026-07-23 | 首版上线说明 | | 2026-07-23 | 买跨对照:可设双边权利金、越过占比与收盘盈亏 | | 2026-07-23 | 周末筛选/标注、止盈点(≥)、日表收益列 | +| 2026-07-23 | 长周期续拉 history K 线;收益列红绿着色 | diff --git a/lib/hub/amp_stats_lib.py b/lib/hub/amp_stats_lib.py index 7e13c5c..4b349d3 100644 --- a/lib/hub/amp_stats_lib.py +++ b/lib/hub/amp_stats_lib.py @@ -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, diff --git a/manual_trading_hub/static/amp_stats.js b/manual_trading_hub/static/amp_stats.js index 6707f38..2c7a179 100644 --- a/manual_trading_hub/static/amp_stats.js +++ b/manual_trading_hub/static/amp_stats.js @@ -178,7 +178,7 @@ const profit = r.profit == null || r.profit === "" ? "—" - : `${esc(r.profit)}`; + : `${esc(r.profit)}`; const trClass = r.is_weekend ? ' class="amp-row-weekend"' : ""; return ( `