Skip to content

14.5 高频做市策略进阶

名词解释:高频做市(High-Frequency Market Making)

高频做市是指在极短时间尺度(毫秒到秒级)内同时提供买卖双边报价,通过赚取买卖价差获利。与传统做市商不同,HFT做市商依赖算法和低延迟基础设施,其核心挑战包括库存风险管理、逆向选择识别以及动态价差调整。

一、库存风险管理

1.1 库存风险的来源

做市商在中介买卖双方时不可避免地持有方向性头寸。库存风险来自:

  • 方向性波动:持仓方向与价格走势相反
  • 流动性风险:无法及时平仓
  • 跳空风险:突发事件导致的价格大幅跳变

库存管理的核心是在价差收入与库存风险之间进行动态平衡

1.2 均值回归市场 vs 趋势市场的库存策略

市场状态对库存管理策略的选择至关重要:

市场状态特征库存策略挂单调整
均值回归价格围绕均值波动,偏离后会回归容忍较大库存,逆势加仓偏离方向提供更好价格
趋势市场价格有持续方向性严格控制库存,顺势减仓缩短等待时间,主动对冲
PYTHON79 行 · 2.7 KB
📄此处有展示代码79 行 · 2.7 KB展开 ▼
python
import numpy as np
import pandas as pd
from enum import Enum
from typing import Tuple

class MarketRegime(Enum):
    MEAN_REVERTING = 1
    TRENDING = 2
    NEUTRAL = 3

def detect_market_regime(prices: np.ndarray,
                          window: int = 100) -> MarketRegime:
    """
    检测市场状态:均值回归 vs 趋势市场。

    使用 Hurst 指数和自相关结构来分类。
    """
    # 1. 计算 Hurst 指数(简化版:方差比检验)
    def hurst_estimate(ts, max_lag=20):
        lags = range(2, max_lag)
        tau = [np.sqrt(np.std(np.subtract(ts[lag:], ts[:-lag])))
               for lag in lags]
        poly = np.polyfit(np.log(lags), np.log(tau), 1)
        return poly[0]

    # 2. 自相关
    returns = np.diff(prices[-window:]) / prices[-window-1:-1]
    autocorr = np.corrcoef(returns[:-1], returns[1:])[0, 1]

    # 3. 趋势强度(趋势占比)
    trend_strength = np.mean(returns) / (np.std(returns) + 1e-10) * np.sqrt(252)

    if abs(trend_strength) > 1.5 and abs(autocorr) > 0.1:
        return MarketRegime.TRENDING
    elif abs(autocorr) < 0.05 and abs(trend_strength) < 0.5:
        return MarketRegime.MEAN_REVERTING
    else:
        return MarketRegime.NEUTRAL


def adaptive_inventory_control(inventory: float,
                                max_inventory: float,
                                mid_price: float,
                                vwap_entry: float,
                                regime: MarketRegime) -> dict:
    """
    基于市场状态的适应性库存控制。

    参数:
        inventory: 当前净头寸(正=多头,负=空头)
        max_inventory: 最大允许头寸
        mid_price: 当前中间价
        vwap_entry: 加权平均入场价
        regime: 市场状态
    返回:
        包含 inventory_ratio, skew_bps, hedge_urgency 的字典
    """
    inventory_ratio = abs(inventory) / max_inventory
    pnl_bps = (mid_price - vwap_entry) / vwap_entry * 10000 if inventory != 0 else 0

    if regime == MarketRegime.MEAN_REVERTING:
        # 均值回归:较大的库存容忍度
        skew_bps = -inventory_ratio * 0.5  # 轻度偏斜
        hedge_urgency = max(0, inventory_ratio - 0.8)
    elif regime == MarketRegime.TRENDING:
        # 趋势市场:严格控制库存
        skew_bps = -np.sign(inventory) * inventory_ratio * 2.0  # 强偏斜
        hedge_urgency = max(0, inventory_ratio - 0.3)
    else:
        # 中性市场
        skew_bps = -inventory_ratio * 1.0
        hedge_urgency = max(0, inventory_ratio - 0.5)

    return {
        'inventory_ratio': inventory_ratio,
        'skew_bps': skew_bps,
        'hedge_urgency': hedge_urgency,
        'unrealized_pnl_bps': pnl_bps if inventory != 0 else 0
    }
