我拿一篇 45 页的华泰动量研报试了试 EVO:从45页研报到可运行策略
先把不太好看的结果放前面:这次回测没有赚钱。
我用 EVO 复现的是华泰金工《多因子 4:华泰单因子测试之动量类因子》。最后一版总收益 -3.28%,年化 -0.70%,夏普 -0.67。没有高收益曲线,也没有一个可以直接拿去实盘的参数组合。
但这篇研报我确实从头跑到了尾:上传 45 页 PDF,载入研究上下文,让 EVO 提取 13 个动量因子,实际创建其中两条,跑完因子有效性分析,再生成策略、回测和调优,最后留下 2 个因子、1 个策略、4 个策略草稿。
接下来我分享一下:EVO 到底是什么,我从哪里开始,每一步输入了什么、页面出现了什么,以及我怎么判断该继续还是回头检查。
EVO 到底是什么
PandaAI 官网把自己定义为 AI 时代的 Trading OS,目标是让交易想法快速变成可验证的策略。这个说法比较大。就我这次实际用下来的感受,EVO 更像一个会动手的量化研究 Agent 工作台。
它和普通聊天框最大的区别是:我说完要求后,它不只回复一段文字,还会在工作区里真的留下东西。
- PDF 放在“资源”里,作为研究输入;
- 公式和预处理落成“因子作品”,可以运行有效性分析;
- 选股、调仓和成本规则落成“策略作品”,可以直接回测;
- 每次修改策略会留下新草稿,旧结果不会被新结果覆盖;
- 同一个策略里还能看定义、业绩、风险、适应性、归因和日志。
所以它做的不是“聊聊这篇研报”,而是把对话里的研究意图,变成可以运行和回看的研究对象。
工作区左边有“作品、资源、环境”三个入口。我的使用顺序基本是:先去资源里载入研报,再回作品里看 EVO 创建的因子和策略。中间区域会随着对象变化:打开因子时看定义、产出、有效性和稳健性;打开策略时看定义、业绩、风险、适应性和归因。研究助手负责理解任务并推进这些操作。
下面这张图是我全部跑完后的状态。左侧“全部 3”不是三段聊天,而是三个真实作品:两条因子和一个策略。中间打开的是策略定义,顶部还能切换草稿。

