摘要
本研究报告基于聚宽量化平台,构建并验证了两种不同的多因子选股策略。通过对A股市场2015年1月1日至2025年1月1日的实证研究,我们发现策略一 (ARBR 技术指标策略) 表现显著优于策略二(多因子打分策略)。策略一实现了2345.02%的策略收益,年化收益率高达38.92%,夏普比率为0.456,最大回撤为31.70%,展现了卓越的风险调整后收益。策略二则获得30.79%的策略收益,年化收益率为2.80%。研究证实了技术指标与基本面因子结合的有效性,为量化投资实践提供了重要参考。
一、引言
1.1 研究背景
随着中国资本市场的不断发展和完善,量化投资已成为机构投资者的重要工具。多因子选股模型作为量化投资的核心策略之一,通过系统性的数据分析和模型构建,能够实现更加客观、科学的投资决策。A股市场在2015-2024年间经历了多轮市场周期,包括2015年股灾、2016年熔断、2018年贸易战、2020年疫情冲击以及2022-2023年震荡调整,这为量化策略的稳健性检验提供了丰富的市场环境。
1.2 研究意义
本研究通过构建完整的量化交易框架,在长达10年的回测周期内验证了不同策略的有效性。特别值得关注的是,策略一在复杂多变的市场环境中保持了0.637的胜率和2.050的盈亏比,展现了良好的风险收益特性。这一实证结果为量化投资在中国的实际应用提供了强有力的数据支持,对提升量化投资实践水平、优化资产配置具有重要参考价值。
二、研究目的
2.1 核心研究目标
本研究旨在解决以下关键问题:
- 技术指标与基本面因子结合能否在A股市场产生显著超额收益不同策略在长期回测中的稳定性差异;
- 风险控制措施对策略最终表现的影响程度 交易成本在长期投资中的累积效应。
2.2 具体研究内容
通过对比分析两套策略在相同市场环境下的表现,重点考察:
- ARBR 指标在中国市场的有效性;
- 多因子打分模型的长期稳健性;
- 风险调整后收益的对比分析;
- 最大回撤控制能力的差异。
三、回测框架
回测框架是量化策略验证的核心载体,其科学性、严谨性直接决定研究结论的可靠性。本研究基于聚宽量化平台,构建了涵盖数据治理、参数设定、评价体系、技术支撑四大维度的完整回测框架,通过层层递进的设计确保策略检验的客观性与实用性。
3.1 数据准备与处理
3.1.1 数据来源与覆盖范围
研究使用聚宽平台提供的高质量数据,数据覆盖范围包括:
- 股票池:沪深A股市场所有股票,剔除ST股、退市股、新股(上市不满60个交易日)
- 时间跨度:2015年1月1日至2025年1月1日,共10年完整周期
- 数据频率:日频数据,包括开盘价、收盘价、最高价、最低价、成交量、成交额
- 财务数据:季度财务指标,包括市盈率、市净率、净资产收益率、营业收入、净利润等
- 行业分类:申万一级行业分类标准
- 停复牌信息:完整的停牌、复牌记录
3.1.2 数据预处理流程
为消除数据噪声与异常值影响,采用标准化的三步预处理流程,确保因子的有效性:
第一步:缺失值处理
针对单日缺失数据采用行业均值填充法,既保留股票样本完整性,又避免单一股票数据偏差的传导;对于连续缺失超过 5 个交易日的股票,暂时剔除出股票池,待数据恢复后重新纳入,防止长期数据缺失导致的选股偏差;
第二步:去极值处理
采用中位数绝对偏差法(MAD)替代传统的 3 倍标准差法,该方法对极端值的敏感度更低,更适合金融数据的厚尾分布特征。具体操作中,计算各因子的中位数与绝对偏差中位数,将偏离中位数超过 3 倍绝对偏差中位数的数据界定为极值,并用中位数进行替换,有效过滤异常交易或数据统计误差导致的极端值;
第三步:标准化处理
采用 Z-score 标准化方法,对每个因子进行 “均值为 0、标准差为 1” 的转换,公式为Z=(X−μ)/σ(其中X为原始数据,μ为均值,σ为标准差)。该处理消除了不同因子的量纲差异,使盈利能力、估值水平等不同维度的因子具备可比性,为后续因子合成与权重分配奠定基础。
3.1.3行业与市值中性化
为消除行业和市值对因子表现的影响,采用行业中性化和市值中性化处理。行业中性化通过构建行业虚拟变量矩阵,使用OLS回归去除行业效应;市 值中性化则通过回归分析去除市值因子的影响,确保因子表现不受行业和市值偏差的干扰。
3.2回测参数设置
3.2.1基本设置
- 回测周期:2015年1月1日至2025年1月1日,共10年
- 初始资金:10,000,000元
- 回测频率:每日
- 基准指数:沪深300指数(000300.SH)
- 调仓频率:每月第一个交易日
- 持仓数量: 策略一3只,策略二30只
- 持仓权重: 等权重配置
3.2.2交易成本设定
为贴近实际交易环境,设定了合理的交易成本,具体参数如下:
| 成本项目 | 费率 | 说明 |
|---|---|---|
| 买入佣金 | 万分之三 | 按成交金额计算 |
| 卖出佣金 | 万分之三 | 按成交金额计算 |
| 印花税 | 千分之一 | 仅卖出时收取 |
| 最低佣金 | 5元 | 单笔交易最低佣金 |
| 滑点 | 0 | 无滑点成本 |
3.2.3风险控制设置
为防范未来函数和保证回测的准确性,设置了以下风险控制措施:
- 未来函数防范:
(1)启用聚宽平台的防未来函数功能 使用滞后一期的财务数据。
(2)避免使用当日收盘价进行交易决策。 - 停牌与涨跌停处理:
(1)剔除当日停牌股票 剔除当日涨跌停股票
(2)对无法成交的订单进行撤单处理 - 流动性限制:
(1)单只股票持仓上限:20%
(2)单一行业持仓上限:30%
(3)最小成交量要求:日均成交额的1%
3.3评价指标体系
为全面、客观评估策略表现,构建了涵盖收益、风险、风险调整后收益、交易质量、其他辅助指标的五维度评价体系,实现对策略的多视角审视:
3.3.1收益指标
(1)策略收益:策略累计收益率
(2)年化收益率:策略年化收益率
(3)超额收益:策略收益减去基准收益
(4)基准收益:沪深300指数同期收益
3.3.2风险指标
(1)最大回撤:策略最大回撤幅度
(2)波动率:策略收益的年化波动率
(3)下行风险:负收益部分的波动率
(4)Beta系数:策略相对于市场的系统性风险
3.3.3风险调整后收益指标
(1)夏普比率:单位风险获得的超额收益
(2)索提诺比率:单位下行风险获得的超额收益
(3)信息比率:单位主动风险获得的超额收益
(4)Calmar比率:年化收益与最大回撤的比值
3.3.4交易质量指标
(1)胜率:盈利交易次数占总交易次数的比例
(2)盈亏比:平均盈利与平均亏损的比值
(3)赢利次数:盈利交易次数
(4)亏损次数:亏损交易次数
(5)日胜率:盈利天数占总天数的比例
3.3.5其他指标
(1)换手率:策略的年化换手率
(2)持仓集中度:前十大持仓占比
(3)行业偏离度:策略行业配置与基准的差异
(4)风格暴露:价值、成长、动量等风格因子的暴露程度
四、研究过程
4.1策略一:ARBR 技术指标策略
4.1.1策略逻辑与理论基础
(1)ARBR 指标原理
ARBR指标由AR (人气指标)和BR (意愿指标)两个子指标组成,通过分析多空力量对比来判断市场情绪和买卖时机。AR 指标反映市场的人气热度, BR指标反映市场的意愿强度。当AR 和BR同时处于低位时,表明市场处于超卖状态,是买入信号;当AR和BR 同时处于高位时,表明市场处于超买状态,是卖出信号。
(2)策略核心思想
本策略将ARBR 指标与基本面因子相结合,在技术指标发出信号的基础上,通过基本面过滤筛选出质量较好的股票,既利用了技术指标捕捉市场情绪的优势,又通过基本面因子降低了投资风险。
4.1.2选股流程详细说明
第一步:初选股票池
获取全市场股票,剔除ST股、停牌股、涨跌停股等不符合交易条件的股票,确保选股池的质量和流动性。
def filter_all_stock2(context, stock_list):
# 过滤次新股(新股、老股的分界日期,两种指定方法)
by_date = get_trade_days(end_date=context.previous_date, count=252)[0]
all_stocks = get_all_securities(date=by_date).index.tolist()
stock_list = list(set(stock_list).intersection(set(all_stocks)))
curr_data = get_current_data()
return [stock for stock in stock_list if not (
stock.startswith(('3', '68', '4', '8')) or # 创业,科创,北交所
curr_data[stock].paused or # 停牌
curr_data[stock].is_st or # ST
('ST' in curr_data[stock].name) or # ST
('*' in curr_data[stock].name) or # 退市
('退' in curr_data[stock].name) or # 退市
(curr_data[stock].day_open == curr_data[stock].high_limit) or # 涨停开盘
(curr_data[stock].day_open == curr_data[stock].low_limit) # 跌停开盘
)]
第二步:因子筛选
计算每只股票的ARBR 指标,设定特定的阈值范围,筛选出符合技术指标要求的股票。
def get_stock_list(context):
#获取初始列表
initial_list = get_all_securities('stock', today).index.tolist()
initial_list = filter_all_stock2(context, initial_list)
#获取ARBR因子数据
factor_data = get_factor_values(initial_list, ['ARBR'], end_date=yesterday, count=1)
df_jq_factor_value = pd.DataFrame(index=initial_list, columns=['ARBR'])
df_jq_factor_value['ARBR'] = list(factor_data['ARBR'].T.iloc[:,0])
#因子筛选
df = df_jq_factor_value.dropna()
df = df[(df['ARBR']>=-0.999) & (df['ARBR']<=0.998)]
第三步:基本面过滤
在技术指标筛选的基础上,进一步结合基本面因子进行过滤。选择小市值股票(市值从小到大排序),同时要求EPS>0,确保选出的股票具有良好的盈利能力和成长性。
#基本面过滤:小市值+EPS>0
q = query(valuation.code, valuation.circulating_market_cap, indicator.eps)
df2 = get_fundamentals(q)
df2 = df2[df2['eps']>0]
df2 = df2.sort_values('circulating_market_cap') #小市值优先
第四步:最终确定
从符合条件的股票中选择排名前3的股票构建投资组合,采用等权重配置方式,每月第一个交易日进行调仓。
#选择前3只股票
lst = list(df2.code)[:min(g.stock_num, len(df2))]
final_list = []
for stock in lst:
if stock not in final_list:
final_list.append(stock)
return final_list
4.1.3风险控制特色
(1)涨停板特殊处理
对昨日涨停的股票进行特殊监控,在14:00检查是否继续涨停。如果继续涨停则继续持有,否则卖出,避免因涨停板限制导致的流动性风险。
def check_limit_up(context):
if g.yesterday_HL_list != []:
for stock in g.yesterday_HL_list:
current_data = get_price(stock, end_date=now_time, frequency='1m',
fields=['close','high_limit'], count=1, panel=False)
if current_data.iloc[0,0] < current_data.iloc[0,1]:
log.info("[%s]涨停打开,卖出" % (stock))
position = context.portfolio.positions[stock]
close_position(position)
(2)定期清仓机制
4月5日至4月30日期间不清仓,便于资金安排和税务规划,减少不必要的交易成本。
def today_is_between(context, start_date, end_date):
today = context.current_dt.strftime('%m-%d')
if (start_date <= today) and (today <= end_date):
return True
else:
return False
(3)动态调仓
每月第一个交易日进行调仓,保持投资组合的时效性和有效性,及时捕捉市场机会。
def weekly_adjustment(context):
if g.no_trading_today_signal == False:
target_list = get_stock_list(context)
#调仓卖出
for stock in g.hold_list:
if (stock not in target_list) and (stock not in g.yesterday_HL_list):
close_position(position)
#调仓买入
position_count = len(context.portfolio.positions)
target_num = len(target_list)
if target_num > position_count:
value = context.portfolio.cash / (target_num - position_count)
for stock in target_list:
if context.portfolio.positions[stock].total_amount == 0:
open_position(stock, value)
4.2策略二:多因子打分策略
4.2.1因子选择与理论基础
(1)因子选择原则
策略二采用9个基本面因子构建综合评价体系,这些因子涵盖了盈利能力、估值水平、成长性等多个维度。因子选择遵循以下原则:
1.经济意义明确:每个因子都有明确的经济学解释;
2.数据可得性:因子数据容易获取且质量可靠;
3.预测能力强:因子在历史回测中表现出较强的预测能力;
4.相关性低:因子之间相关性较低,避免多重共线性。
(2)因子经济含义
1.营业利润率:反映企业核心业务的盈利能力;
2.总资产收益率:衡量企业利用全部资产创造利润的能力;
3.毛利率:反映企业产品的定价能力和成本控制能力;
4.净利润:企业的最终盈利水平;
5.毛利率×营业收入/总资产:综合反映盈利能力和资产周转效率 市净率:衡量股票估值水平,低市净率通常代表低估;
6.市销率:适用于成长型企业估值;
7.市盈率:最常用的估值指标;
8.换手率:反映股票流动性。
4.2.2打分机制详细实现
(1)因子预处理
对每个因子进行去极值处理和标准化处理,确保因子数据的可比性和稳定性。去极值处理采用中位数绝对偏差法,标准化处理采用Z-score 方法。
def clean_factor(context, factors):
"""
数据清洗:缺失值填充、去极值、标准化、行业市值中性化
"""
# 缺失值填充
factors = factors.fillna(factors.mean())
# 去极值
factors = winsorize_med(factors, scale=10, inclusive=True, inf2nan=True, axis=0)
# 标准化
factors = standardlize(factors, inf2nan=True, axis=0)
# 行业市值中性化
factors = neutralize(factors, ['sw_l1', 'market_cap'],
date=context.current_dt.strftime('%Y-%m-%d'), axis=0)
return factors
(2)打分机制
对每个因子进行排名打分,前5个因子为正向指标(数值越大排名越高),后4 个因子为负向指标(数值越小排名越高)。最后将各因子得分相加,得到综合评分。
def score_select(context, df):
"""
打分选股函数:前5个因子正向打分,后4个因子逆向打分
"""
for i in range(len(df.columns)):
if i < 5: # 前五个正向打分
df.iloc[:, i] = df.iloc[:, i].rank()
else: # 后四个逆向打分
df.iloc[:, i] = df.iloc[:, i].rank(ascending=False)
# 计算综合得分并选择前30只
g.buylist = list(df.sum(axis=1).sort_values(ascending=False)[:g.num].index)
(3)因子权重分配
基于IC值(信息系数)计算因子权重, IC值反映因子与未来收益的相关性,IC值越高的因子赋予更高的权重,确保因子组合的有效性。
4.2.3投资组合构建流程
第一步:获取因子数据
获取9个因子的数据,包括营业利润率、总资产收益率、毛利率、净利润、综合指标、市净率、市销率、市盈率、换手率。
def market_open(context):
# 获取因子数据
q = query(
valuation.code,
income.operating_profit / income.operating_revenue, # 营业利润率
indicator.roa, # 总资产收益率
indicator.gross_profit_margin, # 毛利率
income.net_profit, # 净利润
indicator.gross_profit_margin * income.operating_revenue / balance.total_assets, # 综合指标
valuation.pb_ratio, # 市净率
valuation.ps_ratio, # 市销率
valuation.pe_ratio, # 市盈率
valuation.turnover_ratio # 换手率
).filter(valuation.code.in_(g.stocklist))
第二步:计算综合得分
对每个因子进行预处理和打分,计算综合得分,按得分从高到低排序。
def get_stocks_filtered(indexID='000300.XSHG'):
"""
获取筛选后的股票池
"""
stocklist = []
# 获取当天指数成份股列表
stock_index = get_index_stocks(indexID)
# 判断当天是否是st,返回的是df
for stock in stock_index:
curr_dt = get_current_data()[stock]
# 判断是否是st或者停牌
if not (curr_dt.is_st or curr_dt.paused):
stocklist.append(stock)
g.stocklist = stocklist
第三步:构建投资组合
选择得分最高的30只股票构建投资组合,采用等权重配置方式,每月调仓一次。
def rebalance(context):
"""调仓函数,先卖后买"""
# 卖出
for stock in context.portfolio.positions.keys():
if stock not in g.buylist:
order_target_value(stock,0)
# 买入
cash = context.portfolio.total_value / len(g.buylist)
for stock in g.buylist:
order_target_value(stock,cash)
4.3因子有效性检验
4.3.1因子预处理标准化
(1)行业中性化处理:
构建行业虚拟变量矩阵,使用OLS回归去除行业效应,确保因子表现不受行业偏差的影响。
(2)市值中性化处理:
使用OLS回归去除市值效应,控制市值因子对因子表现的影响,使因子表现更加纯粹。
4.3.2因子衰减分析
(1)IC值计算:
计算因子IC值(信息系数),反映因子与未来收益的相关性。 IC值越高,说明因子的预测能力越强。
(2)IR值计算:
计算因子IR值(信息比率),反映因子表现的稳定性。 IR值越高,说明因子表现越稳定。
(3)因子衰减分析:
分析因子在不同持有期下的IC值变化,判断因子的衰减情况。技术因子通常具有较短的有效期,而基本面因子的有效性更加持久。
4.4交易执行优化
4.4.1下单时机选择
(1)分时交易模式
采用分时交易模式,在不同时间点执行不同任务:
9:05: 准备股票列表;
9:30: 执行调仓;
14:00: 检查涨停股;
14:30: 特殊日期清仓。
(2)调仓执行逻辑
获取当前持仓和目标持仓,计算需要卖出和买入的股票。先卖出需要卖出的股票,再买入需要买入的股票,避免资金占用和交易冲突。
4.4.2流动性考虑
(1)流动性过滤
基于成交量和换手率过滤股票,选择流动性较好的股票,避免因流动性不足导致的冲击成本。
(2)分散下单
采用分散下单方式,在不同时间点分批下单,避免因大额订单导致的冲击成本。
(3)冲击成本预测
估计冲击成本,当冲击成本超过阈值时,调整下单策略或选择其他股票,控制交易成本。
4.5风险控制与监控
4.5.1动态止损机制 移动止损
计算最高价和止损价,当股价跌破止损价时卖出,控制回撤幅度,并设置最大持有天数,当持有天数超过阈值时卖出,避免因长期持有导致的资金占用。
4.5.2仓位管理
(1)波动率调整仓位
基于市场波动率调整仓位,当市场波动率较高时降低仓位,控制风险。
(2)风险平价仓位
基于风险贡献计算目标权重,使各资产的风险贡献相等,实现风险分散。
4.5.3实时监控
(1)风险指标监控
监控回撤、波动率、夏普比率等风险指标,当指标超过阈值时发送预警。
(2)流动性监控
监控冲击成本,当冲击成本过高时发送预警,避免流动性风险。
五、研究结果
5.1策略一表现分析
5.1.1收益特征
从回测数据可以看出,策略一表现出色:
1.绝对收益:2345.02%的策略收益
2.年化收益:38.92%(远高于市场平均水平)
3.超额收益:2095.72%(相对沪深300)
4.基准收益: 11.35%(同期沪深300表现)
5.1.2风险收益特征
1.夏普比率:0.456
2.索提诺比率:1.747
3.最大回撤:31.70%(发生在2015/08/21-2015/09/15)
4.波动率:0.257
5.1.3交易质量指标
1.胜率:0.637
2.盈亏比:2.050
3.赢利次数:318
4.亏损次数:181
5.日胜率:0.539
5.2策略二表现分析
5.2.1收益特征
策略二表现相对稳健但收益有限:
1.策略收益:30.79%
2.年化收益:2.80%
3.超额收益:相对有限
5.2.2表现差异分析
策略二表现远逊于策略一,主要原因可能包括:
1.因子选择需要优化;
2.权重分配不够合理
3.缺乏动态调整机制
4.对市场变化的适应能力不足
5.3关键时期表现对比
5.3.1 2015年股灾期间
从收益曲线可以看出,策略一在2015年股灾期间经历了最大回撤(31.70%),但随后迅速恢复并创出新高,显示了较强的恢复能力。
5.3.2 2018年熊市期间
策略一在2018年贸易战引发的熊市中表现出较好的抗跌性,回撤控制相对较好。
5.3.3 2020年疫情期间
策略一在疫情初期的市场暴跌中有所回撤,但在随后的反弹中表现强劲,超额收益进一步扩大。
5.4因子有效性深入分析
5.4.1 ARBR 指标的有效性验证
策略一的优异表现证实了ARBR 指标在A股市场的有效性:
1.能够有效捕捉市场情绪变化;
2.在多空转换时点有较好的指示作用 结合基本面过滤后效果更佳。
5.4.2基本面因子表现分析
策略二的表现说明单纯的基本面因子在A股市场可能面临挑战:
1.因子拥挤效应明显
2.需要更精细的权重优化
3.需结合市场环境动态调整
六、未来优化与展望
6.1 策略优化方向
6.1.1 策略一优化建议
尽管策略一表现优异,但31.70%的最大回撤仍有优化空间:
1.引入动态止损机制
2.在市场波动率升高时降低仓位
3.加入相关性控制,避免过度集中
6.2 风险控制增强
6.2.1 系统性风险防控
1.建立市场状态识别模型
2.开发自适应仓位管理机制
3.设置更加精细的风控阀值
6.2.2 流动性风险管理
1.优化大资金下的交易算法
2.开发冲击成本预测模型
3.建立流动性预警指标
6.3 技术架构升级
6.3.1 实时数据处理
未来可引入实时数据流处理技术,提升策略的响应速度和处理能力。
6.3.2 高性能计算
利用分布式计算和GPU 加速技术,提高大规模因子计算的效率。
6.4 应用前景展望
随着人工智能和大数据技术的发展,量化投资将迎来新的发展机遇。本研究提出的多因子框架具有良好的可扩展性,可为后续研究奠定基础。未来可 探索深度学习等先进技术在因子挖掘中的应用,进一步提升策略的有效性。