报告核心内容总结 (Report Core Summary)

这份报告的核心目标是探索如何 融合不同类型的高频数据(分钟级成交、TICK级委托、逐笔成交),并将其 低频化(日度/月度),以构建有效的选股因子。报告主要从两个角度出发:

  1. 直观逻辑驱动 (Intuitive Logic Driven): 结合委**托挂单(未实现意愿)逐笔成交(已实现行为)**信息,构建“买入意愿”类因子,旨在更全面地刻画投资者的交易意愿。
  2. 机器学习驱动 (Machine Learning Driven): 利用机器学习(特别是特征工程)方法,从融合后的高频数据中自动挖掘新的选股因子 (Alpha因子)。

主要发现 (Key Findings):

  • 买入意愿因子有效性:
    • 结合了委托变动和主动买入的“买入意愿”指标被提出。
    • 基于此构建的“买入意愿占比”和“日内买入意愿强度”因子(尤其是在开盘时段计算)表现出显著的月度选股能力 (IC > 0.03, ICIR > 2.5/3.0, 胜率 > 80%)。
    • 与仅使用逐笔成交构建的“净主买”类因子相比,“买入意愿”类因子在选股效果上有明显提升 (IC、ICIR、多空收益、多头收益均改善)。
  • 机器学习挖掘因子有效性:
    • 报告通过机器学习挖掘出多个Alpha因子 (Alpha1-Alpha6),这些因子即使在剔除常规低频因子影响后仍有显著选股能力。
    • 进一步剔除其他已知高频因子的影响后,这些ML因子的选股能力更为突出 (IC > 0.04, ICIR 接近 3.0, 多空收益 > 1.5%)。
    • 部分ML因子具有一定的逻辑可解释性(如Alpha1衡量买入额波动率,Alpha4/Alpha6衡量特定时段成交额的相对强弱)。
  • 因子组合改进:
    • 将新构建的“买入意愿”类因子或机器学习挖掘的Alpha因子加入传统多因子模型(如中证500增强),能够带来组合表现的改善(提升超额收益)。
    • 部分因子(如开盘后日内买入意愿强度、Alpha_2、Alpha_4)带来的收益提升更显著。
    • 同时引入逻辑因子和ML因子(利用它们之间较低的相关性)可能进一步提升模型的稳健性。

目录 (Table of Contents)

  1. 报告核心总结 (Report Core Summary)
  2. 主要发现 (Key Findings)
  3. 数据准备与假设 (Data Preparation & Assumptions)
  4. Python 实现: 逻辑驱动因子 (Python Implementation: Logic-Driven Factors)
    • 4.1 计算分钟级“买入意愿” (Calculating Minute-level “Purchase Intention”)
    • 4.2 计算日度“买入意愿占比” (Calculating Daily “Purchase Intention Ratio”)
    • 4.3 计算日度“日内买入意愿强度” (Calculating Daily “Intraday Purchase Intention Strength”)
    • 4.4 因子计算主函数 (Main Factor Calculation Function)
  5. Python 实现: 机器学习因子示例 (Python Implementation: Machine Learning Factor Examples)
    • 5.1 Alpha_1 因子计算 (Alpha_1 Factor Calculation)
    • 5.2 Alpha_4 因子计算 (Alpha_4 Factor Calculation)
    • 5.3 Alpha_6 因子计算 (Alpha_6 Factor Calculation)
    • 5.4 因子计算主函数 (Main Factor Calculation Function)
  6. 因子评估与应用 (Factor Evaluation & Application)
    • 6.1 IC/ICIR 计算 (IC/ICIR Calculation)
    • 6.2 因子正交化 (Factor Orthogonalization)
    • 6.3 因子组合 (Factor Combination)
  7. 风险提示 (Risk Warning)
  8. 开源库选择 (Choice of Open-Source Libraries)

