Browse Source

完成phemex标准化部分

gepangpang 1 year ago
parent
commit
a72f5eb538

+ 1 - 1
exchanges/src/phemex_swap_rest.rs

@@ -426,7 +426,7 @@ impl PhemexSwapRest {
         return ResponseData::new(self.tag.clone(), 400, "error".to_string(), json_value);
     }
 
-    pub fn on_error_data(&mut self, text: &String, base_url: &String, params: &String) -> ResponseData {
+    pub fn on_error_data(&mut self, text: &String, _base_url: &String, _params: &String) -> ResponseData {
         let json_value = serde_json::from_str::<Value>(&text);
 
 

+ 12 - 0
global/src/account_info.rs

@@ -19,9 +19,15 @@ pub struct AccountInfo {
     pub bitget_access_key: String,
     pub bitget_secret_key: String,
     pub bitget_pass: String,
+    pub bybit_access_key: String,
+    pub bybit_secret_key: String,
+    pub bybit_pass: String,
     pub htx_access_key: String,
     pub htx_secret_key: String,
     pub htx_pass: String,
+    pub phemex_access_key: String,
+    pub phemex_secret_key: String,
+    pub phemex_pass: String,
 }
 
 impl AccountInfo {
@@ -40,9 +46,15 @@ impl AccountInfo {
             bitget_access_key: "".to_string(),
             bitget_secret_key: "".to_string(),
             bitget_pass: "".to_string(),
+            bybit_access_key: "".to_string(),
+            bybit_secret_key: "".to_string(),
+            bybit_pass: "".to_string(),
             htx_access_key: "".to_string(),
             htx_secret_key: "".to_string(),
             htx_pass: "".to_string(),
+            phemex_access_key: "".to_string(),
+            phemex_secret_key: "".to_string(),
+            phemex_pass: "".to_string(),
         }
     }
 }

+ 1 - 1
standard/Cargo.toml

@@ -12,7 +12,7 @@ tokio = { version = "1.31.0", features = ["full"] }
 async-trait = "0.1.73"
 serde = { version = "1.0", features = ["derive"] }
 serde_json = "1.0.104"
-rust_decimal = "1.32.0"
+rust_decimal = { version = "1.32.0", features = ["maths"] }
 rust_decimal_macros = "1.32.0"
 chrono = "0.4.30"
 futures = "0.3"

+ 6 - 1
standard/src/exchange.rs

@@ -14,6 +14,7 @@ use crate::coinex_swap::CoinexSwap;
 // use crate::kucoin_spot::KucoinSpot;
 // use crate::okx_swap::OkxSwap;
 use crate::htx_swap::HtxSwap;
+use crate::phemex_swap::PhemexSwap;
 
 /// 交易所交易模式枚举
 /// - `BinanceSwap`: Binance交易所期货;
@@ -34,7 +35,8 @@ pub enum ExchangeEnum {
     CoinexSwap,
     BitgetSwap,
     BybitSwap,
-    HtxSwap
+    HtxSwap,
+    PhemexSwap
 }
 
 /// Exchange结构体
@@ -112,6 +114,9 @@ impl Exchange {
             ExchangeEnum::HtxSwap => {
                 Box::new(HtxSwap::new(symbol, is_colo, params, order_sender, error_sender).await)
             }
+            ExchangeEnum::PhemexSwap => {
+                Box::new(PhemexSwap::new(symbol, is_colo, params, order_sender, error_sender).await)
+            }
         }
     }
 }

+ 21 - 1
standard/src/handle_info.rs

@@ -7,7 +7,7 @@ use tracing::{error, info};
 use exchanges::response_base::ResponseData;
 use global::public_params;
 use crate::exchange::ExchangeEnum;
-use crate::{binance_swap_handle, gate_swap_handle, bybit_swap_handle, bitget_swap_handle, kucoin_handle, coinex_swap_handle, htx_swap_handle};
+use crate::{binance_swap_handle, gate_swap_handle, bybit_swap_handle, bitget_swap_handle, kucoin_handle, coinex_swap_handle, htx_swap_handle, phemex_swap_handle};
 use crate::{Account, MarketOrder, Position, SpecialDepth, SpecialOrder, SpecialTicker};
 
 #[allow(dead_code)]
@@ -57,6 +57,9 @@ impl HandleSwapInfo {
             ExchangeEnum::HtxSwap => {
                 htx_swap_handle::handle_account_info(res_data, symbol)
             }
+            ExchangeEnum::PhemexSwap => {
+                phemex_swap_handle::handle_account_info(res_data, symbol)
+            }
             _ => {
                 error!("未找到该交易所!handle_account_info: {:?}",exchange);
                 panic!("未找到该交易所!handle_account_info: {:?}", exchange);
@@ -105,6 +108,9 @@ impl HandleSwapInfo {
                 SpecialDepth::new()
                 // htx_swap_handle::handle_ticker(res_data)
             }
+            ExchangeEnum::PhemexSwap => {
+                phemex_swap_handle::handle_ticker(res_data)
+            }
         }
     }
     // 处理position信息
@@ -143,6 +149,9 @@ impl HandleSwapInfo {
             ExchangeEnum::HtxSwap => {
                 htx_swap_handle::handle_position(res_data, ct_val)
             }
+            ExchangeEnum::PhemexSwap => {
+                phemex_swap_handle::handle_position(res_data, ct_val)
+            }
         }
     }
     // 处理订单信息
@@ -179,6 +188,9 @@ impl HandleSwapInfo {
             ExchangeEnum::HtxSwap => {
                 htx_swap_handle::handle_order(res_data, ct_val)
             }
+            ExchangeEnum::PhemexSwap => {
+                phemex_swap_handle::handle_order(res_data, ct_val)
+            }
         }
     }
 
@@ -335,6 +347,14 @@ pub fn format_depth(exchange: ExchangeEnum, res_data: &ResponseData) -> DepthPar
             t = Decimal::from_i64(time).unwrap();
             create_at = time * 1000;
         }