图 1:本次实际生成的 exp_wgt_return_6m、wgt_return_1m,以及策略 htsc_momentum_reversal_1m。
这次到底做什么
原研报研究的是 2005—2016 年的全 A 股,做的是月频动量因子测试。EVO 这次实际能直接跑的是平台当前可用数据和近 5 年样本。股票池、时间段、数据源不一致,IC 和收益不可能拿来一一对数。
所以我没有把“复现出研报里的收益”当成目标。我验收的是下面这条链路能不能走通:
上传研报 → 读出研究口径 → 创建因子 → 配置分析
→ 看懂因子方向 → 生成策略 → 跑出基线 → 派生草稿调优
这一步看起来像是在降低标准,其实不是。如果连运行口径都不同,却硬要求结果一致,最后很容易为了对数字去调参数。我的标准是:流程要完整,每一步要有产物,替换了什么口径要能讲清楚;效果好不好,照实记录。
第 1 步:把研报载入研究上下文
我先进入左侧“资源”,在 研究报告 文件夹中找到 PDF(内测群里发的,我不便发在这里,大家应该上网可以搜到):
【华泰金工】多因子4:华泰单因子测试之动量类因子20161220.pdf
文件约 3.8 MB,共 45 页。点击文件后,中间出现 PDF 预览,研究助手一侧显示已经载入这份文件作为研究上下文。看到这两个反馈后,我才开始下任务。
这个确认动作我觉得不能省。资源列表里有文件,只能说明上传过;打开预览并看到“已载入上下文”,才说明接下来的回答确实会基于它。否则助手即使给出一个听起来正确的动量策略,我也没办法确认它有没有真的读当前研报。
如果你照着做,这一步至少确认三件事:
- 文件名确实是目标研报,不是同目录里的另一版;
- PDF 在中间能正常预览,不是只有一个空文件条目;
- 助手明确提示当前文件已经进入研究上下文。
第 2 步:不要只说“帮我复现这篇研报”
我一开始最容易犯的错误,就是把“复现”想得很具体,但只给 EVO 两三个字。对人来说,复现可能默认包括公式、样本、预处理、分组、策略和回测;对 Agent 来说,它也可能只是帮我总结全文。
这次我最后使用的任务描述大致如下,可以直接作为起点:
请结合当前载入的研报,完整复现研报中的研究流程,不要只做摘要。
请先提取并列出:
1. 因子定义和经济含义;
2. 样本区间、股票池、频率和预测周期;
3. 缺失值、去极值、标准化和中性化方法;
4. 因子方向、分组方式、调仓规则和组合构建方式;
5. 回测和评价指标。
确认上述口径后,再在 EVO 中依次创建因子、完成因子分析、
生成策略并回测。
本次以流程跑通、每一步留下可检查的产物为成功标准,
不要求收益率、IC 和夏普等数值与原文完全一致。
如果平台当前数据或能力不能使用原文口径,请同时列出:
原文口径、当前替代口径、替代原因、对结果可比性的影响。
这里面最管用的是三句话:先列口径再创建、不要只做摘要、口径变化要单独说明。没有这几句,任务很容易从“复现研究”慢慢滑成“帮我找一个动量因子”。
EVO 随后分三次读取 PDF:1—22 页、22—40 页、40—45 页。最后梳理出 13 个动量类因子,并从 exp_wgt_return_6m 开始。
我没有让它一次性创建 13 条。这里是我第一次真正感觉到“少做一点反而更快”:如果第一轮同时建 13 条,任何一处窗口或预处理不对,都不知道要从哪一条查。我先用 exp_wgt_return_6m 确认中期动量的分析链路,再用 wgt_return_1m 继续走到策略。
拿到研报提取结果后,不要急着点运行。我当时先核对了这些内容:报告名称和页数是否正确、样本是不是 2005—2016、股票池是不是全 A、是否识别出动量方向、选中的因子是否真的在研报里。只有这几个基本事实对上,后面的自动创建才有意义。
第 3 步:因子创建后,别只看代码能不能跑
第一条因子 exp_wgt_return_6m 是为了确认完整的因子分析流程。它跑完后,我又创建了短周期的 wgt_return_1m,后面的策略主要基于第二条。
第一条并不是跑完就被我略过去了。它的 Rank IC 均值是 -0.0358,IC 均值 -0.0089,ICIR -0.08,Newey-West t 值 -1.44,p-value 0.151,覆盖度 87.11%,换手率 6.29%,页面判定稳健性未通过。
这个结果对“选一个强因子”没有太大帮助,但对测试流程是有用的:因子定义、预处理、元数据、任务提交和结果页都能连起来。我没有为了救这条结果马上改参数,而是顺着研报继续做 wgt_return_1m。这样第二条因子既能复用已经确认过的分析流程,也能测试短周期反转方向能不能继续变成策略。
因子作品创建后,真正影响结果的内容分成两类:一类是因子定义本身,另一类是运行元数据和预处理。公式写对了,后面这部分配错,结果照样没有可比性。
我在 wgt_return_1m 上最终使用的是:
| 配置项 | 本次设置 | 我为什么检查它 |
|---|---|---|
| 回看窗口 | 20 个交易日 | 把“1 个月”落实成可计算窗口 |
| 预测周期 | T+20 | 因子值对应未来约 1 个月收益 |
| 分组数 | 5 组 | 用于观察分位组合差异和单调性 |
| 复权方式 | 后复权 | 避免分红送转造成价格序列断点 |
| 缺失值 | 开启处理 | 防止大量股票因空值直接丢失 |
| 去极值 | MAD | 降低异常收益对截面排序的影响 |
| 标准化 | Z-score | 让不同截面的因子值更便于比较 |
| 中性化 | 行业 + 市值 | 尽量分离行业和规模暴露 |
| 样本范围 | 近 5 年 | 本次平台实际可运行口径 |
我觉得这一步最容易被忽略的是“预测周期”。回看 20 日只说明因子用了过去多少数据,T+20 才说明它要解释未来多长时间的收益。两者不是一个参数。
“月末调仓”也是同样的问题。自然语言写起来只有四个字,代码里却要明确是自然月最后一天、月末最后一个交易日,还是跨月后遇到的第一个交易日。后面我的第一次调优,主要就是在这里花的时间。
运行前我还做了一个对照,避免自己过两天就忘了:
| 项目 | 研报原始口径 | 本次实际口径 | 能否直接比较 |
|---|---|---|---|
| 样本期 | 2005—2016 | 近 5 年 | 不能 |
| 股票池 | 全 A | 沪深 300,后续调优到中证 1000 | 不能 |
| 频率 | 月频研究 | wgt_return_1m 使用 T+20 |
只能比较研究逻辑 |
| 因子方向 | 动量/反转分别检验 | 本次结果指向反向使用 | 可以检查方向是否合理 |
这个小表很朴素,但对研报复现很重要。否则结果出来后,人会本能地拿两组数字作比较,忘了它们其实不是同一场实验。
第 4 步:因子分析页到底怎么看
提交后,任务会从排队中、0%,进入计算中,最后显示完成。完成以后我打开因子作品里的“有效性”页,而不是只看助手给我的一句结论。
wgt_return_1m 实际跑出来的数据是:
| 指标 | 结果 | 我当时怎么理解 |
|---|---|---|
| Rank IC 均值 | -0.0429 | 排序关系偏负,先考虑反向使用 |
| IC 均值 | -0.0146 | 线性相关同样偏负 |
| ICIR | -0.14 | 稳定性不强,不能只看平均 IC |
| Newey-West t 值 | -1.95 | 接近常用显著性边界,但不宜说得太满 |
| p-value | 0.052 | 高于 0.05,本次页面也判为不显著 |
| IC 胜率 | 45.9% | 正向胜率不到一半 |
| 换手率 | 15.90% | 后续进入策略时要考虑交易成本 |
| 覆盖度 | 97.50% | 大部分样本都有因子值 |