3. 数据准备与假设 (Data Preparation & Assumptions)

  • 输入数据: 需要分钟级别的行情和交易数据。理想情况下,应包含:
    • 时间戳 (Timestamp)
    • 股票代码 (Stock Code)
    • 成交额 (Turnover / Amount)
    • 主动买入额 (Active Buy Amount)
    • 主动卖出额 (Active Sell Amount)
    • 净委买变动额 (Net Order Change Amount) - 这个指标可能需要从TICK级委托数据计算得到,然后聚合到分钟
    • 大单买入额 (Large Order Buy Amount) - 定义可能需要明确
  • 数据格式: 使用 Pandas DataFrame 进行处理。建议使用 MultiIndex (date, stock_code, minute_timestamp)。
  • 时间段定义 (根据报告):
    • 全天 (Full Day): 09:30 - 14:56 (或根据实际交易时间调整)
    • 开盘后 (Opening): 09:30 - 09:59
    • 盘中 (Mid-day): 10:00 - 14:26
    • 收盘前 (Closing): 14:27 - 14:56
  • 假设:
    • 所需的高频字段已预处理并聚合至分钟级别。
    • “净委买变动额” 指的是特定分钟内买一到买五(或更多档位)委托量变动对应的金额估算,减去卖一到卖五委托量变动金额估算。其精确计算依赖TICK数据。
    • “净主动买入额” = 主动买入额 - 主动卖出额。
    • 因子计算的回看期 (如rolling操作) 根据报告设定(例如ML因子中的20天)。

4. Python 实现: 逻辑驱动因子 (Python Implementation: Logic-Driven Factors)

import pandas as pd
import numpy as np

# 假设 df_minute 是包含分钟数据的 DataFrame
# 列应包括: 'timestamp', 'stock_code', 'turnover', 'net_order_change', 'net_active_buy_value'
# timestamp 应为 datetime 对象

# --- 4.1 计算分钟级“买入意愿” ---
def calculate_minute_purchase_intention(df_minute):
    """计算每分钟的买入意愿"""
    # 报告公式:买入意愿 = 净委买变化额 + 净主动买入额
    # 假设 'net_order_change' 和 'net_active_buy_value' 列已存在
    df_minute['purchase_intention'] = df_minute['net_order_change'].fillna(0) + \
                                      df_minute['net_active_buy_value'].fillna(0)
    return df_minute

# --- 4.2 计算日度“买入意愿占比” ---
def calculate_daily_intention_ratio(daily_group):
    """计算单个股票单日的买入意愿占比"""
    total_intention = daily_group['purchase_intention'].sum()
    total_turnover = daily_group['turnover'].sum()
    if total_turnover > 0:
        return total_intention / total_turnover
    else:
        return np.nan

# --- 4.3 计算日度“日内买入意愿强度” ---
def calculate_daily_intention_strength(daily_group):
    """计算单个股票单日的日内买入意愿强度"""
    mean_intention = daily_group['purchase_intention'].mean()
    std_intention = daily_group['purchase_intention'].std()
    # 防止除以零或接近零的标准差
    if std_intention is not None and std_intention > 1e-6:
        return mean_intention / std_intention
    else:
        return np.nan

# --- 4.4 因子计算主函数 ---
def calculate_logical_factors_daily(df_minute, period='full_day'):
    """
    计算指定时间段内的逻辑因子日度值

    Args:
        df_minute (pd.DataFrame): 包含 'timestamp', 'stock_code', 'turnover',
                                  'net_order_change', 'net_active_buy_value' 的分钟数据.
        period (str): 时间段 ('full_day', 'opening', 'mid_day', 'closing').

    Returns:
        pd.DataFrame: 包含 'date', 'stock_code', 'intention_ratio', 'intention_strength' 的日度因子.
    """
    df = df_minute.copy()
    df['date'] = df['timestamp'].dt.date
    df['time'] = df['timestamp'].dt.time

    # 根据时间段筛选数据
    if period == 'opening':
        df = df[df['time'] <= pd.Timestamp('09:59:00').time()]
    elif period == 'mid_day':
        df = df[(df['time'] >= pd.Timestamp('10:00:00').time()) &
                (df['time'] <= pd.Timestamp('14:26:00').time())]
    elif period == 'closing':
        df = df[df['time'] >= pd.Timestamp('14:27:00').time()]
    elif period != 'full_day':
        raise ValueError("Invalid period specified")
        
    # 计算分钟意愿
    df = calculate_minute_purchase_intention(df)

    # 按日期和股票代码分组计算日度因子
    grouped = df.groupby(['date', 'stock_code'])

    daily_factors = pd.DataFrame({
        f'intention_ratio_{period}': grouped.apply(calculate_daily_intention_ratio),
        f'intention_strength_{period}': grouped.apply(calculate_daily_intention_strength)
    }).reset_index()

    return daily_factors

