4、事件检测与信号生成:基于NLP的事件抽取、正则表达式匹配事件、事件强度打分、信号阈值设定
做事件交易,最核心的问题是什么?
不是你怎么分析,而是你能不能第一时间知道事件发生了。
我早年做量化的时候,吃过这个亏。有一次财报出来,我还在手动刷新页面,结果市场已经反应完了。嗯,从那以后,我就把事件检测这件事,彻底交给了代码。
4.1 事件检测的两条腿:NLP与正则
事件检测,说白了就是从海量文本里捞出我们想要的东西。我个人习惯用两条腿走路:
- 正则表达式:快、准、稳。适合结构化的公告、财报标题。
- NLP事件抽取:灵活、泛化。适合新闻、社交媒体这种非结构化文本。
你想想看,如果只靠正则,遇到「公司拟收购XX」和「公司完成收购XX」这种变体,你得写多少规则?反过来,如果只靠NLP,遇到「分红10派5」这种固定格式,又显得杀鸡用牛刀。
我的经验法则:能用正则的,别用NLP。正则搞不定的,再上NLP。
4.2 正则表达式匹配事件:快刀斩乱麻
正则匹配,我一般用在公告标题上。比如财报、分红、回购、增持这些,格式相对固定。
举个例子,匹配「业绩预增」类事件:
import re
# 匹配业绩预增公告
pattern = r'(业绩|净利润|营收).{0,10}(预增|增长|上升|扭亏)'
text = "公司2024年业绩预增公告"
match = re.search(pattern, text)
if match:
print(f"检测到事件: {match.group()}")
这里有个坑,我踩过。正则写得太宽,容易误报。比如「业绩预增」和「业绩预增幅度低于预期」,前者是利好,后者是利空。所以我的做法是:先粗筛,再精分。
避坑指南:我曾经写过一个「回购」的正则,结果把「回购股份用于注销」和「回购股份用于股权激励」全混在一起了。后来我加了关键词权重,才把两类事件分开。
4.3 NLP事件抽取:让机器读懂新闻
正则搞不定的,就得靠NLP了。我常用的方法是基于预训练模型+触发词的抽取方式。
具体来说,分三步:
- 触发词检测:先找事件关键词,比如「收购」「减持」「中标」。
- 实体识别:找出谁收购了谁,金额多少。
- 事件分类:判断是利好还是利空。
我项目中用过BERT做微调,效果不错。但说实话,对于交易场景,速度比精度更重要。所以我后来改用轻量级的模型,比如ALBERT或者蒸馏版BERT。
from transformers import pipeline
# 加载事件抽取模型
event_extractor = pipeline("text-classification",
model="your-event-model")
text = "公司成功中标5G基站建设项目,金额约2.3亿元"
result = event_extractor(text)
print(f"事件类型: {result[0]['label']}, 置信度: {result[0]['score']:.2f}")
注意:NLP模型不是万能的。我遇到过模型把「公司否认收购传闻」识别成「收购事件」,因为「收购」这个词出现了。所以,否定词处理一定要做。
4.4 事件强度打分:别把蚊子当大象
检测到事件只是第一步。更关键的是,这个事件有多重要?
我设计了一套打分体系,主要看三个维度:
| 维度 | 权重 | 说明 |
|---|---|---|
| 事件类型 | 40% | 并购、财报、政策等基础权重 |
| 金额/规模 | 30% | 占市值比例越高,分数越高 |
| 市场情绪 | 30% | 同行业其他公司的反应 |
举个例子,一个「回购1亿元」的事件,如果公司市值才10亿,那强度分就很高。如果市值1000亿,那也就是个普通事件。
def event_strength_score(event_type, amount, market_cap, sentiment):
# 基础分
base_score = {
'并购': 80,
'财报': 70,
'回购': 60,
'减持': 50
}.get(event_type, 30)
# 规模分
ratio = amount / market_cap
scale_score = min(ratio * 100, 100)
# 情绪分
sentiment_score = sentiment * 100
# 加权总分
total = base_score * 0.4 + scale_score * 0.3 + sentiment_score * 0.3
return total
我个人习惯:强度分低于40的事件,我基本不看。因为噪音太多,容易干扰判断。
4.5 信号阈值设定:别让系统乱叫
有了强度分,接下来就是设阈值。阈值设得太低,系统天天报警,你根本看不过来。设得太高,又容易错过机会。
我的做法是动态阈值:
- 基础阈值:固定60分,低于这个的直接过滤。
- 动态调整:根据市场波动率调整。波动大的时候,阈值提高10-20分。
- 事件类型差异化:并购类事件阈值设低点(50分),因为机会难得。日常公告类设高点(70分)。
我曾经犯过一个错:把所有事件的阈值都设成一样的。结果并购机会没抓到,日常公告倒是堆了一堆。后来改成差异化阈值,效果好了很多。
小技巧:你可以用历史回测来优化阈值。比如回测过去一年,看看阈值设在多少时,信号准确率最高。
4.6 知识体系总览
下面这张图,是我做事件检测的完整流程。你可以把它当成一个参考框架:
这张图里,我特别想强调一点:正则和NLP不是二选一,而是互补的。结构化文本走正则,非结构化文本走NLP,最后汇合到一起做强度打分。
好了,事件检测和信号生成这部分,核心就是这些。记住:快、准、稳,三个字就够了。