第二章:对手行为建模——识别对手类型、行为模式分类与历史数据特征提取

做量化交易这些年,我越来越觉得,市场就是个巨大的牌桌。你手里的策略再牛,如果看不懂对面坐的是谁,迟早得栽跟头。这一章,咱们就聊聊怎么给对手“画像”——说白了,就是通过行为数据,把散户、机构、量化基金这些不同类型的交易者给认出来。

2.1 对手类型识别:先搞清楚跟谁在玩

我个人习惯,把市场上的参与者分成三大类。每一类的行为特征,差异非常大。你想想看,一个拿工资的散户,跟一个管理百亿资金的基金经理,下单逻辑能一样吗?

对手类型 资金规模 交易频率 订单特征 持仓周期
散户 小(<10万) 中低频 整手、限价单为主 数天至数周
机构 大(>1000万) 中频 大单拆分、算法单 数周至数月
量化基金 中到大 高频 小单、冰山单、对倒 秒级至小时级

嗯,这里要注意:光看资金量还不够。我在项目中遇到过,有些游资伪装成机构,用大单砸盘诱多。所以,我们得结合行为模式来综合判断。

2.2 行为模式分类:他们到底在干嘛?

识别出对手类型后,下一步就是看他们的行为模式。我一般把常见行为分成四类:

  • 趋势跟随型:追涨杀跌,散户最爱。特征:价格突破时放量,回调时缩量。
  • 均值回归型:高抛低吸,机构常用。特征:价格偏离均线时反向开仓。
  • 套利型:吃价差,量化基金专属。特征:双边挂单,成交后迅速撤单。
  • 操纵型:挂假单、对倒、拉抬。特征:盘口出现大量挂单但成交稀疏。

为什么会这样?因为每种模式背后,对应的是不同的盈利逻辑。比如量化基金做套利,赚的是流动性溢价,所以他们的订单一定是“快进快出”。

避坑指南:我曾经把一次“对倒”行为误判为“趋势启动”,结果跟进去被套了。后来我加了一个规则:如果同一价位频繁出现“成交-撤单-再成交”的循环,大概率是量化基金在做市或对倒,千万别追。

2.3 历史数据特征提取:把行为变成数字

光靠肉眼盯盘肯定不行。我们需要从历史数据里提取特征,用数字说话。我常用的特征分三类:

2.3.1 订单簿特征

  • 买卖价差:价差突然扩大,说明流动性枯竭,可能是机构在撤单。
  • 订单深度:前五档挂单量变化率。量化基金喜欢用冰山单,深度会突然变化。
  • 撤单率:挂单后未成交就撤掉的比例。散户撤单率低,量化基金撤单率极高。

2.3.2 成交特征

  • 大单占比:单笔成交超过平均单量3倍以上的比例。机构行为。
  • 成交间隔:相邻两笔成交的时间差。量化基金成交间隔极短且均匀。
  • 主动买卖比:主动买入量 vs 主动卖出量。散户容易追涨,主动买卖比会极端化。

2.3.3 时间序列特征

  • 波动率聚类:高波动后往往跟着高波动。机构喜欢在波动率低时建仓。
  • 自相关性:价格序列的自相关系数。量化基金策略会引入负自相关(均值回归)。
  • 成交量分布:一天中成交量集中在哪些时段。散户喜欢开盘和收盘交易。

我的经验:提取特征时,别贪多。我刚开始做的时候,一口气提取了50多个特征,结果模型过拟合得一塌糊涂。后来我只保留了10个核心特征,效果反而更好。记住:特征不是越多越好,关键是每个特征都要有明确的业务解释。

2.4 实战:用Python快速识别对手类型

光说不练假把式。下面我给出一段代码,用来从Level-2行情数据里提取特征,并做简单的对手分类。代码不长,但核心逻辑都在里面了。

import pandas as pd
import numpy as np

def extract_opponent_features(df):
    """
    从逐笔成交数据中提取对手行为特征
    df: 包含['time', 'price', 'volume', 'side']的DataFrame
    """
    features = {}
    
    # 1. 大单占比(单笔成交量 > 平均量3倍)
    avg_vol = df['volume'].mean()
    large_trades = df[df['volume'] > avg_vol * 3]
    features['large_trade_ratio'] = len(large_trades) / len(df)
    
    # 2. 主动买卖比
    buy_vol = df[df['side'] == 'buy']['volume'].sum()
    sell_vol = df[df['side'] == 'sell']['volume'].sum()
    features['buy_sell_ratio'] = buy_vol / (sell_vol + 1e-8)
    
    # 3. 成交间隔均值(秒)
    df['time_diff'] = df['time'].diff().dt.total_seconds()
    features['avg_trade_interval'] = df['time_diff'].mean()
    
    # 4. 撤单率(假设有撤单标记列)
    if 'cancel' in df.columns:
        features['cancel_rate'] = df['cancel'].sum() / len(df)
    
    return features

# 示例:判断对手类型
def classify_opponent(features):
    if features['large_trade_ratio'] > 0.3 and features['avg_trade_interval'] < 1.0:
        return '量化基金'
    elif features['large_trade_ratio'] > 0.1 and features['buy_sell_ratio'] > 1.5:
        return '机构(主动买入)'
    else:
        return '散户/其他'

注意:上面的代码只是演示逻辑。实际生产中,你需要处理数据对齐、缺失值、以及不同交易所的数据格式差异。我踩过的坑是:某交易所的撤单标记字段是空的,导致撤单率一直为0,模型把量化基金全判成了散户。后来我加了一个“挂单存活时间”的替代特征才解决。

2.5 知识体系总览

下面这张图,是我自己画的知识结构。每次做对手建模前,我都会先过一遍这张图,确保没有遗漏关键环节。

对手行为建模知识体系 数据源 Level-2行情 | 逐笔成交 特征提取 订单簿 | 成交 | 时间序列 模式分类 趋势 | 回归 | 套利 | 操纵 对手类型识别 散户 | 机构 | 量化基金 行为预测 下一笔方向 | 持仓周期 | 撤单概率 策略应对 反制 | 跟随 | 套利

这张图从下往上看,就是整个建模流程。我个人习惯,每次拿到新数据,都先按这个框架走一遍,确保每个环节都覆盖到。

2.6 小结

这一章我们聊了对手行为建模的三个核心步骤:识别类型、分类模式、提取特征。说白了,就是先知道对面是谁,再猜他要干嘛,最后用数据验证你的猜测。嗯,这里要提醒一句:模型永远只是辅助,市场里总有你意想不到的“新物种”。保持敬畏,持续迭代,才是长久之道。


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