gepangpang 2 lat temu
rodzic
commit
6b1d33ab44

+ 8 - 1
exchange_data_formatter/src/lib.rs

@@ -5,6 +5,7 @@ mod binance_handle;
 mod gate_handle;
 mod kucoin_handle;
 mod bitget_handle;
+mod okx_handle;
 
 /// 持仓模式枚举
 /// - `Both`:单持仓方向
@@ -216,6 +217,8 @@ impl Order {
 /// - `KucoinSwapRest`: Kucoin交易所期货请求消息;
 /// - `BitgetSpotWss`: Bitget交易所现货订阅消息;
 /// - `BitgetSpotRest`: Bitget交易所现货请求消息;
+/// - `OkxSwapWss`: Okx交易所期货订阅消息;
+/// - `OkxSwapRest`: Okx交易所期货请求消息;
 #[derive(Debug, Clone, PartialEq, Eq)]
 pub enum ExchangeEnum {
     BinanceSwapWss,
@@ -230,7 +233,8 @@ pub enum ExchangeEnum {
     KucoinSwapRest,
     BitgetSpotWss,
     BitgetSpotRest,
-
+    OkxSwapWss,
+    OkxSwapRest,
 }
 
 pub struct Exchange {
@@ -256,6 +260,9 @@ impl Exchange {
             ExchangeEnum::KucoinSwapRest => {
                 kucoin_handle::handle_swap_account(data, self.symbol.clone())
             }
+            ExchangeEnum::OkxSwapRest => {
+                okx_handle::handle_swap_account(data, self.symbol.clone())
+            }
             _ => {
                 panic!()
             }

+ 547 - 0
exchange_data_formatter/src/okx_handle.rs

@@ -0,0 +1,547 @@
+use std::fmt::Debug;
+use serde::{Deserialize, Serialize};
+use rust_decimal::Decimal;
+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;
+
+/// 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
+///
+/// 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,
+#[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,
+    u_time: String,
+}
+
+#[derive(Debug, Clone, Deserialize, Serialize)]
+#[serde(rename_all = "camelCase")]
+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,
+}
+
+/// 处理合约本位货币账户信息
+///
+/// pub(crate) fn handle_account(data: String, symbol: String) -> Account;
+///
+/// - `data`:String, 交易所返回账户信息,JsonString
+/// - `symbol`:String, 交易币对
+pub(crate) fn handle_swap_account(data: String, _symbol: String) -> Account {
+    let account_info: Vec<SwapAccount> = serde_json::from_str(&data).unwrap();
+    let balance_info: SwapAccountDetails = account_info[0].details.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,
+        stocks: dec!(0),
+        available_stocks: dec!(0),
+        frozen_stocks: dec!(0),
+    }
+}
+
+/// Kucoin交易所持仓信息请求数据结构
+/// - 接口`"/api/v1/position"`
+///
+/// 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 当前风险限额等级
+#[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,
+}
+
+/// 处理合约仓位信息
+///
+/// pub(crate) fn handle_swap_position(data: String, symbol: String, ct_val: Decimal) -> Vec<Position>;
+///
+/// - `data`:String, 交易所返回账户信息,JsonString
+/// - `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,
+    }]
+}
+
+/// 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)]
+#[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,
+}
+
+/// 处理合约行情信息
+///
+/// pub(crate) fn handle_swap_ticker(data: String, symbol: String) -> Ticker;
+///
+/// - `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();
+    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,
+    }
+}
+
+/// Kucoin交易所行情信息请求数据结构
+/// - 接口`/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小时涨跌价格
+#[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,
+}
+
+/// 处理合约行情信息
+///
+/// pub(crate) fn handle_swap_market(data: String, symbol: String) -> Market ;
+///
+/// - `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 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)
+        }
+        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,
+            }
+        }
+    }
+}
+
+/// Kucoin交易所行情信息请求数据结构
+/// - 接口`"/api/v1/orders/{order-id}?clientOid={client-order-id}"`
+///
+/// struct SwapOrder
+/// `id`: String 订单编号
+/// `symbol`: String, 合约编号
+/// `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, timeInForce类型
+/// `post_only`: bool, postOnly标志
+/// `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, 订单状态open或done
+/// `filled_value`: Decimal, 已经成交订单价值
+/// `filled_size`: Decimal, 已经成交订单数量
+/// `reduce_only`: bool, 只减仓标记
+#[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,
+}
+
+/// 处理合约订单信息
+///
+/// pub(crate) fn handle_swap_order(data: String, ct_val: Decimal) -> Order;
+///
+/// - `data`:String, 交易所返回账户信息,JsonString
+/// - `ct_val`:Decimal, 张数价值
+pub(crate) fn handle_swap_order(data: String, ct_val: Decimal) -> Order {
+    let order_info: SwapOrder = serde_json::from_str(&data).unwrap();
+
+    let status = order_info.status;
+    let deal_amount = order_info.filled_size * ct_val;
+    let avg_price = if deal_amount.is_zero() { dec!(0) } else { order_info.filled_value / deal_amount };
+    let custom_status = match status.as_str() {
+        "open" => { "NEW".to_string() }
+        "cancelled" => { "REMOVE".to_string() }
+        "closed" => { "REMOVE".to_string() }
+        "finished" => { "REMOVE".to_string() }
+        _ => {
+            error!("Kucoin:格式化订单状态错误!\nhandle_swap_order:status={}", status);
+            panic!("Kucoin:格式化订单状态错误!\nhandle_swap_order:status={}", status)
+        }
+    };
+
+    Order {
+        id: order_info.id,
+        custom_id: order_info.client_oid,
+        price: order_info.price,
+        amount: order_info.size * ct_val,
+        deal_amount,
+        avg_price,
+        status: custom_status,
+        order_type: order_info.order_type,
+    }
+}

