ek-ctp 0.1.0

CTP gateway for the enkeep ek ecosystem: MD/TD session drivers mapping CTP wire rows onto ek-data objects over the ek-event bus (pure-logic core; native SDK bridging lands behind the `native` feature).
Documentation
//! CTP 数据行的内部规范形态(wire)。
//!
//! 来源:原稿 `enkeep_ctp/enkeep_ctp/gateway/ctp_gateway.py` 各回调**实际取用的
//! 字段子集**(TThostFtdc*Field 的窄面)。原生 FFI 镜像(native 特性,0.2.0)将
//! C++ 结构体逐字段搬进这些结构;mock 测试直接构造 wire 行。
//!
//! - 数值统一 `f64`/整数用 `i64`:ek-data 对象面如此,零损耗复制。
//! - 码值字符串(状态/方向/开平/条件)保持 CTP 原值(如 `'3'`),翻译发生在
//!   [`crate::map`]——wire 永远是"未解释"面。

/// CTP 响应错误行(`CThostFtdcRspInfoField` 窄面:ErrorID/ErrorMsg)。
#[derive(Debug, Clone, PartialEq, Eq, Default)]
pub struct ErrorField {
    /// 错误代码(0 = 成功)
    pub error_id: i32,
    /// 错误信息
    pub error_msg: String,
}

impl ErrorField {
    /// 空错误(成功语义,原稿 `if not error["ErrorID"]` 的对偶面)。
    pub fn ok() -> Self {
        Self { error_id: 0, error_msg: String::new() }
    }
}

/// 深度行情行(`CThostFtdcDepthMarketDataField` 窄面;md `onRtnDepthMarketData`
/// 336 处实际取用字段)。
///
/// 原稿取用:InstrumentID/Volume/Turnover/OpenInterest/LastPrice/UpperLimitPrice/
/// LowerLimitPrice/OpenPrice/HighestPrice/LowestPrice/PreClosePrice/BidPrice1..5/
/// AskPrice1..5/BidVolume1..5/AskVolume1..5/UpdateTime/UpdateMillisec/ActionDay。
#[derive(Debug, Clone, PartialEq, Default)]
pub struct DepthMarketData {
    /// 合约代码(CTP InstrumentID,不带交易所)
    pub instrument_id: String,
    /// 最新价(MAX_FLOAT 表全停板,原稿 331 行 `adjust_price` 归零处理)
    pub last_price: f64,
    /// 当日累计成交量
    pub volume: f64,
    /// 当日累计成交额
    pub turnover: f64,
    /// 持仓量
    pub open_interest: f64,
    /// 涨停价
    pub upper_limit_price: f64,
    /// 跌停价
    pub lower_limit_price: f64,
    /// 今开
    pub open_price: f64,
    /// 最高
    pub highest_price: f64,
    /// 最低
    pub lowest_price: f64,
    /// 昨收
    pub pre_close_price: f64,
    /// 买一价..买五价(MAX_FLOAT 时 `adjust_price` 归零)
    pub bid_price1: f64,
    /// 买二价
    pub bid_price2: f64,
    /// 买三价
    pub bid_price3: f64,
    /// 买四价
    pub bid_price4: f64,
    /// 买五价
    pub bid_price5: f64,
    /// 卖一价
    pub ask_price1: f64,
    /// 卖二价
    pub ask_price2: f64,
    /// 卖三价
    pub ask_price3: f64,
    /// 卖四价
    pub ask_price4: f64,
    /// 卖五价
    pub ask_price5: f64,
    /// 买一量
    pub bid_volume1: f64,
    /// 买二量
    pub bid_volume2: f64,
    /// 买三量
    pub bid_volume3: f64,
    /// 买四量
    pub bid_volume4: f64,
    /// 买五量
    pub bid_volume5: f64,
    /// 卖一量
    pub ask_volume1: f64,
    /// 卖二量
    pub ask_volume2: f64,
    /// 卖三量
    pub ask_volume3: f64,
    /// 卖四量
    pub ask_volume4: f64,
    /// 卖五量
    pub ask_volume5: f64,
    /// 更新时间("HH:MM:SS")
    pub update_time: String,
    /// 更新毫秒段
    pub update_millisec: i64,
    /// 行动日("YYYYMMDD")
    pub action_day: String,
}