+        ExchangeEnum::PhemexSwap => {
+            let depth = &res_data.data;
+            depth_asks = phemex_swap_handle::format_depth_items(depth["orderbook_p"]["asks"].clone());
+            depth_bids = phemex_swap_handle::format_depth_items(depth["orderbook_p"]["bids"].clone());
+            let time = depth["timestamp"].as_i64().unwrap() / 1_000_000;
+            t = Decimal::from_i64(time).unwrap();
+            create_at = time * 1000;
+        }
     }
 
     DepthParam {

+ 3 - 1
standard/src/lib.rs

@@ -39,7 +39,9 @@ mod bitget_swap_handle;
 mod coinex_swap;
 mod coinex_swap_handle;
 mod htx_swap;
-pub mod htx_swap_handle;
+mod htx_swap_handle;
+mod phemex_swap;
+pub mod phemex_swap_handle;
 
 /// 持仓模式枚举
 /// - `Both`:单持仓方向

+ 698 - 0
standard/src/phemex_swap.rs

@@ -0,0 +1,698 @@
+use std::collections::{BTreeMap};
+use std::io::{Error, ErrorKind};
+use std::str::FromStr;
+use tokio::sync::mpsc::Sender;
+use async_trait::async_trait;
+use futures::stream::FuturesUnordered;
+use futures::TryStreamExt;
+use rust_decimal::Decimal;
+use rust_decimal_macros::dec;
+use serde_json::{json, Value};
+use tokio::spawn;
+use tokio::time::Instant;
+use tracing::{error, info, trace, warn};
+use exchanges::phemex_swap_rest::PhemexSwapRest;
+use exchanges::response_base::ResponseData;
+use crate::{Platform, ExchangeEnum, Account, Position, Ticker, Market, Order, OrderCommand, PositionModeEnum, utils};
+use global::trace_stack::TraceStack;
+
+#[allow(dead_code)]
+#[derive(Clone)]
+pub struct PhemexSwap {
+    exchange: ExchangeEnum,
+    symbol: String,
+    is_colo: bool,
+    params: BTreeMap<String, String>,
+    request: PhemexSwapRest,
+    market: Market,
+    order_sender: Sender<Order>,
+    error_sender: Sender<Error>,
+}
+
+impl PhemexSwap {
+    pub async fn new(symbol: String, is_colo: bool, params: BTreeMap<String, String>, order_sender: Sender<Order>, error_sender: Sender<Error>) -> PhemexSwap {
+        let market = Market::new();
+        let mut phemex_swap = PhemexSwap {
+            exchange: ExchangeEnum::PhemexSwap,
+            symbol: symbol.to_uppercase(),
+            is_colo,
+            params: params.clone(),
+            request: PhemexSwapRest::new(is_colo, params.clone()),
+            market,
+            order_sender,
+            error_sender,
+        };
+
+        // 修改持仓模式
+        let mode_result = phemex_swap.set_dual_mode("", false).await;
+        match mode_result {
+            Ok(_) => {
+                trace!("Phemex:设置持仓模式成功!")
+            }
+            Err(error) => {
+                error!("Phemex:设置持仓模式失败!mode_result={}", error)
+            }
+        }
+        // 获取市场信息
+        phemex_swap.market = PhemexSwap::get_market(&mut phemex_swap).await.unwrap_or(phemex_swap.market);
+        // phemex_swap.market = Market::new();
+        // 设置持仓杠杆
+        let lever_rate_result = phemex_swap.set_dual_leverage("10").await;
+        match lever_rate_result {
+            Ok(ok) => {
+                info!("Phemex:设置持仓杠杆成功!{:?}", ok);
+            }
+            Err(error) => {
+                error!("Phemex:设置持仓杠杆失败!{:?}", error)
+            }
+        }
+        return phemex_swap;
+    }
+}
+
+#[async_trait]
+impl Platform for PhemexSwap {
+    // 克隆方法
+    fn clone_box(&self) -> Box<dyn Platform + Send + Sync> { Box::new(self.clone()) }
+    // 获取交易所模式
+    fn get_self_exchange(&self) -> ExchangeEnum {
+        ExchangeEnum::PhemexSwap
+    }
+    // 获取交易对
+    fn get_self_symbol(&self) -> String { self.symbol.clone() }
+    // 获取是否使用高速通道
+    fn get_self_is_colo(&self) -> bool {
+        self.is_colo
+    }
+    // 获取params信息
+    fn get_self_params(&self) -> BTreeMap<String, String> {
+        self.params.clone()
+    }
+    // 获取market信息
+    fn get_self_market(&self) -> Market { self.market.clone() }
+    // 获取请求时间
+    fn get_request_delays(&self) -> Vec<i64> { self.request.get_delays() }
+    // 获取请求平均时间
+    fn get_request_avg_delay(&self) -> Decimal { self.request.get_avg_delay() }
+    // 获取请求最大时间
+    fn get_request_max_delay(&self) -> i64 { self.request.get_max_delay() }
+
+    // 获取服务器时间
+    async fn get_server_time(&mut self) -> Result<String, Error> {
+        let res_data = self.request.get_server().await;
+        if res_data.code == 200 {
+            let res_data_json: Value = res_data.data;
+            let result = res_data_json["serverTime"].to_string();
+            Ok(result)
+        } else {
+            Err(Error::new(ErrorKind::Other, res_data.to_string()))
+        }
+    }
+    // 获取账号信息
+    async fn get_account(&mut self) -> Result<Account, Error> {
+        let params = json!({"currency": "USDT"});
+        let response = self.request.get_account_and_positions(params).await;
+        if response.code != 200 {
+            return Err(Error::new(ErrorKind::NotFound, format!("phemex_swap 获取仓位异常{:?}", response).to_string()));
+        }
+
+        let account_info = response.data["account"].clone();
+        let coin = account_info["currency"].as_str().unwrap().to_string();
+        let available_balance = Decimal::from_str(account_info["accountBalanceRv"].as_str().unwrap()).unwrap();
+        let frozen_balance = Decimal::from_str(account_info["totalUsedBalanceRv"].as_str().unwrap()).unwrap();
+        let balance = available_balance + frozen_balance;
+        let result = Account {
+            coin,
+            balance,
+            available_balance,
+            frozen_balance,
+            stocks: Decimal::ZERO,
+            available_stocks: Decimal::ZERO,
+            frozen_stocks: Decimal::ZERO,
+        };
+        Ok(result)
+    }
+
+    async fn get_spot_account(&mut self) -> Result<Vec<Account>, Error> {
+        Err(Error::new(ErrorKind::NotFound, "phemex_swap:该方法暂未实现".to_string()))
+    }
+
+    // 获取持仓信息
+    async fn get_position(&mut self) -> Result<Vec<Position>, Error> {
+        let symbol_format = utils::format_symbol(self.symbol.clone(), "").replace("1000", "u1000");
+        let ct_val = self.market.ct_val;
+
+        let params = json!({
+            "symbol":symbol_format,
+            "currency": "USDT"
+        });
+        let response = self.request.get_account_and_positions(params).await;
+        if response.code != 200 {
+            return Err(Error::new(ErrorKind::NotFound, format!("phemex_swap 获取仓位异常{:?}", response).to_string()));
+        }
+
+        let res_data_json = response.data["positions"].clone();
+        let positions_info = res_data_json.as_array().unwrap();
+        let result = positions_info.iter().map(|item| { format_position_item(item, ct_val) }).collect();
+        Ok(result)
+    }
+
+    // 获取所有持仓
+    async fn get_positions(&mut self) -> Result<Vec<Position>, Error> {
+        let params = json!({
+            "currency": "USDT"
+        });
+        let response = self.request.get_account_and_positions(params).await;
+        if response.code != 200 {
+            return Err(Error::new(ErrorKind::NotFound, format!("phemex_swap 获取仓位异常{:?}", response).to_string()));
+        }
+
+        let res_data_json = response.data["positions"].clone();
+        let positions_info = res_data_json.as_array().unwrap();
+        let result = positions_info.iter().map(|item| { format_position_item(item, Decimal::ONE) }).collect();
+        Ok(result)
+    }
+    // 获取市场行情
+    async fn get_ticker(&mut self) -> Result<Ticker, Error> {
+        self.get_ticker_symbol(self.symbol.clone()).await
+    }
+
+    async fn get_ticker_symbol(&mut self, symbol: String) -> Result<Ticker, Error> {
+        let symbol_format = utils::format_symbol(symbol.clone(), "").replace("1000", "u1000");
+        let params = json!({
+            "symbol":symbol_format
+        });
+        let response = self.request.get_ticker(params).await;
+        if response.code != 200 {
+            return Err(Error::new(ErrorKind::NotFound, format!("phemex_swap 获取市场行情异常{:?}", response).to_string()));
+        }
+
+        let ticker_info = response.data;
+        let result = Ticker {
+            time: ticker_info["timestamp"].as_i64().unwrap() / 1_000_000,
+            high: Decimal::from_str(ticker_info["highRp"].as_str().unwrap()).unwrap(),
+            low: Decimal::from_str(ticker_info["lowRp"].as_str().unwrap()).unwrap(),
+            sell: Decimal::from_str(ticker_info["askRp"].as_str().unwrap()).unwrap(),
+            buy: Decimal::from_str(ticker_info["bidRp"].as_str().unwrap()).unwrap(),
+            last: Decimal::from_str(ticker_info["lastRp"].as_str().unwrap()).unwrap(),
+            volume: Decimal::from_str(ticker_info["volumeRq"].as_str().unwrap()).unwrap(),
+        };
+        Ok(result)
+    }
+
+    async fn get_market(&mut self) -> Result<Market, Error> {
+        self.get_market_symbol(self.symbol.clone()).await
+    }
+
+    async fn get_market_symbol(&mut self, symbol: String) -> Result<Market, Error> {
+        let symbol_format = utils::format_symbol(symbol.clone(), "").replace("1000", "u1000");
+
+        let params = json!({});
+        // let response = self.request.get_market(params).await;
+        let response = get_market_info(params);
+        if response.code != 200 {
+            return Err(Error::new(ErrorKind::NotFound, format!("phemex_swap 获取市场行情异常{:?}", response).to_string()));
+        }
+        let res_data_json = response.data["perpProductsV2"].as_array().unwrap();
+        let market_info = res_data_json.iter().find(|item| {
+            item["symbol"].as_str().unwrap() == symbol_format
+        });
+        match market_info {
+            None => {
+                error!("phemex_swap:获取Market信息错误!\nget_market:res_data={:?}", response);
+                Err(Error::new(ErrorKind::Other, response.to_string()))
+            }
+            Some(value) => {
+                let symbol = value["symbol"].as_str().unwrap().to_string();
+                let base_asset = value["baseCurrency"].as_str().unwrap().to_string().split_whitespace().collect();
+                let quote_asset = value["quoteCurrency"].as_str().unwrap().to_string();
+                let price_precision = Decimal::from_str(&value["pricePrecision"].to_string()).unwrap();
+                let tick_size = Decimal::from_str(value["tickSize"].as_str().unwrap()).unwrap();
+                let amount_precision = Decimal::from_str(&value["qtyPrecision"].to_string()).unwrap();
+                let amount_size = Decimal::from_str(&value["qtyStepSize"].as_str().unwrap()).unwrap();
+                let min_notional = Decimal::from_str(value["minPriceRp"].as_str().unwrap()).unwrap();
+                let max_qty = Decimal::from_str(value["maxOrderQtyRq"].as_str().unwrap()).unwrap();
+
+                let min_qty = Decimal::from_str(value["minOrderValueRv"].as_str().unwrap()).unwrap() / min_notional;
+                let max_notional = Decimal::from_str(value["maxPriceRp"].as_str().unwrap()).unwrap() * max_qty;
+                let ct_val = Decimal::ONE;
+
+                let result = Market {
+                    symbol,
+                    base_asset,
+                    quote_asset,
+                    tick_size,
+                    amount_size,
+                    price_precision,
+                    amount_precision,
+                    min_qty,
+                    max_qty,
+                    min_notional,
+                    max_notional,
+                    ct_val,
+                };
+                Ok(result)
+            }
+        }
+    }
+
+    // 获取订单详情
+    async fn get_order_detail(&mut self, order_id: &str, custom_id: &str) -> Result<Order, Error> {
+        let symbol_format = utils::format_symbol(self.symbol.clone(), "").replace("1000", "u1000");
+        let ct_val = self.market.ct_val;
+        let mut params = json!({
+            "symbol":symbol_format,
+        });
+        if order_id.eq("") { params["clOrdID"] = json!(custom_id.to_string()) } else { params["orderID"] = json!(order_id.to_string()) };
+        if order_id == "" && custom_id == "" { return Err(Error::new(ErrorKind::Other, format!("订单id和客户端id都为空,查询失败!order_id :{}, custom_id: {}", order_id, custom_id))); }
+
+        let response = self.request.get_orders_by_id(params).await;
+        if response.code != 200 {
+            return Err(Error::new(ErrorKind::NotFound, format!("phemex_swap 获取订单详情异常{:?}", response).to_string()));
+        }
+
+        let res_data_json = response.data["rows"].as_array().unwrap();
+        let order_info = res_data_json.iter().find(|item| item["orderId"].as_str().unwrap() == order_id || item["clOrdId"] == custom_id);
+        match order_info {
+            None => {
+                error!("phemex_swap:获取order信息错误!\nget_order_detail:res_data={:?},order_id={},custom_id:{}", response, order_id, custom_id);
+                Err(Error::new(ErrorKind::Other, response.to_string()))
+            }
+            Some(order) => {
+                let result = format_order_item(order.clone(), ct_val);
+                return Ok(result);
+            }
+        }
+    }
+
+    // 获取未完成订单列表
+    async fn get_orders_list(&mut self, _status: &str) -> Result<Vec<Order>, Error> {
+        let symbol_format = utils::format_symbol(self.symbol.clone(), "").replace("1000", "u1000");
+        let ct_val = self.market.ct_val;
+
+        let params = json!({
+            "symbol": symbol_format
+        });
+        let response = self.request.get_orders(params).await;
+        if response.code != 200 {
+            return Err(Error::new(ErrorKind::NotFound, format!("phemex_swap 获取订单列表异常{:?}", response).to_string()));
+        }
+
+        let result = response.data["rows"].as_array().unwrap().iter().map(|item| format_order_item(item.clone(), ct_val)).collect();
+        return Ok(result);
+    }
+
+    // 下单接口
+    async fn take_order(&mut self, custom_id: &str, origin_side: &str, price: Decimal, amount: Decimal) -> Result<Order, Error> {
+        self.take_order_symbol(self.symbol.clone(), self.market.ct_val, custom_id, origin_side, price, amount).await
+    }
+
+    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(), "").replace("1000", "u1000");
+        let mut params = json!({
+            "clOrdID": custom_id,
+            "symbol":symbol_format,
+            "priceRp": price,
+            "orderQtyRq": amount * ct_val
+        });
+        if price == dec!(0) { params["ordType"] = json!("Market") };
+        match origin_side {
+            "kd" => {
+                params["reduce_only"] = json!(false);
+                params["posSide"] = json!("Long");
+                params["side"] = json!("Buy");
+            }
+            "pd" => {
+                params["reduce_only"] = json!(true);
+                params["posSide"] = json!("Long");
+                params["side"] = json!("Sell");
+            }
+            "kk" => {
+                params["reduce_only"] = json!(false);
+                params["posSide"] = json!("Short");
+                params["side"] = json!("Sell");
+            }
+            "pk" => {
+                params["reduce_only"] = json!(true);
+                params["posSide"] = json!("Short");
+                params["side"] = json!("Buy");
+            }
+            _ => {
+                error!("下单参数错误");
+                params["posSide"] = json!("error");
+                params["side"] = json!("error");
+            }
+        };
+        let res_data = self.request.orders(params).await;
+        println!("{:?}", res_data);
+        if res_data.code == 200 {
+            let res_data_json: Value = res_data.data;
+            let result = format_order_item(res_data_json, ct_val);
+            Ok(result)
+        } else {
+            Err(Error::new(ErrorKind::Other, res_data.to_string()))
+        }
+    }
+
+    // 撤销订单
+    async fn cancel_order(&mut self, order_id: &str, custom_id: &str) -> Result<Order, Error> {
+        let symbol = utils::format_symbol(self.symbol.clone(), "").replace("1000", "u1000");
+        let ct_val = self.market.ct_val;
+        let mut params = json!({
+            "orderID": order_id,
+            "clOrdID": custom_id,
+            "symbol": symbol,
+        });
+        params["posSide"] = json!("Short");
+        let response_long = self.request.cancel_order(params.clone()).await;
+        params["posSide"] = json!("Long");
+        let response_short = self.request.cancel_order(params.clone()).await;
+        if response_long.code != 200 && response_short.code != 200 {
+            return Err(Error::new(ErrorKind::NotFound, format!("phemex_swap 撤销订单失败 order_id: {}, custom_id: {}, response_long: {:?}, response_short: {:?}", order_id, custom_id, response_long, response_short)));
+        };
+        let res_data_json: Value = if response_long.code == 200 { response_long.data } else { response_short.data };
+        let mut result = format_order_item(res_data_json, ct_val);
+        result.status = "REMOVE".to_string();
+        Ok(result)
+    }
+
+    // 批量撤销订单
+    async fn cancel_orders(&mut self) -> Result<Vec<Order>, Error> {
+        let symbol = utils::format_symbol(self.symbol.clone(), "").replace("1000", "u1000");
+        let params = json!({
+            "symbol":symbol
+        });
+        let response = self.request.cancel_order_all(params).await;
+        if response.code != 200 {
+            return Err(Error::new(ErrorKind::NotFound, format!("phemex_swap 批量撤销订单失败 res_data: {:?}", response)));
+        };
+        return Ok(vec![]);
+    }
+
+    async fn cancel_orders_all(&mut self) -> Result<Vec<Order>, Error> {
+        let params = json!({});
+        let response = self.request.cancel_order_all(params).await;
+        if response.code != 200 {
+            return Err(Error::new(ErrorKind::NotFound, format!("phemex_swap 批量撤销订单失败 res_data: {:?}", response)));
+        };
+        info!("{}", response.data.to_string());
+        return Ok(vec![]);
+    }
+
+    async fn take_stop_loss_order(&mut self, _stop_price: Decimal, _price: Decimal, _side: &str) -> Result<Value, Error> {
+        Err(Error::new(ErrorKind::NotFound, "coin_ex:该交易所暂未实现自动订单下单".to_string()))
+    }
+
+    async fn cancel_stop_loss_order(&mut self, _order_id: &str) -> Result<Value, Error> {
+        Err(Error::new(ErrorKind::NotFound, "coin_ex:该交易所暂未实现取消自动订单".to_string()))
+    }
+
+    // 设置持仓模式
+    async fn set_dual_mode(&mut self, _coin: &str, _is_dual_mode: bool) -> Result<String, Error> {
+        let symbol = utils::format_symbol(self.symbol.clone(), "").replace("1000", "u1000");
+        let params = json!({
+            "symbol":symbol,
+            "targetPosMode": "Hedged"
+        });
+
+        let response = self.request.set_target_pos_mode(params).await;
+        if response.code != 200 {
+            return Err(Error::new(ErrorKind::NotFound, format!("phemex_swap 设置持仓模式{:?}", response).to_string()));
+        }
+        let result = &response.data;
+        Ok(result.as_str().unwrap().to_string())
+    }
+
+    // 更新杠杆
+    async fn set_dual_leverage(&mut self, leverage: &str) -> Result<String, Error> {
+        let leverage_int = leverage.parse::<i32>().unwrap();
+        let symbol = utils::format_symbol(self.symbol.clone(), "").replace("1000", "u1000");
+        let params = json!({
+            "symbol": symbol,
+            "leverageRr": leverage_int,
+        });
+
+        let response = self.request.set_leverage(params).await;
+        if response.code != 200 {
+            return Err(Error::new(ErrorKind::NotFound, format!("phemex_swap 设置杠杆异常{:?}", response).to_string()));
+        }
+        let result = &response.data;
+        Ok(result.as_str().unwrap().to_string())
+    }
+
+    async fn set_auto_deposit_status(&mut self, _status: bool) -> Result<String, Error> { Err(Error::new(ErrorKind::NotFound, "Phemex:该交易所方法未实现".to_string())) }
+
+    async fn wallet_transfers(&mut self, _coin: &str, _from: &str, _to: &str, _amount: Decimal) -> Result<String, Error> {
+        Err(Error::new(ErrorKind::NotFound, "Phemex wallet_transfers:该交易所方法未实现".to_string()))
+    }
+
+    // 指令下单
+    async fn command_order(&mut self, order_command: &mut OrderCommand, trace_stack: &TraceStack) {
+        let mut handles = vec![];
+
+        // 下单指令
+        for item in order_command.limits_open.keys() {
+            let mut ts = trace_stack.clone();
+
+            let amount = Decimal::from_str(&*order_command.limits_open[item].get(0).unwrap().clone()).unwrap();
+            let side = order_command.limits_open[item].get(1).unwrap().clone();
+            let price = Decimal::from_str(&*order_command.limits_open[item].get(2).unwrap().clone()).unwrap();
+            let cid = order_command.limits_open[item].get(3).unwrap().clone();
+
+            //  order_name: [数量,方向,价格,c_id]
+            let mut self_clone = self.clone();
+            let handle = spawn(async move {
+                // info!("数量 {},方向 {},价格 {},c_id {}", amount, side, price, cid);
+                ts.on_before_send();
+                let result = self_clone.take_order(&cid, &side, price, amount).await;
+                ts.on_after_send();
+
+                match result {
+                    Ok(mut result) => {
+                        result.trace_stack = ts;
+                        // info!("数量 {},方向 {},价格 {},c_id {}", amount, side, price, cid);
+                        self_clone.order_sender.send(result).await.unwrap();
+                    }
+                    Err(error) => {
+                        let mut err_order = Order::new();
+                        err_order.custom_id = cid.clone();
+                        err_order.status = "REMOVE".to_string();
+                        // info!("err 数量 {},方向 {},价格 {},c_id {}", amount, side, price, cid);
+                        self_clone.order_sender.send(err_order).await.unwrap();
+                        self_clone.error_sender.send(error).await.unwrap();
+                        // 触发限频
+                        // if error_info.to_string().contains("213:Please don't try too frequently") {
+                        //     Err(Error::new(ErrorKind::Other, "触发限频, 请调整下单频率"))
+                        // }
+                    }
+                }
+            });
+            handles.push(handle)
+        }
+        let futures = FuturesUnordered::from_iter(handles);
+        // 等待所有任务完成
+        let _: Result<Vec<_>, _> = futures.try_collect().await;
+
+        // 撤销订单
+        let mut cancel_handlers = vec![];
+        for item in order_command.cancel.keys() {
+            let order_id = order_command.cancel[item].get(1).unwrap().clone();
+            let custom_id = order_command.cancel[item].get(0).unwrap().clone();
+
+            let mut self_clone = self.clone();
+            let handle = spawn(async move {
+                let result = self_clone.cancel_order(&order_id, &custom_id).await;
+                match result {
+                    Ok(_) => {
+                        // self_clone.order_sender.send(order).await.unwrap();
+                    }
+                    Err(error) => {
+                        // info!("撤单失败:{:?}", error.to_string());
+                        // 取消失败去查订单。
+                        let query_rst = self_clone.get_order_detail(&order_id, &custom_id).await;
+                        match query_rst {
+                            Ok(order) => {
+                                // info!("查单 订单详情:{:?}", order);
+                                self_clone.order_sender.send(order).await.unwrap();
+                            }
+                            Err(err) => {
+                                // 未成交已取消的订单会报不存在
+                                if err.to_string().contains("3103:order not exists") {
+                                    let mut order = Order::new();
+                                    order.id = order_id.to_string();
+                                    order.custom_id = custom_id.to_string();
+                                    order.status = "REMOVE".to_string();
+                                    self_clone.order_sender.send(order).await.unwrap();
+                                } else {
+                                    warn!("撤单失败,而且查单也失败了,Phemex_io_swap,oid={}, cid={} err={:?}", order_id.clone(), custom_id.clone(), err);
+                                }
+                                // panic!("撤单失败,而且查单也失败了,Phemex_io_swap,oid={}, cid={}。", order_id.clone(), custom_id.clone());
+                            }
+                        }
+                        self_clone.error_sender.send(error).await.unwrap();
+                    }
+                }
+            });
+            cancel_handlers.push(handle)
+        }
+        let futures = FuturesUnordered::from_iter(cancel_handlers);
+        // 等待所有任务完成
+        let _: Result<Vec<_>, _> = futures.try_collect().await;
+
+        // 检查订单指令
+        let mut check_handlers = vec![];
+        for item in order_command.check.keys() {
+            let order_id = order_command.check[item].get(1).unwrap().clone();
+            let custom_id = order_command.check[item].get(0).unwrap().clone();
+
+            let mut self_clone = self.clone();
+            let handle = spawn(async move {
+                let result = self_clone.get_order_detail(&order_id, &custom_id).await;
+                match result {
+                    Ok(result) => {
+                        self_clone.order_sender.send(result).await.unwrap();
+                    }
+                    Err(error) => {
+                        self_clone.error_sender.send(error).await.unwrap();
+                    }
+                }
+            });
+            check_handlers.push(handle)
+        }
+
+        let futures = FuturesUnordered::from_iter(check_handlers);
+        // 等待所有任务完成
+        let _: Result<Vec<_>, _> = futures.try_collect().await;
+    }
+}
+
+pub fn format_position_item(position: &Value, ct_val: Decimal) -> Position {
+    let position_mode = match position["posSide"].as_str().unwrap_or("") {
+        "Long" => PositionModeEnum::Long,
+        "Short" => PositionModeEnum::Short,
+        _ => {
+            error!("phemex_swap:格式化持仓模式错误!\nformat_position_item:position={:?}", position);
+            panic!("phemex_swap:格式化持仓模式错误!\nformat_position_item:position={:?}", position)
+        }
+    };
+    let size = Decimal::from_str(&position["size"].as_str().unwrap()).unwrap();
+    let amount = size * ct_val;
+    Position {
+        symbol: position["symbol"].as_str().unwrap().to_string(),
+        margin_level: Decimal::from_str(position["leverageRr"].as_str().unwrap()).unwrap(),
+        amount,
+        frozen_amount: Decimal::ZERO,
+        price: Decimal::from_str(position["avgEntryPrice"].as_str().unwrap()).unwrap(),
+        profit: Decimal::from_str(position["curTermRealisedPnlRv"].as_str().unwrap()).unwrap(),
+        position_mode,
+        margin: Decimal::from_str(position["positionMarginRv"].as_str().unwrap()).unwrap(),
+    }
+}
+
+pub fn format_order_item(order: Value, ct_val: Decimal) -> Order {
+    let id = order["orderID"].as_str().unwrap().to_string();
+    let custom_id = order["clOrdID"].as_str().unwrap().to_string();
+    let price = Decimal::from_str(order["priceRp"].as_str().unwrap()).unwrap();
+    let amount = Decimal::from_str(order["orderQtyRq"].as_str().unwrap()).unwrap() * ct_val;
+    let deal_amount = Decimal::from_str(order["cumQtyRq"].as_str().unwrap()).unwrap() * ct_val;
+    let avg_price = Decimal::from_str(order["cumValueRv"].as_str().unwrap()).unwrap();
+
+    let status = order["ordStatus"].as_str().unwrap();
+    let custom_status;
+    if vec!["Rejected"].contains(&status) {
+        custom_status = "NULL".to_string()
+    } else if vec!["Filled", "Canceled"].contains(&status) {
+        custom_status = "REMOVE".to_string()
+    } else if vec!["New", "Init", "Created"].contains(&status) {
+        custom_status = "NEW".to_string()
+    } else {
+        error!("gate_swap:格式化订单状态错误!\nformat_order_item:order={:?}", order);
+        panic!("gate_swap:格式化订单状态错误!\nformat_order_item:order={:?}", order)
+    };
+
+    let result = Order {
+        id,
+        custom_id,
+        price,
+        amount,
+        deal_amount,
+        avg_price,
+        status: custom_status,
+        order_type: order["orderType"].as_str().unwrap().to_lowercase(),
+        trace_stack: TraceStack::new(0, Instant::now()).on_special("669 trace_stack".to_string()),
+    };
+    return result;
+}
+
+fn get_market_info(_params: Value) -> ResponseData {
+    let aa = json!({"perpProductsV2": [{
+	"symbol": "u1000PEPEUSDT",
+	"code": 66041,
+	"type": "PerpetualV2",
+	"displaySymbol": "1000PEPE / USDT",
+	"indexSymbol": ".u1000PEPEUSDT",
+	"markSymbol": ".Mu1000PEPEUSDT",
+	"fundingRateSymbol": ".u1000PEPEUSDTFR",
+	"fundingRate8hSymbol": ".u1000PEPEUSDTFR8H",
+	"contractUnderlyingAssets": "1000 PEPE",
+	"settleCurrency": "USDT",
+	"quoteCurrency": "USDT",
+	"tickSize": "0.0000001",
+	"priceScale": 0,
+	"ratioScale": 0,
+	"pricePrecision": 7,
+	"baseCurrency": "1000 PEPE",
+	"description": "1000 PEPE/USDT perpetual contracts are priced on the .u1000PEPEUSDT Index. Each contract is worth 1 1000PEPE. Funding fees are paid and received every 8 hours at UTC time: 00:00, 08:00 and 16:00.",
+	"status": "Listed",
+	"tipOrderQty": 0,
+	"listTime": "1683367200000",
+	"majorSymbol": false,
+	"defaultLeverage": "-10",
+	"fundingInterval": 28800,
+	"maxLeverage": 50,
+	"leverageMargin": 1015,
+	"maxOrderQtyRq": "400000000",
+	"maxPriceRp": "2000",
+	"minOrderValueRv": "1",
+	"minPriceRp": "0.001",
+	"qtyPrecision": 0,
+	"qtyStepSize": "1.0",
+	"tipOrderQtyRq": "80000000",
+	"maxOpenPosLeverage": 50.0
+}, {
+	"symbol": "EDUUSDT",
+	"code": 66241,
+	"type": "PerpetualV2",
+	"displaySymbol": "EDU / USDT",
+	"indexSymbol": ".EDUUSDT",
+	"markSymbol": ".MEDUUSDT",
+	"fundingRateSymbol": ".EDUUSDTFR",
+	"fundingRate8hSymbol": ".EDUUSDTFR8H",
+	"contractUnderlyingAssets": "EDU",
+	"settleCurrency": "USDT",
+	"quoteCurrency": "USDT",
+	"tickSize": "0.0001",
+	"priceScale": 0,
+	"ratioScale": 0,
+	"pricePrecision": 4,
+	"baseCurrency": "EDU",
+	"description": "EDU/USDT perpetual contracts are priced on the .EDUUSDT Index. Each contract is worth 1 EDU. Funding fees are paid and received every 8 hours at UTC time: 00:00, 08:00 and 16:00.",
+	"status": "Listed",
+	"tipOrderQty": 0,
+	"listTime": "1683367200000",
+	"majorSymbol": false,
+	"defaultLeverage": "-10",
+	"fundingInterval": 28800,
+	"maxLeverage": 50,
+	"leverageMargin": 1015,
+	"maxOrderQtyRq": "800000",
+	"maxPriceRp": "2000000",
+	"minOrderValueRv": "1",
+	"minPriceRp": "1.0",
+	"qtyPrecision": 0,
+	"qtyStepSize": "1.0",
+	"tipOrderQtyRq": "160000",
+	"maxOpenPosLeverage": 50.0
+}]});
+    ResponseData::new("".to_string(), 200, "".to_string(), aa)
+}

