问题描述
IC/IR算的数字再好看,都是针对整个市场3000多个股票的,但实际上小散户只能按照因子值最高的5个或者10个票来买。
那问题就来了,最高的5个或者10个票的成绩往往根本达不到group0的水平,最最起码也是波动巨大,根本不靠谱的。要达到因子的实际成绩往往要一口气买个50个或者100个股票才能稳定下来。
有什么数学办法或者投资的思路能更好的锁定在只选5个或者只选10个股票的情况下也成绩非常优秀的因子吗?
解决方案
这是一个非常经典且切中量化实盘痛点的问题。传统的单因子分析(如IC/IR)衡量的是因子在全市场横截面上的线性相关性。一个IC很高的因子,可能只是因为它能很好地把排名第1000的股票和第2000的股票区分开来,但它在最头部的10只股票上可能完全失效,甚至呈现负相关。这就是所谓的“缺乏顶部效应”。
对于只能买5-10只股票的小资金散户,要解决这个问题,可以从数学评价指标的改进和投资逻辑的优化两个维度来入手。在JoinQuant(聚宽)平台上,你可以通过以下几种方法来挖掘和优化具有“顶部效应”的因子:
一、 数学与评价方法的改进
1. 放弃全市场IC,改用“尾部IC (Tail IC)”或“头部胜率”
不要看全市场的Rank IC。你可以将股票池缩小到因子值排名前10%的股票,只在这10%的股票中计算因子值与下期收益率的Rank IC。如果在这个极值区间内IC依然显著为正,说明该因子具有很好的顶部区分度。
此外,直接计算头部5-10只股票的绝对胜率和盈亏比,比看收益率均值更靠谱。均值容易被单只暴涨的股票拉高,而胜率能反映这5-10只股票是否“普遍优秀”。
2. 增加分位数(Quantiles)的颗粒度
在使用聚宽的 analyze_factor 时,默认的 quantiles=5(分为5组,每组几百只票)。你应该将其设置为 quantiles=20 甚至 quantiles=50。观察第1组(Top 2%)的收益率是否显著高于第2组和第3组。如果第1组收益率反而不如第2组,说明该因子在极值处存在“反转”或“噪音”,没有顶部效应。
3. 引入非线性模型(机器学习)
线性因子往往在极值处失效。你可以使用树模型(如XGBoost、Random Forest)。树模型天生就是用来寻找“条件分支”的,它们非常擅长捕捉“当因子A大于X,且因子B小于Y时,胜率极高”这种非线性的顶部特征。
二、 投资思路与策略的优化
为什么头部的5-10只股票波动巨大、极不稳定?因为极值往往伴随着极端的风险暴露。比如某天排名前5的股票全是微盘股,或者全是某个冷门行业的ST股。解决思路如下:
1. 严格的风险中性化(Neutralization)
在选出前5名之前,必须对因子进行行业和市值的剔除与中性化。在聚宽中,使用 neutralize(data, how=['jq_l1', 'market_cap'])。中性化后选出的前5名,就不会扎堆在单一行业或极小市值里,这能极大地降低这5只股票的系统性波动。
2. 多因子交集(共振选股)
单一因子选出的前5名往往包含大量噪音(比如因为一次偶然的资产重组导致财务数据畸高)。
思路:不要用单因子排序选前5。用3个逻辑独立的因子(例如:价值因子 + 动量因子 + 质量因子)。
- 先用因子A选出前20%(600只)
- 在600只中用因子B选出前20%(120只)
- 在120只中用因子C选出前10%(12只)
这种“交集法”选出的头部股票,其基本面和技术面都没有明显硬伤,稳定性远超单因子极值。
3. 增加流动性与基本面“底线”过滤
极值票往往是流动性极差的票。在计算因子前,先在股票池中剔除:
- 市值最小的20%股票
- 成交额最低的20%股票
- ST、停牌、上市不满一年的股票
在一个“干净且流动性好”的池子里算出的Top 5,实盘的可靠性会大幅提升。
三、 聚宽代码实现示例:验证顶部效应
你可以用以下逻辑在聚宽研究环境中测试你的因子是否具有顶部效应:
from jqfactor import get_factor_values, neutralize
import pandas as pd
import numpy as np
# 1. 获取因子数据 (例如:营业利润率)
factor_data = get_factor_values(securities=get_index_stocks('000985.XSHG'),
factors=['operating_profit_ratio'],
start_date='2023-01-01',
end_date='2023-12-31')['operating_profit_ratio']
# 2. 行业与市值中性化 (降低极值风险)
factor_data_neu = neutralize(factor_data, how=['jq_l1', 'market_cap'], axis=1)
# 3. 模拟每天只买Top 10的收益
def get_top_n_returns(factor_df, n=10):
# 获取下期收益率 (这里简化处理,实际需用 get_price 计算 forward returns)
# 假设 forward_returns_df 是已经计算好的下期收益率矩阵
# ...
pass
# 核心逻辑:每天对因子值排序,取前10
# top_10_mask = factor_data_neu.rank(axis=1, ascending=False) <= 10
# top_10_returns = forward_returns_df[top_10_mask].mean(axis=1) # 每天这10只票的平均收益
# print("Top 10 胜率:", (top_10_returns > 0).mean())
总结:
散户做量化,不要迷信全市场IC。把精力放在:1. 股票池的清洗(去微盘去垃圾);2. 因子的严格中性化;3. 多因子交叉过滤。只有经过这三步,你选出的Top 5-10只股票,才是真正具有实战价值的“顶部效应”组合。