Day 2:量化选股策略——从理论模型到因子实践(含代码实现)
发布日期:2026-07-25 | 系列:量化学习笔记 | 作者:Joakim Starr
写在前面
昨天的 Day 1 笔记主要解决了"量化是什么"的问题,确立了整个学习的大方向。按照 WhaleQuant 的章节安排,第二章是金融市场基础概念,第三章是数据获取。但考虑到这两章更偏工具性(统计基础已在 Day 1 中提前梳理,数据获取需要配合代码实操),我决定先把第四章「量化选股策略」作为 Day 2 的核心攻坚内容。
原因很简单:选股是量化交易最核心的环节,也是信息密度最大的一章。 后续所有章节(择时、调仓、回测)本质上都是在为选股服务。先把这一章吃透,后面会顺畅很多。
本文是对第四章全文的精读笔记,包含理论推导、因子体系、有效性检验方法和 Python 实践。篇幅较长,建议配合目录食用。
1. 为什么需要选股?
1.1 从有效市场假说说起
选股这件事存在的根本前提,是市场并非完全有效。教材从有效市场理论切入,把市场分为四类:
| 市场类型 | 特征 | 技术分析 | 基本面分析 | 内幕消息 |
|---|---|---|---|---|
| 无效市场 | 价格未反映历史信息 | ✅ 有效 | ✅ 有效 | ✅ 有效 |
| 弱式有效 | 价格反映历史信息 | ❌ 失效 | ✅ 有效 | ✅ 有效 |
| 半强式有效 | 价格反映所有公开信息 | ❌ 失效 | ❌ 失效 | ✅ 有效 |
| 强式有效 | 价格反映所有信息(含内幕) | ❌ 失效 | ❌ 失效 | ❌ 失效 |
关键结论:现实中不存在完美的强式有效市场。一般认为短期来看市场是无效的,长期来看市场是有效的。
这意味着:
- 短期内,情绪和非理性交易会让股价偏离实际价值(无效性)
- 长期内,理性投资者的套利行为会让价格回归价值(有效性)
量化选股的目标,就是在这种"短期无效→长期有效"的过程中,系统性地识别出被低估的股票,低买高卖,获取超额收益(Alpha)。
1.2 主观选股 vs 量化选股
传统基金经理靠深度研究少数股票来选股,而量化选股的核心差异在于:
- 覆盖广度:同时对全市场几千只股票打分筛选
- 规则客观:选股标准完全量化,不依赖主观判断
- 可回测验证:任何选股逻辑都可以用历史数据检验有效性
2. 理论基石:从效用函数到多因子模型
这一节是全书理论密度最高的部分,教材从最基础的"人为什么厌恶风险"出发,一步步推导出多因子模型的数学形式。我按逻辑链重新梳理了一遍。
2.1 效用函数与风险厌恶
经济学假设每个投资者都有一个效用函数 ,输入是财富总额,输出是这笔财富带来的满足感。大多数人的效用函数满足两个性质:
- 钱多比钱少好:
- 边际效用递减:随着财富增加,每增加一单位财富所带来的额外效用逐渐减少,即效用函数通常为凹函数()。简单来说,就是同样一块钱,对穷人来说价值更大,对富人来说价值更小。
满足性质2的投资者被称为风险厌恶者——这也是大多数人的真实状态。
期望效用假说:面对多个投资选项,理性投资者会选择期望效用 最大的那个。
损失厌恶:人们对损失的敏感程度远大于对同等收益的感受。这是行为经济学的核心发现,也是"为什么人会在下跌时恐慌割肉"的数学解释。
2.2 风险的定义与度量
经济学中,风险 = 未来的不确定性 = 收益分布越分散,确定性越低。
所以最朴素的风险度量就是收益率的标准差 :在期望收益不变的情况下, 越低越好。
2.3 MPT 模型(现代资产配置理论)
Markowitz 在1952年提出的均值-方差模型,是量化投资的奠基性理论。核心思想:
在给定预期收益 的约束下,找到方差最小的资产配置方案。
对于由 个资产组成的组合 (权重 ,满足 ),有:
其中: 是资产 的收益率, 是资产 和 的协方差。 是组合 的收益率。
有效前沿(Efficient Frontier):在所有可行组合中,相同风险下收益最高(或相同收益下风险最低)的那些点连成的曲线。
夏普比率:$$Sharpe = \frac{E(r_P) - r_f}{\sigma_P}$$
其中: 是无风险利率, 是组合收益率的标准差。夏普比率衡量的是单位风险下的超额收益,是投资组合优劣的重要指标。
衡量每承受一单位总风险能获得多少超额回报。夏普比率越高的组合越优。
我的理解:MPT 告诉我们,分散投资不只是"不把鸡蛋放在一个篮子里",而是要放到相关性低的篮子里。两只股票如果走势高度相关,分散持仓并不能降低风险。这也是为什么多因子模型要关注因子之间的共线性问题。
2.4 CAPM 模型(资本资产定价模型)
CAPM 建立在 MPT 之上,用简洁的公式描述了资产收益与系统性风险的关系:
其中 衡量资产 对市场的敏感度。
核心洞察:
- 资产的预期收益只由它的 决定,与自身波动率 无关
- 高 → 承担更多系统性风险 → 预期收益更高
- 这个公式也是后续多因子模型中"因子暴露"概念的思想源头
2.5 APT 套利定价理论与多因子模型
CAPM 只用一个市场因子解释收益,太粗糙了。套利定价理论(APT)将其推广到多个因子:
股票的预期收益可以被多个系统性因子线性解释,不同因子代表不同类型的风险溢价。
多因子模型(Multiple-Factor Model)的数学形式:
- :股票 在因子 上的暴露度(因子载荷)
- :因子 的收益率
- :残差收益(无法被因子解释的部分,即 Alpha)
这就是量化选股的核心公式。 选股的本质,就是找到那些 (Alpha)解释不了超额收益的股票。
3. 常见的因子分类
教材将量化因子分为两大类:基于日频数据构建的和基于高频数据构建的。作为初学者,我先聚焦日频因子。
3.1 因子全景表
| 因子类别 | 具体因子 | 经济学含义 |
|---|---|---|
| 估值因子 | PE(市盈率)、PB(市净率)、PS(市销率)、股息率、PEG | 股票是否"便宜" |
| 成长因子 | 营收增长率、净利润增长率、EPS增长率、ROE增长率 | 公司扩张速度 |
| 盈利因子 | ROE、ROA、毛利率、净利率、资产负债率 | 公司盈利能力和财务健康度 |
| 动量因子 | 过去20日/60日/120日涨跌幅 | "强者恒强"的趋势效应 |
| 规模因子 | 总市值、流通市值 | 小盘股效应 |
| 波动因子 | 日收益率标准差、最大回撤 | 风险特征 |
| 换手率因子 | 日均换手率、换手率变化 | 市场关注度和情绪 |
| 宏观因子 | GDP增速、M2、利率、CPI | 宏观经济环境 |
3.2 因子构建示例
以动量因子为例,计算"过去20个交易日累计涨跌幅":
import pandas as pd
# 假设 df 包含日期、股票代码、收盘价
df['momentum_20'] = df.groupby('stock_code')['close'].pct_change(periods=20)
以换手率因子为例:
# 计算过去20日平均换手率
df['turnover_20'] = df.groupby('stock_code')['turnover_rate'].transform(
lambda x: x.rolling(window=20).mean()
)
因子的构建方式直接决定了它的经济含义。一个好的因子必须有清晰的经济学逻辑支撑,而不是纯数据挖掘出来的数字。
4. 因子有效性检验
这是我在今天学习中觉得最"干货"的部分。选了一堆因子,怎么判断它们真的有效?教材给出了系统的检验方法。
4.1 P值检验
最基础的统计检验。对每个因子做回归:
用 t 检验判断 是否显著不为0。p值越小 → 因子越显著。
注意:p值不是"因子有效的概率",而是"在原假设成立(因子无效)的情况下,观察到当前结果或更极端结果的概率"。p值小 → 拒绝"因子无效"的假设。
4.2 IC 值(信息系数)—— 最核心的指标
IC 定义为每个横截面上,因子值与下期收益率之间的相关系数。
计算逻辑(逐期截面计算):
import numpy as np
from scipy import stats
# 数据结构:每个交易日,所有股票的因子值和未来一期收益率
# 对每一天,计算因子值与未来收益率的 Spearman 秩相关系数
ic_series = []
for date in unique_dates:
daily_data = df[df['date'] == date]
ic = stats.spearmanr(daily_data['factor'], daily_data['forward_return']).correlation
ic_series.append(ic)
ic_mean = np.mean(ic_series) # IC均值 → 因子有效性
ic_std = np.std(ic_series) # IC标准差 → 因子稳定性
为什么用 Spearman 而不是 Pearson?
- Spearman 基于排名,对异常值不敏感
- 金融数据(尤其是PE、PB)往往严重右偏,Pearson 会被极端值带偏
- Spearman 能捕捉单调的非线性关系
IC 值解读标准:
| IC 均值 | 含义 |
|---|---|
| > 0.05 | 强正向预测能力 |
| 0.03 ~ 0.05 | 中等正向预测能力 |
| ≈ 0 | 无预测能力 |
| < -0.03 | 负向预测能力(因子值低反而收益高) |
在股票多因子研究中,由于市场噪声极大,长期稳定维持 IC 均值 0.03~0.05 已经属于较优秀的因子,超过 0.1 的情况十分少见。
4.3 IR 值(信息比率)
IR = IC 均值 / IC 标准差
IR 衡量的是因子预测能力的稳定性,是"风险调整后的 IC"。
IR 值解读标准:
| IR 绝对值 | 因子评级 |
|---|---|
| > 0.5 | 优秀 |
| 0.3 ~ 0.5 | 良好 |
| 0.1 ~ 0.3 | 一般 |
| < 0.1 | 较差 |
本文所说的 IR 指的是 IC Information Ratio(ICIR),而不是组合绩效评价中的 Information Ratio,两者定义不同。
4.4 完整的因子评价体系
教材和实务中通常综合以下指标判断因子质量:
| 指标 | 含义 | 判断标准 |
|---|---|---|
| IC 均值 | 因子平均预测能力 | 绝对值越大越好 |
| IC 标准差 | IC 的波动程度 | 越小越好 |
| IR | 稳定性调整后的预测力 | 绝对值 > 0.3 可用,> 0.5 优秀 |
| IC > 0 比例 | IC 为正的时间占比 | 显著偏离50%说明方向稳定 |
| t 统计量 | IC 是否显著不为0 | 绝对值 > 2 为显著 |
个人体会:这套 IC/IR 体系非常实用。它让我意识到,一个"好因子"不仅要在平均意义上有效(IC均值高),还要在大部分时间里稳定有效(IR高)。偶尔灵偶尔不灵的因子,实际用起来会很痛苦。
5. 行业与市值中性化
这是今天学到的最"实战"的部分。教材花了相当篇幅讲这个概念,因为它直接决定了因子的纯度。
5.1 为什么要中性化?
很多因子并不是在"纯粹"地捕捉某种风险溢价,而是混杂了市值效应或行业效应。
举个例子:PE 因子在低估值组表现好,但如果你选出来的低 PE 股票全是大银行(因为银行天然 PE 低),那你的"低估值策略"本质上就变成了"银行板块超配策略"。一旦银行板块整体下跌,你的策略就会亏得很惨。
中性化的目的:剔除因子中市值和行业的影响,让因子更纯粹地反映自身信息。
5.2 市值中性化(连续变量)
思路:用因子值对市值做线性回归,取残差作为中性化后的因子。
import numpy as np
import pandas as pd
def market_neutralize(df, factor_col, mv_col='total_mv'):
"""市值中性化:对因子值取对数市值的回归残差"""
df = df.copy()
log_mv = np.log(df[mv_col])
# 用 numpy 做简单线性回归取残差
slope, intercept = np.polyfit(log_mv, df[factor_col], 1)
fitted = slope * log_mv + intercept
df[f'{factor_col}_neutralized'] = df[factor_col] - fitted
return df
5.3 行业中性化(离散变量)
两种方法:
方法一:行业均值做差(简单直观)
def industry_neutralize(df, factor_col, industry_col='industry'):
"""行业中性化:因子值减去所在行业的均值"""
industry_mean = df.groupby(industry_col)[factor_col].transform('mean')
df[f'{factor_col}_ind_neutral'] = df[factor_col] - industry_mean
return df
方法二:哑变量回归取残差(更严谨)
将行业转为哑变量,做多元线性回归,取残差。结果与均值做差法本质相同,但数学形式更规范。
5.4 中性化的实际影响
教材中给出的示例显示,中性化前后的因子值分布会发生明显变化。一个混杂了市值和行业效应的"伪因子",经过中性化后可能变得几乎无效——这恰恰说明它原来捕捉的不是真正的信号,而是市值或行业的 Beta 暴露。
⚠️ 警示:在检验任何因子之前,必须先做中性化处理。否则你以为发现的 Alpha,可能只是行业配置或市值暴露的副产品。
6. 多因子选股模型构建(五步法)
这是全章的落地环节。教材给出了一个标准化的五步流程:
Step 1:候选因子选取
根据经济逻辑选取若干候选因子,涵盖估值、成长、质量、动量等类别。
Step 2:因子有效性检验
用 IC/IR 体系筛选掉无效因子,保留 IC 均值显著且 IR > 0.3 的因子。
Step 3:因子预处理
- 异常值处理:用 MAD 法(中位数绝对偏差)或 Winsorize 法截尾
- 缺失值填充:前向填充或行业均值填充
- 标准化:Z-score 标准化使不同量纲的因子可加
- 中性化:市值 + 行业中性化
Step 4:综合评分
两种主流方法:
打分法(推荐初学者):
- 每个因子横截面上排序打分(如 Z-score 或 Rank)
- 按权重加权求和得到综合得分
- 选得分最高的前 N% 股票
# 简化的打分法示例
def composite_score(df, factor_cols, weights=None):
"""多因子综合打分"""
df = df.copy()
if weights is None:
weights = [1.0 / len(factor_cols)] * len(factor_cols)
# 每个因子 Z-score 标准化
for col in factor_cols:
df[f'{col}_z'] = (df[col] - df[col].mean()) / df[col].std()
# 加权求和
score = pd.Series(0.0, index=df.index)
for col, w in zip(factor_cols, weights):
score += w * df[f'{col}_z']
df['composite_score'] = score
return df
# 示例:三个因子等权打分
factor_cols = ['pe_factor', 'roe_factor', 'momentum_factor']
result = composite_score(stock_data, factor_cols)
# 选前20%
selected = result.nlargest(int(len(result)*0.2), 'composite_score')
print(f'Selected {len(selected)} stocks')
打分法的权重选择:
- 等权:简单但不区分因子重要性
- IC 加权:按各因子的 IC 均值赋权
- IR 加权:按 IC/IR 赋权,兼顾有效性和稳定性
- 最大化 IC_IR:通过优化求解最优权重
回归法:
- 用历史收益率对多因子做回归,得到每个因子的系数
- 将最新因子值代入回归方程,预测未来收益
- 选预测收益最高的股票
教材指出:A股市场上,简单的打分法往往比回归法表现更好。原因可能是因子间共线性较高,回归法不稳定。
Step 5:组合优化与回测
对筛选出的股票做组合优化(考虑行业约束、换手率约束等),然后进入回测环节验证策略效果。这部分在第七章会详细展开。
7. 今日反思与行动计划
核心收获
-
选股的本质是因子暴露的管理。好的选股模型不是找到"涨最多的股票",而是找到一组稳定有效的因子,系统性地获取因子溢价。
-
中性化是必经步骤。不中性化的因子很可能只是在偷懒——它暴露的是市值或行业的 Beta,不是真正的 Alpha。
-
IC/IR 体系是因子研究的灵魂工具。它让"这个因子好不好"从一个模糊的直觉变成了可量化的判断。
-
打分法适合A股初学者。等权重或 IC 加权的打分法简单直观,且对共线性不敏感,是入门首选。
尚未解决的问题
- 因子间的共线性如何处理?教材提到了但没有深入,后续需要学习 PCA 降维或 Lasso 回归
- 因子衰减速度怎么度量?IC 的半衰期分析
- 高频因子(如分钟级量价因子)的构建方法
下一步行动
按照今天的五步法,我计划用 Python + Tushare 实际构建一个多因子选股模型:
- 获取全市场股票的基本面数据(PE、PB、ROE)和量价数据(动量、换手率)
- 计算各因子值,做市值+行业中性化
- 计算 IC/IR,筛选有效因子
- 用打分法构建综合评分,选股回测
这部分实操将作为 Day 3 的内容。
参考链接
- DataWhale《WhaleQuant》第4章:量化选股策略
- 摩根士丹利华鑫基金:单因子有效性检验方法
- 多因子模型:回归法和打分法详解(伯乐实验室)
- 量化基本功:IC 分析(本领投资)
下一篇预告:Day 3 —— 股票数据获取实战:用 Tushare + Pandas 拉取行情数据,开始构建第一个多因子选股模型