Browse Source

修改okx新架构格式化数据

gepangpang 2 years ago
parent
commit
6f9dcf89e9

+ 1 - 1
exchanges/src/okx_swap_rest.rs

@@ -181,7 +181,7 @@ impl OkxSwapRest {
     pub async fn swap_order(&mut self, params: serde_json::Value) -> ResponseData {
         let data = self.request("POST".to_string(),
                                 "/api/v5".to_string(),
-                                "/sprd/order".to_string(),
+                                "/trade/order".to_string(),
                                 true,
                                 params.to_string(),
         ).await;

+ 2 - 1
standard/Cargo.toml

@@ -17,4 +17,5 @@ rust_decimal_macros = "1.32.0"
 chrono = "0.4.30"
 futures = "0.3"
 tracing = "0.1"
-tracing-subscriber = { version = "0.3.17", features = ["env-filter"] }
+tracing-subscriber = { version = "0.3.17", features = ["env-filter"] }
+toml = "0.5.11"

+ 2 - 2
standard/src/okx_handle.rs

@@ -153,12 +153,12 @@ pub fn format_position_item(value: &SwapPosition, ct_val: Decimal) -> Position {
     };
     Position {
         symbol: value.inst_id.replace("-SWAP", ""),
-        margin_level: dec!(-1),
+        margin_level: value.lever,
         amount: value.pos * ct_val,
         frozen_amount: Decimal::ZERO,
         price: value.avg_px,
         profit: value.upl,
         position_mode,
-        margin: value.margin,
+        margin: if value.margin != "" { Decimal::from_str(&value.margin).unwrap() } else { Decimal::ZERO },
     }
 }

+ 325 - 135
standard/src/okx_swap.rs

@@ -180,8 +180,8 @@ struct SwapAccountDetails {
 #[derive(Debug, Deserialize, Serialize)]
 #[serde(rename_all = "camelCase")]
 pub struct SwapPosition {
-    pub adl: Decimal,
-    pub avail_pos: Decimal,
+    pub adl: String,
+    pub avail_pos: String,
     pub avg_px: Decimal,
     pub c_time: String,
     pub ccy: String,
@@ -192,52 +192,51 @@ pub struct SwapPosition {
     pub imr: String,
     pub inst_id: String,
     pub inst_type: String,
-    pub interest: Decimal,
-    pub idx_px: Decimal,
-    pub last: Decimal,
+    pub interest: String,
+    pub idx_px: String,
+    pub last: String,
     pub usd_px: String,
-    pub be_px: Decimal,
+    pub be_px: String,
     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 liq_px: String,
+    pub mark_px: String,
+    pub margin: String,
+    pub mgn_mode: String,
+    pub mgn_ratio: String,
+    pub mmr: String,
+    pub notional_usd: String,
     pub opt_val: String,
-    pub p_time: String,
     pub pos: Decimal,
     pub pos_ccy: String,
-    pub pos_id: Decimal,
+    pub pos_id: String,
     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 trade_id: String,
     pub biz_ref_id: String,
     pub biz_ref_type: String,
-    pub quote_bal: Decimal,
-    pub base_bal: Decimal,
+    pub quote_bal: String,
+    pub base_bal: String,
     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 upl_last_px: String,
+    pub upl_ratio: String,
+    pub upl_ratio_last_px: String,
     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 realized_pnl: String,
+    pub pnl: String,
+    pub fee: String,
+    pub funding_fee: String,
+    pub liq_penalty: String,
     pub close_order_algo: Vec<SwapPositionCloseOrderAlgo>,
 }
 
@@ -245,15 +244,15 @@ pub struct SwapPosition {
 #[serde(rename_all = "camelCase")]
 pub struct SwapPositionCloseOrderAlgo {
     pub algo_id: String,
-    pub sl_trigger_px: Decimal,
+    pub sl_trigger_px: String,
     pub sl_trigger_px_type: String,
-    pub tp_trigger_px: Decimal,
+    pub tp_trigger_px: String,
     pub tp_trigger_px_type: String,
-    pub close_fraction: Decimal,
+    pub close_fraction: String,
 }
 
-/// Kucoin交易所行情信息请求数据结构
-/// - 接口`"/api/v1/ticker"`
+/// Okx交易所行情信息请求数据结构
+/// - 接口`"/api/v5/market/ticker"`
 ///
 /// struct SwapTicker
 /// - `inst_type`: String, 产品类型
@@ -293,6 +292,176 @@ struct SwapTicker {
     sod_utc8: Decimal,
 }
 
+/// Okx交易所市场信息请求数据结构
+/// - 接口`"/api/v5/public/instruments"`
+///
+/// struct SwapMarket
+/// - `alias`: String,
+/// - `base_ccy`: String,
+/// - `category`: String,
+/// - `ct_mult`: Decimal,
+/// - `ct_type`: String,
+/// - `ct_val`: Decimal,
+/// - `ct_val_ccy`: 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, Clone, Deserialize, Serialize)]
+#[serde(rename_all = "camelCase")]
+struct SwapMarket {
+    alias: String,
+    base_ccy: String,
+    category: String,
+    ct_mult: Decimal,
+    ct_type: String,
+    ct_val: Decimal,
+    ct_val_ccy: 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,
+}
+
+/// Okx交易所订单信息请求数据结构
+/// - 接口`"/api/v5/trade/order"`
+///
+/// struct SwapOrder
+/// - `inst_type`: String, 产品类型
+/// - `inst_id`: String, 产品ID
+/// - `ccy`: String, 保证金币种
+/// - `ord_id`: String, 订单ID
+/// - `cl_ord_id`: String, 客户自定义订单ID
+/// - `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`: String, 最新成交价格,如果成交数量为0,该字段为""
+/// - `trade_id`: String, 最新成交ID
+/// - `fill_sz`: Decimal, 最新成交数量
+/// - `fill_time`: String, 最新成交时间
+/// - `source`: String, 订单来源
+/// - `state`: String, 订单状态
+/// - `avg_px`: Decimal, 成交均价,如果成交数量为0,该字段也为""
+/// - `lever`: Decimal, 杠杆倍数
+/// - `attach_algo_cl_ord_id`: String, 下单附带止盈止损时,客户自定义的策略订单ID
+/// - `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, 自成交保护ID
+/// - `stp_mode`: String, 自成交保护模式
+/// - `fee_ccy`: String, 交易手续费币种
+/// - `fee`: Decimal, 手续费与返佣
+/// - `rebate_ccy`: String, 返佣金币种
+/// - `rebate`: String, 返佣金额,仅适用于币币和杠杆
+/// - `tgt_ccy`: String, 币币市价单委托数量sz的单位
+/// - `category`: String, 订单种类
+/// - `reduce_only`: String, 是否只减仓
+/// - `cancel_source`: String, 	订单取消来源的原因枚举值代码
+/// - `cancel_source_reason`: String, 订单取消来源的对应具体原因
+/// - `quick_mgn_type`: String, 一键借币类型,仅适用于杠杆逐仓的一键借币模式
+/// - `algo_cl_ord_id`: String, 客户自定义策略订单ID
+/// - `algo_id`: String, 策略委托单ID,策略订单触发时有值,否则为""
+/// - `u_time`: String, 订单状态更新时间
+/// - `c_time`: String, 订单创建时间
+#[derive(Debug, Clone, Deserialize, Serialize)]
+#[serde(rename_all = "camelCase")]
+pub struct SwapOrder {
+    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: String,
+    ord_type: String,
+    side: String,
+    pos_side: String,
+    td_mode: String,
+    acc_fill_sz: Decimal,
+    fill_px: String,
+    trade_id: String,
+    fill_sz: String,
+    fill_time: String,
+    source: String,
+    state: String,
+    avg_px: String,
+    lever: String,
+    attach_algo_cl_ord_id: String,
+    tp_trigger_px: String,
+    tp_trigger_px_type: String,
+    tp_ord_px: String,
+    sl_trigger_px: String,
+    sl_trigger_px_type: String,
+    sl_ord_px: String,
+    stp_id: String,
+    stp_mode: String,
+    fee_ccy: String,
+    fee: String,
+    rebate_ccy: String,
+    rebate: String,
+    tgt_ccy: String,
+    category: String,
+    reduce_only: String,
+    cancel_source: String,
+    cancel_source_reason: String,
+    quick_mgn_type: String,
+    algo_cl_ord_id: String,
+    algo_id: String,
+    u_time: String,
+    c_time: String,
+}
+
 #[allow(dead_code)]
 #[derive(Clone)]
 pub struct OkxSwap {
@@ -363,23 +532,24 @@ impl Platform for OkxSwap {
             let res_data_str = &res_data.data;
             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 {
+            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: 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,
-            };
-            Ok(result)
+                Some(value) => {
+                    let result = Account {
+                        coin: value.ccy.to_uppercase(),
+                        balance: value.avail_bal + value.fixed_bal,
+                        available_balance: value.avail_bal,
+                        frozen_balance: value.fixed_bal,
+                        stocks: Decimal::ZERO,
+                        available_stocks: Decimal::ZERO,
+                        frozen_stocks: Decimal::ZERO,
+                    };
+                    Ok(result)
+                }
+            }
         } else {
             Err(Error::new(ErrorKind::Other, res_data.to_string()))
         }
@@ -390,23 +560,15 @@ impl Platform for OkxSwap {
     }
 
     async fn get_position(&mut self) -> Result<Vec<Position>, Error> {
-        let symbol_format = utils::format_symbol(self.symbol.to_string(), "-");
+        let symbol_format = format!("{}-SWAP", utils::format_symbol(self.symbol.to_string(), "-"));
         let ct_val = self.market.ct_val;
         let res_data = self.request.get_positions("SWAP".to_string()).await;
         if res_data.code == "200" {
             let res_data_str = &res_data.data;
             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, ct_val);
-                    Ok(vec![result])
-                }
-            }
+            let position_info: Vec<&SwapPosition> = data_list.iter().filter(|item| item.inst_id == symbol_format).collect();
+            let result = position_info.iter().map(|item| okx_handle::format_position_item(item, ct_val)).collect();
+            Ok(result)
         } else {
             Err(Error::new(ErrorKind::Other, res_data.to_string()))
         }
@@ -425,12 +587,12 @@ impl Platform for OkxSwap {
     }
 
     async fn get_ticker(&mut self) -> Result<Ticker, Error> {
-        let symbol_format = utils::format_symbol(self.symbol.clone(), "-");
+        let symbol_format = format!("{}-SWAP", utils::format_symbol(self.symbol.clone(), "-"));
         let res_data = self.request.get_ticker(symbol_format.clone()).await;
         if res_data.code == "200" {
             let res_data_str = &res_data.data;
             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()));
+            let ticker_info = ticker_info_list.iter().find(|item| item.inst_id == symbol_format);
             match ticker_info {
                 None => {
                     error!("okx_swap:获取Ticker信息错误!\nget_ticker:res_data={:?}", res_data_str);
@@ -455,12 +617,12 @@ impl Platform for OkxSwap {
     }
 
     async fn get_ticker_symbol(&mut self, symbol: String) -> Result<Ticker, Error> {
-        let symbol_format = utils::format_symbol(symbol.clone(), "-");
+        let symbol_format = format!("{}-SWAP", utils::format_symbol(symbol.clone(), "-"));
         let res_data = self.request.get_ticker(symbol_format.clone()).await;
         if res_data.code == "200" {
             let res_data_str = &res_data.data;
             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()));
+            let ticker_info = ticker_info_list.iter().find(|item| item.inst_id == symbol_format);
             match ticker_info {
                 None => {
                     error!("okx_swap:获取Ticker信息错误!\nget_ticker:res_data={:?}", res_data_str);
@@ -489,41 +651,29 @@ impl Platform for OkxSwap {
         let res_data = self.request.get_instruments().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 market_info = res_data_json.iter().find(|item| item["instId"].as_str().unwrap() == format!("{}-SWAP", symbol_format));
+            let res_data_json: Vec<SwapMarket> = serde_json::from_str(res_data_str).unwrap();
+            let market_info = res_data_json.iter().find(|item| item.inst_id == format!("{}-SWAP", symbol_format));
             match market_info {
                 None => {
                     error!("okx_swap:获取Market信息错误!\nget_market:res_data={:?}", res_data_str);
                     panic!("okx_swap:获取Market信息错误!\nget_market:res_data={:?}", res_data_str)
                 }
                 Some(value) => {
-                    let base_asset = value["ctValCcy"].as_str().unwrap_or("").to_string();
-                    let quote_asset = value["settleCcy"].as_str().unwrap_or("").to_string();
-                    let tick_size = Decimal::from_str(&value["tickSz"].as_str().unwrap()).unwrap();
-                    let min_qty = Decimal::from_str(&value["minSz"].as_str().unwrap()).unwrap();
-                    let max_qty = Decimal::from_str(&value["maxLmtSz"].as_str().unwrap()).unwrap();
-                    let ct_val = Decimal::from_str(&value["ctVal"].as_str().unwrap()).unwrap();
-
-
-                    let amount_size = min_qty * ct_val;
-                    let price_precision = Decimal::from_u32(tick_size.scale()).unwrap();
-                    let amount_precision = Decimal::from_u32(amount_size.scale()).unwrap();
-                    let min_notional = min_qty * ct_val;
-                    let max_notional = max_qty * ct_val;
-
+                    println!("{:?}", value);
+                    let symbol_array: Vec<&str> = value.inst_family.split("-").collect();
                     let result = Market {
-                        symbol: format!("{}_{}", base_asset, quote_asset),
-                        base_asset,
-                        quote_asset,
-                        tick_size,
-                        amount_size,
-                        price_precision,
-                        amount_precision,
-                        min_qty,
-                        max_qty,
-                        min_notional,
-                        max_notional,
-                        ct_val,
+                        symbol: format!("{}_{}", symbol_array[0], symbol_array[1]),
+                        base_asset: symbol_array[0].to_string(),
+                        quote_asset: symbol_array[1].to_string(),
+                        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,
+                        max_qty: value.max_lmt_sz,
+                        min_notional: value.min_sz * value.ct_val,
+                        max_notional: value.max_lmt_sz * value.ct_val,
+                        ct_val: value.ct_val,
                     };
                     Ok(result)
                 }
@@ -538,41 +688,28 @@ impl Platform for OkxSwap {
         let res_data = self.request.get_instruments().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 market_info = res_data_json.iter().find(|item| item["instId"].as_str().unwrap() == format!("{}-SWAP", symbol_format));
+            let res_data_json: Vec<SwapMarket> = serde_json::from_str(res_data_str).unwrap();
+            let market_info = res_data_json.iter().find(|item| item.inst_id == format!("{}-SWAP", symbol_format));
             match market_info {
                 None => {
                     error!("okx_swap:获取Market信息错误!\nget_market:res_data={:?}", res_data_str);
                     panic!("okx_swap:获取Market信息错误!\nget_market:res_data={:?}", res_data_str)
                 }
                 Some(value) => {
-                    let base_asset = value["ctValCcy"].as_str().unwrap_or("").to_string();
-                    let quote_asset = value["settleCcy"].as_str().unwrap_or("").to_string();
-                    let tick_size = Decimal::from_str(&value["tickSz"].as_str().unwrap()).unwrap();
-                    let min_qty = Decimal::from_str(&value["minSz"].as_str().unwrap()).unwrap();
-                    let max_qty = Decimal::from_str(&value["maxLmtSz"].as_str().unwrap()).unwrap();
-                    let ct_val = Decimal::from_str(&value["ctVal"].as_str().unwrap()).unwrap();
-
-
-                    let amount_size = min_qty * ct_val;
-                    let price_precision = Decimal::from_u32(tick_size.scale()).unwrap();
-                    let amount_precision = Decimal::from_u32(amount_size.scale()).unwrap();
-                    let min_notional = min_qty * ct_val;
-                    let max_notional = max_qty * ct_val;
-
+                    let symbol_array: Vec<&str> = value.inst_family.split("-").collect();
                     let result = Market {
-                        symbol: format!("{}_{}", base_asset, quote_asset),
-                        base_asset,
-                        quote_asset,
-                        tick_size,
-                        amount_size,
-                        price_precision,
-                        amount_precision,
-                        min_qty,
-                        max_qty,
-                        min_notional,
-                        max_notional,
-                        ct_val,
+                        symbol: format!("{}_{}", symbol_array[0], symbol_array[1]),
+                        base_asset: symbol_array[0].to_string(),
+                        quote_asset: symbol_array[1].to_string(),
+                        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,
+                        max_qty: value.max_lmt_sz,
+                        min_notional: value.min_sz * value.ct_val,
+                        max_notional: value.max_lmt_sz * value.ct_val,
+                        ct_val: value.ct_mult,
                     };
                     Ok(result)
                 }
@@ -583,13 +720,14 @@ impl Platform for OkxSwap {
     }
 
     async fn get_order_detail(&mut self, order_id: &str, custom_id: &str) -> Result<Order, Error> {
+        let symbol_format = format!("{}-SWAP", utils::format_symbol(self.symbol.clone(), "-"));
         let ct_val = self.market.ct_val;
-        let res_data = self.request.get_order(self.symbol.clone(), order_id.to_string(), custom_id.to_string()).await;
+        let res_data = self.request.get_order(symbol_format, order_id.to_string(), custom_id.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 res_data_json: Vec<SwapOrder> = serde_json::from_str(res_data_str).unwrap();
             let order_info = res_data_json[0].clone();
-            let result = okx_handle::format_order_item(order_info, ct_val);
+            let result = format_order_item(order_info, ct_val);
             Ok(result)
         } else {
             Err(Error::new(ErrorKind::Other, res_data.to_string()))
@@ -597,13 +735,14 @@ impl Platform for OkxSwap {
     }
 
     async fn get_orders_list(&mut self, _status: &str) -> Result<Vec<Order>, Error> {
-        let symbol_format = utils::format_symbol(self.symbol.clone(), "-");
+        let symbol_format = format!("{}-SWAP", utils::format_symbol(self.symbol.clone(), "-"));
         let ct_val = self.market.ct_val;
         let res_data = self.request.get_incomplete_order(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 result = res_data_json.iter().map(|item| okx_handle::format_order_item(item.clone(), ct_val)).collect();
+            println!("{}", res_data_str);
+            let res_data_json: Vec<SwapOrder> = serde_json::from_str(res_data_str).unwrap();
+            let result = res_data_json.iter().map(|item| format_order_item(item.clone(), ct_val)).collect();
             Ok(result)
         } else {
             Err(Error::new(ErrorKind::Other, res_data.to_string()))
@@ -611,7 +750,7 @@ impl Platform for OkxSwap {
     }
 
     async fn take_order(&mut self, custom_id: &str, origin_side: &str, price: Decimal, amount: Decimal) -> Result<Order, Error> {
-        let symbol_format = utils::format_symbol(self.symbol.clone(), "-");
+        let symbol_format = format!("{}-SWAP", utils::format_symbol(self.symbol.clone(), "-"));
         let ct_val = self.market.ct_val;
         let mut params = json!({
             "tdMode": "cross",
@@ -625,23 +764,40 @@ impl Platform for OkxSwap {
         match origin_side {
             "kd" => {
                 params["side"] = json!("buy");
+                params["posSide"] = json!("long");
             }
             "pd" => {
                 params["side"] = json!("sell");
+                params["posSide"] = json!("long");
             }
             "kk" => {
                 params["side"] = json!("sell");
+                params["posSide"] = json!("short");
             }
             "pk" => {
                 params["side"] = json!("buy");
+                params["posSide"] = json!("short");
             }
             _ => { error!("下单参数错误"); }
         };
         let res_data = self.request.swap_order(params).await;
         if res_data.code == "200" {
             let res_data_str = &res_data.data;
-            let res_data_json: serde_json::Value = serde_json::from_str(res_data_str).unwrap();
-            let result = okx_handle::format_order_item(res_data_json, ct_val);
+            let res_data_json: Vec<serde_json::Value> = serde_json::from_str(res_data_str).unwrap();
+            let order_info = res_data_json[0].clone();
+            let id = order_info["ordId"].as_str().unwrap().to_string();
+            let custom_id = order_info["clOrdId"].as_str().unwrap().to_string();
+            let result = Order {
+                id,
+                custom_id,
+                price,
+                amount,
+                deal_amount: Decimal::ZERO,
+                avg_price: Decimal::ZERO,
+                status: "NEW".to_string(),
+                order_type: "".to_string(),
+                trace_stack: TraceStack::default().on_special("798 okx_swap".to_string()),
+            };
             Ok(result)
         } else {
             Err(Error::new(ErrorKind::Other, res_data.to_string()))
@@ -649,7 +805,7 @@ impl Platform for OkxSwap {
     }
 
     async fn take_order_symbol(&mut self, symbol: String, ct_val: Decimal, custom_id: &str, origin_side: &str, price: Decimal, amount: Decimal) -> Result<Order, Error> {
-        let symbol_format = utils::format_symbol(symbol.clone(), "-");
+        let symbol_format = format!("{}-SWAP", utils::format_symbol(symbol.clone(), "-"));
         let mut params = json!({
             "tdMode": "cross",
             "clOrdId": custom_id.to_string(),
@@ -662,23 +818,40 @@ impl Platform for OkxSwap {
         match origin_side {
             "kd" => {
                 params["side"] = json!("buy");
+                params["posSide"] = json!("long");
             }
             "pd" => {
                 params["side"] = json!("sell");
+                params["posSide"] = json!("long");
             }
             "kk" => {
                 params["side"] = json!("sell");
+                params["posSide"] = json!("short");
             }
             "pk" => {
                 params["side"] = json!("buy");
+                params["posSide"] = json!("short");
             }
             _ => { error!("下单参数错误"); }
         };
         let res_data = self.request.swap_order(params).await;
         if res_data.code == "200" {
             let res_data_str = &res_data.data;
-            let res_data_json: serde_json::Value = serde_json::from_str(res_data_str).unwrap();
-            let result = okx_handle::format_order_item(res_data_json, ct_val);
+            let res_data_json: Vec<serde_json::Value> = serde_json::from_str(res_data_str).unwrap();
+            let order_info = res_data_json[0].clone();
+            let id = order_info["ordId"].as_str().unwrap().to_string();
+            let custom_id = order_info["clOrdId"].as_str().unwrap().to_string();
+            let result = Order {
+                id,
+                custom_id,
+                price,
+                amount,
+                deal_amount: Decimal::ZERO,
+                avg_price: Decimal::ZERO,
+                status: "NEW".to_string(),
+                order_type: "".to_string(),
+                trace_stack: TraceStack::default().on_special("852 okx_swap".to_string()),
+            };
             Ok(result)
         } else {
             Err(Error::new(ErrorKind::Other, res_data.to_string()))
@@ -686,12 +859,8 @@ impl Platform for OkxSwap {
     }
 
     async fn cancel_order(&mut self, order_id: &str, custom_id: &str) -> Result<Order, Error> {
-        let symbol_format = utils::format_symbol(self.symbol.clone(), "-");
+        let symbol_format = format!("{}-SWAP", utils::format_symbol(self.symbol.clone(), "-"));
         let res_data = self.request.cancel_order(symbol_format, order_id.to_string(), custom_id.to_string()).await;
-        if order_id == "" {
-            error!("okx_swap:撤销订单错误,该交易所为提供自定义订单号撤销订单!\ncancel_order:order_id={:?},custom_id={:?}", order_id, custom_id);
-            panic!("okx_swap:撤销订单错误,该交易所为提供自定义订单号撤销订单!\ncancel_order:order_id={:?},custom_id={:?}", order_id, custom_id)
-        }
         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();
@@ -707,7 +876,7 @@ impl Platform for OkxSwap {
                 avg_price: Decimal::ZERO,
                 status: "REMOVE".to_string(),
                 order_type: "".to_string(),
-                trace_stack: TraceStack::default().on_special("428 okx_handle".to_string()),
+                trace_stack: TraceStack::default().on_special("854 okx_swap".to_string()),
             };
             Ok(result)
         } else {
@@ -735,7 +904,7 @@ impl Platform for OkxSwap {
     }
 
     async fn set_dual_leverage(&mut self, leverage: &str) -> Result<String, Error> {
-        let symbol_format = utils::format_symbol(self.symbol.clone(), "-");
+        let symbol_format = format!("{}-SWAP", utils::format_symbol(self.symbol.clone(), "-"));
         let res_data = self.request.set_leverage(symbol_format, leverage.to_string()).await;
         if res_data.code == "200" {
             let res_data_str = &res_data.data;
@@ -857,3 +1026,24 @@ impl Platform for OkxSwap {
     }
 }
 
+pub fn format_order_item(data: SwapOrder, ct_val: Decimal) -> Order {
+    let custom_status = if ["canceled", "filled", "mmp_canceled"].contains(&data.state.as_str()) {
+        "REMOVE".to_string()
+    } else if ["live", "partially_filled"].contains(&data.state.as_str()) {
+        "NEW".to_string()
+    } else {
+        "NULL".to_string()
+    };
+
+    Order {
+        id: data.ord_id,
+        custom_id: data.cl_ord_id,
+        price: data.px,
+        amount: data.sz * ct_val,
+        deal_amount: data.acc_fill_sz * ct_val,
+        avg_price: if data.avg_px != "" { Decimal::from_str(&data.avg_px).unwrap() } else { Decimal::ZERO },
+        status: custom_status,
+        order_type: data.ord_type,
+        trace_stack: TraceStack::default().on_special("1022 okx_swap".to_string()),
+    }
+}

+ 81 - 21
standard/tests/exchange_test.rs

@@ -1,10 +1,13 @@
 use std::collections::{BTreeMap};
 use std::{env};
-use std::io::Error;
+use std::fs::File;
+use toml::from_str;
+use std::io::{Error, Read};
 use std::sync::Arc;
 use std::sync::atomic::AtomicBool;
 use std::time::Duration;
 use rust_decimal_macros::dec;
+use serde::Deserialize;
 use tokio::sync::mpsc::{channel, Receiver, Sender};
 use tokio::try_join;
 use tracing::{error, trace};
@@ -21,50 +24,107 @@ use standard::exchange::{Exchange, ExchangeEnum};
 use standard::{kucoin_spot_handle, Order, Platform, utils};
 // use standard::{bitget_spot_handle, Order, Platform, utils};
 
+#[derive(Debug, Deserialize, Clone)]
+pub struct AccountInfo {
+    pub gate_access_key: String,
+    pub gate_secret_key: String,
+    pub binance_access_key: String,
+    pub binance_secret_key: String,
+    pub kucoin_access_key: String,
+    pub kucoin_secret_key: String,
+    pub kucoin_pass: String,
+    pub okx_access_key: String,
+    pub okx_secret_key: String,
+    pub okx_pass: String,
+    pub bitget_access_key: String,
+    pub bitget_secret_key: String,
+    pub bitget_pass: String,
+}
+
+impl AccountInfo {
+    pub fn new() -> AccountInfo {
+        AccountInfo {
+            gate_access_key: "".to_string(),
+            gate_secret_key: "".to_string(),
+            binance_access_key: "".to_string(),
+            binance_secret_key: "".to_string(),
+            kucoin_access_key: "".to_string(),
+            kucoin_secret_key: "".to_string(),
+            kucoin_pass: "".to_string(),
+            okx_access_key: "".to_string(),
+            okx_secret_key: "".to_string(),
+            okx_pass: "".to_string(),
+            bitget_access_key: "".to_string(),
+            bitget_secret_key: "".to_string(),
+            bitget_pass: "".to_string(),
+        }
+    }
+}
+
+// 获取文件内容
+pub fn get_account_info(file_path: &str) -> AccountInfo {
+    let mut file = File::open(file_path);
+    let mut contents = String::new();
+    let result = match file {
+        Ok(mut value) => {
+            value.read_to_string(&mut contents).unwrap_or_default();
+            from_str(&contents).unwrap_or(AccountInfo::new())
+        }
+        Err(_) => {
+            trace!("没有获取到账号配置文件!");
+            AccountInfo::new()
+        }
+    };
+    result
+}
+
+
 // 创建实体
 #[allow(dead_code)]
 pub async fn test_new_exchange(exchange: ExchangeEnum, symbol: &str) -> Box<dyn Platform> {
     utils::proxy_handle();
     let (order_sender, _order_receiver): (Sender<Order>, Receiver<Order>) = channel(1024);
     let (error_sender, _error_receiver): (Sender<Error>, Receiver<Error>) = channel(1024);
+
+    let account_info = get_account_info("config.toml");
     match exchange {
         ExchangeEnum::BinanceSwap => {
             let mut params: BTreeMap<String, String> = BTreeMap::new();
-            let access_key = env::var("binance_access_key").unwrap_or("".to_string());
-            let secret_key = env::var("binance_secret_key").unwrap_or("".to_string());
+            let access_key = account_info.binance_access_key;
+            let secret_key = account_info.binance_secret_key;
             params.insert("access_key".to_string(), access_key);
             params.insert("secret_key".to_string(), secret_key);
             Exchange::new(exchange, symbol.to_string(), false, params, order_sender, error_sender).await
         }
         ExchangeEnum::BinanceSpot => {
             let mut params: BTreeMap<String, String> = BTreeMap::new();
-            let access_key = env::var("binance_access_key").unwrap_or("".to_string());
-            let secret_key = env::var("binance_secret_key").unwrap_or("".to_string());
+            let access_key = account_info.binance_access_key;
+            let secret_key = account_info.binance_secret_key;
             params.insert("access_key".to_string(), access_key);
             params.insert("secret_key".to_string(), secret_key);
             Exchange::new(exchange, symbol.to_string(), false, params, order_sender, error_sender).await
         }
         ExchangeEnum::GateSwap => {
             let mut params: BTreeMap<String, String> = BTreeMap::new();
-            let access_key = env::var("gate_access_key").unwrap_or("".to_string());
-            let secret_key = env::var("gate_secret_key").unwrap_or("".to_string());
+            let access_key = account_info.gate_access_key;
+            let secret_key = account_info.gate_secret_key;
             params.insert("access_key".to_string(), access_key);
             params.insert("secret_key".to_string(), secret_key);
             Exchange::new(exchange, symbol.to_string(), false, params, order_sender, error_sender).await
         }
         ExchangeEnum::GateSpot => {
             let mut params: BTreeMap<String, String> = BTreeMap::new();
-            let access_key = env::var("gate_access_key").unwrap_or("".to_string());
-            let secret_key = env::var("gate_secret_key").unwrap_or("".to_string());
+            let access_key = account_info.gate_access_key;
+            let secret_key = account_info.gate_secret_key;
             params.insert("access_key".to_string(), access_key);
             params.insert("secret_key".to_string(), secret_key);
             Exchange::new(exchange, symbol.to_string(), false, params, order_sender, error_sender).await
         }
         ExchangeEnum::KucoinSwap => {
             let mut params: BTreeMap<String, String> = BTreeMap::new();
-            let access_key = env::var("kucoin_access_key").unwrap_or("".to_string());
-            let secret_key = env::var("kucoin_secret_key").unwrap_or("".to_string());
-            let pass_key = env::var("kucoin_pass_key").unwrap_or("".to_string());
+            let access_key = account_info.kucoin_access_key;
+            let secret_key = account_info.kucoin_secret_key;
+            let pass_key = account_info.kucoin_pass;
             params.insert("access_key".to_string(), access_key);
             params.insert("secret_key".to_string(), secret_key);
             params.insert("pass_key".to_string(), pass_key);
@@ -72,9 +132,9 @@ pub async fn test_new_exchange(exchange: ExchangeEnum, symbol: &str) -> Box<dyn
         }
         ExchangeEnum::KucoinSpot => {
             let mut params: BTreeMap<String, String> = BTreeMap::new();
-            let access_key = env::var("kucoin_access_key").unwrap_or("".to_string());
-            let secret_key = env::var("kucoin_secret_key").unwrap_or("".to_string());
-            let pass_key = env::var("kucoin_pass_key").unwrap_or("".to_string());
+            let access_key = account_info.kucoin_access_key;
+            let secret_key = account_info.kucoin_secret_key;
+            let pass_key = account_info.kucoin_pass;
             params.insert("access_key".to_string(), access_key);
             params.insert("secret_key".to_string(), secret_key);
             params.insert("pass_key".to_string(), pass_key);
@@ -82,9 +142,9 @@ pub async fn test_new_exchange(exchange: ExchangeEnum, symbol: &str) -> Box<dyn
         }
         ExchangeEnum::OkxSwap => {
             let mut params: BTreeMap<String, String> = BTreeMap::new();
-            let access_key = env::var("okx_access_key").unwrap_or("".to_string());
-            let secret_key = env::var("okx_secret_key").unwrap_or("".to_string());
-            let pass_key = env::var("okx_passphrase").unwrap_or("".to_string());
+            let access_key = account_info.okx_access_key;
+            let secret_key = account_info.okx_secret_key;
+            let pass_key = account_info.okx_pass;
             params.insert("access_key".to_string(), access_key);
             params.insert("secret_key".to_string(), secret_key);
             params.insert("pass_key".to_string(), pass_key);
@@ -92,9 +152,9 @@ pub async fn test_new_exchange(exchange: ExchangeEnum, symbol: &str) -> Box<dyn
         }
         ExchangeEnum::BitgetSpot => {
             let mut params: BTreeMap<String, String> = BTreeMap::new();
-            let access_key = env::var("bitget_access_key").unwrap_or("".to_string());
-            let secret_key = env::var("bitget_secret_key").unwrap_or("".to_string());
-            let pass_key = env::var("bitget_pass_key").unwrap_or("".to_string());
+            let access_key = account_info.bitget_access_key;
+            let secret_key = account_info.bitget_secret_key;
+            let pass_key = account_info.bitget_pass;
             params.insert("access_key".to_string(), access_key);
             params.insert("secret_key".to_string(), secret_key);
             params.insert("pass_key".to_string(), pass_key);

+ 36 - 2
standard/tests/okx_swap_test.rs

@@ -1,3 +1,4 @@
+use rust_decimal_macros::dec;
 use tracing::{instrument, trace};
 use standard::exchange::ExchangeEnum;
 use standard::Platform;
@@ -5,7 +6,7 @@ use crate::exchange_test::test_new_exchange;
 
 mod exchange_test;
 
-const SYMBOL: &str = "ETH_USDT";
+const SYMBOL: &str = "CRO_USDT";
 
 // 测试获取Exchange实体
 #[tokio::test]
@@ -157,7 +158,7 @@ async fn test_get_order_detail() {
     global::log_utils::init_log_with_trace();
 
     let mut okx_swap_exchange: Box<dyn Platform> = test_new_exchange(ExchangeEnum::OkxSwap, SYMBOL).await;
-    let okx_get_order_detail = okx_swap_exchange.get_order_detail("", "999999").await;
+    let okx_get_order_detail = okx_swap_exchange.get_order_detail("", "999997").await;
     trace!(?okx_get_order_detail);
 }
 
@@ -172,6 +173,39 @@ async fn test_get_orders_list() {
     trace!(?okx_get_orders_list);
 }
 
+// 测试下单
+#[tokio::test]
+#[instrument(level = "TRACE")]
+async fn test_take_order() {
+    global::log_utils::init_log_with_trace();
+
+    let mut okx_swap_exchange: Box<dyn Platform> = test_new_exchange(ExchangeEnum::OkxSwap, SYMBOL).await;
+    let okx_take_order = okx_swap_exchange.take_order("999997", "kk", dec!(0.0901), dec!(100)).await;
+    trace!(?okx_take_order);
+}
+
+// 测试撤销订单
+#[tokio::test]
+#[instrument(level = "TRACE")]
+async fn test_cancel_order() {
+    global::log_utils::init_log_with_trace();
+
+    let mut okx_swap_exchange: Box<dyn Platform> = test_new_exchange(ExchangeEnum::OkxSwap, SYMBOL).await;
+    let okx_cancel_order = okx_swap_exchange.cancel_order("", "999998").await;
+    trace!(?okx_cancel_order);
+}
+
+// 测试撤销订单
+#[tokio::test]
+#[instrument(level = "TRACE")]
+async fn test_cancel_orders() {
+    global::log_utils::init_log_with_trace();
+
+    let mut kucoin_swap_exchange: Box<dyn Platform> = test_new_exchange(ExchangeEnum::KucoinSwap, SYMBOL).await;
+    let kucoin_cancel_orders = kucoin_swap_exchange.cancel_orders().await;
+    trace!(?kucoin_cancel_orders);
+}
+
 // 测试设置持仓模式
 #[tokio::test]
 #[instrument(level = "TRACE")]