ek-data 0.2.2

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
//! 行情逐笔快照(`object.py:37-119`,字段逐值复刻 + 方法三层)。

use crate::constant::Exchange;
use crate::time::DtNs;

/// Tick 数据:最后成交、盘口快照、日内统计。
///
/// 字段与 Python `TickData` 同名同义(snake_case);缺省值同 Python(0 / "")。
#[derive(Debug, Clone, PartialEq, Default)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct TickData {
    /// 上游网关名(`BaseData.gateway_name`,`object.py:31`)
    pub gateway_name: String,
    /// 合约代码
    pub symbol: String,
    /// 交易所
    pub exchange: Exchange,
    /// 时间戳(UTC 纪元纳秒;Python 为本地 naive datetime)
    pub datetime: DtNs,

    /// 交易日(缺省 None;Python 缺省空串)
    pub trading_day: Option<i32>,
    /// 行动日/自然日(缺省 None;Python 缺省空串)
    pub action_day: Option<i32>,
    /// 原始 HH:MM:SS 文本(上游原样)
    pub update_time: String,
    /// 毫秒段
    pub update_millisec: i64,

    /// 合约中文名
    pub name: String,
    /// 当日累计成交量
    pub volume: f64,
    /// 当日累计成交额
    pub turnover: f64,
    /// 持仓量/流通量
    pub open_interest: f64,
    /// 最新价
    pub last_price: f64,
    /// 本笔成交量
    pub last_volume: f64,
    /// 涨停价
    pub limit_up: f64,
    /// 跌停价
    pub limit_down: f64,

    /// 今开
    pub open_price: f64,
    /// 最高
    pub high_price: f64,
    /// 最低
    pub low_price: f64,
    /// 昨收
    pub pre_close: f64,
    /// 涨跌幅(%)
    pub pct_change: f64,

    /// 买一价
    pub bid_price_1: f64,
    /// 买二价
    pub bid_price_2: f64,
    /// 买三价
    pub bid_price_3: f64,
    /// 买四价
    pub bid_price_4: f64,
    /// 买五价
    pub bid_price_5: f64,

    /// 卖一价
    pub ask_price_1: f64,
    /// 卖二价
    pub ask_price_2: f64,
    /// 卖三价
    pub ask_price_3: f64,
    /// 卖四价
    pub ask_price_4: f64,
    /// 卖五价
    pub ask_price_5: f64,

    /// 买一量
    pub bid_volume_1: f64,
    /// 买二量
    pub bid_volume_2: f64,
    /// 买三量
    pub bid_volume_3: f64,
    /// 买四量
    pub bid_volume_4: f64,
    /// 买五量
    pub bid_volume_5: f64,

    /// 卖一量
    pub ask_volume_1: f64,
    /// 卖二量
    pub ask_volume_2: f64,
    /// 卖三量
    pub ask_volume_3: f64,
    /// 卖四量
    pub ask_volume_4: f64,
    /// 卖五量
    pub ask_volume_5: f64,

    /// 本地收包时间(UTC 纪元纳秒;Python 缺省 None)
    pub localtime: Option<DtNs>,
}

impl TickData {
    /// `en_symbol`(Python `__post_init__` 暂存字段的派生方法化;分配一次)。
    pub fn en_symbol(&self) -> String {
        let mut buf = String::with_capacity(self.exchange.as_str().len() + 1 + self.symbol.len());
        self.en_symbol_into(&mut buf);
        buf
    }

    /// 零分配版本:追加到复用缓冲(逐 tick 热路径;每笔行情少一次堆分配)。
    pub fn en_symbol_into(&self, buf: &mut String) {
        crate::symbol::write_vt_symbol(buf, &self.symbol, self.exchange);
    }

    /// tick 是否触及涨停(`object.py:99`;diff 为容差,非负向给)。
    ///
    /// 注意原作怪癖(字节级保留):tick 缺省字段(0.0/0.0)时
    /// `bid_price_1(0) + 0 >= limit_up(0)` 成立 → 返回 true;
    /// 使用方须先落真实价格再作判,或自行先校验 limit_up>0。
    pub fn reach_limit_up(&self, diff_price: f64) -> bool {
        self.bid_price_1 + diff_price >= self.limit_up
    }

    /// tick 是否触及跌停(`object.py:105`)。
    pub fn reach_limit_down(&self, diff_price: f64) -> bool {
        self.ask_price_1 - diff_price <= self.limit_down
    }

    /// 触及涨停或跌停(`object.py:111`)。
    pub fn reach_limit(&self, diff_price: f64) -> bool {
        self.reach_limit_up(diff_price) || self.reach_limit_down(diff_price)
    }
}