我在2019年第一次接触量化交易时,最头疼的问题就是因子之间的共线性。那时候我们团队有30多个Alpha因子,但回测结果总是差强人意——后来才发现问题出在因子设计层面,很多因子提供的信息其实是重复的。经过三年多的实践,我总结出一套完整的因子库设计方法论,今天分享给各位初学者。
一、什么是量化因子?为什么你需要关注因子质量?
简单来说,量化因子就是能够解释资产收益率变化的数值特征。就像医生通过体温、血压等指标判断身体健康程度,量化交易员通过各种因子来判断股票未来的涨跌概率。
常见的因子类别包括:
- 估值因子:PE、PB、PS等,反映公司贵不贵
- 动量因子:过去N日收益率,反映趋势延续性
- 质量因子:ROE、资产负债率,反映公司经营质量
- 成长因子:营收增速、利润增速,反映发展潜力
- 情绪因子:换手率波动、分析师评级变化
我见过很多新手投资者盲目追求因子数量,以为因子越多越好。实际上,这种想法非常危险。当因子之间存在高度相关性时,模型会过度拟合历史数据,在实盘中表现惨淡。真正高质量的因子库,应该做到因子之间相互独立、信息不重叠。
二、HolySheheep API 在量化因子分析中的核心优势
在正式讲解技术实现之前,我先介绍一下我们团队为什么选择 HolySheep AI 作为我们的主要AI服务提供商。
在做因子分析时,我们经常需要用大语言模型来解释因子组合、生成因子描述、或者用自然语言查询因子库。HolySheep 的国内直连延迟小于50ms,这对于需要实时交互的因子分析场景非常重要。而且 ¥1=$1 的汇率政策让我们在API调用成本上节省了超过85%。
💡 HolySheep 2026年主流模型定价参考:
- GPT-4.1:$8/MTok(适合复杂因子逻辑分析)
- Claude Sonnet 4.5:$15/MTok(适合长文本因子报告生成)
- Gemini 2.5 Flash:$2.50/MTok(适合高频因子调用)
- DeepSeek V3.2:$0.42/MTok(适合大规模因子筛选)
配合微信/支付宝充值,对于个人投资者来说非常友好。
三、因子正交化:让你的因子库“降噪提纯”
3.1 为什么要做因子正交化?
让我用一个实际案例来说明。假设我们有两个因子:
- 因子A:总市值(单位:亿元)
- 因子B:流通市值(单位:亿元)
这两个因子相关性高达0.98!如果你同时使用它们,模型会认为市值信息被“强调了两遍”,导致偏向市值效应的结论。实际上,流通市值/总市值的比值(自由流通比例)才是更有效的因子。
3.2 Gram-Schmidt 正交化原理
Gram-Schmidt 正交化是量化领域最常用的方法。它的核心思想是:将每个新因子投影到已有因子的正交补空间,从而消除信息冗余。
假设我们有因子 f₁, f₂, ..., fₙ,Gram-Schmidt 正交化的步骤如下:
# 伪代码示例
def gram_schmidt_orthogonalize(factors_matrix):
"""
factors_matrix: shape (N, K) N个样本,K个因子
返回: 正交化后的因子矩阵
"""
orthogonal_factors = []
for k in range(K):
new_factor = factors_matrix[:, k].copy()
# 减去与前面因子的相关性
for prev_factor in orthogonal_factors:
# 计算投影系数
projection = np.dot(new_factor, prev_factor) / np.dot(prev_factor, prev_factor)
new_factor = new_factor - projection * prev_factor
orthogonal_factors.append(new_factor)
return np.column_stack(orthogonal_factors)
3.3 实战:Python 实现完整因子正交化流程
import numpy as np
import pandas as pd
from sklearn.linear_model import LinearRegression
class FactorOrthogonalizer:
"""因子正交化处理器"""
def __init__(self, method='施密特'):
self.method = method
self.factor_names = []
self.orthogonal_matrix = None
self.correlation_before = None
self.correlation_after = None
def fit_transform(self, factor_df):
"""
参数:
factor_df: DataFrame, 每列是一个因子
返回:
正交化后的DataFrame
"""
self.factor_names = list(factor_df.columns)
factor_matrix = factor_df.values
# 记录正交化前的相关矩阵
self.correlation_before = np.corrcoef(factor_matrix.T)
if self.method == '施密特':
self.orthogonal_matrix = self._gram_schmidt(factor_matrix)
else:
self.orthogonal_matrix = self._regression_residual(factor_matrix)
# 记录正交化后的相关矩阵
self.correlation_after = np.corrcoef(self.orthogonal_matrix.T)
result_df = pd.DataFrame(
self.orthogonal_matrix,
columns=[f'{name}_orth' for name in self.factor_names]
)
return result_df
def _gram_schmidt(self, matrix):
"""标准Gram-Schmidt正交化"""
n, k = matrix.shape
ortho = np.zeros_like(matrix)
for i in range(k):
ortho[:, i] = matrix[:, i]
for j in range(i):
# 减去前面所有正交因子的投影
coef = np.dot(matrix[:, i], ortho[:, j]) / np.dot(ortho[:, j], ortho[:, j])
ortho[:, i] -= coef * ortho[:, j]
# 标准化(可选,保留方向信息)
norm = np.linalg.norm(ortho[:, i])
if norm > 1e-10:
ortho[:, i] /= norm
return ortho
def _regression_residual(self, matrix):
"""回归残差法(逐步正交化)"""
n, k = matrix.shape
residual = np.zeros_like(matrix)
# 第一个因子直接保留
residual[:, 0] = matrix[:, 0]
for i in range(1, k):
# 用前面所有因子回归当前因子
X = matrix[:, :i]
y = matrix[:, i]
model = LinearRegression()
model.fit(X, y)
# 残差即为正交化后的因子
residual[:, i] = y - model.predict(X)
return residual
def get_report(self):
"""生成正交化效果报告"""
print("="*60)
print("因子正交化分析报告")
print("="*60)
print("\n【正交化前因子相关矩阵】")
corr_before = pd.DataFrame(
self.correlation_before,
index=self.factor_names,
columns=self.factor_names
)
print(corr_before.round(3))
print("\n【正交化后因子相关矩阵】")
corr_after = pd.DataFrame(
self.correlation_after,
index=[f'{n}_orth' for n in self.factor_names],
columns=[f'{n}_orth' for n in self.factor_names]
)
print(corr_after.round(3))
# 计算平均绝对相关系数降低幅度
mask = np.triu(np.ones_like(self.correlation_after, dtype=bool), k=1)
avg_corr_before = np.abs(self.correlation_before[mask]).mean()
avg_corr_after = np.abs(self.correlation_after[mask]).mean()
print(f"\n平均绝对相关系数: {avg_corr_before:.4f} → {avg_corr_after:.4f}")
print(f"降幅: {(1 - avg_corr_after/avg_corr_before)*100:.1f}%")
return {
'avg_corr_before': avg_corr_before,
'avg_corr_after': avg_corr_after,
'improvement': (1 - avg_corr_after/avg_corr_before)*100
}
使用示例
if __name__ == "__main__":
# 模拟因子数据(市值、流通市值、ROE、营收增速)
np.random.seed(42)
n_samples = 1000
# 构造高度相关的因子(模拟真实场景)
market_cap = np.random.exponential(100, n_samples)
float_cap = market_cap * np.random.uniform(0.3, 0.9, n_samples) # 与市值高度相关
roe = np.random.normal(0.15, 0.1, n_samples)
revenue_growth = np.random.normal(0.2, 0.3, n_samples)
# 添加噪声
float_cap += np.random.normal(0, 5, n_samples)
factor_df = pd.DataFrame({
'market_cap': market_cap,
'float_cap': float_cap,
'roe': roe,
'revenue_growth': revenue_growth
})
# 执行正交化
orthogonlizer = FactorOrthogonalizer(method='施密特')
ortho_df = orthogonlizer.fit_transform(factor_df)
report = orthogonlizer.get_report()
我自己在使用时发现,回归残差法的数值稳定性更好,特别是在因子数值量纲差异较大时。Gram-Schmidt 虽然理论更优美,但在浮点运算中可能累积误差。
四、IC分析方法论:量化评估因子预测能力
4.1 IC(Information Coefficient)是什么?
IC是衡量因子预测能力的核心指标,它本质上就是因子值与下期收益率的相关系数。IC越高,说明这个因子越能预测未来收益。
我一般用以下标准评估IC质量:
- IC > 0.03:因子质量优秀,具备实盘盈利潜力
- IC 0.02~0.03:因子质量良好,可作为补充因子
- IC 0.01~0.02:因子质量一般,需要组合使用
- IC < 0.01:因子预测能力弱,考虑剔除
4.2 IR(Information Ratio)衡量因子稳定性
光有高IC还不够,你还需要关注IC的稳定性。IR定义为 IC均值 / IC标准差,代表因子的信息效率。
IR = mean(IC) / std(IC)
我的经验是:
- IR > 0.5:因子稳定可靠
- IR 0.3~0.5:因子基本可用
- IR < 0.3:因子波动太大,实盘风险高
4.3 完整 IC 分析代码实现
import numpy as np
import pandas as pd
from scipy import stats
from typing import Tuple, Dict, List
import matplotlib.pyplot as plt
class FactorICAnalyzer:
"""因子IC分析器 - 评估因子预测能力"""
def __init__(self, factor_df: pd.DataFrame, return_df: pd.DataFrame):
"""
参数:
factor_df: 因子值矩阵,index为日期,columns为股票代码
return_df: 下期收益率矩阵,index为日期,columns为股票代码
"""
self.factor_df = factor_df
self.return_df = return_df
self.ic_series = None
self.ic_stats = {}
def calculate_ic(self) -> pd.DataFrame:
"""计算每日IC"""
ic_data = {}
common_dates = self.factor_df.index.intersection(self.return_df.index)
for date in common_dates:
factor_values = self.factor_df.loc[date]
returns = self.return_df.loc[date]
# 合并有效数据(去除NaN)
valid_mask = ~(factor_values.isna() | returns.isna())
valid_factor = factor_values[valid_mask]
valid_return = returns[valid_mask]
if len(valid_factor) >= 30: # 至少30个样本
# Pearson相关系数
pearson_ic = valid_factor.corr(valid_return)
# Spearman秩相关系数(对极端值更鲁棒)
spearman_ic, _ = stats.spearmanr(valid_factor, valid_return)
ic_data[date] = {
'pearson_ic': pearson_ic,
'spearman_ic': spearman_ic
}
self.ic_series = pd.DataFrame(ic_data).T
return self.ic_series
def analyze_ic_stats(self) -> Dict:
"""分析IC统计特征"""
if self.ic_series is None:
self.calculate_ic()
results = {}
for ic_type in ['pearson_ic', 'spearman_ic']:
ic_values = self.ic_series[ic_type].dropna()
results[ic_type] = {
'mean': ic_values.mean(),
'std': ic_values.std(),
'ir': ic_values.mean() / ic_values.std() if ic_values.std() > 0 else 0,
'positive_rate': (ic_values > 0).mean(),
'ic > 0.02 rate': (abs(ic_values) > 0.02).mean(),
'ic > 0.03 rate': (abs(ic_values) > 0.03).mean(),
'skewness': stats.skew(ic_values),
'kurtosis': stats.kurtosis(ic_values)
}
self.ic_stats = results
return results
def calculate_ic_decay(self, max_lag: int = 20) -> pd.DataFrame:
"""计算IC衰减"""
if self.ic_series is None:
self.calculate_ic()
decay_data = {}
for lag in range(max_lag + 1):
if lag == 0:
decay_data[lag] = self.ic_series['spearman_ic'].mean()
else:
# 计算因子与N天后收益率的IC
ic_lag = []
for i in range(len(self.ic_series) - lag):
factor_date = self.ic_series.index[i]
return_date = self.ic_series.index[i + lag]
if factor_date in self.factor_df.index and return_date in self.return_df.index:
factor_vals = self.factor_df.loc[factor_date]
return_vals = self.return_df.loc[return_date]
valid_mask = ~(factor_vals.isna() | return_vals.isna())
if valid_mask.sum() >= 30:
ic, _ = stats.spearmanr(
factor_vals[valid_mask],
return_vals[valid_mask]
)
if not np.isnan(ic):
ic_lag.append(ic)
decay_data[lag] = np.mean(ic_lag) if ic_lag else 0
return pd.Series(decay_data)
def generate_report(self) -> str:
"""生成IC分析报告"""
if self.ic_series is None:
self.analyze_ic_stats()
report = []
report.append("="*70)
report.append(" 因子IC分析报告")
report.append("="*70)
report.append(f"分析日期范围: {self.ic_series.index[0]} 至 {self.ic_series.index[-1]}")
report.append(f"有效交易日数: {len(self.ic_series)}")
report.append("")
for ic_type, stats_dict in self.ic_stats.items():
ic_name = "Pearson IC" if 'pearson' in ic_type else "Spearman IC"
report.append(f"【{ic_name}】")
report.append(f" 均值 (IC Mean): {stats_dict['mean']:.4f}")
report.append(f" 标准差 (IC Std): {stats_dict['std']:.4f}")
report.append(f" 信息比率 (IR): {stats_dict['ir']:.4f}")
report.append(f" 正IC占比: {stats_dict['positive_rate']*100:.1f}%")
report.append(f" |IC| > 0.02 占比: {stats_dict['ic > 0.02 rate']*100:.1f}%")
report.append(f" |IC| > 0.03 占比: {stats_dict['ic > 0.03 rate']*100:.1f}%")
report.append("")
# IC衰减分析
ic_decay = self.calculate_ic_decay(max_lag=10)
report.append("【IC衰减曲线】(因子有效性持续天数)")
for lag, ic_val in ic_decay.items():
bar = "█" * int(abs(ic_val) * 200)
sign = "+" if ic_val > 0 else "-"
report.append(f" Lag {lag:2d}: {sign}{abs(ic_val):.4f} {bar}")
report.append("")
report.append("="*70)
return "\n".join(report)
模拟完整分析流程
def demo_ic_analysis():
"""演示完整的IC分析流程"""
np.random.seed(2024)
# 模拟100天、200只股票的因子数据和收益率数据
dates = pd.date_range('2024-01-01', periods=100, freq='B')
stocks = [f'STOCK_{i:04d}' for i in range(200)]
# 因子:假设有一定预测能力
factor_matrix = pd.DataFrame(
np.random.randn(100, 200) * 0.5 + 0.1, # 偏正
index=dates,
columns=stocks
)
# 收益率:与因子有一定相关性
# 加入部分噪声
return_matrix = pd.DataFrame(
np.random.randn(100, 200) * 0.02 + factor_matrix.values * 0.01 + np.random.randn(100, 200) * 0.015,
index=dates,
columns=stocks
)
# 执行IC分析
analyzer = FactorICAnalyzer(factor_matrix, return_matrix)
analyzer.calculate_ic()
stats = analyzer.analyze_ic_stats()
report = analyzer.generate_report()
print(report)
return analyzer
if __name__ == "__main__":
analyzer = demo_ic_analysis()
五、结合 HolySheep API 智能生成因子分析报告
在实际工作中,我经常需要用自然语言向团队解释因子组合的效果。这里我推荐使用 HolySheep API 来生成因子分析报告。以下是完整的集成代码:
import requests
import json
from typing import Dict, List
import pandas as pd
class HolySheepAPIClient:
"""HolySheep API 客户端 - 用于生成因子分析报告"""
def __init__(self, api_key: str):
"""
初始化API客户端
参数:
api_key: 你的 HolySheep API密钥,格式为 YOUR_HOLYSHEEP_API_KEY
"""
self.api_key = api_key
self.base_url = "https://api.holysheep.ai/v1"
self.headers = {
"Authorization": f"Bearer {api_key}",
"Content-Type": "application/json"
}
def generate_factor_report(self, ic_stats: Dict, factor_names: List[str]) -> str:
"""
使用LLM生成因子分析报告
参数:
ic_stats: IC统计分析结果
factor_names: 因子名称列表
返回:
格式化后的分析报告
"""
prompt = f"""你是一位量化投资专家,请根据以下因子IC统计分析结果,
为我生成一份专业的因子分析报告。
因子列表: {', '.join(factor_names)}
IC统计分析:
{json.dumps(ic_stats, indent=2, ensure_ascii=False)}
请从以下角度进行分析:
1. 各因子预测能力评价
2. 因子组合的协同效应
3. 潜在风险与改进建议
4. 实盘应用可行性评估
请用简洁专业的语言输出报告,中文回答。
"""
payload = {
"model": "gpt-4.1",
"messages": [
{
"role": "system",
"content": "你是一位资深量化投资专家,擅长因子分析与组合优化。"
},
{
"role": "user",
"content": prompt
}
],
"temperature": 0.3, # 降低随机性,保持专业严谨
"max_tokens": 1500
}
try:
response = requests.post(
f"{self.base_url}/chat/completions",
headers=self.headers,
json=payload,
timeout=30
)
response.raise_for_status()
result = response.json()
return result['choices'][0]['message']['content']
except requests.exceptions.RequestException as e:
raise Exception(f"HolySheep API调用失败: {str(e)}")
def batch_factor_evaluation(self, factors_df: pd.DataFrame, returns_df: pd.DataFrame) -> Dict:
"""
批量评估因子并生成综合报告
参数:
factors_df: 因子DataFrame
returns_df: 收益率DataFrame
返回:
包含统计分析和LLM报告的完整结果
"""
# 计算IC统计
ic_results = {}
for factor_name in factors_df.columns:
valid_data = factors_df[factor_name].dropna()
if len(valid_data) > 0:
# 简化计算
ic_mean = 0.032 # 模拟值
ic_std = 0.018
ic_results[factor_name] = {
'ic_mean': ic_mean,
'ic_std': ic_std,
'ir': ic_mean / ic_std if ic_std > 0 else 0,
'positive_rate': 0.68
}
# 生成LLM报告
llm_report = self.generate_factor_report(ic_results, list(factors_df.columns))
return {
'ic_statistics': ic_results,
'llm_analysis': llm_report
}
使用示例
def main():
# 初始化客户端
api_key = "YOUR_HOLYSHEEP_API_KEY" # 替换为你的实际API密钥
client = HolySheepAPIClient(api_key)
# 模拟因子数据
np.random.seed(42)
dates = pd.date_range('2024-01-01', periods=60, freq='B')
factors = pd.DataFrame({
'市值因子': np.random.randn(60) * 100 + 500,
'动量因子': np.random.randn(60) * 0.05 + 0.02,
'质量因子': np.random.randn(60) * 0.1 + 0.15,
'成长因子': np.random.randn(60) * 0.08 + 0.25
}, index=dates)
returns = pd.DataFrame({
f'S{i:04d}': np.random.randn(60) * 0.02 for i in range(100)
}, index=dates)
# 执行批量评估
result = client.batch_factor_evaluation(factors, returns)
print("="*70)
print(" HolySheep AI 因子分析报告")
print("="*70)
print("\n【IC统计分析】")
for factor, stats in result['ic_statistics'].items():
print(f"\n{factor}:")
print(f" IC均值: {stats['ic_mean']:.4f}")
print(f" IC标准差: {stats['ic_std']:.4f}")
print(f" IR: {stats['ir']:.4f}")
print(f" 正IC占比: {stats['positive_rate']*100:.1f}%")
print("\n【LLM智能分析】")
print(result['llm_analysis'])
if __name__ == "__main__":
main()
六、实战案例:构建一个完整的因子库系统
让我分享我们团队的实际经验,演示如何从零开始构建因子库。
import numpy as np
import pandas as pd
from typing import Tuple, List
import warnings
warnings.filterwarnings('ignore')
class FactorLibrary:
"""量化因子库系统"""
def __init__(self):
self.raw_factors = {}
self.orthogonal_factors = {}
self.factor_metadata = {}
self.ic_results = {}
def add_factor(self, name: str, data: pd.Series, category: str = "unknown"):
"""添加原始因子"""
self.raw_factors[name] = data
self.factor_metadata[name] = {
'category': category,
'added_date': pd.Timestamp.now(),
'is_orthogonal': False
}
def orthogonalize_all(self, method: str = '施密特') -> pd.DataFrame:
"""批量正交化所有因子"""
if len(self.raw_factors) == 0:
raise ValueError("请先添加因子数据")
# 合并所有因子
factor_df = pd.DataFrame(self.raw_factors)
# 执行正交化
from sklearn.linear_model import LinearRegression
n_samples, n_factors = factor_df.shape
ortho_matrix = np.zeros_like(factor_df.values)
# 第一个因子保留
ortho_matrix[:, 0] = factor_df.iloc[:, 0].values
for i in range(1, n_factors):
# 标准化当前因子
current = (factor_df.iloc[:, i].values - np.nanmean(factor_df.iloc[:, i].values))
current_std = np.nanstd(current)
if current_std > 1e-10:
current = current / current_std
# 回归去除前面因子的影响
X = ortho_matrix[:, :i]
y = current
# 处理NaN
valid_mask = ~(np.isnan(X).any(axis=1) | np.isnan(y))
if valid_mask.sum() > i + 5:
model = LinearRegression()
model.fit(X[valid_mask], y[valid_mask])
residual = y - model.predict(X)
else:
residual = current
ortho_matrix[:, i] = residual
# 更新存储
ortho_df = pd.DataFrame(
ortho_matrix,
index=factor_df.index,
columns=[f"{col}_orth" for col in factor_df.columns]
)
self.orthogonal_factors = {
col: ortho_df[col] for col in ortho_df.columns
}
# 更新元数据
for name in self.orthogonal_factors:
self.factor_metadata[name] = {
**self.factor_metadata[name.replace('_orth', '')],
'is_orthogonal': True
}
return ortho_df
def calculate_ic(self, returns: pd.Series, top_n: int = None) -> pd.DataFrame:
"""计算各因子的IC"""
from scipy import stats
all_factors = {**self.raw_factors, **self.orthogonal_factors}
ic_data = []
for name, factor_data in all_factors.items():
# 对齐日期
common_dates = factor_data.index.intersection(returns.index)
if len(common_dates) < 30:
continue
f_vals = factor_data.loc[common_dates]
r_vals = returns.loc[common_dates]
# 去除NaN
valid = ~(f_vals.isna() | r_vals.isna())
if valid.sum() >= 30:
ic, p_value = stats.spearmanr(
f_vals[valid],
r_vals[valid]
)
ic_data.append({
'factor': name,
'category': self.factor_metadata.get(name, {}).get('category', 'unknown'),
'is_orthogonal': self.factor_metadata.get(name, {}).get('is_orthogonal', False),
'ic_mean': ic,
'ic_std': 0.015, # 简化处理
'p_value': p_value,
'ir': ic / 0.015
})
ic_df = pd.DataFrame(ic_data)
ic_df = ic_df.sort_values('ic_mean', ascending=False)
if top_n:
ic_df = ic_df.head(top_n)
self.ic_results = ic_df
return ic_df
def select_factors(self, min_ic: float = 0.01, min_ir: float = 0.3) -> List[str]:
"""根据IC指标筛选因子"""
if not self.ic_results:
raise ValueError("请先计算IC")
selected = self.ic_results[
(self.ic_results['ic_mean'].abs() >= min_ic) &
(self.ic_results['ir'] >= min_ir)
]['factor'].tolist()
# 去重,优先选择正交因子
selected_clean = []
original_factors = set()
for factor in selected:
if factor.endswith('_orth'):
original = factor.replace('_orth', '')
if original not in original_factors:
selected_clean.append(factor)
original_factors.add(original)
else:
if factor not in original_factors:
selected_clean.append(factor)
original_factors.add(factor)
return selected_clean
def generate_summary(self) -> str:
"""生成因子库摘要报告"""
report = []
report.append("\n" + "="*70)
report.append(" 因子库构建报告")
report.append("="*70)
report.append(f"\n原始因子数量: {len(self.raw_factors)}")
report.append(f"正交因子数量: {len(self.orthogonal_factors)}")
report.append(f"因子类别分布:")
categories = {}
for name, meta in self.factor_metadata.items():
cat = meta.get('category', 'unknown')
categories[cat] = categories.get(cat, 0) + 1
for cat, count in sorted(categories.items()):
report.append(f" - {cat}: {count}")
if self.ic_results is not None and len(self.ic_results) > 0:
report.append("\n【Top 5 预测能力最强的因子】")
top5 = self.ic_results.head(5)
for _, row in top5.iterrows():
ortho_tag = "[正交]" if row['is_orthogonal'] else ""
report.append(f" {row['factor']} {ortho_tag}: IC={row['ic_mean']:.4f}, IR={row['ir']:.4f}")
report.append("\n" + "="*70)
return "\n".join(report)
实战演示
def build_factor_library_demo():
"""构建因子库完整演示"""
print("🎯 开始构建量化因子库...")
# 1. 初始化因子库
library = FactorLibrary()
# 2. 添加模拟因子数据
np.random.seed(2024)
dates = pd.date_range('2023-01-01', periods=250, freq='B') # 一年交易日
# 估值类因子
library.add_factor('pe_ratio', pd.Series(
np.random.normal(15, 5, len(dates)), index=dates
), category='估值')
library.add_factor('pb_ratio', pd.Series(
np.random.normal(2, 0.5, len(dates)), index=dates
), category='估值')
# 动量类因子
library.add_factor('mom_20d', pd.Series(
np.random.normal(0.02, 0.08, len(dates)), index=dates
), category='动量')
library.add_factor('mom_60d', pd.Series(
np.random.normal(0.05, 0.15, len(dates)), index=dates
), category='动量')
# 质量类因子
library.add_factor('roe', pd.Series(
np.random.normal(0.15, 0.05, len(dates)), index=dates
), category='质量')
library.add_factor('debt_ratio', pd.Series(
np.random.normal(0.5, 0.15, len(dates)), index=dates
), category='质量')
print(f"✅ 已添加 {len(library.raw_factors)} 个原始因子")
# 3. 执行正交化
print("\n🔧 执行因子正交化...")
ortho_df = library.orthogonalize_all()
print(f"✅ 生成 {len(library.orthogonal_factors)} 个正交因子")
# 4. 计算IC
print("\n📊 计算因子IC...")
mock_returns = pd.Series(
np.random.randn(len(dates)) * 0.02,
index=dates
)
ic_results = library.calculate_ic(mock_returns)
print(ic_results.to_string())
# 5. 筛选因子
print("\n✨ 筛选优质因子...")
selected = library.select_factors(min_ic=0.005, min_ir=0.1)
print(f"选中的因子: {selected}")
# 6. 生成报告
print(library.generate_summary())
return library
if __name__ == "__main__":
library = build_factor_library_demo()