第三章:事件序列可视化——用Matplotlib绘制事件序列图与K线图叠加事件标记

可视化这件事,在量化交易里有多重要?

我个人的体会是:你跑完一百个回测,看了一千个数字,都不如一张图来得直观。尤其是事件序列模式识别,你光看时间戳和价格变动,脑子很容易宕机。但把事件标在K线图上,一眼就能看出规律——嗯,这里出信号了,那里是假突破。

这一章,我们就来搞定两件事:

  • 第一,画出事件序列图,看看事件在时间轴上的分布
  • 第二,把事件标记叠加到K线图上,让模式和价格走势对应起来

说白了,就是让数据「开口说话」。


3.1 事件序列图:先看看事件长什么样

事件序列图,本质上就是一个时间轴上的散点图或柱状图。每个点代表一个事件发生的时间点,纵轴可以是事件类型、事件强度,或者干脆就是0/1标记。

我刚开始做事件驱动策略时,第一件事就是把所有事件按时间画出来。为什么?因为你会发现很多「看起来很美」的策略,事件分布其实稀稀拉拉,根本撑不起交易频率。

核心思路:

  • 横轴:时间(datetime)
  • 纵轴:事件类型(用不同颜色或y轴位置区分)
  • 标记:每个事件用一个点或竖线表示

来看一个简单的例子。假设我们有一组事件数据:

import pandas as pd
import matplotlib.pyplot as plt
import numpy as np

# 模拟事件数据
np.random.seed(42)
dates = pd.date_range('2024-01-01', periods=100, freq='D')
events = pd.DataFrame({
    'date': dates,
    'event_type': np.random.choice(['买入信号', '卖出信号', '新闻冲击', '异常波动'], size=100),
    'strength': np.random.rand(100) * 10
})

# 绘制事件序列图
fig, ax = plt.subplots(figsize=(12, 5))

# 用不同颜色区分事件类型
colors = {'买入信号': 'green', '卖出信号': 'red', '新闻冲击': 'orange', '异常波动': 'purple'}
for etype, group in events.groupby('event_type'):
    ax.scatter(group['date'], [etype]*len(group), 
               color=colors[etype], label=etype, s=group['strength']*20, alpha=0.6)

ax.set_xlabel('时间')
ax.set_ylabel('事件类型')
ax.set_title('事件序列分布图')
ax.legend()
plt.xticks(rotation=45)
plt.tight_layout()
plt.show()

这段代码里,我用散点图把事件按类型分布在纵轴上。点的大小代表事件强度——你想想看,如果某个时间段突然出现一堆大圆点,那肯定是有情况。

我的小技巧: 事件序列图最好配合「事件密度图」一起看。用直方图统计每天/每小时的事件数量,能快速发现事件聚集的时段。我曾经在分析某只股票的新闻事件时,发现大部分事件都集中在开盘后半小时内——后来才知道,那是机构集中发布公告的时间窗口。


3.2 K线图叠加事件标记:这才是实战利器

事件序列图只能看事件本身,但做交易的人更关心的是:事件发生时,价格在干什么?

所以,把事件标记直接画在K线图上,就成了最直观的分析方式。你一眼就能看到:

  • 这个买入信号出现时,K线是什么形态?
  • 那个新闻冲击之后,价格是涨了还是跌了?
  • 异常波动事件是不是总出现在大阴线之后?

嗯,这才是模式识别的起点。

3.3 用mplfinance画带事件的K线图

Python里画K线图,我个人最推荐 mplfinance 这个库。它封装得很好,而且支持自定义标记叠加。

先安装:

pip install mplfinance

然后看代码:

import mplfinance as mpf
import pandas as pd
import numpy as np

# 模拟K线数据
np.random.seed(42)
dates = pd.date_range('2024-01-01', periods=200, freq='D')
price = 100 + np.cumsum(np.random.randn(200) * 0.5)
df = pd.DataFrame({
    'Open': price + np.random.randn(200) * 0.2,
    'High': price + np.abs(np.random.randn(200)) * 0.5,
    'Low': price - np.abs(np.random.randn(200)) * 0.5,
    'Close': price + np.random.randn(200) * 0.3,
    'Volume': np.random.randint(1000, 10000, 200)
}, index=dates)

# 模拟事件标记
event_dates = dates[np.random.choice(range(200), size=15, replace=False)]
event_types = np.random.choice(['买入', '卖出', '新闻'], size=15)

