diff --git a/app/services/tech_service.py b/app/services/tech_service.py index 10b04f2..c9164b4 100644 --- a/app/services/tech_service.py +++ b/app/services/tech_service.py @@ -30,7 +30,7 @@ logger = logging.getLogger("pms.tech") MAP_KEY = "PMS_TECH_STATE_MAP" FRESH_DAYS = 3 # 映射超过这么多自然日没刷新就当没读数 (调度断了不拿旧态拦人) DEFAULT_PATH = "/api/v1/market/technical" -PAGE_SIZE = 1500 # 分页每页条数 (全市场约 5000, 三四页取完) +PAGE_SIZE = 1000 # 分页每页条数 (接口 limit 上限实测 1000, 设成一样避免误判最后一页) MAX_PAGES = 20 # 防呆: 分页硬上限 @@ -187,9 +187,14 @@ def fetch_all_pages(*, base=None, path=None, timeout=None, page_size=PAGE_SIZE, pages += 1 got = len(items) offset += got - if got < page_size: # 最后一页 + if got == 0: # 空页, 到底了 break - if matched and offset >= matched: # 够了 (服务端若忽略 limit 也在这里收住) + if matched is not None and offset >= matched: # 拉够 matched 只 + break + # 不能用 got < page_size 判最后一页: 接口 limit 上限可能小于 page_size, 那样每页都返回 + # 上限条数、got 恒小于 page_size, 第一页就误判成最后一页 (2026-09-11 真机: 上限 1000、 + # matched 4991, 旧逻辑只落了 1000/4991)。matched 缺失时才退回用 got 判, 另有 MAX_PAGES 兜底。 + if matched is None and got < page_size: break return {"status": "OK", "data_date": data_date, "algo_version": algo, "rows": rows, "pages": pages, "total": len(rows), "matched": matched} diff --git a/scripts/test_batch27_units.py b/scripts/test_batch27_units.py index af57b68..fd632f9 100644 --- a/scripts/test_batch27_units.py +++ b/scripts/test_batch27_units.py @@ -219,6 +219,19 @@ def test_fetch_pages(): pass +@case("C fetch_all_pages: 接口每页上限小于页大小时按 matched 拉完多页(2026-09-11 真机抓到)") +def test_fetch_pages_capped(): + # 接口每页最多给 2 条(上限),page_size 传 5,matched 5 → 要拉 3 页 (2+2+1),不能第一页就停 + def f(url, params, timeout): + off = params["offset"] + n = min(2, max(0, 5 - off)) + items = [{"stock_code": "SH60000%d" % (off + i), "sar": {"side": "多"}, + "reanchored": True, "quality": "OK", "boll": {"pos": 0.5}} for i in range(n)] + return {"status": "OK", "data_date": 20260910, "matched": 5, "items": items} + got = ts.fetch_all_pages(base="x", path="/y", timeout=5, page_size=5, fetch=f) + assert got["total"] == 5 and got["pages"] == 3, got + + # ================================================================ D 映射 @case("D build_map: 正常合成, 只覆盖有当天读数的相关票") def test_build_map_ok():