第四章:标签构建与样本设计

做内幕交易检测,最头疼的问题是什么?

不是模型选得不够好,也不是特征工程不够花哨。我做了这么多年风控,实话告诉你——标签怎么打,样本怎么配,这才是真正的拦路虎

你想想看,内幕交易本身是隐蔽的,监管机构公布的处罚案例只是冰山一角。我们拿到的正样本,说白了就是「已经被抓到的」。那些没被抓到的呢?嗯,这就是问题所在。

4.1 内幕交易样本的标注方法

先聊聊标注。我个人习惯把标注方法分成三类,每一类都有它的适用场景和坑。

4.1.1 基于监管处罚的标注

这是最「干净」的方法。直接用证监会、交易所公布的处罚决定书,把被处罚的交易行为标为1,其他标为0。

我在项目中遇到过一个问题:处罚案例太少了。A股市场一年也就几十起内幕交易处罚,你拿这点样本去训练模型?别说深度学习,逻辑回归都够呛。

核心思路:监管处罚数据是「黄金标准」,但样本量极小。适合做验证集,不适合做训练集。

4.1.2 基于异常事件的标注

这个方法我比较常用。用重大事件公告作为锚点,比如并购重组、业绩预告、高送转等。然后看事件发生前的交易行为是否异常。

具体做法是这样的:

# 伪代码示例:基于事件窗口的标注
def label_by_event(trade_data, event_date, window=30):
    """
    trade_data: 个股的逐笔交易数据
    event_date: 重大事件公告日期
    window: 事件前窗口期(交易日)
    """
    # 窗口期内的交易行为
    window_data = trade_data[
        (trade_data.date >= event_date - window) &
        (trade_data.date < event_date)
    ]
    
    # 计算异常指标
    abnormal_volume = window_data.volume / window_data.volume.rolling(60).mean()
    
    # 如果异常指标超过阈值,标记为可疑
    label = 1 if abnormal_volume.max() > 3.0 else 0
    return label

这里有个坑:阈值怎么设?设太松,误报多;设太紧,漏报多。我一般会用3倍标准差作为起点,然后根据业务反馈调整。

4.1.3 基于规则引擎的标注

这个方法适合大规模标注。把交易所的监控规则、行业经验、学术论文里的指标,全部写成规则。

举个例子:

  • 规则1:事件前5日,累计异常成交量超过日均成交量的200%
  • 规则2:事件前10日,账户对倒交易占比超过30%
  • 规则3:事件前3日,关联账户组集中买入

满足3条以上规则的,标为1。满足1-2条的,标为待确认。一条都不满足的,标为0。

我的经验:规则引擎标注的样本,一定要人工复核。我曾经吃过亏,规则太死板,把正常的机构调仓行为也标成了内幕交易。后来加了「机构持仓占比」这个过滤条件,误报率降了40%。

4.2 正负样本不平衡问题

做内幕交易检测,正负样本比例可能达到1:10000甚至更夸张。你想想看,一个模型如果全部预测为负样本,准确率也有99.99%。但这有意义吗?

4.2.1 采样策略

我常用的方法有三种:

方法 原理 适用场景 我的评价
随机欠采样 从负样本中随机抽取,与正样本数量持平 负样本量极大时 简单粗暴,但会丢失信息
SMOTE过采样 在正样本之间插值生成新样本 正样本量较少时 效果好,但可能生成不合理样本
集成采样 多次欠采样+多个模型投票 追求稳定性时 我最推荐的方法

我个人最常用的是集成采样。为什么?因为内幕交易样本太珍贵了,我不想浪费任何一个。集成采样能最大程度保留信息。

4.2.2 损失函数调整

除了采样,还可以从损失函数入手。我常用的两个技巧:

# 方法1:类别权重
from sklearn.utils.class_weight import compute_class_weight

weights = compute_class_weight(
    class_weight='balanced',
    classes=[0, 1],
    y=y_train
)
# 正样本权重会远大于负样本权重

