市值中性化
大部分因子当中都包含了市值的影响,所以当我们通过一些指标选择股票的时候, 每个因子都会提供市值的因素,选择的股票就会比较集中, 及选股的标准不太好。市值中性化就是排除市值影响后的因子。
计算方法:
回归法去除
建立目标因子 y 和市值 x 的回归方程,然后计算目标因子和其预测值之间的偏差,偏差就是不受市值影响的部分,即市值中性化后的结果
例如股票振幅,要计算市值中性化后的股票振幅,过程如下:
1. 获取两个因子数据,即股票振幅和市值数据
2. 对目标值因子股票振幅进行去极值,然后标准化
3. 建立市值 x 与股票振幅 y 的回归方程
4. 通过回归系数, 预测新的因子结果 y_predict
5. 求出目标因子 y 与 y_predict 的偏差即为新的因子值
以代码 600000 的股票数据为例,计算其 2024 年中性化股票振幅。
代码示例:
A |
|
1 |
600000 |
2 |
2024-01-01 |
3 |
2024-12-31 |
4 |
=call("adjustprice.splx", "", call("loadkday.splx", A1, A2,A3) ) |
5 |
=call("loadcompany.splx",A1,A2,A3) |
6 |
=A5.(statdate) |
7 |
=A4.group(A6.pseg(tdate-1)) |
8 |
=A7.(~.derive(close*A5(A7.#).totalshare:total_value)).conj() |
9 |
=A8.new(code,tdate,if(#==1,0,(high - low)/ close[-1]):amp, total_value) |
10 |
=A9.sert(3) |
11 |
=A10(1).numnorm() |
12 |
=A9.([lg(total_value)].insert(0,1)) |
13 |
=linefit(A12,A11(1)).conj() |
14 |
=A9.derive(lg(total_value)*A13(1)+A13(2):amp_pre) |
15 |
=A14.new(code,tdate,amp-amp_pre: NSA) |
A1-A5 读取股票数据和公司基本面数据
A6-A7 将股票数据按照基本面数据的 statdate 分组
A8 计算总市值
A9 计算股票振幅 amp
A10 对 amp 去极值
A11 去极值后标准化
A12 构造最小二乘法拟合需要的矩阵 X
A13 最小二乘法线性拟合,返回拟合系数
A14 计算股票振幅的预测值
A15 计算股票振幅和预测值的偏差,即中性股票振幅
为了使用方便,可以封装成脚本供调用。
脚本代码:
A |
|
1 |
=data2.(statdate) |
2 |
=data1.group(A1.pseg(tdate-1)) |
3 |
=A2.(~.derive(close*data2(A2.#).totalshare:total_value)).conj() |
4 |
=A3.new(code,tdate,if(#==1,0,(high - low)/ close[-1]):amp, total_value) |
5 |
=A4.sert(3) |
6 |
=A5(1).numnorm() |
7 |
=A4.([lg(total_value)].insert(0,1)) |
8 |
=linefit(A7,A6(1)).conj() |
9 |
=A4.derive(lg(total_value)*A8(1)+A8(2):amp_pre) |
10 |
=A9.new(code,tdate,amp-amp_pre: NSA) |
脚本名保存为 beta.splx。
脚本参数:
data1 |
序表,某支股票的日线数据 |
data2 |
序表,股票基本面数据 |
返回数据集结构:
code |
股票代码 |
tdate |
日期 |
NSA |
中性股票振幅 |
例如,调用脚本计算浦发银行 2024 年的中性化股票振幅。
A |
B |
|
… |
… |
计算出源数据 |
6 |
=call("nsa.splx",A4,A5) |
调用脚本 |
运行效果: