第 2 章 · 02 策略与 Signal Engine


文档摘要

第 2 章 · 02 策略与 Signal Engine 本节摘要:策略(strategy)是把研究想法变成可执行规则——从「这个因子看起来不错」到「具体买什么、买多少、什么时候卖、怎么止损」。本节讲清在 Vibe-Trading 里策略通常落到一个 run dir,由两个文件分工: 告诉回测系统「标的、起止日期、数据源、bar 周期、用哪个市场引擎」, 告诉系统「每根 K 线该生成什么信号」。我们会用一个朴素均线策略和一个多因子策略做例子,并重点警示新手最常犯的错——把「因子分数高」直接等同于「马上满仓买入」。读完本节,你能看懂一个 run dir 的结构,并理解从因子到策略需要补齐哪些规则。 内容来源:原项目中文入门教程(第 4 章「策略和 Signal Engine」)改写。

第 2 章 · 02 策略与 Signal Engine

本节摘要:策略(strategy)是把研究想法变成可执行规则——从「这个因子看起来不错」到「具体买什么、买多少、什么时候卖、怎么止损」。本节讲清在 Vibe-Trading 里策略通常落到一个 run dir,由两个文件分工:config.json 告诉回测系统「标的、起止日期、数据源、bar 周期、用哪个市场引擎」,signal_engine.py 告诉系统「每根 K 线该生成什么信号」。我们会用一个朴素均线策略和一个多因子策略做例子,并重点警示新手最常犯的错——把「因子分数高」直接等同于「马上满仓买入」。读完本节,你能看懂一个 run dir 的结构,并理解从因子到策略需要补齐哪些规则。

内容来源:原项目中文入门教程(第 4 章「策略和 Signal Engine」)改写。

学习目标

阅读完本节,你应当能够:

  1. 用一句话说清策略是什么(把信号变成交易规则),以及它与因子的边界。
  2. 说清 config.jsonsignal_engine.py分工
  3. 读懂一个 run dir 的标准结构(config.json + code/signal_engine.py)。
  4. 区分朴素策略(单因子/均线)与多因子策略(合成分数 + 调仓 + 仓位上限)。
  5. 解释为什么「因子分数高」不等于「马上满仓买入」,以及一个真实策略还需要补齐哪些规则。

一、策略是什么:从想法到规则

第 1 章 04 你认识了因子——它是一个打分公式,只回答「哪个标的分数更高」。但光有分数还不够交易,你还得回答一连串现实问题:

  • 买什么?(选哪些标的)
  • 买多少?(每只买多少仓位,总仓位上限多少)
  • 什么时候买?(信号触发条件)
  • 什么时候卖?(退出条件、止损、调仓频率)
  • 成本多少?(手续费、滑点、印花税)
  • 能不能成交?(停牌、涨跌停、流动性)

策略(strategy)就是把这些问题都给出明确答案的可执行规则。 因子是策略的原料之一,策略还要叠加仓位、成本、风控、调仓逻辑。

举两个对比例子:

  • 朴素策略:「如果 20 日均线高于 60 日均线,就持有;否则空仓。」——只用了一个信号(均线相对位置),规则简单。
  • 多因子策略:「在一个股票池里,用动量、质量、波动率三个因子合成分数,买前 20 只,每月调仓一次,单只最多 5% 仓位,总仓位不超过 80%。」——叠加了多因子合成、调仓频率、仓位上限。

💡 因子与策略的关系:因子是「打分」,策略是「打分 + 仓位 + 调仓 + 成本 + 风控」。一个策略可以用零个、一个或多个因子;一个因子也可以被很多策略复用。两者是「原料」与「成品」的关系。

二、run dir:策略落地的标准结构

在 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.jsoncode/signal_engine.py 的合法性,再运行回测。

三、config.json:告诉系统「跑什么」

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 数据源,如 yfinancetushareokxlocal,或 auto 自动路由。
bar K 线周期,如 1d(日)、5m(5 分钟)、1H(1 小时)。
engine 市场引擎,如 global_equitychina_acryptocomposite
initial_capital 初始资金。
commission / slippage 佣金率、滑点参数。

