第 2 章 · 02 策略与 Signal Engine 本节摘要:策略(strategy)是把研究想法变成可执行规则——从「这个因子看起来不错」到「具体买什么、买多少、什么时候卖、怎么止损」。本节讲清在 Vibe-Trading 里策略通常落到一个 run dir,由两个文件分工: 告诉回测系统「标的、起止日期、数据源、bar 周期、用哪个市场引擎」, 告诉系统「每根 K 线该生成什么信号」。我们会用一个朴素均线策略和一个多因子策略做例子,并重点警示新手最常犯的错——把「因子分数高」直接等同于「马上满仓买入」。读完本节,你能看懂一个 run dir 的结构,并理解从因子到策略需要补齐哪些规则。 内容来源:原项目中文入门教程(第 4 章「策略和 Signal Engine」)改写。
本节摘要:策略(strategy)是把研究想法变成可执行规则——从「这个因子看起来不错」到「具体买什么、买多少、什么时候卖、怎么止损」。本节讲清在 Vibe-Trading 里策略通常落到一个 run dir,由两个文件分工:
config.json告诉回测系统「标的、起止日期、数据源、bar 周期、用哪个市场引擎」,signal_engine.py告诉系统「每根 K 线该生成什么信号」。我们会用一个朴素均线策略和一个多因子策略做例子,并重点警示新手最常犯的错——把「因子分数高」直接等同于「马上满仓买入」。读完本节,你能看懂一个 run dir 的结构,并理解从因子到策略需要补齐哪些规则。
内容来源:原项目中文入门教程(第 4 章「策略和 Signal Engine」)改写。
阅读完本节,你应当能够:
config.json 与 signal_engine.py 的分工。config.json + code/signal_engine.py)。第 1 章 04 你认识了因子——它是一个打分公式,只回答「哪个标的分数更高」。但光有分数还不够交易,你还得回答一连串现实问题:
策略(strategy)就是把这些问题都给出明确答案的可执行规则。 因子是策略的原料之一,策略还要叠加仓位、成本、风控、调仓逻辑。
举两个对比例子:
💡 因子与策略的关系:因子是「打分」,策略是「打分 + 仓位 + 调仓 + 成本 + 风控」。一个策略可以用零个、一个或多个因子;一个因子也可以被很多策略复用。两者是「原料」与「成品」的关系。
在 Vibe-Trading 里,一次策略研究通常落到一个 run dir(运行目录),标准结构是:
my_run/ config.json ← 告诉回测系统「跑什么」 code/ signal_engine.py ← 告诉回测系统「怎么算信号」
这两个文件分工明确:
config.json —— 描述「这次回测的参数」:标的列表(codes)、起止日期、数据源、bar 周期(日/分钟)、用哪个市场引擎、初始资金、佣金/滑点参数等。signal_engine.py —— 描述「信号逻辑」:一个 Python 类(Signal Engine),读取每根 bar 或整个 panel,输出目标仓位或买卖信号。💡 为什么要分成两个文件:把「参数」和「逻辑」分开,便于复查和复现。改参数(比如换个时间段)只动
config.json,改策略思路只动signal_engine.py。这种分离也让 agent 能分别生成、校验这两个文件——backtest工具会先校验config.json和code/signal_engine.py的合法性,再运行回测。
config.json 是回测的「参数清单」。一个典型的全球股票策略配置大致包含这些字段:
{ "codes": ["AAPL", "MSFT", "GOOG"], "start_date": "2020-01-01", "end_date": "2025-12-31", "source": "yfinance", "bar": "1d", "engine": "global_equity", "initial_capital": 100000, "commission": 0.001, "slippage": 0.001 }
关键字段的含义:
| 字段 | 含义 |
|---|---|
codes |
标的列表,如 ["AAPL", "MSFT"] 或 ["BTC-USDT"]。 |
start_date / end_date |
回测起止日期。 |
source |
数据源,如 yfinance、tushare、okx、local,或 auto 自动路由。 |
bar |
K 线周期,如 1d(日)、5m(5 分钟)、1H(1 小时)。 |
engine |
市场引擎,如 global_equity、china_a、crypto、composite。 |
initial_capital |
初始资金。 |
commission / slippage |
佣金率、滑点参数。 |
💡 engine 选错会怎样:如果你用
global_equity引擎跑 A 股,就不会处理 T+1、涨跌停、印花税,回测结果会和真实交易差距很大。engine 必须和市场匹配,这是第 2 章 03 的重点。
signal_engine.py 是策略的核心逻辑。它是一个 Python 类(继承自项目的 Signal Engine 基类),主要做一件事:读取每根 K 线(或整个 panel),输出目标仓位或买卖信号。
一个最朴素的均线策略,Signal Engine 大致长这样(伪代码):
class MovingAverageStrategy: def on_bar(self, bar, state): # 计算 20 日均线和 60 日均线 ma20 = bar.close.rolling(20).mean() ma60 = bar.close.rolling(60).mean() # 信号:均线多头排列就持有,否则空仓 if ma20 > ma60: return {"target_weight": 1.0} # 满仓 else: return {"target_weight": 0.0} # 空仓
这个例子输出的是目标仓位(target weight)——告诉回测引擎「这一刻我应该持有多少」。引擎会根据这个目标,结合交易规则(手续费、T+1、涨跌停)算出实际成交。
💡 两种信号输出方式:
- 目标仓位(target weight):输出「应该持有多少比例」,引擎负责算怎么调仓。适合仓位型策略。
- 买卖信号(buy/sell signal):输出「买/卖多少股」,更接近事件驱动。适合择时型策略。
对比两个典型策略,你会更清楚「从因子到策略」要补齐什么。
信号:20 日均线 > 60 日均线 → 持有;否则空仓 仓位:满仓或空仓(0 或 1) 调仓:每日检查 成本:每日调仓的手续费 + 滑点
这个策略只用了一个信号(均线相对位置),规则极简。它的优点是好理解、好调试;缺点是没有仓位管理、没有风控、调仓频繁导致成本高。
信号:动量(40 日收益率)+ 质量(ROE)+ 波动率(倒数)合成 z 分数 选股:在 universe 里取分数最高的前 20 只 仓位:每只最多 5%,总仓位不超过 80% 调仓:每月最后一个交易日 风控:单只回撤超 15% 强制平仓
这个策略明显复杂得多——它叠加了多因子合成、选股数量、仓位上限、调仓频率、止损。这正是「策略」比「因子」多出来的部分。
这是本节最需要强调的一点。
⚠️ 新手最常见错误:把「因子分数高」直接等同于「马上满仓买入」。实际策略还需要仓位上限、调仓频率、交易成本、停牌/涨跌停、风险控制和 benchmark 对比。
为什么不能直接满仓?至少有五个理由:
所以从「因子分数高」到「能赚钱」,你至少要补齐:选股数量、仓位上限、调仓频率、成本扣除、风控止损、benchmark 对比。这正是 signal_engine.py 和 config.json 要一起表达的内容。
💡 判断一个策略是否完整:问自己六个问题——买什么?买多少?什么时候买?什么时候卖?成本多少?能不能成交?如果任何一个答不上来,这个策略就还不完整。
把策略放回第 2 章 01 的五步工作流里,你会看清它的位置:
Plan → 决定用哪个因子、哪个引擎、哪个 universe Ground → 拉行情数据 Execute → signal_engine.py 在每根 bar 上算信号,引擎按规则模拟 ← 策略在这里 Validate→ 挂上 benchmark、回撤、turnover Deliver → 交付报告 + run dir(含 config.json + signal_engine.py)
策略本质上是 Execute 阶段的核心输入——它告诉回测引擎「每个时刻应该做什么」。config.json 是 Plan 阶段定下的参数沉淀,signal_engine.py 是策略逻辑的代码化。
config.json(参数)+ code/signal_engine.py(信号逻辑),两者分工明确。⚠️ 任何策略设计与回测结果均不构成投资建议。历史回测表现不代表未来收益,实盘前必须经过样本外验证和模拟盘测试。
下一节,我们将进入本章的重头戏——回测如何工作:回测入口命令、为什么不同市场必须走不同引擎(T+1/涨跌停/佣金/滑点),以及为什么「很多漂亮的短线策略一加费用就失效」。