图 2:wgt_return_1m 的实际有效性页面。顶部同时给出了回测区间、61 期月度展示和 T+20 收益口径。
我第一次看到 Rank IC 为负,也下意识觉得这条因子是不是写反了。但继续看分组单调性和 EVO 给出的方向判断,低分位更值得关注,逻辑上对应的是短期反转:过去一个月相对弱的股票,在后一个月存在反弹倾向。
这也是读因子页时一个挺实用的顺序:
- 先看正负号,判断是正向还是反向;
- 再看分组是否按这个方向排列,而不是只盯一个均值;
- 再看 ICIR、t 值和 p-value,判断关系稳不稳;
- 最后看覆盖度和换手率,判断它落成策略后是否可能被样本缺失和成本拖累。
这组结果不能叫强因子。p-value = 0.052 并没有通过常用的 5% 阈值,ICIR 也不好看。但它至少给出了一个可继续验证的方向。我没有在这里反复改参数“刷”到显著,而是保留原结果,继续测试它落成交易规则后会怎么样。
第 5 步:从因子结果走到第一个策略
因子方向确认后,我让 EVO 根据 wgt_return_1m 的低分位反转思路创建策略 htsc_momentum_reversal_1m。
如果从头再做一次,我会把这一步写成下面这样,避免只说“生成策略”以后让选股方向又被猜一遍:
请基于已经完成分析的 wgt_return_1m 创建一条 A 股策略草稿。
因子按反向使用:选择因子值最低的一组,而不是最高组。
先沿用当前 20 日窗口和 T+20 研究口径,以沪深 300 为初始股票池和基准,
每次选择因子值最低的 20 只股票等权持有,并写入交易成本。
创建后先不要继续调参。请打开并说明策略定义中的:
股票池、基准、回测区间、调仓触发、持仓数量、单票上限、
总仓位、佣金、印花税和滑点。
完成静态检查和第一次回测,把该草稿保留为原始基线。
这里的 20 只并不是研报证明过的最优持仓数,只是把第一版策略的规则明确下来。第一轮最重要的是留一个不再移动的基线,而不是一开始就追求最优参数。
策略出现后,我先回到左侧“作品”确认它确实已经创建。打开策略,中间顶部能看到“定义、业绩、风险、适应性、归因”几个页面。定义页里又分“策略定义”和“护栏”,右上角显示当前草稿和“定义锁定”。
我主要核对定义里的 META 和策略说明:
universe:股票池;benchmark:业绩比较基准;adjust:复权方式;freq:运行频率;rangeStart / rangeEnd:回测时间;builder:持仓数、权重上限、总仓位;cost:佣金、印花税和滑点;generate_signal:选股和调仓到底在什么条件下触发。
这里我最大的体会是:策略说明写着“低分位反转、月末调仓”,只是研究意图;真正决定回测行为的是下面的代码和元数据。两边都要看,不能只读那几行中文注释。
草稿 1 使用沪深 300 作为股票池和基准。回测完成后,业绩页生成了累计净值、基准对比、回撤和月度收益,结果是:
- 总收益
-40.27%; - 年化收益
-10.34%; - 最大回撤
-42.68%; - 夏普
-2.09; - 卡玛
-0.24; - 索提诺
-2.35; - 月度胜率
30.0%。
到这一步,“研报 → 因子 → 策略 → 回测”的流程其实已经闭环了,只是效果很差。
我没有直接输入“帮我把收益优化到正数”。这种要求太容易让 Agent 同时改窗口、股票池、持仓数和调仓逻辑。最后曲线即使变好,我也不知道是哪一处改动造成的。所以后面的原则变成了:先留基线,一轮只问一个问题。
第 6 步:四个草稿是怎么一步步出来的
EVO 的草稿机制在这次调优里挺实用。已经锁定的草稿不会被直接覆盖,要修改就从指定草稿派生一个新草稿。于是草稿 1 的原始结果、草稿 2 的失败结果、草稿 3 和草稿 4 的回测都能来回切换。

