做新闻Alpha这几年,我最大的感受是:它不像因子挖掘那样有明确的数学框架,更像是一门“把信息变成持仓”的手艺。市面上讲情绪Alpha的文章已经很多了,但真正把新闻Alpha单独拎出来,讲清楚它和情绪因子的边界、数据处理的坑、以及信号衰减规律的,其实不多。我这套内容打算分成三章来写,第一章聊情绪Alpha的整体框架,这是第二章,专门聚焦新闻Alpha本身。第三章再回到情绪与新闻的组合应用。
这一章里,我会把新闻Alpha从数据到信号再到回测的完整链路拆开揉碎,重点讲清楚几个容易被忽略的细节:比如新闻时间戳的“真实发生时刻”和“机器收录时刻”之间的差,比如如何把非结构化文本映射到可交易的主体上,再比如新闻信号为什么要做“衰减”处理而不是简单二值化。这些都是我在实际项目中反复踩坑后才总结出来的东西,希望能帮正在做类似方向的朋友少走些弯路。
如果你正准备把新闻数据纳入自己的量化体系,或者已经在用但效果不稳定,这篇内容应该对你有用。我会尽量少讲空泛的“自然语言处理赋能投资”之类的话,多给一些能直接落地的东西。
1. 新闻Alpha的核心问题:它到底在赚什么钱
先说一个我经常被问到的问题:新闻Alpha和情绪Alpha,到底有什么区别?很多人觉得新闻就是情绪的载体,两者没必要分家。但如果从信号构建的逻辑来看,它们其实赚的是两种不同的钱。
情绪Alpha赚的是“市场参与者的情绪偏差”。它关注的是人群的恐慌、贪婪、过度乐观,比如社交媒体上的讨论热度、散户论坛的看多看空比例。这类信号的核心假设是:情绪极端时,价格会偏离价值,而这种偏离终会回归。
新闻Alpha赚的则是“信息传递的时滞与反应不足”。它关注的是已经发生的事实——公司发布了财报、产品被召回、管理层变动、行业政策变化——这些客观事件对资产价值的影响,以及市场对这个信息的定价速度。新闻Alpha的底层逻辑是:信息从发布到被市场充分定价,中间存在可捕捉的窗口期。在这个窗口期内做出反应,就能跑赢那些反应慢的市场参与者。
这个区别直接决定了数据处理方式。情绪数据强调的是“量”——多少人说了、说了多少、情绪多极端;新闻数据强调的是“质”和“时”——发生了什么、影响多大、什么时候发生的。很多团队把新闻数据按情绪分析的路子处理,就会显得信息密度太低、噪声太大,根本原因就是搞混了这两类信号的本质。
新闻Alpha的第二个关键特性是它的事件驱动属性。它不是一种时刻都在输出的连续信号,而是“等待事件发生,然后快速反应”的触发式信号。这带来的直接影响是:它的持仓周期通常比传统因子短,换手率更高,收益分布也更不均匀——可能一个月里大部分时间都在空转,但只要几个大事件抓对了,整月收益就出来了。
也正因如此,新闻Alpha的容量相对有限。它不像市值因子那样可以容纳巨额资金,因为当你的资金体量足够大时,你的买入行为本身就抹平了那个信息时滞,超额收益也随之消失。这一点在做资金管理时必须提前想清楚。
1.1 从信息到收益的传导链路
我在做新闻Alpha系统时,习惯把整个流程拆成四个环节:事件检测、影响评估、信号生成、执行衰减。下面把这个链路铺开讲。
事件检测解决的是“这条新闻里有没有值得交易的事件”。不是所有新闻都能产生Alpha——公司换了前台接待这种消息就不值得反应。一个可交易的新闻事件,至少要满足两个条件:一是它对资产的内在价值有实质性影响,二是它的影响方向可以相对明确地判断。财报超预期、核心产品获批、大股东增持,这些是典型的正方向事件;营收暴雷、核心高管离职、产品质量事故,这些则是典型的负方向事件。
影响评估解决的是“这件事的影响有多大”。同样是“公司发布公告”,季度财报和“签署战略合作协议”的影响力完全不是一个量级。评估影响强度通常有几种途径:基于历史同类事件发生后的价格反应均值来估算、基于文本中数字的偏离度来量化(比如实际营收比预期高了多少)、或者直接交给模型从历史样本中学习。
信号生成解决的是“该用什么方向、多大仓位去应对”。这里的关键是方向映射和强度换算。方向映射就是把事件分类映射到多空方向上,这一步相对成熟;强度换算则要把事件的影响力度转换成具体的仓位权重,通常会和波动率挂钩——影响大、波动预期高的信号,仓位就相应调低,保持风险预算不变。
执行衰减解决的是“这个信号能活多久”。新闻Alpha天然是个短命信号,因为信息会快速被市场消化。典型的做法是对信号做时间衰减——事件发生当天信号强度最高,之后按小时或按天指数衰减,直到归零。衰减半衰期的设定,直接取决于你所交易标的的定价效率:美股大盘股的新闻信号可能几个小时就废了,而一些小盘股或流动性较差的品种,新闻信号可以维持好几天。
1.2 新闻Alpha的获利来源与边界
理解了传导链路,我们就能更清楚地看到新闻Alpha的获利来源。核心就是一句话:当信息已经发生、但价格尚未完全反应时介入。学术上这叫post-earnings-announcement drift(盈余公告后漂移),是最经典、证据最扎实的异象之一。公司发布财报后,股价不是瞬间跳到位的,而是会沿着超预期或低于预期的方向持续漂移一段时间,这个漂移过程就是新闻Alpha的利润池。
但边界也很明显。第一,这个利润池正在变浅。参与新闻交易的资金越来越多,从新闻发布到价格反应的时间窗口被压缩得越来越短,手动交易基本已经没有优势,半自动甚至全自动的管线才有机会。第二,新闻Alpha的回测极其容易自欺欺人。如果你在回测里假设自己能毫秒级响应所有新闻,而实盘里数据推送延迟几秒甚至几十秒,那回测出来的收益曲线就是镜花水月。关于回测的坑,我会在第5节专门展开。
另外要提醒的是,新闻Alpha并不是散户友好的策略类型。它需要低延迟的新闻数据源、稳定的执行通道、以及快速迭代的事件模型,这三样都有不低的门槛。但如果你是在做中低频的“事件驱动增强”——比如在每日调仓的框架里,用新闻信号作为已有因子组合的权重调整依据——那么对延迟的要求会友好很多。这也是我认为新闻Alpha最适合普通量化团队切入的姿势。
2. 数据处理:新闻Alpha的隐形护城河
说实话,新闻Alpha的模型部分很多人都能做,真正拉开差距的地方,是数据。文本数据与价格数据有本质区别:价格数据是结构化、干净、对齐好的;文本数据则是非结构化、充满噪声、时间归属模糊的。我见过太多团队把精力全花在调模型上,结果喂进去的数据满是基础性错误——公司名匹配错了、时间戳是爬虫抓取时间而不是发布时间、同一条新闻被多个源重复计入——这些错误会让再好的模型也白搭。
所以在新闻Alpha系统里,我始终把数据处理放在比建模更优先的位置。这个章节我会按数据处理的几个关键环节逐一展开:数据源选型、清洗去重、公司实体映射、时间戳处理。这四步看着基础,但每一步都有足够多的坑,值得细细说。
2.1 数据源选型:快、全、净怎么取舍
新闻数据源的选择,本质上是在“快、全、净”这三个维度上做权衡。快,指的是新闻从发布到你能拿到的时间延迟;全,指的是覆盖的新闻源数量和事件类型的广度;净,指的是数据的结构化程度和噪声水平。
传统的财经数据终端(比如Refinitiv、Bloomberg等)在“净”上最有优势,它们提供的是已经整理好的结构化新闻和标签,字段清晰、历史完整,非常适合做回测研究。但缺点是贵,而且“快”的优势不一定明显——有些终端的新闻推送是轮询或批量更新的,并不是真正的事件驱动推送。如果你做的是日内级别的新闻策略,这种延迟是不可接受的。
网络爬虫自建数据源在“快”和“全”上可以做到极致——你可以在新闻发布的毫秒级时间内抓到它,可以覆盖几乎所有你关注的媒体源和公告源。但“净”就完全依赖你的工程能力了。爬虫抓下来的HTML里充满广告、推荐位、相关阅读等噪声内容,需要一层层清洗才能变成可用的文本。此外,爬虫的稳定性维护也是一个持续投入的坑——目标网站的页面结构一变,你的解析器就可能要重写。
还有一类介于两者之间的数据服务商,它们提供经过清洗、标记了发布时间和关联公司的半结构化新闻流,价格远低于传统终端,又省去了自建爬虫的维护成本。对于大多数团队来说,我认为这是性价比较高的起点。如果你一开始就自建爬虫,会很轻易地陷入“每天都在修解析器”的泥潭,反而没有精力去打磨核心的策略逻辑。
我的建议是:起步阶段先买一家靠谱的新闻API,把策略逻辑跑通;等确认这条路径能产出稳定Alpha后,再逐步叠加自建爬虫来扩充覆盖面和降低延迟。别一上来就搞“全自建”,那是一个工程无底洞。
2.2 文本清洗与去重的关键细节
拿到原始新闻数据后,第一道工序是清洗。这个环节的技术含量看起来不高,但细节决定成败。
先说噪声去除。网页正文里常见的噪声包括:导航栏文字、页脚信息、推荐阅读标题、图片alt文本、广告追踪代码等。用经验规则就能过滤掉大部分——比如去除所有HTML标签后,再按文本长度、标点密度等特征筛掉明显不是正文的段落。复杂的部分在于识别“正文的一部分但信息量为零”的句子,比如“点击了解更多”“本文来源:某某财经”这类文字,需要在清洗规则里不断迭代补充。
再说去重。同一事件往往被多家媒体报道,文本相近但不完全相同。如果不去重,同一条新闻在信号聚合时会被重复计数,相当于放大了这个事件的权重,造成信号失真。常用的去重方案有两种:一种是基于MinHash或SimHash的文本相似度去重,设定一个相似度阈值,超过阈值就只保留最早的源;另一种是更粗暴的“标题精确匹配 + 发布时间窗口”规则,同一标题在同一小时窗口内只保留一条。前者适合大规模处理,后者适合快速起步。我做项目时一般先用SimHash粗筛,再用规则兜底,误杀率可以控制在可接受范围内。
还需要特别处理一类数据:定期发布的例行新闻。比如公司每个月都发布的经营数据、行业每个季度发布的报告等。这类新闻里偶尔会藏着真正的Alpha(比如经营数据大幅超预期),但因为它们与大量“内容正常、无新信息”的例行公告混在一起,很容易被模型当噪声忽略掉。一个可行的处理方式是单独建一个“例行公告日历”,对到点发布的公告做专门的同比或环比偏离检测,而不是和普通新闻混在一起跑同一套分析流程。
2.3 实体映射:从新闻文本到可交易主体
新闻Alpha处理中有一个看似简单但经常翻车的环节:把新闻中提到的公司,准确映射到你可交易的主体上。这步错了,后面全白搭。
首先是公司名称歧义问题。比如“苹果”既可能是Apple Inc.,也可能是水果;但如果在财经新闻语境下,通常指前者。再比如“华住酒店集团”在新闻里可能被写为“华住”、“华住集团”、“华住酒店”、“H World”。你需要一个别名表,把所有这些指称映射到统一的主体ID上。“Brooklyn”这种名字看起来是个地点,但如果你交易的是对应的专业产品品牌(Brooklyn品牌归属于某上市公司),就需要额外的知识库来辅助判断。
其次是母公司关系。新闻里提到的品牌或子公司,往往不是直接的可交易标的,而是隶属于某家上市公司。比如某个知名子品牌出现食品安全问题,直接影响的是其母公司的股价。所以你需要维护一个动态的“公司关系图谱”,包含了公司与其旗下品牌、子公司、关联方的关系。这个图谱不是静态的——并购、分拆、品牌出售都会改变关系——需要持续更新。“雷曼兄弟破产”和“雷曼兄弟旗下某基金清盘”这两条新闻,对可交易主体的指向完全不同,这种粒度上的分辨能力,决定了你的系统是“能用的”还是“好用的”。
最后是市场与品种映射。同一家公司可能在不同市场上市(A股、H股、美股ADR),新闻对不同市场的定价影响方向和幅度可能不同。比如一家公司在A股和港股同时上市,A股市场的消息传到港股可能存在时间差,这个时间差本身又是一个可以开发的Alpha。如果你的系统不做多市场同步映射,就白白丢掉了这块利润。
实体映射的落地工程,通常由两部分组成:离线构建静态知识库,在线进行实体链接解析。静态知识库可以从公司公告、财报、官网等渠道采集;在线解析我常用的是基于规则和词典的匹配为主,模型辅助消歧——因为低延迟场景下,深度学习模型的推理耗时有时不可接受,而且实体链接的badcase很容易通过词典快速修复,比重新训练模型要快得多。
2.4 时间戳陷阱:发布时间、公告时间与交易时间的对齐
时间戳处理是我认为整个新闻Alpha工程里最容易出错、也是最致命的一个环节。我们做量化的人必须建立一条铁律:在处理新闻数据时,永远区分“事件真实发生时间”和“数据系统收到时间”。这两个时间一旦混淆,你的回测就失真了——最典型的表现是未来函数污染,也就是你在回测中用了实盘里当时根本来不及收到的信息,结果收益曲线漂亮得不像话,实盘一跑就现出原形。
以财报新闻为例,“财报实际发布时间”是精确到秒的,交易所和公司官网的公告通常有电子时间戳。但媒体转述新闻的发布时间,可能与财报实际发布之间存在几秒到几分钟的延迟。如果你的回测框架粒度是分钟级甚至秒级,那么用新闻流API的收录时间,可能比公司财报的电子发布时间晚了好几分钟,这几分钟之内价格已经在动了。回测时按API收录时间触发信号,你实际上用了“已经反映了一部分信息的价格”来成交——看起来你是追上了收益,其实是在用未来数据骗自己。
解决这个问题没有银弹,只能从数据源头去卡。最好的时间字段是公司在监管指定平台发布的原始公告时间,其次是交易所官方数据的时间戳,最后才是新闻媒体页面上的时间戳。一个在实践中比较可靠的折中方案是:拿公司财报发布的历史时刻分布作为先验,如果一条财报新闻的媒体发布时间与预期的财报发布时刻明显不符(比如财报通常盘后发,忽然盘中跳出一条疑似财报新闻),就对这条数据的可靠性提高警惕,在信号生成时降权或丢弃。
还有一层是对齐交易时间。新闻是7x24小时发生的,但交易时间是有限的。凌晨三点发布的重要新闻,对当天开盘价的影响需要在开盘前的集合竞价阶段就纳入考虑;而收盘后发布的财报,影响的是次日的开盘。所以你需要把新闻时间轴映射到交易时间轴上:盘中新闻按分钟对齐,盘后新闻全部归集到下一个交易日的开盘信号,在这之间发生的所有新闻,还要做“信息优先级聚合”——一夜之间可能有多条新闻,不可能每一条都独立触发信号,需要聚合出一个综合的隔夜情绪方向。
3. 信号构建:从文本到可交易信号的关键一跃
数据处理完成后,核心挑战就变成了:如何从已经清洗好的文本中,构建出有预测力的交易信号。
这一章会从文本特征的提取方法讲起,再讨论事件类型和标签体系的设计、如何从模型输出映射到持仓方向和仓位,最后把信号聚合到组合层面的方法做一个完整的推演。这里面既有传统的金融文本处理方法,也有近年来才趋于成熟的NLP模型应用,还会有一些我习惯用的业务规则兜底。四者结合才是我认为在工程上最抗造的方案。
3.1 文本特征提取:从词袋到大模型的分层路线
金融文本的特征提取,业界大致走了三个阶段,每个阶段的适用场景和成本都不同。理解这三条路的适用边界,比盲目追新更重要。
早期的经典路线是词典法。预先维护一组正负面词汇表,统计新闻文本里正面词和负面词的出现次数,形成一个简单的情感打分。Loughran-McDonald词典是金融领域用得最多的公开词典,它专门针对财报文本中的情感词做了优化,把“risk”“uncertainty”这类在金融语境里中性偏负面的词做了单独标注。词典法的优点是快、可解释性强、几乎不需要训练样本;缺点是过于粗糙——它完全不管语法结构和上下文,“业绩不及预期但好于担心”这种转折句在词典法下很容易被打成正向。
第二条路线是传统机器学习加人工特征,比如用TF-IDF向量或词嵌入表示文本,再训练一个分类器来判断这条新闻属于正方向还是负方向。这个方案比词典法更灵活,但需要一套可靠的训练标签,标签从哪儿来是新的瓶颈。
第三条路线就是近年来大家听得比较多的预训练语言模型。用金融语料微调过的模型(比如FinBERT这类),相比前两条路线的优势在于它能理解上下文,能处理转折、双关、指代等复杂语言现象。我实测在财报电话会议记录这类长文本、口语化内容较多的场景下,大模型对情感方向的判断准确率比词典法能高出不少,尤其在“明褒暗贬”“表面中性实则重大利空”这类高级语义场景上,捕捉能力是降维打击。
但在实战项目里,我的建议是分层使用,而不是全家追大模型。用词典法作为第一道快速筛选,能在毫秒级过滤掉大量明显无关的新闻;再对筛选后的事件型新闻上模型做深度判断。这样既控制了整体计算成本,又保证了判断质量。L2层都用最重的模型跑一遍,在时间敏感的策略里基本跑不动。
3.2 事件类型与标签体系设计
新闻Alpha与通用情绪分析最大的不同在于:它不满足于一个简单的“利好/利空”方向,而是要回答谁、发生了什么、影响有多大。所以在我的系统里,第一层标签是“事件类型”。
事件类型体系设计的核心原则是:足够覆盖你交易的策略,但不冗余到模型学不过来。一套典型的财经事件类型体系可能包含这些粗分类:
- 业绩类:财报发布、业绩预告、业绩修正、审计意见变更
- 经营类:重大合同签订、产品获批/上市、产线投产、销售数据发布
- 资本类:并购重组、定增、股份回购、股东增减持
- 治理类:高管变更、股权纠纷、股东会决议、分红方案
- 合规类:行政处罚、监管问询、诉讼仲裁、立案调查
- 行业类:政策变化、行业标准发布、上下游价格波动、技术突破
每个大事件类别下再细分出子事件,子事件才有相对明确的方向和影响定义。比如“并购重组”这个事件类别下面,要区分是“上市公司收购标的”还是“上市公司被收购”,两种情况的股价含义截然不同。
第二层标签是事件方向。方向不总是简单的利好利空,有时需要三分类甚至五分类。以“股东减持”为例,大股东减持通常被解读为利空,但如果减持方是创投机构、而减持比例很小,市场可能完全不反应甚至反向解读。所以事件标签方向上,我总是建议多做一档“中性/待观察”,让模型学会在信息不足时不乱下注。把不确定的事件硬归到多头或空头,往往是新手最容易犯的错误。
第三层标签是事件主体。这里包含了我在2.3节里说的实体映射结果、事件涉及的市场、行业归属等。标签体系的最终形态,是让一条新闻变成类似这样的结构化记录:
{ "entity_id": "600519.SH", "event_type": "earnings_surprise", "direction": "positive", "magnitude": 0.032, "event_time": "2025-04-28 15:32:00", "confidence": 0.87, "raw_text_md5": "..." }这样一条记录就可以设计为一个可直接参与信号计算的输入。也只有把文本“翻译”成结构化的标签,后续的策略计算才谈得上可复用和可回测。
3.3 从模型输出到持仓:方向映射与仓位换算
有了事件类型和方向标签后,下一步就是要把它们换算成具体的信号强度和持仓权重。这一步是连接“机器学习”与“投资组合管理”两个世界的桥梁,容易被两边都忽略。
方向映射的核心是定义事件类型到多空方向的基准表。比如在我的系统里,初始基准表大致是这样:
| 事件类型 | 子事件示例 | 基准方向 | 基准影响强度 |
|---|---|---|---|
| 业绩类 | 实际EPS超预期 | 多头 | 取决于超预期幅度与历史分布 |
| 业绩类 | 业绩暴雷/亏损扩大 | 空头 | 同上 |
| 资本类 | 大股东增持 | 多头 | 中 |
| 资本类 | 大股东清仓式减持 | 空头 | 中高 |
| 治理类 | 核心高管离职 | 空头 | 中低 |
| 合规类 | 立案调查 | 空头 | 高 |
基准表给出的是先验方向,模型输出的置信度用来做修正。比如模型判定这条新闻为正向的概率是0.65,基准方向也是多头,那么最终信号就可以以0.65作为加权系数。如果模型判定与基准方向相反——这件事往往意味深长,比如“业绩下滑但公司宣布大额回购”,这时候就需要更谨慎地评估,可能是模型被文本里的积极措辞干扰了。
仓位换算的核心原则是风险平价。同样强度的利好事件,波动率低的股票可以多给仓位,波动率高的股票必须减仓。具体计算公式可以为:
[ w_i = \frac{s_i}{\sigma_i} \times \frac{b}{\sum_{j=1}^{n} \frac{s_j}{\sigma_j}} ]
其中(s_i)是事件信号强度(已归一化到0到1之间),(\sigma_i)是股票的预期波动率(可以是历史波动率或隐含波动率),(b)是本策略分配的总风险预算。这个公式的本质,是把事件强度按波动率倒数加权分配到各标的上,让每个信号对组合的风险贡献大致相等。
这里需要特别注意的是:新闻信号是稀疏的、脉冲式的,如果完全按公式实时调仓,会造成很高的换手,你需要给仓位变化设置一个最小阈值和最大持仓数量限制。比如单只股票权重不得低于1%否则不持仓、单日调仓不超过20%仓位等。这些约束都需要放在实盘约束的框架下统一考量。
3.4 信号聚合与蒸馏:把脉冲变成稳定的组合信号
单条新闻的信号是脉冲式的——它只在一个瞬间触发。但组合管理需要的是连续、稳定的信号输入。它们之间需要一个“信号聚合与蒸馏”的过程。
第一步是横截面聚合:同一时刻多个标的有多个新闻信号,有些信号之间存在联动,需要合并。比如“美联储宣布加息”这种宏观新闻,会影响你持仓池里的所有标的,你不能让每个标的都单独对该新闻反应一次——这时需要把宏观新闻信号变成一个组合层面的风险开关(risk-on/risk-off),而不是个股的独立信号。
第二步是时间维度的聚合:一个标的在短时间内连续出现多条同向新闻,需要把它们的信号强度累加,但不能让它无限膨胀。我通常用带衰减的累积方式——信号值按小时或按交易日指数衰减:
[ S_t = \sum_{k=1}^{K} s_k \cdot \exp\left(-\lambda \cdot (t - t_k)\right) ]
其中(\lambda)是衰减系数,(t)是当前时间,(t_k)是第k条新闻的时间。选择(\lambda)时,需要与目标持仓周期匹配。如果是日内策略,(\lambda)要取到让信号在几个小时到一天内衰减到接近零的程度;如果是持仓几天的策略,可以让信号在2到3个交易日内缓慢衰减。设定衰减系数时,一个经验性的参考做法是:先算出历史新闻事件发生后价格漂移持续的平均时间,再把衰减半衰期设为该持续时间的一半。这比盲目拍脑袋选数更贴合实际市场行为。
第三步是信号的方向校验。聚合完成后,我会对每一个组合信号做一个额外检查:信号方向是否与近期价格趋势方向相反?如果相反,要重新审视。比如某公司发布了一个看似利好的公告,但股价却持续下跌,这通常说明市场对这条公告另有解读,或者有利空因素被公告的表面措辞掩盖了。这种“模型看多、市场走空”的分歧,本身信息量极大。我不太建议硬着头皮按模型方向开仓,更稳妥的处理是把它当作一个“不参与”的信号,或降低仓位,直到市场用价格给出更清晰的答案。
4. 实操过程:搭建一套可落地的新闻Alpha流水线
前面几节讲的是思路和原理,这节落到实处,我会以一个简化但完整的示例为主线,完整跑一遍新闻Alpha的信号生产流程。示例用的是类似新闻流的模拟输入,重点讲清楚从原始数据到最终信号的每一步是做什么的、为什么要这么做。
4.1 整体架构与模块职责划分
一个生产级别的新闻Alpha系统,大致包含以下几个模块:新闻接入层、清洗与解析层、实体链接层、事件识别层、信号计算层、策略决策层。下面我用一个表格来说明每个模块的核心职责和输入输出。
| 模块 | 核心职责 | 输入 | 输出 |
|---|---|---|---|
| 新闻接入层 | 从多个数据源拉取新闻流,统一格式 | 原始新闻API响应 | 标准化JSON |
| 清洗与解析层 | 去HTML,去重,抽正文,提取发布时间 | 标准化JSON | 纯文本新闻(带元信息) |
| 实体链接层 | 识别新闻涉及的公司并映射到标的ID | 纯文本新闻 + 知识库 | 新闻-标的关联对 |
| 事件识别层 | 判断新闻包含的事件类型、方向、强度 | 新闻-标的关联对 | 结构化事件记录 |
| 信号计算层 | 计算单条新闻信号、聚合衰减 | 结构化事件记录 | 连续信号序列 |
| 策略决策层 | 结合仓位约束生成最终交易列表 | 信号序列 + 持仓约束 | 订单指令 |
数据在模块间流转时,最好使用统一的数据格式(比如JSON或Parquet),不要把Python对象直接传递,否则后续扩展和维护会非常被动。命名实体本身也有讲究,通常我建议用公司ID统一命名,如600519.SH、AAPL.O等。
4.2 核心代码实现:从新闻到信号的关键流程
各模块的代码实现细节差异很大,这里我给出最核心的一段——清洗后的结构化新闻如何经过事件识别、信号计算、衰减聚合成最终信号。假设已经完成了实体链接:
import pandas as pd import numpy as np # 假设每条news已经过清洗、实体链接,得到如下结构 # news_list = [ # { # "entity_id": "600519.SH", # "event_type": "earnings_surprise", # "direction": 1, # 1=多头, -1=空头, 0=中性 # "magnitude": 0.032, # 事件强度 # "confidence": 0.87, # 模型置信度 # "event_time": pd.Timestamp("2025-04-28 15:32:00"), # }, # ... # ] def calculate_signal_single(news_item, base_strength_map): """ 基于结构化新闻计算单条信号强度。 base_strength_map: 事件类型到基准强度的映射 """ event_type = news_item["event_type"] base = base_strength_map.get(event_type, 0.5) # 最终信号 = 方向 * 基准强度 * 幅度因子 * 置信度 magnitude_factor = 1.0 + min(news_item.get("magnitude", 0.0) * 10, 3.0) signal = ( news_item["direction"] * base * magnitude_factor * news_item.get("confidence", 0.5) ) return signal def aggregate_signals(news_list, lambda_decay=0.25, now=None): """ 对一段时间内的新闻信号做时间衰减聚合。 lambda_decay: 衰减系数,取值越大信号衰减越快 """ if now is None: now = pd.Timestamp.utcnow() signal_by_entity = {} for item in news_list: entity_id = item["entity_id"] signal = calculate_signal_single(item, item.get("base_strength_map", {})) time_diff_hours = (now - item["event_time"]).total_seconds() / 3600.0 if time_diff_hours < 0: # 未来时间戳,直接丢弃或告警,防止未来函数 continue decay_weight = np.exp(-lambda_decay * time_diff_hours) signal_by_entity[entity_id] = signal_by_entity.get(entity_id, 0.0) + signal * decay_weight # 归一化到 [-1, 1] 区间,方便后续仓位换算 max_abs = max([abs(v) for v in signal_by_entity.values()], default=1.0) return {k: v / max_abs for k, v in signal_by_entity.items()} # 用法示例 news_list = [ { "entity_id": "600519.SH", "event_type": "earnings_surprise", "direction": 1, "magnitude": 0.032, "confidence": 0.87, "event_time": pd.Timestamp("2025-04-28 15:32:00"), "base_strength_map": {"earnings_surprise": 0.8}, }, # 其他新闻... ] signals = aggregate_signals(news_list, lambda_decay=0.2) print(signals)这段代码最需要注意的就是时间戳的越界处理——如果数据的时间戳晚于当前时间,必须直接丢弃并告警,这是防止未来函数最重要的防线。另一个需要注意的点是归一化,我们把它放在聚合完成后进行,因为衰减计算用的是绝对值——如果先归一化再衰减,不同时间进来的信号量纲不一致,后面累加的结果就会失真。
4.3 模型训练集构建与标签生成策略
事件识别是整个流程里最依赖机器学习的部分,它的训练集和标签从哪来,是实践中最容易被卡住的一环。
构建训练集的黄金标准在于利用“市场反应”来代替人工打标。我用的方法是:先取一批历史新闻,以新闻发布时间为T,统计T到T+1小时、T+1日、T+3日三个窗口的收益率,再用这些收益率超出基准(如大盘指数)的部分,给新闻打上“正向/负向/中性”的弱标签。窗口越长,标签越可靠,但混入的干扰因素也越多;窗口太短,噪声又太大。
这里要强调的是,这件事的思路和“预测情绪”不同——预测情绪是主观任务,判断“这条新闻是正面还是负面”有正确答案;而用市场反应打标是客观任务,它贴合的是“这条新闻能不能带来Alpha”这个终极目标。两者在部分案例上结果不同很正常,比如“业绩大增但股价暴跌”的新闻,情绪上正面,市场标签则是负面。你会需要根据策略本身的定位来选择标签口径——如果是做情绪反转策略,用主观情绪标签;如果是做事件驱动,用市场反应标签更贴切。
实测下来,纯用市场反应打标会产生不少噪声标签。比如财报超预期的好新闻,恰好当天大盘暴跌,股价跟着跌,就会被误标为负面。缓解方法有两种:一是用超额收益而不是绝对收益来打标,二是对多次出现矛盾标注的同类型事件做人工复核,并适当修正。经过这两层处理后,标签质量会明显改善,模型训练效果也更稳健。
标签不平衡则是另一个常见问题。负面新闻天然比正面新闻更容易被市场放大反应,比如“立案调查”这类事件,价格的下跌幅度和持久性往往比同等强度的利好消息更强。针对这一点,我在训练时会做类别权重的调整,或者在采样时对少数类别做上采样,避免模型偏向多数类导致漏掉稀有的强空头事件。
4.4 参数选择与衰减半衰期的经验取值
衰减半衰期对新闻Alpha策略的效果影响很大。它本质上决定了你的系统对新闻事件的记忆有多长。半衰期太短,信号在信息还没完全充分定价时就归零了,等于浪费了已有的信息优势;半衰期太长,信号拖泥带水,会在价格已经到位后还让你持续持仓,这时你持有的不再是alpha,而是beta甚至是负alpha。
实操中怎么选?我的经验是把锚点放在“你交易频率”上。如果你做的是日内交易,新闻信号的时效窗口通常只有几个小时,半衰期设在2到4小时比较合适;如果是日频调仓的策略,半衰期可以放到1到2个交易日;如果是周频,考虑3到5个交易日。具体取值可以在回测里做一个简单的参数扫描,再结合价差分析的结果来确定。
但这里有一个隐蔽的坑:衰减系数如果是在回测数据上扫描出来的最优值,实盘里往往会过度拟合。新闻Alpha的信号衰减规律会随市场参与者的结构变化而变化——当一个事件类型越来越多人用机器跟踪时,它的有效半衰期就会越来越短。所以我的习惯是:不追求用参数扫描找出历史最优半衰期,而是根据最近3到6个月的样本估计一个偏保守的值,且在实盘中每季度复核一次,有条件就做滚动重估。
有一个相对可靠的替代方法:直接测量“新闻事件发生后,价格漂移持续的时间分布”。对历史上已发生的同类型新闻事件,画出事件后平均累计超额收益曲线,观察它斜率拐点出现在哪里,那个拐点时间就是当前市场对该类信息定价的主要完成时点。以此为基础设置半衰期,比纯回测扫描的结果稳健得多。这条经验来自我踩过多次坑后的总结——用回归方法直接扫描得到的最优衰减参数,实盘效果往往被证明是一场过拟合的幻觉。
5. 回测与评估:如何验证一个新闻Alpha真的有效
新闻Alpha的回测,是所有回测里最容易自欺欺人的一种。原因在于:它的数据天然带有时序不确定性、事件稀疏性和语义复杂性。很多人拿一个看似不错的新闻Alpha收益曲线过来问我,我第一句话就会问:你的回测里,从“事件发生”到“你实际下单”的时间差是多少?九成的人答不上来。
5.1 事件研究法:新闻Alpha的标准评估方式
新闻Alpha回测和常规因子回测最大的区别是:常规因子的信号每个交易日都在变化,可以用连续的时间序列回测;而新闻Alpha的信号在大部分时间是零,只有在事件发生时才有值。如果按连续回测去算年化收益和夏普比率,会因为大量无信号的交易日把结果稀释得很平淡。
业界通常采用事件研究法(event study)来评估新闻Alpha的效果。核心做法是:把所有历史事件按“事件类型”归组,统计每个事件发生后T日内的平均累计超额收益(CAR, cumulative abnormal return)。超额收益指的是个股收益减去基准收益,通常是减去大盘指数或行业指数的收益。如果某类事件在发生后一段时间内CAR显著为正(或负),并且呈现出单调的趋势,那说明这类事件确实有Alpha提取空间。
这里说一个具体例子来帮助理解。假设我们统计了过去三年“业绩预告大超预期”的所有事件,得到它们的CAR走势:事件后第1天平均超额收益+0.8%,第2天+1.1%,第3天+1.2%,第5天+1.3%,第10天+1.2%。这说明市场对该类事件的定价过程横跨了大约2到3天。考虑到第一天的收益可能因为瞬时反应跟不上而难以捕捉,真正留给策略的部分大约是第二天到第三天的0.3到0.4个百分点的窗口。如果还要扣除交易成本,那这个Alpha已经相当薄了——这时就得靠信号强度分层:把“大超预期”和“小幅超预期”分开统计CAR,超额收益会集中在前者。
事件研究法还能顺带帮你解决一个重要问题:一个新闻事件应该持有多少天才能最大化风险调整后的收益。你不需要自己猜,CAR曲线的拐点就是答案。当CAR在某一天后不再增长而是走平或回撤时,那就是这个事件信号的合理离场时间点。用这个时间点去指导持仓周期的设定,比统一用固定持仓天数要合理得多。
5.2 未来函数与延迟假设:回测里最致命的坑
新闻Alpha的回测中,未来函数可能以几种形态出现,而且都相当隐蔽。一种是最常见的“时间戳错位”——我在2.4节中讲过,用新闻数据商的入库时间而非事件真实发布时间来触发信号,会让回测用上当时实际无法获知的信息。处理方案只能在数据源头卡:标注每个事件的权威时间戳(监管公告时间优先),再用该时间戳触发信号。
第二种未来函数藏在新闻文本里。你可能不自觉地用了一篇“回顾性报道”来触发信号。比如某天下午发布了一篇深度报道,里面回顾了一家公司在过去一个月里发生的产品事故和销量下滑,你在回测里把这条报道的发布时间当作事件时间,然后在这个时间点触发了一个空头信号——表面上你是在报道发布时做空并获利了,但实际上这些利空信息早在事故发生的那几天就反应在价格里了,只是你没检测到而已。这种回顾性新闻是新闻回测里的“暗雷”,我的处理方法是:在事件识别层单独标记出“说明/回顾类新闻”,不让它像“突发新闻”那样独立触发信号,只用它来增强已有事件的信息强度。
第三种未来函数是重述文本带来的重复计算。比如某个重大事件发生后,媒体连续两天发布了多条相关报道,每条报道你单独触发了一个信号,等于在实盘里你把这个事件重复交易了好几遍。去除重述文本的一种可行方式是:用文本相似度聚类,聚类内的后续文本不再作为独立信号源,只作为原事件的“信息增强”存在。
延迟假设的坑同样隐蔽。回测里信号发出到价格成交之间,通常你会设定一个固定的延迟(比如1分钟、5分钟或一个K线周期),这个延迟需要覆盖从事件发生、数据到达、模型推理、交易系统下单、订单成交的全链路耗时。很多团队的回测延迟只覆盖了其中一部分,比如只考虑了模型推理时间而忽略了数据推送延迟,结果实盘滑点远超回测预期。我的建议是:把所有环节的延迟逐项列出来,加总后再乘以2作为回测保守延迟,把“意外”也纳进去。
5.3 交易成本与冲击成本:新闻信号最敏感的环节
新闻Alpha这类事件驱动的策略,天然是高换手、短持仓的,所以它对交易成本的敏感度远超低频因子策略。一套回测里如果交易成本设置得不真实,新闻Alpha很容易“账面美丽、实盘亏损”。
我以前做过一个粗略的测算:一个典型的日频新闻Alpha策略,如果年化换手率在60倍左右(平均持仓3天左右),单边交易成本从万2提高到万5,年化超额收益可能要下降4到6个百分点。对很多事件驱动策略来说,这已经足以把正Alpha打成负。
所以回测里的成本假设必须尽可能贴近实盘。具体到每笔交易,你要把这几部分成本都算进去:佣金、印花税/交易费、冲击成本、以及买卖价差。在流动性一般的标的上做事件驱动,冲击成本和大盘股完全不是一个量级。一个务实的方法是对持仓池做一个流动性分层评估,流动性差的标的调低最大信号权重,同时回测时用较高的冲击成本模型。这个细节,往往比你在模型上多做一轮调参更能决定策略的生死。
5.4 新闻Alpha的容量评估与收益衰减判断
做新闻Alpha的人还得面对一个资金层面的现实问题——这个策略能容纳的资金规模是有限的。原因我在1.2节提过一点:当你的买卖行为本身影响了价格,你就会成为那个自己抹平信号的人。
容量评估方法其实不复杂:取策略历史上持仓标的的日均成交额,估算策略在不同资金规模下会占标的日均成交量的比例,结合冲击成本模型推算出不同资金规模下的净收益。一般来说,事件驱动策略要尽量避免超过单标的日均成交量的1%到2%,否则冲击成本会显著侵蚀收益。另一个信号是:当你在回测中发现某些日子的成交价显著偏离信号发出时的价格,或者有大量成交在回测模拟价格之外完成,那就说明策略的有效容量可能已经触顶了。
关于收益衰减,我记得自己在研究美股市场新闻Alpha时就发现,新闻事件发生后股价漂移的幅度,在新浪财经、华尔街见闻这类媒体普及前后有显著差异——当一个信息更快被更多人同步看到,漂移窗口就变短、幅度也变小了。这也是新闻Alpha领域的一个长期矛盾:新的事件类型刚被发现时往往Alpha很厚,随着跟踪的人变多而快速衰减,让你不得不持续地去寻找新的事件源、新的事件类型。这不是一个可以一劳永逸的策略方向。
6. 常见问题与排查技巧
新闻Alpha项目里,有几个我反复遇到的典型问题。它们不一定是模型本身的问题,更多是数据、工程和设计上的坑。这节我会把这些问题、排查思路和最终解决方案整理成速查表,方便你对照检查自己的系统。
6.1 问题速查表
| 现象 | 可能原因 | 排查/解决方案 |
|---|---|---|
| 回测收益很高,实盘完全不同 | 未来函数污染或延迟假设过乐观 | 检查时间戳口径,逐环节核对延迟;保守设置为全链路延迟×2 |
| 同一新闻反复触发信号 | 多源新闻未彻底去重,未过滤回顾性报道 | 用SimHash去重;识别回顾类报道,只增强不单独触发 |
| 信号总是滞后于价格,追高被套 | 事件识别耗时过长;新闻数据源延迟太大 | 优化模型推理效率;体检数据源的实时性,必要时切换 |
| 小盘股新闻信号效果差、滑点大 | 流动性不足,冲击成本吃掉收益 | 缩小小盘股的权重上限,提高流动性过滤门槛 |
| 高换手下收益被成本吞噬 | 信号交易过于频繁,仓位调整阈值过低 | 提高调仓触发阈值;降低衰减半衰期以减少无效交易 |
| 同一事件在不同时期效果差异巨大 | 市场参与者结构变化,事件Alpha衰减 | 对事件类型做分年度的CAR跟踪,及时下线失效事件类型 |
| 新闻文本乱码或解析不完整 | 编码问题或爬虫解析器失效 | 建立异常率监控,乱码率超过阈值即告警;定期巡检解析逻辑 |
| 实体链接匹配到错误的公司 | 别名表缺失或歧义未消解 | 建立公司别名表,重要歧义规则人工维护,大额信号做二次人工复核 |
6.2 实盘案例分析:一次典型的事件信号异常排查
为了让你更直观地理解排查过程,我分享一次真实的排查经历。有段时间,我们系统里某个事件类型的信号表现持续弱于回测——利润贡献从正转负。单独测试模型时各项指标又都正常,百思不得其解,于是我把整个链路跑了一遍日志审计。
逐一排查后发现异常出在数据源接入层。我们当时从两家新闻源做交叉验证,但没注意其中一家通道在特定时段存在持续积压,导致它推送的新闻时间戳几乎都比另一家晚若干分钟。结果在信号聚合时,同一事件被当成两条“独立新闻”先后触发,后一条实际上是同一条新闻的迟到版本。
这造成了两个问题:同一事件被重复计算了权重,而且延迟版本触发后,系统是在信息已经被市场消化后才开的仓,结果必然不佳。定位到根因后,我们在聚合层加了跨源去重逻辑:如果在短时间窗口内收到多条相似文本且指向同一实体,就只取最早的一条;同时给每个接入源增加了延迟监控,超过设定阈值就自动降级或告警。
这次排查带给我的启发是:新闻Alpha的bug往往隐藏在“你觉得不会出问题的地方”。数据源不会永远稳定,文本里总有意外情况,你必须靠监控和日志把不确定性兜住。
6.3 文本噪声过滤与异常检测技巧
新闻文本里的噪声除了广告和HTML标签之外,还有几类比较隐蔽的干扰。一类是“标题党”式的夸张措辞,模型很容易被这类措辞带偏。比如一篇“震惊!某公司业绩暴雷,股价或将腰斩”的报道,真实信息可能只是“某公司某季度净利润同比下滑5%”,模型如果被标题牵着走,信号强度就会被不成比例地放大。一个务实的缓解方案是:标题和正文分开处理,标题权重设低一些,正文里可验证的定量描述(具体百分比、具体金额)给更高权重——毕竟定量的数字才是市场定价的真正锚点。
另一类干扰来自“旧闻翻新”。有些媒体会把几年前发生的事件换个角度重新包装成新闻。系统如果只看发布时间而不校验事件时效性,就会把这些过期信息当成新事件来交易。处理方法是建立“事件指纹库”——对已经触发过信号的核心事件(公司+事件类型+关键数字)做记录,如果在后续文本中检测到相同指纹,就把它标记为旧闻增强,而不是新信号。
各类异常文本也需要持续监控。比如财报数据被写错小数位、公司名简称相似导致实体误匹配等,需要靠规则+人工抽检来兜底。新闻Alpha这个领域,模型可以不够炫酷,但清洗规则库和知识库的迭代绝对不能停——它们才是系统稳定性的基石。
6.4 持续迭代机制:新闻Alpha系统的“保鲜期”管理
新闻Alpha系统上线只是开始。因为市场参与者结构在变、事件源在变、交易执行方式也在变,新闻信号的生命周期通常比传统因子更短。所以我个人体会中极其重要的一件事是:建立一个闭环迭代流程,保障系统“保鲜”。
具体来说,我每个季度会做这样一轮复盘:看各个事件类型的CAR统计有没有明显衰减,看事件识别模型在最近一个季度的预测准确率有没有下降,检查实体知识库是否有需要更新的公司关系变化。如果某些事件类型的CAR已经不再显著,就果断把它们从策略池里降权或去掉;如果新出现的事件类型在初步统计中表现不错,就设一个小仓位进行样本外观察。
同时,我还养成了一个习惯:定期做“新闻源体检”。每隔一段时间抽查各数据源的推送延迟、内容完整度、异常率,把质量下降的源降级并寻找替代。数据源质量的变化是渐进的,不刻意检查很难发现。
这个持续迭代机制本身,已经把做新闻Alpha的定位清晰化了:它不是“训练一个模型、上线、躺着收钱”的领域,而是“持续经营一套信息处理系统”的活。
7. 写在最后的实践经验小结
做新闻Alpha这几年,我最大的一个认知变化是从“追求复杂的模型”转向“打磨可靠的基础设施”。一次让我印象深刻的经历是:模型从FinBERT换成更大的模型后,单条新闻的情绪判断准确率确实提升了几个点,但整个策略的收益并没有显著变化。后来复盘才发现,收益的主要贡献从来不是单个模型对单条新闻判断得多准,而是整个链条上的细节叠加——数据够不够快、事件识别够不够准、衰减设计得够不够贴切、交易成本有没有控制住。
在对新闻Alpha的效果评估上,我通常给自己留一道验算题:把策略单拿出来,跟一个最朴素的基线比较——每当有突发事件,就简单按“利好做多、利空做空”买入持有三天的收益率。如果我的系统连这种不用模型、不用复杂规则的笨办法都跑不赢,那我应该先审视系统本身,而不是往模型上加更多参数。这道验算看起来粗糙,却帮我推翻了不止一个看起来逻辑自洽的方案。
最后,我想单独给正在考虑入场的团队一个建议:新闻Alpha不太适合当作第一个量化策略来做。它需要稳定低延迟的数据、成熟的事件研究框架、足够细颗粒度的回测系统、以及能把清洗规则持续打磨的执行力。如果你已经有传统的因子策略在跑,把它当作组合里的卫星策略来增强,比让它独挑大梁要稳妥得多。反过来,如果你已经跑通了新闻Alpha并积累了一手数据,你会发现这套能力对情绪Alpha的构建也有巨大帮助——毕竟情绪本身也是新闻和舆情作用的结果。这一章讲的新闻Alpha,正好能和整体系列里的其他内容衔接上,我们下一章见。