ek-data 0.2.8

Trading data contracts for the enkeep ek ecosystem: venue enums, zero-dep epoch-nanosecond time, decimal-exact price rounding, vt-symbol convention, bus event dictionary, tick/bar/order/trade/position/account/contract objects and request objects (Python enkeep_trade trader/object.py + constant.py, faithfully ported).
Documentation
# Changelog


本项目遵循语义化版本(`0.x` 期间:加 API 走 minor,破坏性走 minor)。


## 0.2.6 — 2026-10-31(边界零丢弃波次:四个 UNKNOWN + TickData 时间戳空位)


契约来源:网关侧「入向零丢弃」—— CtP 返回的数据不许在中途静默消失,翻译不了也要
填表达后在界面上/事件上推出来。为此本 crate 需要提供几个「显式表达不可知」的位置。

### 加(向后兼容;全部是新增字段/变体,不删不改既有)


> **兼容性已实测,不是推断**:给枚举加变体在理论上是破坏性的(下游若有穷举 `match`
> 就会编译失败),所以发布前把 7 个下游 crate(ek-oms / ek-ui / ek-station / ek-dm /
> ek-risk / ek-converter / ek-tq)逐个用 `[patch.crates-io]` 指向本仓 0.2.6 重编,
> **全部通过**。它们要么没有穷举 `match`,要么已有 `_ =>` 兜底。
>
> 万一将来某个下游加了穷举 `match`,那一次失败会在它自己的 CI 里暴露,而不是在
> 运行时静默 —— 这也正是 `UNKNOWN` 存在的意义:让「我不认识」成为可编译期检查的
> 显式值,而不是一个被悄悄丢掉的 `None`。

- `Exchange::UNKNOWN` —— 「来自交易所,但我们不认识那个码」。与 `LOCAL`(「不来自任何
  交易所」)语义**不同**,不要混用。`ALL` 50 → 51。
- `Status::UNKNOWN` —— 「柜台给了个我不认识的状态」。**刻意不进 `ACTIVE_STATUSES`**:
  在途判定是 ek-oms 的业务决策,网关只如实说「不认识」。`ALL` 6 → 7。
- `OrderType::UNKNOWN` —— 委托类型三元组翻译不了时用它,不借 `LIMIT` 顶替
  (借用会让界面显示一个假的限价单)。`ALL` 6 → 7。
- `Asset::UNKNOWN` —— 产品类码无对应资产大类时用它。触发条件很窄:只在用户显式勾选
  非标准产品类码(如 `'4'` 现货 / `'5'` EFP / `'I'` MI)时才可达。`ALL` 5 → 6。
- `TickData.datetime_invalid: bool` —— 时间戳是否可信。为假时 `datetime` 是 `DtNs` 缺省值
  (纪元零点),**不可用于排序/绘图**。缺省 `false`:漏填时的失败方向必须是「这条时间
  不可用」,不能是「把 1970 当成真实成交时间」。配套 `TickData::datetime_if_ok()` 作为
  唯一推荐取值口。

### 记

- 没有把 `TickData.datetime` 改成 `Option<DtNs>`:它是图表横轴主键,改 `Option` 会传染
  ek-dm / ek-ui 全部消费点;用一个独立布尔位表达「能不能用」,改动面只落在构造侧。
  代价是消费侧必须记得判 —— 这写进了字段文档,并给了唯一入口函数。

### 改(测试)

- `tests/enums_roundtrip.rs` 的四条 `ALL.len()` 断言随契约 +1 / +1(SHE 51 / Status 7 /
  OrderType 7 / Asset 6),并补 `UNKNOWN` 的线值、中文别名可解析、`UNKNOWN ≠ LOCAL`。

## 0.2.5 — 2026-10-27(背压刀发布波次;本 crate 代码零改动)


- 票 T4 收口:补 `scripts/gate.ps1`(与 ek-ui 同构四闸:fmt --check / test /
  `clippy --all-targets -- -D warnings` / doc --no-deps)。工具面进包,源码与 API 零改动。
- 背压刀发布波次(ek-core 0.5.0 邮箱不丢 + 水位、ek-ctp 0.11.0 状态事件化/分批/补名、
  ek-ui 0.7.0 显形与零轮询)整链抬版:本 crate 抬一个 patch 位,让「一份链」在 crates.io
  上有单一可对照的坐标;下游 ek-ctp/ek-dm/ek-oms/ek-risk/ek-station/ek-ui/ek-converter/ek-tq
  的 pin 同步对齐到 **0.2.5**。


## 0.2.4 — 2026-10-23(随 ek-ctp 0.9.8 / ek-ui 0.5.0 整链抬版;本 crate 代码零改动)


