1. 流动性定义与核心指标

大家好,我是老张。今天咱们聊聊流动性——这个在量化交易里绕不开的话题。

流动性是什么?说白了,就是你能不能用合理的价格,快速地把资产变成现金。你想想看,如果你手里拿着一张股票,想卖的时候没人接盘,或者得打个八折才能出手,那这资产就“不流动”。

我刚开始做量化那会儿,吃过一次亏。策略回测跑得漂亮,年化收益30%+,结果实盘一跑,滑点直接吃掉一半利润。后来复盘才发现,我选的标的流动性太差了。嗯,从那以后,流动性指标就成了我策略里的“标配”。

核心观点:流动性差的资产,再好的策略也是纸上谈兵。流动性风险是量化策略的“隐形杀手”。

1.1 为什么流动性对量化策略重要?

这个问题我问过不少刚入行的朋友。他们的第一反应往往是:“流动性好,交易成本低呗。”对,但不全对。

流动性影响的不只是成本,还有策略的容量、执行效率,甚至信号的有效性。举个例子:

  • 交易成本:买卖价差越大,你进出的摩擦成本越高。高频策略尤其敏感。
  • 策略容量:流动性不足,大资金一进去就把价格打飞了。我见过有人用1000万做小盘股,结果自己把自己拉涨停。
  • 信号衰减:你想买的量,市场接不住,信号还没执行完,价格已经变了。
  • 风险控制:遇到黑天鹅,流动性枯竭,你想止损都出不来。2015年股灾就是活生生的例子。

所以,流动性不是锦上添花,而是策略的“地基”。地基不稳,楼盖得再高也得塌。

1.2 核心指标详解

接下来,我带你逐个拆解几个最常用的流动性指标。每个指标我都会给出数学定义和Python实现,方便你直接拿来用。

1.2.1 买卖价差(Bid-Ask Spread)

这是最直观的流动性指标。买一价和卖一价的差值,就是你交易一单位需要付出的“过路费”。

数学定义:

绝对价差 = 卖一价 - 买一价
相对价差 = (卖一价 - 买一价) / 中间价
中间价 = (买一价 + 卖一价) / 2

Python计算:

import pandas as pd

def calc_spread(df):
    """
    df 必须包含 ask_price1, bid_price1 两列
    """
    df['mid_price'] = (df['ask_price1'] + df['bid_price1']) / 2
    df['abs_spread'] = df['ask_price1'] - df['bid_price1']
    df['rel_spread'] = df['abs_spread'] / df['mid_price']
    return df

# 示例
data = pd.DataFrame({
    'ask_price1': [10.05, 10.10, 10.08],
    'bid_price1': [10.00, 10.02, 10.03]
})
result = calc_spread(data)
print(result[['abs_spread', 'rel_spread']])

个人经验:我习惯用相对价差,因为不同价格的股票绝对值没法直接比。比如茅台和工商银行,绝对价差差好几倍,但相对价差都在0.1%左右。

1.2.2 市场深度(Market Depth)

价差只告诉你第一档的成本,但如果你想买100万股呢?这时候就得看市场深度了。

定义:在某个价格水平上,市场能承受的订单数量。通常看买卖各档位的累计挂单量。

Python计算:

def calc_depth(df, levels=5):
    """
    计算买卖各档位的累计深度
    df 需包含 ask_vol1~ask_vol5, bid_vol1~bid_vol5
    """
    ask_cols = [f'ask_vol{i}' for i in range(1, levels+1)]
    bid_cols = [f'bid_vol{i}' for i in range(1, levels+1)]
    
    df['ask_depth'] = df[ask_cols].sum(axis=1)
    df['bid_depth'] = df[bid_cols].sum(axis=1)
    df['total_depth'] = df['ask_depth'] + df['bid_depth']
    return df

注意:市场深度是动态变化的。我曾经在回测里用了静态深度数据,结果实盘时发现深度只有回测的一半。后来我改用实时快照数据,才解决了这个问题。

1.2.3 成交量(Volume)

成交量是最常用的流动性代理指标。量越大,通常流动性越好。但要注意,成交量是事后指标,不能预测未来的流动性。

Python计算:

# 计算日成交量滚动均值
df['volume_ma5'] = df['volume'].rolling(window=5).mean()
df['volume_std'] = df['volume'].rolling(window=20).std()

# 成交量异常检测
df['volume_zscore'] = (df['volume'] - df['volume'].rolling(20).mean()) / df['volume'].rolling(20).std()

1.2.4 换手率(Turnover Rate)

换手率 = 成交量 / 流通股本。它剔除了股本规模的影响,更适合跨股票比较。

数学定义:

换手率 = 当日成交量 / 流通股本

Python计算:

def calc_turnover(df, shares_outstanding):
    """
    shares_outstanding: 流通股本(股数)
    """
    df['turnover'] = df['volume'] / shares_outstanding
    return df

避坑指南:我曾经用总股本代替流通股本算换手率,结果发现指标严重偏低。后来才意识到,很多大股东的股份是不流通的。一定要用流通股本!

1.2.5 Amihud非流动性指标

这是学术界用得最多的流动性指标之一。它衡量的是“每单位成交量引起的价格变化”。价格变化越大,说明流动性越差。

数学定义:

Amihud_i = (1/N) * Σ(|r_i| / volume_i)

其中 r_i 是第 i 分钟的收益率,volume_i 是第 i 分钟的成交量(金额)。

Python计算:

def calc_amihud(df):
    """
    df 需包含 close, volume(金额), 按时间排序
    """
    df['return'] = df['close'].pct_change().abs()
    df['amihud_raw'] = df['return'] / df['volume']
    # 通常取滚动均值
    df['amihud'] = df['amihud_raw'].rolling(window=20).mean()
    # 处理无穷大
    df['amihud'] = df['amihud'].replace([float('inf'), -float('inf')], float('nan'))
    return df

重要提示:Amihud指标的值通常非常小(10^-6量级),建议乘以10^6或取对数后使用。我一般取log(1 + Amihud * 10^6)做标准化。

1.3 知识体系总览

下面这张图,我把本章的核心逻辑梳理了一下。你可以把它当作一个“流动性指标工具箱”。

流动性指标知识体系 流动性 交易成本维度 市场容量维度 价格冲击维度 买卖价差 市场深度 成交量 换手率 Amihud非流动性 三个维度覆盖了流动性的主要特征 应用:策略筛选 → 交易执行 → 风险控制 每个指标都有其适用场景,建议组合使用

1.4 指标对比与选择建议

这么多指标,到底用哪个?我的建议是:不要只用单一指标。每个指标都有它的盲区。

指标 优点 缺点 适用场景
买卖价差 直观、实时性强 只反映第一档,大单不适用 高频策略、小单交易
市场深度 反映多档位承接能力 数据量大,更新频繁 大单执行、算法交易
成交量 数据易得,稳定 事后指标,有滞后 中低频策略、选股
换手率 跨股票可比 依赖流通股本数据 选股、行业对比
Amihud 综合价格与成交量 计算复杂,值域不稳定 学术研究、因子构建

我的组合拳:做选股策略时,我一般用换手率+Amihud;做执行策略时,用价差+深度。不同场景,不同工具。

1.5 小结

流动性不是玄学,它是可以量化、可以计算的。今天讲的五个指标,每个都有它的数学定义和Python实现。你拿回去就能用。

记住一句话:流动性是策略的“安全带”。系好安全带,才能开快车。

下一章,我会讲如何用这些指标构建一个流动性评分系统。到时候咱们再聊。


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