gepangpang пре 2 година
родитељ
комит
ecdcfadf87

+ 1 - 1
exchange_data_formatter/src/binance_handle.rs

@@ -344,7 +344,7 @@ pub(crate) fn handle_swap_market(data: String, symbol: String) -> Market {
     }
 }
 
-/// Binance交易所行情信息请求数据结构
+/// Binance交易所订单信息请求数据结构
 /// - 接口`"/fapi/v1/order"`
 ///
 /// struct SwapOrder

+ 1 - 1
exchange_data_formatter/src/bitget_handle.rs

@@ -197,7 +197,7 @@ pub(crate) fn handle_swap_market(data: String, symbol: String) -> Market {
     }
 }
 
-/// Bitget交易所行情信息请求数据结构
+/// Bitget交易所订单信息请求数据结构
 /// - 接口`"/api/v2/spot/trade/orderInfo`
 ///
 /// struct SpotOrder

+ 1 - 1
exchange_data_formatter/src/gate_handle.rs

@@ -369,7 +369,7 @@ pub(crate) fn handle_swap_market(data: String, symbol: String) -> Market {
     }
 }
 
-/// Gate交易所行情信息请求数据结构
+/// Gate交易所订单信息请求数据结构
 /// - 接口`"/futures/{settle}/orders/{order_id}"`
 ///
 /// struct SwapOrder

+ 1 - 1
exchange_data_formatter/src/kucoin_handle.rs

@@ -364,7 +364,7 @@ pub(crate) fn handle_swap_market(data: String, symbol: String) -> Market {
     }
 }
 
-/// Kucoin交易所行情信息请求数据结构
+/// Kucoin交易所订单信息请求数据结构
 /// - 接口`"/api/v1/orders/{order-id}?clientOid={client-order-id}"`
 ///
 /// struct SwapOrder

+ 397 - 351
exchange_data_formatter/src/okx_handle.rs

@@ -5,63 +5,64 @@ use rust_decimal::prelude::{FromPrimitive, ToPrimitive};
 use rust_decimal_macros::dec;
 use tracing::error;
 use crate::{Account, Market, Order, Position, PositionModeEnum, Ticker, utils};
-use crate::ExchangeEnum::KucoinSwapRest;
+use crate::ExchangeEnum::{KucoinSwapRest, OkxSwapRest};
 
 /// Okx交易所账户信息请求数据结构
 /// - 接口`"/api/v5/account/balance"`
 ///
 /// struct SwapAccount
-/// - `adj_eq·: Decimal,
-/// - `borrow_froz·: Decimal,
-/// - `imr·: Decimal,
-/// - `iso_eq·: Decimal,
-/// - `mgn_ratio·: Decimal,
-/// - `mmr·: Decimal,
-/// - `notional_usd·: Decimal,
-/// - `ord_froz·: Decimal,
-/// - `total_eq·: Decimal,
-/// - `u_time·: String
+/// - `adj_eq`: String, 美金层面有效保证金
+/// - `borrow_froz`: String, 账户美金层面潜在借币占用保证金
+/// - `details`: Vec<SwapAccountDetails>, 各币种资产详细信息
+/// - `imr`: String, 美金层面占用保证金
+/// - `iso_eq`: String, 美金层面逐仓仓位权益
+/// - `mgn_ratio`: String, 美金层面保证金率
+/// - `mmr`: String, 美金层面维持保证金
+/// - `notional_usd`: String, 以美金价值为单位的持仓数量,即仓位美金价值
+/// - `ord_froz`: String, 美金层面全仓挂单占用保证金
+/// - `total_eq`: String, 美金层面权益
+/// - `u_time`: String, 账户信息的更新时间
 ///
 /// struct SwapAccountDetails
