量化股票投资的七个原则

前言

上一节我们讲到,量化投资组合有两个基本目标:实现高阿尔法和高信息比率

在实现这两个基本目标时,我们要遵循一定的“游戏规则”,而这也就是量化股票组合管理的七原则。

原则一:市场在大多数情况下是有效的。
原则二:纯套利机会是不存在的。
原则三:量化分析创造统计套利机会。
原则四:量化分析以有效的方式结合所有可得的信息。
原则五:量化模型应当以可靠的经济理论为基础。
原则六:量化模型应当反映持续与稳定的模式。
原则七:组合与比较基准之间的偏离只有当不确定性足够小时才是合理的。

这七条原则,本质上分为三层:对市场的基本假设(原则一、原则二)、如何创造超额收益(原则三、原则四)以及模型约束(原则五、原则六、原则七),我们下面来逐条解释这些原则。

原则一:市场在大多数情况下是有效的

原则二:纯套利机会是不存在的

原则一与原则二基于这样一种信念:市场在大多数(但并非所有)情况下是有效的。 因为根据市场有效性假说(CPA财管:财务分析与预测),如果市场是完全有效的,那么主动投资组合将是徒劳的。 因此,如果我们进行主动组合投资,就应当相信市场中存在某些可以被利用的无效性。

从现实结果来看,我们观察到历史金融数据存在很多“异象”——即与有效市场假说相悖的现象,例如:

  • 1月效应:小盘股和上年表现不佳的股票倾向于在当年1月表现优异;
  • 冷门股效应:分析师覆盖率较低的股票倾向于有更高的风险调整后超额收益率;
  • IPO效应:IPO后的股票在之后的3-5年中,风险调整后超额收益率倾向于表现不佳。

对于这些发现的异象,已经有很多的研究成果给出了解释,比如:

  • 信息存在获取成本;
  • 很多投资者不具备处理大量信息的能力;
  • 投资者存在非理性行为,例如模糊厌恶、知识幻觉、过度自信等(行为金融学)。

以上种种原因带来了无效性,但是我们认为,这些无效性并不会带来纯套利机会,而是会带来统计套利机会,即低风险但并非无风险的套利机会,这也是进行化投资的重要前提。

原则三:量化分析创造统计套利机会

原则四:量化分析以有效的方式结合所有可得的信息

很明显,原则三、原则四是前两条原则的自然延伸:只要所使用的方法与模型能够有效地结合所有可获得的信息,那么量化分析就提供了统计套利的可能性

这两条原则可以通过 Grinold 和 Kahn (1997) 提出的“主动管理基本法则”来理解:

IR=ICBRIR = IC \cdot \sqrt{BR}

由上式可知,信息比率由 信息系数 (Information Coefficient, IC)宽度 (Breadth, BR) 平方根的乘积决定。 因此,要提高信息比率,可以通过提高信息系数实现(寻找比模型现有因子更有效的因子),也可以通过提高宽度实现(寻找更多与现有因子不相关的因子)。

需要注意的是,基本法则主要用于“理解”而非直接用于“实施”组合构建,量化经理并不直接使用此公式构建组合。

原则五:量化模型应当以可靠的经济理论为基础

原则六:量化模型应当反映持续与稳定的模式

原则七:组合与比较基准之间的偏离只有当不确定性足够小时才是合理的

在统计套利的基础上,原则五到原则七进一步关注将统计方法应用于投资组合选择时所涉及的问题,分别是:数据挖掘参数的稳定性参数的不确定性

数据挖掘

对历史过分精确和必然的解释,通常不是伟大或正确,而只是穿凿附会的谬误。

数据挖掘问题是量化投资中的最大挑战之一,我们必须时刻极力避免数据挖掘,因为它并不是基于合理的经济学理论,而是仅靠统计显著性,违反了原则五。

有的时候,数据挖掘是显而易见的,比如将历史股票收益率于大量因子组合进行回归。由于使用了大量的因子组合,因此几乎确保找到于收益率显著相关的因子和模型(R21R^2≈1),但实际上并没有太多意义,因为模型此时已经过拟合了(overfitting) (关于过拟合的参考:【漫士】为什么刷题想得越多,考得反而越差?)。

