Files
tick-stock-panel/backend/app/strategy/prompts/strategy-example.md
T
shy3130 918c7ade7e refactor(core): 策略与信号全面去内置化, 转为用户自定义定义
- 策略: 引擎只加载 data/strategies/{custom,ai,composite} 与研究模板目录,
  原 25 个内置策略一次性迁移为用户自定义文件(ID 不变, 引用零迁移);
  研究模板移至 app/strategy/research, 打包 spec 同步; 新装环境策略库为空
- 信号: 管线不再硬编码任何信号表达式; 涨跌停判定价成为运行时列
  limit_up_price/limit_down_price(生效价∓0.005 容差), 20 个信号转为
  data/user_data/custom_signals 定义(显式 column 沿用 signal_* 原列名);
  依赖解析/注入顺序/当日路径 prev-join 全部定义驱动; 语义统一为历史路径
  口径(顺带修正当日路径 BOLL 比较符与翘板/炸板空值两处既有偏差)
- 前端: 信号库单列表(全部可编辑), SignalPicker/监控选项/信号标签全走
  定义接口; 回测页新增免责声明(模拟性质/数据源准确性不作保证/不构成
  投资建议)
- 测试: 25 个策略夹具与 20 个信号种子入库 tests/fixtures, 受影响测试
  全部自包含化(不依赖运行目录用户数据); 77 万行 MA 死叉新旧表达式对拍
  逐行一致; 回测实跑 45 笔卖点信号出场验证矩阵链路
- 同批包含工作区既有进度: 策略结果 ext 列同日投影修复(含测试)、数据源插件、fuyao/auth/api_gateway/data_integrity 调整、README 信号库
  描述与 strategy.md 导入路径补充

验证: 后端 2592 passed(空数据目录 CI 模拟 2588 passed, 4 例为模拟环境
伪影复验排除); 前端 vitest 125 passed + tsc 0 错 + vite build 通过
2026-10-10 21:10:44 +08:00

5.2 KiB

两步创建示例:强势反包策略

本文演示从零创建一个自定义策略的完整流程。


Step 1:填写规则

用户在创建对话框填写:

字段 填写内容
名称 强势反包
描述 筛选前日阴线下跌、今日放量阳线反包的短线强势股
方向 做多
规则 前一交易日为明显阴线且跌幅不低于2%,今日阳线收盘反包前一日实体,收盘价接近或高于前一日高点,成交量较前一日放大1.2倍以上,当前 close > ma5 或 close > ma10;使用 filter_history,并优先用 Polars shift/with_columns/filter 实现。

点击「AI 生成」,AI 返回完整策略代码(含参数、信号、评分):

"""强势反包 — 前日阴线下跌 + 今日放量阳线反包"""
import polars as pl

META = {
    "id": "strong_reversal",
    "name": "强势反包",
    "description": "筛选前日阴线下跌、今日放量阳线反包的短线强势股",
    "tags": ["反包", "短线", "放量"],
    "asset_types": ["stock"],
    "timeframes": ["1d"],
    "basic_filter": {
        "price_min": 3,
        "price_max": 200,
        "market_cap_min": 10e8,
        "amount_min": 0.5e8,
        "exclude_st": True,
        "exclude_new_days": 30,
    },
    "params": [
        {
            "id": "prev_down_pct",
            "label": "前日最大跌幅",
            "type": "float",
            "default": -0.02,
            "min": -0.10,
            "max": -0.005,
            "step": 0.005,
        },
        {
            "id": "volume_ratio",
            "label": "成交量放大倍数",
            "type": "float",
            "default": 1.2,
            "min": 1.0,
            "max": 5.0,
            "step": 0.1,
        },
        {
            "id": "reversal_tolerance",
            "label": "反包容忍误差",
            "type": "float",
            "default": 0.005,
            "min": 0.0,
            "max": 0.03,
            "step": 0.005,
        },
    ],
    "scoring": {
        "change_pct": 0.4,
        "vol_ratio_5d": 0.3,
        "momentum_5d": 0.3,
    },
    "order_by": "score",
    "descending": True,
    "limit": 100,
}

EXECUTION_BACKEND = "python_history_legacy"
LOOKBACK_DAYS = 2

ENTRY_SIGNALS = ["signal_broken_board_recovery"]
EXIT_SIGNALS = ["signal_ma20_breakdown"]
STOP_LOSS = -0.05
MAX_HOLD_DAYS = 10

RULES = """
1. 前一交易日为阴线,且跌幅不小于设定阈值
2. 今日为阳线,收盘价收复前一日开盘价并接近或突破前一日高点
3. 今日成交量较前一日明显放大,且收盘价站上 MA5 或 MA10
"""


def filter_history(df: pl.DataFrame, params: dict) -> pl.DataFrame:
    if df.is_empty() or "date" not in df.columns:
        return df

    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 = (
        df.sort(["symbol", "date"])
        .with_columns([
            pl.col("open").shift(1).over("symbol").alias("_prev_open"),
            pl.col("high").shift(1).over("symbol").alias("_prev_high"),
            pl.col("close").shift(1).over("symbol").alias("_prev_close"),
            pl.col("volume").shift(1).over("symbol").alias("_prev_volume"),
            pl.col("change_pct").shift(1).over("symbol").alias("_prev_change_pct"),
        ])
    )
    return hist.filter(pl.col("date") == latest).filter(
        (pl.col("_prev_close") < pl.col("_prev_open"))
        & (pl.col("_prev_change_pct") <= down_pct)
        & (pl.col("close") > pl.col("open"))
        & (pl.col("close") > pl.col("_prev_open"))
        & (pl.col("close") >= pl.col("_prev_high") * (1 - tolerance))
        & (pl.col("volume") >= pl.col("_prev_volume") * vol_ratio)
        & ((pl.col("close") > pl.col("ma5")) | (pl.col("close") > pl.col("ma10")))
    )

Step 2:预览 + 指令修改

进入第二步,显示完整的策略预览和指令输入框。

用户如果觉得反包条件太严格,可以输入「把前日跌幅放宽到 -1.5%,反包前高允许 1% 误差」→ 点 AI 修改。AI 更新 params 默认值和 filter_history() 逻辑。

确认无误后点「保存策略」→ 策略池中出现。


后续使用

打开策略配置,基础参数和策略参数分别独立:

┌─ 配置:强势反包 ──────────────────────────┐
│  名称 [强势反包             ] 显示上限 [30]│
│                                            │
│  📊 基础参数          [启用 ●]             │
│    价格 [3]~[200]元  排除ST、新股          │
│    最低成交额 [5000万]                     │
│                                            │
│  ⚙ 策略参数                               │
│    前日最大跌幅 [-0.02]                    │
│    成交量放大倍数 [1.2]                    │
│    反包容忍误差 [0.005]                    │
│                                            │
│  ⭐ 策略权重    📈 交易参数                 │
└────────────────────────────────────────────┘