- 整链抬版波次:ek-ctp 0.9.8(查询节律改串行阶段机 + 链状态 `[链] ` 日志推送)与 ek-ui 0.5.0
  (事件驱动改造 + 账户表「阶段」列)收口,链上各 crate 各抬一个 patch 版,让「一份链」在
  crates.io 上有单一可对照的坐标。**本 crate 源码与 API 零改动。**
- 唯一动作:dev 依赖 `ek-event` 0.1.1 → **0.1.2**(集成测试用,不随 lib 发布)。


## 0.2.3 — 2026-10-23(随 ek-ui 0.4.1 整链抬版;本 crate 代码零改动)


- 整链抬版波次:ek-ui 0.4.1(行情带 tab 归位 + 中文名 / 整行高亮 / 竖分隔条贯穿 / 账户表单单列 /
  柜台原因打到账户行 / 演示登录判据改读状态口)收口,链上各 crate 各抬一个 patch 版,让「一份链」
  在 crates.io 上有单一可对照的坐标。**本 crate 源码与 API 零改动。**
- 唯一动作:dev 依赖 `ek-event` 0.1.0 → **0.1.1**(集成测试用,不随 lib 发布)。


## 0.2.2


### Changed (manifest only;unchanged crate 代码与用例)

- **模块独立纪律落地**:`[dev-dependencies]` 的 `ek-event` 去掉 `path = "../ek-event"` 半边,改为纯版本引用 `ek-event = "0.1.0"` —— 自研 crate 之间也必须以已装版本(crates.io)互引,不以目录形式耦合;由于 dev-deps 本就不随 lib 发布,下游无感。

# Changelog


本项目遵循语义化版本(`0.x` 期间:加 API 走 minor,破坏性走 minor)。


## 0.2.1


### Added (tests only;runtime dependency remains zero)

- 业务流集成测试 5 个文件(`tests/flows_stream.rs` / `flows_order.rs` / `flows_position_account.rs` / `flows_contract_log.rs` / `flows_time_negative.rs`)+ `tests/common`(Capture<T> / wait_until / FIFO 排空哨兵):数据对象在真实 ek-event 总线上的订阅、派生 ID 键组合、状态时间轴、合约单投 parity 正证、eLog 单形态契约、civil 往返与 DTNS_MAX 边界过流、坏载荷/坏键负面集。
- `[dev-dependencies] ek-event = { path = "../ek-event", version = "0.1.0" }`(仅测试;发布时自动剥 path)。

### Fixed (test-side expectations)

- 委托流组合键 = `eOrder.<gateway.orderid>`、成交流 = `eTrade.<gateway.tradeid>`(object.py:230/231 序,无 symbol 段)——先期键位设计(K线序/订单序)以源码为准回调。

# Changelog


本项目遵循语义化版本(`0.x` 期间:加 API 走 minor,破坏性走 minor)。

## 0.2.0


### Added


- `price` 模块:`round_to` / `floor_to` / `ceil_to` / `get_digits` 及其可失败版
  `try_round_to` / `try_floor_to` / `try_ceil_to` —— 对齐 Python `utility.py:275-318`
  的 **Decimal 精确十进制**语义(`floor_to(0.3, 0.1) == 0.3`,`round_to(2.5, 1.0) == 2.0`
  的 half-even 平局规则),不用朴素 f64 近似。
- `time` 模块:`parse_civil`(网关/回放常见 `"YYYY-MM-DD[ HH:MM[:SS[.f]]]"` 形态)、
  `try_civil_to_nanos`、`is_valid_civil`、`days_in_month`、`is_leap_year`、
  `DTNS_MIN` / `DTNS_MAX` 与 `DtNs` 可表达范围文档。
- `Status::is_active()`:活跃态判定的唯一真源(`OrderData::is_active` 委托到它)。
- `symbol::write_vt_symbol` 与六个流对象(tick/bar/order/trade/position/contract)的
  `en_symbol_into(&mut String)`:逐 tick 热路径零分配的 `en_symbol` 拼装。
- 审计级用例:枚举线值/别名**冲突不变量**、时间严格性/解析/范围、价格十进制精确性。
- `README.md` 与 `Cargo.toml` 的 `readme` / `documentation` 元数据。

### Changed


- `civil_to_nanos` 现在**严格校验**输入(月/日/闰年/时分秒/纳秒/i64 范围),
  越界即 panic —— 对齐 Python `datetime` 抛 `ValueError` 的失败面;
  原先越界会静默产生错误时间戳。可失败路径用 `try_civil_to_nanos`。

## 0.1.0


### Added


- 首版:10 个类型枚举(`constant.py` 全量,含 50 个交易所与 `CBT`/`EUX`/`ETF_index`
  线值特例)、12 个数据/请求对象(含迅投 Xt 扩展字段)、`event.py` 事件字典、
  `vt_symbol` 约定、零依赖时间面、可选 `serde`。
- 测试:parity / enums_roundtrip / objects / serde_cfg 四套。