💡 engine 选错会怎样:如果你用 global_equity 引擎跑 A 股,就不会处理 T+1、涨跌停、印花税,回测结果会和真实交易差距很大。engine 必须和市场匹配,这是第 2 章 03 的重点。

四、signal_engine.py:告诉系统「怎么算信号」

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):输出「买/卖多少股」,更接近事件驱动。适合择时型策略。

五、一个朴素策略 vs 一个多因子策略

对比两个典型策略,你会更清楚「从因子到策略」要补齐什么。

朴素策略:单均线

信号:20 日均线 > 60 日均线 → 持有;否则空仓 仓位:满仓或空仓(0 或 1) 调仓:每日检查 成本:每日调仓的手续费 + 滑点

这个策略只用了一个信号(均线相对位置),规则极简。它的优点是好理解、好调试;缺点是没有仓位管理、没有风控、调仓频繁导致成本高。

多因子策略:三因子合成 + 调仓 + 仓位上限

信号:动量(40 日收益率)+ 质量(ROE)+ 波动率(倒数)合成 z 分数 选股:在 universe 里取分数最高的前 20 只 仓位:每只最多 5%,总仓位不超过 80% 调仓:每月最后一个交易日 风控:单只回撤超 15% 强制平仓

这个策略明显复杂得多——它叠加了多因子合成、选股数量、仓位上限、调仓频率、止损。这正是「策略」比「因子」多出来的部分。

六、新手最大误区:因子分数高 ≠ 马上满仓买入

这是本节最需要强调的一点。

⚠️ 新手最常见错误:把「因子分数高」直接等同于「马上满仓买入」。实际策略还需要仓位上限、调仓频率、交易成本、停牌/涨跌停、风险控制和 benchmark 对比。

为什么不能直接满仓?至少有五个理由:

  1. 容量限制:某只股票流动性差,你想买很多也买不到,强行买入会推高成本。
  2. 集中度风险:满仓一只股票,一旦它暴跌就全军覆没。策略通常要分散持仓。
  3. 成本侵蚀:频繁按信号调仓,手续费和滑点会吃掉收益。很多短线策略一加成本就失效。
  4. 市场规则:A 股 T+1(今天买明天才能卖)、涨跌停(买不到/卖不掉),信号触发了也未必能成交。
  5. 过拟合风险:直接按历史最优分数满仓,极易过拟合,样本外失效。

所以从「因子分数高」到「能赚钱」,你至少要补齐:选股数量、仓位上限、调仓频率、成本扣除、风控止损、benchmark 对比。这正是 signal_engine.pyconfig.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 是策略逻辑的代码化。

本节要点回顾

  1. 策略 = 信号 + 仓位 + 调仓 + 成本 + 风控:把研究想法变成可执行规则,因子只是策略的原料之一。
  2. run dir 结构:config.json(参数)+ code/signal_engine.py(信号逻辑),两者分工明确。
  3. config.json:标的、日期、数据源、bar 周期、市场引擎、初始资金、佣金/滑点。
  4. signal_engine.py:一个 Python 类,读取 bar/panel,输出目标仓位或买卖信号。
  5. 两种信号输出:目标仓位(target weight)适合仓位型,买卖信号(buy/sell)适合择时型。
  6. 朴素 vs 多因子:朴素策略只一个信号;多因子策略叠加合成、选股、仓位上限、调仓、止损。
  7. 新手最大误区:因子分数高 ≠ 马上满仓买入——还要考虑容量、集中度、成本、市场规则、过拟合。

⚠️ 任何策略设计与回测结果均不构成投资建议。历史回测表现不代表未来收益,实盘前必须经过样本外验证和模拟盘测试。

下一节,我们将进入本章的重头戏——回测如何工作:回测入口命令、为什么不同市场必须走不同引擎(T+1/涨跌停/佣金/滑点),以及为什么「很多漂亮的短线策略一加费用就失效」。


发布者: 作者: HKUDS 转发
评论区 (0)
U