feat(engine): 添加核心基础设施 — engine/common 模块

- engine/__init__.py: 包入口,导出 Kline/KlineInterval/OrderBook/Ticker/Trade
- common/base.py: BaseStrategy 抽象基类,定义 on_kline/on_ticker/on_orderbook 回调
- common/models.py: Pydantic 数据模型,与 TS 侧 types 字段对齐,支持字段校验
- common/config.py: 全局配置加载(YAML),统一 engine/env.yaml 读取
- common/logger.py: 结构化日志,支持 JSON/pretty print 输出
This commit is contained in:
Rekey
2026-06-12 10:26:37 +08:00
parent 4d66a86234
commit 039bfb5075
6 changed files with 540 additions and 0 deletions
+178
View File
@@ -0,0 +1,178 @@
"""
数据模型定义 — 与 TS data/types/base.ts 对齐的 Pydantic 模型
Ticker / Trade / OrderBook / Kline 是系统中流通的核心行情数据结构,
字段语义与 Binance/OKX/Bybit 通用概念对齐,时间戳统一使用 Unix 毫秒。
"""
from typing import Literal
from pydantic import BaseModel, Field, field_validator
# ============================================================
# K 线周期类型
# ============================================================
KlineInterval = Literal["1m", "5m", "15m", "30m", "1h", "4h", "1d", "1w"]
# ============================================================
# 行情数据模型
# ============================================================
class Ticker(BaseModel):
"""24 小时滚动行情统计
每笔成交触发推送,包含最近 24 小时的 OHLC、成交量、买卖盘口等统计信息。
"""
exchange: str
"""交易所标识(如 binance"""
symbol: str
"""交易对符号(大写,如 BTCUSDT"""
# 24h 价格统计
last_price: float = Field(alias="lastPrice")
"""最新成交价"""
open_price: float = Field(alias="openPrice")
"""24h 开盘价"""
high_price: float = Field(alias="highPrice")
"""24h 最高价"""
low_price: float = Field(alias="lowPrice")
"""24h 最低价"""
# 24h 成交量统计
volume: float
"""24h 成交量(base 币种)"""
quote_volume: float = Field(alias="quoteVolume")
"""24h 成交额(quote 币种)"""
# 价格变化
price_change: float = Field(alias="priceChange")
"""24h 价格变化"""
price_change_percent: float = Field(alias="priceChangePercent")
"""24h 价格变化百分比(0.05 = 5%"""
# 最优买卖盘口
bid_price: float = Field(alias="bidPrice")
"""买一价"""
bid_qty: float = Field(alias="bidQty")
"""买一量"""
ask_price: float = Field(alias="askPrice")
"""卖一价"""
ask_qty: float = Field(alias="askQty")
"""卖一量"""
# 时间戳
event_time: float = Field(alias="eventTime")
"""事件发生时间(Unix 毫秒)"""
close_time: float = Field(alias="closeTime")
"""交易所收盘时间(Unix 毫秒,用于判断 K 线是否闭合)"""
class Trade(BaseModel):
"""逐笔成交记录"""
exchange: str
"""交易所标识"""
symbol: str
"""交易对符号"""
price: float
"""成交价"""
amount: float
"""成交数量(base 币种)"""
quote_amount: float = Field(alias="quoteAmount")
"""成交额(quote 币种 = price × amount"""
timestamp: float
"""成交时间(Unix 毫秒)"""
is_buyer_maker: bool = Field(alias="isBuyerMaker")
"""买方是否为挂单方(true = 主动卖出 / taker sell"""
trade_id: str = Field(alias="tradeId")
"""交易所成交 ID"""
class OrderBook(BaseModel):
"""订单簿深度快照"""
exchange: str
"""交易所标识"""
symbol: str
"""交易对符号"""
bids: list[tuple[float, float]]
"""买单列表 [[price, qty], ...],按价格降序(买一在前)"""
asks: list[tuple[float, float]]
"""卖单列表 [[price, qty], ...],按价格升序(卖一在前)"""
last_update_id: int = Field(alias="lastUpdateId")
"""上次更新 ID"""
event_time: float = Field(alias="eventTime")
"""事件发生时间(Unix 毫秒)"""
class Kline(BaseModel):
"""标准化 K 线(OHLCV
K 线是最主要的行情输入,策略通过 on_kline() 接收此数据。
open/high/low/close/volume 字段在 TS 侧为字符串以保持精度,
模型在初始化时自动转换为 float。
"""
exchange: str
"""交易所标识"""
symbol: str
"""交易对符号"""
interval: KlineInterval
"""K 线周期"""
# 时间
open_time: float = Field(alias="openTime")
"""开盘时间(Unix 毫秒)"""
close_time: float = Field(alias="closeTime")
"""收盘时间(Unix 毫秒)"""
# OHLCV
open: float
"""开盘价"""
high: float
"""最高价"""
low: float
"""最低价"""
close: float
"""收盘价"""
volume: float
"""成交量(base 币种)"""
# 扩展字段
quote_volume: float = Field(default=0.0, alias="quoteVolume")
"""成交额(quote 币种)"""
taker_buy_base_vol: float = Field(default=0.0, alias="takerBuyBaseVol")
"""主动买入成交量(base 币种)"""
taker_buy_quote_vol: float = Field(default=0.0, alias="takerBuyQuoteVol")
"""主动买入成交额(quote 币种)"""
trade_count: int = Field(default=0, alias="tradeCount")
"""成交笔数"""
is_closed: bool = Field(alias="isClosed")
"""该 K 线是否已关闭(不再更新)"""
# ── 字段校验:处理 TS 侧字符串 → float 转换 ──
@field_validator(
"open", "high", "low", "close", "volume",
"quote_volume", "taker_buy_base_vol", "taker_buy_quote_vol",
mode="before",
)
@classmethod
def _coerce_float(cls, v: object) -> float:
"""将字符串类型数值转为 float,兼容 TS 侧 MessagePack 序列化格式"""
if isinstance(v, str):
return float(v)
return float(v)
@field_validator("trade_count", mode="before")
@classmethod
def _coerce_int(cls, v: object) -> int:
"""将字符串类型数值转为 int"""
if isinstance(v, str):
return int(v)
return int(v)