Bläddra i källkod

修改okx处理数据account,position,ticker

DESKTOP-F4JN2J4\Citrus_limon 2 år sedan
förälder
incheckning
099153067a
3 ändrade filer med 347 tillägg och 58 borttagningar
  1. 30 25
      standard/src/okx_handle.rs
  2. 316 32
      standard/src/okx_swap.rs
  3. 1 1
      standard/tests/okx_handle_test.rs

+ 30 - 25
standard/src/okx_handle.rs

@@ -1,13 +1,29 @@
 use std::str::FromStr;
 use rust_decimal::Decimal;
-use rust_decimal::prelude::FromPrimitive;
 use rust_decimal_macros::dec;
+use serde::{Deserialize, Serialize};
 use tracing::trace;
 use exchanges::response_base::ResponseData;
 use global::trace_stack::TraceStack;
 use crate::{Account, MarketOrder, Order, Position, PositionModeEnum, SpecialDepth, SpecialOrder, SpecialTicker};
 use crate::exchange::ExchangeEnum;
 use crate::handle_info::HandleSwapInfo;
+use crate::okx_swap::SwapPosition;
+
+#[derive(Debug, Deserialize, Serialize)]
+#[serde(rename_all = "camelCase")]
+struct SwapPositionSubscribe {
+    arg: SwapPositionSubscribeArg,
+    data: Vec<SwapPosition>,
+}
+
+#[derive(Debug, Deserialize, Serialize)]
+#[serde(rename_all = "camelCase")]
+struct SwapPositionSubscribeArg {
+    channel: String,
+    uid: String,
+    inst_type: String,
+}
 
 // 处理账号信息
 pub fn handle_account_info(res_data: ResponseData, symbol: String) -> Account {
@@ -124,36 +140,25 @@ pub fn format_special_ticker(data: serde_json::Value, label: String) -> SpecialD
 // 处理position信息
 pub fn handle_position(res_data: ResponseData, ct_val: Decimal) -> Vec<Position> {
     let res_data_str = res_data.data;
-    let res_data_json: serde_json::Value = serde_json::from_str(&res_data_str).unwrap();
-    let position_data = res_data_json[0]["posData"].clone();
-    let result = format_position_item(position_data, ct_val);
-    return vec![result];
+    let data_list: SwapPositionSubscribe = serde_json::from_str(&res_data_str).unwrap();
+    let position_data = data_list.data;
+    position_data.iter().map(|item| format_position_item(item.clone(), ct_val)).collect()
 }
 
-pub fn format_position_item(position: serde_json::Value, ct_val: Decimal) -> Position {
-    let symbol = position["instId"].as_str().unwrap_or("");
-    let real_leverage = dec!(-1);
-    let currency = position["ccy"].as_str().unwrap_or("");
-    let coin: Vec<&str> = symbol.split("-").collect();
-    let avg_entry_price = Decimal::from_f64(position["avgPx"].as_f64().unwrap()).unwrap();
-    let unrealised_pnl = Decimal::from_f64(position["unrealisedPnl"].as_f64().unwrap()).unwrap();
-    let pos_margin = Decimal::from_f64(position["posSide"].as_f64().unwrap()).unwrap();
-
-    let current_qty = Decimal::from_f64(position["pos"].as_f64().unwrap()).unwrap();
-    let amount = current_qty * ct_val;
-    let position_mode = match amount {
-        amount if amount > Decimal::ZERO => PositionModeEnum::Long,
-        amount if amount < Decimal::ZERO => PositionModeEnum::Short,
+pub fn format_position_item(value: &SwapPosition, ct_val: Decimal) -> Position {
+    let position_mode = match value.pos_side.as_str() {
+        "long" => { PositionModeEnum::Long }
+        "short" => { PositionModeEnum::Short }
         _ => { PositionModeEnum::Both }
     };
     Position {
-        symbol: format!("{}_{}", coin[0], currency),
-        margin_level: real_leverage,
-        amount,
+        symbol: value.inst_id.replace("-SWAP", ""),
+        margin_level: dec!(-1),
+        amount: value.pos * ct_val,
         frozen_amount: Decimal::ZERO,
-        price: avg_entry_price,
-        profit: unrealised_pnl,
+        price: value.avg_px,
+        profit: value.upl,
         position_mode,
-        margin: pos_margin,
+        margin: value.margin,
     }
 }

+ 316 - 32
standard/src/okx_swap.rs

@@ -7,6 +7,7 @@ use futures::stream::FuturesUnordered;
 use futures::TryStreamExt;
 use rust_decimal::Decimal;
 use rust_decimal::prelude::FromPrimitive;
+use serde::{Deserialize, Serialize};
 use serde_json::json;
 use tracing::error;
 use exchanges::okx_swap_rest::OkxSwapRest;
@@ -14,6 +15,284 @@ use global::trace_stack::TraceStack;
 use crate::exchange::ExchangeEnum;
 use crate::{Account, Market, okx_handle, Order, OrderCommand, Platform, Position, Ticker, utils};
 
+/// Okx交易所账户信息请求数据结构
+/// - 接口`"/api/v5/account/balance"`
+///
+/// struct SwapAccount
+/// - `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`: 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: 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,
+}
+
+#[derive(Debug, Clone, Deserialize, Serialize)]
+#[serde(rename_all = "camelCase")]
+struct SwapAccountDetails {
+    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,
+}
+
+/// Okx交易所持仓信息请求数据结构
+/// - 接口`"/api/v5/account/positions"`
+///
+/// struct SwapPosition
+/// - `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")]
+pub struct SwapPosition {
+    pub adl: Decimal,
+    pub avail_pos: Decimal,
+    pub avg_px: Decimal,
+    pub c_time: String,
+    pub ccy: String,
+    pub delta_b_s: String,
+    pub delta_p_a: String,
+    pub gamma_b_s: String,
+    pub gamma_p_a: String,
+    pub imr: String,
+    pub inst_id: String,
+    pub inst_type: String,
+    pub interest: Decimal,
+    pub idx_px: Decimal,
+    pub last: Decimal,
+    pub usd_px: String,
+    pub be_px: Decimal,
+    pub lever: Decimal,
+    pub liab: String,
+    pub liab_ccy: String,
+    pub liq_px: Decimal,
+    pub mark_px: Decimal,
+    pub margin: Decimal,
+    pub mgn_mode: Decimal,
+    pub mgn_ratio: Decimal,
+    pub mmr: Decimal,
+    pub notional_usd: Decimal,
+    pub opt_val: String,
+    pub p_time: String,
+    pub pos: Decimal,
+    pub pos_ccy: String,
+    pub pos_id: Decimal,
+    pub pos_side: String,
+    pub spot_in_use_amt: String,
+    pub spot_in_use_ccy: String,
+    pub theta_b_s: String,
+    pub theta_p_a: String,
+    pub trade_id: Decimal,
+    pub biz_ref_id: String,
+    pub biz_ref_type: String,
+    pub quote_bal: Decimal,
+    pub base_bal: Decimal,
+    pub base_borrowed: String,
+    pub base_interest: String,
+    pub quote_borrowed: String,
+    pub quote_interest: String,
+    pub u_time: String,
+    pub upl: Decimal,
+    pub upl_last_px: Decimal,
+    pub upl_ratio: Decimal,
+    pub upl_ratio_last_px: Decimal,
+    pub vega_b_s: String,
+    pub vega_p_a: String,
+    pub realized_pnl: Decimal,
+    pub pnl: Decimal,
+    pub fee: Decimal,
+    pub funding_fee: Decimal,
+    pub liq_penalty: Decimal,
+    pub close_order_algo: Vec<SwapPositionCloseOrderAlgo>,
+}
+
+#[derive(Debug, Deserialize, Serialize)]
+#[serde(rename_all = "camelCase")]
+pub struct SwapPositionCloseOrderAlgo {
+    pub algo_id: String,
+    pub sl_trigger_px: Decimal,
+    pub sl_trigger_px_type: String,
+    pub tp_trigger_px: Decimal,
+    pub tp_trigger_px_type: String,
+    pub close_fraction: Decimal,
+}
+
+/// Kucoin交易所行情信息请求数据结构
+/// - 接口`"/api/v1/ticker"`
+///
+/// struct SwapTicker
+/// - `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 {
+    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,
+}
+
 #[allow(dead_code)]
 #[derive(Clone)]
 pub struct OkxSwap {
@@ -82,16 +361,20 @@ impl Platform for OkxSwap {
         let res_data = self.request.get_balance(symbol_array[1].to_string()).await;
         if res_data.code == "200" {
             let res_data_str = &res_data.data;
-            let res_data_json: Vec<serde_json::Value> = serde_json::from_str(res_data_str).unwrap();
-            let account_info = res_data_json[0]["details"][0].clone();
-            let available_balance = Decimal::from_str(&account_info["availEq"].as_str().unwrap()).unwrap();
-            let frozen_balance = Decimal::from_str(&account_info["fixedBal"].as_str().unwrap()).unwrap();
-            let balance = available_balance + frozen_balance;
+            let balance_info_list: Vec<SwapAccount> = serde_json::from_str(res_data_str).unwrap();
+            let detail = balance_info_list[0].details.iter().find(|&item| item.ccy == symbol_array[1]);
+            let balance_info: SwapAccountDetails = match detail {
+                None => {
+                    error!("Okx:获取Account信息错误!\nhandle_swap_account:res_data={:?}", res_data);
+                    panic!("Okx:获取Account信息错误!\nhandle_swap_account:res_data={:?}", res_data)
+                }
+                Some(value) => { value.clone() }
+            };
             let result = Account {
-                coin: symbol_array[1].to_string(),
-                balance,
-                available_balance,
-                frozen_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: Decimal::ZERO,
                 available_stocks: Decimal::ZERO,
                 frozen_stocks: Decimal::ZERO,
@@ -112,15 +395,15 @@ impl Platform for OkxSwap {
         let res_data = self.request.get_positions("SWAP".to_string()).await;
         if res_data.code == "200" {
             let res_data_str = &res_data.data;
-            let res_data_json: Vec<serde_json::Value> = serde_json::from_str(res_data_str).unwrap();
-            let position_info = res_data_json.iter().find(|&item| item["instId"].as_str().unwrap() == format!("{}-SWAP", symbol_format));
+            let data_list: Vec<SwapPosition> = serde_json::from_str(&res_data_str).unwrap();
+            let position_info = data_list.iter().find(|&item| item.inst_id == format!("{}-SWAP", symbol_format));
             match position_info {
                 None => {
                     error!("okx_swap:获取Position信息错误!\nget_position:res_data={:?}", res_data_str);
                     panic!("okx_swap:获取Position信息错误!\nget_position:res_data={:?}", res_data_str)
                 }
                 Some(value) => {
-                    let result = okx_handle::format_position_item(value.clone(), ct_val);
+                    let result = okx_handle::format_position_item(value, ct_val);
                     Ok(vec![result])
                 }
             }
@@ -133,8 +416,8 @@ impl Platform for OkxSwap {
         let res_data = self.request.get_positions("SWAP".to_string()).await;
         if res_data.code == "200" {
             let res_data_str = &res_data.data;
-            let res_data_json: Vec<serde_json::Value> = serde_json::from_str(res_data_str).unwrap();
-            let result = res_data_json.iter().map(|item| okx_handle::format_position_item(item.clone(), Decimal::ONE)).collect();
+            let data_list: Vec<SwapPosition> = serde_json::from_str(&res_data_str).unwrap();
+            let result = data_list.iter().map(|item| okx_handle::format_position_item(item.clone(), Decimal::ONE)).collect();
             Ok(result)
         } else {
             Err(Error::new(ErrorKind::Other, res_data.to_string()))
@@ -146,8 +429,8 @@ impl Platform for OkxSwap {
         let res_data = self.request.get_ticker(symbol_format.clone()).await;
         if res_data.code == "200" {
             let res_data_str = &res_data.data;
-            let res_data_json: Vec<serde_json::Value> = serde_json::from_str(res_data_str).unwrap();
-            let ticker_info = res_data_json.iter().find(|item| item["instId"].as_str().unwrap() == format!("{}-SWAP", symbol_format.clone()));
+            let ticker_info_list: Vec<SwapTicker> = serde_json::from_str(&res_data_str).unwrap();
+            let ticker_info = ticker_info_list.iter().find(|item| item.inst_id == format!("{}-SWAP", symbol_format.clone()));
             match ticker_info {
                 None => {
                     error!("okx_swap:获取Ticker信息错误!\nget_ticker:res_data={:?}", res_data_str);
@@ -155,13 +438,13 @@ impl Platform for OkxSwap {
                 }
                 Some(value) => {
                     let result = Ticker {
-                        time: value["ts"].as_str().unwrap().parse().unwrap(),
-                        high: Decimal::from_str(value["high24h"].as_str().unwrap()).unwrap(),
-                        low: Decimal::from_str(value["low24h"].as_str().unwrap()).unwrap(),
-                        sell: Decimal::from_str(value["askPx"].as_str().unwrap()).unwrap(),
-                        buy: Decimal::from_str(value["bidPx"].as_str().unwrap()).unwrap(),
-                        last: Decimal::from_str(value["last"].as_str().unwrap()).unwrap(),
-                        volume: Decimal::from_str(value["lastSz"].as_str().unwrap()).unwrap(),
+                        time: value.ts.parse().unwrap(),
+                        high: value.high24h,
+                        low: value.low24h,
+                        sell: value.ask_px,
+                        buy: value.bid_px,
+                        last: value.last,
+                        volume: value.last_sz,
                     };
                     Ok(result)
                 }
@@ -176,8 +459,8 @@ impl Platform for OkxSwap {
         let res_data = self.request.get_ticker(symbol_format.clone()).await;
         if res_data.code == "200" {
             let res_data_str = &res_data.data;
-            let res_data_json: Vec<serde_json::Value> = serde_json::from_str(res_data_str).unwrap();
-            let ticker_info = res_data_json.iter().find(|item| item["instId"].as_str().unwrap() == format!("{}-SWAP", symbol_format.clone()));
+            let ticker_info_list: Vec<SwapTicker> = serde_json::from_str(&res_data_str).unwrap();
+            let ticker_info = ticker_info_list.iter().find(|item| item.inst_id == format!("{}-SWAP", symbol_format.clone()));
             match ticker_info {
                 None => {
                     error!("okx_swap:获取Ticker信息错误!\nget_ticker:res_data={:?}", res_data_str);
@@ -185,13 +468,13 @@ impl Platform for OkxSwap {
                 }
                 Some(value) => {
                     let result = Ticker {
-                        time: value["ts"].as_str().unwrap().parse().unwrap(),
-                        high: Decimal::from_str(value["high24h"].as_str().unwrap()).unwrap(),
-                        low: Decimal::from_str(value["low24h"].as_str().unwrap()).unwrap(),
-                        sell: Decimal::from_str(value["askPx"].as_str().unwrap()).unwrap(),
-                        buy: Decimal::from_str(value["bidPx"].as_str().unwrap()).unwrap(),
-                        last: Decimal::from_str(value["last"].as_str().unwrap()).unwrap(),
-                        volume: Decimal::from_str(value["lastSz"].as_str().unwrap()).unwrap(),
+                        time: value.ts.parse().unwrap(),
+                        high: value.high24h,
+                        low: value.low24h,
+                        sell: value.ask_px,
+                        buy: value.bid_px,
+                        last: value.last,
+                        volume: value.last_sz,
                     };
                     Ok(result)
                 }
@@ -573,3 +856,4 @@ impl Platform for OkxSwap {
         let _: Result<Vec<_>, _> = futures.try_collect().await;
     }
 }
+

+ 1 - 1
standard/tests/okx_handle_test.rs

@@ -50,7 +50,7 @@ async fn test_get_wss_position() {
     global::log_utils::init_log_with_trace();
 
     let okx_subscribe_type = vec![
-        OkxSubscribeType::PrBalanceAndPosition
+        OkxSubscribeType::PrPositions
     ];
     test_new_exchange_wss(ExchangeEnum::OkxSwap, SYMBOL, okx_subscribe_type, "position").await;
 }