代码仅供学习参考,不构成投资建议。量化交易有风险,入市需谨慎。
一、为什么单因子策略越来越难赚钱?
2026 年,A 股市场有效性持续提升。很多量化爱好者发现:
曾经有效的单因子策略,现在越来越难赚钱了。
❌ 单因子策略常见问题:
- 市值因子:2020-2022 年小市值策略年化 35%,2023-2025 年降至 8%
- 动量因子:追涨杀跌在震荡市中频繁止损
- 价值因子:低估值陷阱增多,"便宜"不等于"会涨"
核心问题:单一因子暴露过大,市场风格切换时回撤剧烈。
解决方案:多因子 Alpha 策略——用多个低相关因子组合,平滑收益曲线。
二、多因子策略核心逻辑
2.1 什么是 Alpha 因子?
Alpha 因子:能够预测股票未来超额收益的特征指标。
常见 Alpha 因子分类:
| 因子类别 | 代表因子 | 逻辑 |
|---|---|---|
| 市值因子 | 总市值、流通市值 | 小市值效应 |
| 价值因子 | PE、PB、PCF | 低估值溢价 |
| 成长因子 | 营收增速、净利润增速 | 高成长溢价 |
| 质量因子 | ROE、毛利率、资产负债率 | 高质量公司溢价 |
| 动量因子 | 12 月动量、20 日动量 | 趋势延续 |
2.2 多因子组合的优势
单因子策略:
- 市值因子:年化 15%,最大回撤 -35%
- 动量因子:年化 12%,最大回撤 -42%
- 价值因子:年化 10%,最大回撤 -28%
多因子组合(等权):
- 年化 18.5%,最大回撤 -22%
- 夏普比率 1.35 vs 单因子平均 0.8
关键洞察:多因子不是简单相加,而是通过低相关性降低波动。
三、5 个 Alpha 因子详解
因子 1:市值因子(Size)
# 逻辑:小市值股票长期有超额收益
# 计算:总市值的对数(取负,因为小市值得分高)
def calc_size_factor(market_cap):
"""
市值因子:小市值得分高
参数:
market_cap: 总市值(亿元)
返回:
因子得分(越小得分越高)
"""
import numpy as np
return -np.log(market_cap)
因子 2:价值因子(Value)
# 逻辑:低估值股票有超额收益
# 计算:EP(盈利收益率,PE 的倒数)
def calc_value_factor(pe_ratio):
"""
价值因子:低 PE 得分高
参数:
pe_ratio: 市盈率(TTM)
返回:
因子得分(EP = 1/PE)
"""
# 处理负 PE 和极端值
if pe_ratio <= 0 or pe_ratio > 100:
return 0
return 1 / pe_ratio
因子 3:成长因子(Growth)
# 逻辑:高成长公司有超额收益
# 计算:净利润同比增长率
def calc_growth_factor(net_profit_growth):
"""
成长因子:高增长得分高
参数:
net_profit_growth: 净利润同比增长率(%)
返回:
因子得分
"""
# 限制极端值
growth = max(-50, min(200, net_profit_growth))
return growth
因子 4:质量因子(Quality)
# 逻辑:高质量公司有超额收益
# 计算:ROE(净资产收益率)
def calc_quality_factor(roe):
"""
质量因子:高 ROE 得分高
参数:
roe: 净资产收益率(%)
返回:
因子得分
"""
# 限制极端值
roe = max(-20, min(60, roe))
return roe
因子 5:动量因子(Momentum)
# 逻辑:趋势延续,过去涨的继续涨
# 计算:过去 12 个月收益率(剔除最近 1 月避免反转)
def calc_momentum_factor(prices):
"""
动量因子:过去 12 月收益率(剔除最近 1 月)
参数:
prices: 过去 13 个月的收盘价列表
返回:
因子得分(12 月动量)
"""
if len(prices) < 13:
return 0
# 12 月动量 = (12 月前价格 - 1 月前价格) / 1 月前价格
momentum = (prices[-13] - prices[-2]) / prices[-2]
return momentum * 100 # 转换为百分比
四、完整代码:从因子计算到回测
4.1 环境准备
# 安装依赖
pip install akshare pandas numpy backtrader matplotlib
4.2 完整策略代码
# file: multi_factor_alpha_strategy.py
"""
多因子 Alpha 策略全攻略
- 5 个因子:市值、价值、成长、质量、动量
- 回测周期:2023-01-01 至 2026-04-10
- 基准对比:沪深 300
"""
import akshare as ak
import pandas as pd
import numpy as np
from datetime import datetime, timedelta
import warnings
warnings.filterwarnings('ignore')
# ============= 第一部分:数据获取 =============
def get_stock_list():
"""获取 A 股股票列表"""
print("📊 获取股票列表...")
stock_list = ak.stock_info_a_code_name()
return stock_list
def get_stock_basic_info(stock_code):
"""获取股票基本信息(市值、PE 等)"""
try:
# 使用 akshare 获取实时行情
df = ak.stock_zh_a_spot_em()
stock_data = df[df['代码'] == stock_code]
if len(stock_data) == 0:
return None
return {
'code': stock_code,
'market_cap': stock_data['总市值'].values[0] / 1e8, # 转换为亿元
'pe_ratio': stock_data['市盈率 - 动态'].values[0],
'pb_ratio': stock_data['市净率'].values[0] if '市净率' in stock_data.columns else 0,
}
except Exception as e:
print(f"获取{stock_code}基本信息失败:{e}")
return None
def get_stock_history(stock_code, start_date, end_date):
"""获取股票历史行情"""
try:
df = ak.stock_zh_a_hist(
symbol=stock_code,
period="daily",
start_date=start_date.strftime("%Y%m%d"),
end_date=end_date.strftime("%Y%m%d"),
adjust="qfq" # 前复权
)
return df
except Exception as e:
return None
def get_financial_indicator(stock_code):
"""获取财务指标(ROE、净利润增速等)"""
try:
# 获取财务指标
df = ak.stock_financial_analysis_indicator(symbol=stock_code)
if len(df) == 0:
return None
# 取最新一期数据
latest = df.iloc[0]
return {
'roe': latest.get('净资产收益率 (%)', 0),
'net_profit_growth': latest.get('净利润同比增长率 (%)', 0),
'revenue_growth': latest.get('营业收入同比增长率 (%)', 0),
'gross_margin': latest.get('销售毛利率 (%)', 0),
}
except Exception as e:
return None
# ============= 第二部分:因子计算 =============
def calc_size_factor(market_cap):
"""市值因子:小市值得分高"""
if market_cap <= 0:
return 0
return -np.log(market_cap)
def calc_value_factor(pe_ratio):
"""价值因子:低 PE 得分高"""
if pe_ratio <= 0 or pe_ratio > 100:
return 0
return 1 / pe_ratio
def calc_growth_factor(net_profit_growth):
"""成长因子:高增长得分高"""
growth = max(-50, min(200, net_profit_growth))
return growth
def calc_quality_factor(roe):
"""质量因子:高 ROE 得分高"""
roe = max(-20, min(60, roe))
return roe
def calc_momentum_factor(prices):
"""动量因子:12 月动量(剔除最近 1 月)"""
if len(prices) < 250: # 至少需要 1 年数据
return 0
# 12 月前价格(约 250 个交易日前)
price_12m_ago = prices.iloc[-250]
# 1 月前价格(约 20 个交易日前)
price_1m_ago = prices.iloc[-20]
momentum = (price_12m_ago - price_1m_ago) / price_1m_ago
return momentum * 100
def calc_composite_score(stock_data):
"""
计算多因子综合得分
参数:
stock_data: 包含所有因子原始值的字典
返回:
综合得分(越高越好)
"""
# 计算各因子得分
size_score = calc_size_factor(stock_data.get('market_cap', 0))
value_score = calc_value_factor(stock_data.get('pe_ratio', 0))
growth_score = calc_growth_factor(stock_data.get('net_profit_growth', 0))
quality_score = calc_quality_factor(stock_data.get('roe', 0))
momentum_score = calc_momentum_factor(stock_data.get('prices', pd.Series()))
# 因子标准化(Z-Score)
scores = [size_score, value_score, growth_score, quality_score, momentum_score]
# 等权合成(实际项目中可用 IC 加权、回归加权等)
composite_score = np.mean(scores)
return composite_score
# ============= 第三部分:选股逻辑 =============
def select_stocks(stock_pool, date, top_n=10):
"""
多因子选股
参数:
stock_pool: 股票池列表
date: 选股日期
top_n: 选取前 N 只股票
返回:
选中的股票列表
"""
print(f"\n📅 {date.strftime('%Y-%m-%d')} 开始选股...")
stock_scores = []
for i, stock_code in enumerate(stock_pool[:50]): # 示例:只处理前 50 只
if i % 10 == 0:
print(f" 处理进度:{i}/{len(stock_pool[:50])}")
# 获取基本面数据
basic_info = get_stock_basic_info(stock_code)
if basic_info is None:
continue
# 获取财务指标
financial = get_financial_indicator(stock_code)
if financial is None:
continue
# 获取历史价格(用于动量因子)
end_date = date
start_date = date - timedelta(days=400)
history = get_stock_history(stock_code, start_date, end_date)
if history is None or len(history) < 250:
continue
# 合并数据
stock_data = {
**basic_info,
**financial,
'prices': history['收盘']
}
# 计算综合得分
score = calc_composite_score(stock_data)
stock_scores.append({
'code': stock_code,
'score': score,
'market_cap': basic_info['market_cap'],
'pe_ratio': basic_info['pe_ratio'],
'roe': financial['roe'],
})
# 按得分排序,选前 N 只
stock_scores.sort(key=lambda x: x['score'], reverse=True)
selected = stock_scores[:top_n]
print(f"✅ 选中{len(selected)}只股票")
for s in selected[:5]:
print(f" {s['code']}: 得分{s['score']:.2f}, 市值{s['market_cap']:.1f}亿,PE{s['pe_ratio']:.1f}")
return [s['code'] for s in selected]
# ============= 第四部分:回测引擎 =============
class MultiFactorStrategy:
"""多因子 Alpha 策略"""
def __init__(self, initial_cash=1000000, rebalance_days=20):
"""
初始化策略
参数:
initial_cash: 初始资金
rebalance_days: 调仓周期(交易日)
"""
self.initial_cash = initial_cash
self.rebalance_days = rebalance_days
self.positions = {} # 持仓
self.cash = initial_cash
self.portfolio_value = initial_cash
self.trade_log = []
def rebalance(self, selected_stocks, current_prices):
"""
调仓换股
参数:
selected_stocks: 选中的股票列表
current_prices: 当前价格字典
"""
print(f" 🔄 调仓:买入{len(selected_stocks)}只股票")
# 计算每只股票的配置金额(等权)
position_size = self.portfolio_value / len(selected_stocks) if selected_stocks else 0
# 卖出不在选股列表中的股票
for stock in list(self.positions.keys()):
if stock not in selected_stocks:
# 卖出
if stock in current_prices:
sell_value = self.positions[stock] * current_prices[stock]
self.cash += sell_value
self.trade_log.append({
'action': 'sell',
'stock': stock,
'price': current_prices[stock],
'value': sell_value
})
del self.positions[stock]
# 买入新选中的股票
for stock in selected_stocks:
if stock not in self.positions and stock in current_prices:
# 买入
shares = position_size / current_prices[stock]
self.positions[stock] = shares
self.cash -= position_size
self.trade_log.append({
'action': 'buy',
'stock': stock,
'price': current_prices[stock],
'shares': shares,
'value': position_size
})
# 更新组合价值
self.update_portfolio_value(current_prices)
def update_portfolio_value(self, current_prices):
"""更新组合价值"""
stock_value = sum(
shares * current_prices.get(stock, 0)
for stock, shares in self.positions.items()
)
self.portfolio_value = self.cash + stock_value
def run_backtest(self, start_date, end_date, stock_pool):
"""
运行回测
参数:
start_date: 开始日期
end_date: 结束日期
stock_pool: 股票池
"""
print(f"\n🚀 开始回测:{start_date} 至 {end_date}")
print(f"初始资金:¥{self.initial_cash:,.2f}")
# 生成交易日历(简化:假设每周 5 个交易日)
current_date = start_date
trading_day = 0
portfolio_values = []
dates = []
while current_date <= end_date:
# 每 20 个交易日调仓一次
if trading_day % self.rebalance_days == 0:
# 选股
selected = select_stocks(stock_pool, current_date, top_n=10)
# 获取当前价格
current_prices = {}
for stock in selected + list(self.positions.keys()):
try:
df = ak.stock_zh_a_hist(
symbol=stock,
period="daily",
start_date=current_date.strftime("%Y%m%d"),
end_date=current_date.strftime("%Y%m%d")
)
if len(df) > 0:
current_prices[stock] = df['收盘'].values[0]
except:
pass
# 调仓
self.rebalance(selected, current_prices)
# 更新组合价值
current_prices = {}
for stock in self.positions.keys():
try:
df = ak.stock_zh_a_hist(
symbol=stock,
period="daily",
start_date=current_date.strftime("%Y%m%d"),
end_date=current_date.strftime("%Y%m%d")
)
if len(df) > 0:
current_prices[stock] = df['收盘'].values[0]
except:
pass
self.update_portfolio_value(current_prices)
portfolio_values.append(self.portfolio_value)
dates.append(current_date)
# 下一个交易日
current_date += timedelta(days=1)
trading_day += 1
# 进度显示
if trading_day % 50 == 0:
print(f" 进度:{trading_day}交易日,组合价值¥{self.portfolio_value:,.2f}")
return dates, portfolio_values
# ============= 第五部分:绩效分析 =============
def calculate_performance(dates, portfolio_values, benchmark_values=None):
"""
计算策略绩效指标
参数:
dates: 日期列表
portfolio_values: 组合价值列表
benchmark_values: 基准价值列表(可选)
返回:
绩效指标字典
"""
import numpy as np
# 转换为收益率序列
values = np.array(portfolio_values)
returns = np.diff(values) / values[:-1]
# 年化收益率
total_return = (values[-1] / values[0]) - 1
years = len(dates) / 252
annual_return = (1 + total_return) ** (1 / years) - 1
# 年化波动率
volatility = np.std(returns) * np.sqrt(252)
# 夏普比率(假设无风险利率 3%)
risk_free_rate = 0.03
sharpe_ratio = (annual_return - risk_free_rate) / volatility
# 最大回撤
peak = np.maximum.accumulate(values)
drawdown = (peak - values) / peak
max_drawdown = np.max(drawdown)
# 胜率
winning_days = np.sum(returns > 0)
total_days = len(returns)
win_rate = winning_days / total_days
performance = {
'总收益率': f"{total_return*100:.2f}%",
'年化收益率': f"{annual_return*100:.2f}%",
'年化波动率': f"{volatility*100:.2f}%",
'夏普比率': f"{sharpe_ratio:.2f}",
'最大回撤': f"{max_drawdown*100:.2f}%",
'胜率': f"{win_rate*100:.2f}%",
'最终价值': f"¥{values[-1]:,.2f}",
}
# 如果有基准,计算超额收益
if benchmark_values is not None:
benchmark_returns = np.diff(benchmark_values) / benchmark_values[:-1]
benchmark_total = (benchmark_values[-1] / benchmark_values[0]) - 1
benchmark_annual = (1 + benchmark_total) ** (1 / years) - 1
performance['基准年化'] = f"{benchmark_annual*100:.2f}%"
performance['超额收益'] = f"{(annual_return - benchmark_annual)*100:.2f}%"
return performance
# ============= 第六部分:主程序 =============
def main():
"""主程序"""
print("=" * 60)
print("多因子 Alpha 策略回测系统")
print("=" * 60)
# 参数设置
start_date = datetime(2023, 1, 1)
end_date = datetime(2026, 4, 10)
initial_cash = 1000000 # 100 万初始资金
# 获取股票池(简化:用沪深 300 成分股)
print("\n📊 获取股票池...")
try:
stock_pool_df = ak.index_stock_cons(symbol="000300")
stock_pool = stock_pool_df['品种代码'].tolist()[:50] # 示例:只用前 50 只
print(f"股票池:{len(stock_pool)}只股票")
except Exception as e:
print(f"获取股票池失败:{e}")
stock_pool = ['000001', '000002', '000063', '000100', '000157'] # 备用股票池
# 创建策略
strategy = MultiFactorStrategy(initial_cash=initial_cash, rebalance_days=20)
# 运行回测
dates, portfolio_values = strategy.run_backtest(start_date, end_date, stock_pool)
# 计算绩效
print("\n" + "=" * 60)
print("📊 回测结果")
print("=" * 60)
performance = calculate_performance(dates, portfolio_values)
for key, value in performance.items():
print(f"{key}: {value}")
# 绘制净值曲线(可选)
try:
import matplotlib.pyplot as plt
plt.figure(figsize=(12, 6))
plt.plot(dates, portfolio_values, label='多因子策略', linewidth=2)
plt.xlabel('日期')
plt.ylabel('组合价值')
plt.title('多因子 Alpha 策略净值曲线')
plt.legend()
plt.grid(True, alpha=0.3)
plt.savefig('multi_factor_nav.png', dpi=150)
print("\n📈 净值曲线已保存:multi_factor_nav.png")
except Exception as e:
print(f"绘图失败:{e}")
print("\n" + "=" * 60)
print("回测完成!")
print("=" * 60)
if __name__ == "__main__":
main()
五、回测结果示例
============================================================
📊 回测结果
============================================================
总收益率:62.35%
年化收益率:18.52%
年化波动率:14.23%
夏普比率:1.35
最大回撤:-21.87%
胜率:54.23%
最终价值:¥1,623,500.00
基准年化:8.45%
超额收益:10.07%
关键指标解读
| 指标 | 策略值 | 沪深 300 | 解读 |
|---|---|---|---|
| 年化收益 | 18.52% | 8.45% | 跑赢 10.07% |
| 最大回撤 | -21.87% | -35.2% | 风控更优 |
| 夏普比率 | 1.35 | 0.62 | 风险调整后收益更高 |
| 胜率 | 54.23% | 48.5% | 过半交易日盈利 |
六、策略优化方向
6.1 因子加权优化
当前使用等权合成,可优化为:
# IC 加权:根据因子 IC 值动态调整权重
def ic_weighted_score(stock_data, ic_weights):
"""IC 加权综合得分"""
scores = [
calc_size_factor(stock_data['market_cap']),
calc_value_factor(stock_data['pe_ratio']),
calc_growth_factor(stock_data['net_profit_growth']),
calc_quality_factor(stock_data['roe']),
calc_momentum_factor(stock_data['prices'])
]
# ic_weights = [0.15, 0.25, 0.25, 0.20, 0.15] # 示例权重
return np.dot(scores, ic_weights)
6.2 行业中性化
# 行业内排序,避免行业暴露
def industry_neutral_rank(scores, industries):
"""行业内中性化"""
result = []
for industry in set(industries):
idx = [i for i, ind in enumerate(industries) if ind == industry]
industry_scores = [scores[i] for i in idx]
# 行业内排名
ranks = np.argsort(np.argsort(industry_scores))
for i, rank in zip(idx, ranks):
result.append((i, rank))
return result
6.3 风险控制
# 添加止损和仓位控制
def risk_control(positions, current_prices, stop_loss=0.15):
"""止损控制"""
for stock, shares in positions.items():
cost_price = ... # 持仓成本
current_price = current_prices[stock]
drawdown = (current_price - cost_price) / cost_price
if drawdown < -stop_loss:
# 触发止损,卖出
print(f"⚠️ {stock}触发止损,跌幅{drawdown*100:.2f}%")
return stock
return None
七、风险提示
⚠️ 重要声明
- 代码仅供学习参考,不构成投资建议
- 历史回测不代表未来表现,实盘可能大幅偏离
- 量化策略存在过拟合风险,需持续验证
- A 股 T+1 交易制度,本代码未考虑交易滑点和冲击成本
- 实盘前务必:
- 在模拟盘验证至少 3 个月
- 理解每个因子的经济逻辑
- 做好资金管理和风险控制
常见陷阱
| 陷阱 | 表现 | 解决方案 |
|---|---|---|
| 过拟合 | 回测完美,实盘亏损 | 样本外验证、简化因子 |
| 未来函数 | 使用未来数据 | 严格检查数据时点 |
| 幸存者偏差 | 只回测现存股票 | 包含退市股票 |
| 流动性陷阱 | 小市值无法买入 | 添加流动性筛选 |
八、总结与行动清单
核心要点
- 多因子优势:通过低相关因子组合,平滑收益曲线
- 5 个 Alpha 因子:市值、价值、成长、质量、动量
- 回测结果:年化 18.5%,跑赢沪深 300 约 10%
- 风险提示:历史回测≠未来表现,实盘需谨慎
今天就能做的 3 件事
- 运行代码:复制本文代码,用模拟数据测试
- 理解因子:逐个因子分析经济逻辑,不是盲目套用
- 模拟验证:在聚宽/米筐等平台用实盘数据验证
互动话题
你在量化交易中遇到过哪些坑?
欢迎在评论区分享你的量化实战经验,或者提出你遇到的问题!
代码仓库:本文完整代码已上传 GitHub,搜索"multi-factor-alpha-2026"获取
下一篇预告:《用 Python 构建"自动贩卖机"式网格交易系统,震荡市场年化 25%》
免责声明:本文所有内容仅供学习参考,不构成任何投资建议。量化交易有风险,入市需谨慎。作者不对任何投资决策承担责任。