4. 买卖价差与市场情绪度量
任务目标
本案例基于订单簿或逐笔成交数据,计算买卖价差(bid-ask spread)的时序变化,并分析价差扩大/缩小与市场情绪(恐慌/贪婪)之间的关联。核心交付物为:价差时序曲线、价差统计特征,以及价差与情绪指标的联动判断逻辑。
数据与依赖
使用Python 3.9+,依赖pandas、numpy、matplotlib。输入数据为模拟的订单簿快照(时间戳、买一价、卖一价),共200个连续快照,代表约3.3分钟的交易时段(间隔1秒)。数据生成逻辑内嵌于代码中,保证可独立复现。
核心实现
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
# ---------- 1. 生成模拟订单簿快照数据 ----------
np.random.seed(42)
n = 200
t = pd.date_range('2025-01-06 09:30:00', periods=n, freq='s')
# 构造价差动态:前80秒窄幅(恐慌缓释),中间60秒显著扩大(恐慌加剧),后60秒回落(情绪修复)
base_spread = 0.02
spread_pattern = np.concatenate([
np.random.normal(0.02, 0.005, 80), # 正常/偏贪婪
np.random.normal(0.08, 0.015, 60), # 恐慌扩大
np.random.normal(0.03, 0.008, 60) # 修复
])
spread = np.abs(spread_pattern) # 保证非负
# 买一价围绕100波动,卖一价 = 买一价 + spread
bid = 100 + np.cumsum(np.random.normal(0, 0.01, n))
ask = bid + spread
df = pd.DataFrame({'ts': t, 'bid': bid, 'ask': ask})
df['spread'] = df['ask'] - df['bid']
# ---------- 2. 价差统计与情绪区间划分 ----------
# 用滚动均值平滑,识别价差趋势
df['spread_ma'] = df['spread'].rolling(window=10, min_periods=1).mean()
# 情绪判定阈值:以整体均值为基准,高于均值+0.5倍标准差视为恐慌(价差扩大)
mean_s = df['spread'].mean()
std_s = df['spread'].std()
panic_threshold = mean_s + 0.5 * std_s
df['sentiment'] = np.where(df['spread_ma'] > panic_threshold, '恐慌', '正常/贪婪')
# ---------- 3. 输出关键统计量 ----------
print(f"整体价差均值: {mean_s:.4f}")
print(f"整体价差标准差: {std_s:.4f}")
print(f"恐慌判定阈值: {panic_threshold:.4f}")
print(f"恐慌状态占比: {(df['sentiment']=='恐慌').mean()*100:.1f}%")
# 恐慌时段 vs 正常时段的平均价差对比
panic_spread = df.loc[df['sentiment']=='恐慌', 'spread'].mean()
normal_spread = df.loc[df['sentiment']!='恐慌', 'spread'].mean()
print(f"恐慌时段平均价差: {panic_spread:.4f}")
print(f"正常时段平均价差: {normal_spread:.4f}")
# ---------- 4. 可视化 ----------
fig, ax = plt.subplots(2, 1, figsize=(10, 6), sharex=True)
ax[0].plot(df['ts'], df['spread'], color='gray', alpha=0.5, label='原始价差')
ax[0].plot(df['ts'], df['spread_ma'], color='blue', linewidth=2, label='10秒滚动均值')
ax[0].axhline(panic_threshold, color='red', linestyle='--', label='恐慌阈值')
ax[0].set_ylabel('价差')
ax[0].legend()
ax[0].set_title('买卖价差时序与恐慌阈值')
ax[1].fill_between(df['ts'], 0, 1, where=(df['sentiment']=='恐慌').values,
color='red', alpha=0.3, transform=ax[1].get_xaxis_transform())
ax[1].set_yticks([])
ax[1].set_xlabel('时间')
ax[1].set_title('恐慌区间(红色高亮)')
plt.tight_layout()
plt.savefig('spread_sentiment.png', dpi=100)
plt.close()
print("图表已保存为 spread_sentiment.png")
运行与验证
运行方式:将上述代码保存为spread_analysis.py,在命令行执行python spread_analysis.py。
验证路径:
- 程序正常结束,无异常报错;
- 控制台输出5行统计信息,其中“恐慌时段平均价差”应显著高于“正常时段平均价差”(预期约0.08 vs 0.025,因数据构造如此);
- 当前目录生成
spread_sentiment.png,图中上半部分可见价差先平稳→扩大→回落的趋势,红色虚线为阈值;下半部分红色高亮区间与价差扩大区间基本重合。
判定标准:若恐慌区间占比在20%~40%之间,且恐慌/正常平均价差比值大于1.5,则说明价差扩大与恐慌情绪区间存在明显对应关系,案例验证通过。
结果解读
价差扩大通常反映市场深度下降、做市商避险情绪上升,对应恐慌状态;价差收窄则反映市场流动性恢复、情绪趋于平稳或贪婪。本案例通过滚动均值与阈值划分,将连续的价差序列映射为离散情绪状态,从而量化两者的联动关系。