图 3:右上角切换草稿时,四次尝试和各自的夏普都还在。
草稿 1:先留下最原始的基线
草稿 1 就是 EVO 自动生成的沪深 300 版本。虽然亏损很大,我仍然先保存它,因为没有这个版本,后面所有“改善了多少”都没有参照。
草稿 2:静态检查通过,但回测全是 0
我先让 EVO 重新读草稿 1 的 definition.py,核对月末调仓。第一轮修改生成草稿 2,静态体检显示 14 项,0 项不通过,1 项未查,随后回测也正常跑完。
但我打开业绩页后发现,总收益、年化和最大回撤全部是 0.00%,夏普和卡玛没有值,月度收益也全是 0。日志能看到回测跑完了 1191 根 bar,时间覆盖 2021-09-22 到 2026-08-21。
这时候要特别小心:任务显示“完成”,只能说明回测程序结束了;静态检查通过,也只能说明代码没有被检查项拦住。它们都不能证明策略真的触发了信号和交易。
我当时的判断路径是:
回测是否完成? 是
净值是否有变化? 否
月度收益是否非零? 否
风险指标是否有值? 否
=> 这不是“策略特别稳”,而是本轮没有产生有效交易
所以草稿 2 没有继续往下当基线。
草稿 3:回到草稿 1,重新处理调仓判断
因为草稿 2 已经锁定,我重新从草稿 1 派生草稿 3,再修改调仓逻辑。静态体检仍是 14 项,0 项不通过,1 项未查,这次业绩页终于出现正常波动:总收益 -7.89%,年化 -1.73%,最大回撤 -12.36%,夏普 -0.92。
相对草稿 1,这几个数字明显收窄,但我没有把它写成“月末调仓已经验证有效”。因为调仓日期的自然语言、代码实现和实际交易日还需要逐项核对。这轮能确认的是:修改后产生了交易,回测结果也能和基线比较。
草稿 4:只把股票池和基准换成中证 1000
第二轮调优以草稿 3 为基线,只改两处对应同一个实验变量:股票池从沪深 300 换成中证 1000,基准也同步换成中证 1000。
我明确要求 20 日窗口、选股方向、top 20、单票上限、总仓位、交易成本、回测区间和调仓代码全部保持不变。静态体检后再跑回测,得到草稿 4。

