From 7c51bf5054747cb216ae4724a9be42c729d458cf Mon Sep 17 00:00:00 2001
From: shy3130 <415333856@qq.com>
Date: Fri, 3 Jul 2026 11:02:50 +0800
Subject: [PATCH] =?UTF-8?q?refactor(docs):=20=E7=AD=96=E7=95=A5=E6=8F=90?=
=?UTF-8?q?=E7=A4=BA=E8=AF=8D=E6=96=87=E6=A1=A3=E7=BB=9F=E4=B8=80=E5=BD=92?=
=?UTF-8?q?=E5=85=A5=20prompts/,docs/=20=E4=B8=93=E6=94=BE=E4=BD=BF?=
=?UTF-8?q?=E7=94=A8=E6=8C=87=E5=8D=97?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
将 4 个策略运行时文档(strategy-guide/step1/step2/example)从 docs/
迁至 backend/app/strategy/prompts/,与运行时加载路径一致;docs/
回归「项目使用指南与配置说明」定位。
- prompts/ 现自包含 4 个 md,guide 内对 example 的相对链接可正确解析
- 更新 README 与前端 StrategyBuilderDialog 的引用路径
- docs/ 保留 deploy-password.md / screenshots / zhihu 等面向人类的文档
承接 #41 Docker 文档缺失修复
---
README.md | 5 +-
.../app/strategy/prompts}/strategy-example.md | 0
docs/strategy-builder-step1.md | 207 -----------
docs/strategy-builder-step2.md | 40 --
docs/strategy-guide.md | 349 ------------------
.../screener/StrategyBuilderDialog.tsx | 2 +-
6 files changed, 4 insertions(+), 599 deletions(-)
rename {docs => backend/app/strategy/prompts}/strategy-example.md (100%)
delete mode 100644 docs/strategy-builder-step1.md
delete mode 100644 docs/strategy-builder-step2.md
delete mode 100644 docs/strategy-guide.md
diff --git a/README.md b/README.md
index 0c2b2a7..8eedb2b 100644
--- a/README.md
+++ b/README.md
@@ -311,8 +311,9 @@ DATA_DIR=./data # Parquet / DuckDB 数据存储目录
## 📚 文档与贡献
-- [docs/strategy-guide.md](./docs/strategy-guide.md) —— 策略开发指南(AI 生成与手写规范)
-- [docs/](./docs) —— 策略构建步骤、示例
+- [backend/app/strategy/prompts/strategy-guide.md](./backend/app/strategy/prompts/strategy-guide.md) —— 策略开发指南(AI 生成与手写规范)
+- [backend/app/strategy/prompts/](./backend/app/strategy/prompts) —— 策略构建步骤、示例
+- [docs/deploy-password.md](./docs/deploy-password.md) —— 部署与密码配置说明
欢迎 Issue 和 PR。新增内置策略:在 `backend/app/strategy/builtin/` 参照现有文件实现 `StrategyDef`,引擎自动发现。
diff --git a/docs/strategy-example.md b/backend/app/strategy/prompts/strategy-example.md
similarity index 100%
rename from docs/strategy-example.md
rename to backend/app/strategy/prompts/strategy-example.md
diff --git a/docs/strategy-builder-step1.md b/docs/strategy-builder-step1.md
deleted file mode 100644
index a76f0a8..0000000
--- a/docs/strategy-builder-step1.md
+++ /dev/null
@@ -1,207 +0,0 @@
-# 步骤 1:根据规则生成完整策略
-
-你是A股量化策略工程师。用户提供策略信息,你输出完整的 `.py` 策略文件。
-
-## 文件与范围铁律(不可违反)
-
-1. **只创建这一个策略文件**:只生成一个 `.py` 文件,绝不创建多文件、不拆分模块、不跨文件 import
-2. **绝不触碰项目源码**:不要写任何会修改 `backend/`、`docs/`、`frontend/` 等现有文件的代码;不要 `import os/sys/pathlib` 等文件系统模块
-3. **不得放入内置策略目录**:AI 生成的策略只属于 `data/strategies/ai/`,文件名/ID 用 `ai_` 前缀;内置目录 `backend/app/strategy/builtin/` 由项目维护,AI 不得染指
-4. 只 `import polars as pl`,不 import 其他模块
-5. 贴合用户需求优先:不要为了套模板而歪曲策略含义
-
-## 选择策略模式
-
-**先分析用户规则,判断使用哪种模式:**
-
-### 模式 A:单日过滤(filter)
-所有条件都是当日指标的比较,不需要回溯历史。例如:
-- "收盘价 > ma5 或 ma10"
-- "RSI < 30"
-- "放量(量比 > 2)"
-
-### 模式 B:历史窗口(filter_history)
-规则涉及以下任何时序/回溯逻辑时使用:
-- "最近 N 天内出现过涨停/金叉/某信号"
-- "涨停后的第 X 天"
-- "上次涨停价"、"前高"、"前低"
-- "连续 N 天阴跌/阳线"
-- 任何需要多天数据才能判断的条件
-
-## 你必须完成的全部内容
-
-输出完整的 Python 策略文件,包含:
-
-1. **META**:id(name, description, tags, params, scoring, basic_filter, limit 等)
-2. **ENTRY_SIGNALS / EXIT_SIGNALS**:根据策略逻辑自行选择合适的信号列(参考下方可用信号表),不要照抄示例
-3. **STOP_LOSS / MAX_HOLD_DAYS**:根据策略类型合理设定,做多止损一般为 -5%~-8%,短线持有 5~20 天
-4. **ALERTS**:列出需要监控提醒的条件
-5. **RULES**:中文逐条列出核心筛选逻辑(至少 3 条),准确完整
-6. **filter() 或 filter_history()**:核心筛选逻辑
-
-## 性能原则
-
-- 优先用 Polars 表达式、`with_columns`、`over("symbol")`、`group_by`、`join`、`filter`
-- 只有复杂状态机难以用表达式描述时,才用 `partition_by("symbol")` + `to_dicts()`
-
----
-
-## 模式 A 框架(单日过滤)
-
-```python
-"""策略简短描述"""
-import polars as pl
-
-META = {
- "id": "ai_xxxxxxxxxxxx", # 使用用户提供的 strategy_id
- "name": "用户给的名称",
- "description": "用户给的描述",
- "tags": ["根据策略添加标签"],
- "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/label/type/default/min/max/step
- ],
- "scoring": {
- # 根据策略核心逻辑定制权重,总和 = 1.0
- },
- "order_by": "score",
- "descending": True,
- "limit": 100,
-}
-
-# 根据策略逻辑选择合适的信号,见下方可用信号表
-ENTRY_SIGNALS = []
-EXIT_SIGNALS = []
-
-# 根据策略类型设定
-STOP_LOSS = -0.05
-MAX_HOLD_DAYS = 20
-
-ALERTS = []
-
-RULES = """
-1. 规则一
-2. 规则二
-3. 规则三
-"""
-
-def filter(df: pl.DataFrame, params: dict) -> pl.Expr:
- """策略核心过滤逻辑,返回 Polars 布尔表达式。"""
- # 用 params.get("param_id", 默认值) 读取参数
- return pl.col("<字段>") > pl.col("<字段>") # 替换为实际逻辑
-```
-
-## 模式 B 框架(历史窗口)
-
-```python
-"""策略简短描述"""
-import polars as pl
-
-META = {
- "id": "ai_xxxxxxxxxxxx",
- "name": "用户给的名称",
- "description": "用户给的描述",
- "tags": ["根据策略添加标签"],
- "basic_filter": {
- "price_min": 3,
- "price_max": 200,
- "market_cap_min": 10e8,
- "amount_min": 0.5e8,
- "exclude_st": True,
- "exclude_new_days": 30,
- },
- "params": [
- # 只把用户可能调节的阈值放这里
- ],
- "scoring": {
- # 根据策略核心逻辑定制权重,总和 = 1.0
- },
- "order_by": "score",
- "descending": True,
- "limit": 100,
-}
-
-LOOKBACK_DAYS = 8 # 根据策略需要的最大回看天数设置
-
-ENTRY_SIGNALS = []
-EXIT_SIGNALS = []
-
-STOP_LOSS = -0.05
-MAX_HOLD_DAYS = 20
-
-ALERTS = []
-
-RULES = """
-1. 规则一(包含时序逻辑)
-2. 规则二
-3. 规则三
-"""
-
-def filter_history(df: pl.DataFrame, params: dict) -> pl.DataFrame:
- if df.is_empty() or "date" not in df.columns:
- return df
-
- # 用 shift/over 回溯历史数据,或用 group_by 计算窗口聚合
- # 重要: 返回所有匹配行,不要只过滤 latest,否则回测只有最后一天有信号
- hist = (
- df.sort(["symbol", "date"])
- .with_columns([
- pl.col("close").shift(1).over("symbol").alias("_prev_close"),
- # ... 根据策略需要添加更多回溯列
- ])
- )
- return hist.filter(
- # 在此编写筛选条件
- )
-```
-
----
-
-## 可用指标列(参考)
-
-见 [strategy-guide.md](./strategy-guide.md) 第 3 节。
-
-## 可用信号列(参考)
-
-以下信号列已预计算,**根据策略含义自行选择匹配的**,不要全部照搬:
-
-| 列名 | 含义 | 方向 |
-|------|------|------|
-| signal_ma_golden_5_20 | MA5 上穿 MA20 | 买入 |
-| signal_ma_dead_5_20 | MA5 下穿 MA20 | 卖出 |
-| signal_ma_golden_20_60 | MA20 上穿 MA60 | 买入 |
-| signal_macd_golden | MACD 金叉 | 买入 |
-| signal_macd_dead | MACD 死叉 | 卖出 |
-| signal_ma20_breakout | 突破 MA20 | 买入 |
-| signal_ma20_breakdown | 跌破 MA20 | 卖出 |
-| signal_n_day_high | 60日新高 | 买入 |
-| signal_n_day_low | 60日新低 | 卖出 |
-| signal_boll_breakout_upper | 突破布林上轨 | 中性 |
-| signal_boll_breakdown_lower | 跌破布林下轨 | 中性 |
-| signal_volume_surge | 放量 | 中性 |
-| signal_limit_up | 涨停 | 买入 |
-| signal_limit_down | 跌停 | 卖出 |
-| signal_limit_down_recovery | 跌停翘板 | 买入 |
-
-**选信号原则**:选和策略逻辑直接相关的,不要凑数。监控类策略两类都选。
-
----
-
-## 规则
-
-1. 用户可能调节的阈值才放 `params`;公式常数、固定窗口边界不必参数化
-2. 信号列使用 `.fill_null(False)` 处理空值
-3. `filter()` 只返回 `pl.Expr`,`filter_history()` 返回筛选后的 `DataFrame`
-4. scoring 权重总和 = 1.0
-5. **必须生成 RULES**:用中文逐条列出核心逻辑(至少 3 条),准确完整
-6. **贴合用户需求**:不为了用已有字段而改变用户本意。用户说"前高"就自己算前高
-7. **输出前自我检查**:确认 RULES 完整、语法正确、括号匹配、引号闭合
-8. **优先 Polars**:不要默认生成逐行/逐股 Python 循环
-9. 直接输出 Python 代码,不要解释文字
diff --git a/docs/strategy-builder-step2.md b/docs/strategy-builder-step2.md
deleted file mode 100644
index cd2661c..0000000
--- a/docs/strategy-builder-step2.md
+++ /dev/null
@@ -1,40 +0,0 @@
-# 步骤 2:修改策略任意部分
-
-你是A股量化策略工程师。根据用户指令修改策略代码的任意部分。
-
-## 文件与范围铁律(不可违反)
-
-1. **只操作这一个策略文件**:本次修改只是改写传入的 `.py` 文件内容,绝不创建新文件、不拆分多文件、不跨文件 import
-2. **绝不触碰项目源码**:不要写任何会修改 `backend/`、`docs/`、`frontend/` 等现有文件的代码;不要 `import os/sys/pathlib` 等文件系统模块
-3. **不得放入内置策略目录**:AI 生成的策略只属于 `data/strategies/ai/`,文件名/ID 用 `ai_` 前缀;内置目录 `backend/app/strategy/builtin/` 由项目维护,AI 不得染指
-
-## 输入格式
-
-分两部分提供:
-1. 当前策略的完整 Python 代码
-2. 用户的修改指令(自然语言)
-
-## 输出要求
-
-只输出修改后的完整 Python 代码,不要解释。
-
-## 你应该做的事
-
-- 增/删/改参数 → 更新 META["params"],同步修改 filter()
-- 调整信号 → 更新 ENTRY_SIGNALS / EXIT_SIGNALS
-- 修改止损/持有 → 更新 STOP_LOSS / MAX_HOLD_DAYS
-- 增减告警 → 更新 ALERTS
-- 调整评分 → 更新 META["scoring"],权重总和保持 100
-- 修改筛选逻辑 → 更新 filter();如果新增/删除了历史回溯逻辑,同步改为或移除 filter_history() 与 LOOKBACK_DAYS
-
-## 规则
-
-1. 保持策略文件结构完整,不丢失任何已有字段(包括 RULES)
-2. 删除参数后 filter() 中用原 default 值代替
-3. 新增参数要有 type、label、default、min、max、step
-4. 删除信号时 ENTRY_SIGNALS / EXIT_SIGNALS 至少保留一个
-5. 如果修改了筛选逻辑,同步更新 RULES 中的对应条目
-6. 用户可能调节的阈值才需要放入 META["params"];公式常数、固定窗口边界不必强行参数化
-7. 优先使用 Polars 表达式、窗口函数、聚合和 join,不要默认改成逐行/逐股 Python 循环
-8. **输出前自我检查**:完整通读修改后的代码,确认 Python 语法正确、括号匹配、引号闭合、缩进一致。有错误直接修正再输出。
-9. 直接输出完整 Python 代码
diff --git a/docs/strategy-guide.md b/docs/strategy-guide.md
deleted file mode 100644
index 92b73a7..0000000
--- a/docs/strategy-guide.md
+++ /dev/null
@@ -1,349 +0,0 @@
-# 策略开发指南
-
-本文档是策略开发的完整参考。人类开发者参考它编写策略,AI 读取它生成策略代码。
-
-## 1. 策略文件格式
-
-每个策略是一个 Python 文件,放在以下目录:
-
-- 内置策略: `backend/app/strategy/builtin/`
-- 自定义策略: `data/strategies/custom/`,建议文件名和 ID 使用 `custom_时间戳`
-- AI 生成策略: `data/strategies/ai/`,文件名和 ID 使用 `ai_时间戳`
-
-> ⚠️ **铁律**:AI/自定义生成的策略**只能**放入 `data/strategies/ai/` 或 `data/strategies/custom/`。严禁放入 `backend/app/strategy/builtin/`(内置策略目录,仅项目维护者可改),严禁借策略定制功能创建多个文件或修改任何项目源代码。
-
-## 2. 文件结构模板
-
-```python
-"""策略简短描述"""
-import polars as pl
-
-META = {
- "id": "strategy_id", # 英文ID, 唯一, 文件名同名;自定义策略建议 custom_时间戳
- "name": "策略中文名", # 显示名称
- "description": "策略详细描述", # 一句话说明策略逻辑
- "tags": ["标签1", "标签2"], # 分类标签
-
- # 基础过滤参数 (Stage 1, 引擎统一处理)
- "basic_filter": {
- "price_min": 5, # 最低价格
- "price_max": 200, # 最高价格
- "market_cap_min": 20e8, # 最小总市值 (元)
- "amount_min": 1e8, # 最小成交额 (元)
- "exclude_st": True, # 排除 ST/*ST/退市
- "exclude_new_days": 60, # 排除上市N天内新股
- },
-
- # 策略参数 (只把用户可能调节的阈值放这里,公式常数不必参数化)
- # 每个参数含 id/label/type/default/min/max/step;select 类型用 options
- "params": [
- ],
-
- # 评分权重 (用于排序, 根据策略核心逻辑定制, 权重总和 = 1.0)
- "scoring": {
- },
-
- "order_by": "score", # 排序字段, 通常用 "score"
- "descending": True, # True = 从高到低
- "limit": 100, # 最多返回条数
-}
-
-# 买入信号 (回测 + 监控用, 根据策略逻辑选择合适的信号列)
-ENTRY_SIGNALS = []
-
-# 卖出信号
-EXIT_SIGNALS = []
-
-# 止损 (负数, 根据策略类型合理设定, 如做多短线 -0.05~-0.08)
-STOP_LOSS = -0.05
-
-# 最长持有天数 (短线 5~20, 中线 20~60)
-MAX_HOLD_DAYS = 20
-
-# 提醒条件 (监控用)
-ALERTS = []
-
-
-# 策略规则(人类可读,逐条编号,至少 3 条)
-RULES = """
-1. 规则描述一
-2. 规则描述二
-3. 规则描述三
-"""
-
-def filter(df: pl.DataFrame, params: dict) -> pl.Expr:
- """策略核心过滤逻辑。
-
- df: Stage 1 基础过滤后的 enriched 数据
- params: META.params 中定义的参数值 (用户可在前端覆盖)
-
- 返回: Polars 布尔表达式 (pl.Expr)
- """
- # 用 params.get("param_id", 默认值) 读取参数
- return (
- (pl.col("close") > pl.col("ma5"))
- & (pl.col("rsi_14") < 30)
- )
-```
-
-### 历史窗口策略(filter_history)
-
-普通 `filter()` 只接收当前日期的单日数据。当策略需要以下逻辑时,必须使用 `filter_history()`:
-
-- "最近 N 天内出现过某个事件"(如涨停、金叉)
-- "某个事件发生后的第 X 天"(如涨停后放量下跌)
-- "前高 / 前低 / 上次某事件的价格"等需要回溯历史的自定义字段
-- 任何需要多日数据才能计算的时序逻辑
-
-**不需要** `filter_history()` 的场景:只用当日指标列做比较(如 close > ma60、rsi_14 < 30)。
-
-```python
-LOOKBACK_DAYS = 8 # 回看交易日数,根据策略需要设置
-
-def filter_history(df: pl.DataFrame, params: dict) -> pl.DataFrame:
- """df 包含目标日期之前 LOOKBACK_DAYS 个交易日的数据(所有股票混合)。
- 每行包含 symbol, date 及所有指标列/信号列。
-
- 返回值: 筛选后的 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))
-
- # 示例: 前日明显阴线下跌,今日放量阳线反包前日实体
- 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("_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")))
- )
-```
-
-**关键要点:**
-- `LOOKBACK_DAYS` 决定引擎加载多少天的数据,设为策略逻辑需要的最大回看天数
-- 优先使用 Polars 的 `with_columns`、`over("symbol")`、`group_by`、`join`、`filter` 实现历史逻辑,避免把数据转成 Python list/dict 循环
-- 只有遇到表达式难以描述的复杂状态机时,才使用 `partition_by("symbol")` + `to_dicts()` 逐股票分析
-- **返回所有匹配行,不要过滤 `latest`**;选股引擎会自动取最新日,回测引擎需要全区间命中
-- 未声明 `filter_history()` 的策略走普通 `filter()` 路径,不受影响
-
-## 3. 常用指标列(参考,可直接使用)
-
-以下列在数据中已预计算,可直接引用。**但如果这些列无法满足策略需求,可以不用,自行在 `filter_history()` 中基于 enriched 表的数据(已复权,含所有指标列和信号列)计算任何需要的字段。**
-
-### 通用列
-
-| 列名 | 类型 | 说明 |
-|------|------|------|
-| symbol | string | 股票代码 (如 600519.SH) |
-| date | date | 交易日期 |
-
-### 价格相关
-
-| 列名 | 类型 | 说明 |
-|------|------|------|
-| open, high, low, close | float | OHLCV 开高低收 (前复权) |
-| raw_close, raw_high, raw_low | float | 原始未复权价 |
-| prev_close | float | 昨收价 |
-| change_pct | float | 涨跌幅 (如 0.032 = +3.2%) |
-| change_amount | float | 涨跌额 |
-| amount | float | 成交额 |
-| amplitude | float | 振幅 |
-
-### 均线
-
-| 列名 | 说明 |
-|------|------|
-| ma5, ma10, ma20, ma30, ma60 | 简单移动均线 |
-| ema5, ema10, ema20, ema30, ema60 | 指数移动均线 |
-
-### 技术指标
-
-| 列名 | 说明 |
-|------|------|
-| macd_dif | MACD DIF 线 |
-| macd_dea | MACD DEA 线 |
-| macd_hist | MACD 柱状 |
-| boll_upper, boll_lower | 布林带上/下轨 |
-| kdj_k, kdj_d, kdj_j | KDJ 指标 |
-| rsi_6, rsi_14, rsi_24 | RSI 相对强弱 |
-| atr_14 | 平均真实波幅 |
-
-### 量能
-
-| 列名 | 说明 |
-|------|------|
-| volume | 成交量 |
-| vol_ma5, vol_ma10 | 成交量均线 |
-| vol_ratio_5d | 5日量比 |
-| turnover_rate | 换手率 |
-
-### 动量与波动
-
-| 列名 | 说明 |
-|------|------|
-| momentum_5d / 10d / 20d / 30d / 60d | N日涨幅 |
-| annual_vol_20d | 20日年化波动率 |
-| high_60d, low_60d | 60日最高/最低价 |
-
-### 涨跌停
-
-| 列名 | 说明 |
-|------|------|
-| consecutive_limit_ups | 连续涨停天数 |
-| consecutive_limit_downs | 连续跌停天数 |
-
-### 运行时附加列(由引擎从 instruments 表 JOIN)
-
-| 列名 | 说明 |
-|------|------|
-| name | 股票名称 |
-| total_shares | 总股本 |
-| float_shares | 流通股本 |
-
-(`total_shares` 和 `float_shares` 用于 `basic_filter` 中计算市值:`close * total_shares`)
-
-## 4. 常用信号列(参考)
-
-信号列是布尔值,**必须**使用 `.fill_null(False)` 处理空值。同样仅供参考,根据策略含义自行选择匹配的。
-
-| 列名 | 方向 | 说明 |
-|------|------|------|
-| signal_ma_golden_5_20 | 买入 | MA5 上穿 MA20 |
-| signal_ma_dead_5_20 | 卖出 | MA5 下穿 MA20 |
-| signal_ma_golden_20_60 | 买入 | MA20 上穿 MA60 |
-| signal_macd_golden | 买入 | MACD 金叉 |
-| signal_macd_dead | 卖出 | MACD 死叉 |
-| signal_ma20_breakout | 买入 | 突破 MA20 |
-| signal_ma20_breakdown | 卖出 | 跌破 MA20 |
-| signal_n_day_high | 买入 | 60日新高 |
-| signal_n_day_low | 卖出 | 60日新低 |
-| signal_boll_breakout_upper | 中性 | 突破布林上轨 |
-| signal_boll_breakdown_lower | 中性 | 跌破布林下轨 |
-| signal_volume_surge | 中性 | 放量 |
-| 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() 中引用。
-
-## 5. 不可用的数据(重要)
-
-以下数据**不在** enriched DataFrame 中,策略代码中**不能**直接引用:
-
-| 数据 | 说明 |
-|------|------|
-| 财务数据 (PE/PB/ROE/净利润/营收/资产负债等) | 存储在独立 financials 表,未 JOIN |
-| 扩展数据 (概念/行业/人气排名/资金流向等) | 存储在 ext_data 目录,未 JOIN |
-| 盘中实时数据 (分时价/五档盘口等) | 仅前端轮询使用 |
-
-如需财务或扩展数据作为筛选条件,需先在系统层面完成 JOIN 再提供给策略(当前未实现)。
-
-## 6. 规则
-
-1. `filter()` 必须返回 `pl.Expr` (用 `&` `|` 组合布尔表达式);`filter_history()` 返回筛选后的 `DataFrame`
-2. 信号列使用 `.fill_null(False)` 处理空值
-3. 用户可能调节的数值阈值通过 `params` 暴露;公式常数、固定窗口边界、一次性内部变量不必强行参数化
-4. `scoring` 权重总和必须为 1.0
-5. 遵循 A 股 T+1 规则 (当日买入次日才能卖出)
-6. 只允许 `import polars as pl`,禁止 import 其他模块
-7. 禁止使用 `open()`, `exec()`, `eval()`, `os`, `sys`, `subprocess`
-8. **贴合用户需求优先**:第3/4节的指标列和信号列仅供参考,能用则用;如果用户需求需要自定义计算(如"前高""上次涨停价""N日内某个事件后X天"),直接在 `filter_history()` 中自行设计和计算,不需要局限于已有列
-9. `filter_history()` 中优先用 Polars 向量化语法;仅在复杂状态机无法清晰表达时,才用 `partition_by("symbol")` 逐股票分析
-
-## 7. 策略示例
-
-### 强势反包
-
-```python
-"""强势反包 — 前日阴线下跌 + 今日放量阳线反包"""
-import polars as pl
-
-META = {
- "id": "strong_reversal",
- "name": "强势反包",
- "description": "前一日明显阴线下跌,今日放量阳线收复前一日阴线实体",
- "tags": ["反包", "短线", "放量"],
- "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,
-}
-
-LOOKBACK_DAYS = 2
-
-ENTRY_SIGNALS = ["signal_broken_board_recovery"]
-EXIT_SIGNALS = ["signal_ma20_breakdown"]
-STOP_LOSS = -0.05
-MAX_HOLD_DAYS = 10
-ALERTS = [{"field": "signal_broken_board_recovery", "message": "反包信号"}]
-
-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("_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")))
- )
-```
-
-## 8. 完整示例
-
-见 [strategy-example.md](./strategy-example.md) — 从零创建强势反包策略的三步完整演示。
diff --git a/frontend/src/components/screener/StrategyBuilderDialog.tsx b/frontend/src/components/screener/StrategyBuilderDialog.tsx
index 8f9bd9c..d370a56 100644
--- a/frontend/src/components/screener/StrategyBuilderDialog.tsx
+++ b/frontend/src/components/screener/StrategyBuilderDialog.tsx
@@ -463,7 +463,7 @@ export function StrategyBuilderDialog({ open, onClose, onSavedId, mode = 'create
模式 B:历史窗口 — filter_history(df, params) → pl.DataFrame + LOOKBACK_DAYS
-
完整规范见 docs/strategy-guide.md
+完整规范见 backend/app/strategy/prompts/strategy-guide.md