+ 15 - 0
exchange_data_formatter/tests/okx_handle_test.rs

@@ -0,0 +1,15 @@
+use rust_decimal_macros::dec;
+use tracing::{instrument, trace};
+use exchange_data_formatter::{Exchange, ExchangeEnum};
+
+// 测试获取账号信息
+#[tokio::test]
+#[instrument(level = "TRACE")]
+async fn test_handle_account() {
+    global::log_utils::init_log_with_trace();
+
+    let data = "[{\"adjEq\":\"\",\"borrowFroz\":\"\",\"details\":[{\"availBal\":\"28.9505905\",\"availEq\":\"28.9505905\",\"borrowFroz\":\"\",\"cashBal\":\"28.9505905\",\"ccy\":\"USDT\",\"crossLiab\":\"\",\"disEq\":\"28.96159172439\",\"eq\":\"28.9505905\",\"eqUsd\":\"28.96159172439\",\"fixedBal\":\"0\",\"frozenBal\":\"0\",\"interest\":\"\",\"isoEq\":\"0\",\"isoLiab\":\"\",\"isoUpl\":\"0\",\"liab\":\"\",\"maxLoan\":\"\",\"mgnRatio\":\"\",\"notionalLever\":\"0\",\"ordFrozen\":\"0\",\"spotInUseAmt\":\"\",\"spotIsoBal\":\"0\",\"stgyEq\":\"0\",\"twap\":\"0\",\"uTime\":\"1697535693932\",\"upl\":\"0\",\"uplLiab\":\"\"}],\"imr\":\"\",\"isoEq\":\"0\",\"mgnRatio\":\"\",\"mmr\":\"\",\"notionalUsd\":\"\",\"ordFroz\":\"\",\"totalEq\":\"29.82127110700236\",\"uTime\":\"1698659144409\"}]";
+    let exchange = Exchange::new(ExchangeEnum::OkxSwapRest, "BTC_USDT".to_string());
+    let result = exchange.handle_account(data.to_string());
+    trace!(?result);
+}