/// 合约行(`CThostFtdcInstrumentField` 窄面;td `onRspQryInstrument` 632-654 行
/// 实际取用字段)。
///
/// 原稿注记(619-631 行样例):合约行的 `ExchangeID` 是交易所真源;`ProductClass`
/// 决定资产大类映射;`ProductID` 为品种代码。
#[derive(Debug, Clone, PartialEq, Default)]
pub struct InstrumentField {
    /// 合约代码
    pub instrument_id: String,
    /// 交易所代码("CFFEX"/"SHFE"/"CZCE"/"DCE"/"INE"/"GFEX")
    pub exchange_id: String,
    /// 合约名称
    pub instrument_name: String,
    /// 产品类码(`THOST_FTDC_PC_*`,map::asset_from 翻译)
    pub product_class: String,
    /// 合约乘数(VolumeMultiple)
    pub volume_multiple: f64,
    /// 最小价格变动(PriceTick)
    pub price_tick: f64,
    /// 限价单最大上量
    pub max_limit_order_volume: f64,
    /// 限价单最小上量
    pub min_limit_order_volume: f64,
    /// 市价单最大上量
    pub max_market_order_volume: f64,
    /// 市价单最小上量
    pub min_market_order_volume: f64,
    /// 交割年
    pub delivery_year: i64,
    /// 交割月
    pub delivery_month: i64,
    /// 品种代码
    pub product_id: String,
    /// 是否可交易(1/0)
    pub is_trading: i64,
}

/// 委托/订单行(`CThostFtdcOrderField` 窄面;td `onRspOrderInsert` 494-511 与
/// `onRtnOrder` 669-718 行实际取用字段)。
#[derive(Debug, Clone, PartialEq, Default)]
pub struct OrderField {
    /// 合约代码
    pub instrument_id: String,
    /// 本地报单号(OrderRef,零起递增)
    pub order_ref: String,
    /// 前置编号
    pub front_id: i64,
    /// 会话编号
    pub session_id: i64,
    /// 交易所报单编号(OrderSysID)
    pub order_sys_id: String,
    /// 报单方向码(`'0'`买/`'1'`卖)
    pub direction: String,
    /// 组合开平标志码(OFEN_*;原稿 708 行读 `CombOffsetFlag`)
    pub comb_offset_flag: String,
    /// 报单价格类型码(OPT_*)
    pub order_price_type: String,
    /// 有效期类型码(TC_*)
    pub time_condition: String,
    /// 成交量类型码(VC_*)
    pub volume_condition: String,
    /// 委托价
    pub limit_price: f64,
    /// 报单中的委托总量
    pub volume_total_original: f64,
    /// 尚未成交量
    pub volume_total: f64,
    /// 已成交数量
    pub volume_traded: f64,
    /// 报单状态码(OST_*;map::status_of 翻译)
    pub order_status: String,
    /// 报单日期("YYYYMMDD")
    pub insert_date: String,
    /// 委托时间("HH:MM:SS")
    pub insert_time: String,
}

/// 成交行(`CThostFtdcTradeField` 窄面;td `onRtnTrade` 720-747 行实际取用字段)。
///
/// 注意(原稿 741 与 708 的差异):成交行读 `OffsetFlag`(单偏移),委托行读
/// `CombOffsetFlag`(组合偏移);wire 分列如实保留。
#[derive(Debug, Clone, PartialEq, Default)]
pub struct TradeField {
    /// 合约代码
    pub instrument_id: String,
    /// 交易所报单编号(与 OrderData 的映射键)
    pub order_sys_id: String,
    /// 成交编号(TradeID)
    pub trade_id: String,
    /// 报单方向码('0'/'1')
    pub direction: String,
    /// 单偏移开平标志码(OF_*;原稿 741 行)
    pub offset_flag: String,
    /// 成交价格
    pub price: f64,
    /// 成交数量
    pub volume: f64,
    /// 成交日期("YYYYMMDD")
    pub trade_date: String,
    /// 成交时间("HH:MM:SS")
    pub trade_time: String,
}

