"""hub_ohlcv_lib:分页拉取(Gate 等单次不足 chunk 时仍继续)。""" from __future__ import annotations import unittest from hub_ohlcv_lib import fetch_ohlcv_for_hub class _FakeExchange: def __init__(self, pages): self.pages = list(pages) self.calls = [] self.markets = {} def fetch_ohlcv(self, symbol, timeframe=None, since=None, limit=None): self.calls.append({"symbol": symbol, "since": since, "limit": limit}) if not self.pages: return [] page = self.pages.pop(0) return [b for b in page if b[0] >= since] if since else page class TestHubOhlcvLib(unittest.TestCase): def test_pagination_continues_when_page_smaller_than_chunk(self): """Gate 等常返回 299 根/次,不应误判为已到末尾。""" base = 1_700_000_000_000 step = 4 * 60 * 60 * 1000 page1 = [ [base + i * step, 1.0, 1.1, 0.9, 1.05, 100.0] for i in range(299) ] page2 = [ [base + (299 + i) * step, 2.0, 2.1, 1.9, 2.05, 200.0] for i in range(299) ] page3 = [ [base + (598 + i) * step, 3.0, 3.1, 2.9, 3.05, 300.0] for i in range(50) ] ex = _FakeExchange([page1, page2, page3]) out = fetch_ohlcv_for_hub( symbol="INJ/USDT", timeframe="4h", since_ms=base, limit=600, normalize_symbol_input=lambda s: str(s).strip().upper(), normalize_exchange_symbol=lambda s: f"{s}:USDT" if ":" not in s else s, ensure_markets_loaded=lambda: None, exchange=ex, ) self.assertTrue(out.get("ok")) self.assertEqual(len(out.get("bars") or []), 600) self.assertGreaterEqual(len(ex.calls), 3) self.assertAlmostEqual(out["bars"][-1]["close"], 3.05) if __name__ == "__main__": unittest.main()