点击展开可浏览运行结果
📘 本段代码定义了 3 个函数/类:函数 `detect_market_regime`(检测市场状态:均值回归 vs 趋势市场)、函数 `adaptive_inventory_control`(基于市场状态的适应性库存控制),以及 类 `MarketRegime`。该片段为教学展示(未包含独立运行的输入数据),可在实战练习中结合真实数据调用。

1.3 库存均值回归策略

经典的 Avellaneda-Stoikov(2008) 模型给出了做市商最优报价的解析解:

rb(s)=sqγσ2(Tt),ra(s)=s+qγσ2(Tt)

其中 rb,ra 是买卖报价的保留价格,s 是参考价格,q 是库存,γ 是风险厌恶系数,σ 是波动率。

PYTHON39 行 · 1.3 KB
📄此处有展示代码39 行 · 1.3 KB展开 ▼
python
def avellaneda_stoikov_quotes(inventory: float,
                                reference_price: float,
                                T_remaining: float,
                                gamma: float,
                                sigma: float,
                                k: float,
                                A: float) -> Tuple[float, float, float, float]:
    """
    Avellaneda-Stoikov(2008) 最优做市报价。

    参数:
        inventory: 当前库存
        reference_price: 参考价格
        T_remaining: 剩余交易时间
        gamma: 风险厌恶参数
        sigma: 波动率
        k: 订单到达率参数
        A: 订单到达率缩放参数
    返回:
        (reservation_bid, reservation_ask, bid_quote, ask_quote)
    """
    # 保留价格
    reservation_price = reference_price - inventory * gamma * sigma ** 2 * T_remaining

    # 最优价差
    optimal_spread = gamma * sigma ** 2 * T_remaining + \
        2 / gamma * np.log(1 + gamma / k)

    # 报价
    bid_quote = reservation_price - optimal_spread / 2
    ask_quote = reservation_price + optimal_spread / 2

    # 确保不交叉
    bid_quote = min(bid_quote, reference_price)
    ask_quote = max(ask_quote, reference_price)

    return reservation_price - optimal_spread / 2, \
        reservation_price + optimal_spread / 2, \
        bid_quote, ask_quote
点击展开可浏览运行结果
📘 本段代码定义了 1 个函数/类:函数 `avellaneda_stoikov_quotes`。该片段为教学展示(未包含独立运行的输入数据),可在实战练习中结合真实数据调用。

二、做市策略的回测难点

2.1 核心挑战

高频做市策略的回测面临几个独特挑战:

  1. 数据粒度:需要 tick 级别或 LOB 快照数据。分钟级数据完全不够。
  2. 成交概率建模:回测必须模拟限价单的实际成交过程,而非假设所有订单都能成交。
  3. 市场冲击建模:简化假设(如"以中间价成交")会严重高估绩效。
  4. 延迟模拟:即使几毫秒的延迟差异也会显著影响做市策略的盈利能力。
  5. 幸存者偏差:只有被成交的订单才在数据中可见,未成交的不可见。

2.2 订单簿回放(Replay)方法