-/// - `avail_bal`: Decimal,
-/// - `avail_eq`: Decimal,
-/// - `cash_bal`: Decimal,
-/// - `ccy`: String,
-/// - `cross_liab`: Decimal,
-/// - `dis_eq`: Decimal,
-/// - `eq`: Decimal,
-/// - `eq_usd`: Decimal,
-/// - `fixed_bal`: Decimal,
-/// - `frozen_bal`: Decimal,
-/// - `interest`: Decimal,
-/// - `iso_eq`: Decimal,
-/// - `iso_liab`: Decimal,
-/// - `iso_upl`: Decimal,
-/// - `liab`: Decimal,
-/// - `max_loan`: Decimal,
-/// - `mgn_ratio`: Decimal,
-/// - `notional_lever`: Decimal,
-/// - `ord_frozen`: Decimal,
-/// - `twap`: Decimal,
-/// - `u_time`: String,
-/// - `upl`: Decimal,
-/// - `upl_liab`: Decimal,
-/// - `stgy_eq`: Decimal,
-/// - `spot_in_use_amt`: Decimal,
-/// - `borrow_froz`: Decimal,
+/// - `avail_bal`: Decimal, 可用余额
+/// - `avail_eq`: Decimal, 可用保证金
+/// - `cash_bal`: Decimal, 币种余额
+/// - `ccy`: String, 币种
+/// - `cross_liab`: String, 币种全仓负债额
+/// - `dis_eq`: Decimal, 美金层面币种折算权益
+/// - `eq`: Decimal, 币种总权益
+/// - `eq_usd`: Decimal, 币种权益美金价值
+/// - `fixed_bal`: Decimal, 币种冻结金额
+/// - `frozen_bal`: Decimal, 币种占用金额
+/// - `interest`:String, 计息,应扣未扣利息。
+/// - `iso_eq`: Decimal, 币种逐仓仓位权益
+/// - `iso_liab`: String, 逐仓未实现盈亏
+/// - `iso_upl`: Decimal, 币种逐仓负债额
+/// - `liab`: String, 币种负债额
+/// - `max_loan`: String, 币种最大可借
+/// - `mgn_ratio`: String, 保证金率
+/// - `notional_lever`: Decimal, 币种杠杆倍数
+/// - `ord_frozen`: Decimal, 挂单冻结数量
+/// - `twap`: Decimal, 当前负债币种触发系统自动换币的风险
+/// - `u_time`: String, 币种余额信息的更新时间
+/// - `upl`: Decimal, 未实现盈亏
+/// - `upl_liab`: String, 由于仓位未实现亏损导致的负债
+/// - `stgy_eq`: Decimal, 策略权益
+/// - `spot_in_use_amt`: String, 现货对冲占用数量
+/// - `borrow_froz`: String, 币种美金层面潜在借币占用保证金
 #[derive(Debug, Deserialize, Serialize)]
 #[serde(rename_all = "camelCase")]
 struct SwapAccount {
-    adj_eq: Decimal,
-    borrow_froz: Decimal,
-    details: SwapAccountDetails,
-    imr: Decimal,
-    iso_eq: Decimal,
-    mgn_ratio: Decimal,
-    mmr: Decimal,
-    notional_usd: Decimal,
-    ord_froz: Decimal,
-    total_eq: Decimal,
+    adj_eq: String,
+    borrow_froz: String,
+    details: Vec<SwapAccountDetails>,
+    imr: String,
+    iso_eq: String,
+    mgn_ratio: String,
+    mmr: String,
+    notional_usd: String,
+    ord_froz: String,
+    total_eq: String,
     u_time: String,
 }
 
@@ -72,28 +73,28 @@ struct SwapAccountDetails {
     avail_eq: Decimal,
     cash_bal: Decimal,
     ccy: String,
-    cross_liab: Decimal,
+    cross_liab: String,
     dis_eq: Decimal,
     eq: Decimal,
     eq_usd: Decimal,
     fixed_bal: Decimal,
     frozen_bal: Decimal,
-    interest: Decimal,
+    interest: String,
     iso_eq: Decimal,
-    iso_liab: Decimal,
+    iso_liab: String,
     iso_upl: Decimal,
-    liab: Decimal,
-    max_loan: Decimal,
-    mgn_ratio: Decimal,
+    liab: String,
+    max_loan: String,
+    mgn_ratio: String,
     notional_lever: Decimal,
     ord_frozen: Decimal,
     twap: Decimal,
     u_time: String,
     upl: Decimal,
-    upl_liab: Decimal,
+    upl_liab: String,
     stgy_eq: Decimal,
-    spot_in_use_amt: Decimal,
-    borrow_froz: Decimal,
+    spot_in_use_amt: String,
+    borrow_froz: String,
 }
 
 /// 处理合约本位货币账户信息