# --- 示例 ---
# 假设已有分钟数据 df_minute_data
# factor_opening = calculate_logical_factors_daily(df_minute_data, period='opening')
# factor_full_day = calculate_logical_factors_daily(df_minute_data, period='full_day')
# ... 合并不同周期的因子 ...

5. Python 实现: 机器学习因子示例 (Python Implementation: Machine Learning Factor Examples)

这里我们根据报告表10中的公式,用Pandas实现其中几个Alpha因子的计算逻辑。这需要日度聚合后的分钟数据和滚动窗口操作。

import pandas as pd
import numpy as np

# 假设 df_daily_features 是包含日度聚合特征的 DataFrame
# 需要 MultiIndex (date, stock_code)
# 列应包括: 'active_buy_amount_sum_mid', 'turnover_sum_med',
#           'net_active_buy_value_sum_end', 'turnover_sum_full',
#           'active_buy_amount_sum_open', 'active_buy_amount_sum_end',
#           'turnover_sum_open', 'turnover_sum_end'
# 这些日度特征需要先从分钟数据按不同时间段聚合得到 (sum 或其他聚合方式)

# --- 辅助函数:获取不同时间段的日度聚合值 ---
def get_daily_agg_features(df_minute):
    """从分钟数据计算所需的日度聚合特征"""
    df = df_minute.copy()
    df['date'] = df['timestamp'].dt.date
    df['time'] = df['timestamp'].dt.time

    # 定义时间段
    is_opening = (df['time'] <= pd.Timestamp('09:59:00').time())
    is_mid_day = (df['time'] >= pd.Timestamp('10:00:00').time()) & \
                 (df['time'] <= pd.Timestamp('14:26:00').time())
    is_closing = (df['time'] >= pd.Timestamp('14:27:00').time())
    
    # 确保必要的列存在,若不存在则设为0(根据实际情况调整)
    required_cols = ['turnover', 'active_buy_amount', 'net_active_buy_value', 'large_order_buy_amount']
    for col in required_cols:
        if col not in df.columns:
            df[col] = 0 # 或者根据实际数据来源处理

    grouped = df.groupby(['date', 'stock_code'])

    # 聚合计算 - 注意'主买额'可能指'active_buy_amount'或'net_active_buy_value',根据实际定义
    # '成交额' 指 'turnover'
    # 这里以 sum 为例进行聚合,具体聚合方式需核对因子原始定义
    features = pd.DataFrame({
        'turnover_sum_full': grouped['turnover'].sum(),
        'active_buy_amount_sum_mid': grouped.apply(lambda x: x.loc[is_mid_day[x.index], 'active_buy_amount'].sum()),
        'turnover_sum_med': grouped.apply(lambda x: x.loc[is_mid_day[x.index], 'turnover'].sum()),
        'net_active_buy_value_sum_end': grouped.apply(lambda x: x.loc[is_closing[x.index], 'net_active_buy_value'].sum()),
        'turnover_sum_open': grouped.apply(lambda x: x.loc[is_opening[x.index], 'turnover'].sum()),
        'turnover_sum_end': grouped.apply(lambda x: x.loc[is_closing[x.index], 'turnover'].sum()),
        # Alpha2 需要 大单买入额 * 开盘成交额 的波动率,这个计算更复杂,需要先算分钟乘积再日聚合
        # 'large_buy_X_turnover_open_minute_product': df['large_order_buy_amount'] * df['turnover'],
        # ... 然后聚合这个乘积序列 ...
    })

    # 为了简化后续因子计算,将列名对应报告中的含义
    features = features.rename(columns={
        'active_buy_amount_sum_mid': 'period_med(主买额)',
        'turnover_sum_med': 'period_med(成交额)',
        'net_active_buy_value_sum_end': 'period_end(净主买额)',
        'turnover_sum_full': '成交额', # 假设 Alpha4 的成交额指全天
        'turnover_sum_open': 'period_beg(成交额)',
        'turnover_sum_end': 'period_end(成交额)',
    })
    
    return features

