Vibe-Trading 事件驱动策略实战指南:从情感打分到信号聚合的完整实现
2026/9/10 4:38:52 网站建设 项目流程

Vibe-Trading 事件驱动策略实战指南:从情感打分到信号聚合的完整实现

【免费下载链接】Vibe-Trading"Vibe-Trading: Your Personal Trading Agent"项目地址: https://gitcode.com/GitHub_Trending/vi/Vibe-Trading

事件驱动(Event-Driven)是 Vibe-Trading 中一类以新闻、公告与宏观事件为数据源、由 LLM 充当 NLP 引擎的策略形态。本文将完整拆解仓库内agent/src/skills/event-driven/SKILL.md所定义的工作流、事件 CSV 数据规范、时间衰减与信号加权算法,并结合 示例信号引擎 与 RSSHub 事件提供器 的源码实现,为你呈现一条「数据采集 → LLM 打分 → CSV 落盘 → 信号聚合 → 回测接入」的端到端落地路径,读完即可在自己的策略中复现。

一、技能定位与整体架构

agent/src/skills/event-driven/SKILL.md的元信息将该技能归类为category: strategy,其核心思想是:把 LLM 当作 NLP 引擎来打分新闻事件,事件数据统一管理为 CSV,再将技术信号与事件信号做加权聚合,得到最终交易信号。

该文档强调一条贯穿全流程的关键原则:

事件 CSV 是数据层,signal_engine.py是逻辑层,两者必须保持解耦。

这一分层设计在仓库源码中得到了印证:事件侧的数据层由 rsshub_events.py 承担(负责抓取、归一化、打分、落列),逻辑层则由策略开发者自行实现的signal_engine类承担(文档同目录提供了完整范本 example_signal_engine.py)。数据层不关心策略逻辑,逻辑层不关心数据来源,二者通过统一的event_score列衔接。

二、四步工作流

文档定义的标准工作流如下:

  1. 数据采集:使用read_url工具抓取新闻与公告全文;
  2. LLM 分析:LLM 阅读新闻,用标准化提示词在-1.01.0区间打分(极度看空到极度看多);
  3. 生成事件 CSV:按date,event_type,score,source,summary五列 Schema 写入数据;
  4. 信号聚合signal_engine.py读取事件 CSV,施加时间衰减,并与技术信号合并。

其中read_url是 Agent 内置工具,其实现位于 web_reader_tool.py:它通过 Jina Reader(r.jina.ai)把目标 URL 转为 Markdown 文本,内置 30 秒超时、8000 字符截断,并对目标地址做了严格的安全过滤(拒绝localhost、私网 IP、带凭据的 URL 等),返回结果包含titlecontenturl字段。也就是说,Agent 抓取到的是已经清洗过的正文,可直接交给 LLM 打分,无需额外做网页解析。

三、事件 CSV Schema 与字段语义

事件数据统一落盘为 CSV,文档给出了可直接复制的示例:

date,event_type,score,source,summary 2024-01-15,earnings,0.8,read_url,Q4 revenue beat expectations by 30% 2024-01-20,macro,-0.5,read_url,Central bank raised rates by 25bp 2024-02-01,policy,0.3,read_url,New-energy subsidies extended 2024-02-10,sentiment,-0.7,read_url,Bearish sentiment surged on social media 2024-03-05,insider,0.4,read_url,CEO bought 5 million shares

五个字段的语义如下:

字段类型说明
datestr(YYYY-MM-DD事件变得可知的日期(发布时间,而非发生时间;若收盘后发布则顺延到下一交易日)
event_typestrearnings / macro / policy / sentiment / insider / technical_break
scorefloat-1.0 ~ 1.0(标准化 LLM 打分)
sourcestr数据源标签(如read_url
summarystr事件摘要(一句话,不要包含逗号

关于date的「可知日期」约定,仓库级实现给出了严格的落地方案:在 rsshub_events.py 中定义了收盘截断小时DEFAULT_CLOSE_CUTOFF_HOUR = 16_knowable_date()函数(见第 264-278 行)会把当日 16 点及以后发布的条目滚动到下一个自然日,与技能文档「收盘后发布 → 使用下一交易日」的规则完全对齐。这正是回测避免未来函数(look-ahead bias)的第一道闸门。

四、事件类型体系与影响周期

文档按事件类型规定了各自的影响周期,这决定了时间衰减参数的调优方向:

类型含义典型影响持续时间
earnings财报发布短期冲击1-5 天
macro宏观数据 / 央行政策中期影响5-20 天
policy行业政策 / 监管变化长期影响20-60 天
sentiment市场情绪 / 舆情短期冲击1-3 天
insider内部交易 / 大宗交易中期信号5-10 天
technical_break关键技术位突破短期催化剂1-5 天

从实现细节看,这一事件分类法也被 FeedSpec 数据结构继承——每个 RSSHub 订阅源在注册时必须声明自己产出的事件类型(event_type),从而在数据源头就完成事件分类,而非在策略层事后打标。

五、信号聚合:时间衰减与加权组合

5.1 事件信号的时间衰减

事件对价格的影响随天数呈指数衰减。文档给出的核心算法如下:

import numpy as np import pandas as pd def compute_event_signal(event_df: pd.DataFrame, dates: pd.DatetimeIndex, decay_lambda: float = 0.1, min_score_threshold: float = 0.2, event_lookback: int = 30) -> pd.Series: """Compute an event-driven signal with time decay.""" event_df = event_df[event_df["score"].abs() >= min_score_threshold].copy() event_df["date"] = pd.to_datetime(event_df["date"]) signal = pd.Series(0.0, index=dates) for trade_date in dates: # Only consider events published on or before trade_date (avoid look-ahead) mask = (event_df["date"] <= trade_date) & \ (event_df["date"] >= trade_date - pd.Timedelta(days=event_lookback)) relevant = event_df[mask] if relevant.empty: continue days_since = (trade_date - relevant["date"]).dt.days.values scores = relevant["score"].values # Exponential decay: score * exp(-lambda * days) decayed = scores * np.exp(-decay_lambda * days_since) # Sum multiple events and clip to [-1, 1] signal[trade_date] = np.clip(decayed.sum(), -1.0, 1.0) return signal

算法的三个要点:

  • 防未来函数:只取date <= trade_date的事件,保证任一交易日只能看到当日及之前已知的事件;
  • 回看窗口event_lookback = 30天之外的事件直接排除,避免陈旧事件长期滞留;
  • 阈值过滤|score| < min_score_threshold的事件先被剔除,只保留有实质信息量的条目;
  • 多事件叠加:窗口内多个事件做衰减后求和,再clip[-1.0, 1.0]

值得注意的是,这套「衰减求和 + 窗口 + 截断」公式在仓库生产级实现 enrich_price_frames_with_events 中得到了向量化复刻:它为每根 bar 计算event_score(衰减求和、clip 到[-1,1])与event_count(窗口内事件数)两个附加列,直接用 NumPy 的 datetime64 与np.exp完成逐 bar 计算,逻辑与技能文档完全一致。

5.2 技术信号与事件信号的加权融合

最终交易信号由技术信号与事件信号按权重合成:

def combine_signals(tech_signal: pd.Series, event_signal: pd.Series, alpha: float = 0.6) -> pd.Series: """Combine technical and event signals with weights.""" combined = alpha * tech_signal + (1 - alpha) * event_signal return combined.clip(-1.0, 1.0)

默认alpha = 0.6:技术信号占 60%,事件信号占 40%。当没有事件时event_signal = 0,组合信号退化为纯技术信号,这是设计上的刻意行为——事件驱动是增强层,而非主策略

六、可调参数速查

文档给出的参数表及默认值如下:

参数默认值说明
alpha0.6技术信号权重(1-alpha为事件权重)
decay_lambda0.1衰减系数(越大衰减越快;0.1≈ 10 天衰减到 37%)
event_lookback30事件回看窗口(天),更早的事件被排除
min_score_threshold0.2最低分数阈值,|score|低于此值的事件被忽略

这些默认值同样体现在生产实现中:enrich_price_frames_with_events 的decay_lambda=0.1lookback=30min_abs_score=0.0与技能默认保持对齐(min_abs_score在技能侧为 0.2,属于文档中「策略层过滤」与「数据层过滤」的粒度差异——数据层默认不丢事件,把阈值判断留给策略)。

七、LLM 打分提示词模板

为保证打分跨时间、跨模型版本的一致性,文档规定抓取新闻后必须使用以下标准化提示词:

You are a financial event analyst. Read the following news / announcement and score its impact on the stock price. Scoring scale: - 1.0: extremely bullish (for example, earnings far above expectations, major favorable policy) - 0.5: moderately bullish (for example, earnings slightly above expectations, favorable industry news) - 0.2: mildly bullish - 0.0: neutral (no obvious impact) - -0.2: mildly bearish - -0.5: moderately bearish (for example, earnings below expectations, tighter industry regulation) - -1.0: extremely bearish (for example, accounting fraud, major violations, black-swan event) Score strictly on the scale above. Output one number only. Do not explain. News content: {news_content} Score:

模板的关键约束是「只输出一个数字、不做解释」,从而让打分结果可以机械化地解析进 CSV 的score列。值得注意的是,仓库在数据层还内置了一套确定性的词典打分器作为无需 LLM 的兜底基线——default_lexicon_scorer 通过统计标题与摘要中正负面词条(如 beat/beat、surge、record、growth 等正面词,与 miss、plunge、fraud、bankruptcy 等负面词)的净占比,产出[-1.0, 1.0]的分数。query_events接受可插拔的scorer参数,既可以用词典打分器做离线快速验证,也可以如技能文档描述的那样注入 LLM 裁判,两种打分路径共享同一套数据流。

八、回测中的事件数据:从 CSV 到手写引擎

技能文档明确指出:历史回测要求提前备好完整的历史事件 CSV,不能在回测中实时抓取,且建议按标的维护独立的事件文件。文档同目录的 example_signal_engine.py 给出了一种可直接套用的手写引擎范式:

class SignalEngine: """Long-only sentiment pre-filter over the enriched ``event_score`` column.""" def __init__(self, score_threshold: float = 0.2, top_n: int | None = None) -> None: self.score_threshold = score_threshold self.top_n = top_n def generate(self, data_map: Dict[str, pd.DataFrame]) -> Dict[str, pd.Series]: ... for dt in date_index: scored: List[tuple[str, float]] = [] for code, df in data_map.items(): if dt not in df.index: continue score = df.loc[dt].get("event_score", np.nan) if pd.notna(score) and score >= self.score_threshold: scored.append((code, float(score))) ... weight = 1.0 / len(scored) for code, _ in scored: signals[code].at[dt] = weight ...

这个引擎实现了一个典型的情绪预筛(sentiment pre-filter)多头策略:每个 bar 上选出event_score >= score_threshold的标的,按分数降序(可top_n截断),对入选标的等权做多。event_score列由回测配置中的event_feeds触发数据层富化(enrichment)自动生成,并且天然防未来——它只反映t日及之前可知的事件,引擎本身从不主动前移数据。

九、常见陷阱与规避清单

文档共列出 7 条实战中反复踩坑的经验,这些在源码中都有对应的工程化对策:

  1. 未来函数:CSV 的date必须是「可知日期」,收盘后发布的事件要用下一交易日;回测中严格执行event_date <= trade_date。对应实现:_knowable_date的收盘截断 +query_eventsknowable_date <= as_of过滤([rsshub_events.py](https://link.gitcode.com/i/4fd762b20e7059ba31bdb1f3d3d58e6a#L264-L278, L397))。
  2. 重复打分:同一事件可能被多个新闻源重复报道而产生多行。按(date, event_type)去重或取均值。对应实现:query_events(ts_code, knowable_date, event_type, summary)去重(第 398 行)。
  3. 情绪漂移:提示词或模型版本变化会导致 LLM 打分尺度漂移。对策是固定提示词模板、定期重新校准。数据层的词典打分器可作为稳定的比对基线。
  4. 事件稀疏性:大多数交易日没有事件,事件信号为 0、最终信号由技术面主导是正常现象,严禁为「填空」而捏造数据
  5. 回测事件数据:必须提前备好历史事件 CSV(建议按标的分文件),不能回测时实时抓取。
  6. summary字段中的逗号:这是 CSV 解析错误的常见原因——摘要中避免逗号,或用pd.read_csv(quoting=csv.QUOTE_ALL)读取。对应实现:_clean_summary在数据层直接做逗号剥离(第 281-285 行)。
  7. 衰减参数敏感性decay_lambda过大事件影响消失过快、过小则陈旧事件长期存活;理想上不同事件类型(财报 vs 政策)应有不同衰减曲线,但默认统一为0.1,是一种可接受的简化。

十、信号约定与依赖

信号约定

  • 纯事件信号:[-1.0, 1.0](由事件分数 + 时间衰减计算得出);
  • 组合信号:alpha * tech_signal + (1 - alpha) * event_signal,clip 到[-1.0, 1.0]
  • 无事件时event_signal = 0,组合信号退化为纯技术信号。

依赖:仅需pip install pandas numpy。LLM 分析由 Agent 自身完成,read_url工具内置,无额外依赖。这意味着该技能可以零成本地在任意回测框架中接入——只要数据层产出了合规的event_score列,手写引擎即可直接消费。

总结

事件驱动策略的本质是把「信息冲击」变成可回测、可调参、可叠加在技术信号之上的量化信号。Vibe-Trading 的这套技能设计通过三层保障让这件事变得工程上可靠:标准化提示词保证 LLM 打分可复现,CSV + 可知日期约定保证数据层与逻辑层解耦且天然防未来,指数衰减 + 加权合成保证信号可解释、可调参。若要进一步深入,推荐阅读 示例信号引擎完整实现 与 RSSHub 事件提供器,前者是技能文档的最小可运行范本,后者则是生产级的 point-in-time 事件数据管线,两者对照阅读即可完整掌握该技能的落地全貌。

【免费下载链接】Vibe-Trading"Vibe-Trading: Your Personal Trading Agent"项目地址: https://gitcode.com/GitHub_Trending/vi/Vibe-Trading

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询