@@ -102,104 +103,173 @@ struct SwapAccountDetails {
 ///
 /// - `data`:String, 交易所返回账户信息,JsonString
 /// - `symbol`:String, 交易币对
-pub(crate) fn handle_swap_account(data: String, _symbol: String) -> Account {
+pub(crate) fn handle_swap_account(data: String, symbol: String) -> Account {
+    let symbol_array: Vec<&str> = symbol.split("_").collect();
     let account_info: Vec<SwapAccount> = serde_json::from_str(&data).unwrap();
-    let balance_info: SwapAccountDetails = account_info[0].details.clone();
+    let detail = account_info[0].details.iter().find(|&item| item.ccy == symbol_array[1]);
+    let balance_info: SwapAccountDetails = match detail {
+        None => {
+            error!("Okx:获取Account信息错误!\nhandle_swap_account:data={:?}", data);
+            panic!("Okx:获取Account信息错误!\nhandle_swap_account:data={:?}", data)
+        }
+        Some(value) => { value.clone() }
+    };
     Account {
-        coin: balance_info.currency.to_uppercase(),
-        balance: balance_info.account_equity,
-        available_balance: balance_info.available_balance,
-        frozen_balance: balance_info.account_equity - balance_info.available_balance,
+        coin: balance_info.ccy.to_uppercase(),
+        balance: balance_info.avail_bal + balance_info.fixed_bal,
+        available_balance: balance_info.avail_bal,
+        frozen_balance: balance_info.fixed_bal,
         stocks: dec!(0),
         available_stocks: dec!(0),
         frozen_stocks: dec!(0),
     }
 }
 
-/// Kucoin交易所持仓信息请求数据结构
-/// - 接口`"/api/v1/position"`
+/// Okx交易所持仓信息请求数据结构
+/// - 接口`"/api/v5/account/positions"`
 ///
 /// struct SwapPosition
-/// - `id`: String, 仓位Id
-/// - `symbol`: String, 合约symbol
-/// - `auto_deposit`: bool, 是否自动最佳保证金
-/// - `maint_margin_req`: Decimal, 维持保证金率
-/// - `risk_limit`: Decimal, 风险限额
-/// - `real_leverage`: Decimal, 杠杆倍数
-/// - `cross_mode`: bool, 是否全仓模式
-/// - `delev_percentage`: Decimal, ADL分为数
-/// - `opening_timestamp`: i64, 开仓时间
-/// - `current_timestamp`: i64, 当前时间戳
-/// - `current_qty`: Decimal, 当前仓位数量
-/// - `current_cost`: Decimal, 当前仓位价值
-/// - `current_comm`: Decimal, 当前仓位总费用
-/// - `unrealised_cost`: Decimal, 为实现价值
-/// - `realised_gross_cost`: Decimal, 累计已实现毛利价值
-/// - `realised_cost`: Decimal, 累计已实现仓位价值
-/// - `is_open`: bool, 是否开仓
-/// - `mark_price`: Decimal, 标记价格
-/// - `mark_value`: Decimal, 标记价值
-/// - `pos_cost`: Decimal, 仓位价值
-/// - `pos_cross`:Decimal, 追加到仓位的保证金
-/// - `pos_init`: Decimal, 杠杆保证金
-/// - `pos_comm`: Decimal, 破产费用
-/// - `pos_loss`: Decimal, 资金费用最少的资金
-/// - `pos_margin`:Decimal, 仓位保证金
-/// - `pos_maint`: Decimal, 维持保证金
-/// - `maint_margin`: Decimal, 包含未实现盈亏的仓位保证金
-/// - `realised_gross_pnl`: Decimal, 累计已实现毛利
-/// - `realised_pnl`: Decimal, 已实现盈亏
-/// - `unrealised_pnl`: Decimal, 未实现盈亏
-/// - `unrealised_pnl_pcnt`:Decimal, 仓位盈亏率
-/// - `unrealised_roe_pcnt`:Decimal, 投资回报率
-/// - `avg_entry_price`: Decimal, 平均开仓价格
-/// - `liquidation_price`: Decimal, 强平价格
-/// - `bankrupt_price`: Decimal, 破产价格
-/// - `settle_currency`:String, 结算币种
-/// - `maintain_margin`: Decimal, 维持保证金率
-/// - `user_id`: i64,
-/// - `risk_limit_level`: Decimal 当前风险限额等级
+/// - `adl`: Decimal, 信号区
+/// - `avail_pos`: Decimal, 可平仓数量,适用于 币币杠杆,交割/永续(开平仓模式)
+/// - `avg_px`: Decimal, 开仓平均价
+/// - `c_time`: String, 持仓创建时间
+/// - `ccy`: String, 占用保证金的币种
+/// - `delta_b_s`: String, 美金本位持仓仓位delta,仅适用于期权
+/// - `delta_p_a`: String, 币本位持仓仓位delta,仅适用于期权
+/// - `gamma_b_s`: String, 美金本位持仓仓位gamma,仅适用于期权
+/// - `gamma_p_a`: String, 币本位持仓仓位gamma,仅适用于期权
+/// - `imr`: String, 初始保证金,仅适用于全仓
+/// - `inst_id`: String, 产品ID
+/// - `inst_type`: String, 产品类型
+/// - `interest`: Decimal, 利息,已经生成的未扣利息
+/// - `idx_px`: Decimal, 最新指数价格
+/// - `last`: Decimal, 最新成交价
+/// - `usd_px`: String, 美金价格
+/// - `be_px`: Decimal, 盈亏平衡价
+/// - `lever`: Decimal, 杠杆倍数,不适用于期权
+/// - `liab`: String, 负债额,仅适用于币币杠杆
+/// - `liab_ccy`: String, 负债币种,仅适用于币币杠杆
+/// - `liq_px`: Decimal, 预估强平价
+/// - `mark_px`: Decimal, 最新标记价格
+/// - `margin`: Decimal, 保证金余额,可增减,仅适用于逐仓
+/// - `mgn_mode`: Decimal, 保证金模式
+/// - `mgn_ratio`: Decimal, 保证金率
+/// - `mmr`: Decimal, 维持保证金
+/// - `notional_usd`: Decimal, 以美金价值为单位的持仓数量
+/// - `opt_val`: String, 期权市值,仅适用于期权
+/// - `p_time`: String,
+/// - `pos`: Decimal, 持仓数量,逐仓自主划转模式下,转入保证金后会产生pos为0的仓位
+/// - `pos_ccy`: String, 仓位资产币种,仅适用于币币杠杆仓位
+/// - `pos_id`: Decimal, 持仓ID
+/// - `pos_side`: String, 持仓方向
+/// - `spot_in_use_amt`: String,
+/// - `spot_in_use_ccy`: String,
+/// - `theta_b_s`: String, 美金本位持仓仓位theta,仅适用于期权
+/// - `theta_p_a`: String, 币本位持仓仓位theta,仅适用于期权
+/// - `trade_id`: Decimal, 最新成交ID
+/// - `biz_ref_id`: String, 外部业务id
+/// - `biz_ref_type`: String, 外部业务类型
+/// - `quote_bal`: Decimal, 计价币余额 ,适用于 币币杠杆(逐仓自主划转模式 和 一键借币模式)
+/// - `base_bal`: Decimal, 交易币余额,适用于 币币杠杆(逐仓自主划转模式 和 一键借币模式)
+/// - `base_borrowed`: String, 交易币已借,适用于 币币杠杆(逐仓一键借币模式)
+/// - `base_interest`: String, 交易币计息,适用于 币币杠杆(逐仓一键借币模式)
+/// - `quote_borrowed`: String, 计价币已借,适用于 币币杠杆(逐仓一键借币模式)
+/// - `quote_interest`: String, 计价币计息,适用于 币币杠杆(逐仓一键借币模式)
+/// - `u_time`: String, 最近一次持仓更新时间
+/// - `upl`: Decimal, 未实现收益(以标记价格计算)
+/// - `upl_last_px`: Decimal, 以最新成交价格计算的未实现收益,主要做展示使用,实际值还是 upl
+/// - `upl_ratio`: Decimal, 未实现收益率(以标记价格计算
+/// - `upl_ratio_last_px`: Decimal, 以最新成交价格计算的未实现收益率
+/// - `vega_b_s`: String, 美金本位持仓仓位vega,仅适用于期权
+/// - `vega_p_a`: String, 币本位持仓仓位vega,仅适用于期权
+/// - `realized_pnl`: Decimal, 已实现收益
+/// - `pnl`: Decimal, 平仓订单累计收益额
+/// - `fee`: Decimal, 累计手续费金额,正数代表平台返佣 ,负数代表平台扣除
+/// - `funding_fee`: Decimal, 累计资金费用
+/// - `liq_penalty`: Decimal, 累计爆仓罚金,有值时为负数。
+/// - `close_order_algo`: Vec<SwapPositionCloseOrderAlgo>, 	平仓策略委托订单
+///
+/// struct SwapPositionCloseOrderAlgo
+///
+/// - `algo_id`: String, 策略委托单ID
+/// - `sl_trigger_px`: Decimal, 止损触发价
+/// - `sl_trigger_px_type`: String, 止损触发价类型
+/// - `tp_trigger_px`: Decimal, 止盈委托价
+/// - `tp_trigger_px_type`: String, 止盈触发价类型
+/// - `close_fraction`: Decimal, 策略委托触发时
 #[derive(Debug, Deserialize, Serialize)]
 #[serde(rename_all = "camelCase")]
 struct SwapPosition {
-    id: String,
-    symbol: String,
-    auto_deposit: bool,
-    maint_margin_req: Decimal,
-    risk_limit: Decimal,
-    real_leverage: Decimal,
-    cross_mode: bool,
-    delev_percentage: Decimal,
-    opening_timestamp: i64,
-    current_timestamp: i64,
-    current_qty: Decimal,
-    current_cost: Decimal,
-    current_comm: Decimal,
-    unrealised_cost: Decimal,
-    realised_gross_cost: Decimal,
-    realised_cost: Decimal,
-    is_open: bool,
-    mark_price: Decimal,
-    mark_value: Decimal,
-    pos_cost: Decimal,
-    pos_cross: Decimal,
-    pos_init: Decimal,
-    pos_comm: Decimal,
-    pos_loss: Decimal,
-    pos_margin: Decimal,
-    pos_maint: Decimal,
-    maint_margin: Decimal,
-    realised_gross_pnl: Decimal,
-    realised_pnl: Decimal,
-    unrealised_pnl: Decimal,
-    unrealised_pnl_pcnt: Decimal,
-    unrealised_roe_pcnt: Decimal,
-    avg_entry_price: Decimal,
-    liquidation_price: Decimal,
-    bankrupt_price: Decimal,
-    settle_currency: String,
-    maintain_margin: Decimal,
-    risk_limit_level: Decimal,
+    adl: Decimal,
+    avail_pos: Decimal,
+    avg_px: Decimal,
+    c_time: String,
+    ccy: String,
+    delta_b_s: String,
+    delta_p_a: String,
+    gamma_b_s: String,
+    gamma_p_a: String,
+    imr: String,
+    inst_id: String,
+    inst_type: String,
+    interest: Decimal,
+    idx_px: Decimal,
+    last: Decimal,
+    usd_px: String,
+    be_px: Decimal,
+    lever: Decimal,
+    liab: String,
+    liab_ccy: String,
+    liq_px: Decimal,
+    mark_px: Decimal,
+    margin: Decimal,
+    mgn_mode: Decimal,
+    mgn_ratio: Decimal,
+    mmr: Decimal,
+    notional_usd: Decimal,
+    opt_val: String,
+    p_time: String,
+    pos: Decimal,
+    pos_ccy: String,
+    pos_id: Decimal,
+    pos_side: String,
+    spot_in_use_amt: String,
+    spot_in_use_ccy: String,
+    theta_b_s: String,
+    theta_p_a: String,
+    trade_id: Decimal,
+    biz_ref_id: String,
+    biz_ref_type: String,
+    quote_bal: Decimal,
+    base_bal: Decimal,
+    base_borrowed: String,
+    base_interest: String,
+    quote_borrowed: String,
+    quote_interest: String,
+    u_time: String,
+    upl: Decimal,
+    upl_last_px: Decimal,
+    upl_ratio: Decimal,
+    upl_ratio_last_px: Decimal,
+    vega_b_s: String,
+    vega_p_a: String,
+    realized_pnl: Decimal,
+    pnl: Decimal,
+    fee: Decimal,
+    funding_fee: Decimal,
+    liq_penalty: Decimal,
+    close_order_algo: Vec<SwapPositionCloseOrderAlgo>,
+}
+
+#[derive(Debug, Deserialize, Serialize)]
+#[serde(rename_all = "camelCase")]
+struct SwapPositionCloseOrderAlgo {
+    algo_id: String,
+    sl_trigger_px: Decimal,
+    sl_trigger_px_type: String,
+    tp_trigger_px: Decimal,
+    tp_trigger_px_type: String,
+    close_fraction: Decimal,
 }
 
 /// 处理合约仓位信息
@@ -210,51 +280,68 @@ struct SwapPosition {
 /// - `symbol`:String, 交易币对
 /// - `ct_val`:Decimal, 张数价值
 pub(crate) fn handle_swap_position(data: String, symbol: String, ct_val: Decimal) -> Vec<Position> {
-    let exchange_symbol = utils::symbol_mapper(KucoinSwapRest, &symbol);
-    let position_info: SwapPosition = serde_json::from_str(&data).unwrap();
-    let coin = position_info.symbol[..symbol.find(&position_info.settle_currency).unwrap() - 1].to_string();
-    let base_asset = if coin == exchange_symbol.base_asset.clone() { coin } else { exchange_symbol.base_asset.clone() };
-    vec![Position {
-        symbol: format!("{}_{}", base_asset, position_info.settle_currency),
-        margin_level: position_info.real_leverage,
-        amount: position_info.current_qty * ct_val,
-        frozen_amount: dec!(0),
-        price: position_info.avg_entry_price,
-        profit: position_info.unrealised_pnl,
-        position_mode: if position_info.current_qty * ct_val > dec!(0) { PositionModeEnum::Long } else { PositionModeEnum::Short },
-        margin: position_info.pos_margin,
-    }]
+    let exchange_symbol = utils::symbol_mapper(OkxSwapRest, &symbol);
+    let symbol_format = utils::format_symbol(exchange_symbol.symbol, "-");
+    let data_list: Vec<SwapPosition> = serde_json::from_str(&data).unwrap();
+    let position_info_list = if symbol != "" { data_list.iter().filter(|&item| item.inst_id == format!("{}-SWAP", symbol_format)).collect() } else { data_list };
+    position_info_list.iter().map(|&item| {
+        let position_mode = match item.pos_side.as_str() {
+            "long" => { PositionModeEnum::Long }
+            "short" => { PositionModeEnum::Short }
+            _ => { PositionModeEnum::Both }
+        };
+        Position {
+            symbol: item.inst_id.replace("-SWAP", ""),
+            margin_level: dec!(-1),
+            amount: item.pos * ct_val,
+            frozen_amount: dec!(0),
+            price: item.avg_px,
+            profit: item.upl,
+            position_mode,
+            margin: item.margin,
+        }
+    }).collect()
 }
 
 /// Kucoin交易所行情信息请求数据结构
 /// - 接口`"/api/v1/ticker"`
 ///
 /// struct SwapTicker
-/// - `sequence`: i64, 顺序号
-/// - `symbol`: String, 合约
-/// - `side`: String, 成交方向
-/// - `size`: Decimal, 成交数量
-/// - `price`: Decimal, 成交价格
-/// - `best_bid_size`: Decimal,	最佳买一价总量
-/// - `best_bid_price`: Decimal, 最佳买一价
-/// - `best_ask_size`: Decimal, 最佳卖一价总量
-/// - `best_ask_price`: Decimal, 最佳卖一价
-/// - `trade_id`: String, 交易号
-/// - `ts`: Decimal, 成交时间
-#[derive(Debug, Deserialize, Serialize)]
+/// - `inst_type`: String, 产品类型
+/// - `inst_id`: String, 产品ID
+/// - `last`: Decimal, 最新成交价
+/// - `last_sz`: Decimal, 最新成交的数量
+/// - `ask_px`: Decimal, 卖一价
+/// - `ask_sz`: Decimal, 卖一价的挂单数数量
+/// - `bid_px`: Decimal, 买一价
+/// - `bid_sz`: Decimal, 买一价的挂单数量
+/// - `open24h`: Decimal, 24小时开盘价
+/// - `high24h`: Decimal, 24小时最高价
+/// - `low24h`: Decimal, 24小时最低价
+/// - `vol_ccy24h`: Decimal, 24小时成交量,以币为单位
+/// - `vol24h`: Decimal, 24小时成交量,以张为单位
+/// - `ts`: String, ticker数据产生时间
+/// - `sod_utc0`: Decimal, UTC 0 时开盘价
+/// - `sod_utc8`: Decimal, UTC+8 时开盘价
+#[derive(Debug, Clone, Deserialize, Serialize)]
 #[serde(rename_all = "camelCase")]
 struct SwapTicker {
-    sequence: i64,
-    symbol: String,
-    side: String,
-    size: Decimal,
-    price: Decimal,
-    best_bid_size: Decimal,
-    best_bid_price: Decimal,
-    best_ask_size: Decimal,
-    best_ask_price: Decimal,
-    trade_id: String,
-    ts: Decimal,
+    inst_type: String,
+    inst_id: String,
+    last: Decimal,
+    last_sz: Decimal,
+    ask_px: Decimal,
+    ask_sz: Decimal,
+    bid_px: Decimal,
+    bid_sz: Decimal,
+    open24h: Decimal,
+    high24h: Decimal,
+    low24h: Decimal,
+    vol_ccy24h: Decimal,
+    vol24h: Decimal,
+    ts: String,
+    sod_utc0: Decimal,
+    sod_utc8: Decimal,
 }
 
 /// 处理合约行情信息
@@ -264,133 +351,82 @@ struct SwapTicker {
 /// - `data`:String, 交易所返回账户信息,JsonString
 /// - `symbol`:String, 交易币对
 pub(crate) fn handle_swap_ticker(data: String, _symbol: String) -> Ticker {
-    let ticker_info: SwapTicker = serde_json::from_str(&data).unwrap();
+    let ticker_info_list: Vec<SwapTicker> = serde_json::from_str(&data).unwrap();
+    let ticker_info = ticker_info_list[0].clone();
     Ticker {
-        time: (ticker_info.ts / dec!(1000000)).to_i64().unwrap(),
-        high: ticker_info.best_ask_price,
-        low: ticker_info.best_bid_price,
-        sell: ticker_info.best_ask_price,
-        buy: ticker_info.best_bid_price,
-        last: ticker_info.price,
-        volume: ticker_info.size,
+        time: ticker_info.ts.parse().unwrap(),
+        high: ticker_info.high24h,
+        low: ticker_info.low24h,
+        sell: ticker_info.ask_px,
+        buy: ticker_info.bid_px,
+        last: ticker_info.last,
+        volume: ticker_info.last_sz,
     }
 }
 
-/// Kucoin交易所行情信息请求数据结构
+/// Okx交易所行情信息请求数据结构
 /// - 接口`/api/v1/contracts/active"`
 ///
 /// struct SwapMarket
-/// - `symbol`: String, 合约名称
-/// - `root_symbol`: String, 合约系列
-/// - `contract_type`: String, 合约类型
-/// - `first_open_date`: Decimal, 首次开放时间
-/// - `expire_date`: Decimal, 到期日期,为Null表示永不过期
-/// - `settle_date`: Decimal, 结算日期,为Null表示不支持自动结算
-/// - `base_currency`: String, 基础货币
-/// - `quote_currency`: String, 计价货币
-/// - `settle_currency`: String, 结算币种
-/// - `max_order_qty`: Decimal, 最大委托数量
-/// - `max_price`: Decimal, 最大下单价格
-/// - `lot_size`: Decimal, 最小合约数量
-/// - `tick_size`: Decimal, 最小的价格变化
-/// - `index_price_tick_size`: Decimal, 指数价格变化步长
-/// - `multiplier`: Decimal, 合约乘数
-/// - `initial_margin`: Decimal, 初始保证金率
-/// - `maintain_margin`: Decimal, 维持保证金率
-/// - `max_risk_limit`: Decimal, 最大风险限额(以XBT为单位)
-/// - `min_risk_limit`: Decimal, 最小风险限额(以XBT为单位)
-/// - `risk_step`: Decimal, 风险限额递增值(以XBT为单位)
-/// - `maker_fee_rate`: Decimal, marker手续费
-/// - `taker_fee_rate`: Decimal, taker手续费
-/// - `settlement_fee`: Decimal, 结算手续费
-/// - `is_deleverage`: bool, 是否支持自动减仓
-/// - `is_inverse`: bool, 是否是反向合约
-/// - `mark_method`: String, 标记方式
-/// - `fair_method`: String, 合理标记方式
-/// - `funding_base_symbol`: String, 基础货币symbol
-/// - `funding_quote_symbol`: String, 计价货币symbol
-/// - `funding_rate_symbol`: String, 资金货币symbol
-/// - `index_symbol`: String, 指数symbol
-/// - `settlement_symbol`: String, 结算symbol
-/// - `status`: String, 合约状态(Init:初始、Open:已上线、BeingSettled:结算中、Settled:已结算、Paused:已暂停、Closed:已下线、CancelOnly:只能撤单)
-/// - `funding_fee_rate`: Decimal, 资金费率值
-/// - `predicted_funding_fee_rate`: Decimal, 预测资金费率值
-/// - `open_interest`: Decimal, 活动仓位数
-/// - `turnover_of24h`: Decimal, 24小时成交额
-/// - `volume_of24h`: Decimal, 24小时成交量
-/// - `mark_price`: Decimal, 标记价格
-/// - `index_price`: Decimal, 指数价格
-/// - `last_trade_price`: Decimal, 最新成交额
-/// - `next_funding_rate_time`: Decimal, 下次资金费率时间
-/// - `max_leverage`: Decimal, 最大可用杠杆
-/// - `source_exchanges`: Vec<String>, 该合约指数来源交易所
-/// - `premiums_symbol1m`: String, 溢价指数symbol(1分钟)
-/// - `premiums_symbol8h`: String, 溢价指数symbol(8小时)
-/// - `funding_base_symbol1m`: String, 基础货币利率symbol(1分钟)
-/// - `funding_quote_symbol1m`: String, 计价货币利率symbol(1分钟)
-/// - `low_price`: Decimal, 24小时最低成交价
-/// - `high_price`: Decimal, 24小时最高成交价
-/// - `price_chg_pct`: Decimal, 24小时涨跌幅
-/// - `price_chg`: Decimal, 24小时涨跌价格
+/// - `alias`: String,
+/// - `base_ccy`: String,
+/// - `category: String,
+/// - `ct_mult`: Decimal,
+/// - `ct_type`: String,
+/// - `ct_val`: Decimal,
+/// - `ct_val_vcy`: String,
+/// - `exp_time`: String,
+/// - `inst_family`: String,
+/// - `inst_id`: String,
+/// - `inst_type`: String,
+/// - `lever`: Decimal,
+/// - `list_time`: String,
+/// - `lot_sz`: Decimal,
+/// - `max_iceberg_sz`: Decimal,
+/// - `max_lmt_sz`: Decimal,
+/// - `max_mkt_sz`: Decimal,
+/// - `max_stop_sz`: Decimal,
+/// - `max_trigger_sz`: Decimal,
+/// - `max_twap_sz`: Decimal,
+/// - `min_sz`: Decimal,
+/// - `opt_type`: String,
+/// - `quote_ccy`: String,
+/// - `settle_ccy`: String,
+/// - `state`: String,
+/// - `stk`: String,
+/// - `tick_sz`: Decimal,
+/// - `uly`: String
 #[derive(Debug, Deserialize, Serialize)]
 #[serde(rename_all = "camelCase")]
 struct SwapMarket {
-    symbol: String,
-    root_symbol: String,
-    #[serde(rename = "type")]
-    contract_type: String,
-    first_open_date: Option<Decimal>,
-    expire_date: Option<Decimal>,
-    settle_date: Option<Decimal>,
-    base_currency: String,
-    quote_currency: String,
-    settle_currency: String,
-    max_order_qty: Decimal,
-    max_price: Decimal,
-    lot_size: Decimal,
-    tick_size: Decimal,
-    index_price_tick_size: Decimal,
-    multiplier: Decimal,
-    initial_margin: Decimal,
-    maintain_margin: Decimal,
-    max_risk_limit: Decimal,
-    min_risk_limit: Decimal,
-    risk_step: Decimal,
-    maker_fee_rate: Decimal,
-    taker_fee_rate: Decimal,
-    taker_fix_fee: Decimal,
-    maker_fix_fee: Decimal,
-    settlement_fee: Option<Decimal>,
-    is_deleverage: bool,
-    is_quanto: bool,
-    is_inverse: bool,
-    mark_method: String,
-    fair_method: String,
-    funding_base_symbol: String,
-    funding_quote_symbol: String,
-    funding_rate_symbol: String,
-    index_symbol: String,
-    settlement_symbol: Option<String>,
-    status: String,
-    funding_fee_rate: Decimal,
-    predicted_funding_fee_rate: Decimal,
-    open_interest: Decimal,
-    turnover_of24h: Decimal,
-    volume_of24h: Decimal,
-    mark_price: Decimal,
-    index_price: Decimal,
-    last_trade_price: Decimal,
-    next_funding_rate_time: Decimal,
-    max_leverage: Decimal,
-    source_exchanges: Vec<String>,
-    premiums_symbol_1_m: String,
-    premiums_symbol_8_h: String,
-    funding_base_symbol_1_m: String,
-    funding_quote_symbol_1_m: String,
-    low_price: Decimal,
-    high_price: Decimal,
-    price_chg_pct: Decimal,
-    price_chg: Decimal,
+    alias: String,
+    base_ccy: String,
+    category: String,
+    ct_mult: Decimal,
+    ct_type: String,
+    ct_val: Decimal,
+    ct_val_vcy: String,
+    exp_time: String,
+    inst_family: String,
+    inst_id: String,
+    inst_type: String,
+    lever: Decimal,
+    list_time: String,
+    lot_sz: Decimal,
+    max_iceberg_sz: Decimal,
+    max_lmt_sz: Decimal,
+    max_mkt_sz: Decimal,
+    max_stop_sz: Decimal,
+    max_trigger_sz: Decimal,
+    max_twap_sz: Decimal,
+    min_sz: Decimal,
+    opt_type: String,
+    quote_ccy: String,
+    settle_ccy: String,
+    state: String,
+    stk: String,
+    tick_sz: Decimal,
+    uly: String,
 }
 
 /// 处理合约行情信息
@@ -400,37 +436,36 @@ struct SwapMarket {
 /// - `data`:String, 交易所返回账户信息,JsonString
 /// - `symbol`:String, 交易币对
 pub(crate) fn handle_swap_market(data: String, symbol: String) -> Market {
-    let exchange_symbol = utils::symbol_mapper(KucoinSwapRest, &symbol);
-    let symbol_format = format!("{}M", utils::format_symbol(exchange_symbol.exchange_symbol.clone(), ""));
+    let exchange_symbol = utils::symbol_mapper(OkxSwapRest, &symbol);
+    let symbol_format = format!("{}-SWAP", utils::format_symbol(exchange_symbol.symbol.clone(), "-"));
     let market_info_list: Vec<SwapMarket> = serde_json::from_str(&data).unwrap();
     let market_info = market_info_list.iter().find(|&item| item.symbol == symbol_format);
     match market_info {
         None => {
-            error!("Kucoin:获取Market信息错误!\nhandle_swap_market:data={:?}", data);
-            panic!("Kucoin:获取Market信息错误!\nhandle_swap_market:data={:?}", data)
+            error!("Okx:获取Market信息错误!\nhandle_swap_market:data={:?}", data);
+            panic!("Okx:获取Market信息错误!\nhandle_swap_market:data={:?}", data)
         }
         Some(value) => {
-            let base_asset = if value.base_currency == exchange_symbol.base_asset.clone() { &value.base_currency } else { &exchange_symbol.base_asset };
             Market {
-                symbol: format!("{}_{}", base_asset.clone(), value.quote_currency),
-                base_asset: base_asset.clone(),
-                quote_asset: value.quote_currency.clone(),
-                tick_size: value.tick_size.clone(),
-                amount_size: value.lot_size * value.multiplier,
-                price_precision: Decimal::from_u32(value.tick_size.scale()).unwrap(),
-                amount_precision: Decimal::from_u32((value.lot_size * value.multiplier).scale()).unwrap(),
-                min_qty: value.lot_size,
-                max_qty: value.max_order_qty,
-                min_notional: value.lot_size * value.multiplier,
-                max_notional: value.max_price,
-                ct_val: value.multiplier,
+                symbol: format!("{}_{}", value.base_ccy, value.quote_ccy),
+                base_asset: value.base_ccy.clone(),
+                quote_asset: value.quote_ccy.clone(),
+                tick_size: value.tick_sz,
+                amount_size: value.min_sz * value.ct_val,
+                price_precision: Decimal::from_u32(value.tick_sz.scale()).unwrap(),
+                amount_precision: Decimal::from_u32((value.min_sz * value.ct_val).scale()).unwrap(),
+                min_qty: value.min_sz * value.ct_val,
+                max_qty: value.max_lmt_sz * value.ct_val,
+                min_notional: value.min_sz * value.ct_val,
+                max_notional: value.max_mkt_sz * value.ct_val,
+                ct_val: value.ct_val,
             }
         }
     }
 }
 
-/// Kucoin交易所行情信息请求数据结构
-/// - 接口`"/api/v1/orders/{order-id}?clientOid={client-order-id}"`
+/// Okx交易所订单信息请求数据结构
+/// - 接口`"/api/v5/trade/order"`
 ///
 /// struct SwapOrder
 /// `id`: String 订单编号
@@ -472,43 +507,54 @@ pub(crate) fn handle_swap_market(data: String, symbol: String) -> Market {
 #[derive(Debug, Deserialize, Serialize)]
 #[serde(rename_all = "camelCase")]
 struct SwapOrder {
-    id: String,
-    symbol: String,
-    #[serde(rename = "type")]
-    order_type: String,
-    side: String,
-    price: Decimal,
-    size: Decimal,
-    value: Decimal,
-    deal_value: Decimal,
-    deal_size: Decimal,
-    stp: Option<String>,
-    stop: String,
-    stop_price_type: String,
-    stop_triggered: bool,
-    stop_price: Option<Decimal>,
-    time_in_force: String,
-    post_only: bool,
-    hidden: bool,
-    iceberg: bool,
-    leverage: Decimal,
-    force_hold: bool,
-    close_order: bool,
-    visible_size: Option<Decimal>,
-    client_oid: String,
-    remark: Option<String>,
-    tags: Option<String>,
-    is_active: bool,
-    cancel_exist: bool,
-    created_at: i64,
-    updated_at: i64,
-    end_at: Option<i64>,
-    order_time: i128,
-    settle_currency: String,
-    status: String,
-    filled_value: Decimal,
-    filled_size: Decimal,
-    reduce_only: bool,
+    inst_type:String,
+    inst_id:String,
+    ccy:String,
+    ord_id:String,
+    cl_ord_id:String,
+    tag:String,
+    px:Decimal,
+    px_usd:String,
+    px_vol:String,
+    px_type:String,
+    sz:Decimal,
+    pnl:Decimal,
+    ord_type:String,
+    side:String,
+    pos_side:String,
+    td_mode:String,
+    acc_fill_sz:Decimal,
+    fill_px:Decimal,
+    trade_id:String,
+    fill_sz:Decimal,
+    fill_time:String,
+    source: "",
+    state:String,
+    avg_px:Decimal,
+    lever:Decimal,
+    attach_algo_cl_ord_id:String,
+    tp_trigger_px:Decimal,
+    tp_trigger_px_type:String,
+    tp_ord_px:Decimal,
+    sl_trigger_px:Decimal,
+    sl_trigger_px_type:String,
+    sl_ord_px:Decimal,
+    stp_id:String,
+    stp_mode:String,
+    fee_ccy:String,
+    fee:Decimal,
+    rebate_ccy:String,
+    rebate:"",
+    tgt_ccy:"",
+    category:"",
+    reduce_only: "false",
+    cancel_source: "20",
+    cancel_source_reason: "Cancel all after triggered",
+    quick_mgn_type: "",
+    algo_cl_ord_id: "",
+    algo_id: "",
+    u_time:"1597026383085",
+    c_time:"1597026383085"
 }
 
 /// 处理合约订单信息

+ 2 - 0
exchange_data_formatter/tests/okx_handle_test.rs

@@ -1,4 +1,6 @@
+use rust_decimal::Decimal;
 use rust_decimal_macros::dec;
+use serde_json::json;
 use tracing::{instrument, trace};
 use exchange_data_formatter::{Exchange, ExchangeEnum};