跳到主要内容

撰写研究报告:让结论可信

直觉

跑出一条漂亮的净值曲线,离「可信」还差得远。一份合格的研究报告要回答评审最尖锐的问题:「这是真本事还是过拟合?」 为此它必须包含稳健性证据——把策略放到不同的样本段(IS/OOS)、**不同的参数(选几只、看几个月)**下反复检验,看结论是否依然成立。如果换组参数就崩,那它只是偶然拟合了某段历史。本节把流水线的结果整理成「报告级」的稳健性表格。

报告骨架与稳健性检验

一份量化研究报告通常含:

  1. 假设与数据:信什么、用什么数据、口径如何;
  2. 方法:因子、加权、再平衡、成本假设;
  3. 主结果:全样本净值 + 核心指标表;
  4. 稳健性(最关键):IS/OOS 切分 + 参数敏感性
  5. 风险:最大回撤、VaR/CVaR、压力情景下的表现;
  6. 结论与局限:能否投产、依赖什么前提、何时会失效。
「人话」解释:评审为什么盯着「稳健性」不放?

因为「全样本漂亮」太容易造假——你完全可以反复调参直到某段历史净值完美。评审不信「最棒的那一次」,他们问的是:「把样本劈成两半,前半段调的参、在后半段还管用吗?」「选 5 只和选 20 只,结论是不是一致?」 如果是,说明你抓的是真结构而非噪声;如果一换就崩,那就是过拟合。所以报告里稳健性表格往往比主净值曲线更重要——它展示的是「结论的可靠程度」,而不仅是「收益有多高」。

可运行案例:IS/OOS 切分 + 参数敏感性

把上一节的流水线封装成函数,输出样本内外指标与选股数量敏感性——一份报告的量化骨架。

import quant
import numpy as np
import pandas as pd

prices = pd.read_csv('/data/sp500_universe_daily.csv', parse_dates=['date']).set_index('date')
meta = pd.read_csv('/data/sp500_metadata.csv').set_index('ticker').loc[prices.columns]
dret = np.log(prices / prices.shift(1)); monthly = prices.resample('ME').last(); mret = monthly.pct_change()
quality = pd.DataFrame(np.tile(meta['quality'].values, (len(monthly), 1)),
                     index=monthly.index, columns=monthly.columns)
score = quality.rank(axis=1) + np.log(monthly/monthly.shift(12)).rank(axis=1)
vol3 = (dret.rolling(63).std() * np.sqrt(252)).resample('ME').last()
fwd = mret.shift(-1); dec = monthly.index[12:-1]

def run(k):                                                   # 选前 k 只
  out = []
  for t in dec:
      picks = score.loc[t].nlargest(k).index
      invv = 1 / vol3.loc[t, picks].clip(lower=0.05); w = invv / invv.sum()
      out.append((fwd.loc[t, picks] * w).sum())
  return pd.Series(out, index=dec)

def metrics(r):
  eq = (1 + r).cumprod(); s = quant.performance_summary(eq, r, freq=12)
  return s['年化收益'], s['夏普'], s['最大回撤']

print("=== 参数敏感性: 选股数量 ===")
print(f"{'topK':>5} {'年化':>7} {'夏普':>6} {'最大回撤':>8}")
for k in [5, 10, 20, 30]:
  a, sh, dd = metrics(run(k)); print(f"{k:5} {a:+6.2%} {sh:6.2f} {dd:7.2%}")

print("\n=== 样本内外切分 (top10, 前60% IS / 后40% OOS) ===")
p = run(10); cut = int(len(p) * 0.6)
for name, seg in [('IS(训练)', p.iloc[:cut]), ('OOS(测试)', p.iloc[cut:])]:
  a, sh, dd = metrics(seg); print(f"{name:9} {a:+6.2%} {sh:6.2f} {dd:7.2%}")
print("\n→ 若 OOS 夏普与 IS 接近、参数敏感性平稳, 才说明结论稳健、非过拟合。")

小结

  • 研究报告的稳健性章节比主净值更重要——它证明结论不是过拟合;
  • 两大检验:IS/OOS 切分(前段调参、后段验证)+ 参数敏感性(换参结论是否稳定);
  • OOS 与 IS 接近、参数敏感性平稳,才敢说策略「可信」,再谈投产。

小测验

1. 研究报告中比「主净值曲线」更重要的是?

2. 两大稳健性检验是?

3. 若 OOS 夏普与 IS 接近、参数敏感性平稳,说明?