PYTHON120 行 · 4.4 KB
📄此处有展示代码120 行 · 4.4 KB展开 ▼
python
class LOBBacktester:
    """
    基于订单簿回放的做市策略回测器。
    """

    def __init__(self, lob_data: pd.DataFrame):
        """
        参数:
            lob_data: LOB快照数据,包含时间戳和各级买卖价量
        """
        self.lob_data = lob_data.sort_values('timestamp').reset_index(drop=True)
        self.position = 0
        self.cash = 0.0
        self.active_orders = {'bid': [], 'ask': []}  # [(price, size, timestamp)]
        self.fill_log = []
        self.pnl = []

    def _check_fills(self, current_idx: int) -> list:
        """检查当前快照下是否有订单成交"""
        current = self.lob_data.iloc[current_idx]
        best_bid = current['bid_price_1']
        best_ask = current['ask_price_1']
        best_bid_size = current['bid_size_1']
        best_ask_size = current['ask_size_1']

        fills = []

        # 检查卖单成交(挂的卖单被买方吃掉)
        for i, (price, size, ts) in enumerate(self.active_orders['ask']):
            if price <= best_bid:  # 卖价低于等于最优买价,成交
                fill_prob = min(1.0, best_bid_size / size)
                if np.random.random() < fill_prob:
                    fills.append({
                        'side': 'sell',
                        'price': price,
                        'size': size,
                        'time': current['timestamp']
                    })
                    self.position -= size
                    self.cash += price * size
                    self.active_orders['ask'].pop(i)

        # 检查买单成交
        for i, (price, size, ts) in enumerate(self.active_orders['bid']):
            if price >= best_ask:
                fill_prob = min(1.0, best_ask_size / size)
                if np.random.random() < fill_prob:
                    fills.append({
                        'side': 'buy',
                        'price': price,
                        'size': size,
                        'time': current['timestamp']
                    })
                    self.position += size
                    self.cash -= price * size
                    self.active_orders['bid'].pop(i)

        return fills

    def _cancel_stale_orders(self, current_time, max_age_seconds: float = 5.0):
        """取消超时未成交的挂单"""
        for side in ['bid', 'ask']:
            self.active_orders[side] = [
                (p, s, ts) for p, s, ts in self.active_orders[side]
                if (current_time - ts).total_seconds() < max_age_seconds
            ]

    def run(self,
            quote_func,
            max_position: int = 1000,
            order_size: int = 100,
            cancel_age: float = 5.0) -> pd.DataFrame:
        """
        执行回测。

        参数:
            quote_func: 报价函数,接收 (current_idx, position, lob_data) 返回
                       {'bid_price': float, 'ask_price': float, 'bid_size': int,
                        'ask_size': int}
        """
        for i in range(len(self.lob_data)):
            current_time = self.lob_data.iloc[i]['timestamp']

            # 1. 检查成交
            fills = self._check_fills(i)
            self.fill_log.extend(fills)

            # 2. 取消过期订单
            self._cancel_stale_orders(current_time, cancel_age)

            # 3. 生成新报价
            if abs(self.position) < max_position:
                quotes = quote_func(i, self.position, self.lob_data)
                if quotes:
                    bid_p = quotes.get('bid_price')
                    ask_p = quotes.get('ask_price')
                    bid_s = quotes.get('bid_size', order_size)
                    ask_s = quotes.get('ask_size', order_size)

                    if bid_p is not None:
                        self.active_orders['bid'].append(
                            (bid_p, bid_s, current_time)
                        )
                    if ask_p is not None:
                        self.active_orders['ask'].append(
                            (ask_p, ask_s, current_time)
                        )

            # 4. 记录市值盈亏
            mid = (self.lob_data.iloc[i]['bid_price_1'] +
                   self.lob_data.iloc[i]['ask_price_1']) / 2
            mtm = self.cash + self.position * mid
            self.pnl.append({
                'time': current_time,
                'position': self.position,
                'cash': self.cash,
                'mtm': mtm
            })

        return pd.DataFrame(self.pnl)
点击展开可浏览运行结果
📘 本段代码定义了 1 个函数/类:类 `LOBBacktester`(基于订单簿回放的做市策略回测器)。该片段为教学展示(未包含独立运行的输入数据),可在实战练习中结合真实数据调用。

三、信号驱动的动态价差调整

3.1 多维信号综合

现代做市策略不仅依赖库存状态,还结合多种市场信号动态调整报价:

PYTHON31 行 · 1.4 KB
📄此处有展示代码31 行 · 1.4 KB展开 ▼
python
def signal_driven_spread(base_spread: float,
                          volatility: float,
                          order_imbalance: float,
                          vpin: float,
                          time_of_day_factor: float,
                          inventory_ratio: float) -> float:
    """
    多维信号驱动的动态价差调整。

    参数:
        base_spread: 基础价差(tick的倍数)
        volatility: 当前波动率与历史均值的比率
        order_imbalance: 订单簿不平衡指标 [-1, 1]
        vpin: 订单流毒性指标 [0, 1]
        time_of_day_factor: 日内时间因子 (0=开盘/收盘, 1=盘中)
        inventory_ratio: 库存/最大库存比率 [0, 1]
    返回:
        调整后的价差
    """
    # 各信号的调整系数
    vol_adj = 1.0 + (volatility - 1.0) * 0.5      # 波动率高 -> 加大价差
    tox_adj = 1.0 + vpin * 1.5                      # 毒性高 -> 加大价差
    imbalance_adj = 1.0 + abs(order_imbalance) * 0.3 # 不平衡 -> 加大价差
    tod_adj = 1.0 + (1 - time_of_day_factor) * 0.5  # 开盘/收盘 -> 加大价差
    inv_adj = 1.0 + inventory_ratio * 1.0           # 库存高 -> 加大价差

    adjusted_spread = base_spread * (
        vol_adj * tox_adj * imbalance_adj * tod_adj * inv_adj
    ) ** (1.0 / 5.0)  # 几何平均

    return max(base_spread * 0.8, min(adjusted_spread, base_spread * 3.0))
点击展开可浏览运行结果
📘 本段代码定义了 1 个函数/类:函数 `signal_driven_spread`。该片段为教学展示(未包含独立运行的输入数据),可在实战练习中结合真实数据调用。

3.2 竞争性做市的反应速度

在竞争激烈的电子化市场中,做市商的反应速度是核心竞争力。关键因素包括:

  1. 基础设施延迟:网卡、交换机、光纤的物理延迟(纳秒级优化)
  2. 软件延迟:事件处理循环、数据结构选择、内存分配/释放
  3. 协同定位(Co-location):将服务器放置在交易所数据中心
名词解释:反应速度的分层
  • tick-to-trade:从接收到市场数据到发出订单的延迟(目标:< 1微秒)
  • round-trip:从订单发出到确认接收的延迟(取决于物理距离)
  • jitter:延迟的波动性,低抖动与低延迟同等重要

3.3 回测到实盘的差距管理

PYTHON33 行 · 1.3 KB
📄此处有展示代码33 行 · 1.3 KB展开 ▼
python
def estimate_backtest_to_live_gap(backtest_sharpe: float,
                                   fill_rate_backtest: float,
                                   estimated_live_fill_rate: float,
                                   latency_ms: float,
                                   competition_index: float) -> dict:
    """
    估计从回测到实盘的性能衰减。

    参数:
        backtest_sharpe: 回测夏普比率
        fill_rate_backtest: 回测中的成交率
        estimated_live_fill_rate: 估计的实盘成交率
        latency_ms: 策略延迟(毫秒)
        competition_index: 竞争指数 [0, 1],1表示极度竞争
    返回:
        包含性能衰减估计的字典
    """
    # 成交率衰减
    fill_decay = estimated_live_fill_rate / fill_rate_backtest

    # 滑点估计(基于延迟和竞争)
    slippage_bps = latency_ms * 0.1 * (1 + competition_index * 5)

    # 夏普衰减估计
    live_sharpe_estimate = backtest_sharpe * fill_decay * 0.7

    return {
        'fill_rate_decay': 1 - fill_decay,
        'estimated_slippage_bps': slippage_bps,
        'backtest_sharpe': backtest_sharpe,
        'estimated_live_sharpe': live_sharpe_estimate,
        'performance_decay_pct': (1 - live_sharpe_estimate / backtest_sharpe) * 100
    }
点击展开可浏览运行结果
📘 本段代码定义了 1 个函数/类:函数 `estimate_backtest_to_live_gap`(估计从回测到实盘的性能衰减)。该片段为教学展示(未包含独立运行的输入数据),可在实战练习中结合真实数据调用。

高频做市是量化交易中技术密集度最高的领域之一,它横跨了市场微观结构理论、低延迟系统架构和随机最优控制三个学科。在深入理解了市场微观结构之后,接下来我们将视角扩大到宏观经济层面,探讨宏观因子如何系统性地影响资产定价