# ek-data —— 设计说明(v0.1.0)
交易平台的**业务数据契约 crate**:全生态(规划中的 ek-paper / ek-book /
回放器 / 对账工具 / xt 适配层)共用的数据对象、类型枚举、件流事件字典、
标识约定与请求对象。**纯 std、零依赖**;`serde` 为 optional feature(default off)。
Python 原稿:`enkeep_trade/enkeep_trade/trader/constant.py`(207 行)与
`trader/object.py`(819 行)。本 crate 是它们的忠实移植,差异都有决策编号。
## 1. 模块布局(维护铁律:一个结构体一个文件)
```
src/
lib.rs reexport 聚合点 + Python#行号 对照总表
constant.rs 10 枚举 + ACTIVE_STATUSES + EnumParseError + Default 取值
time.rs DtNs(i64 纪元纳秒)/ Day / Civil / 双向换算(now/format 辅件)
symbol.rs vt_symbol 组装 + parse_vt_symbol(extract 语义)
event.rs EVENT_* 事件字典(前缀型 `eTick.` / 一字面型 `eOrder`)
tick.rs bar.rs 行情对象(Tick 40+ 字段五档全量;Bar 公共字段版)
order.rs trade.rs 委托/成交(Xt 扩展字段全保留)
position.rs account.rs log.rs / contract.rs
subscribe_request.rs / order_request.rs / cancel_request.rs / history_request.rs
serde_impls.rs feature=on 的 JSON 便捷层(to_json/from_json)
tests/
parity.rs ID/线值与 Python 字节级对照(含 CBOT→CBT 等特例)
enums_roundtrip.rs 全枚举 Display/FromStr 双通道回路
objects.rs 方法行为用例(限价三层/活跃矩阵/量域四件套/Hinnant 钉死值)
serde_cfg.rs feature 双路径:serde=on 时 JSON roundtrip + 特例 rename;off 时编译通过
```
规则:新增字段只动一个文件;对外 import 一律走 lib.rs 聚合点;
serde 标注不进结构体文件正文(`#[cfg_attr(...)]` 单行除外),语义层保持纯数据。
## 2. 对象与方法清单(Python → Rust 一对一)
| TickData | gateway_name/symbol/exchange/datetime + trading_day/action_day/update_time/update_millisec + 五档 price/volume×5 + OHLC/limit/pct_change + localtime | `en_symbol` · `reach_limit_up(diff)`(object.py:99)· `reach_limit_down(diff)`(:105)· `reach_limit(diff)`(:111) |
| BarData | 公共字段(symbol/exchange/datetime/interval/volume/turnover/open_interest/OHLC/pct_change) | `en_symbol` |
| OrderData | + type(Python `type`→Rust `order_type`)/direction(Option)/offset/price/volume/traded/status/datetime/reference + Xt:name/status_msg/traded_price | `en_symbol`·`en_orderid`(:180)·`is_active`(:182)·`create_cancel_request`(:188) |
| TradeData | + orderid/tradeid/direction/offset/price/volume/datetime + commission/slippage/trade_pnl + Xt:name/traded_amount | `en_symbol`·`en_orderid`(:230)·`en_tradeid`(:231) |
| PositionData | + direction(必填)/volume/frozen/price/pnl/yd_volume + Xt:can_use_volume/market_value/on_road_volume/avg_price/last_price/profit_rate | `en_symbol`·`en_positionid`(:262-264) |
| AccountData | accountid/balance/frozen | `en_accountid`(:282)·`available`(:281 暂存→方法) |
| LogData | msg/level(缺省 20=INFO) | level 常量(20/30/40)·`info`·`is_warning_or_above` |
| ContractData | asset/instrument_type/size(缺省1)/price_tick(缺省0.01)/product_id/下量四件套/交割年月 + 扩展(open_date/pre_close/涨跌停/股本/停牌态) | `en_symbol` |
| SubscribeRequest | symbol/exchange | `from_vt_symbol`·`en_symbol`·`FromStr` |
| OrderRequest | symbol/exchange/direction/type/volume/price/offset/reference + old_order_id | `en_symbol`·`create_order_data`(:541)·量域四件套(:559-588:min/max/range/beishu) |
| CancelRequest | orderid/symbol/exchange | `en_symbol`·`en_orderid(gateway)` |
| HistoryRequest | symbol/exchange/start/end/interval | `en_symbol` |
**defer 清单**(共识,后续批次):QuoteData/QuoteRequest、HedgeContractData/
ContractData2/ProductInfo/HedgeSetting、StockData/SectorData/KlineChartData、
NotifyData/AlertData;BarData 的 pe/pb/float_mv/total_mv 四件套移除待持久层另立。
## 3. 枚举线值决策(Display=英文令牌,FromStr 容中文旧值)
英文令牌即 `ALL/Display/as_str()` 线值;中文别名只进 `FromStr`。
特例(字节级对齐 Python `.value`):`CBOT→"CBT"`、`EUREX→"EUX"`、
`ETF_INDEX→"ETF_index"`。Exchange 全量 50 变体复刻。
上标:`Direction/Offset/Status/Asset/InstrumentType/OrderType/OptionType/
Exchange/Currency/Interval`;`Interval.seconds()` 即 Python `.value` 秒数;
`ACTIVE_STATUSES = [SUBMITTING, NOTTRADED, PARTTRADED]`(object.py:21)。
Default 取值(供对象 `..Default::default()`,对齐 Python 字段缺省):
Exchange=LOCAL、OrderType=LIMIT、Offset=NONE、Status=SUBMITTING、
Direction=NET、Asset=EQUITY(Position/ContractData 里 Python 必填,
Rust Default 面为中性值)。
## 4. 派生 ID:方法化,不暂存
Python 的 `__post_init__` 暂存字段(en_symbol/en_orderid/en_tradeid/
en_positionid/en_accountid/available)在 Rust 版全部为**方法即时计算**——
字段改动永不脱同步;`en_positionid` 第三段为英文方向令牌(线值决策 3)。
## 5. 时间决定:A 零依赖
`DtNs = i64`(Unix 纪元**纳秒**,UTC 视角)+ `Day = i32`(纪元天)+
`Civil{year,month,day,hour,minute,second,nanos}`。换算走 Hinnant
days_from_civil/civil_from_days(负纳秒用 div_euclid/rem_euclid 的 floor
语义),单测包括 2000-03-01=11017、闰日、纪元前负值。
对齐说明:Python datetime 是本地 naive,故逐字节对齐仅限于**字段语义**
而非时区;时区/本地化展示由使用方(网关层)处理。
## 6. serde 决定:optional、default off
`feature=serde` 开启 derive(字段名即 Python 字段名 snake_case)与
serde_impls::{to_json,from_json};枚举 serde 线值同样英文(**中文旧值不做
serde 反序列化**,兼容通道收敛在 `FromStr`)。off 路径连编译都要过
(serde_cfg.rs 用 `#![cfg(feature = "serde")]` 门面)。
## 7. 与生态的边界
- ek-event 0.1.0 / ek-core 0.2.0 **一行不动**;ek-data 不依赖二者
(数据契约先行,插件 crate 再同时依赖 ek-data + ek-core)。
- event.rs 的 `eTick.` 等是**业务事件字典**(ek-event 泛事件队列上的载荷约定),
与 ek-core 的 `ePlugUp/eSrvChg/eReq.*` 属不同命名域,互不重叠。
- 发布流程同前序:tests→clippy(-D warnings,双 feature)→3 连跑→
commit→tag→push(发布人工执行)。
## 8. 版本历史
- **0.1.0**(规划于 0.2.0 宿主发布之后):初始形态,即本文档。