但有的时候,问题并不会这么明显。假如我们不是直接将100个变量加入模型,而是通过所谓的逐步回归,从中寻找最显著的变量作为模型因子,这样可以避免数据挖掘问题吗?答案是不行。我们可以通过下面的例子来说明:

数据挖掘陷阱示例

数据挖掘陷阱示例
import numpy as np
import matplotlib.pyplot as plt

# 参数设置
np.random.seed(42)

n_sim = 1000      # 模拟次数
n_obs = 100       # 样本数,缩小该值会系统性提高 R^2
n_x = 100         # 解释变量个数,提高该值会系统性提高 R^2

max_r2_list = []      # 每次模拟中“最大”的 R^2
single_r2_list = []   # 每次模拟中“随便一个”的 R^2(这里取第 1 个)

# 主模拟循环
for _ in range(n_sim):
    # 被解释变量 y
    y = np.random.randn(n_obs)

    # 100 个解释变量
    X = np.random.randn(n_obs, n_x)

    r2_values = []

    for j in range(n_x):
        x = X[:, j]

        # 设计矩阵(常数项 + x)
        X_design = np.column_stack([np.ones(n_obs), x])

        # OLS 回归
        beta = np.linalg.lstsq(X_design, y, rcond=None)[0]
        y_hat = X_design @ beta

        # 计算 R^2
        ss_res = np.sum((y - y_hat) ** 2)
        ss_tot = np.sum((y - y.mean()) ** 2)
        r2 = 1 - ss_res / ss_tot

        r2_values.append(r2)

    # 记录结果
    max_r2_list.append(max(r2_values))
    single_r2_list.append(r2_values[0])  # 任取一个

# 打印结果
plt.figure()
plt.hist(max_r2_list, bins=30)
plt.xlabel("R²")
plt.ylabel("Frequency")
plt.title("Distribution of Maximum R² (Selected from 100 Variables)")
plt.show()

plt.figure()
plt.hist(single_r2_list, bins=30)
plt.xlabel("R²")
plt.ylabel("Frequency")
plt.title("Distribution of R² (Single Arbitrary Variable)")
plt.show()

测试结果:

结果1
结果2

可以观察到最大R2R^2的结果明显高于随机R2R^2的结果,此外,如果我们进一步缩小样本数(n_obs)或增加解释变量数(n_x),R2R^2 还会进一步提高(隐式多重检验)。

这是因为:由于我们在 100 个中变量选择了最好的那一个,所以得到的结果稍微但不明显地大于 0 ,这在很多实证论文 / 量化策略中完全可能被当成“有解释力”,但实际上变量并不存在任何关系。

参数稳定性

为了基于历史数据进行预测,我们必须假设“历史会重演”。比如如果股票的历史收益率为1%,则我们可以假设下个月的收益率也大约是1%;如果股票历史收益率的标准差为10%,那么我们可以假说下个月的标准差大约也是10%。

然而,市场是不断变化的,这种变化会打破我们基于历史的假设,所以我们必须考虑:随着时间推移,我们基于历史的假设是否仍然成立?

对参数稳定性的考虑在确定样本数据大小时至关重要。比如,如果我们认为时间区间超过5年时,β\beta一般不会保持不变,那么我们就不应该使用一个超过5年的数据样本来估计它。再比如,如果我们知道一家公司已经合并了,那么我们就不应该构建一个既包含合并前数据,又包含合并后数据的样本。

参数的不确定性

这里讲的其实是风险与收益的匹配关系,我们不应该只关注组合的超额收益,还需要考虑其具有的风险。在多数时候,组合获取了更大的超额收益并不是因为其本身的优越性,而只是因为承担了更大的风险。

借鉴巴菲特的“好球区”理论,我们应等待胜率或赔率足够高时再出手。如果模型提示的信号比较模糊(不确定性大),最好的做法就是紧跟基准,而不是冒险重仓,不要为了交易而交易,要为了“确定性”而交易