# 准备标记数据
markers = []
for d, t in zip(event_dates, event_types):
    if t == '买入':
        markers.append(mpf.make_addplot(df.loc[d:d], type='scatter', 
                       markersize=100, marker='^', color='green'))
    elif t == '卖出':
        markers.append(mpf.make_addplot(df.loc[d:d], type='scatter',
                       markersize=100, marker='v', color='red'))
    else:
        markers.append(mpf.make_addplot(df.loc[d:d], type='scatter',
                       markersize=80, marker='o', color='orange'))

# 绘制K线图叠加事件
mpf.plot(df, type='candle', volume=True, 
         addplot=markers,
         title='K线图叠加事件标记',
         style='charles',
         figsize=(14, 8))

关键点说明:

  • make_addplot 用来创建叠加图层,可以指定散点、线条、柱状图等
  • 用不同形状和颜色区分事件类型:绿色三角(买入)、红色倒三角(卖出)、橙色圆点(新闻)
  • markersize 控制标记大小,可以根据事件强度动态调整

为什么我用三角和倒三角?因为买入信号向上,卖出信号向下,视觉上非常直觉。你想想看,如果都用圆点,那还得看颜色才能区分,多费劲。

避坑指南: 我曾经在叠加事件标记时,直接把所有事件都画上去,结果K线图密密麻麻全是点,根本看不清价格走势。后来我学乖了——只标记「高置信度」的事件,或者只显示最近N个事件。记住:可视化是为了看清模式,不是为了展示所有数据。


3.4 进阶:事件时间轴与K线图的联动

有时候,光在K线上标点还不够。比如你想看事件发生前后N根K线的价格行为——这就是事件驱动分析的核心。

我常用的做法是:

  1. 在K线图下方画一个事件时间轴子图
  2. 用竖线或色带标记事件发生的区间
  3. 在事件前后用不同背景色高亮

来看一个实现:

fig, (ax1, ax2) = plt.subplots(2, 1, figsize=(14, 8), 
                                gridspec_kw={'height_ratios': [3, 1]})

# 上子图:K线图
mpf.plot(df, type='candle', ax=ax1, volume=False,
         style='charles', show_nontrading=False)

# 下子图:事件时间轴
for d, t in zip(event_dates, event_types):
    color = 'green' if t == '买入' else 'red' if t == '卖出' else 'orange'
    ax2.axvline(x=d, color=color, linestyle='--', alpha=0.7, linewidth=1)
    ax2.text(d, 0.5, t, rotation=90, fontsize=8, color=color)

ax2.set_ylim(0, 1)
ax2.set_yticks([])
ax2.set_xlabel('时间')
ax2.set_title('事件时间轴')
plt.tight_layout()
plt.show()

这样上下对照着看,效果非常好。上面是价格走势,下面是事件分布,一眼就能看出事件和价格之间的因果关系。


3.5 本章知识体系

下面这张图,是我自己总结的事件序列可视化核心逻辑,你可以把它当作一个检查清单:

事件序列可视化核心流程 数据准备 K线数据 + 事件数据 可视化类型 事件序列图 / K线叠加图 标记设计 形状 / 颜色 / 大小 关键要素:时间对齐 | 事件过滤 | 强度映射 | 前后窗口 输出:带事件标记的K线图 + 事件时间轴 图:事件序列可视化的五个核心步骤

3.6 一些实战经验

最后,分享几个我在项目中踩过的坑和总结的经验:

  • 事件过滤很重要:别把所有事件都画上去。我一般会设置一个「置信度阈值」,只标记置信度高于0.7的事件。否则图上一团乱麻,什么都看不出来。
  • 颜色要克制:最多用4-5种颜色,再多就分不清了。红绿蓝橙黄,基本够用。
  • 交互式探索更高效:静态图只能看个大概。我建议用 plotlybokeh 做交互式图表,鼠标悬停能看到事件详情。这个我们后面章节会专门讲。
  • 注意时间对齐:事件时间戳和K线时间戳必须精确对齐。我曾经因为时区问题,事件标记全部偏移了一天,查了半天才发现。

一个小技巧: 如果你的事件很多,可以试试「事件热力图」——把事件密度用颜色映射到K线图上,颜色越深代表事件越密集。这样既能保留K线信息,又能看到事件聚集区域。

好了,这一章的内容就到这里。可视化这件事,说白了就是「把数据变成故事」。你画得越清楚,模式就越容易浮现出来。下一章我们会进入更核心的部分——如何用机器学习自动识别这些事件模式。


公众号:蓝海数据掘金营,微信deep3321