Files
tick-stock-panel/backend/tests/test_enriched_partial_partition.py
T
shy3130 e89ea9becf fix: 修复 4 个 P1 issue (#224/#232/#223/#215)
- #224 screener 自定义 SQL 的内存连接关闭 enable_external_access,
  注入的 read_parquet/COPY 文件读写直接报错 (安全)
- #232 指数展示缓存百分数口径在消费边界显式 /100:
  pipeline._bench_rt_pct_of 与 abnormal_moves._bench_rt_pct 两处,
  修复 3/10/30 日偏离值被放大两个数量级
- #223 盘后管道按同日 daily/enriched 行数比较检测实时合并提前
  创建的部分分区, 删除后由增量重算全市场补齐
- #215 _basic_filter_for_asset 扩展中和股票专属键 (price_min/max/boards),
  并应用到回测/挖掘/策略扫描三个运行期入口, 修复 ETF 静默零信号
2026-09-03 13:01:43 +08:00

63 lines
2.5 KiB
Python

"""#223 回归: 盘后管道必须识别并重算覆盖不全的 enriched 分区。
自选实时路径 (merge_live_enriched_asset) 会在全市场 enriched 生成前提前
创建当日分区 (只有几只自选); 仅按日期目录计数比较会把它误判为完整分区
而跳过计算, 造成日K连续缺失与均线错误。_prune_partial_enriched_partitions
按同日 daily/enriched 行数比较, 发现部分分区即删除, 让增量重算按"新日期"
全市场补齐。
"""
from __future__ import annotations
from datetime import date
from pathlib import Path
import polars as pl
from app.jobs.daily_pipeline import _prune_partial_enriched_partitions
def _write_partition(base: Path, day: str, symbols: list[str]) -> None:
part = base / f"date={day}"
part.mkdir(parents=True, exist_ok=True)
pl.DataFrame({"symbol": symbols, "close": [1.0] * len(symbols)}).write_parquet(
part / "part.parquet"
)
def test_partial_partition_is_pruned(tmp_path) -> None:
daily = tmp_path / "kline_daily"
enriched = tmp_path / "kline_daily_enriched"
# 2026-08-28: daily 全市场 100 只, enriched 只有实时写入的 5 只 (issue 实测形态)
_write_partition(daily, "2026-08-28", [f"s{i:06d}" for i in range(100)])
_write_partition(enriched, "2026-08-28", [f"s{i:06d}" for i in range(5)])
# 前一日两边都是完整的 → 不动
_write_partition(daily, "2026-08-27", ["a", "b"])
_write_partition(enriched, "2026-08-27", ["a", "b"])
pruned = _prune_partial_enriched_partitions(daily, enriched)
assert pruned == ["2026-08-28"]
assert not (enriched / "date=2026-08-28").exists()
assert (enriched / "date=2026-08-27").exists() # 完整分区保留
def test_complete_partitions_untouched(tmp_path) -> None:
daily = tmp_path / "kline_daily"
enriched = tmp_path / "kline_daily_enriched"
syms = [f"s{i:06d}" for i in range(50)]
_write_partition(daily, "2026-09-01", syms)
_write_partition(enriched, "2026-09-01", syms)
assert _prune_partial_enriched_partitions(daily, enriched) == []
assert (enriched / "date=2026-09-01" / "part.parquet").exists()
def test_enriched_date_without_daily_is_left_alone(tmp_path) -> None:
# 今日日K尚未同步时, 实时创建的当日分区留给当日正常流程处理
daily = tmp_path / "kline_daily"
enriched = tmp_path / "kline_daily_enriched"
_write_partition(enriched, str(date.today()), ["only_watchlist"])
assert _prune_partial_enriched_partitions(daily, enriched) == []
assert (enriched / f"date={date.today()}").exists()