# --- 5.1 Alpha_1 因子计算 ---
# Alpha1 = neg(log(roll_std(period_med(主买额))))
def calculate_alpha1(daily_features, window=20):
    """计算 Alpha1 因子"""
    # 计算 period_med(主买额) 的 20 日滚动标准差
    # groupby().rolling() 需要时间序列索引是单调递增的
    # 需要先 unstack,计算 rolling,再 stack 回来
    feat = daily_features['period_med(主买额)'].unstack()
    rolling_std = feat.rolling(window=window, min_periods=max(1, window // 2)).std() # 设置最小期数
    alpha1_unstacked = -np.log(rolling_std + 1e-9) # 加小量防止log(0)
    alpha1 = alpha1_unstacked.stack().rename('Alpha_1')
    return alpha1

# --- 5.2 Alpha_4 因子计算 ---
# Alpha4 = neg(log(roll_mean(成交额 - period_med(成交额))))
def calculate_alpha4(daily_features, window=20):
    """计算 Alpha4 因子"""
    # 计算 (全天成交额 - 盘中成交额)
    diff = daily_features['成交额'] - daily_features['period_med(成交额)']
    # 计算 diff 的 20 日滚动均值
    diff_unstacked = diff.unstack()
    rolling_mean = diff_unstacked.rolling(window=window, min_periods=max(1, window // 2)).mean()
    alpha4_unstacked = -np.log(rolling_mean + 1e-9) # 加小量防止负数或零
    # 注意:如果 rolling_mean 可能为负,log 会出错,需要处理,例如取绝对值或符号处理
    # alpha4_unstacked = -np.sign(rolling_mean) * np.log(np.abs(rolling_mean) + 1e-9)
    alpha4 = alpha4_unstacked.stack().rename('Alpha_4')
    return alpha4

# --- 5.3 Alpha_6 因子计算 ---
# Alpha6 = neg(roll_sum(period_beg(成交额) + period_end(成交额)) / roll_sum(period_med(成交额)))
def calculate_alpha6(daily_features, window=20):
    """计算 Alpha6 因子"""
    # 开盘+收盘成交额
    open_close_turnover = daily_features['period_beg(成交额)'] + daily_features['period_end(成交额)']
    mid_turnover = daily_features['period_med(成交额)']

    # 计算滚动和
    open_close_unstacked = open_close_turnover.unstack()
    mid_unstacked = mid_turnover.unstack()

    roll_sum_open_close = open_close_unstacked.rolling(window=window, min_periods=max(1, window // 2)).sum()
    roll_sum_mid = mid_unstacked.rolling(window=window, min_periods=max(1, window // 2)).sum()

    # 计算比率并取负
    ratio_unstacked = roll_sum_open_close / (roll_sum_mid + 1e-9) # 防止除零
    alpha6_unstacked = -ratio_unstacked
    alpha6 = alpha6_unstacked.stack().rename('Alpha_6')
    return alpha6

# --- 5.4 因子计算主函数 ---
def calculate_ml_factors_daily(df_minute, window=20):
    """计算所有(示例)ML因子的日度值"""
    
    print("Aggregating daily features from minute data...")
    daily_features = get_daily_agg_features(df_minute)
    daily_features = daily_features.sort_index(level='date') # 确保按时间排序

    print("Calculating Alpha_1...")
    alpha1 = calculate_alpha1(daily_features, window)
    print("Calculating Alpha_4...")
    alpha4 = calculate_alpha4(daily_features, window)
    print("Calculating Alpha_6...")
    alpha6 = calculate_alpha6(daily_features, window)
    
    # ... 计算其他 Alpha 因子 ...

    # 合并所有因子
    all_ml_factors = pd.concat([alpha1, alpha4, alpha6], axis=1) # 添加其他计算出的alpha因子
    
    return all_ml_factors.reset_index()

# --- 示例 ---
# 假设已有分钟数据 df_minute_data
# ml_factors = calculate_ml_factors_daily(df_minute_data, window=20)

注意: ML因子的计算(尤其是Alpha2等涉及乘积波动的)可能更复杂,并且rolling操作在大型数据集上可能较慢,需要优化。unstack/stack是处理面板数据滚动计算的常用方法。


6. 因子评估与应用 (Factor Evaluation & Application)

  • 6.1 IC/ICIR 计算:
    • 需要股票的未来收益率数据 (e.g., T+1日收益率, T+20日收益率)。
    • 计算每个截面期 (通常是每天或每月) 因子值与未来收益率的 Spearmann 或 Pearson 相关系数 (即 IC)。
    • ICIR = mean(IC) / std(IC)
    • 可以使用 scipy.stats.spearmanrpandas.Series.corr
  • 6.2 因子正交化:
    • 需要其他基准因子(市值、行业、估值等)的同期因子值。
    • 对每个截面期,将待正交化的因子 Y 对基准因子 X1, X2, … 做线性回归: Y = a + b1*X1 + b2*X2 + ... + residual
    • 正交化后的因子即为回归的残差 (residual)
    • 可以使用 statsmodels.api.OLS
  • 6.3 因子组合:
    • 将计算得到的因子值(可能经过标准化和正交化处理)输入到多因子模型框架中(如 Barra CNE5 或自定义模型)。
    • 根据因子暴露度和预期收益(通常与IC/ICIR相关)进行打分或优化,构建投资组合。
    • 回测组合表现,评估超额收益、信息比率、最大回撤等指标。
    • 常用的回测框架有 zipline (略旧但经典), backtrader, QuantConnect LEAN, 或商业平台。

7. 风险提示 (Risk Warning)

  • 过拟合风险: 机器学习挖掘的因子可能存在过拟合风险,样本外表现可能不及回测。
  • 数据质量: 高频数据的清洗和处理至关重要,错误或缺失数据会严重影响因子质量。
  • 计算成本: 处理高频数据和进行复杂因子计算(尤其是滚动计算和ML挖掘)需要较高的计算资源。
  • 模型衰减: 因子有效性可能随市场环境变化而衰减。
  • 逻辑理解: 部分ML因子缺乏直观逻辑,增加了理解和风控的难度。
  • 报告中的回测结果是基于特定时期和参数设置,未来表现不确定。

8. 开源库选择 (Choice of Open-Source Libraries)

  • 数据处理: Pandas, NumPy (核心库)
  • 统计与评估: SciPy (相关性计算), Statsmodels (回归/正交化)
  • 机器学习因子挖掘 (可选):
    • scikit-learn (用于特征工程、回归等辅助任务)
    • gplearn (可用于遗传规划,类似报告中可能使用的挖掘方法之一,但使用较复杂)
  • 回测框架 (可选): backtrader, Zipline (维护可能滞后), QuantConnect LEAN

这份 Python 代码提供了报告中核心因子计算思路的实现框架。在实际应用中,需要根据具体的数据源、精确的指标定义以及计算效率要求进行调整和优化。

Logo

技术共进,成长同行——讯飞AI开发者社区

更多推荐