3. 事件类型定义与分类
在事件驱动回测系统中,事件是系统运转的“燃料”。所有逻辑——从数据接收、信号生成、订单执行到账户更新——都通过事件来触发和传递。一个清晰、完备的事件类型体系,决定了回测框架的扩展性与可维护性。本章将定义五大核心事件类型:市场事件、订单事件、信号事件、账户事件和定时事件,并给出标准化的数据结构。
3.1 事件分类总览
事件类型按照其产生来源与消费用途进行划分。下表列出了五种事件的核心特征与典型用途:
| 事件类型 | 产生源 | 主要消费者 | 触发时机 | 典型用途 |
|---|---|---|---|---|
| 市场事件 | 数据馈送模块 | 策略模块、风控模块 | 新行情数据到达 | 驱动策略计算、更新市场状态 |
| 信号事件 | 策略模块 | 订单管理模块、风控模块 | 策略逻辑产生买卖意向 | 传递交易信号,触发订单生成 |
| 订单事件 | 订单管理模块 | 执行模拟器、风控模块 | 订单状态变更(创建、成交、撤销) | 跟踪订单生命周期,更新持仓 |
| 账户事件 | 执行模拟器/风控 | 绩效模块、账户管理器 | 持仓、资金、保证金变动 | 更新账户状态,计算盈亏 |
| 定时事件 | 定时器模块 | 策略模块、调度器 | 预设时间点或间隔到达 | 执行定期任务(如再平衡、收盘处理) |
3.2 事件基类与通用结构
所有事件都继承自一个抽象基类 Event,包含两个通用字段:
from dataclasses import dataclass, field
from datetime import datetime
from enum import Enum, auto
from typing import Any, Dict
class EventType(Enum):
MARKET = auto()
SIGNAL = auto()
ORDER = auto()
ACCOUNT = auto()
TIMER = auto()
@dataclass
class Event:
"""事件基类"""
event_type: EventType # 事件类型枚举
timestamp: datetime # 事件发生时间(交易所时间)
source: str = "" # 事件来源模块标识
metadata: Dict[str, Any] = field(default_factory=dict) # 扩展元数据
timestamp 字段是回测时间轴的核心锚点,所有事件处理必须严格按时间顺序进行。metadata 字典用于携带调试信息或模块间传递的临时数据,不参与核心业务逻辑。
3.3 市场事件 (MarketEvent)
市场事件是回测系统中最基础、最频繁的事件。它代表一个新的市场数据点(如 tick、1分钟K线、5分钟K线)到达系统。市场事件驱动策略模块进行判断,是“事件驱动”一词的直接体现。
@dataclass
class MarketEvent(Event):
"""市场事件:携带新的行情数据"""
symbol: str # 交易标的代码
price: float # 最新成交价(或K线收盘价)
volume: float # 成交量
bid: float = 0.0 # 买一价(tick级别)
ask: float = 0.0 # 卖一价(tick级别)
open_interest: float = 0.0 # 持仓量(期货/期权)
# 扩展字段:可携带K线OHLCV结构
ohlcv: Dict[str, float] = field(default_factory=dict)
def __post_init__(self):
self.event_type = EventType.MARKET
- 粒度无关: 无论是 tick 还是日线,都使用同一个 MarketEvent 结构,通过
ohlcv字段承载不同粒度的数据。 - 买卖价差:
bid和ask字段在 tick 级别数据中填充,用于模拟滑点和限价单成交逻辑。 - 时间戳精度: 回测中必须使用交易所时间戳,而非系统时间,以保证回放顺序的准确性。
3.4 信号事件 (SignalEvent)
当策略模块接收到市场事件并完成计算后,如果产生交易意向,就会生成一个信号事件。信号事件是策略逻辑的输出,它不包含具体的订单指令,而是表达“我想做什么”。
@dataclass
class SignalEvent(Event):
"""信号事件:策略产生的交易意向"""
symbol: str # 交易标的
direction: str # 'BUY' 或 'SELL'
strength: float = 1.0 # 信号强度(0~1),用于仓位管理
signal_id: str = "" # 信号唯一标识,用于追踪
strategy_name: str = "" # 产生信号的策略名称(多策略场景)
def __post_init__(self):
self.event_type = EventType.SIGNAL
3.5 订单事件 (OrderEvent)
订单事件是回测系统中状态最复杂的事件。它描述了订单从创建到最终状态(成交、撤销、拒绝)的完整生命周期。订单事件由订单管理模块生成,并被执行模拟器消费。
class OrderStatus(Enum):
CREATED = auto() # 已创建
SUBMITTED = auto() # 已提交到交易所
PARTIALLY_FILLED = auto() # 部分成交
FILLED = auto() # 全部成交
CANCELLED = auto() # 已撤销
REJECTED = auto() # 被拒绝
class OrderType(Enum):
MARKET = auto() # 市价单
LIMIT = auto() # 限价单
STOP = auto() # 止损单
STOP_LIMIT = auto() # 止损限价单
@dataclass
class OrderEvent(Event):
"""订单事件:描述订单状态变化"""
order_id: str # 订单唯一编号
symbol: str # 交易标的
order_type: OrderType # 订单类型
direction: str # 'BUY' 或 'SELL'
quantity: float # 委托数量
price: float = 0.0 # 限价/触发价(市价单为0)
status: OrderStatus = OrderStatus.CREATED # 当前状态
filled_quantity: float = 0.0 # 已成交数量
avg_fill_price: float = 0.0 # 平均成交价格
commission: float = 0.0 # 手续费
reason: str = "" # 拒绝/撤销原因
def __post_init__(self):
self.event_type = EventType.ORDER
订单事件的生命周期流转如下图所示:
3.6 账户事件 (AccountEvent)
账户事件用于通知系统账户状态的变化。当订单成交、资金划转、分红或保证金调整发生时,系统生成账户事件,绩效模块和风控模块据此更新账户快照。
@dataclass
class AccountEvent(Event):
"""账户事件:账户资金/持仓变动"""
account_id: str # 账户编号
cash_balance: float # 当前现金余额
total_equity: float # 总权益(现金 + 持仓市值)
unrealized_pnl: float = 0.0 # 未实现盈亏
realized_pnl: float = 0.0 # 已实现盈亏
margin_used: float = 0.0 # 已占用保证金
positions: Dict[str, float] = field(default_factory=dict) # 持仓快照 {symbol: quantity}
change_reason: str = "" # 变动原因(如 'FILL', 'DIVIDEND', 'FEE')
def __post_init__(self):
self.event_type = EventType.ACCOUNT
3.7 定时事件 (TimerEvent)
定时事件是回测系统中唯一不直接由市场数据驱动的事件类型。它由定时器模块在预设的时间点触发,用于执行与行情无关的定期任务。
@dataclass
class TimerEvent(Event):
"""定时事件:按预设时间触发"""
timer_id: str # 定时器标识
interval_seconds: float # 触发间隔(秒)
repeat_count: int = -1 # 重复次数(-1表示无限重复)
current_count: int = 0 # 当前已触发次数
user_data: Any = None # 用户自定义数据
def __post_init__(self):
self.event_type = EventType.TIMER
定时事件的典型应用场景包括:
- 收盘处理: 在交易日收盘前5分钟触发,执行平仓或调整操作。
- 定期再平衡: 每月第一个交易日触发,执行投资组合再平衡。
- 风控检查: 每隔30分钟触发一次,检查持仓集中度或杠杆率。
- 数据快照: 每日收盘后触发,保存账户状态快照用于绩效分析。
3.8 事件类型关系图
下图展示了五种事件类型在回测系统中的流转关系与模块边界:
3.9 事件处理优先级与顺序
在事件驱动回测中,同一时间戳可能同时到达多个事件。为了保证回测的确定性,必须定义事件处理优先级:
- 定时事件(最高优先级):确保定期任务在行情处理前执行。
- 市场事件:驱动策略计算,产生信号。
- 信号事件:由策略产生后立即处理,生成订单。
- 订单事件:订单状态变更,触发执行模拟。
- 账户事件(最低优先级):在订单处理完成后更新账户状态。
heapq 或 PriorityQueue 实现,以 (timestamp, priority, sequence_id) 作为排序键,确保相同时间戳下的事件按预定顺序处理。
3.10 扩展性设计
上述事件类型定义并非一成不变。在实际项目中,你可能需要扩展:
- 自定义事件: 继承
Event基类,添加业务特定字段(如新闻事件、宏观经济数据事件)。 - 事件过滤器: 在事件总线上添加过滤器,允许模块只订阅感兴趣的事件类型。
- 事件序列化: 为事件添加
to_dict()/from_dict()方法,支持回测结果的序列化存储与复盘。
@dataclass
class NewsEvent(Event):
"""扩展示例:新闻事件"""
headline: str
sentiment_score: float # -1.0 ~ 1.0
source: str
def __post_init__(self):
self.event_type = EventType.MARKET # 复用市场事件类型,或新增枚举值
通过这种清晰的事件分类与数据结构设计,回测系统的各个模块可以像乐高积木一样组合与替换,而事件总线则成为连接所有模块的“神经系统”。