+ 162 - 0
standard/src/phemex_swap_handle.rs

@@ -0,0 +1,162 @@
+use std::str::FromStr;
+use rust_decimal::Decimal;
+use rust_decimal::prelude::FromPrimitive;
+use rust_decimal_macros::dec;
+use serde_json::Value;
+use tokio::time::Instant;
+use tracing::{error};
+use exchanges::response_base::ResponseData;
+use global::trace_stack::TraceStack;
+use crate::{Account, MarketOrder, Order, Position, PositionModeEnum, SpecialDepth, SpecialOrder, SpecialTicker};
+
+// 处理账号信息
+pub fn handle_account_info(res_data: &ResponseData, symbol: &String) -> Account {
+    let res_data_json = res_data.data.as_array().unwrap();
+    format_account_info(res_data_json, symbol)
+}
+
+pub fn format_account_info(accounts: &Vec<Value>, symbol: &String) -> Account {
+    let symbol_upper = symbol.to_uppercase();
+    let symbol_array: Vec<&str> = symbol_upper.split("_").collect();
+    let balance_info = accounts.iter().find(|&item| item["currency"].as_str().unwrap().contains(symbol_array[1]));
+
+    match balance_info {
+        None => {
+            error!("Phemex:格式化账号信息错误!\nformat_account_info: accounts={:?}", accounts);
+            panic!("Phemex:格式化账号信息错误!\nformat_account_info: accounts={:?}", accounts)
+        }
+        Some(value) => {
+            let coin = value["currency"].as_str().unwrap().to_string();
+            let available_balance = Decimal::from_str(value["accountBalanceRv"].as_str().unwrap()).unwrap();
+            let frozen_balance = Decimal::from_str(value["totalUsedBalanceRv"].as_str().unwrap()).unwrap();
+            let balance = available_balance + frozen_balance;
+            Account {
+                coin,
+                balance,
+                available_balance,
+                frozen_balance,
+                stocks: Decimal::ZERO,
+                available_stocks: Decimal::ZERO,
+                frozen_stocks: Decimal::ZERO,
+            }
+        }
+    }
+}
+
+// 处理position信息
+pub fn handle_position(res_data: &ResponseData, ct_val: &Decimal) -> Vec<Position> {
+    let res_data_json = res_data.data.as_array().unwrap();
+    res_data_json.iter().map(|item| { format_position_item(item, ct_val) }).collect()
+}
+
+pub fn format_position_item(position: &Value, ct_val: &Decimal) -> Position {
+    let symbol = position["symbol"].as_str().unwrap().to_string();
+    let margin_level = Decimal::from_str(position["leverageRr"].as_str().unwrap()).unwrap();
+    let price = Decimal::from_str(position["avgEntryPrice"].as_str().unwrap()).unwrap();
+    let profit = Decimal::from_str(position["curTermRealisedPnlRv"].as_str().unwrap()).unwrap();
+    let margin = Decimal::from_str(position["positionMarginRv"].as_str().unwrap()).unwrap();
+    let position_mode = match position["posSide"].as_str().unwrap_or("") {
+        "Long" => PositionModeEnum::Long,
+        "Short" => PositionModeEnum::Short,
+        _ => {
+            error!("phemex_swap:格式化持仓模式错误!\nformat_position_item:position={:?}", position);
+            panic!("phemex_swap:格式化持仓模式错误!\nformat_position_item:position={:?}", position)
+        }
+    };
+    let size = Decimal::from_str(&position["size"].as_str().unwrap()).unwrap();
+    let amount = size * ct_val;
+    Position {
+        symbol,
+        margin_level,
+        amount,
+        frozen_amount: Decimal::ZERO,
+        price,
+        profit,
+        position_mode,
+        margin,
+    }
+}
+
+// 处理order信息
+pub fn handle_order(res_data: ResponseData, ct_val: Decimal) -> SpecialOrder {
+    let orders = res_data.data.as_array().unwrap();
+    let order_info = orders.iter().map(|item| format_order_item(item, ct_val)).collect();
+
+    SpecialOrder {
+        name: res_data.label,
+        order: order_info,
+    }
+}
+pub fn format_order_item(order: &Value, ct_val: Decimal) -> Order {
+    let id = order["orderID"].as_str().unwrap().to_string();
+    let custom_id = order["clOrdID"].as_str().unwrap().to_string();
+    let price = Decimal::from_str(order["priceRp"].as_str().unwrap()).unwrap();
+    let amount = Decimal::from_str(order["orderQty"].as_str().unwrap()).unwrap() * ct_val;
+    let deal_amount = Decimal::from_str(order["cumQty"].as_str().unwrap()).unwrap() * ct_val;
+    let avg_price = Decimal::from_str(order["cumValueRv"].as_str().unwrap()).unwrap();
+
+    let status = order["ordStatus"].as_str().unwrap();
+    let custom_status;
+    if vec!["Rejected"].contains(&status) {
+        custom_status = "NULL".to_string()
+    } else if vec!["Filled", "Canceled"].contains(&status) {
+        custom_status = "REMOVE".to_string()
+    } else if vec!["New", "Init", "Created"].contains(&status) {
+        custom_status = "NEW".to_string()
+    } else {
+        error!("gate_swap:格式化订单状态错误!\nformat_order_item:order={:?}", order);
+        panic!("gate_swap:格式化订单状态错误!\nformat_order_item:order={:?}", order)
+    };
+
+    let result = Order {
+        id,
+        custom_id,
+        price,
+        amount,
+        deal_amount,
+        avg_price,
+        status: custom_status,
+        order_type: order["orderType"].as_str().unwrap().to_lowercase(),
+        trace_stack: TraceStack::new(0, Instant::now()).on_special("114 trace_stack".to_string()),
+    };
+    return result;
+}
+
+// 处理特殊Ticket信息
+pub fn handle_ticker(res_data: &ResponseData) -> SpecialDepth {
+    let depth = &res_data.data;
+
+    let bp = Decimal::from_str(depth["orderbook_p"]["bids"][0][0].as_str().unwrap()).unwrap();
+    let bq = Decimal::from_str(depth["orderbook_p"]["bids"][0][1].as_str().unwrap()).unwrap();
+    let ap = Decimal::from_str(depth["orderbook_p"]["asks"][0][0].as_str().unwrap()).unwrap();
+    let aq = Decimal::from_str(depth["orderbook_p"]["asks"][0][1].as_str().unwrap()).unwrap();
+    let mp = (bp + ap) * dec!(0.5);
+    let t = Decimal::from_i64(depth["timestamp"].as_i64().unwrap() / 1_000_000).unwrap();
+    let create_at = depth["timestamp"].as_i64().unwrap() / 1_000_000;
+
+    let ticker_info = SpecialTicker { sell: ap, buy: bp, mid_price: mp, t, create_at };
+    let depth_info = vec![bp, bq, ap, aq];
+
+    SpecialDepth {
+        name: (*res_data).label.clone(),
+        depth: depth_info,
+        ticker: ticker_info,
+        t,
+        create_at,
+    }
+}
+
+pub fn format_depth_items(depth: Value) -> Vec<MarketOrder> {
+    if depth.is_null() {
+        return vec![];
+    }
+    let mut depth_items: Vec<MarketOrder> = vec![];
+    for values in depth.as_array().unwrap() {
+        let value = values.as_array().unwrap();
+        depth_items.push(MarketOrder {
+            price: Decimal::from_str(value[0].as_str().unwrap()).unwrap(),
+            amount: Decimal::from_str(value[1].as_str().unwrap()).unwrap(),
+        })
+    }
+    return depth_items;
+}