/// 持仓明细行(`CThostFtdcInvestorPositionField` 窄面;td `onRspQryInvestorPosition`
/// 543-586 行实际取用字段)。
///
/// CTP 语义候选源:同一 (InstrumentID, PosiDirection) 键可能多行(上期 Today/
/// Yesterday 分行),合并算法在驱动层(仓库 driver.rs 持仓合并块,546-595 行)。
#[derive(Debug, Clone, PartialEq, Default)]
pub struct InvestorPositionField {
    /// 合约代码
    pub instrument_id: String,
    /// 持仓方向码(PD_*:'1'净/'2'多/'3'空;map::direction_from 同表)
    pub posi_direction: String,
    /// 上日持仓(YdPosition)
    pub yd_position: f64,
    /// 总持仓(Position)
    pub position: f64,
    /// 今日持仓(TodayPosition)
    pub today_position: f64,
    /// 持仓成本(PositionCost)
    pub position_cost: f64,
    /// 持仓盈亏(PositionProfit)
    pub position_profit: f64,
    /// 空头冻结量(多向仓记其值)
    pub short_frozen: f64,
    /// 多头冻结量(空向仓记其值)
    pub long_frozen: f64,
}

/// 资金行(`CThostFtdcTradingAccountField` 窄面;td `onRspQryTradingAccount`
/// 604-610 行实际取用字段)。
#[derive(Debug, Clone, PartialEq, Default)]
pub struct TradingAccountField {
    /// 账户号
    pub account_id: String,
    /// 当前权益(Balance)
    pub balance: f64,
    /// 冻结的保证金(并进 frozen;原稿 607 三项求和)
    pub frozen_margin: f64,
    /// 冻结的现金
    pub frozen_cash: f64,
    /// 冻结的手续费
    pub frozen_commission: f64,
    /// 可用资金(⚠ 见 DESIGN.md D-AVAIL)
    pub available: f64,
}

/// 下单输入行(原稿 `send_order` 808-842 行 ctp_req 的字段面)。
#[derive(Debug, Clone, PartialEq, Default)]
pub struct InputOrder {
    /// 合约代码
    pub instrument_id: String,
    /// 交易所代码
    pub exchange_id: String,
    /// 委托价
    pub limit_price: f64,
    /// 委托总量(int(req.volume) 截断)
    pub volume_total_original: i64,
    /// 报单价格类型码
    pub order_price_type: String,
    /// 报单方向码
    pub direction: String,
    /// 组合开平标志码
    pub comb_offset_flag: String,
    /// 本地报单号(str(order_ref))
    pub order_ref: String,
    /// 投资者代码
    pub investor_id: String,
    /// 用户代码
    pub user_id: String,
    /// 经纪公司代码
    pub broker_id: String,
    /// 组合投机套保标志('1'=投机)
    pub comb_hedge_flag: String,
    /// 触发条件('1'=立即)
    pub contingent_condition: String,
    /// 强平原因('0'=非强平)
    pub force_close_reason: String,
    /// 自动挂起标志(0)
    pub is_auto_suspend: i32,
    /// 有效期类型码
    pub time_condition: String,
    /// 成交量类型码
    pub volume_condition: String,
    /// 最小成交量(原稿固定 1)
    pub min_volume: i64,
}

/// 撤单输入行(原稿 `cancel_order` 856-872 行 ctp_req 的字段面)。
#[derive(Debug, Clone, PartialEq, Default)]
pub struct InputOrderAction {
    /// 合约代码
    pub instrument_id: String,
    /// 交易所代码
    pub exchange_id: String,
    /// 本地报单号(req.orderid 三段中的第三段)
    pub order_ref: String,
    /// 前置编号
    pub front_id: i64,
    /// 会话编号
    pub session_id: i64,
    /// 报单操作标志('0'=删除,AF_Delete)
    pub action_flag: String,
    /// 经纪公司代码
    pub broker_id: String,
    /// 投资者代码
    pub investor_id: String,
}