From 349ff3062e65682a537be4aa4a9490fb68ab3581 Mon Sep 17 00:00:00 2001 From: shy3130 <415333856@qq.com> Date: Tue, 23 Jun 2026 11:55:58 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=20AI=20=E7=AD=96=E7=95=A5?= =?UTF-8?q?=E5=9B=9E=E6=B5=8B=E6=97=A0=E4=BF=A1=E5=8F=B7=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - filter_history 模板去掉 latest 过滤: 选股/回测期望不同, 选股自动取 as_of 日 - 涨跌停类信号(signal_limit_up 等)标注依赖 instruments 表, 部分环境不生成 - 指南加提示: 涨停判断优先用 consecutive_limit_ups 或 change_pct --- docs/strategy-builder-step1.md | 4 ++-- docs/strategy-guide.md | 20 +++++++++++--------- 2 files changed, 13 insertions(+), 11 deletions(-) diff --git a/docs/strategy-builder-step1.md b/docs/strategy-builder-step1.md index 9d62891..a7510b8 100644 --- a/docs/strategy-builder-step1.md +++ b/docs/strategy-builder-step1.md @@ -146,8 +146,8 @@ def filter_history(df: pl.DataFrame, params: dict) -> pl.DataFrame: if df.is_empty() or "date" not in df.columns: return df - latest = df["date"].max() # 用 shift/over 回溯历史数据,或用 group_by 计算窗口聚合 + # 重要: 返回所有匹配行,不要只过滤 latest,否则回测只有最后一天有信号 hist = ( df.sort(["symbol", "date"]) .with_columns([ @@ -155,7 +155,7 @@ def filter_history(df: pl.DataFrame, params: dict) -> pl.DataFrame: # ... 根据策略需要添加更多回溯列 ]) ) - return hist.filter(pl.col("date") == latest).filter( + return hist.filter( # 在此编写筛选条件 ) ``` diff --git a/docs/strategy-guide.md b/docs/strategy-guide.md index f43b3ac..cd5b684 100644 --- a/docs/strategy-guide.md +++ b/docs/strategy-guide.md @@ -102,7 +102,8 @@ def filter_history(df: pl.DataFrame, params: dict) -> pl.DataFrame: """df 包含目标日期之前 LOOKBACK_DAYS 个交易日的数据(所有股票混合)。 每行包含 symbol, date 及所有指标列/信号列。 - 返回值: 筛选后的 DataFrame,引擎会最终保留目标日期行。 + 返回值: 筛选后的 DataFrame。 + 重要: 返回所有匹配的行,不要只过滤最新日期,否则回测只有最后一天有信号。 """ if df.is_empty() or "date" not in df.columns: return df @@ -110,7 +111,6 @@ def filter_history(df: pl.DataFrame, params: dict) -> pl.DataFrame: down_pct = float(params.get("prev_down_pct", -0.02)) vol_ratio = float(params.get("volume_ratio", 1.2)) tolerance = float(params.get("reversal_tolerance", 0.005)) - latest = df["date"].max() # 示例: 前日明显阴线下跌,今日放量阳线反包前日实体 hist = ( @@ -124,7 +124,7 @@ def filter_history(df: pl.DataFrame, params: dict) -> pl.DataFrame: ]) ) - return hist.filter(pl.col("date") == latest).filter( + return hist.filter( (pl.col("_prev_close") < pl.col("_prev_open")) & (pl.col("_prev_change_pct") <= down_pct) & (pl.col("close") > pl.col("open")) @@ -139,7 +139,7 @@ def filter_history(df: pl.DataFrame, params: dict) -> pl.DataFrame: - `LOOKBACK_DAYS` 决定引擎加载多少天的数据,设为策略逻辑需要的最大回看天数 - 优先使用 Polars 的 `with_columns`、`over("symbol")`、`group_by`、`join`、`filter` 实现历史逻辑,避免把数据转成 Python list/dict 循环 - 只有遇到表达式难以描述的复杂状态机时,才使用 `partition_by("symbol")` + `to_dicts()` 逐股票分析 -- 返回的 DataFrame 必须只包含目标日期行,通过 `pl.col("date") == latest` 过滤 +- **返回所有匹配行,不要过滤 `latest`**;选股引擎会自动取最新日,回测引擎需要全区间命中 - 未声明 `filter_history()` 的策略走普通 `filter()` 路径,不受影响 ## 3. 常用指标列(参考,可直接使用) @@ -236,10 +236,12 @@ def filter_history(df: pl.DataFrame, params: dict) -> pl.DataFrame: | signal_boll_breakout_upper | 中性 | 突破布林上轨 | | signal_boll_breakdown_lower | 中性 | 跌破布林下轨 | | signal_volume_surge | 中性 | 放量 | -| signal_limit_up | 买入 | 涨停 | -| signal_limit_down | 卖出 | 跌停 | -| signal_limit_down_recovery | 买入 | 跌停翘板 | -| signal_broken_limit_up | 卖出 | 炸板 | +| signal_limit_up | 买入 | 涨停 (依赖 instruments 表,部分环境不生成) | +| signal_limit_down | 卖出 | 跌停 (依赖 instruments 表,部分环境不生成) | +| signal_limit_down_recovery | 买入 | 跌停翘板 (依赖 instruments 表,部分环境不生成) | +| signal_broken_limit_up | 卖出 | 炸板 (依赖 instruments 表,部分环境不生成) | + +> **注意**:涨跌停类信号需要 instruments 表(板块代码)才能计算。如果策略只用涨停判断,优先用 `consecutive_limit_ups >= 1`(稳定列,始终可用)。 此外,用户自定义信号(`data/user_data/custom_signals/`)以 `csg_` 前缀注入,也可在 filter() 中引用。 @@ -329,7 +331,7 @@ def filter_history(df: pl.DataFrame, params: dict) -> pl.DataFrame: pl.col("change_pct").shift(1).over("symbol").alias("_prev_change_pct"), ]) ) - return hist.filter(pl.col("date") == latest).filter( + return hist.filter( (pl.col("_prev_close") < pl.col("_prev_open")) & (pl.col("_prev_change_pct") <= down_pct) & (pl.col("close") > pl.col("open"))