# 方法2:Focal Loss(适合深度学习)
def focal_loss(gamma=2.0, alpha=0.25):
    """
    gamma: 聚焦参数,越大越关注难分类样本
    alpha: 平衡参数,控制正负样本权重
    """
    def loss(y_true, y_pred):
        pt = y_true * y_pred + (1 - y_true) * (1 - y_pred)
        focal_weight = (1 - pt) ** gamma
        return -alpha * focal_weight * tf.math.log(pt)
    return loss

避坑指南:我曾经在一个项目里,把正样本权重设得过高,结果模型把所有稍微有点异常的样本都判成了内幕交易。后来我加了一个规则:预测概率低于0.7的,一律不输出。这才把误报率压下来。

4.3 时间序列交叉验证策略

做金融风控,最忌讳的就是数据泄露。你想想看,如果用未来的数据去预测过去的事件,那模型再烂也能「预测」得很准。

4.3.1 为什么不能用随机交叉验证?

标准的K折交叉验证,是把数据随机打乱再分折。这在金融数据上是大忌。

举个例子:假设第1折包含2023年1月的数据,第2折包含2023年6月的数据。如果用第2折训练、第1折验证,那模型就「看到」了未来的信息。这在实盘部署时根本不可能实现。

4.3.2 时间序列交叉验证的正确姿势

我常用的方法有两种:

# 方法1:滑动窗口验证
def time_series_cv(data, train_window=252, test_window=63):
    """
    train_window: 训练窗口长度(交易日)
    test_window: 测试窗口长度(交易日)
    """
    folds = []
    start = 0
    while start + train_window + test_window < len(data):
        train_end = start + train_window
        test_end = train_end + test_window
        
        train_idx = list(range(start, train_end))
        test_idx = list(range(train_end, test_end))
        folds.append((train_idx, test_idx))
        
        # 滑动步长,我一般用test_window的一半
        start += test_window // 2
    
    return folds

# 方法2:扩展窗口验证
def expanding_window_cv(data, min_train=504, test_window=63):
    """
    min_train: 最小训练集长度(2年)
    """
    folds = []
    train_end = min_train
    while train_end + test_window < len(data):
        train_idx = list(range(0, train_end))
        test_idx = list(range(train_end, train_end + test_window))
        folds.append((train_idx, test_idx))
        
        train_end += test_window
    
    return folds

4.3.3 我的实战经验

我一般用扩展窗口验证。为什么?因为金融数据是非平稳的,市场结构会变。用扩展窗口,模型能不断学习新的市场规律。

但这里有个细节:窗口长度怎么设?

  • 训练窗口:至少2年(504个交易日),太短学不到规律
  • 测试窗口:3个月(63个交易日),太长模型可能过时
  • 滑动步长:1个月(21个交易日),保证验证频率

核心原则:永远用过去的数据预测未来。训练集的时间必须早于验证集。这是金融风控的铁律。

4.4 本章知识体系

说了这么多,我画了一张图帮你理清思路:

标签构建与样本设计知识体系 标注方法 1. 监管处罚标注 黄金标准,样本极少 2. 异常事件标注 事件窗口+异常指标 3. 规则引擎标注 多条规则组合判定 4. 人工复核 降低误报率的关键 不平衡处理 采样策略 欠采样 / SMOTE / 集成 损失函数调整 类别权重 / Focal Loss 评估指标 Precision-Recall曲线 阈值调优 概率阈值 > 0.7 交叉验证 滑动窗口验证 固定窗口长度 扩展窗口验证 训练集不断累积 窗口长度设置 训练≥2年,测试3月 防数据泄露 时间顺序严格保持 核心目标:构建高质量、无泄露的训练样本

这张图把本章的三个核心模块串起来了。标注方法是基础,不平衡处理是手段,交叉验证是保障。三者缺一不可。

最后说一句:标签构建这件事,没有标准答案。每个市场、每个品种、每个时期,最优方案都不一样。我的建议是:先跑通一个基线,然后根据业务反馈不断迭代。别想着一口吃成胖子。


公众号:蓝海资料掘金营,微信deep3321