+ 2 - 2
standard/src/utils.rs

@@ -11,8 +11,8 @@ pub fn format_symbol(symbol: String, pat: &str) -> String {
 }
 
 // 检测是否走代理
-pub fn proxy_handle() {
-    if proxy::ParsingDetail::http_enable_proxy(None) {
+pub fn proxy_handle(str: Option<&str>) {
+    if proxy::ParsingDetail::http_enable_proxy(str) {
         trace!("检测有代理配置,配置走代理");
     }
 }

+ 457 - 421
standard/tests/exchange_test.rs

@@ -2,11 +2,10 @@ use std::collections::{BTreeMap};
 use std::io::{Error};
 use std::sync::Arc;
 use std::sync::atomic::AtomicBool;
-use futures::StreamExt;
 use rust_decimal_macros::dec;
+use serde::de::Unexpected::Option;
 use tokio::sync::mpsc::{channel, Receiver, Sender};
 use tokio::sync::Mutex;
-use tokio::try_join;
 use tracing::{error, trace};
 // use exchanges::binance_spot_ws::{BinanceSpotLogin, BinanceSpotSubscribeType, BinanceSpotWs, BinanceSpotWsType};
 // use exchanges::binance_swap_ws::{BinanceSwapLogin, BinanceSwapSubscribeType, BinanceSwapWs, BinanceSwapWsType};
@@ -14,21 +13,28 @@ use tracing::{error, trace};
 // use exchanges::kucoin_spot_ws::{KucoinSpotLogin, KucoinSpotSubscribeType, KucoinSpotWs, KucoinSpotWsType};
 // use exchanges::gate_swap_ws::{GateSwapLogin, GateSwapSubscribeType, GateSwapWs, GateSwapWsType};
 // use exchanges::bitget_spot_ws::{BitgetSpotLogin, BitgetSpotSubscribeType, BitgetSpotWs, BitgetSpotWsType};
-use exchanges::okx_swap_ws::{OkxSwapLogin, OkxSwapSubscribeType, OkxSwapWs, OkxSwapWsType};
+// use exchanges::okx_swap_ws::{OkxSwapLogin, OkxSwapSubscribeType, OkxSwapWs, OkxSwapWsType};
+use exchanges::htx_swap_ws::{HtxSwapLogin, HtxSwapSubscribeType, HtxSwapWs, HtxSwapWsType};
 use exchanges::response_base::ResponseData;
 use standard::exchange::{Exchange, ExchangeEnum};
 // use standard::{binance_spot_handle, Order, Platform, utils};
 // use standard::{binance_handle, Order, Platform, utils};
 // use standard::{kucoin_handle, Order, Platform, utils};
 // use standard::{kucoin_spot_handle, Order, Platform, utils};
-// use standard::{gate_handle, Order, Platform, utils};
+// use standard::{gate_swap_handle, handle_info, Order, Platform, utils};
+// use standard::{okx_handle, Order, Platform, utils};
 // use standard::{bitget_spot_handle, Order, Platform, utils};
-use standard::{okx_handle, Order, Platform, utils};
+// use standard::{htx_swap_handle, handle_info, Order, Platform, utils};
+use standard::{phemex_swap_handle, handle_info, Order, Platform, utils};
 
 // 创建实体
 #[allow(dead_code)]
 pub async fn test_new_exchange(exchange: ExchangeEnum, symbol: &str) -> Box<dyn Platform> {
-    utils::proxy_handle();
+    match exchange {
+        ExchangeEnum::PhemexSwap => utils::proxy_handle(Some("phemex")),
+        _ => utils::proxy_handle(None)
+    }
+
     let (order_sender, _order_receiver): (Sender<Order>, Receiver<Order>) = channel(1024);
     let (error_sender, _error_receiver): (Sender<Error>, Receiver<Error>) = channel(1024);
 
@@ -42,14 +48,14 @@ pub async fn test_new_exchange(exchange: ExchangeEnum, symbol: &str) -> Box<dyn
             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 = 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 = 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 = account_info.gate_access_key;
@@ -58,14 +64,14 @@ pub async fn test_new_exchange(exchange: ExchangeEnum, symbol: &str) -> Box<dyn
             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 = 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 = 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 = account_info.kucoin_access_key;
@@ -76,41 +82,71 @@ pub async fn test_new_exchange(exchange: ExchangeEnum, symbol: &str) -> Box<dyn
             params.insert("pass_key".to_string(), pass_key);
             Exchange::new(exchange, symbol.to_string(), false, params, order_sender, error_sender).await
         }
-        ExchangeEnum::KucoinSpot => {
+        // ExchangeEnum::KucoinSpot => {
+        //     let mut params: BTreeMap<String, String> = BTreeMap::new();
+        //     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);
+        //     Exchange::new(exchange, symbol.to_string(), false, params, order_sender, error_sender).await
+        // }
+        // ExchangeEnum::OkxSwap => {
+        //     let mut params: BTreeMap<String, String> = BTreeMap::new();
+        //     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);
+        //     Exchange::new(exchange, symbol.to_string(), false, params, order_sender, error_sender).await
+        // }
+        // ExchangeEnum::BitgetSpot => {
+        //     let mut params: BTreeMap<String, String> = BTreeMap::new();
+        //     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);
+        //     Exchange::new(exchange, symbol.to_string(), false, params, order_sender, error_sender).await
+        // }
+        ExchangeEnum::BitgetSwap => {
             let mut params: BTreeMap<String, String> = BTreeMap::new();
-            let access_key = account_info.kucoin_access_key;
-            let secret_key = account_info.kucoin_secret_key;
-            let pass_key = account_info.kucoin_pass;
+            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);
             Exchange::new(exchange, symbol.to_string(), false, params, order_sender, error_sender).await
         }
-        ExchangeEnum::OkxSwap => {
+        ExchangeEnum::BybitSwap => {
             let mut params: BTreeMap<String, String> = BTreeMap::new();
-            let access_key = account_info.okx_access_key;
-            let secret_key = account_info.okx_secret_key;
-            let pass_key = account_info.okx_pass;
+            let access_key = account_info.bybit_access_key;
+            let secret_key = account_info.bybit_secret_key;
+            let pass_key = account_info.bybit_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);
             Exchange::new(exchange, symbol.to_string(), false, params, order_sender, error_sender).await
         }
-        ExchangeEnum::BitgetSpot => {
+        ExchangeEnum::HtxSwap => {
             let mut params: BTreeMap<String, String> = BTreeMap::new();
-            let access_key = account_info.bitget_access_key;
-            let secret_key = account_info.bitget_secret_key;
-            let pass_key = account_info.bitget_pass;
+            let access_key = account_info.htx_access_key;
+            let secret_key = account_info.htx_secret_key;
+            let pass_key = account_info.htx_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);
             Exchange::new(exchange, symbol.to_string(), false, params, order_sender, error_sender).await
         }
-        ExchangeEnum::HtxSwap => {
+        ExchangeEnum::PhemexSwap => {
             let mut params: BTreeMap<String, String> = BTreeMap::new();
-            let access_key = account_info.htx_access_key;
-            let secret_key = account_info.htx_secret_key;
-            let pass_key = account_info.htx_pass;
+            let access_key = account_info.phemex_access_key;
+            let secret_key = account_info.phemex_secret_key;
+            let pass_key = account_info.phemex_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);
@@ -123,65 +159,69 @@ pub async fn test_new_exchange(exchange: ExchangeEnum, symbol: &str) -> Box<dyn
 }
 
 #[allow(dead_code)]
-pub async fn test_new_exchange_wss<T>(exchange: ExchangeEnum, symbol: &str, subscriber_type: T, mold: &str) where Vec<OkxSwapSubscribeType>: From<T> {
-    utils::proxy_handle();
+pub async fn test_new_exchange_wss<T>(exchange: ExchangeEnum, symbol: &str, subscriber_type: T, mold: &str) where Vec<HtxSwapSubscribeType>: From<T> {
+    match exchange {
+        ExchangeEnum::PhemexSwap => utils::proxy_handle(Some("phemex")),
+        _ => utils::proxy_handle(None)
+    }
+
     let account_info = global::account_info::get_account_info("../test_account.toml");
     match exchange {
-        ExchangeEnum::BinanceSpot => {
-            // let symbol_format = utils::format_symbol(symbol.to_string(), "").to_uppercase();
-            // trace!(symbol_format);
-            // let name = format!("binance_spot@{}", symbol.to_string().to_lowercase());
-            // let (write_tx, write_rx) = futures_channel::mpsc::unbounded();
-            // let (read_tx, mut read_rx) = futures_channel::mpsc::unbounded::<ResponseData>();
-            // let write_tx_am = Arc::new(Mutex::new(write_tx));
-            // let is_shutdown_arc = Arc::new(AtomicBool::new(true));
-            //
-            // let params = BinanceSpotLogin {
-            //     api_key: account_info.binance_access_key,
-            //     api_secret: account_info.binance_secret_key,
-            // };
-            // let mut exchange_wss;
-            // exchange_wss = BinanceSpotWs::new_label(name, false, Option::from(params), BinanceSpotWsType::PublicAndPrivate);
-            // exchange_wss.set_symbols(vec![symbol_format]);
-            // exchange_wss.set_subscribe(subscriber_type.into());
-            //
-            //
-            // let mold_arc = Arc::new(mold.to_string());
-            // //读取
-            // tokio::spawn(async move {
-            //     let mold_clone = Arc::clone(&mold_arc);
-            //     loop {
-            //         if let Some(data) = read_rx.next().await {
-            //             trace!("原始数据 data:{:?}",data);
-            //             match mold_clone.as_str() {
-            //                 "depth" => {
-            //                     if data.data != "" {
-            //                         let result = binance_spot_handle::handle_special_depth(data);
-            //                         trace!(?result)
-            //                     }
-            //                 }
-            //                 "ticker" => {
-            //                     if data.data != "" {
-            //                         let result = binance_spot_handle::handle_special_ticker(data);
-            //                         trace!(?result)
-            //                     }
-            //                 }
-            //                 _ => {
-            //                     error!("没有该命令!mode={}", mold_clone);
-            //                     panic!("没有该命令!mode={}", mold_clone)
-            //                 }
-            //             }
-            //         }
-            //     };
-            // });
-            //
-            // let t1 = tokio::spawn(async move {
-            //     //链接
-            //     let bool_v3_clone = Arc::clone(&is_shutdown_arc);
-            //     exchange_wss.ws_connect_async(bool_v3_clone, &write_tx_am, write_rx, read_tx).await.expect("链接失败(内部一个心跳线程应该已经关闭了)");
-            // });
-            // try_join!(t1).unwrap();
-        }
+        // ExchangeEnum::BinanceSpot => {
+        // let symbol_format = utils::format_symbol(symbol.to_string(), "").to_uppercase();
+        // trace!(symbol_format);
+        // let name = format!("binance_spot@{}", symbol.to_string().to_lowercase());
+        // let (write_tx, write_rx) = futures_channel::mpsc::unbounded();
+        // let (read_tx, mut read_rx) = futures_channel::mpsc::unbounded::<ResponseData>();
+        // let write_tx_am = Arc::new(Mutex::new(write_tx));
+        // let is_shutdown_arc = Arc::new(AtomicBool::new(true));
+        //
+        // let params = BinanceSpotLogin {
+        //     api_key: account_info.binance_access_key,
+        //     api_secret: account_info.binance_secret_key,
+        // };
+        // let mut exchange_wss;
+        // exchange_wss = BinanceSpotWs::new_label(name, false, Option::from(params), BinanceSpotWsType::PublicAndPrivate);
+        // exchange_wss.set_symbols(vec![symbol_format]);
+        // exchange_wss.set_subscribe(subscriber_type.into());
+        //
+        //
+        // let mold_arc = Arc::new(mold.to_string());
+        // //读取
+        // tokio::spawn(async move {
+        //     let mold_clone = Arc::clone(&mold_arc);
+        //     loop {
+        //         if let Some(data) = read_rx.next().await {
+        //             trace!("原始数据 data:{:?}",data);
+        //             match mold_clone.as_str() {
+        //                 "depth" => {
+        //                     if data.data != "" {
+        //                         let result = binance_spot_handle::handle_special_depth(data);
+        //                         trace!(?result)
+        //                     }
+        //                 }
+        //                 "ticker" => {
+        //                     if data.data != "" {
+        //                         let result = binance_spot_handle::handle_special_ticker(data);
+        //                         trace!(?result)
+        //                     }
+        //                 }
+        //                 _ => {
+        //                     error!("没有该命令!mode={}", mold_clone);
+        //                     panic!("没有该命令!mode={}", mold_clone)
+        //                 }
+        //             }
+        //         }
+        //     };
+        // });
+        //
+        // let t1 = tokio::spawn(async move {
+        //     //链接
+        //     let bool_v3_clone = Arc::clone(&is_shutdown_arc);
+        //     exchange_wss.ws_connect_async(bool_v3_clone, &write_tx_am, write_rx, read_tx).await.expect("链接失败(内部一个心跳线程应该已经关闭了)");
+        // });
+        // try_join!(t1).unwrap();
+        // }
         ExchangeEnum::BinanceSwap => {
             // let symbol_format = utils::format_symbol(symbol.to_string(), "").to_uppercase();
             // trace!(symbol_format);
@@ -304,75 +344,75 @@ pub async fn test_new_exchange_wss<T>(exchange: ExchangeEnum, symbol: &str, subs
             // });
             // try_join!(t1).unwrap();
         }
-        ExchangeEnum::KucoinSpot => {
-            // let symbol_format = utils::format_symbol(symbol.to_string(), "-").to_uppercase();
-            // let symbol_back = utils::format_symbol(symbol.to_string(), "_");
-            // trace!(symbol_format);
-            // let name = format!("kucoin_spot@{}", symbol.to_string().to_lowercase());
-            // let (write_tx, write_rx) = futures_channel::mpsc::unbounded();
-            // let (read_tx, mut read_rx) = futures_channel::mpsc::unbounded::<ResponseData>();
-            // let write_tx_am = Arc::new(Mutex::new(write_tx));
-            // let is_shutdown_arc = Arc::new(AtomicBool::new(true));
-            //
-            // let params = KucoinSpotLogin {
-            //     access_key: account_info.kucoin_access_key,
-            //     secret_key: account_info.kucoin_secret_key,
-            //     pass_key: account_info.kucoin_pass,
-            // };
-            // let mut exchange_wss = if ["depth", "ticker"].contains(&mold) {
-            //     KucoinSpotWs::new_label(name, false, Option::from(params), KucoinSpotWsType::Public).await
-            // } else {
-            //     KucoinSpotWs::new_label(name, false, Option::from(params), KucoinSpotWsType::Private).await
-            // };
-            // exchange_wss.set_symbols(vec![symbol_format]);
-            // exchange_wss.set_subscribe(subscriber_type.into());
-            //
-            // let mold_arc = Arc::new(mold.to_string());
-            // tokio::spawn(async move {
-            //     let mold_clone = Arc::clone(&mold_arc);
-            //     loop {
-            //         if let Some(data) = read_rx.next().await {
-            //             trace!("原始数据 data:{:?}",data);
-            //             match mold_clone.as_str() {
-            //                 "depth" => {
-            //                     if data.data != "" {
-            //                         let result = kucoin_spot_handle::handle_special_depth(data);
-            //                         trace!(?result)
-            //                     }
-            //                 }
-            //                 "ticker" => {
-            //                     if data.data != "" {
-            //                         let result = kucoin_spot_handle::handle_special_ticker(data);
-            //                         trace!(?result)
-            //                     }
-            //                 }
-            //                 "account" => {
-            //                     if data.data != "" {
-            //                         let result = kucoin_spot_handle::handle_account_info(data, symbol_back.clone());
-            //                         trace!(?result)
-            //                     }
-            //                 }
-            //                 "orders" => {
-            //                     if data.data != "" {
-            //                         let result = kucoin_spot_handle::handle_order(data, dec!(1));
-            //                         trace!(?result)
-            //                     }
-            //                 }
-            //                 _ => {
-            //                     error!("没有该命令!mode={}", mold_clone);
-            //                     panic!("没有该命令!mode={}", mold_clone)
-            //                 }
-            //             }
-            //         }
-            //     }
-            // });
-            // let t1 = tokio::spawn(async move {
-            //     //链接
-            //     let bool_v3_clone = Arc::clone(&is_shutdown_arc);
-            //     exchange_wss.ws_connect_async(bool_v3_clone, &write_tx_am, write_rx, read_tx).await.expect("链接失败(内部一个心跳线程应该已经关闭了)");
-            // });
-            // try_join!(t1).unwrap();
-        }
+        // ExchangeEnum::KucoinSpot => {
+        // let symbol_format = utils::format_symbol(symbol.to_string(), "-").to_uppercase();
+        // let symbol_back = utils::format_symbol(symbol.to_string(), "_");
+        // trace!(symbol_format);
+        // let name = format!("kucoin_spot@{}", symbol.to_string().to_lowercase());
+        // let (write_tx, write_rx) = futures_channel::mpsc::unbounded();
+        // let (read_tx, mut read_rx) = futures_channel::mpsc::unbounded::<ResponseData>();
+        // let write_tx_am = Arc::new(Mutex::new(write_tx));
+        // let is_shutdown_arc = Arc::new(AtomicBool::new(true));
+        //
+        // let params = KucoinSpotLogin {
+        //     access_key: account_info.kucoin_access_key,
+        //     secret_key: account_info.kucoin_secret_key,
+        //     pass_key: account_info.kucoin_pass,
+        // };
+        // let mut exchange_wss = if ["depth", "ticker"].contains(&mold) {
+        //     KucoinSpotWs::new_label(name, false, Option::from(params), KucoinSpotWsType::Public).await
+        // } else {
+        //     KucoinSpotWs::new_label(name, false, Option::from(params), KucoinSpotWsType::Private).await
+        // };
+        // exchange_wss.set_symbols(vec![symbol_format]);
+        // exchange_wss.set_subscribe(subscriber_type.into());
+        //
+        // let mold_arc = Arc::new(mold.to_string());
+        // tokio::spawn(async move {
+        //     let mold_clone = Arc::clone(&mold_arc);
+        //     loop {
+        //         if let Some(data) = read_rx.next().await {
+        //             trace!("原始数据 data:{:?}",data);
+        //             match mold_clone.as_str() {
+        //                 "depth" => {
+        //                     if data.data != "" {
+        //                         let result = kucoin_spot_handle::handle_special_depth(data);
+        //                         trace!(?result)
+        //                     }
+        //                 }
+        //                 "ticker" => {
+        //                     if data.data != "" {
+        //                         let result = kucoin_spot_handle::handle_special_ticker(data);
+        //                         trace!(?result)
+        //                     }
+        //                 }
+        //                 "account" => {
+        //                     if data.data != "" {
+        //                         let result = kucoin_spot_handle::handle_account_info(data, symbol_back.clone());
+        //                         trace!(?result)
+        //                     }
+        //                 }
+        //                 "orders" => {
+        //                     if data.data != "" {
+        //                         let result = kucoin_spot_handle::handle_order(data, dec!(1));
+        //                         trace!(?result)
+        //                     }
+        //                 }
+        //                 _ => {
+        //                     error!("没有该命令!mode={}", mold_clone);
+        //                     panic!("没有该命令!mode={}", mold_clone)
+        //                 }
+        //             }
+        //         }
+        //     }
+        // });
+        // let t1 = tokio::spawn(async move {
+        //     //链接
+        //     let bool_v3_clone = Arc::clone(&is_shutdown_arc);
+        //     exchange_wss.ws_connect_async(bool_v3_clone, &write_tx_am, write_rx, read_tx).await.expect("链接失败(内部一个心跳线程应该已经关闭了)");
+        // });
+        // try_join!(t1).unwrap();
+        // }
         ExchangeEnum::GateSwap => {
             // let symbol_format = utils::format_symbol(symbol.to_string(), "_").to_uppercase();
             // trace!(symbol_format);
@@ -390,272 +430,268 @@ pub async fn test_new_exchange_wss<T>(exchange: ExchangeEnum, symbol: &str, subs
             // exchange_wss.set_symbols(vec![symbol_format.clone()]);
             // exchange_wss.set_subscribe(subscriber_type.into());
             //
-            // let mold_arc = Arc::new(mold.to_string());
-            // tokio::spawn(async move {
-            //     let mold_clone = Arc::clone(&mold_arc);
-            //     loop {
-            //         if let Some(data) = read_rx.next().await {
-            //             trace!("原始数据 data:{:?}",data);
-            //             match mold_clone.as_str() {
-            //                 "depth" => {
-            //                     if data.data != "" {
-            //                         let result = gate_handle::handle_special_depth(data);
-            //                         trace!(?result)
-            //                     }
-            //                 }
-            //                 "ticker" => {
-            //                     if data.data != "" {
-            //                         let result = gate_handle::handle_special_ticker(data);
-            //                         trace!(?result)
-            //                     }
-            //                 }
-            //                 "account" => {
-            //                     if data.data != "" {
-            //                         let result = gate_handle::handle_account_info(data, symbol_format.clone());
-            //                         trace!(?result)
-            //                     }
-            //                 }
-            //                 "orders" => {
-            //                     if data.data != "" {
-            //                         let result = gate_handle::handle_order(data, dec!(1));
-            //                         trace!(?result)
-            //                     }
-            //                 }
-            //                 _ => {
-            //                     error!("没有该命令!mode={}", mold_clone);
-            //                     panic!("没有该命令!mode={}", mold_clone)
-            //                 }
-            //             }
-            //         }
-            //     }
-            // });
-            // let t1 = tokio::spawn(async move {
-            //     //链接
-            //     let bool_v3_clone = Arc::clone(&is_shutdown_arc);
-            //     exchange_wss.ws_connect_async(bool_v3_clone, &write_tx_am, write_rx, read_tx).await.expect("链接失败(内部一个心跳线程应该已经关闭了)");
-            // });
-            // try_join!(t1).unwrap();
-        }
-        ExchangeEnum::BitgetSpot => {
-            // let symbol_format = utils::format_symbol(symbol.to_string(), "-").to_uppercase();
-            // let symbol_back = utils::format_symbol(symbol.to_string(), "_");
-            // trace!(symbol_format);
-            // let name = format!("bitget_spot@{}", symbol.to_string().to_lowercase());
-            // let (write_tx, write_rx) = futures_channel::mpsc::unbounded();
-            // let (read_tx, mut read_rx) = futures_channel::mpsc::unbounded::<ResponseData>();
-            // let write_tx_am = Arc::new(Mutex::new(write_tx));
-            // let is_shutdown_arc = Arc::new(AtomicBool::new(true));
+            // let bool_v3_clone = Arc::clone(&is_shutdown_arc);
+            // let mold_clone = mold.to_string().clone();
+            // let fun = move |data: ResponseData| {
+            //     let symbol_format_c = symbol_format.clone();
+            //     let mold_cc = mold_clone.clone();
             //
-            // let params = BitgetSpotLogin {
-            //     api_key: account_info.bitget_access_key,
-            //     secret_key: account_info.bitget_secret_key,
-            //     passphrase_key: account_info.bitget_pass,
-            // };
-            //
-            // let mut exchange_wss = if ["depth", "ticker"].contains(&mold) {
-            //     BitgetSpotWs::new_label(name, false, Option::from(params), BitgetSpotWsType::Public)
-            // } else {
-            //     BitgetSpotWs::new_label(name, false, Option::from(params), BitgetSpotWsType::Private)
-            // };
-            // exchange_wss.set_symbols(vec![symbol_format]);
-            // exchange_wss.set_subscribe(subscriber_type.into());
-            //
-            // let mold_arc = Arc::new(mold.to_string());
-            // //读取
-            // tokio::spawn(async move {
-            //     loop {
-            //         let mold_clone = Arc::clone(&mold_arc);
-            //         if let Some(data) = read_rx.next().await {
-            //             trace!("原始数据 data:{:?}",data);
-            //             match mold_clone.as_str() {
-            //                 "depth" => {
-            //                     if data.data != "" {
-            //                         let result = bitget_spot_handle::handle_special_depth(data);
-            //                         trace!(?result)
-            //                     }
-            //                 }
-            //                 "ticker" => {
-            //                     if data.data != "" {
-            //                         let result = bitget_spot_handle::handle_special_ticker(data);
-            //                         trace!(?result)
-            //                     }
+            //     async move {
+            //         trace!("原始数据 data:{:?}",data);
+            //         match mold_cc.as_str() {
+            //             "depth" => {
+            //                 if data.data != "" {
+            //                     let result = handle_info::format_depth(ExchangeEnum::GateSwap, &data);
+            //                     trace!(?result)
             //                 }
-            //                 "account" => {
-            //                     if data.data != "" {
-            //                         let result = bitget_spot_handle::handle_account_info(data, symbol_back.clone());
-            //                         trace!(?result)
-            //                     }
+            //             }
+            //             "ticker" => {
+            //                 if data.data != "" {
+            //                     let result = gate_swap_handle::handle_book_ticker(&data);
+            //                     trace!(?result)
             //                 }
-            //                 "orders" => {
-            //                     if data.data != "" {
-            //                         let result = bitget_spot_handle::handle_order(data, dec!(1));
-            //                         trace!(?result)
-            //                     }
+            //             }
+            //             "account" => {
+            //                 if data.data != "" {
+            //                     let result = gate_swap_handle::handle_account_info(&data, &symbol_format_c);
+            //                     trace!(?result)
             //                 }
-            //                 _ => {
-            //                     error!("没有该命令!mode={}", mold_clone);
-            //                     panic!("没有该命令!mode={}", mold_clone)
+            //             }
+            //             "orders" => {
+            //                 if data.data != "" {
+            //                     let result = gate_swap_handle::handle_order(data, dec!(1));
+            //                     trace!(?result)
             //                 }
             //             }
-            //         }
+            //             _ => {
+            //                 error!("没有该命令!mode={}", mold_cc);
+            //                 panic!("没有该命令!mode={}", mold_cc)
+            //             }
+            //         };
             //     }
-            // });
-            // let t1 = tokio::spawn(async move {
-            //     //链接
-            //     let bool_v3_clone = Arc::clone(&is_shutdown_arc);
-            //     exchange_wss.ws_connect_async(bool_v3_clone, &write_tx_am, write_rx, read_tx).await.expect("链接失败(内部一个心跳线程应该已经关闭了)");
-            // });
-            // try_join!(t1).unwrap();
-        }
-        ExchangeEnum::OkxSwap => {
-            let symbol_format = utils::format_symbol(symbol.to_string(), "-").to_uppercase();
-            trace!(symbol_format);
-            let name = format!("okx_swap@{}", symbol.to_string().to_lowercase());
-            let (write_tx, write_rx) = futures_channel::mpsc::unbounded();
-            let (read_tx, mut read_rx) = futures_channel::mpsc::unbounded::<ResponseData>();
-            let write_tx_am = Arc::new(Mutex::new(write_tx));
-            let is_shutdown_arc = Arc::new(AtomicBool::new(true));
-
-            let params = OkxSwapLogin {
-                api_key: account_info.okx_access_key,
-                secret_key: account_info.okx_secret_key,
-                passphrase: account_info.okx_pass,
-            };
-
-            let mut exchange_wss = if ["depth", "ticker"].contains(&mold) {
-                OkxSwapWs::new_label(name, false, Option::from(params), OkxSwapWsType::Public)
-            } else if ["account", "orders", "position"].contains(&mold) {
-                OkxSwapWs::new_label(name, false, Option::from(params), OkxSwapWsType::Private)
-            } else {
-                OkxSwapWs::new_label(name, false, Option::from(params), OkxSwapWsType::Business)
-            };
-
-            exchange_wss.set_symbols(vec![symbol_format.clone()]);
-            exchange_wss.set_subscribe(subscriber_type.into());
-
-            let mold_arc = Arc::new(mold.to_string());
-            tokio::spawn(async move {
-                let mold_clone = Arc::clone(&mold_arc);
-                loop {
-                    if let Some(data) = read_rx.next().await {
-                        trace!("原始数据 data:{:?}",data);
-                        match mold_clone.as_str() {
-                            "depth" => {
-                                if data.data != "" {
-                                    let result = okx_handle::handle_special_depth(data);
-                                    trace!(?result)
-                                }
-                            }
-                            "ticker" => {
-                                if data.data != "" {
-                                    let result = okx_handle::handle_special_ticker(data);
-                                    trace!(?result)
-                                }
-                            }
-                            "account" => {
-                                if data.data != "" {
-                                    let result = okx_handle::handle_account_info(data, symbol_format.clone());
-                                    trace!(?result)
-                                }
-                            }
-                            "position" => {
-                                if data.data != "" {
-                                    let result = okx_handle::handle_position(data, dec!(10));
-                                    trace!(?result)
-                                }
-                            }
-                            "orders" => {
-                                if data.data != "" {
-                                    let result = okx_handle::handle_order(data, dec!(10));
-                                    trace!(?result)
-                                }
-                            }
-                            _ => {
-                                error!("没有该命令!mode={}", mold_clone);
-                                panic!("没有该命令!mode={}", mold_clone)
-                            }
-                        }
-                    }
-                }
-            });
-
-            let t1 = tokio::spawn(async move {
-                //链接
-                let bool_v3_clone = Arc::clone(&is_shutdown_arc);
-                exchange_wss.ws_connect_async(bool_v3_clone, &write_tx_am, write_rx, read_tx).await.expect("链接失败(内部一个心跳线程应该已经关闭了)");
-            });
-            try_join!(t1).unwrap();
-        }
-        ExchangeEnum::HtxSwap => {
-            let symbol_format = utils::format_symbol(symbol.to_string(), "-").to_uppercase();
-            trace!(symbol_format);
-            let name = format!("htx_swap@{}", symbol.to_string().to_lowercase());
-            let (write_tx, write_rx) = futures_channel::mpsc::unbounded();
-            let write_tx_am = Arc::new(Mutex::new(write_tx));
-            let is_shutdown_arc = Arc::new(AtomicBool::new(true));
-
-            let params = HtxSwapLogin {
-                api_key: account_info.htx_access_key,
-                secret: account_info.htx_secret_key,
-            };
-
-            let htx_wss_type = match mold.to_string().clone().as_str() {
-                "depth" => HtxSwapWsType::Public,
-                _ => HtxSwapWsType::Private
-            };
-
-            let mut exchange_wss = HtxSwapWs::new_label(name, Option::from(params), htx_wss_type);
-            exchange_wss.set_symbols(vec![symbol_format.clone()]);
-            exchange_wss.set_subscribe(subscriber_type.into());
-            let bool_v3_clone = Arc::clone(&is_shutdown_arc);
-            let mold_clone = mold.to_string().clone();
-            let fun = move |data: ResponseData| {
-                let symbol_format_c = symbol_format.clone();
-                let mold_cc = mold_clone.clone();
-
-                async move {
-                    trace!("原始数据 data:{:?}",data);
-                    match mold_cc.as_str() {
-                        "depth" => {
-                            if data.data != "" {
-                                let result = handle_info::format_depth(ExchangeEnum::HtxSwap, &data);
-                                trace!("-------------------------------");
-                                trace!(?result)
-                            }
-                        }
-                        "position" => {
-                            if data.data != "" {
-                                let result = htx_swap_handle::handle_position(&data, &dec!(10));
-                                trace!("-------------------------------");
-                                trace!(?result)
-                            }
-                        }
-                        "account" => {
-                            if data.data != "" {
-                                let result = htx_swap_handle::handle_account_info(&data, &symbol_format_c);
-                                trace!("-------------------------------");
-                                trace!(?result)
-                            }
-                        }
-                        "orders" => {
-                            println!("{:?}", data);
-                            if data.data != "" {
-                                let result = htx_swap_handle::handle_order(data, dec!(10));
-                                trace!("-------------------------------");
-                                trace!(?result)
-                            }
-                        }
-                        _ => {
-                            error!("没有该命令!mode={}", mold_cc);
-                            panic!("没有该命令!mode={}", mold_cc)
-                        }
-                    };
-                }
-            };
-            exchange_wss.ws_connect_async(bool_v3_clone, fun, &write_tx_am, write_rx).await.expect("链接失败(内部一个心跳线程应该已经关闭了)");
+            // };
+            // exchange_wss.ws_connect_async(bool_v3_clone, fun, &write_tx_am, write_rx).await.expect("链接失败(内部一个心跳线程应该已经关闭了)");
         }
+        // ExchangeEnum::BitgetSpot => {
+        // let symbol_format = utils::format_symbol(symbol.to_string(), "-").to_uppercase();
+        // let symbol_back = utils::format_symbol(symbol.to_string(), "_");
+        // trace!(symbol_format);
+        // let name = format!("bitget_spot@{}", symbol.to_string().to_lowercase());
+        // let (write_tx, write_rx) = futures_channel::mpsc::unbounded();
+        // let (read_tx, mut read_rx) = futures_channel::mpsc::unbounded::<ResponseData>();
+        // let write_tx_am = Arc::new(Mutex::new(write_tx));
+        // let is_shutdown_arc = Arc::new(AtomicBool::new(true));
+        //
+        // let params = BitgetSpotLogin {
+        //     api_key: account_info.bitget_access_key,
+        //     secret_key: account_info.bitget_secret_key,
+        //     passphrase_key: account_info.bitget_pass,
+        // };
+        //
+        // let mut exchange_wss = if ["depth", "ticker"].contains(&mold) {
+        //     BitgetSpotWs::new_label(name, false, Option::from(params), BitgetSpotWsType::Public)
+        // } else {
+        //     BitgetSpotWs::new_label(name, false, Option::from(params), BitgetSpotWsType::Private)
+        // };
+        // exchange_wss.set_symbols(vec![symbol_format]);
+        // exchange_wss.set_subscribe(subscriber_type.into());
+        //
+        // let mold_arc = Arc::new(mold.to_string());
+        // //读取
+        // tokio::spawn(async move {
+        //     loop {
+        //         let mold_clone = Arc::clone(&mold_arc);
+        //         if let Some(data) = read_rx.next().await {
+        //             trace!("原始数据 data:{:?}",data);
+        //             match mold_clone.as_str() {
+        //                 "depth" => {
+        //                     if data.data != "" {
+        //                         let result = bitget_spot_handle::handle_special_depth(data);
+        //                         trace!(?result)
+        //                     }
+        //                 }
+        //                 "ticker" => {
+        //                     if data.data != "" {
+        //                         let result = bitget_spot_handle::handle_special_ticker(data);
+        //                         trace!(?result)
+        //                     }
+        //                 }
+        //                 "account" => {
+        //                     if data.data != "" {
+        //                         let result = bitget_spot_handle::handle_account_info(data, symbol_back.clone());
+        //                         trace!(?result)
+        //                     }
+        //                 }
+        //                 "orders" => {
+        //                     if data.data != "" {
+        //                         let result = bitget_spot_handle::handle_order(data, dec!(1));
+        //                         trace!(?result)
+        //                     }
+        //                 }
+        //                 _ => {
+        //                     error!("没有该命令!mode={}", mold_clone);
+        //                     panic!("没有该命令!mode={}", mold_clone)
+        //                 }
+        //             }
+        //         }
+        //     }
+        // });
+        // let t1 = tokio::spawn(async move {
+        //     //链接
+        //     let bool_v3_clone = Arc::clone(&is_shutdown_arc);
+        //     exchange_wss.ws_connect_async(bool_v3_clone, &write_tx_am, write_rx, read_tx).await.expect("链接失败(内部一个心跳线程应该已经关闭了)");
+        // });
+        // try_join!(t1).unwrap();
+        // }
+        // ExchangeEnum::OkxSwap => {
+        //     let symbol_format = utils::format_symbol(symbol.to_string(), "-").to_uppercase();
+        //     trace!(symbol_format);
+        //     let name = format!("okx_swap@{}", symbol.to_string().to_lowercase());
+        //     let (write_tx, write_rx) = futures_channel::mpsc::unbounded();
+        //     let (read_tx, mut read_rx) = futures_channel::mpsc::unbounded::<ResponseData>();
+        //     let write_tx_am = Arc::new(Mutex::new(write_tx));
+        //     let is_shutdown_arc = Arc::new(AtomicBool::new(true));
+        //
+        //     let params = OkxSwapLogin {
+        //         api_key: account_info.okx_access_key,
+        //         secret_key: account_info.okx_secret_key,
+        //         passphrase: account_info.okx_pass,
+        //     };
+        //
+        //     let mut exchange_wss = if ["depth", "ticker"].contains(&mold) {
+        //         OkxSwapWs::new_label(name, false, Option::from(params), OkxSwapWsType::Public)
+        //     } else if ["account", "orders", "position"].contains(&mold) {
+        //         OkxSwapWs::new_label(name, false, Option::from(params), OkxSwapWsType::Private)
+        //     } else {
+        //         OkxSwapWs::new_label(name, false, Option::from(params), OkxSwapWsType::Business)
+        //     };
+        //
+        //     exchange_wss.set_symbols(vec![symbol_format.clone()]);
+        //     exchange_wss.set_subscribe(subscriber_type.into());
+        //
+        //     let mold_arc = Arc::new(mold.to_string());
+        //     tokio::spawn(async move {
+        //         let mold_clone = Arc::clone(&mold_arc);
+        //         loop {
+        //             if let Some(data) = read_rx.next().await {
+        //                 trace!("原始数据 data:{:?}",data);
+        //                 match mold_clone.as_str() {
+        //                     "depth" => {
+        //                         if data.data != "" {
+        //                             let result = okx_handle::handle_special_depth(data);
+        //                             trace!(?result)
+        //                         }
+        //                     }
+        //                     "ticker" => {
+        //                         if data.data != "" {
+        //                             let result = okx_handle::handle_special_ticker(data);
+        //                             trace!(?result)
+        //                         }
+        //                     }
+        //                     "account" => {
+        //                         if data.data != "" {
+        //                             let result = okx_handle::handle_account_info(data, symbol_format.clone());
+        //                             trace!(?result)
+        //                         }
+        //                     }
+        //                     "position" => {
+        //                         if data.data != "" {
+        //                             let result = okx_handle::handle_position(data, dec!(10));
+        //                             trace!(?result)
+        //                         }
+        //                     }
+        //                     "orders" => {
+        //                         if data.data != "" {
+        //                             let result = okx_handle::handle_order(data, dec!(10));
+        //                             trace!(?result)
+        //                         }
+        //                     }
+        //                     _ => {
+        //                         error!("没有该命令!mode={}", mold_clone);
+        //                         panic!("没有该命令!mode={}", mold_clone)
+        //                     }
+        //                 }
+        //             }
+        //         }
+        //     });
+        //
+        //     let t1 = tokio::spawn(async move {
+        //         //链接
+        //         let bool_v3_clone = Arc::clone(&is_shutdown_arc);
+        //         exchange_wss.ws_connect_async(bool_v3_clone, &write_tx_am, write_rx, read_tx).await.expect("链接失败(内部一个心跳线程应该已经关闭了)");
+        //     });
+        //     try_join!(t1).unwrap();
+        // }
+        // ExchangeEnum::HtxSwap => {
+        //     let symbol_format = utils::format_symbol(symbol.to_string(), "-").to_uppercase();
+        //     trace!(symbol_format);
+        //     let name = format!("htx_swap@{}", symbol.to_string().to_lowercase());
+        //     let (write_tx, write_rx) = futures_channel::mpsc::unbounded();
+        //     let write_tx_am = Arc::new(Mutex::new(write_tx));
+        //     let is_shutdown_arc = Arc::new(AtomicBool::new(true));
+        //
+        //     let params = HtxSwapLogin {
+        //         api_key: account_info.htx_access_key,
+        //         secret: account_info.htx_secret_key,
+        //     };
+        //
+        //     let htx_wss_type = match mold.to_string().clone().as_str() {
+        //         "depth" => HtxSwapWsType::Public,
+        //         _ => HtxSwapWsType::Private
+        //     };
+        //
+        //     let mut exchange_wss = HtxSwapWs::new_label(name, Option::from(params), htx_wss_type);
+        //     exchange_wss.set_symbols(vec![symbol_format.clone()]);
+        //     exchange_wss.set_subscribe(subscriber_type.into());
+        //     let bool_v3_clone = Arc::clone(&is_shutdown_arc);
+        //     let mold_clone = mold.to_string().clone();
+        //     let fun = move |data: ResponseData| {
+        //         let symbol_format_c = symbol_format.clone();
+        //         let mold_cc = mold_clone.clone();
+        //
+        //         async move {
+        //             trace!("原始数据 data:{:?}",data);
+        //             match mold_cc.as_str() {
+        //                 "depth" => {
+        //                     if data.data != "" {
+        //                         let result = handle_info::format_depth(ExchangeEnum::HtxSwap, &data);
+        //                         trace!("-------------------------------");
+        //                         trace!(?result)
+        //                     }
+        //                 }
+        //                 "position" => {
+        //                     if data.data != "" {
+        //                         let result = htx_swap_handle::handle_position(&data, &dec!(10));
+        //                         trace!("-------------------------------");
+        //                         trace!(?result)
+        //                     }
+        //                 }
+        //                 "account" => {
+        //                     if data.data != "" {
+        //                         let result = htx_swap_handle::handle_account_info(&data, &symbol_format_c);
+        //                         trace!("-------------------------------");
+        //                         trace!(?result)
+        //                     }
+        //                 }
+        //                 "orders" => {
+        //                     println!("{:?}", data);
+        //                     if data.data != "" {
+        //                         let result = htx_swap_handle::handle_order(data, dec!(10));
+        //                         trace!("-------------------------------");
+        //                         trace!(?result)
+        //                     }
+        //                 }
+        //                 _ => {
+        //                     error!("没有该命令!mode={}", mold_cc);
+        //                     panic!("没有该命令!mode={}", mold_cc)
+        //                 }
+        //             };
+        //         }
+        //     };
+        //     exchange_wss.ws_connect_async(bool_v3_clone, fun, &write_tx_am, write_rx).await.expect("链接失败(内部一个心跳线程应该已经关闭了)");
+        // }
         _ => {
-            error!("该交易所不支持!test_new_exchange_wss:{:?}",exchange);
+            error!("该交易所不支持!test_new_exchange_wss:{:?}", exchange);
             panic!("该交易所不支持!test_new_exchange_wss:{:?}", exchange)
         }
     }

+ 4 - 1
standard/tests/gate_swap_test.rs

@@ -3,9 +3,12 @@ mod exchange_test;
 use std::collections::BTreeMap;
 use std::env;
 use std::io::Error;
+use chrono::Utc;
 use rust_decimal_macros::dec;
 use tokio::sync::mpsc;
+use tokio::time::Instant;
 use tracing::{instrument, trace};
+use global::trace_stack::TraceStack;
 use standard::exchange::{Exchange, ExchangeEnum};
 use standard::{Order, OrderCommand, Platform, utils};
 use crate::exchange_test::{test_new_exchange};
@@ -266,7 +269,7 @@ async fn test_command_order() {
     command.limits_open.insert("888888".to_string(), vec!["100".to_string(), "kd".to_string(), "0.18".to_string(), "888888".to_string()]);
     command.limits_close.insert("999999".to_string(), vec!["100".to_string(), "kk".to_string(), "0.25".to_string(), "999999".to_string()]);
     command.check.insert("888888".to_string(), vec!["999999".to_string(), "".to_string()]);
-    gate_swap_exchange.command_order(command, Default::default()).await;
+    gate_swap_exchange.command_order(&mut command, &TraceStack::new(Utc::now().timestamp_micros(), Instant::now())).await;
 
     loop {
         if let Ok(order) = order_receiver.try_recv() {

+ 282 - 0
standard/tests/phemex_swap_test.rs

@@ -0,0 +1,282 @@
+mod exchange_test;
+
+use std::collections::BTreeMap;
+use std::env;
+use std::io::Error;
+use chrono::Utc;
+use rust_decimal_macros::dec;
+use tokio::sync::mpsc;
+use tokio::time::Instant;
+use tracing::{instrument, trace};
+use global::trace_stack::TraceStack;
+use standard::exchange::{Exchange, ExchangeEnum};
+use standard::{Order, OrderCommand, Platform, utils};
+use crate::exchange_test::{test_new_exchange};
+
+const SYMBOL: &str = "1000PEPE_USDT";
+
+// 测试获取Exchange实体
+#[tokio::test]
+#[instrument(level = "TRACE")]
+async fn test_get_self_exchange() {
+    global::log_utils::init_log_with_trace();
+
+    let phemex_swap_exchange: Box<dyn Platform> = test_new_exchange(ExchangeEnum::PhemexSwap, SYMBOL).await;
+    let phemex_get_self_exchange = phemex_swap_exchange.get_self_exchange();
+    trace!(?phemex_get_self_exchange);
+}
+
+// 测试获取交易对信息
+#[tokio::test]
+#[instrument(level = "TRACE")]
+async fn test_get_self_symbol() {
+    global::log_utils::init_log_with_trace();
+
+    let phemex_swap_exchange: Box<dyn Platform> = test_new_exchange(ExchangeEnum::PhemexSwap, SYMBOL).await;
+    let phemex_get_self_symbol = phemex_swap_exchange.get_self_symbol();
+    trace!(?phemex_get_self_symbol);
+}
+
+// 测试获取是否使用高速通道
+#[tokio::test]
+#[instrument(level = "TRACE")]
+async fn test_get_self_is_colo() {
+    global::log_utils::init_log_with_trace();
+
+    let phemex_swap_exchange: Box<dyn Platform> = test_new_exchange(ExchangeEnum::PhemexSwap, SYMBOL).await;
+    let phemex_get_self_is_colo = phemex_swap_exchange.get_self_is_colo();
+    trace!(?phemex_get_self_is_colo);
+}
+
+// 测试获取登录params信息
+#[tokio::test]
+#[instrument(level = "TRACE")]
+async fn test_get_self_params() {
+    global::log_utils::init_log_with_trace();
+
+    let phemex_swap_exchange: Box<dyn Platform> = test_new_exchange(ExchangeEnum::PhemexSwap, SYMBOL).await;
+    let phemex_get_self_params = phemex_swap_exchange.get_self_params();
+    trace!("phemex_get_self_params={:?}",phemex_get_self_params);
+}
+
+// 测试获取Market信息
+#[tokio::test]
+#[instrument(level = "TRACE")]
+async fn test_get_self_market() {
+    global::log_utils::init_log_with_trace();
+
+    let phemex_swap_exchange: Box<dyn Platform> = test_new_exchange(ExchangeEnum::PhemexSwap, SYMBOL).await;
+    let phemex_get_self_market = phemex_swap_exchange.get_self_market();
+    trace!(?phemex_get_self_market);
+}
+
+// 测试获取请求时间信息
+#[tokio::test]
+#[instrument(level = "TRACE")]
+async fn test_get_request_delays() {
+    global::log_utils::init_log_with_trace();
+
+    let phemex_swap_exchange: Box<dyn Platform> = test_new_exchange(ExchangeEnum::PhemexSwap, SYMBOL).await;
+    let phemex_get_request_delays = phemex_swap_exchange.get_request_delays();
+    trace!(?phemex_get_request_delays);
+}
+
+// 测试获取请求平均时间信息
+#[tokio::test]
+#[instrument(level = "TRACE")]
+async fn test_get_request_avg_delay() {
+    global::log_utils::init_log_with_trace();
+
+    let phemex_swap_exchange: Box<dyn Platform> = test_new_exchange(ExchangeEnum::PhemexSwap, SYMBOL).await;
+    let phemex_get_request_avg_delay = phemex_swap_exchange.get_request_avg_delay();
+    trace!(?phemex_get_request_avg_delay);
+}
+
+// 测试获取最大请求时间信息
+#[tokio::test]
+#[instrument(level = "TRACE")]
+async fn test_get_request_max_delay() {
+    global::log_utils::init_log_with_trace();
+
+    let phemex_swap_exchange: Box<dyn Platform> = test_new_exchange(ExchangeEnum::PhemexSwap, SYMBOL).await;
+    let phemex_get_request_max_delay = phemex_swap_exchange.get_request_max_delay();
+    trace!(?phemex_get_request_max_delay);
+}
+
+// 测试获取服务器时间
+#[tokio::test]
+#[instrument(level = "TRACE")]
+async fn test_get_server_time() {
+    global::log_utils::init_log_with_trace();
+
+    let mut phemex_swap_exchange: Box<dyn Platform> = test_new_exchange(ExchangeEnum::PhemexSwap, SYMBOL).await;
+    let phemex_get_server_time = phemex_swap_exchange.get_server_time().await;
+    trace!(?phemex_get_server_time);
+}
+
+// 测试获取账号信息
+#[tokio::test]
+#[instrument(level = "TRACE")]
+async fn test_get_account() {
+    global::log_utils::init_log_with_trace();
+
+    let mut phemex_swap_exchange: Box<dyn Platform> = test_new_exchange(ExchangeEnum::PhemexSwap, SYMBOL).await;
+    let phemex_get_account = phemex_swap_exchange.get_account().await;
+    trace!(?phemex_get_account);
+}
+
+// 测试获取持仓信息
+#[tokio::test]
+#[instrument(level = "TRACE")]
+async fn test_get_position() {
+    global::log_utils::init_log_with_trace();
+
+    let mut phemex_swap_exchange: Box<dyn Platform> = test_new_exchange(ExchangeEnum::PhemexSwap, SYMBOL).await;
+    let phemex_get_position = phemex_swap_exchange.get_position().await;
+    trace!(?phemex_get_position);
+}
+
+// 测试获取所有持仓信息
+#[tokio::test]
+#[instrument(level = "TRACE")]
+async fn test_get_positions() {
+    global::log_utils::init_log_with_trace();
+
+    let mut phemex_swap_exchange: Box<dyn Platform> = test_new_exchange(ExchangeEnum::PhemexSwap, SYMBOL).await;
+    let phemex_get_positions = phemex_swap_exchange.get_positions().await;
+    trace!(?phemex_get_positions);
+}
+
+// 测试获取Ticker信息
+#[tokio::test]
+#[instrument(level = "TRACE")]
+async fn test_get_ticker() {
+    global::log_utils::init_log_with_trace();
+
+    let mut phemex_swap_exchange: Box<dyn Platform> = test_new_exchange(ExchangeEnum::PhemexSwap, SYMBOL).await;
+    let phemex_get_ticker = phemex_swap_exchange.get_ticker().await;
+    trace!(?phemex_get_ticker);
+}
+
+// 测试获取Market信息
+#[tokio::test]
+#[instrument(level = "TRACE")]
+async fn test_get_market() {
+    global::log_utils::init_log_with_trace();
+
+    let mut phemex_swap_exchange: Box<dyn Platform> = test_new_exchange(ExchangeEnum::PhemexSwap, SYMBOL).await;
+    let phemex_get_market = phemex_swap_exchange.get_market().await;
+    trace!(?phemex_get_market);
+}
+
+// 测试获取Order详情信息
+#[tokio::test]
+#[instrument(level = "TRACE")]
+async fn test_get_order_detail() {
+    global::log_utils::init_log_with_trace();
+
+    let mut phemex_swap_exchange: Box<dyn Platform> = test_new_exchange(ExchangeEnum::PhemexSwap, SYMBOL).await;
+    let phemex_get_order_detail = phemex_swap_exchange.get_order_detail("", "999999").await;
+    trace!(?phemex_get_order_detail);
+}
+
+// 测试获取Order列表信息
+#[tokio::test]
+#[instrument(level = "TRACE")]
+async fn test_get_orders_list() {
+    global::log_utils::init_log_with_trace();
+
+    let mut phemex_swap_exchange: Box<dyn Platform> = test_new_exchange(ExchangeEnum::PhemexSwap, SYMBOL).await;
+    let phemex_get_orders_list = phemex_swap_exchange.get_orders_list("finished").await;
+    trace!(?phemex_get_orders_list);
+}
+
+// 测试下单
+#[tokio::test]
+#[instrument(level = "TRACE")]
+async fn test_take_order() {
+    global::log_utils::init_log_with_trace();
+
+    let mut phemex_swap_exchange: Box<dyn Platform> = test_new_exchange(ExchangeEnum::PhemexSwap, SYMBOL).await;
+    let phemex_take_order = phemex_swap_exchange.take_order("999999", "pk", dec!(0), dec!(10)).await;
+    trace!(?phemex_take_order);
+}
+
+// 测试撤销订单
+#[tokio::test]
+#[instrument(level = "TRACE")]
+async fn test_cancel_order() {
+    global::log_utils::init_log_with_trace();
+
+    let mut phemex_swap_exchange: Box<dyn Platform> = test_new_exchange(ExchangeEnum::PhemexSwap, SYMBOL).await;
+    let phemex_cancel_order = phemex_swap_exchange.cancel_order("6632dfd9-6ea5-4c11-87d3-a757960ea153", "").await;
+    trace!(?phemex_cancel_order);
+}
+
+// 测试批量撤销订单
+#[tokio::test]
+#[instrument(level = "TRACE")]
+async fn test_cancel_orders() {
+    global::log_utils::init_log_with_trace();
+
+    let mut phemex_swap_exchange: Box<dyn Platform> = test_new_exchange(ExchangeEnum::PhemexSwap, SYMBOL).await;
+    let phemex_cancel_orders = phemex_swap_exchange.cancel_orders().await;
+    trace!(?phemex_cancel_orders);
+}
+
+// 测试设置持仓模式
+#[tokio::test]
+#[instrument(level = "TRACE")]
+async fn test_set_dual_mode() {
+    global::log_utils::init_log_with_trace();
+
+    let mut phemex_swap_exchange: Box<dyn Platform> = test_new_exchange(ExchangeEnum::PhemexSwap, SYMBOL).await;
+    let phemex_set_dual_mode = phemex_swap_exchange.set_dual_mode("usdt", true).await;
+    trace!(?phemex_set_dual_mode);
+}
+
+// 测试设置杠杆
+#[tokio::test]
+#[instrument(level = "TRACE")]
+async fn test_set_dual_leverage() {
+    global::log_utils::init_log_with_trace();
+
+    let mut phemex_swap_exchange: Box<dyn Platform> = test_new_exchange(ExchangeEnum::PhemexSwap, SYMBOL).await;
+    let phemex_set_dual_leverage = phemex_swap_exchange.set_dual_leverage("10").await;
+    trace!(?phemex_set_dual_leverage);
+}
+
+// 测试指令下单
+#[tokio::test]
+#[instrument(level = "TRACE")]
+async fn test_command_order() {
+    global::log_utils::init_log_with_trace();
+    utils::proxy_handle(Some("phemex"));
+
+    let (order_sender, mut order_receiver): (mpsc::Sender<Order>, mpsc::Receiver<Order>) = mpsc::channel(1024);
+    let (error_sender, mut error_receiver): (mpsc::Sender<Error>, mpsc::Receiver<Error>) = mpsc::channel(1024);
+
+    let mut params: BTreeMap<String, String> = BTreeMap::new();
+    let access_key = env::var("phemex_access_key").unwrap_or("".to_string());
+    let secret_key = env::var("phemex_secret_key").unwrap_or("".to_string());
+    params.insert("access_key".to_string(), access_key);
+    params.insert("secret_key".to_string(), secret_key);
+
+    let mut phemex_swap_exchange: Box<dyn Platform> = Exchange::new(ExchangeEnum::PhemexSwap, SYMBOL.to_string(), false, params, order_sender, error_sender).await;
+
+    let mut command = OrderCommand::new();
+    command.cancel.insert("888888".to_string(), vec!["888888".to_string(), "".to_string()]);
+    command.limits_open.insert("888888".to_string(), vec!["100".to_string(), "kd".to_string(), "0.18".to_string(), "888888".to_string()]);
+    command.limits_close.insert("999999".to_string(), vec!["100".to_string(), "kk".to_string(), "0.25".to_string(), "999999".to_string()]);
+    command.check.insert("888888".to_string(), vec!["999999".to_string(), "".to_string()]);
+    phemex_swap_exchange.command_order(&mut command, &TraceStack::new(Utc::now().timestamp_micros(), Instant::now())).await;
+
+    loop {
+        if let Ok(order) = order_receiver.try_recv() {
+            trace!(?order);
+        }
+        if let Ok(error) = error_receiver.try_recv() {
+            trace!(?error);
+        }
+    }
+}