图 4:草稿 4 的业绩页。策略总收益仍是负数;页面同时展示了中证 1000 基准和累计净值。
四个草稿放在一起看更直观:
| 草稿 | 本轮处理的问题 | 总收益 | 年化收益 | 最大回撤 | 夏普 |
|---|---|---|---|---|---|
| 草稿 1 | 原始基线,沪深 300 | -40.27% | -10.34% | -42.68% | -2.09 |
| 草稿 2 | 第一次修改调仓判断 | 0.00% | 0.00% | 0.00% | N/A |
| 草稿 3 | 从草稿 1 重新修改调仓判断 | -7.89% | -1.73% | -12.36% | -0.92 |
| 草稿 4 | 从草稿 3 切换到中证 1000 | -3.28% | -0.70% | -15.24% | -0.67 |
草稿 4 相比草稿 3,总收益、年化、夏普和月度胜率有所改善,月度胜率从 35.0% 到 38.3%;但最大回撤从 -12.36% 扩大到 -15.24%,波动率也从 4.99% 升到 5.26%。
所以我最后只敢下一个很有限的结论:在当前近 5 年样本和这套固定参数下,中证 1000 版本比沪深 300 版本少亏了一些,但承担的回撤更大。它不能证明小盘股短期反转长期有效,更不能说明策略已经调好。
如果你也想复现一篇研报,我建议按这个顺序检查
这是我实际跑完后会保留的顺序:
- 确认文件真的被载入。 能预览,并且助手明确显示已进入研究上下文。
- 先让 EVO 列口径。 因子、样本、股票池、频率、预处理、方向和评价指标先对上。
- 先跑一条最小链路。 长研报不要第一轮就批量建全部因子。
- 创建因子后再核对元数据。 尤其是回看窗口、预测周期、复权和中性化。
- 因子页先判方向。 负 IC 可能是反向因子,不要直接当成创建失败。
- 保留第一个策略作为基线。 结果再差也先别覆盖。
- 回测完成后确认真的有交易。 看净值、月度收益、风险指标和日志,不能只看任务状态。
- 每轮只改一个实验变量。 从指定草稿派生,并写清哪些参数不能动。
- 同时比较收益和风险。 收益少亏不代表回撤也会改善。
- 最后再写结论。 把研报口径和当前口径并排放着,别把样本内变化写成普遍规律。
最后说点真实感受
这次让我觉得有用的,不是 EVO 给了一个“正确答案”,而是它把原来很分散的研究动作接在了一起。
以前读一篇研报,我可能在 PDF 里做笔记,在本地写因子代码,换一个地方跑回测,再自己用文件名保存 final_v2_new。这次我在资源区载入研报后,研究助手能继续创建因子;因子分析完能生成策略;策略效果不好,又能从指定草稿继续改。回过头看时,两条因子、四个草稿和每次结果还在同一个工作区里。
但它也不是按一下就能交卷。特别是时间窗口、因子方向、调仓日期和是否实际成交,这些地方仍然需要人做判断。EVO 把“想法变成实验”的门槛降下来了,并不等于研究责任也交出去了。
我最后停在草稿 4,没有继续把参数调到正收益。再往下当然还可以试窗口、持仓数和过滤条件,但如果一直盯着这 5 年数据调,很快就会变成在样本里找最好看的答案。对这次测试来说,把流程跑通、把失败草稿留下、知道下一步应该验证什么,比硬凑一条正收益曲线更有价值。毕竟现在2026年了,追求这个正收益也很难上实盘,跑通流程倒是可以帮我以后用得更顺畅,尝试自己的策略。
本文仅记录一次研报复现和历史回测过程,不代表未来表现,也不构成投资建议。


评论