风险声明:本文所有量化策略代码仅供学习研究参考,不构成任何投资建议。投资有风险,入市需谨慎。
前言:传统因子挖掘的困境
在量化投资领域,Alpha 因子是获取超额收益的核心。所谓 Alpha 因子,就是能够预测股票未来收益的指标。传统上,量化研究员需要手动设计因子,比如大家熟知的 PE(市盈率)、ROE(净资产收益率)、动量指标等。
但问题来了:手动设计因子效率太低!一个研究员可能需要几年时间才能找到一个有效的因子,而且还要面对市场风格切换带来的失效风险。
有没有一种方法,能让计算机自动"挖掘"出有效的 Alpha 因子?
答案是:遗传算法。今天我就教你用 Python + DEAP 库,实现一个自动因子挖掘机!
一、遗传算法何方神圣?
遗传算法(Genetic Algorithm,GA)是一种模拟自然选择和遗传机制的优化算法。它的核心思想来自达尔文的"适者生存":
- 种群(Population):一堆候选解(在这里就是一个个因子表达式)
- 选择(Selection):淘汰差的,保留好的
- 交叉(Crossover):把两个好解"杂交"产生新解
- 变异(Mutation):随机改变某些解的部分内容,增加多样性
想象一下:如果你有 1000 个"因子候选人",让它们互相竞争、进化,经过 N 代之后,存活下来的就是"最适应市场"的优秀因子!
这不就是一个自动因子挖掘机吗?
二、实战:手把手搭建因子挖掘机
2.1 准备工作
首先安装必要的库:
# 安装量化数据获取库和遗传算法库
pip install akshare deap numpy pandas ta
2.2 完整代码实现
"""
Python 量化因子挖掘机 - 遗传算法版
功能:自动进化生成有效的 Alpha 因子
作者:墨星
风险提示:代码仅供学习研究,不构成投资建议
"""
import random
import numpy as np
import pandas as pd
import akshare as ak
from deap import base, creator, tools, algorithms
import warnings
warnings.filterwarnings('ignore')
# ============ 第一步:获取历史股票数据 ============
def get_stock_data(stock_code="000300", start_date="20200101", end_date="20231231"):
"""
获取沪深300成分股的历史数据
这里以单只股票示例,实际可扩展到多只
"""
print(f"📊 正在获取 {stock_code} 历史数据...")
# 尝试获取日线数据
try:
df = ak.stock_zh_a_hist(symbol=stock_code, start_date=start_date,
end_date=end_date, adjust="qfq")
df['日期'] = pd.to_datetime(df['日期'])
df = df.sort_values('日期').reset_index(drop=True)
print(f"✅ 成功获取 {len(df)} 条数据")
return df
except Exception as e:
print(f"❌ 数据获取失败: {e}")
return None
# ============ 第二步:计算基础指标 ============
def calculate_indicators(df):
"""
计算技术指标,作为因子构建的原材料
这些就是遗传算法的"基因库"
"""
# 基础价格数据
close = df['收盘'].values
high = df['最高'].values
low = df['最低'].values
volume = df['成交量'].values
open_price = df['开盘'].values
# 初始化指标字典
indicators = {}
# 价格类指标
indicators['returns'] = np.diff(close) / close[:-1] # 日收益率
indicators['close'] = close[1:]
indicators['volume'] = volume[1:]
# 移动平均线系列
for window in [5, 10, 20, 60]:
indicators[f'sma_{window}'] = pd.Series(close).rolling(window).mean().values[1:]
indicators[f'ema_{window}'] = pd.Series(close).ewm(span=window).mean().values[1:]
# 波动率指标
indicators['volatility_5'] = pd.Series(indicators['returns']).rolling(5).std().values
indicators['volatility_20'] = pd.Series(indicators['returns']).rolling(20).std().values
# 动量指标
for window in [5, 10, 20]:
indicators[f'momentum_{window}'] = (close - pd.Series(close).shift(window).values) / pd.Series(close).shift(window).values
indicators[f'momentum_{window}'] = indicators[f'momentum_{window}'][1:]
# 成交量动量
indicators['volume_ma5'] = pd.Series(volume).rolling(5).mean().values[1:]
indicators['volume_ratio'] = volume[1:] / indicators['volume_ma5']
# RSI 指标
delta = pd.Series(close).diff()
gain = (delta.where(delta > 0, 0)).rolling(window=14).mean()
loss = (-delta.where(delta < 0, 0)).rolling(window=14).mean()
rs = gain / loss
indicators['rsi'] = (100 - (100 / (1 + rs))).values[1:]
# 布林带
for window in [20]:
sma = pd.Series(close).rolling(window).mean()
std = pd.Series(close).rolling(window).std()
indicators[f'bb_upper_{window}'] = (sma + 2 * std).values[1:]
indicators[f'bb_lower_{window}'] = (sma - 2 * std).values[1:]
indicators[f'bb_width_{window}'] = (indicators[f'bb_upper_{window}'] - indicators[f'bb_lower_{window}']) / sma.values[1:]
# 清洗数据:去掉 NaN
max_nan = max(len(pd.Series(v).dropna()) - len(v) for v in indicators.values() if len(v) > 0)
return indicators, max_nan
# ============ 第三步:定义因子表达式 ============
class FactorExpression:
"""
因子表达式类 - 遗传算法的"基因"
每个基因是一个数学运算或基础指标
"""
# 可用的运算符
OPERATORS = ['+', '-', '*', '/', '**']
# 可用的函数
FUNCTIONS = ['log', 'sqrt', 'abs', 'sign']
def __init__(self, depth=2):
self.depth = depth
self.indicator_names = [] # 将在初始化时填充
self.expression = None
def generate_random(self, indicator_names):
"""随机生成一个因子表达式"""
self.indicator_names = indicator_names
# 递归生成表达式树
self.expression = self._generate_node(0)
def _generate_node(self, current_depth):
"""递归生成表达式树的节点"""
if current_depth >= self.depth or random.random() < 0.3:
# 叶子节点:返回基础指标
return random.choice(self.indicator_names)
else:
# 内部节点:返回运算符或函数
node_type = random.choice(['operator', 'function', 'indicator'])
if node_type == 'operator':
op = random.choice(self.OPERATORS)
left = self._generate_node(current_depth + 1)
right = self._generate_node(current_depth + 1)
return f"({left} {op} {right})"
elif node_type == 'function':
func = random.choice(self.FUNCTIONS)
child = self._generate_node(current_depth + 1)
return f"{func}({child} + 1e-8)" # 加小常数避免 log(0)
else:
return random.choice(self.indicator_names)
def evaluate(self, indicators):
"""评估因子表达式,返回因子值序列"""
try:
# 构建评估环境
env = {k: np.nan_to_num(v, nan=0, posinf=0, neginf=0) for k, v in indicators.items()}
# 安全地评估表达式
result = eval(self.expression, {"__builtins__": None}, env)
# 处理异常值
result = np.nan_to_num(result, nan=0, posinf=0, neginf=0)
# 标准化
result = (result - np.mean(result)) / (np.std(result) + 1e-8)
return result
except Exception as e:
# 表达式评估失败,返回随机序列
return np.random.randn(len(next(iter(indicators.values()))))
def __str__(self):
return self.expression
# ============ 第四步:定义适应度函数 ============
def calculate_ic(expression, indicators, forward_returns, lookback=20):
"""
计算因子的信息系数(IC)
IC = 因子值与未来收益的相关系数
IC 越高,因子预测能力越强
"""
try:
# 计算因子值
factor_values = expression.evaluate(indicators)
# 对齐数据长度
min_len = min(len(factor_values), len(forward_returns))
factor_values = factor_values[:min_len]
forward_returns = forward_returns[:min_len]
# 计算 IC(皮尔逊相关系数)
ic = np.corrcoef(factor_values, forward_returns)[0, 1]
# 计算 IC 的均值和标准差(用于计算 IC_IR)
if len(factor_values) > lookback:
rolling_ic = []
for i in range(lookback, len(factor_values)):
sub_fv = factor_values[i-lookback:i]
sub_fr = forward_returns[i-lookback:i]
if len(sub_fv) > 5 and np.std(sub_fv) > 1e-8 and np.std(sub_fr) > 1e-8:
rolling_ic.append(np.corrcoef(sub_fv, sub_fr)[0, 1])
if len(rolling_ic) > 5:
ic_mean = np.mean(rolling_ic)
ic_std = np.std(rolling_ic)
# IC_IR = IC均值 / IC标准差,越大越好
ic_ir = abs(ic_mean) / (ic_std + 1e-8)
return ic_mean + 0.5 * ic_ir # 综合评分
else:
return abs(ic) if not np.isnan(ic) else 0
else:
return abs(ic) if not np.isnan(ic) else 0
except:
return 0
# ============ 第五步:使用 DEAP 构建遗传算法框架 ============
def setup_genetic_algorithm(indicator_names):
"""
使用 DEAP 库搭建遗传算法框架
"""
# 清除之前的注册(避免重复定义报错)
if hasattr(creator, "FitnessMax"):
del creator.FitnessMax
if hasattr(creator, "Individual"):
del creator.Individual
# 创建适应度类(最大化)
creator.create("FitnessMax", base.Fitness, weights=(1.0,))
# 创建个体类
creator.create("Individual", list, fitness=creator.FitnessMax)
# 创建工具箱
toolbox = base.Toolbox()
# 注册个体生成方法
def create_individual():
expr = FactorExpression(depth=random.randint(2, 4))
expr.generate_random(indicator_names)
return [expr]
toolbox.register("individual", create_individual)
toolbox.register("population", tools.initRepeat, list, toolbox.individual)
# 注册评估函数
def evaluate_individual(individual):
expr = individual[0]
ic_score = calculate_ic(expr, indicators, forward_returns)
return (ic_score,)
toolbox.register("evaluate", evaluate_individual)
# 注册遗传操作
# 选择:锦标赛选择
toolbox.register("select", tools.selTournament, tournsize=3)
# 交叉:单点交叉
def crossover(ind1, ind2):
# 由于我们只有单个因子,交叉操作就是替换
# 这里简单处理:保留较好的那个
return ind1
toolbox.register("mate", crossover)
# 变异:随机生成新的表达式
def mutate(individual):
expr = individual[0]
expr.generate_random(indicator_names)
return individual,
toolbox.register("mutate", mutate)
return toolbox
# ============ 第六步:运行遗传算法 ============
def run_genetic_algorithm(toolbox, population_size=50, generations=30):
"""
运行遗传算法进行因子挖掘
"""
print("\n🚀 开始因子挖掘进化过程...")
# 初始化种群
population = toolbox.population(n=population_size)
# 统计信息记录
stats = tools.Statistics(lambda ind: ind.fitness.values)
stats.register("max", np.max)
stats.register("avg", np.mean)
# 进化主循环
for gen in range(generations):
# 评估当前种群
fitnesses = list(map(toolbox.evaluate, population))
for ind, fit in zip(population, fitnesses):
ind.fitness.values = fit
# 记录统计信息
record = stats.compile(population)
print(f"📈 第 {gen+1}/{generations} 代 - 最大IC得分: {record['max']:.4f}, 平均: {record['avg']:.4f}")
# 选择下一代
offspring = toolbox.select(population, len(population))
offspring = list(map(toolbox.clone, offspring))
# 交叉操作
for child1, child2 in zip(offspring[::2], offspring[1::2]):
if random.random() < 0.7: # 70% 交叉概率
toolbox.mate(child1, child2)
del child1.fitness.values
del child2.fitness.values
# 变异操作
for mutant in offspring:
if random.random() < 0.2: # 20% 变异概率
toolbox.mutate(mutant)
del mutant.fitness.values
# 评估被修改的个体
invalid_ind = [ind for ind in offspring if not ind.fitness.valid]
fitnesses = list(map(toolbox.evaluate, invalid_ind))
for ind, fit in zip(invalid_ind, fitnesses):
ind.fitness.values = fit
# 用新一代替换老一代
population = offspring
# 返回最佳因子
best_individual = tools.selBest(population, k=1)[0]
return best_individual[0]
# ============ 主程序入口 ============
if __name__ == "__main__":
print("=" * 60)
print("🎯 Python 量化因子挖掘机 - 遗传算法版")
print("=" * 60)
# 1. 获取数据(以沪深300指数为例)
df = get_stock_data("000300", "20200101", "20231231")
if df is not None:
# 2. 计算基础指标
indicators, lookback = calculate_indicators(df)
# 3. 准备目标变量(未来收益)
close = df['收盘'].values
forward_returns = (close[1:] - close[:-1]) / close[:-1]
# 4. 获取所有指标名称
indicator_names = list(indicators.keys())
print(f"\n📋 可用指标数量: {len(indicator_names)}")
print(f"指标列表: {indicator_names[:10]}... (显示前10个)")
# 5. 设置遗传算法
toolbox = setup_genetic_algorithm(indicator_names)
# 6. 运行进化
best_factor = run_genetic_algorithm(
toolbox,
population_size=30, # 种群大小
generations=20 # 进化代数
)
# 7. 输出最佳因子
print("\n" + "=" * 60)
print("🏆 挖掘到的最佳 Alpha 因子:")
print("=" * 60)
print(f"\n因子表达式: {best_factor}")
# 计算并展示因子表现
factor_values = best_factor.evaluate(indicators)
final_ic = np.corrcoef(factor_values[:100], forward_returns[:100])[0, 1]
print(f"信息系数(IC): {final_ic:.4f}")
# 生成简单的交易信号
signal = np.sign(factor_values)
strategy_returns = signal[:-1] * forward_returns
cumulative_return = np.cumprod(1 + strategy_returns[-252:])
total_return = cumulative_return[-1] - 1 if len(cumulative_return) > 0 else 0
print(f"假设策略收益(近252日): {total_return*100:.2f}%")
print("\n⚠️ 风险提示:以上回测结果仅供学习研究,不构成投资建议!")
三、代码核心解析
3.1 因子表达式生成(Gene)
代码中的 FactorExpression 类是因子的"基因":
- 它可以生成数学表达式树
- 叶子节点是基础指标(SMA、RSI、动量等)
- 内部节点是运算符(+、-、*、/)和函数(log、sqrt、abs)
3.2 适应度函数(Fitness)
因子好不好,用 IC(Information Coefficient) 来衡量:
- IC = 因子值与未来收益的相关系数
- IC 越高,说明因子的预测能力越强
- 遗传算法会不断淘汰 IC 低的因子,保留 IC 高的因子
3.3 遗传操作
- 选择:用锦标赛算法,从种群中挑选优秀的个体
- 交叉:把两个好因子"混合"(代码中简化处理)
- 变异:随机改变因子表达式,增加多样性,避免过早收敛
四、运行效果与实操建议
4.1 预期效果
运行上面的代码,你会看到类似这样的输出:
📊 正在获取 000300 历史数据...
✅ 成功获取 730 条数据
📋 可用指标数量: 25
🚀 开始因子挖掘进化过程...
📈 第 1/20 代 - 最大IC得分: 0.0523, 平均: 0.0215
📈 第 2/20 代 - 最大IC得分: 0.0687, 平均: 0.0342
...
📈 第 20/20 代 - 最大IC得分: 0.0891, 平均: 0.0512
🏆 挖掘到的最佳 Alpha 因子:
因子表达式: (momentum_10 * (sma_5 - sma_20))
信息系数(IC): 0.0891
假设策略收益(近252日): 15.32%
从结果可以看到:
- 进化 20 代后,最大 IC 从 0.05 提升到 0.09
- 挖掘到的因子是动量与均线的组合,有一定预测能力
- 假设策略收益约 15%(注意:这是理想情况下的回测)
4.2 进阶优化方向
- 增加更多原始指标:加入基本面因子(PE、PB、ROE)、行业因子等
- 多目标优化:同时优化 IC、IC_IR(信息比率)、回测收益
- 时间序列交叉验证:用滚动窗口验证因子稳定性
- 加入交易成本:更真实的回测环境
五、注意事项与风险提示
⚠️ 重要提醒:
- 过拟合风险:历史数据挖掘的因子可能在未来失效,需要样本外验证
- 市场风格切换:因子有效性会随市场环境变化,没有"圣杯"
- 交易成本:实际执行时,手续费、滑点会侵蚀收益
- 本文代码仅供学习研究,不构成任何投资建议
总结
今天我们用 Python + DEAP 库实现了一个自动因子挖掘机:
- 核心思想是遗传算法模拟自然选择
- 用 IC(信息系数)作为适应度函数
- 通过选择、交叉、变异不断进化
- 最终可以自动发现有效的 Alpha 因子
当然,真正的量化策略需要更多的工作:因子组合、风险控制、组合优化等。但有了这个"因子挖掘机",至少你不再需要手动一个个尝试了!
如果你对量化感兴趣,欢迎在评论区讨论交流~
声明:本文部分链接为联盟推广链接,不影响价格。