我在2019年第一次接触量化交易时,最头疼的问题就是因子之间的共线性。那时候我们团队有30多个Alpha因子,但回测结果总是差强人意——后来才发现问题出在因子设计层面,很多因子提供的信息其实是重复的。经过三年多的实践,我总结出一套完整的因子库设计方法论,今天分享给各位初学者。

一、什么是量化因子?为什么你需要关注因子质量?

简单来说,量化因子就是能够解释资产收益率变化的数值特征。就像医生通过体温、血压等指标判断身体健康程度,量化交易员通过各种因子来判断股票未来的涨跌概率。

常见的因子类别包括:

我见过很多新手投资者盲目追求因子数量,以为因子越多越好。实际上,这种想法非常危险。当因子之间存在高度相关性时,模型会过度拟合历史数据,在实盘中表现惨淡。真正高质量的因子库,应该做到因子之间相互独立、信息不重叠

二、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 为什么要做因子正交化?

让我用一个实际案例来说明。假设我们有两个因子:

这两个因子相关性高达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质量:

4.2 IR(Information Ratio)衡量因子稳定性

光有高IC还不够,你还需要关注IC的稳定性。IR定义为 IC均值 / IC标准差,代表因子的信息效率。

IR = mean(IC) / std(IC)

我的经验是:

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()

七、常见报错排查