Explorar el Código

数据前置处理

skyffire hace 1 año
padre
commit
40a39b0cc5
Se han modificado 61 ficheros con 14044 adiciones y 6116 borrados
  1. 314 0
      exchanges/src/bingx_swap_rest.rs
  2. 318 0
      exchanges/src/bingx_swap_ws.rs
  3. 399 0
      exchanges/src/bitmart_swap_rest.rs
  4. 459 0
      exchanges/src/bitmart_swap_ws.rs
  5. 313 0
      exchanges/src/coinsph_swap_rest.rs
  6. 400 0
      exchanges/src/coinsph_swap_ws.rs
  7. 307 0
      exchanges/src/cointr_swap_rest.rs
  8. 434 0
      exchanges/src/cointr_swap_ws.rs
  9. 15 3
      exchanges/src/lib.rs
  10. 314 0
      exchanges/src/mexc_swap_rest.rs
  11. 368 0
      exchanges/src/mexc_swap_ws.rs
  12. 305 580
      exchanges/src/okx_swap_rest.rs
  13. 314 0
      exchanges/src/phemex_swap_rest.rs
  14. 339 0
      exchanges/src/phemex_swap_ws.rs
  15. 305 0
      exchanges/src/woo_swap_rest.rs
  16. 411 0
      exchanges/src/woo_swap_ws.rs
  17. 68 25
      standard/src/binance_swap_handle.rs
  18. 259 0
      standard/src/bingx_swap.rs
  19. 105 0
      standard/src/bingx_swap_handle.rs
  20. 4 4
      standard/src/bitget_spot_handle.rs
  21. 668 668
      standard/src/bitget_swap.rs
  22. 220 177
      standard/src/bitget_swap_handle.rs
  23. 220 0
      standard/src/bitmart_swap.rs
  24. 105 0
      standard/src/bitmart_swap_handle.rs
  25. 748 748
      standard/src/bybit_swap.rs
  26. 167 172
      standard/src/bybit_swap_handle.rs
  27. 771 771
      standard/src/coinex_swap.rs
  28. 180 158
      standard/src/coinex_swap_handle.rs
  29. 252 0
      standard/src/coinsph_swap.rs
  30. 94 0
      standard/src/coinsph_swap_handle.rs
  31. 268 0
      standard/src/cointr_swap.rs
  32. 55 0
      standard/src/cointr_swap_handle.rs
  33. 49 31
      standard/src/exchange.rs
  34. 270 0
      standard/src/exchange_struct_handler.rs
  35. 67 8
      standard/src/gate_spot.rs
  36. 45 0
      standard/src/gate_spot_handle.rs
  37. 64 26
      standard/src/gate_swap_handle.rs
  38. 639 639
      standard/src/htx_swap.rs
  39. 182 135
      standard/src/htx_swap_handle.rs
  40. 4 4
      standard/src/kucoin_spot_handle.rs
  41. 671 671
      standard/src/kucoin_swap.rs
  42. 136 0
      standard/src/kucoin_swap_handle.rs
  43. 142 48
      standard/src/lib.rs
  44. 261 0
      standard/src/mexc_swap.rs
  45. 92 0
      standard/src/mexc_swap_handle.rs
  46. 54 0
      standard/src/okx_swap_handle.rs
  47. 265 0
      standard/src/phemex_swap.rs
  48. 55 0
      standard/src/phemex_swap_handle.rs
  49. 10 10
      standard/src/utils.rs
  50. 268 0
      standard/src/woo_swap.rs
  51. 52 0
      standard/src/woo_swap_handle.rs
  52. 41 43
      strategy/src/binance_usdt_swap.rs
  53. 190 189
      strategy/src/bitget_usdt_swap.rs
  54. 246 245
      strategy/src/bybit_usdt_swap.rs
  55. 16 16
      strategy/src/clear_core.rs
  56. 270 270
      strategy/src/coinex_usdt_swap.rs
  57. 20 18
      strategy/src/core.rs
  58. 42 52
      strategy/src/exchange_disguise.rs
  59. 61 72
      strategy/src/gate_usdt_swap.rs
  60. 168 168
      strategy/src/htx_usdt_swap.rs
  61. 165 165
      strategy/src/kucoin_swap.rs

+ 314 - 0
exchanges/src/bingx_swap_rest.rs

@@ -0,0 +1,314 @@
+use std::collections::BTreeMap;
+use chrono::Utc;
+use reqwest::header::HeaderMap;
+use reqwest::{Client};
+use rust_decimal::Decimal;
+use rust_decimal::prelude::FromPrimitive;
+use rust_decimal_macros::dec;
+use tracing::{error, info, trace};
+use crate::http_tool::RestTool;
+use crate::response_base::ResponseData;
+use ring::hmac;
+use serde_json::Value;
+
+#[derive(Clone, Debug)]
+pub struct BingxSwapRest {
+    pub tag: String,
+    base_url: String,
+    client: reqwest::Client,
+    /*******参数*/
+    //是否需要登录
+    //登录所需参数
+    login_param: BTreeMap<String, String>,
+    delays: Vec<i64>,
+    max_delay: i64,
+    avg_delay: Decimal,
+
+}
+
+impl BingxSwapRest {
+    /*******************************************************************************************************/
+    /*****************************************获取一个对象****************************************************/
+    /*******************************************************************************************************/
+
+    pub fn new(is_colo: bool, login_param: BTreeMap<String, String>) -> BingxSwapRest
+    {
+        return BingxSwapRest::new_with_tag("default-BingxSwapRest".to_string(), is_colo, login_param);
+    }
+    pub fn new_with_tag(tag: String, is_colo: bool, login_param: BTreeMap<String, String>) -> BingxSwapRest {
+        let base_url = if is_colo {
+            "https://open-api.bingx.com".to_string()
+        } else {
+            "https://open-api.bingx.com".to_string()
+        };
+
+        if is_colo {
+            info!("开启高速(未配置,走普通:{})通道",base_url);
+        } else {
+            info!("走普通通道:{}",base_url);
+        }
+        /*****返回结构体*******/
+        BingxSwapRest {
+            tag,
+            base_url,
+            client: Client::new(),
+            login_param,
+            delays: vec![],
+            max_delay: 0,
+            avg_delay: dec!(0.0),
+        }
+    }
+
+    /*******************************************************************************************************/
+    /*****************************************rest请求函数********************************************************/
+    /*******************************************************************************************************/
+    //查詢合約基礎信息
+    pub async fn get_market(&mut self, params: Value) -> ResponseData {
+        let data = self.request("GET".to_string(),
+                                "/openApi/swap/v2".to_string(),
+                                "/quote/contracts".to_string(),
+                                false,
+                                params,
+        ).await;
+        data
+    }
+
+    /*******************************************************************************************************/
+    /*****************************************工具函数********************************************************/
+    /*******************************************************************************************************/
+    pub fn get_delays(&self) -> Vec<i64> {
+        self.delays.clone()
+    }
+    pub fn get_avg_delay(&self) -> Decimal {
+        self.avg_delay.clone()
+    }
+    pub fn get_max_delay(&self) -> i64 {
+        self.max_delay.clone()
+    }
+    fn get_delay_info(&mut self) {
+        let last_100 = if self.delays.len() > 100 {
+            self.delays[self.delays.len() - 100..].to_vec()
+        } else {
+            self.delays.clone()
+        };
+
+        let max_value = last_100.iter().max().unwrap();
+        if max_value.clone().to_owned() > self.max_delay {
+            self.max_delay = max_value.clone().to_owned();
+        }
+
+        let sum: i64 = last_100.iter().sum();
+        let sum_v = Decimal::from_i64(sum).unwrap();
+        let len_v = Decimal::from_u64(last_100.len() as u64).unwrap();
+        self.avg_delay = (sum_v / len_v).round_dp(1);
+        self.delays = last_100.clone().into_iter().collect();
+    }
+    //调用请求
+    pub async fn request(&mut self,
+                         method: String,
+                         prefix_url: String,
+                         request_url: String,
+                         is_login: bool,
+                         mut  params: Value) -> ResponseData
+    {
+        trace!("login_param:{:?}", self.login_param);
+        //解析账号信息
+        let mut access_key = "".to_string();
+        let mut secret_key = "".to_string();
+        let mut passphrase = "".to_string();
+        if self.login_param.contains_key("access_key") {
+            access_key = self.login_param.get("access_key").unwrap().to_string();
+        }
+        if self.login_param.contains_key("secret_key") {
+            secret_key = self.login_param.get("secret_key").unwrap().to_string();
+        }
+        if self.login_param.contains_key("pass_key") {
+            passphrase = self.login_param.get("pass_key").unwrap().to_string();
+        }
+        let mut is_login_param = true;
+        if access_key == "" || secret_key == "" || passphrase == "" {
+            is_login_param = false
+        }
+
+        //每个接口都有的参数
+        let timestamp = Utc::now().timestamp_millis();
+        let recv_window = 3000;
+        params["timestamp"] = serde_json::json!(timestamp);
+        params["recvWindow"] = serde_json::json!(recv_window);
+
+
+        //请求类型不同,可能请求头body 不同
+        let mut body = "{}".to_string();
+        let mut headers = HeaderMap::new();
+        if method == "POST" {
+            headers.insert("Content-Type", "application/x-www-form-urlencoded".parse().unwrap());
+            body = params.to_string();
+        }
+
+        //是否需要登录-- 组装sing
+        if is_login {
+            if !is_login_param {
+                let e = ResponseData::error(self.tag.clone(), "登录参数错误!".to_string());
+                return e;
+            } else {
+                // //需要登录-且登录参数齐全
+                // trace!("param:{}", params);
+                // trace!("body:{}", body);
+                // //组装sing
+                // let sing = Self::sign(secret_key.clone(),
+                //                       method.clone(),
+                //                       prefix_url.clone(),
+                //                       request_url.clone(),
+                //                       params.clone(),
+                //                       body.clone(),
+                //                       timestamp.clone(),
+                // );
+                // //组装header
+                // headers.extend(Self::headers(sing, timestamp, passphrase, access_key));
+            }
+        }
+
+
+        // trace!("headers:{:?}", headers);
+        // let base_url = format!("{}{}", prefix_url.clone(), request_url.clone());
+        let start_time = chrono::Utc::now().timestamp_millis();
+        let response = self.http_tool(
+            format!("{}{}", prefix_url.clone(), request_url.clone()),
+            method.to_string(),
+            params.to_string(),
+            body,
+            headers,
+        ).await;
+
+        let time_array = chrono::Utc::now().timestamp_millis() - start_time;
+        self.delays.push(time_array);
+        self.get_delay_info();
+
+        response
+        //
+        // let time_array = chrono::Utc::now().timestamp_millis() - start_time;
+        // self.delays.push(time_array);
+        // self.get_delay_info();
+        // let res_data = Self::res_data_analysis(get_response, base_url, params.to_string());
+        // res_data
+    }
+
+    // pub fn headers(_: String, _timestamp: String, passphrase: String, access_key: String) -> HeaderMap {
+    //     let mut headers = HeaderMap::new();
+    //     // headers.insert("OK-ACCESS-KEY", access_key.parse().unwrap());
+    //     // headers.insert("OK-ACCESS-SIGN", sign.parse().unwrap());
+    //     // headers.insert("OK-ACCESS-TIMESTAMP", timestamp.parse().unwrap());
+    //     // headers.insert("OK-ACCESS-PASSPHRASE", passphrase.parse().unwrap());
+    //     headers
+    // }
+    pub fn sign(secret_key: String,
+                method: String, prefix_url: String, request_url: String,
+                params: String, body: String, timestamp: String) -> String
+    {
+        /*签名生成*/
+        let url_param_str = RestTool::parse_params_to_str(params);
+        let base_url = if method == "GET" {
+            format!("{}{}?{}", prefix_url, request_url, url_param_str)
+        } else {
+            format!("{}{}", prefix_url, request_url)
+        };
+
+        // 时间戳 + 请求类型+ 请求参数字符串
+        let message = format!("{}{}{}{}", timestamp, method, base_url, body);
+        trace!("message:{}",message);
+
+        // 做签名
+        let hmac_key = ring::hmac::Key::new(hmac::HMAC_SHA256, secret_key.as_bytes());
+        let result = ring::hmac::sign(&hmac_key, &message.as_bytes());
+        let sign = base64::encode(result);
+        sign
+    }
+
+    // async fn http_tool(&mut self, request_path: String, request_type: String, params: String, headers: HeaderMap) -> Result<ResponseData, reqwest::Error> {
+    async fn http_tool(&mut self, request_path: String,
+                       request_type: String,
+                       params: String,
+                       body: String,
+                       headers: HeaderMap) -> ResponseData {
+        /****请求接口与 地址*/
+        let url = format!("{}{}", self.base_url.to_string(), request_path);
+        let request_type = request_type.clone().to_uppercase();
+        let addrs_url: String = if RestTool::parse_params_to_str(params.clone()) == "" {
+            url.clone()
+        } else {
+            format!("{}?{}", url.clone(), RestTool::parse_params_to_str(params.clone()))
+        };
+
+        trace!("url-----:???{}",url.clone());
+        trace!("addrs_url-----:???{}",addrs_url.clone());
+        trace!("params-----:???{}",params.clone());
+        trace!("body-----:???{}",body.clone());
+
+        let request_builder = match request_type.as_str() {
+            "GET" => self.client.get(addrs_url.clone()).headers(headers),
+            "POST" => self.client.post(url.clone()).body(body).headers(headers),
+            // "DELETE" => self.client.delete(addrs_url.clone()).headers(headers),
+            // "PUT" => self.client.put(url.clone()).json(&params),
+            _ => {
+                panic!("{}", format!("错误的请求类型:{}", request_type.clone()))
+            }
+        };
+
+        // 读取响应的内容
+        let response = request_builder.send().await.unwrap();
+        let is_success = response.status().is_success(); // 先检查状态码
+        let text = response.text().await.unwrap();
+        // trace!("text:???{:?}",text);
+        return if is_success {
+            self.on_success_data(&text)
+        } else {
+            self.on_error_data(&text, &addrs_url, &params)
+        };
+    }
+    pub fn on_success_data(&mut self, text: &String) -> ResponseData {
+        let json_value = serde_json::from_str::<Value>(&text).unwrap();
+        // return  ResponseData::new(self.tag.clone(), 200, "success".to_string(), json_value);
+
+        let code = json_value["code"].as_i64().unwrap();
+        match code {
+            0 => {
+                //判断是否有code ,没有表示特殊接口,直接返回
+                if json_value.get("data").is_some() {
+                    let data = json_value.get("data").unwrap();
+                    ResponseData::new(self.tag.clone(), 200, "success".to_string(), data.clone())
+                } else {
+                    ResponseData::new(self.tag.clone(), 200, "success".to_string(), json_value)
+                }
+            }
+            _ => {
+                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 {
+        let json_value = serde_json::from_str::<Value>(&text);
+
+        match json_value {
+            Ok(data) => {
+                let message;
+
+                if !data["message"].is_null() {
+                    message = format!("{}:{}", data["tag"].as_str().unwrap(), data["message"].as_str().unwrap());
+                } else {
+                    message = data["tag"].to_string();
+                }
+
+                let mut error = ResponseData::error(self.tag.clone(), message);
+                error.message = format!("请求地址:{}, 请求参数:{}, 报错内容:{}。", base_url, params, error.message);
+                error
+            }
+            Err(e) => {
+                error!("解析错误:{:?}", e);
+                let error = ResponseData::error("".to_string(),
+                                                format!("json 解析失败:{},相关参数:{}", e, text));
+                error
+            }
+        }
+    }
+}

+ 318 - 0
exchanges/src/bingx_swap_ws.rs

@@ -0,0 +1,318 @@
+use std::io::Read;
+use std::sync::Arc;
+use std::sync::atomic::AtomicBool;
+use std::time::Duration;
+
+use flate2::read::GzDecoder;
+use futures_channel::mpsc::{UnboundedReceiver, UnboundedSender};
+use serde_json::json;
+use serde_json::Value;
+use tokio::sync::Mutex;
+use tokio_tungstenite::tungstenite::{Error, Message};
+use tracing::{error, info, trace};
+
+use crate::response_base::ResponseData;
+use crate::socket_tool::AbstractWsMode;
+
+//类型
+pub enum BingxSwapWsType {
+    PublicAndPrivate,
+}
+
+
+#[derive(Debug)]
+#[derive(Clone)]
+pub struct BingxSwapWsParam {
+    pub token: String,
+    pub ws_url: String,
+    pub ws_ping_interval: i64,
+    pub ws_ping_timeout: i64,
+    pub is_ok_subscribe: bool,
+}
+
+//订阅频道
+#[derive(Clone)]
+pub enum BingxSwapSubscribeType {
+    // 深度
+    PuFuturesDepth,
+    // 公开成交
+    PuFuturesTrades,
+    // K线数据
+    PuFuturesRecords,
+}
+
+//账号信息
+#[derive(Clone, Debug)]
+pub struct BingxSwapLogin {
+    pub access_key: String,
+    pub secret_key: String,
+    pub pass_key: String,
+}
+
+#[derive(Clone)]
+#[allow(dead_code)]
+pub struct BingxSwapWs {
+    //类型
+    tag: String,
+    //地址
+    address_url: String,
+    //账号
+    login_param: Option<BingxSwapLogin>,
+    //登录数据
+    ws_param: BingxSwapWsParam,
+    //币对
+    symbol_s: Vec<String>,
+    //订阅
+    subscribe_types: Vec<BingxSwapSubscribeType>,
+    //心跳间隔
+    heartbeat_time: u64,
+}
+
+impl BingxSwapWs {
+    /*******************************************************************************************************/
+    /*****************************************获取一个对象****************************************************/
+    /*******************************************************************************************************/
+    pub fn new(is_colo: bool, login_param: Option<BingxSwapLogin>, ws_type: BingxSwapWsType) -> BingxSwapWs {
+        return Self::new_with_tag("default-BingxSwapWs".to_string(), is_colo, login_param, ws_type);
+    }
+    pub fn new_with_tag(tag: String, is_colo: bool, login_param: Option<BingxSwapLogin>, ws_type: BingxSwapWsType) -> BingxSwapWs {
+        /*******公共频道-私有频道数据组装*/
+        let address_url = match ws_type {
+            BingxSwapWsType::PublicAndPrivate => {
+                let url = "wss://open-api-swap.bingx.com/swap-market".to_string();
+                info!("走普通通道(不支持colo通道):{}", url);
+                url
+            }
+        };
+
+        /*******公共频道-私有频道数据组装*/
+        let ws_param = BingxSwapWsParam {
+            token: "".to_string(),
+            ws_url: "".to_string(),
+            ws_ping_interval: 0,
+            ws_ping_timeout: 0,
+            is_ok_subscribe: false,
+        };
+
+        if is_colo {
+            info!("开启高速(未配置,走普通:{})通道",address_url);
+        } else {
+            info!("走普通通道:{}",address_url);
+        }
+
+        BingxSwapWs {
+            tag,
+            address_url,
+            login_param,
+            ws_param,
+            symbol_s: vec![],
+            subscribe_types: vec![],
+            heartbeat_time: 1000 * 18,
+        }
+    }
+
+    /*******************************************************************************************************/
+    /*****************************************订阅函数********************************************************/
+    /*******************************************************************************************************/
+    //手动添加订阅信息
+    pub fn set_subscribe(&mut self, subscribe_types: Vec<BingxSwapSubscribeType>) {
+        self.subscribe_types.extend(subscribe_types);
+    }
+    //手动添加币对
+    pub fn set_symbols(&mut self, mut b_array: Vec<String>) {
+        for symbol in b_array.iter_mut() {
+            // 大写
+            *symbol = symbol.to_uppercase();
+            // 字符串替换
+            *symbol = symbol.replace("_", "-");
+        }
+        self.symbol_s = b_array;
+    }
+    fn contains_pr(&self) -> bool {
+        for t in self.subscribe_types.clone() {
+            if match t {
+                BingxSwapSubscribeType::PuFuturesTrades => false,
+                BingxSwapSubscribeType::PuFuturesRecords => false,
+                BingxSwapSubscribeType::PuFuturesDepth => false,
+            } {
+                return true;
+            }
+        }
+        false
+    }
+    /*******************************************************************************************************/
+    /*****************************************工具函数********************************************************/
+    /*******************************************************************************************************/
+    //订阅枚举解析
+    pub fn enum_to_string(symbol: String, subscribe_type: BingxSwapSubscribeType) -> String {
+        match subscribe_type {
+            BingxSwapSubscribeType::PuFuturesDepth => {
+                format!("{}@depth5@100ms", symbol)
+            }
+            BingxSwapSubscribeType::PuFuturesRecords => {
+                format!("{}@kline_1m", symbol)
+            }
+            BingxSwapSubscribeType::PuFuturesTrades => {
+                format!("{}@trade", symbol)
+            }
+        }
+    }
+    //订阅信息生成
+    pub fn get_subscription(&self) -> Vec<String> {
+        let mut array = vec![];
+        for symbol in &self.symbol_s {
+            for subscribe_type in &self.subscribe_types {
+                let ty_str = Self::enum_to_string(symbol.clone(), subscribe_type.clone());
+                let str = json!({
+                    "id": "id1",
+                    "reqType": "sub",
+                    "dataType": ty_str.to_string()
+                });
+                array.push(str.to_string());
+            }
+        }
+        array
+    }
+    /*******************************************************************************************************/
+    /*****************************************socket基本*****************************************************/
+    /*******************************************************************************************************/
+    //链接
+    pub async fn ws_connect_async<F, Future>(&mut self,
+                                             is_shutdown_arc: Arc<AtomicBool>,
+                                             handle_function: F,
+                                             _write_tx_am: &Arc<Mutex<UnboundedSender<Message>>>,
+                                             write_to_socket_rx: UnboundedReceiver<Message>) -> Result<(), Error>
+        where
+            F: Fn(ResponseData) -> Future + Clone + Send + 'static + Sync,
+            Future: std::future::Future<Output=()> + Send + 'static, // 确保 Fut 是一个 Future,且输出类型为 ()
+    {
+        let login_is = self.contains_pr();
+        let subscription = self.get_subscription();
+        let address_url = self.address_url.clone();
+        let tag = self.tag.clone();
+        // let heartbeat_time = self.ws_param.ws_ping_interval.clone();
+
+        //心跳-- 方法内部线程启动
+        // let write_tx_clone1 = write_tx_am.clone();
+        // tokio::spawn(async move {
+        //     trace!("线程-异步心跳-开始");
+        //     AbstractWsMode::ping_or_pong(write_tx_clone1, HeartbeatType::Ping, heartbeat_time as u64).await;
+        //     trace!("线程-异步心跳-结束");
+        // });
+
+
+        //设置订阅
+        let subscribe_array = subscription.clone();
+        if login_is {
+            //登录相关
+        }
+
+        //1 链接
+        let t2 = tokio::spawn(async move {
+            let write_to_socket_rx_arc = Arc::new(Mutex::new(write_to_socket_rx));
+
+            loop {
+                info!("Bingx_usdt_swap socket 连接中……");
+                AbstractWsMode::ws_connect_async(is_shutdown_arc.clone(), handle_function.clone(), address_url.clone(),
+                                                 false, tag.clone(), subscribe_array.clone(), write_to_socket_rx_arc.clone(),
+                                                 Self::message_text, Self::message_ping, Self::message_pong, Self::message_binary).await;
+
+                error!("Bingx_usdt_swap socket 断连,1s以后重连……");
+                tokio::time::sleep(Duration::from_secs(1)).await;
+            }
+        });
+
+        tokio::try_join!(t2).unwrap();
+        trace!("线程-心跳与链接-结束");
+
+        Ok(())
+    }
+    /*******************************************************************************************************/
+    /*****************************************数据解析*****************************************************/
+    /*******************************************************************************************************/
+    //数据解析-Text
+    pub fn message_text(text: String) -> Option<ResponseData> {
+        let response_data = Self::ok_text(text);
+        Option::from(response_data)
+    }
+    //数据解析-ping
+    pub fn message_ping(_pi: Vec<u8>) -> Option<ResponseData> {
+        return Option::from(ResponseData::new("".to_string(), -300, "success".to_string(), Value::Null));
+    }
+    //数据解析-pong
+    pub fn message_pong(_po: Vec<u8>) -> Option<ResponseData> {
+        return Option::from(ResponseData::new("".to_string(), -301, "success".to_string(), Value::Null));
+    }
+    //数据解析-二进制
+    pub fn message_binary(po: Vec<u8>) -> Option<ResponseData> {
+        //二进制WebSocket消息
+        // let message_str = format!("Binary:{:?}", _po);
+        // Option::from(ResponseData::new("".to_string(), 2, message_str, Value::Null))
+        // let result = String::from_utf8(bytes);
+        // let result = String::from_utf8(po);
+
+        let mut gz_decoder = GzDecoder::new(&po[..]);
+        let mut decompressed_data = Vec::new();
+
+        // 尝试解压数据
+        if let Ok(_) = gz_decoder.read_to_end(&mut decompressed_data) {
+            // 将解压后的字节向量转换为 UTF-8 字符串
+            match String::from_utf8(decompressed_data) {
+                Ok(text) => {
+                    let response_data = Self::ok_text(text);
+                    return Option::from(response_data);
+                }
+                Err(_) => {
+                    return Option::from(ResponseData::new("".to_string(), 400, "二进制数据转化出错".to_string(), Value::Null));
+                }
+            }
+        } else {
+            return Option::from(ResponseData::new("".to_string(), 400, "二进制数据转化出错".to_string(), Value::Null));
+        }
+    }
+    //数据解析
+    pub fn ok_text(text: String) -> ResponseData
+    {
+        // trace!("原始数据:{:?}",text);
+        match text.as_str() {
+            "Ping" => {
+                return ResponseData::new("".to_string(), -300, "success".to_string(), Value::String(String::from("Pong")));
+            }
+            _ => {}
+        }
+        let mut res_data = ResponseData::new("".to_string(), 200, "success".to_string(), Value::Null);
+        let json_value: serde_json::Value = serde_json::from_str(&text).unwrap();
+
+        // { "id": "id1", "code": 0, "msg": "" }
+        if json_value["id"].as_str() == Option::from("id1") {
+            //订阅
+            if json_value["code"].as_i64() == Option::from(0) {
+                res_data.code = -201;
+                res_data.message = "订阅成功".to_string();
+            } else {
+                res_data.code = 400;
+                res_data.message = "订阅失败".to_string();
+            }
+        } else if json_value["code"].as_i64() == Option::from(0) {
+            res_data.code = 200;
+            res_data.data = json_value.clone();
+
+            //订阅数据 甄别
+            let data_type = json_value["dataType"].as_str().unwrap();
+            if data_type.contains("@depth") {
+                res_data.channel = "futures.order_book".to_string();
+            } else if data_type.contains("@trade") {
+                res_data.channel = "futures.trades".to_string();
+            } else if data_type.contains("@kline_1m") {
+                res_data.channel = "futures.candlesticks".to_string();
+            } else {
+                res_data.channel = "未知推送数据".to_string();
+            }
+        } else {
+            res_data.code = -1;
+            res_data.message = "未知解析".to_string();
+        }
+
+        res_data
+    }
+}

+ 399 - 0
exchanges/src/bitmart_swap_rest.rs

@@ -0,0 +1,399 @@
+use std::collections::BTreeMap;
+use chrono::Utc;
+use reqwest::Client;
+use reqwest::header::HeaderMap;
+use ring::hmac;
+use rust_decimal::Decimal;
+use rust_decimal::prelude::FromPrimitive;
+use serde_json::{json, Value};
+use tracing::{info, trace};
+use std::borrow::Borrow;
+
+use crate::http_tool::RestTool;
+use crate::response_base::ResponseData;
+
+#[derive(Clone)]
+pub struct BitMartSwapRest {
+    pub tag: String,
+    base_url: String,
+    client: Client,
+    login_param: BTreeMap<String, String>,                  // 登录参数
+    delays: Vec<i64>,
+    max_delay: i64,
+    avg_delay: Decimal,
+}
+
+impl BitMartSwapRest {
+    pub fn new(is_colo: bool, login_param: BTreeMap<String, String>) -> BitMartSwapRest {
+        return BitMartSwapRest::new_with_tag("default-BitMartSwapRest".to_string(), is_colo, login_param);
+    }
+    // 构造Bitget,可以自定义tag
+    pub fn new_with_tag(tag: String, is_colo: bool, login_param: BTreeMap<String, String>) -> BitMartSwapRest {
+        let base_url = if is_colo {
+            "https://api-cloud.bitmart.com".to_string()
+        } else {
+            "https://api-cloud.bitmart.com".to_string()
+        };
+
+        if is_colo {
+            info!("开启高速(未配置,走普通:{})通道", base_url);
+        } else {
+            info!("走普通通道:{}", base_url);
+        }
+
+        BitMartSwapRest {
+            tag,
+            base_url,
+            client: Client::new(),
+            login_param,
+            delays: vec![],
+            max_delay: 0,
+            avg_delay: Decimal::ZERO,
+        }
+    }
+
+    /*******************************************************************************************************/
+    /*****************************************rest请求函数********************************************************/
+    /*******************************************************************************************************/
+
+    //获取服务器时间
+    pub async fn get_server_time(&mut self) -> ResponseData {
+        let params = json!({
+        });
+        let data = self.request("GET".to_string(),
+                                "".to_string(),
+                                format!("/system/time"),
+                                false,
+                                params,
+        ).await;
+        data
+    }
+
+    //深度
+    pub async fn get_depth(&mut self, params: Value) -> ResponseData {
+        let data = self.request("GET".to_string(),
+                                "/contract".to_string(),
+                                format!("/public/depth"),
+                                false,
+                                params,
+        ).await;
+        data
+    }
+
+    //获取所有合约详情
+    pub async fn get_market(&mut self, params: Value) -> ResponseData {
+        let data = self.request("GET".to_string(),
+                                "/contract".to_string(),
+                                format!("/public/details"),
+                                false,
+                                params,
+        ).await;
+        data
+    }
+
+
+    //查询合约账户 (查询合约资产明细 )
+    pub async fn get_account(&mut self, params: Value) -> ResponseData {
+        let data = self.request("GET".to_string(),
+                                "/contract".to_string(),
+                                format!("/private/assets-detail"),
+                                true,
+                                params,
+        ).await;
+        data
+    }
+
+    //用户仓位列表(查询仓位详情 (KEYED))
+    pub async fn get_user_position(&mut self, params: Value) -> ResponseData {
+        let data = self.request("GET".to_string(),
+                                "/contract".to_string(),
+                                format!("/private/position"),
+                                true,
+                                params,
+        ).await;
+        data
+    }
+
+    //查询合约订单列表 (查询合约历史订单 (KEYED))
+    pub async fn get_orders(&mut self, params: Value) -> ResponseData {
+        let data = self.request("GET".to_string(),
+                                "/contract".to_string(),
+                                format!("/private/order-history"),
+                                true,
+                                params,
+        ).await;
+        data
+    }
+
+
+    //查询单个订单详情 (【全仓】获取订单明细信息)
+    pub async fn get_order_details(&mut self, params: Value) -> ResponseData {
+        let data = self.request("GET".to_string(),
+                                "/contract".to_string(),
+                                format!("/private/order"),
+                                true,
+                                params,
+        ).await;
+        data
+    }
+
+    //合约交易下单 (合约下单 (SIGNED))
+    pub async fn swap_order(&mut self, params: Value) -> ResponseData {
+        let data = self.request("POST".to_string(),
+                                "/contract".to_string(),
+                                format!("/private/submit-order"),
+                                true,
+                                params,
+        ).await;
+        data
+    }
+
+    // 全部撤单(批量撤销合约订单 (SIGNED))
+    pub async fn cancel_price_order(&mut self, params: Value) -> ResponseData {
+        self.request("POST".to_string(),
+                     "/contract".to_string(),
+                     format!("/private/cancel-orders"),
+                     true,
+                     params,
+        ).await
+    }
+
+    //撤销单个订单 (取消单个合约订单 (SIGNED))
+    pub async fn cancel_order(&mut self, params: Value) -> ResponseData {
+        let data = self.request("POST".to_string(),
+                                "/contract".to_string(),
+                                format!("/private/cancel-order"),
+                                true,
+                                params,
+        ).await;
+        data
+    }
+
+    // //设置持仓模式 (【全仓】切换持仓模式)
+    // pub async fn setting_dual_mode(&mut self, params: Value) -> ResponseData {
+    //     let data = self.request("POST".to_string(),
+    //                             "/linear-swap-api/v1".to_string(),
+    //                             format!("/swap_cross_switch_position_mode"),
+    //                             true,
+    //                             params,
+    //     ).await;
+    //     data
+    // }
+
+    //设置杠杆(合约杠杆调整 (SIGNED))
+    pub async fn setting_dual_leverage(&mut self, params: Value) -> ResponseData {
+        let data = self.request("POST".to_string(),
+                                "/contract".to_string(),
+                                format!("/private/submit-leverage"),
+                                true,
+                                params,
+        ).await;
+        data
+    }
+
+    /*******************************************************************************************************/
+    /*****************************************工具函数********************************************************/
+    /*******************************************************************************************************/
+    pub fn get_delays(&self) -> Vec<i64> {
+        self.delays.clone()
+    }
+    pub fn get_avg_delay(&self) -> Decimal {
+        self.avg_delay.clone()
+    }
+    pub fn get_max_delay(&self) -> i64 {
+        self.max_delay.clone()
+    }
+    fn get_delay_info(&mut self) {
+        let last_100 = if self.delays.len() > 100 {
+            self.delays[self.delays.len() - 100..].to_vec()
+        } else {
+            self.delays.clone()
+        };
+
+        let max_value = last_100.iter().max().unwrap();
+        if max_value.clone().to_owned() > self.max_delay {
+            self.max_delay = max_value.clone().to_owned();
+        }
+
+        let sum: i64 = last_100.iter().sum();
+        let sum_v = Decimal::from_i64(sum).unwrap();
+        let len_v = Decimal::from_u64(last_100.len() as u64).unwrap();
+        self.avg_delay = (sum_v / len_v).round_dp(1);
+        self.delays = last_100.clone().into_iter().collect();
+    }
+    //调用请求
+    async fn request(&mut self,
+                     requesst_type: String,
+                     prefix_url: String,
+                     request_url: String,
+                     is_login: bool,
+                     params: Value) -> ResponseData
+    {
+        // trace!("login_param:{:?}", self.login_param);
+        //解析账号信息
+        let mut access_key = "".to_string();
+        let mut secret_key = "".to_string();
+        let mut api_memo = "".to_string();
+        if self.login_param.contains_key("access_key") {
+            access_key = self.login_param.get("access_key").unwrap().to_string();
+        }
+        if self.login_param.contains_key("secret_key") {
+            secret_key = self.login_param.get("secret_key").unwrap().to_string();
+        }
+        if self.login_param.contains_key("pass_key") {
+            api_memo = self.login_param.get("pass_key").unwrap().to_string();
+        }
+        let mut is_login_param = true;
+        if access_key == "" || secret_key == "" {
+            is_login_param = false
+        }
+
+        //请求头配置-如果需要登录则存在额外配置
+        let body;
+        let mut headers = HeaderMap::new();
+        headers.insert("Content-Type", "application/json".parse().unwrap());
+
+        let timestamp = Utc::now().timestamp_millis().to_string();
+        // let timestamp = "1589793796145".to_string();
+
+        let params_str = params.to_string();
+        // let mut params_str =  json!({
+        //     "count":"100","price":"8600","symbol":"BTC_USDT"
+        // }).to_string();
+        if requesst_type == "GET" {
+            body = "{}".to_string();
+        } else {
+            body = params_str.clone();
+        }
+        //是否需要登录-- 组装sing
+        if is_login {
+            if !is_login_param {
+                let e = ResponseData::error(self.tag.clone(), "登录参数错误!".to_string());
+                return e;
+            } else {
+                //组装sing
+                let sing = Self::sign(secret_key.clone(),
+                                      api_memo.clone(),
+                                      params_str.clone(),
+                                      timestamp.clone(),
+                );
+                headers.extend(Self::headers(access_key.clone(), timestamp.clone(), sing.clone()));
+            }
+        }
+
+
+        // trace!("headers:{:?}", headers);
+        let base_url = format!("{}{}", prefix_url.clone(), request_url.clone());
+        let start_time = chrono::Utc::now().timestamp_millis();
+        let response = self.http_tool(
+            base_url.clone(),
+            requesst_type.to_string(),
+            params_str.clone(),
+            body.clone(),
+            headers,
+        ).await;
+
+        let time_array = chrono::Utc::now().timestamp_millis() - start_time;
+        self.delays.push(time_array);
+        self.get_delay_info();
+
+        response
+    }
+
+    pub fn headers(access_key: String, timestamp: String, sign: String) -> HeaderMap {
+        let mut headers = HeaderMap::new();
+        headers.insert("X-BM-KEY", access_key.clone().parse().unwrap());
+        headers.insert("X-BM-SIGN", sign.clone().parse().unwrap());
+        headers.insert("X-BM-TIMESTAMP", timestamp.clone().parse().unwrap());
+        headers
+    }
+    pub fn sign(secret_key: String, api_memo: String, param_str: String, timestamp: String) -> String
+    {
+
+        // X-BM-SIGN= hmac_sha256(Your_api_secret_key, X-BM-TIMESTAMP + '#' +Your_api_memo + '#' + '{"symbol":"BTC_USDT","price":"8600","count":"100"}')
+        let message = format!("{}#{}#{}", timestamp, api_memo, param_str);
+        trace!("1组装数据:\n{}", message);
+        let signed_key = hmac::Key::new(hmac::HMAC_SHA256, secret_key.as_ref());
+        let sign = hex::encode(hmac::sign(&signed_key, message.as_bytes()).as_ref());
+        sign
+    }
+
+
+    async fn http_tool(&mut self, request_path: String,
+                       request_type: String,
+                       params: String,
+                       body: String, headers: HeaderMap) -> ResponseData {
+        /****请求接口与 地址*/
+        let url = format!("{}{}", self.base_url.to_string(), request_path);
+        let request_type = request_type.clone().to_uppercase();
+        let params_str = RestTool::parse_params_to_str(params.clone());
+        let addrs_url = if params_str.len() > 0 {
+            format!("{}?{}", url.clone(), params_str)
+        } else {
+            format!("{}", url.clone())
+        };
+
+        trace!("url-----:???{}",url.clone());
+        trace!("addrs_url-----:???{}",addrs_url.clone());
+        trace!("param-----:???{}",params.clone());
+        trace!("param_str-----:???{}",params_str.clone());
+        trace!("body-----:???{}",body.clone());
+        trace!("headers-----:???{:?}",headers.clone());
+
+        let request_builder = match request_type.as_str() {
+            "GET" => self.client.get(addrs_url.clone()).headers(headers),
+            "POST" => self.client.post(url.clone()).body(body).headers(headers),
+            // "DELETE" => self.client.delete(addrs_url.clone()).headers(headers),
+            // "PUT" => self.client.put(url.clone()).json(&params),
+            _ => {
+                panic!("{}", format!("错误的请求类型:{}", request_type.clone()))
+            }
+        };
+
+        // 读取响应的内容
+        let response = request_builder.send().await.unwrap();
+        let is_success = response.status().is_success(); // 先检查状态码
+        let text = response.text().await.unwrap();
+        trace!("text:???{:?}",text);
+        return if is_success {
+            self.on_success_data(&text)
+        } else {
+            self.on_error_data(&text, &addrs_url, &params)
+        };
+    }
+
+    pub fn on_success_data(&mut self, text: &String) -> ResponseData {
+        let json_value = serde_json::from_str::<Value>(&text).unwrap();
+        // return  ResponseData::new(self.label.clone(), 200, "success".to_string(), json_value);
+
+        let code = json_value["code"].as_i64();
+        match code {
+            Some(c) => {
+                if c == 1000 {
+                    let default_data = json!({});
+                    let data = json_value.get("data").unwrap_or(default_data.borrow());
+                    ResponseData::new(self.tag.clone(), 200, "success".to_string(), data.clone())
+                } else {
+                    ResponseData::new(self.tag.clone(), 400, "message".to_string(), json_value)
+                }
+            }
+            None => {
+                ResponseData::new(self.tag.clone(), 400, "message".to_string(), json_value)
+            }
+        }
+    }
+
+    pub fn on_error_data(&mut self, text: &String, base_url: &String, params: &String) -> ResponseData {
+        let json_value = serde_json::from_str::<Value>(&text);
+        match json_value {
+            Ok(d) => {
+                ResponseData::new(self.tag.clone(), 400, format!("base_url {} params {} 错误:{} ", base_url, params, d["message"].as_str().unwrap()), d)
+            }
+            Err(_) => {
+                ResponseData::new(self.tag.clone(), 400, "未知错误".to_string(), text.parse().unwrap())
+            }
+        }
+    }
+}
+
+

+ 459 - 0
exchanges/src/bitmart_swap_ws.rs

@@ -0,0 +1,459 @@
+use std::io::Read;
+use std::str::from_utf8;
+use std::sync::Arc;
+use std::sync::atomic::AtomicBool;
+use std::time::Duration;
+
+use chrono::Utc;
+use flate2::bufread::GzDecoder;
+use futures_channel::mpsc::{UnboundedReceiver, UnboundedSender};
+use once_cell::sync::Lazy;
+use ring::hmac;
+use serde_json::{json, Value};
+use tokio::sync::Mutex;
+use tokio::task;
+use tokio_tungstenite::tungstenite::{Error, Message};
+use tracing::{error, info, trace};
+
+use crate::response_base::ResponseData;
+use crate::socket_tool::{AbstractWsMode, HeartbeatType};
+
+pub(crate) static LOGIN_DATA: Lazy<Mutex<(bool, bool)>> = Lazy::new(|| {
+    println!("初始化...");
+    // 0: 需要登录, 1:是否已经登录
+    Mutex::new((false, false))
+});
+
+
+pub enum BitMartSwapWsType {
+    Public,
+    Private,
+}
+
+
+//订阅频道
+#[derive(Clone)]
+pub enum BitMartSwapSubscribeType {
+    // 深度
+    PuFuturesDepth,
+    // 公开成交
+    PuFuturesTrades,
+    // K线数据
+    PuFuturesRecords,
+
+    // // 深度
+    // PuFuturesDepth,
+    // // 公开成交
+    // PuFuturesTrades,
+    // // K线数据
+    // PuFuturesRecords,
+    //
+    // // 订单
+    // PrFuturesOrders,
+    // // 仓位
+    // PrFuturesPositions,
+    // // 余额
+    // PrFuturesBalances,
+}
+
+//账号信息
+#[derive(Clone)]
+#[allow(dead_code)]
+pub struct BitMartSwapLogin {
+    pub api_key: String,
+    pub secret: String,
+    pub api_memo: String,
+}
+
+#[derive(Clone)]
+pub struct BitMartSwapWs {
+    tag: String,                                              // 类型
+    address_url: String,                                        // 地址
+    login_param: Option<BitMartSwapLogin>,                       // 账号
+    symbol_s: Vec<String>,                                      // 币对
+    subscribe_types: Vec<BitMartSwapSubscribeType>,              // 订阅
+    heartbeat_time: u64,                                        // 心跳间隔
+}
+
+
+impl BitMartSwapWs {
+    /*******************************************************************************************************/
+    /*****************************************实例化一个对象****************************************************/
+    /*******************************************************************************************************/
+    pub fn new(is_colo: bool, login_param: Option<BitMartSwapLogin>, ws_type: BitMartSwapWsType) -> BitMartSwapWs {
+        return Self::new_with_tag("default-BingxSwapWs".to_string(), is_colo, login_param, ws_type);
+    }
+
+    pub fn new_with_tag(tag: String, _is_colo: bool, login_param: Option<BitMartSwapLogin>, ws_type: BitMartSwapWsType) -> BitMartSwapWs {
+        /*******公共频道-私有频道数据组装*/
+        let address_url = match ws_type {
+            BitMartSwapWsType::Public => {
+                let url = "wss://openapi-ws.bitmart.com/api?protocol=1.1".to_string();
+                info!("走普通通道(不支持colo通道):{}", url);
+                url
+            }
+            BitMartSwapWsType::Private => {
+                let url = "wss://openapi-ws.bitmart.com/user?protocol=1.1".to_string();
+                info!("走普通通道(不支持colo通道):{}", url);
+                url
+            }
+        };
+
+        BitMartSwapWs {
+            tag,
+            address_url,
+            login_param,
+            symbol_s: vec![],
+            subscribe_types: vec![],
+            heartbeat_time: 1000 * 5,
+        }
+    }
+
+    /*******************************************************************************************************/
+    /*****************************************订阅函数********************************************************/
+    /*******************************************************************************************************/
+    //手动添加订阅信息
+    pub fn set_subscribe(&mut self, subscribe_types: Vec<BitMartSwapSubscribeType>) {
+        self.subscribe_types.extend(subscribe_types);
+    }
+    //手动添加币对
+    pub fn set_symbols(&mut self, mut b_array: Vec<String>) {
+        for symbol in b_array.iter_mut() {
+            // 大写
+            *symbol = symbol.to_uppercase();
+            // 字符串替换
+            *symbol = symbol.replace("_", "");
+        }
+        self.symbol_s = b_array;
+    }
+    //频道是否需要登录
+    fn contains_pr(&self) -> bool {
+        for t in self.subscribe_types.clone() {
+            if match t {
+                BitMartSwapSubscribeType::PuFuturesDepth => false,
+                BitMartSwapSubscribeType::PuFuturesTrades => false,
+                BitMartSwapSubscribeType::PuFuturesRecords => false,
+            } {
+                return true;
+            }
+        }
+        false
+    }
+
+    /*******************************************************************************************************/
+    /*****************************************工具函数********************************************************/
+    /*******************************************************************************************************/
+    //订阅枚举解析
+    pub fn enum_to_string(symbol: String, subscribe_type: BitMartSwapSubscribeType, _login_param: Option<BitMartSwapLogin>) -> String {
+        // let access_key;
+        // let secret_key;
+        // match login_param {
+        //     None => {
+        //         access_key = "".to_string();
+        //         secret_key = "".to_string();
+        //     }
+        //     Some(param) => {
+        //         access_key = param.api_key.clone();
+        //         secret_key = param.secret.clone();
+        //     }
+        // }
+        // let cid = "";
+
+        match subscribe_type {
+            BitMartSwapSubscribeType::PuFuturesDepth => {
+                format!("futures/depth5:{}", symbol.to_uppercase())
+            }
+            BitMartSwapSubscribeType::PuFuturesTrades => {
+                format!("futures/trade:{}", symbol.to_uppercase())
+            }
+            BitMartSwapSubscribeType::PuFuturesRecords => {
+                format!("futures/klineBin1m:{}", symbol.to_uppercase())
+            }
+        }
+    }
+    //订阅信息生成
+    pub fn get_subscription(&self) -> Value {
+        let mut args = vec![];
+        // 只获取第一个
+        for symbol in &self.symbol_s {
+            for subscribe_type in &self.subscribe_types {
+                let ty_str = Self::enum_to_string(symbol.clone(),
+                                                  subscribe_type.clone(),
+                                                  self.login_param.clone(),
+                );
+                args.push(ty_str);
+            }
+        }
+        json!({
+            "action":"subscribe",
+            "args":args
+         })
+    }
+
+    /*******************************************************************************************************/
+    /*****************************************socket基本*****************************************************/
+    /*******************************************************************************************************/
+    //链接
+    pub async fn ws_connect_async<F, Future>(&mut self,
+                                             is_shutdown_arc: Arc<AtomicBool>,
+                                             handle_function: F,
+                                             write_tx_am: &Arc<Mutex<UnboundedSender<Message>>>,
+                                             write_to_socket_rx: UnboundedReceiver<Message>) -> Result<(), Error>
+        where
+            F: Fn(ResponseData) -> Future + Clone + Send + 'static + Sync,
+            Future: std::future::Future<Output=()> + Send + 'static, // 确保 Fut 是一个 Future,且输出类型为 ()
+    {
+        let login_is = self.contains_pr();
+        let login_param = self.login_param.clone();
+        let subscription = self.get_subscription();
+        let address_url = self.address_url.clone();
+        let label = self.tag.clone();
+        let heartbeat_time = self.heartbeat_time.clone();
+
+
+        //心跳-- 方法内部线程启动
+        let write_tx_clone1 = Arc::clone(write_tx_am);
+        let write_tx_clone2 = Arc::clone(write_tx_am);
+        tokio::spawn(async move {
+            trace!("线程-异步心跳-开始");
+            AbstractWsMode::ping_or_pong(write_tx_clone1, HeartbeatType::Ping, heartbeat_time).await;
+            trace!("线程-异步心跳-结束");
+        });
+
+        //设置订阅
+        let mut subscribe_array = vec![];
+        subscribe_array.push(subscription.to_string());
+
+        //链接
+        let t2 = tokio::spawn(async move {
+            let write_to_socket_rx_arc = Arc::new(Mutex::new(write_to_socket_rx));
+
+            info!("启动连接");
+            loop {
+                info!("BitMart_usdt_swap socket 连接中……");
+                // 需要登录
+                if login_is {
+                    let mut login_data = LOGIN_DATA.lock().await;
+                    let login_param_real = login_param.clone().unwrap();
+                    login_data.0 = true;
+
+                    let timestamp = Utc::now().timestamp_millis().to_string();
+                    let api_key = login_param_real.api_key.clone();
+                    let secret_key = login_param_real.secret.clone();
+                    let api_memo = login_param_real.api_memo.clone();
+
+
+                    // let timestamp = "1589267764859".to_string();
+                    // let api_key = "80618e45710812162b04892c7ee5ead4a3cc3e56".to_string();
+                    // let secret_key = "6c6c98544461bbe71db2bca4c6d7fd0021e0ba9efc215f9c6ad41852df9d9df9".to_string();
+                    // let api_memo = "test001".to_string();
+
+                    let sign = {
+                        let message = format!("{}#{}#bitmart.WebSocket", timestamp.clone(), api_memo);
+                        trace!("组装数据:\n{}", message);
+
+                        let signed_key = hmac::Key::new(hmac::HMAC_SHA256, secret_key.as_ref());
+                        let sign = hex::encode(hmac::sign(&signed_key, message.as_bytes()).as_ref());
+                        sign
+                    };
+
+                    trace!("参考sign-3ceeb7e1b8cb165a975e28a2e2dfaca4d30b358873c0351c1a071d8c83314556",);
+                    trace!("自己的sign-{}",sign.clone());
+
+                    let mut args = vec![];
+                    args.push(api_key.clone());
+                    args.push(timestamp.clone());
+                    args.push(sign.clone());
+                    args.push(String::from("web"));
+                    // {"action":"access","args":["<API_KEY>","<timestamp>","<sign>","<dev>"]}
+                    let login_param = json!({
+                        "action": "access",
+                        "args": [
+                           api_key, timestamp.as_str(),sign.as_str(),"web"
+                        ]
+                    });
+                    let login_str = login_param.to_string();
+                    info!("发起ws登录: {}", login_str);
+                    let write_tx_c = Arc::clone(&write_tx_clone2);
+                    AbstractWsMode::send_subscribe(write_tx_c, Message::Text(login_str)).await;
+                }
+
+                AbstractWsMode::ws_connect_async(is_shutdown_arc.clone(), handle_function.clone(), address_url.clone(),
+                                                 login_is, label.clone(), subscribe_array.clone(), write_to_socket_rx_arc.clone(),
+                                                 Self::message_text_sync, Self::message_ping, Self::message_pong, Self::message_binary_sync,
+                ).await;
+                let mut login_data = LOGIN_DATA.lock().await;
+                // 断联后 设置为没有登录
+                login_data.1 = false;
+                info!("BitMart_usdt_swap socket 断连,1s以后重连……");
+                error!("BitMart_usdt_swap socket 断连,1s以后重连……");
+                tokio::time::sleep(Duration::from_secs(1)).await;
+            }
+        });
+        tokio::try_join!(t2).unwrap();
+        trace!("线程-心跳与链接-结束");
+
+        Ok(())
+    }
+    /*******************************************************************************************************/
+    /*****************************************数据解析*****************************************************/
+    /*******************************************************************************************************/
+    //数据解析-Text
+    pub async fn message_text(text: String) -> Option<ResponseData> {
+        let response_data = Self::ok_text(text).await;
+        Option::from(response_data)
+    }
+    pub fn message_text_sync(text: String) -> Option<ResponseData> {
+        // 使用 tokio::task::block_in_place 来等待异步函数的结果
+        task::block_in_place(|| {
+            tokio::runtime::Handle::current().block_on(Self::message_text(text))
+        })
+    }
+    //数据解析-ping
+    pub fn message_ping(_pi: Vec<u8>) -> Option<ResponseData> {
+        return Option::from(ResponseData::new("".to_string(), -300, "success".to_string(), Value::Null));
+    }
+    //数据解析-pong
+    pub fn message_pong(_po: Vec<u8>) -> Option<ResponseData> {
+        return Option::from(ResponseData::new("".to_string(), -301, "success".to_string(), Value::Null));
+    }
+    //数据解析-二进制
+    pub async fn message_binary(binary: Vec<u8>) -> Option<ResponseData> {
+        //二进制WebSocket消息
+        let message_str = Self::parse_zip_data(binary);
+        let response_data = Self::ok_text(message_str).await;
+        Option::from(response_data)
+    }
+    pub fn message_binary_sync(binary: Vec<u8>) -> Option<ResponseData> {
+        // 使用 tokio::task::block_in_place 来等待异步函数的结果
+        task::block_in_place(|| {
+            tokio::runtime::Handle::current().block_on(Self::message_binary(binary))
+        })
+    }
+    //数据解析
+    pub async fn ok_text(text: String) -> ResponseData
+    {
+        // info!("原始数据:{}", text);
+        let mut res_data = ResponseData::new("".to_string(), 200, "success".to_string(), Value::Null);
+        let json_value: Value = serde_json::from_str(&text).unwrap();
+
+        // {"action":"access","success":true}
+        let action = json_value["action"].as_str();
+        match action {
+            None => {}
+            Some(r) => {
+                match r {
+                    "access" => {
+                        /*登录响应*/
+                        let success = json_value["success"].as_bool();
+                        match success {
+                            None => {}
+                            Some(s) => {
+                                if s {
+                                    res_data.code = -200;
+                                    res_data.message = "登录成功".to_string();
+                                } else {
+                                    res_data.code = 400;
+                                    res_data.message = format!("登录失败:{}", json_value["error"].as_str().unwrap());
+                                }
+                                return res_data;
+                            }
+                        }
+                    }
+                    "subscribe" => {
+                        /*订阅响应*/
+                        let success = json_value["success"].as_bool();
+                        match success {
+                            None => {}
+                            Some(s) => {
+                                if s {
+                                    res_data.code = -201;
+                                    res_data.message = format!("订阅成功:{}", json_value["request"].clone().to_string());
+                                } else {
+                                    res_data.code = 400;
+                                    res_data.message = format!("订阅失败:{}", json_value["error"].as_str().unwrap());
+                                }
+                                return res_data;
+                            }
+                        }
+                    }
+                    "unsubscribe" => {
+                        /*取消订阅响应*/
+                        let success = json_value["success"].as_bool();
+                        match success {
+                            None => {}
+                            Some(s) => {
+                                if s {
+                                    res_data.code = -201;
+                                    res_data.message = format!("取消-订阅成功:{}", json_value["request"].clone().to_string());
+                                } else {
+                                    res_data.code = 400;
+                                    res_data.message = format!("取消-订阅失败:{}", json_value["error"].as_str().unwrap());
+                                }
+                                return res_data;
+                            }
+                        }
+                    }
+                    _ => {}
+                }
+            }
+        }
+
+        let group = json_value["group"].as_str();
+        match group {
+            Some(ch) => {
+                res_data.code = 200;
+                res_data.data = json_value["data"].clone();
+
+                //订阅数据 甄别
+                if ch.contains("futures/depth") {
+                    res_data.channel = "futures.order_book".to_string();
+                } else if ch.contains("futures/trade") {
+                    res_data.channel = "futures.trades".to_string();
+                } else if ch.contains("futures/klineBin") {
+                    res_data.channel = "futures.candlesticks".to_string();
+                } else {
+                    res_data.channel = "未知推送数据".to_string();
+                }
+
+                return res_data;
+                // match data {
+                //     Some(_) => {
+                //
+                //     }
+                //     None => {
+                //         res_data.channel = format!("{}", ch);
+                //         res_data.code = 400;
+                //         res_data.data = data.clone();
+                //         return res_data;
+                //     }
+                // }
+            }
+            None => {}
+        }
+
+
+        res_data.code = 400;
+        res_data.message = format!("未知响应内容");
+        res_data.data = text.parse().unwrap();
+        trace!("--------------------------------");
+        res_data
+    }
+
+    fn parse_zip_data(p0: Vec<u8>) -> String {
+        // 创建一个GzDecoder的实例,将压缩数据作为输入
+        let mut decoder = GzDecoder::new(&p0[..]);
+
+        // 创建一个缓冲区来存放解压缩后的数据
+        let mut decompressed_data = Vec::new();
+
+        // 读取解压缩的数据到缓冲区中
+        decoder.read_to_end(&mut decompressed_data).expect("解压缩失败");
+        let result = from_utf8(&decompressed_data)
+            .expect("解压缩后的数据不是有效的UTF-8");
+
+        // info!("解压缩数据 {:?}", result);
+        result.to_string()
+    }
+}
+

+ 313 - 0
exchanges/src/coinsph_swap_rest.rs

@@ -0,0 +1,313 @@
+use std::collections::BTreeMap;
+// use chrono::Utc;
+use reqwest::header::HeaderMap;
+use reqwest::{Client};
+use rust_decimal::Decimal;
+use rust_decimal::prelude::FromPrimitive;
+use rust_decimal_macros::dec;
+use tracing::{error, info, trace};
+use crate::http_tool::RestTool;
+use crate::response_base::ResponseData;
+use ring::hmac;
+use serde_json::{json, Value};
+
+#[derive(Clone, Debug)]
+pub struct CoinsphSwapRest {
+    pub tag: String,
+    base_url: String,
+    client: reqwest::Client,
+    /*******参数*/
+    //是否需要登录
+    //登录所需参数
+    login_param: BTreeMap<String, String>,
+    delays: Vec<i64>,
+    max_delay: i64,
+    avg_delay: Decimal,
+
+}
+
+impl CoinsphSwapRest {
+    /*******************************************************************************************************/
+    /*****************************************获取一个对象****************************************************/
+    /*******************************************************************************************************/
+
+    pub fn new(is_colo: bool, login_param: BTreeMap<String, String>) -> CoinsphSwapRest
+    {
+        return CoinsphSwapRest::new_with_tag("default-CoinsphSwapRest".to_string(), is_colo, login_param);
+    }
+    pub fn new_with_tag(tag: String, is_colo: bool, login_param: BTreeMap<String, String>) -> CoinsphSwapRest {
+        let base_url = if is_colo {
+            "https://api.pro.coins.ph".to_string()
+        } else {
+            "https://api.pro.coins.ph".to_string()
+        };
+
+        if is_colo {
+            info!("开启高速(未配置,走普通:{})通道",base_url);
+        } else {
+            info!("走普通通道:{}",base_url);
+        }
+        /*****返回结构体*******/
+        CoinsphSwapRest {
+            tag,
+            base_url,
+            client: Client::new(),
+            login_param,
+            delays: vec![],
+            max_delay: 0,
+            avg_delay: dec!(0.0),
+        }
+    }
+
+    /*******************************************************************************************************/
+    /*****************************************rest请求函数********************************************************/
+    /*******************************************************************************************************/
+    //查询服务器时间是
+    pub async fn get_server_time(&mut self) -> ResponseData {
+        let params = json!({});
+        let data = self.request("GET".to_string(),
+                                "/openapi/v1".to_string(),
+                                "/time".to_string(),
+                                false,
+                                params,
+        ).await;
+        data
+    }
+    //获取合约信息
+    pub async fn get_market(&mut self,params:Value) -> ResponseData {
+        let data = self.request("GET".to_string(),
+                                "/openapi/v1".to_string(),
+                                "/exchangeInfo".to_string(),
+                                false,
+                                params,
+        ).await;
+        data
+    }
+
+    /*******************************************************************************************************/
+    /*****************************************工具函数********************************************************/
+    /*******************************************************************************************************/
+    pub fn get_delays(&self) -> Vec<i64> {
+        self.delays.clone()
+    }
+    pub fn get_avg_delay(&self) -> Decimal {
+        self.avg_delay.clone()
+    }
+    pub fn get_max_delay(&self) -> i64 {
+        self.max_delay.clone()
+    }
+    fn get_delay_info(&mut self) {
+        let last_100 = if self.delays.len() > 100 {
+            self.delays[self.delays.len() - 100..].to_vec()
+        } else {
+            self.delays.clone()
+        };
+
+        let max_value = last_100.iter().max().unwrap();
+        if max_value.clone().to_owned() > self.max_delay {
+            self.max_delay = max_value.clone().to_owned();
+        }
+
+        let sum: i64 = last_100.iter().sum();
+        let sum_v = Decimal::from_i64(sum).unwrap();
+        let len_v = Decimal::from_u64(last_100.len() as u64).unwrap();
+        self.avg_delay = (sum_v / len_v).round_dp(1);
+        self.delays = last_100.clone().into_iter().collect();
+    }
+    //调用请求
+    pub async fn request(&mut self,
+                         method: String,
+                         prefix_url: String,
+                         request_url: String,
+                         is_login: bool,
+                         params: Value) -> ResponseData
+    {
+        trace!("login_param:{:?}", self.login_param);
+        //解析账号信息
+        let mut access_key = "".to_string();
+        let mut secret_key = "".to_string();
+        let mut passphrase = "".to_string();
+        if self.login_param.contains_key("access_key") {
+            access_key = self.login_param.get("access_key").unwrap().to_string();
+        }
+        if self.login_param.contains_key("secret_key") {
+            secret_key = self.login_param.get("secret_key").unwrap().to_string();
+        }
+        if self.login_param.contains_key("pass_key") {
+            passphrase = self.login_param.get("pass_key").unwrap().to_string();
+        }
+        let mut is_login_param = true;
+        if access_key == "" || secret_key == "" || passphrase == "" {
+            is_login_param = false
+        }
+
+        //每个接口都有的参数
+        // let timestamp = Utc::now().timestamp_millis();
+
+        //请求类型不同,可能请求头body 不同
+        let mut body = "{}".to_string();
+        let mut headers = HeaderMap::new();
+        if method == "POST" {
+            headers.insert("Content-Type", "application/json".parse().unwrap());
+            body = params.to_string();
+        }
+
+        //是否需要登录-- 组装sing
+        if is_login {
+            if !is_login_param {
+                let e = ResponseData::error(self.tag.clone(), "登录参数错误!".to_string());
+                return e;
+            } else {
+                // //需要登录-且登录参数齐全
+                // trace!("param:{}", params);
+                // trace!("body:{}", body);
+                // //组装sing
+                // let sing = Self::sign(secret_key.clone(),
+                //                       method.clone(),
+                //                       prefix_url.clone(),
+                //                       request_url.clone(),
+                //                       params.clone(),
+                //                       body.clone(),
+                //                       timestamp.clone(),
+                // );
+                // //组装header
+                // headers.extend(Self::headers(sing, timestamp, passphrase, access_key));
+            }
+        }
+
+
+        // trace!("headers:{:?}", headers);
+        // let base_url = format!("{}{}", prefix_url.clone(), request_url.clone());
+        let start_time = chrono::Utc::now().timestamp_millis();
+        let response = self.http_tool(
+            format!("{}{}", prefix_url.clone(), request_url.clone()),
+            method.to_string(),
+            params.to_string(),
+            body,
+            headers,
+        ).await;
+
+        let time_array = chrono::Utc::now().timestamp_millis() - start_time;
+        self.delays.push(time_array);
+        self.get_delay_info();
+
+        response
+        //
+        // let time_array = chrono::Utc::now().timestamp_millis() - start_time;
+        // self.delays.push(time_array);
+        // self.get_delay_info();
+        // let res_data = Self::res_data_analysis(get_response, base_url, params.to_string());
+        // res_data
+    }
+
+    // pub fn headers(_: String, _timestamp: String, passphrase: String, access_key: String) -> HeaderMap {
+    //     let mut headers = HeaderMap::new();
+    //     // headers.insert("OK-ACCESS-KEY", access_key.parse().unwrap());
+    //     // headers.insert("OK-ACCESS-SIGN", sign.parse().unwrap());
+    //     // headers.insert("OK-ACCESS-TIMESTAMP", timestamp.parse().unwrap());
+    //     // headers.insert("OK-ACCESS-PASSPHRASE", passphrase.parse().unwrap());
+    //     headers
+    // }
+    pub fn sign(secret_key: String,
+                method: String, prefix_url: String, request_url: String,
+                params: String, body: String, timestamp: String) -> String
+    {
+        /*签名生成*/
+        let url_param_str = RestTool::parse_params_to_str(params);
+        let base_url = if method == "GET" {
+            format!("{}{}?{}", prefix_url, request_url, url_param_str)
+        } else {
+            format!("{}{}", prefix_url, request_url)
+        };
+
+        // 时间戳 + 请求类型+ 请求参数字符串
+        let message = format!("{}{}{}{}", timestamp, method, base_url, body);
+        trace!("message:{}",message);
+
+        // 做签名
+        let hmac_key = ring::hmac::Key::new(hmac::HMAC_SHA256, secret_key.as_bytes());
+        let result = ring::hmac::sign(&hmac_key, &message.as_bytes());
+        let sign = base64::encode(result);
+        sign
+    }
+
+    // async fn http_tool(&mut self, request_path: String, request_type: String, params: String, headers: HeaderMap) -> Result<ResponseData, reqwest::Error> {
+    async fn http_tool(&mut self, request_path: String,
+                       request_type: String,
+                       params: String,
+                       body: String,
+                       headers: HeaderMap) -> ResponseData {
+        /****请求接口与 地址*/
+        let url = format!("{}{}", self.base_url.to_string(), request_path);
+        let request_type = request_type.clone().to_uppercase();
+        let addrs_url: String = if RestTool::parse_params_to_str(params.clone()) == "" {
+            url.clone()
+        } else {
+            format!("{}?{}", url.clone(), RestTool::parse_params_to_str(params.clone()))
+        };
+
+        trace!("url-----:???{}",url.clone());
+        trace!("addrs_url-----:???{}",addrs_url.clone());
+        trace!("params-----:???{}",params.clone());
+        trace!("body-----:???{}",body.clone());
+
+        let request_builder = match request_type.as_str() {
+            "GET" => self.client.get(addrs_url.clone()).headers(headers),
+            "POST" => self.client.post(url.clone()).body(body).headers(headers),
+            // "DELETE" => self.client.delete(addrs_url.clone()).headers(headers),
+            // "PUT" => self.client.put(url.clone()).json(&params),
+            _ => {
+                panic!("{}", format!("错误的请求类型:{}", request_type.clone()))
+            }
+        };
+
+        // 读取响应的内容
+        let response = request_builder.send().await.unwrap();
+        let is_success = response.status().is_success(); // 先检查状态码
+        let text = response.text().await.unwrap();
+        // trace!("text:???{:?}",text);
+        return if is_success {
+            self.on_success_data(&text)
+        } else {
+            self.on_error_data(&text, &addrs_url, &params)
+        };
+    }
+    pub fn on_success_data(&mut self, text: &String) -> ResponseData {
+        let json_value = serde_json::from_str::<Value>(&text).unwrap();
+        // return  ResponseData::new(self.tag.clone(), 200, "success".to_string(), json_value);
+
+        // let serverTime = json_value["serverTime"].as_i64();
+        // match serverTime {
+        //     None => {}
+        //     Some(v) => {
+        //            }
+        // }
+        return ResponseData::new(self.tag.clone(), 200, "success".to_string(), json_value.clone());
+    }
+
+    pub fn on_error_data(&mut self, text: &String, base_url: &String, params: &String) -> ResponseData {
+        let json_value = serde_json::from_str::<Value>(&text);
+
+        match json_value {
+            Ok(data) => {
+                let message;
+
+                if !data["message"].is_null() {
+                    message = format!("{}:{}", data["tag"].as_str().unwrap(), data["message"].as_str().unwrap());
+                } else {
+                    message = data["tag"].to_string();
+                }
+
+                let mut error = ResponseData::error(self.tag.clone(), message);
+                error.message = format!("请求地址:{}, 请求参数:{}, 报错内容:{}。", base_url, params, error.message);
+                error
+            }
+            Err(e) => {
+                error!("解析错误:{:?}", e);
+                let error = ResponseData::error("".to_string(),
+                                                format!("json 解析失败:{},相关参数:{}", e, text));
+                error
+            }
+        }
+    }
+}

+ 400 - 0
exchanges/src/coinsph_swap_ws.rs

@@ -0,0 +1,400 @@
+use std::io::Read;
+use std::str::from_utf8;
+use std::sync::Arc;
+use std::sync::atomic::AtomicBool;
+use std::time::Duration;
+
+use chrono::Utc;
+use flate2::bufread::GzDecoder;
+use futures_channel::mpsc::{UnboundedReceiver, UnboundedSender};
+use once_cell::sync::Lazy;
+use ring::hmac;
+use serde_json::{json, Value};
+use tokio::sync::Mutex;
+use tokio::task;
+use tokio_tungstenite::tungstenite::{Error, Message};
+use tracing::{error, info, trace};
+
+use crate::response_base::ResponseData;
+use crate::socket_tool::{AbstractWsMode, HeartbeatType};
+
+pub(crate) static LOGIN_DATA: Lazy<Mutex<(bool, bool)>> = Lazy::new(|| {
+    println!("初始化...");
+    // 0: 需要登录, 1:是否已经登录
+    Mutex::new((false, false))
+});
+
+
+pub enum CoinsphSwapWsType {
+    Public,
+    Private,
+}
+
+
+//订阅频道
+#[derive(Clone)]
+pub enum CoinsphSwapSubscribeType {
+    // 深度
+    PuFuturesDepth,
+    // 公开成交
+    PuFuturesTrades,
+    // K线数据
+    PuFuturesRecords,
+
+    // // 深度
+    // PuFuturesDepth,
+    // // 公开成交
+    // PuFuturesTrades,
+    // // K线数据
+    // PuFuturesRecords,
+    //
+    // // 订单
+    // PrFuturesOrders,
+    // // 仓位
+    // PrFuturesPositions,
+    // // 余额
+    // PrFuturesBalances,
+}
+
+//账号信息
+#[derive(Clone)]
+#[allow(dead_code)]
+pub struct CoinsphSwapLogin {
+    pub api_key: String,
+    pub secret: String,
+    pub api_memo: String,
+}
+
+#[derive(Clone)]
+pub struct CoinsphSwapWs {
+    tag: String,
+    // 类型
+    address_url: String,
+    // 地址
+    login_param: Option<CoinsphSwapLogin>,
+    // 账号
+    symbol_s: Vec<String>,
+    // 币对
+    subscribe_types: Vec<CoinsphSwapSubscribeType>,
+    // 订阅
+    heartbeat_time: u64,                                        // 心跳间隔
+}
+
+
+impl CoinsphSwapWs {
+    /*******************************************************************************************************/
+    /*****************************************实例化一个对象****************************************************/
+    /*******************************************************************************************************/
+    pub fn new(is_colo: bool, login_param: Option<CoinsphSwapLogin>, ws_type: CoinsphSwapWsType) -> CoinsphSwapWs {
+        return Self::new_with_tag("default-BingxSwapWs".to_string(), is_colo, login_param, ws_type);
+    }
+
+    pub fn new_with_tag(tag: String, _is_colo: bool, login_param: Option<CoinsphSwapLogin>, ws_type: CoinsphSwapWsType) -> CoinsphSwapWs {
+        /*******公共频道-私有频道数据组装*/
+        let address_url = match ws_type {
+            CoinsphSwapWsType::Public => {
+                let url = "wss://wsapi.pro.coins.ph/openapi/quote/stream".to_string();
+                info!("走普通通道(不支持colo通道):{}", url);
+                url
+            }
+            CoinsphSwapWsType::Private => {
+                let url = "wss://wsapi.pro.coins.ph/user?protocol=1.1".to_string();
+                info!("走普通通道(不支持colo通道):{}", url);
+                url
+            }
+        };
+
+        CoinsphSwapWs {
+            tag,
+            address_url,
+            login_param,
+            symbol_s: vec![],
+            subscribe_types: vec![],
+            heartbeat_time: 1000 * 5,
+        }
+    }
+
+    /*******************************************************************************************************/
+    /*****************************************订阅函数********************************************************/
+    /*******************************************************************************************************/
+    //手动添加订阅信息
+    pub fn set_subscribe(&mut self, subscribe_types: Vec<CoinsphSwapSubscribeType>) {
+        self.subscribe_types.extend(subscribe_types);
+    }
+    //手动添加币对
+    pub fn set_symbols(&mut self, mut b_array: Vec<String>) {
+        for symbol in b_array.iter_mut() {
+            // 小写
+            *symbol = symbol.to_lowercase();
+            // 字符串替换
+            *symbol = symbol.replace("_", "");
+        }
+        self.symbol_s = b_array;
+    }
+    //频道是否需要登录
+    fn contains_pr(&self) -> bool {
+        for t in self.subscribe_types.clone() {
+            if match t {
+                CoinsphSwapSubscribeType::PuFuturesDepth => false,
+                CoinsphSwapSubscribeType::PuFuturesTrades => false,
+                CoinsphSwapSubscribeType::PuFuturesRecords => false,
+            } {
+                return true;
+            }
+        }
+        false
+    }
+
+    /*******************************************************************************************************/
+    /*****************************************工具函数********************************************************/
+    /*******************************************************************************************************/
+    //订阅枚举解析
+    pub fn enum_to_string(symbol: String, subscribe_type: CoinsphSwapSubscribeType, _login_param: Option<CoinsphSwapLogin>) -> String {
+        // let access_key;
+        // let secret_key;
+        // match login_param {
+        //     None => {
+        //         access_key = "".to_string();
+        //         secret_key = "".to_string();
+        //     }
+        //     Some(param) => {
+        //         access_key = param.api_key.clone();
+        //         secret_key = param.secret.clone();
+        //     }
+        // }
+        // let cid = "";
+
+        match subscribe_type {
+            CoinsphSwapSubscribeType::PuFuturesDepth => {//深度
+                format!("{}@depth5", symbol)
+            }
+            CoinsphSwapSubscribeType::PuFuturesTrades => {//公开成交
+                format!("{}@aggTrade", symbol)
+            }
+            CoinsphSwapSubscribeType::PuFuturesRecords => {//k线数据
+                format!("{}@kline_1m", symbol)
+            }
+        }
+    }
+    //订阅信息生成
+    pub fn get_subscription(&self) -> Value {
+        let mut args = vec![];
+        // 只获取第一个
+        for symbol in &self.symbol_s {
+            for subscribe_type in &self.subscribe_types {
+                let ty_str = Self::enum_to_string(symbol.clone(),
+                                                  subscribe_type.clone(),
+                                                  self.login_param.clone(),
+                );
+                args.push(ty_str);
+            }
+        }
+        json!({
+             "method": "SUBSCRIBE",
+             "params": args,
+              "id": 1
+         })
+    }
+
+    /*******************************************************************************************************/
+    /*****************************************socket基本*****************************************************/
+    /*******************************************************************************************************/
+    //链接
+    pub async fn ws_connect_async<F, Future>(&mut self,
+                                             is_shutdown_arc: Arc<AtomicBool>,
+                                             handle_function: F,
+                                             write_tx_am: &Arc<Mutex<UnboundedSender<Message>>>,
+                                             write_to_socket_rx: UnboundedReceiver<Message>) -> Result<(), Error>
+        where
+            F: Fn(ResponseData) -> Future + Clone + Send + 'static + Sync,
+            Future: std::future::Future<Output=()> + Send + 'static, // 确保 Fut 是一个 Future,且输出类型为 ()
+    {
+        let login_is = self.contains_pr();
+        let login_param = self.login_param.clone();
+        let subscription = self.get_subscription();
+        let address_url = self.address_url.clone();
+        let label = self.tag.clone();
+        let heartbeat_time = self.heartbeat_time.clone();
+
+
+        //心跳-- 方法内部线程启动
+        let write_tx_clone1 = Arc::clone(write_tx_am);
+        let write_tx_clone2 = Arc::clone(write_tx_am);
+        tokio::spawn(async move {
+            trace!("线程-异步心跳-开始");
+            AbstractWsMode::ping_or_pong(write_tx_clone1, HeartbeatType::Ping, heartbeat_time).await;
+            trace!("线程-异步心跳-结束");
+        });
+
+        //设置订阅
+        let mut subscribe_array = vec![];
+        subscribe_array.push(subscription.to_string());
+
+        //链接
+        let t2 = tokio::spawn(async move {
+            let write_to_socket_rx_arc = Arc::new(Mutex::new(write_to_socket_rx));
+
+            info!("启动连接");
+            loop {
+                info!("coinsph_usdt_swap socket 连接中……");
+                // 需要登录
+                if login_is {
+                    let mut login_data = LOGIN_DATA.lock().await;
+                    let login_param_real = login_param.clone().unwrap();
+                    login_data.0 = true;
+
+                    let timestamp = Utc::now().timestamp_millis().to_string();
+                    let api_key = login_param_real.api_key.clone();
+                    let secret_key = login_param_real.secret.clone();
+                    let api_memo = login_param_real.api_memo.clone();
+
+
+                    // let timestamp = "1589267764859".to_string();
+                    // let api_key = "80618e45710812162b04892c7ee5ead4a3cc3e56".to_string();
+                    // let secret_key = "6c6c98544461bbe71db2bca4c6d7fd0021e0ba9efc215f9c6ad41852df9d9df9".to_string();
+                    // let api_memo = "test001".to_string();
+
+                    let sign = {
+                        let message = format!("{}#{}#Coinsph.WebSocket", timestamp.clone(), api_memo);
+                        trace!("组装数据:\n{}", message);
+
+                        let signed_key = hmac::Key::new(hmac::HMAC_SHA256, secret_key.as_ref());
+                        let sign = hex::encode(hmac::sign(&signed_key, message.as_bytes()).as_ref());
+                        sign
+                    };
+
+                    trace!("参考sign-3ceeb7e1b8cb165a975e28a2e2dfaca4d30b358873c0351c1a071d8c83314556",);
+                    trace!("自己的sign-{}",sign.clone());
+
+                    let mut args = vec![];
+                    args.push(api_key.clone());
+                    args.push(timestamp.clone());
+                    args.push(sign.clone());
+                    args.push(String::from("web"));
+                    // {"action":"access","args":["<API_KEY>","<timestamp>","<sign>","<dev>"]}
+                    let login_param = json!({
+                        "action": "access",
+                        "args": [
+                           api_key, timestamp.as_str(),sign.as_str(),"web"
+                        ]
+                    });
+                    let login_str = login_param.to_string();
+                    info!("发起ws登录: {}", login_str);
+                    let write_tx_c = Arc::clone(&write_tx_clone2);
+                    AbstractWsMode::send_subscribe(write_tx_c, Message::Text(login_str)).await;
+                }
+
+                AbstractWsMode::ws_connect_async(is_shutdown_arc.clone(), handle_function.clone(), address_url.clone(),
+                                                 login_is, label.clone(), subscribe_array.clone(), write_to_socket_rx_arc.clone(),
+                                                 Self::message_text_sync, Self::message_ping, Self::message_pong, Self::message_binary_sync,
+                ).await;
+                let mut login_data = LOGIN_DATA.lock().await;
+                // 断联后 设置为没有登录
+                login_data.1 = false;
+                info!("coinsph_usdt_swap socket 断连,1s以后重连……");
+                error!("coinsph_usdt_swap socket 断连,1s以后重连……");
+                tokio::time::sleep(Duration::from_secs(1)).await;
+            }
+        });
+        tokio::try_join!(t2).unwrap();
+        trace!("线程-心跳与链接-结束");
+
+        Ok(())
+    }
+    /*******************************************************************************************************/
+    /*****************************************数据解析*****************************************************/
+    /*******************************************************************************************************/
+    //数据解析-Text
+    pub async fn message_text(text: String) -> Option<ResponseData> {
+        let response_data = Self::ok_text(text).await;
+        Option::from(response_data)
+    }
+    pub fn message_text_sync(text: String) -> Option<ResponseData> {
+        // 使用 tokio::task::block_in_place 来等待异步函数的结果
+        task::block_in_place(|| {
+            tokio::runtime::Handle::current().block_on(Self::message_text(text))
+        })
+    }
+    //数据解析-ping
+    pub fn message_ping(_pi: Vec<u8>) -> Option<ResponseData> {
+        return Option::from(ResponseData::new("".to_string(), -300, "success".to_string(), Value::Null));
+    }
+    //数据解析-pong
+    pub fn message_pong(_po: Vec<u8>) -> Option<ResponseData> {
+        return Option::from(ResponseData::new("".to_string(), -301, "success".to_string(), Value::Null));
+    }
+    //数据解析-二进制
+    pub async fn message_binary(binary: Vec<u8>) -> Option<ResponseData> {
+        //二进制WebSocket消息
+        let message_str = Self::parse_zip_data(binary);
+        let response_data = Self::ok_text(message_str).await;
+        Option::from(response_data)
+    }
+    pub fn message_binary_sync(binary: Vec<u8>) -> Option<ResponseData> {
+        // 使用 tokio::task::block_in_place 来等待异步函数的结果
+        task::block_in_place(|| {
+            tokio::runtime::Handle::current().block_on(Self::message_binary(binary))
+        })
+    }
+    //数据解析
+    pub async fn ok_text(text: String) -> ResponseData
+    {
+        // info!("原始数据:{}", text);
+        let mut res_data = ResponseData::new("".to_string(), 200, "success".to_string(), Value::Null);
+        let json_value: Value = serde_json::from_str(&text).unwrap();
+
+        let id = json_value["id"].as_str();
+        match id {
+            Some(_v) => {
+                res_data.code = -201;
+                res_data.message = format!("订阅成功:{}", json_value["request"].clone().to_string());
+                return res_data;
+            }
+            None => {}
+        }
+
+
+        let e = json_value["e"].as_str();
+        match e {
+            None => {}
+            Some(v) => {
+                res_data.code = 200;
+                res_data.data = json_value.clone();
+                if v.contains("depth") {
+                    res_data.channel = "futures.order_book".to_string();
+                } else if v.contains("aggTrade") {
+                    res_data.channel = "futures.trades".to_string();
+                } else if v.contains("kline") {
+                    res_data.channel = "futures.candlesticks".to_string();
+                } else {
+                    res_data.code = 400;
+                    res_data.channel = "未知推送数据".to_string();
+                }
+                return res_data;
+            }
+        }
+
+        res_data.code = 400;
+        res_data.message = format!("未知响应内容");
+        res_data.data = text.parse().unwrap();
+        trace!("--------------------------------");
+        res_data
+    }
+
+    fn parse_zip_data(p0: Vec<u8>) -> String {
+        // 创建一个GzDecoder的实例,将压缩数据作为输入
+        let mut decoder = GzDecoder::new(&p0[..]);
+
+        // 创建一个缓冲区来存放解压缩后的数据
+        let mut decompressed_data = Vec::new();
+
+        // 读取解压缩的数据到缓冲区中
+        decoder.read_to_end(&mut decompressed_data).expect("解压缩失败");
+        let result = from_utf8(&decompressed_data)
+            .expect("解压缩后的数据不是有效的UTF-8");
+
+        // info!("解压缩数据 {:?}", result);
+        result.to_string()
+    }
+}
+

+ 307 - 0
exchanges/src/cointr_swap_rest.rs

@@ -0,0 +1,307 @@
+use std::collections::BTreeMap;
+
+use reqwest::Client;
+// use chrono::Utc;
+use reqwest::header::HeaderMap;
+use ring::hmac;
+use rust_decimal::Decimal;
+use rust_decimal::prelude::FromPrimitive;
+use rust_decimal_macros::dec;
+use serde_json::Value;
+use tracing::{error, info, trace};
+
+use crate::http_tool::RestTool;
+use crate::response_base::ResponseData;
+
+#[derive(Clone, Debug)]
+pub struct CointrSwapRest {
+    pub tag: String,
+    base_url: String,
+    client: reqwest::Client,
+    /*******参数*/
+    //是否需要登录
+    //登录所需参数
+    login_param: BTreeMap<String, String>,
+    delays: Vec<i64>,
+    max_delay: i64,
+    avg_delay: Decimal,
+
+}
+
+impl CointrSwapRest {
+    /*******************************************************************************************************/
+    /*****************************************获取一个对象****************************************************/
+    /*******************************************************************************************************/
+
+    pub fn new(is_colo: bool, login_param: BTreeMap<String, String>) -> CointrSwapRest
+    {
+        return CointrSwapRest::new_with_tag("default-CointrSwapRest".to_string(), is_colo, login_param);
+    }
+    pub fn new_with_tag(tag: String, is_colo: bool, login_param: BTreeMap<String, String>) -> CointrSwapRest {
+        let base_url = if is_colo {
+            "https://api.cointr.pro".to_string()
+        } else {
+            "https://api.cointr.pro".to_string()
+        };
+
+        if is_colo {
+            info!("开启高速(未配置,走普通:{})通道",base_url);
+        } else {
+            info!("走普通通道:{}",base_url);
+        }
+        /*****返回结构体*******/
+        CointrSwapRest {
+            tag,
+            base_url,
+            client: Client::new(),
+            login_param,
+            delays: vec![],
+            max_delay: 0,
+            avg_delay: dec!(0.0),
+        }
+    }
+
+    /*******************************************************************************************************/
+    /*****************************************rest请求函数********************************************************/
+    /*******************************************************************************************************/
+    // //查询服务器时间是(获取系统维护状态(公共))
+    // pub async fn get_server_time(&mut self) -> ResponseData {
+    //     let params = json!({});
+    //     let data = self.request("GET".to_string(),
+    //                             "/v1".to_string(),
+    //                             "/public/system_info".to_string(),
+    //                             false,
+    //                             params,
+    //     ).await;
+    //     data
+    // }
+    //获取合约信息( 合同规格)
+    pub async fn get_market(&mut self, params: Value) -> ResponseData {
+        let data = self.request("GET".to_string(),
+                                "/v1".to_string(),
+                                "/futures/public/instruments".to_string(),
+                                false,
+                                params,
+        ).await;
+        data
+    }
+
+    /*******************************************************************************************************/
+    /*****************************************工具函数********************************************************/
+    /*******************************************************************************************************/
+    pub fn get_delays(&self) -> Vec<i64> {
+        self.delays.clone()
+    }
+    pub fn get_avg_delay(&self) -> Decimal {
+        self.avg_delay.clone()
+    }
+    pub fn get_max_delay(&self) -> i64 {
+        self.max_delay.clone()
+    }
+    fn get_delay_info(&mut self) {
+        let last_100 = if self.delays.len() > 100 {
+            self.delays[self.delays.len() - 100..].to_vec()
+        } else {
+            self.delays.clone()
+        };
+
+        let max_value = last_100.iter().max().unwrap();
+        if max_value.clone().to_owned() > self.max_delay {
+            self.max_delay = max_value.clone().to_owned();
+        }
+
+        let sum: i64 = last_100.iter().sum();
+        let sum_v = Decimal::from_i64(sum).unwrap();
+        let len_v = Decimal::from_u64(last_100.len() as u64).unwrap();
+        self.avg_delay = (sum_v / len_v).round_dp(1);
+        self.delays = last_100.clone().into_iter().collect();
+    }
+    //调用请求
+    pub async fn request(&mut self,
+                         method: String,
+                         prefix_url: String,
+                         request_url: String,
+                         is_login: bool,
+                         params: Value) -> ResponseData
+    {
+        trace!("login_param:{:?}", self.login_param);
+        //解析账号信息
+        let mut access_key = "".to_string();
+        let mut secret_key = "".to_string();
+        let mut passphrase = "".to_string();
+        if self.login_param.contains_key("access_key") {
+            access_key = self.login_param.get("access_key").unwrap().to_string();
+        }
+        if self.login_param.contains_key("secret_key") {
+            secret_key = self.login_param.get("secret_key").unwrap().to_string();
+        }
+        if self.login_param.contains_key("pass_key") {
+            passphrase = self.login_param.get("pass_key").unwrap().to_string();
+        }
+        let mut is_login_param = true;
+        if access_key == "" || secret_key == "" || passphrase == "" {
+            is_login_param = false
+        }
+
+        //每个接口都有的参数
+        // let timestamp = Utc::now().timestamp_millis();
+
+        //请求类型不同,可能请求头body 不同
+        let mut body = "{}".to_string();
+        let mut headers = HeaderMap::new();
+        if method == "POST" {
+            headers.insert("Content-Type", "application/json".parse().unwrap());
+            body = params.to_string();
+        }
+
+        //是否需要登录-- 组装sing
+        if is_login {
+            if !is_login_param {
+                let e = ResponseData::error(self.tag.clone(), "登录参数错误!".to_string());
+                return e;
+            } else {
+                // //需要登录-且登录参数齐全
+                // trace!("param:{}", params);
+                // trace!("body:{}", body);
+                // //组装sing
+                // let sing = Self::sign(secret_key.clone(),
+                //                       method.clone(),
+                //                       prefix_url.clone(),
+                //                       request_url.clone(),
+                //                       params.clone(),
+                //                       body.clone(),
+                //                       timestamp.clone(),
+                // );
+                // //组装header
+                // headers.extend(Self::headers(sing, timestamp, passphrase, access_key));
+            }
+        }
+
+
+        // trace!("headers:{:?}", headers);
+        // let base_url = format!("{}{}", prefix_url.clone(), request_url.clone());
+        let start_time = chrono::Utc::now().timestamp_millis();
+        let response = self.http_tool(
+            format!("{}{}", prefix_url.clone(), request_url.clone()),
+            method.to_string(),
+            params.to_string(),
+            body,
+            headers,
+        ).await;
+
+        let time_array = chrono::Utc::now().timestamp_millis() - start_time;
+        self.delays.push(time_array);
+        self.get_delay_info();
+
+        response
+        //
+        // let time_array = chrono::Utc::now().timestamp_millis() - start_time;
+        // self.delays.push(time_array);
+        // self.get_delay_info();
+        // let res_data = Self::res_data_analysis(get_response, base_url, params.to_string());
+        // res_data
+    }
+
+    // pub fn headers(_: String, _timestamp: String, passphrase: String, access_key: String) -> HeaderMap {
+    //     let mut headers = HeaderMap::new();
+    //     // headers.insert("OK-ACCESS-KEY", access_key.parse().unwrap());
+    //     // headers.insert("OK-ACCESS-SIGN", sign.parse().unwrap());
+    //     // headers.insert("OK-ACCESS-TIMESTAMP", timestamp.parse().unwrap());
+    //     // headers.insert("OK-ACCESS-PASSPHRASE", passphrase.parse().unwrap());
+    //     headers
+    // }
+    pub fn sign(secret_key: String,
+                method: String, prefix_url: String, request_url: String,
+                params: String, body: String, timestamp: String) -> String
+    {
+        /*签名生成*/
+        let url_param_str = RestTool::parse_params_to_str(params);
+        let base_url = if method == "GET" {
+            format!("{}{}?{}", prefix_url, request_url, url_param_str)
+        } else {
+            format!("{}{}", prefix_url, request_url)
+        };
+
+        // 时间戳 + 请求类型+ 请求参数字符串
+        let message = format!("{}{}{}{}", timestamp, method, base_url, body);
+        trace!("message:{}",message);
+
+        // 做签名
+        let hmac_key = ring::hmac::Key::new(hmac::HMAC_SHA256, secret_key.as_bytes());
+        let result = ring::hmac::sign(&hmac_key, &message.as_bytes());
+        let sign = base64::encode(result);
+        sign
+    }
+
+    // async fn http_tool(&mut self, request_path: String, request_type: String, params: String, headers: HeaderMap) -> Result<ResponseData, reqwest::Error> {
+    async fn http_tool(&mut self, request_path: String,
+                       request_type: String,
+                       params: String,
+                       body: String,
+                       headers: HeaderMap) -> ResponseData {
+        /****请求接口与 地址*/
+        let url = format!("{}{}", self.base_url.to_string(), request_path);
+        let request_type = request_type.clone().to_uppercase();
+        let addrs_url: String = if RestTool::parse_params_to_str(params.clone()) == "" {
+            url.clone()
+        } else {
+            format!("{}?{}", url.clone(), RestTool::parse_params_to_str(params.clone()))
+        };
+
+        trace!("url-----:???{}",url.clone());
+        trace!("addrs_url-----:???{}",addrs_url.clone());
+        trace!("params-----:???{}",params.clone());
+        trace!("body-----:???{}",body.clone());
+
+        let request_builder = match request_type.as_str() {
+            "GET" => self.client.get(addrs_url.clone()).headers(headers),
+            "POST" => self.client.post(url.clone()).body(body).headers(headers),
+            // "DELETE" => self.client.delete(addrs_url.clone()).headers(headers),
+            // "PUT" => self.client.put(url.clone()).json(&params),
+            _ => {
+                panic!("{}", format!("错误的请求类型:{}", request_type.clone()))
+            }
+        };
+
+        // 读取响应的内容
+        let response = request_builder.send().await.unwrap();
+        let is_success = response.status().is_success(); // 先检查状态码
+        let text = response.text().await.unwrap();
+        // trace!("text:???{:?}",text);
+        return if is_success {
+            self.on_success_data(&text)
+        } else {
+            self.on_error_data(&text, &addrs_url, &params)
+        };
+    }
+    pub fn on_success_data(&mut self, text: &String) -> ResponseData {
+        let json_value = serde_json::from_str::<Value>(&text).unwrap();
+        return ResponseData::new(self.tag.clone(), 200, "success".to_string(), json_value.clone());
+    }
+
+    pub fn on_error_data(&mut self, text: &String, base_url: &String, params: &String) -> ResponseData {
+        let json_value = serde_json::from_str::<Value>(&text);
+
+        match json_value {
+            Ok(data) => {
+                let message;
+
+                if !data["message"].is_null() {
+                    message = format!("{}:{}", data["tag"].as_str().unwrap(), data["message"].as_str().unwrap());
+                } else {
+                    message = data["tag"].to_string();
+                }
+
+                let mut error = ResponseData::error(self.tag.clone(), message);
+                error.message = format!("请求地址:{}, 请求参数:{}, 报错内容:{}。", base_url, params, error.message);
+                error
+            }
+            Err(e) => {
+                error!("解析错误:{:?}", e);
+                let error = ResponseData::error("".to_string(),
+                                                format!("json 解析失败:{},相关参数:{}", e, text));
+                error
+            }
+        }
+    }
+}

+ 434 - 0
exchanges/src/cointr_swap_ws.rs

@@ -0,0 +1,434 @@
+use std::io::Read;
+use std::str::from_utf8;
+use std::sync::Arc;
+use std::sync::atomic::AtomicBool;
+use std::time::Duration;
+
+use chrono::Utc;
+use flate2::bufread::GzDecoder;
+use futures_channel::mpsc::{UnboundedReceiver, UnboundedSender};
+use once_cell::sync::Lazy;
+use ring::hmac;
+use serde_json::{json, Value};
+use tokio::sync::Mutex;
+use tokio::task;
+use tokio_tungstenite::tungstenite::{Error, Message};
+use tracing::{error, info, trace};
+
+use crate::response_base::ResponseData;
+use crate::socket_tool::{AbstractWsMode};
+
+pub(crate) static LOGIN_DATA: Lazy<Mutex<(bool, bool)>> = Lazy::new(|| {
+    println!("初始化...");
+    // 0: 需要登录, 1:是否已经登录
+    Mutex::new((false, false))
+});
+
+
+pub enum CointrSwapWsType {
+    PublicAndPrivate
+}
+
+
+//订阅频道
+#[derive(Clone)]
+pub enum CointrSwapSubscribeType {
+    // 深度
+    PuFuturesDepth,
+    // 公开成交
+    PuFuturesTrades,
+    // K线数据
+    PuFuturesRecords,
+
+    // // 深度
+    // PuFuturesDepth,
+    // // 公开成交
+    // PuFuturesTrades,
+    // // K线数据
+    // PuFuturesRecords,
+    //
+    // // 订单
+    // PrFuturesOrders,
+    // // 仓位
+    // PrFuturesPositions,
+    // // 余额
+    // PrFuturesBalances,
+}
+
+//账号信息
+#[derive(Clone)]
+#[allow(dead_code)]
+pub struct CointrSwapLogin {
+    pub api_key: String,
+    pub secret: String,
+    pub api_memo: String,
+}
+
+#[derive(Clone)]
+pub struct CointrSwapWs {
+    tag: String,
+    // 类型
+    address_url: String,
+    // 地址
+    login_param: Option<CointrSwapLogin>,
+    // 账号
+    symbol_s: Vec<String>,
+    // 币对
+    subscribe_types: Vec<CointrSwapSubscribeType>,
+    // 订阅
+    _heartbeat_time: u64,                                        // 心跳间隔
+}
+
+
+impl CointrSwapWs {
+    /*******************************************************************************************************/
+    /*****************************************实例化一个对象****************************************************/
+    /*******************************************************************************************************/
+    pub fn new(is_colo: bool, login_param: Option<CointrSwapLogin>, ws_type: CointrSwapWsType) -> CointrSwapWs {
+        return Self::new_with_tag("default-BingxSwapWs".to_string(), is_colo, login_param, ws_type);
+    }
+
+    pub fn new_with_tag(tag: String, _is_colo: bool, login_param: Option<CointrSwapLogin>, ws_type: CointrSwapWsType) -> CointrSwapWs {
+        /*******公共频道-私有频道数据组装*/
+        let address_url = match ws_type {
+            CointrSwapWsType::PublicAndPrivate => {
+                let url = "wss://stream.cointr.pro/ws".to_string();
+                info!("走普通通道(不支持colo通道):{}", url);
+                url
+            }
+        };
+
+        CointrSwapWs {
+            tag,
+            address_url,
+            login_param,
+            symbol_s: vec![],
+            subscribe_types: vec![],
+            _heartbeat_time: 1000 * 5,
+        }
+    }
+
+    /*******************************************************************************************************/
+    /*****************************************订阅函数********************************************************/
+    /*******************************************************************************************************/
+    //手动添加订阅信息
+    pub fn set_subscribe(&mut self, subscribe_types: Vec<CointrSwapSubscribeType>) {
+        self.subscribe_types.extend(subscribe_types);
+    }
+    //手动添加币对
+    pub fn set_symbols(&mut self, mut b_array: Vec<String>) {
+        for symbol in b_array.iter_mut() {
+            // 大写
+            *symbol = symbol.to_uppercase();
+            // 字符串替换
+            *symbol = symbol.replace("_", "");
+        }
+        self.symbol_s = b_array;
+    }
+    //频道是否需要登录
+    fn contains_pr(&self) -> bool {
+        for t in self.subscribe_types.clone() {
+            if match t {
+                CointrSwapSubscribeType::PuFuturesDepth => false,
+                CointrSwapSubscribeType::PuFuturesTrades => false,
+                CointrSwapSubscribeType::PuFuturesRecords => false,
+            } {
+                return true;
+            }
+        }
+        false
+    }
+
+    /*******************************************************************************************************/
+    /*****************************************工具函数********************************************************/
+    /*******************************************************************************************************/
+    //订阅枚举解析
+    pub fn enum_to_string(symbol: String, subscribe_type: CointrSwapSubscribeType, _login_param: Option<CointrSwapLogin>) -> String {
+        match subscribe_type {
+            CointrSwapSubscribeType::PuFuturesDepth => {//深度
+                json!({
+                    "op":"subscribe",
+                    "channel":"books_perp",
+                    "args":{
+                        "instId":symbol,
+                        "":"0.001"
+                    },
+                }).to_string()
+            }
+            CointrSwapSubscribeType::PuFuturesTrades => {//公开成交
+                json!({
+                    "op":"subscribe",
+                    "channel":"trades_perp",
+                    "args":{
+                        "instId":symbol
+                    },
+                }).to_string()
+            }
+            CointrSwapSubscribeType::PuFuturesRecords => {//k线数据
+                json!({
+                    "op":"subscribe",
+                    "channel":"kline_perp",
+                    "args":{
+                        "instId":symbol,
+                        "bar":"1M"
+                    },
+                }).to_string()
+            }
+        }
+    }
+    //订阅信息生成
+    pub fn get_subscription(&self) -> Vec<String> {
+        let mut args = vec![];
+        // 只获取第一个
+        for symbol in &self.symbol_s {
+            for subscribe_type in &self.subscribe_types {
+                let ty_str = Self::enum_to_string(symbol.clone(),
+                                                  subscribe_type.clone(),
+                                                  self.login_param.clone(),
+                );
+                args.push(ty_str);
+            }
+        }
+
+        return args;
+    }
+
+    /*******************************************************************************************************/
+    /*****************************************socket基本*****************************************************/
+    /*******************************************************************************************************/
+    //链接
+    pub async fn ws_connect_async<F, Future>(&mut self,
+                                             is_shutdown_arc: Arc<AtomicBool>,
+                                             handle_function: F,
+                                             write_tx_am: &Arc<Mutex<UnboundedSender<Message>>>,
+                                             write_to_socket_rx: UnboundedReceiver<Message>) -> Result<(), Error>
+        where
+            F: Fn(ResponseData) -> Future + Clone + Send + 'static + Sync,
+            Future: std::future::Future<Output=()> + Send + 'static, // 确保 Fut 是一个 Future,且输出类型为 ()
+    {
+        let login_is = self.contains_pr();
+        let login_param = self.login_param.clone();
+        let subscription = self.get_subscription();
+        let address_url = self.address_url.clone();
+        let label = self.tag.clone();
+        // let heartbeat_time = self.heartbeat_time.clone();
+
+
+        //心跳-- 方法内部线程启动
+        // let write_tx_clone1 = Arc::clone(write_tx_am);
+        let write_tx_clone2 = Arc::clone(write_tx_am);
+        // tokio::spawn(async move {
+        //     trace!("线程-异步心跳-开始");
+        //     AbstractWsMode::ping_or_pong(write_tx_clone1, HeartbeatType::Ping, heartbeat_time).await;
+        //     trace!("线程-异步心跳-结束");
+        // });
+
+        //设置订阅
+        let mut subscribe_array = vec![];
+        for su in subscription {
+            subscribe_array.push(su);
+        }
+
+
+        //链接
+        let t2 = tokio::spawn(async move {
+            let write_to_socket_rx_arc = Arc::new(Mutex::new(write_to_socket_rx));
+
+            info!("启动连接");
+            loop {
+                info!("Cointr_usdt_swap socket 连接中……");
+                // 需要登录
+                if login_is {
+                    let mut login_data = LOGIN_DATA.lock().await;
+                    let login_param_real = login_param.clone().unwrap();
+                    login_data.0 = true;
+
+                    let timestamp = Utc::now().timestamp_millis().to_string();
+                    let api_key = login_param_real.api_key.clone();
+                    let secret_key = login_param_real.secret.clone();
+                    let api_memo = login_param_real.api_memo.clone();
+
+
+                    // let timestamp = "1589267764859".to_string();
+                    // let api_key = "80618e45710812162b04892c7ee5ead4a3cc3e56".to_string();
+                    // let secret_key = "6c6c98544461bbe71db2bca4c6d7fd0021e0ba9efc215f9c6ad41852df9d9df9".to_string();
+                    // let api_memo = "test001".to_string();
+
+                    let sign = {
+                        let message = format!("{}#{}#Cointr.WebSocket", timestamp.clone(), api_memo);
+                        trace!("组装数据:\n{}", message);
+
+                        let signed_key = hmac::Key::new(hmac::HMAC_SHA256, secret_key.as_ref());
+                        let sign = hex::encode(hmac::sign(&signed_key, message.as_bytes()).as_ref());
+                        sign
+                    };
+
+
+                    let mut args = vec![];
+                    args.push(api_key.clone());
+                    args.push(timestamp.clone());
+                    args.push(sign.clone());
+                    args.push(String::from("web"));
+                    // {"action":"access","args":["<API_KEY>","<timestamp>","<sign>","<dev>"]}
+                    let login_param = json!({
+                        "action": "access",
+                        "args": [
+                           api_key, timestamp.as_str(),sign.as_str(),"web"
+                        ]
+                    });
+                    let login_str = login_param.to_string();
+                    info!("发起ws登录: {}", login_str);
+                    let write_tx_c = Arc::clone(&write_tx_clone2);
+                    AbstractWsMode::send_subscribe(write_tx_c, Message::Text(login_str)).await;
+                }
+
+                AbstractWsMode::ws_connect_async(is_shutdown_arc.clone(), handle_function.clone(), address_url.clone(),
+                                                 login_is, label.clone(), subscribe_array.clone(), write_to_socket_rx_arc.clone(),
+                                                 Self::message_text_sync, Self::message_ping, Self::message_pong, Self::message_binary_sync,
+                ).await;
+                let mut login_data = LOGIN_DATA.lock().await;
+                // 断联后 设置为没有登录
+                login_data.1 = false;
+                info!("Cointr_usdt_swap socket 断连,1s以后重连……");
+                error!("Cointr_usdt_swap socket 断连,1s以后重连……");
+                tokio::time::sleep(Duration::from_secs(1)).await;
+            }
+        });
+        tokio::try_join!(t2).unwrap();
+        trace!("线程-心跳与链接-结束");
+
+        Ok(())
+    }
+    /*******************************************************************************************************/
+    /*****************************************数据解析*****************************************************/
+    /*******************************************************************************************************/
+    //数据解析-Text
+    pub async fn message_text(text: String) -> Option<ResponseData> {
+        let response_data = Self::ok_text(text).await;
+        Option::from(response_data)
+    }
+    pub fn message_text_sync(text: String) -> Option<ResponseData> {
+        // 使用 tokio::task::block_in_place 来等待异步函数的结果
+        task::block_in_place(|| {
+            tokio::runtime::Handle::current().block_on(Self::message_text(text))
+        })
+    }
+    //数据解析-ping
+    pub fn message_ping(_pi: Vec<u8>) -> Option<ResponseData> {
+        return Option::from(ResponseData::new("".to_string(), -300, "success".to_string(), Value::Null));
+    }
+    //数据解析-pong
+    pub fn message_pong(_po: Vec<u8>) -> Option<ResponseData> {
+        return Option::from(ResponseData::new("".to_string(), -301, "success".to_string(), Value::Null));
+    }
+    //数据解析-二进制
+    pub async fn message_binary(binary: Vec<u8>) -> Option<ResponseData> {
+        //二进制WebSocket消息
+        let message_str = Self::parse_zip_data(binary);
+        let response_data = Self::ok_text(message_str).await;
+        Option::from(response_data)
+    }
+    pub fn message_binary_sync(binary: Vec<u8>) -> Option<ResponseData> {
+        // 使用 tokio::task::block_in_place 来等待异步函数的结果
+        task::block_in_place(|| {
+            tokio::runtime::Handle::current().block_on(Self::message_binary(binary))
+        })
+    }
+    //数据解析
+    pub async fn ok_text(text: String) -> ResponseData
+    {
+        // info!("原始数据:{}", text);
+        let mut res_data = ResponseData::new("".to_string(), 200, "success".to_string(), Value::Null);
+        let json_value: Value = serde_json::from_str(&text).unwrap();
+
+        let code = json_value["code"].as_i64();
+        match code {
+            None => {}
+            Some(_) => {
+                let msg = json_value["msg"].as_str().unwrap();
+                match msg {
+                    "connect.success" => {
+                        res_data.code = -201;
+                        res_data.message = format!("连接成功:");
+                        return res_data;
+                    }
+                    "subscribe.faild" => {
+                        res_data.code = 400;
+                        res_data.message = format!("订阅失败:{}", msg);
+                        return res_data;
+                    }
+                    _ => {}
+                }
+            }
+        }
+        let event = json_value["event"].as_str();
+        match event {
+            None => {}
+            Some(v) => {
+                match v {
+                    "subscribe" => {
+                        res_data.code = -201;
+                        res_data.message = format!("订阅成功:{}", json_value.clone().to_string());
+                        return res_data;
+                    }
+                    "error" => {
+                        res_data.code = 400;
+                        res_data.message = format!("订阅失败:{}", json_value["msg"].clone().to_string());
+                        return res_data;
+                    }
+                    _ => {}
+                }
+            }
+        }
+
+
+        let channel = json_value["channel"].as_str();
+        match channel {
+            None => {}
+            Some(c) => {
+                let action = json_value["action"].as_str().unwrap();
+                if action.contains("update") {
+                    res_data.code = 200;
+                    res_data.data = json_value.clone();
+                    if c.contains("books_perp") {
+                        res_data.channel = "futures.order_book".to_string();
+                    } else if c.contains("trades_perp") {
+                        res_data.channel = "futures.trades".to_string();
+                    } else if c.contains("kline_perp") {
+                        res_data.channel = "futures.candlesticks".to_string();
+                    } else {
+                        res_data.code = 400;
+                        res_data.channel = "未知推送数据".to_string();
+                    }
+                }else{
+                    res_data.code = 400;
+                    res_data.channel = format!("{}类型数据",action);
+                }
+                return res_data;
+            }
+        }
+
+        res_data.code = 400;
+        res_data.message = format!("未知响应内容");
+        res_data.data = text.parse().unwrap();
+        trace!("--------------------------------");
+        res_data
+    }
+
+    fn parse_zip_data(p0: Vec<u8>) -> String {
+        // 创建一个GzDecoder的实例,将压缩数据作为输入
+        let mut decoder = GzDecoder::new(&p0[..]);
+
+        // 创建一个缓冲区来存放解压缩后的数据
+        let mut decompressed_data = Vec::new();
+
+        // 读取解压缩的数据到缓冲区中
+        decoder.read_to_end(&mut decompressed_data).expect("解压缩失败");
+        let result = from_utf8(&decompressed_data)
+            .expect("解压缩后的数据不是有效的UTF-8");
+
+        // info!("解压缩数据 {:?}", result);
+        result.to_string()
+    }
+}
+

+ 15 - 3
exchanges/src/lib.rs

@@ -23,10 +23,22 @@ pub mod kucoin_spot_ws;
 pub mod kucoin_spot_rest;
 pub mod crypto_spot_ws;
 pub mod bybit_swap_rest;
-pub mod xlsx_utils;
 pub mod bybit_swap_ws;
-pub mod coinex_swap_rest;
 pub mod coinex_swap_ws;
+pub mod coinex_swap_rest;
 pub mod htx_swap_ws;
 pub mod htx_swap_rest;
-
+pub mod bingx_swap_ws;
+pub mod bingx_swap_rest;
+pub mod mexc_swap_ws;
+pub mod mexc_swap_rest;
+pub mod bitmart_swap_rest;
+pub mod bitmart_swap_ws;
+pub mod coinsph_swap_rest;
+pub mod coinsph_swap_ws;
+pub mod phemex_swap_rest;
+pub mod phemex_swap_ws;
+pub mod woo_swap_ws;
+pub mod woo_swap_rest;
+pub mod cointr_swap_rest;
+pub mod cointr_swap_ws;

+ 314 - 0
exchanges/src/mexc_swap_rest.rs

@@ -0,0 +1,314 @@
+use std::collections::BTreeMap;
+use chrono::Utc;
+use reqwest::header::HeaderMap;
+use reqwest::{Client};
+use rust_decimal::Decimal;
+use rust_decimal::prelude::FromPrimitive;
+use rust_decimal_macros::dec;
+use tracing::{error, info, trace};
+use crate::http_tool::RestTool;
+use crate::response_base::ResponseData;
+use ring::hmac;
+use serde_json::Value;
+
+#[derive(Clone, Debug)]
+pub struct MexcSwapRest {
+    pub tag: String,
+    base_url: String,
+    client: reqwest::Client,
+    /*******参数*/
+    //是否需要登录
+    //登录所需参数
+    login_param: BTreeMap<String, String>,
+    delays: Vec<i64>,
+    max_delay: i64,
+    avg_delay: Decimal,
+
+}
+
+impl MexcSwapRest {
+    /*******************************************************************************************************/
+    /*****************************************获取一个对象****************************************************/
+    /*******************************************************************************************************/
+
+    pub fn new(is_colo: bool, login_param: BTreeMap<String, String>) -> MexcSwapRest
+    {
+        return MexcSwapRest::new_with_tag("default-MexcSwapRest".to_string(), is_colo, login_param);
+    }
+    pub fn new_with_tag(tag: String, is_colo: bool, login_param: BTreeMap<String, String>) -> MexcSwapRest {
+        let base_url = if is_colo {
+            "https://contract.mexc.com".to_string()
+        } else {
+            "https://contract.mexc.com".to_string()
+        };
+
+        if is_colo {
+            info!("开启高速(未配置,走普通:{})通道",base_url);
+        } else {
+            info!("走普通通道:{}",base_url);
+        }
+        /*****返回结构体*******/
+        MexcSwapRest {
+            tag,
+            base_url,
+            client: Client::new(),
+            login_param,
+            delays: vec![],
+            max_delay: 0,
+            avg_delay: dec!(0.0),
+        }
+    }
+
+    /*******************************************************************************************************/
+    /*****************************************rest请求函数********************************************************/
+    /*******************************************************************************************************/
+    //获取合约信息
+    pub async fn get_market(&mut self, params: Value) -> ResponseData {
+        let data = self.request("GET".to_string(),
+                                "/api/v1".to_string(),
+                                "/contract/detail".to_string(),
+                                false,
+                                params,
+        ).await;
+        data
+    }
+
+    /*******************************************************************************************************/
+    /*****************************************工具函数********************************************************/
+    /*******************************************************************************************************/
+    pub fn get_delays(&self) -> Vec<i64> {
+        self.delays.clone()
+    }
+    pub fn get_avg_delay(&self) -> Decimal {
+        self.avg_delay.clone()
+    }
+    pub fn get_max_delay(&self) -> i64 {
+        self.max_delay.clone()
+    }
+    fn get_delay_info(&mut self) {
+        let last_100 = if self.delays.len() > 100 {
+            self.delays[self.delays.len() - 100..].to_vec()
+        } else {
+            self.delays.clone()
+        };
+
+        let max_value = last_100.iter().max().unwrap();
+        if max_value.clone().to_owned() > self.max_delay {
+            self.max_delay = max_value.clone().to_owned();
+        }
+
+        let sum: i64 = last_100.iter().sum();
+        let sum_v = Decimal::from_i64(sum).unwrap();
+        let len_v = Decimal::from_u64(last_100.len() as u64).unwrap();
+        self.avg_delay = (sum_v / len_v).round_dp(1);
+        self.delays = last_100.clone().into_iter().collect();
+    }
+    //调用请求
+    pub async fn request(&mut self,
+                         method: String,
+                         prefix_url: String,
+                         request_url: String,
+                         is_login: bool,
+                         mut  params: Value) -> ResponseData
+    {
+        trace!("login_param:{:?}", self.login_param);
+        //解析账号信息
+        let mut access_key = "".to_string();
+        let mut secret_key = "".to_string();
+        let mut passphrase = "".to_string();
+        if self.login_param.contains_key("access_key") {
+            access_key = self.login_param.get("access_key").unwrap().to_string();
+        }
+        if self.login_param.contains_key("secret_key") {
+            secret_key = self.login_param.get("secret_key").unwrap().to_string();
+        }
+        if self.login_param.contains_key("pass_key") {
+            passphrase = self.login_param.get("pass_key").unwrap().to_string();
+        }
+        let mut is_login_param = true;
+        if access_key == "" || secret_key == "" || passphrase == "" {
+            is_login_param = false
+        }
+
+        //每个接口都有的参数
+        let timestamp = Utc::now().timestamp_millis();
+        let recv_window = 3000;
+        params["timestamp"] = serde_json::json!(timestamp);
+        params["recvWindow"] = serde_json::json!(recv_window);
+
+
+        //请求类型不同,可能请求头body 不同
+        let mut body = "{}".to_string();
+        let mut headers = HeaderMap::new();
+        if method == "POST" {
+            headers.insert("Content-Type", "application/json".parse().unwrap());
+            body = params.to_string();
+        }
+
+        //是否需要登录-- 组装sing
+        if is_login {
+            if !is_login_param {
+                let e = ResponseData::error(self.tag.clone(), "登录参数错误!".to_string());
+                return e;
+            } else {
+                // //需要登录-且登录参数齐全
+                // trace!("param:{}", params);
+                // trace!("body:{}", body);
+                // //组装sing
+                // let sing = Self::sign(secret_key.clone(),
+                //                       method.clone(),
+                //                       prefix_url.clone(),
+                //                       request_url.clone(),
+                //                       params.clone(),
+                //                       body.clone(),
+                //                       timestamp.clone(),
+                // );
+                // //组装header
+                // headers.extend(Self::headers(sing, timestamp, passphrase, access_key));
+            }
+        }
+
+
+        // trace!("headers:{:?}", headers);
+        // let base_url = format!("{}{}", prefix_url.clone(), request_url.clone());
+        let start_time = chrono::Utc::now().timestamp_millis();
+        let response = self.http_tool(
+            format!("{}{}", prefix_url.clone(), request_url.clone()),
+            method.to_string(),
+            params.to_string(),
+            body,
+            headers,
+        ).await;
+
+        let time_array = chrono::Utc::now().timestamp_millis() - start_time;
+        self.delays.push(time_array);
+        self.get_delay_info();
+
+        response
+        //
+        // let time_array = chrono::Utc::now().timestamp_millis() - start_time;
+        // self.delays.push(time_array);
+        // self.get_delay_info();
+        // let res_data = Self::res_data_analysis(get_response, base_url, params.to_string());
+        // res_data
+    }
+
+    // pub fn headers(_: String, _timestamp: String, passphrase: String, access_key: String) -> HeaderMap {
+    //     let mut headers = HeaderMap::new();
+    //     // headers.insert("OK-ACCESS-KEY", access_key.parse().unwrap());
+    //     // headers.insert("OK-ACCESS-SIGN", sign.parse().unwrap());
+    //     // headers.insert("OK-ACCESS-TIMESTAMP", timestamp.parse().unwrap());
+    //     // headers.insert("OK-ACCESS-PASSPHRASE", passphrase.parse().unwrap());
+    //     headers
+    // }
+    pub fn sign(secret_key: String,
+                method: String, prefix_url: String, request_url: String,
+                params: String, body: String, timestamp: String) -> String
+    {
+        /*签名生成*/
+        let url_param_str = RestTool::parse_params_to_str(params);
+        let base_url = if method == "GET" {
+            format!("{}{}?{}", prefix_url, request_url, url_param_str)
+        } else {
+            format!("{}{}", prefix_url, request_url)
+        };
+
+        // 时间戳 + 请求类型+ 请求参数字符串
+        let message = format!("{}{}{}{}", timestamp, method, base_url, body);
+        trace!("message:{}",message);
+
+        // 做签名
+        let hmac_key = ring::hmac::Key::new(hmac::HMAC_SHA256, secret_key.as_bytes());
+        let result = ring::hmac::sign(&hmac_key, &message.as_bytes());
+        let sign = base64::encode(result);
+        sign
+    }
+
+    // async fn http_tool(&mut self, request_path: String, request_type: String, params: String, headers: HeaderMap) -> Result<ResponseData, reqwest::Error> {
+    async fn http_tool(&mut self, request_path: String,
+                       request_type: String,
+                       params: String,
+                       body: String,
+                       headers: HeaderMap) -> ResponseData {
+        /****请求接口与 地址*/
+        let url = format!("{}{}", self.base_url.to_string(), request_path);
+        let request_type = request_type.clone().to_uppercase();
+        let addrs_url: String = if RestTool::parse_params_to_str(params.clone()) == "" {
+            url.clone()
+        } else {
+            format!("{}?{}", url.clone(), RestTool::parse_params_to_str(params.clone()))
+        };
+
+        trace!("url-----:???{}",url.clone());
+        trace!("addrs_url-----:???{}",addrs_url.clone());
+        trace!("params-----:???{}",params.clone());
+        trace!("body-----:???{}",body.clone());
+
+        let request_builder = match request_type.as_str() {
+            "GET" => self.client.get(addrs_url.clone()).headers(headers),
+            "POST" => self.client.post(url.clone()).body(body).headers(headers),
+            // "DELETE" => self.client.delete(addrs_url.clone()).headers(headers),
+            // "PUT" => self.client.put(url.clone()).json(&params),
+            _ => {
+                panic!("{}", format!("错误的请求类型:{}", request_type.clone()))
+            }
+        };
+
+        // 读取响应的内容
+        let response = request_builder.send().await.unwrap();
+        let is_success = response.status().is_success(); // 先检查状态码
+        let text = response.text().await.unwrap();
+        // trace!("text:???{:?}",text);
+        return if is_success {
+            self.on_success_data(&text)
+        } else {
+            self.on_error_data(&text, &addrs_url, &params)
+        };
+    }
+    pub fn on_success_data(&mut self, text: &String) -> ResponseData {
+        let json_value = serde_json::from_str::<Value>(&text).unwrap();
+        // return  ResponseData::new(self.tag.clone(), 200, "success".to_string(), json_value);
+
+        let code = json_value["code"].as_i64().unwrap();
+        match code {
+            0 => {
+                //判断是否有code ,没有表示特殊接口,直接返回
+                if json_value.get("data").is_some() {
+                    let data = json_value.get("data").unwrap();
+                    ResponseData::new(self.tag.clone(), 200, "success".to_string(), data.clone())
+                } else {
+                    ResponseData::new(self.tag.clone(), 200, "success".to_string(), json_value)
+                }
+            }
+            _ => {
+                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 {
+        let json_value = serde_json::from_str::<Value>(&text);
+
+        match json_value {
+            Ok(data) => {
+                let message;
+
+                if !data["message"].is_null() {
+                    message = format!("{}:{}", data["tag"].as_str().unwrap(), data["message"].as_str().unwrap());
+                } else {
+                    message = data["tag"].to_string();
+                }
+
+                let mut error = ResponseData::error(self.tag.clone(), message);
+                error.message = format!("请求地址:{}, 请求参数:{}, 报错内容:{}。", base_url, params, error.message);
+                error
+            }
+            Err(e) => {
+                error!("解析错误:{:?}", e);
+                let error = ResponseData::error("".to_string(),
+                                                format!("json 解析失败:{},相关参数:{}", e, text));
+                error
+            }
+        }
+    }
+}

+ 368 - 0
exchanges/src/mexc_swap_ws.rs

@@ -0,0 +1,368 @@
+use std::io::Read;
+use std::sync::Arc;
+use std::sync::atomic::AtomicBool;
+use std::time::Duration;
+
+use flate2::read::GzDecoder;
+use futures_channel::mpsc::{UnboundedReceiver, UnboundedSender};
+use serde_json::json;
+use serde_json::Value;
+use tokio::sync::Mutex;
+use tokio_tungstenite::tungstenite::{Error, Message};
+use tracing::{error, info, trace};
+
+use crate::response_base::ResponseData;
+use crate::socket_tool::AbstractWsMode;
+
+//类型
+pub enum MexcSwapWsType {
+    PublicAndPrivate,
+}
+
+
+#[derive(Debug)]
+#[derive(Clone)]
+pub struct MexcSwapWsParam {
+    pub token: String,
+    pub ws_url: String,
+    pub ws_ping_interval: i64,
+    pub ws_ping_timeout: i64,
+    pub is_ok_subscribe: bool,
+}
+
+//订阅频道
+#[derive(Clone)]
+pub enum MexcSwapSubscribeType {
+    // 深度
+    PuFuturesDepth,
+    // 公开成交
+    PuFuturesTrades,
+    // K线数据
+    PuFuturesRecords,
+}
+
+//账号信息
+#[derive(Clone, Debug)]
+pub struct MexcSwapLogin {
+    pub access_key: String,
+    pub secret_key: String,
+    pub pass_key: String,
+}
+
+#[derive(Clone)]
+#[allow(dead_code)]
+pub struct MexcSwapWs {
+    //类型
+    tag: String,
+    //地址
+    address_url: String,
+    //账号
+    login_param: Option<MexcSwapLogin>,
+    //登录数据
+    ws_param: MexcSwapWsParam,
+    //币对
+    symbol_s: Vec<String>,
+    //订阅
+    subscribe_types: Vec<MexcSwapSubscribeType>,
+    //心跳间隔
+    heartbeat_time: u64,
+}
+
+impl MexcSwapWs {
+    /*******************************************************************************************************/
+    /*****************************************获取一个对象****************************************************/
+    /*******************************************************************************************************/
+    pub fn new(is_colo: bool, login_param: Option<MexcSwapLogin>, ws_type: MexcSwapWsType) -> MexcSwapWs {
+        return Self::new_with_tag("default-MexcSwapWs".to_string(), is_colo, login_param, ws_type);
+    }
+    pub fn new_with_tag(tag: String, is_colo: bool, login_param: Option<MexcSwapLogin>, ws_type: MexcSwapWsType) -> MexcSwapWs {
+        /*******公共频道-私有频道数据组装*/
+        let address_url = match ws_type {
+            MexcSwapWsType::PublicAndPrivate => {
+                let url = "wss://contract.mexc.com/edge".to_string();
+                info!("走普通通道(不支持colo通道):{}", url);
+                url
+            }
+        };
+
+        /*******公共频道-私有频道数据组装*/
+        let ws_param = MexcSwapWsParam {
+            token: "".to_string(),
+            ws_url: "".to_string(),
+            ws_ping_interval: 0,
+            ws_ping_timeout: 0,
+            is_ok_subscribe: false,
+        };
+
+        if is_colo {
+            info!("开启高速(未配置,走普通:{})通道",address_url);
+        } else {
+            info!("走普通通道:{}",address_url);
+        }
+
+        MexcSwapWs {
+            tag,
+            address_url,
+            login_param,
+            ws_param,
+            symbol_s: vec![],
+            subscribe_types: vec![],
+            heartbeat_time: 1000 * 18,
+        }
+    }
+
+    /*******************************************************************************************************/
+    /*****************************************订阅函数********************************************************/
+    /*******************************************************************************************************/
+    //手动添加订阅信息
+    pub fn set_subscribe(&mut self, subscribe_types: Vec<MexcSwapSubscribeType>) {
+        self.subscribe_types.extend(subscribe_types);
+    }
+    //手动添加币对
+    pub fn set_symbols(&mut self, mut b_array: Vec<String>) {
+        for symbol in b_array.iter_mut() {
+            // 大写
+            *symbol = symbol.to_uppercase();
+            // 字符串替换
+            *symbol = symbol.replace("_", "_");
+        }
+        self.symbol_s = b_array;
+    }
+    fn contains_pr(&self) -> bool {
+        for t in self.subscribe_types.clone() {
+            if match t {
+                MexcSwapSubscribeType::PuFuturesTrades => false,
+                MexcSwapSubscribeType::PuFuturesRecords => false,
+                MexcSwapSubscribeType::PuFuturesDepth => false,
+            } {
+                return true;
+            }
+        }
+        false
+    }
+    /*******************************************************************************************************/
+    /*****************************************工具函数********************************************************/
+    /*******************************************************************************************************/
+    //订阅枚举解析
+    pub fn enum_to_string(symbol: String, subscribe_type: MexcSwapSubscribeType) -> Value {
+        match subscribe_type {
+            MexcSwapSubscribeType::PuFuturesDepth => {//深度
+                json!({
+                   "method":"sub.depth",
+                   "param":{ "symbol":symbol }
+                })
+            }
+            MexcSwapSubscribeType::PuFuturesRecords => {//k线
+                json!({
+                    "method":"sub.kline",
+                    "param":{
+                        "symbol":symbol,
+                        "interval":"Min1"
+                    }
+                })
+            }
+            MexcSwapSubscribeType::PuFuturesTrades => {//公开成交
+                json!({
+                    "method": "sub.deal",
+                    "param": {"symbol":symbol}
+                })
+            }
+        }
+    }
+    //订阅信息生成
+    pub fn get_subscription(&self) -> Vec<String> {
+        let mut array = vec![];
+        for symbol in &self.symbol_s {
+            for subscribe_type in &self.subscribe_types {
+                let ty_str = Self::enum_to_string(symbol.clone(), subscribe_type.clone());
+                array.push(ty_str.to_string());
+            }
+        }
+        array
+    }
+    /*******************************************************************************************************/
+    /*****************************************socket基本*****************************************************/
+    /*******************************************************************************************************/
+    //链接
+    pub async fn ws_connect_async<F, Future>(&mut self,
+                                             is_shutdown_arc: Arc<AtomicBool>,
+                                             handle_function: F,
+                                             _write_tx_am: &Arc<Mutex<UnboundedSender<Message>>>,
+                                             write_to_socket_rx: UnboundedReceiver<Message>) -> Result<(), Error>
+        where
+            F: Fn(ResponseData) -> Future + Clone + Send + 'static + Sync,
+            Future: std::future::Future<Output=()> + Send + 'static, // 确保 Fut 是一个 Future,且输出类型为 ()
+    {
+        let login_is = self.contains_pr();
+        let subscription = self.get_subscription();
+        let address_url = self.address_url.clone();
+        let tag = self.tag.clone();
+        // let heartbeat_time = self.ws_param.ws_ping_interval.clone();
+
+        //心跳-- 方法内部线程启动
+        // let write_tx_clone1 = write_tx_am.clone();
+        // tokio::spawn(async move {
+        //     trace!("线程-异步心跳-开始");
+        //     AbstractWsMode::ping_or_pong(write_tx_clone1, HeartbeatType::Ping, heartbeat_time as u64).await;
+        //     trace!("线程-异步心跳-结束");
+        // });
+
+
+        //设置订阅
+        let subscribe_array = subscription.clone();
+        if login_is {
+            //登录相关
+        }
+
+        //1 链接
+        let t2 = tokio::spawn(async move {
+            let write_to_socket_rx_arc = Arc::new(Mutex::new(write_to_socket_rx));
+
+            loop {
+                info!("Mexc_usdt_swap socket 连接中……");
+                AbstractWsMode::ws_connect_async(is_shutdown_arc.clone(), handle_function.clone(), address_url.clone(),
+                                                 false, tag.clone(), subscribe_array.clone(), write_to_socket_rx_arc.clone(),
+                                                 Self::message_text, Self::message_ping, Self::message_pong, Self::message_binary).await;
+
+                error!("Mexc_usdt_swap socket 断连,1s以后重连……");
+                tokio::time::sleep(Duration::from_secs(1)).await;
+            }
+        });
+
+        tokio::try_join!(t2).unwrap();
+        trace!("线程-心跳与链接-结束");
+
+        Ok(())
+    }
+    /*******************************************************************************************************/
+    /*****************************************数据解析*****************************************************/
+    /*******************************************************************************************************/
+    //数据解析-Text
+    pub fn message_text(text: String) -> Option<ResponseData> {
+        let response_data = Self::ok_text(text);
+        Option::from(response_data)
+    }
+    //数据解析-ping
+    pub fn message_ping(_pi: Vec<u8>) -> Option<ResponseData> {
+        return Option::from(ResponseData::new("".to_string(), -300, "success".to_string(), Value::Null));
+    }
+    //数据解析-pong
+    pub fn message_pong(_po: Vec<u8>) -> Option<ResponseData> {
+        return Option::from(ResponseData::new("".to_string(), -301, "success".to_string(), Value::Null));
+    }
+    //数据解析-二进制
+    pub fn message_binary(po: Vec<u8>) -> Option<ResponseData> {
+        //二进制WebSocket消息
+        // let message_str = format!("Binary:{:?}", _po);
+        // Option::from(ResponseData::new("".to_string(), 2, message_str, Value::Null))
+        // let result = String::from_utf8(bytes);
+        // let result = String::from_utf8(po);
+
+        let mut gz_decoder = GzDecoder::new(&po[..]);
+        let mut decompressed_data = Vec::new();
+
+        // 尝试解压数据
+        if let Ok(_) = gz_decoder.read_to_end(&mut decompressed_data) {
+            // 将解压后的字节向量转换为 UTF-8 字符串
+            match String::from_utf8(decompressed_data) {
+                Ok(text) => {
+                    let response_data = Self::ok_text(text);
+                    return Option::from(response_data);
+                }
+                Err(_) => {
+                    return Option::from(ResponseData::new("".to_string(), 400, "二进制数据转化出错".to_string(), Value::Null));
+                }
+            }
+        } else {
+            return Option::from(ResponseData::new("".to_string(), 400, "二进制数据转化出错".to_string(), Value::Null));
+        }
+    }
+    //数据解析
+    pub fn ok_text(text: String) -> ResponseData
+    {
+        // trace!("原始数据:{:?}",text);
+        let mut res_data = ResponseData::new("".to_string(), 200, "success".to_string(), Value::Null);
+        let json_value: serde_json::Value = serde_json::from_str(&text).unwrap();
+
+        match json_value["channel"].as_str() {
+            Some(method) => {
+                if method.contains("pong") {
+                    return ResponseData::new("".to_string(), -301, "success".to_string(), Value::Null);
+                } else if method.contains("rs.sub.") {
+                    //订阅响应
+                    let data = json_value["data"].as_str().unwrap();
+                    if method.contains(".depth") {
+                        res_data.channel = "futures.order_book".to_string();
+                    } else if method.contains(".kline") {
+                        res_data.channel = "futures.candlesticks".to_string();
+                    } else if method.contains(".deal") {
+                        res_data.channel = "futures.trades".to_string();
+                    } else {
+                        res_data.channel = "未知频道订阅".to_string();
+                    }
+
+                    if data == "success" {
+                        res_data.code = -201;
+                        res_data.message = "订阅成功".to_string();
+                    } else {
+                        res_data.code = 400;
+                        res_data.message = "订阅失败".to_string();
+                    }
+                } else if method.contains("push.") {
+                    if method.contains(".depth") {
+                        res_data.channel = "futures.order_book".to_string();
+                    } else if method.contains(".kline") {
+                        res_data.channel = "futures.candlesticks".to_string();
+                    } else if method.contains(".deal") {
+                        res_data.channel = "futures.trades".to_string();
+                    } else {
+                        res_data.channel = "未知频道推送".to_string();
+                    }
+                    res_data.code = 200;
+                    res_data.data = json_value.clone();
+                } else {
+                    res_data.code = -1;
+                    res_data.message = "未知解析".to_string();
+                }
+            }
+            None => {
+                res_data.code = -1;
+                res_data.message = "未知解析".to_string();
+            }
+        }
+        //
+        // if json_value["method"].as_str() == Option::from("id1") {}
+        //
+        // // { "id": "id1", "code": 0, "msg": "" }
+        // if json_value["id"].as_str() == Option::from("id1") {
+        //     //订阅
+        //     if json_value["code"].as_i64() == Option::from(0) {
+        //         res_data.code = -201;
+        //         res_data.message = "订阅成功".to_string();
+        //     } else {
+        //         res_data.code = 400;
+        //         res_data.message = "订阅失败".to_string();
+        //     }
+        // } else if json_value["code"].as_i64() == Option::from(0) {
+        //     res_data.code = 200;
+        //     res_data.data = json_value.clone();
+        //
+        //     //订阅数据 甄别
+        //     let dataType = json_value["dataType"].as_str().unwrap();
+        //     if dataType.contains("@depth") {
+        //         res_data.channel = "futures.order_book".to_string();
+        //     } else if dataType.contains("@trade") {
+        //         res_data.channel = "futures.trades".to_string();
+        //     } else if dataType.contains("@kline_1m") {
+        //         res_data.channel = "futures.candlesticks".to_string();
+        //     } else {
+        //         res_data.channel = "未知推送数据".to_string();
+        //     }
+        // } else {
+        //     res_data.code = -1;
+        //     res_data.message = "未知解析".to_string();
+        // }
+
+        res_data
+    }
+}

+ 305 - 580
exchanges/src/okx_swap_rest.rs

@@ -1,580 +1,305 @@
-// use std::collections::BTreeMap;
-// use reqwest::header::HeaderMap;
-// use reqwest::{Client};
-// use rust_decimal::Decimal;
-// use rust_decimal::prelude::FromPrimitive;
-// use rust_decimal_macros::dec;
-// use tracing::{info, trace};
-// use crate::http_tool::RestTool;
-// use crate::response_base::ResponseData;
-// use ring::hmac;
-//
-// #[derive(Clone, Debug)]
-// pub struct OkxSwapRest {
-//     pub label: String,
-//     base_url: String,
-//     client: reqwest::Client,
-//     /*******参数*/
-//     //是否需要登录
-//     //登录所需参数
-//     login_param: BTreeMap<String, String>,
-//     delays: Vec<i64>,
-//     max_delay: i64,
-//     avg_delay: Decimal,
-//
-// }
-//
-// impl OkxSwapRest {
-//     /*******************************************************************************************************/
-//     /*****************************************获取一个对象****************************************************/
-//     /*******************************************************************************************************/
-//
-//     pub fn new(is_colo: bool, login_param: BTreeMap<String, String>) -> OkxSwapRest
-//     {
-//         return OkxSwapRest::new_label("default-OkxSwapRest".to_string(), is_colo, login_param);
-//     }
-//     pub fn new_label(label: String, is_colo: bool, login_param: BTreeMap<String, String>) -> OkxSwapRest {
-//         let base_url = if is_colo {
-//             "https://www.okx.com".to_string()
-//         } else {
-//             "https://www.okx.com".to_string()
-//         };
-//
-//         if is_colo {
-//             info!("开启高速(未配置,走普通:{})通道",base_url);
-//         } else {
-//             info!("走普通通道:{}",base_url);
-//         }
-//         /*****返回结构体*******/
-//         OkxSwapRest {
-//             label,
-//             base_url,
-//             client: Client::new(),
-//             login_param,
-//             delays: vec![],
-//             max_delay: 0,
-//             avg_delay: dec!(0.0),
-//         }
-//     }
-//
-//     /*******************************************************************************************************/
-//     /*****************************************rest请求函数********************************************************/
-//     /*******************************************************************************************************/
-//     //获取订单信息
-//     pub async fn get_order(&mut self, symbol: String, ord_id: String, cl_ord_id: String) -> ResponseData {
-//         let mut params = serde_json::json!({
-//             "instId":symbol
-//          });
-//         if ord_id.len() > 0 {
-//             params.as_object_mut().unwrap().insert("ordId".parse().unwrap(), serde_json::Value::from(ord_id));
-//         }
-//         if cl_ord_id.len() > 0 {
-//             params.as_object_mut().unwrap().insert("clOrdId".parse().unwrap(), serde_json::Value::from(cl_ord_id));
-//         }
-//         let data = self.request("GET".to_string(),
-//                                 "/api/v5".to_string(),
-//                                 "/trade/order".to_string(),
-//                                 true,
-//                                 params.to_string(),
-//         ).await;
-//         data
-//     }
-//     //获取未成交订单列表
-//     pub async fn get_incomplete_order(&mut self, symbol: String) -> ResponseData {
-//         let params = serde_json::json!({
-//             "instId":symbol
-//          });
-//         let data = self.request("GET".to_string(),
-//                                 "/api/v5".to_string(),
-//                                 "/trade/orders-pending".to_string(),
-//                                 true,
-//                                 params.to_string(),
-//         ).await;
-//         data
-//     }
-//     //获取系统时间
-//     pub async fn get_server_time(&mut self) -> ResponseData {
-//         let params = serde_json::json!({
-//          });
-//         let data = self.request("GET".to_string(),
-//                                 "/api/v5".to_string(),
-//                                 "/public/time".to_string(),
-//                                 false,
-//                                 params.to_string(),
-//         ).await;
-//         data
-//     }
-//     //查看持仓信息
-//     pub async fn get_positions(&mut self, inst_type: String) -> ResponseData {
-//         let mut params = serde_json::json!({
-//          });
-//         if inst_type.len() > 0 {
-//             params.as_object_mut().unwrap().insert("instType".parse().unwrap(), serde_json::Value::from(inst_type));
-//         }
-//         let data = self.request("GET".to_string(),
-//                                 "/api/v5".to_string(),
-//                                 "/account/positions".to_string(),
-//                                 true,
-//                                 params.to_string(),
-//         ).await;
-//         data
-//     }
-//     //获取单个产品行情信息
-//     pub async fn get_ticker(&mut self, symbol: String) -> ResponseData {
-//         let params = serde_json::json!({
-//             "instId":symbol
-//          });
-//         let data = self.request("GET".to_string(),
-//                                 "/api/v5".to_string(),
-//                                 "/market/ticker".to_string(),
-//                                 false,
-//                                 params.to_string(),
-//         ).await;
-//         data
-//     }
-//     //查看账户余额
-//     pub async fn get_balance(&mut self, ccy: String) -> ResponseData {
-//         let params = serde_json::json!({
-//             "ccy":ccy
-//          });
-//         let data = self.request("GET".to_string(),
-//                                 "/api/v5".to_string(),
-//                                 "/account/balance".to_string(),
-//                                 true,
-//                                 params.to_string(),
-//         ).await;
-//         data
-//     }
-//     //获取交易产品基础信息
-//     pub async fn get_instruments(&mut self) -> ResponseData {
-//         let params = serde_json::json!({
-//            "instType":"SWAP"
-//          });
-//         let data = self.request("GET".to_string(),
-//                                 "/api/v5".to_string(),
-//                                 "/public/instruments".to_string(),
-//                                 false,
-//                                 params.to_string(),
-//         ).await;
-//         data
-//     }
-//     //获取成交明细(近三天)
-//     pub async fn get_trade_fills(&mut self, after: String) -> ResponseData {
-//         let mut params = serde_json::json!({
-//              "instType": "SWAP",
-//              "limit":"100"
-//          });
-//         if after.len() > 0 {
-//             params.as_object_mut().unwrap().insert("after".parse().unwrap(), serde_json::Value::from(after));
-//         }
-//         let data = self.request("GET".to_string(),
-//                                 "/api/v5".to_string(),
-//                                 "/trade/fills".to_string(),
-//                                 true,
-//                                 params.to_string(),
-//         ).await;
-//         data
-//     }
-//
-//     //获取成交明细(近三个月)
-//     pub async fn get_trade_fills_history(&mut self, inst_id: String, begin: String, end: String, limit: String) -> ResponseData {
-//         let mut params = serde_json::json!({
-//             "instType": "SWAP",
-//             "instId":inst_id,
-//             "limit":100,
-//          });
-//
-//         if begin.len() > 0 {
-//             params["begin"] = serde_json::json!(begin);
-//         }
-//         if end.len() > 0 {
-//             params["end"] = serde_json::json!(end);
-//         }
-//         if limit.len() > 0 {
-//             params["limit"] = serde_json::json!(limit);
-//         }
-//         let data = self.request("GET".to_string(),
-//                                 "/api/v5".to_string(),
-//                                 "/trade/fills-history".to_string(),
-//                                 true,
-//                                 params.to_string(),
-//         ).await;
-//         data
-//     }
-//
-//     //合约-下单
-//     pub async fn swap_order(&mut self, params: serde_json::Value) -> ResponseData {
-//         let data = self.request("POST".to_string(),
-//                                 "/api/v5".to_string(),
-//                                 "/trade/order".to_string(),
-//                                 true,
-//                                 params.to_string(),
-//         ).await;
-//         data
-//     }
-//     //撤单
-//     pub async fn cancel_order(&mut self, symbol: String, ord_id: String, cl_ord_id: String) -> ResponseData {
-//         let mut params = serde_json::json!({
-//              "instId": symbol
-//          });
-//         if ord_id.len() > 0 {
-//             params.as_object_mut().unwrap().insert("ordId".parse().unwrap(), serde_json::Value::from(ord_id));
-//         }
-//         if cl_ord_id.len() > 0 {
-//             params.as_object_mut().unwrap().insert("clOrdId".parse().unwrap(), serde_json::Value::from(cl_ord_id));
-//         }
-//         let data = self.request("POST".to_string(),
-//                                 "/api/v5".to_string(),
-//                                 "/trade/cancel-order".to_string(),
-//                                 true,
-//                                 params.to_string(),
-//         ).await;
-//         data
-//     }
-//     //设置杠杆倍数-单币种保证金`账户在`全仓`交易模式下,设置`币币杠杆`的杠杆倍数(币对层面)
-//     pub async fn set_leverage(&mut self, symbol: String, lever: String) -> ResponseData {
-//         let params = serde_json::json!({
-//              "instId": symbol,
-//              "lever": lever,
-//              "mgnMode": "cross"
-//          });
-//         let data = self.request("POST".to_string(),
-//                                 "/api/v5".to_string(),
-//                                 "/account/set-leverage".to_string(),
-//                                 true,
-//                                 params.to_string(),
-//         ).await;
-//         data
-//     }
-//     //设置持仓模式
-//     pub async fn set_position_mode(&mut self) -> ResponseData {
-//         let params = serde_json::json!({
-//              "posMode": "long_short_mode",
-//          });
-//         let data = self.request("POST".to_string(),
-//                                 "/api/v5".to_string(),
-//                                 "/account/set-position-mode".to_string(),
-//                                 true,
-//                                 params.to_string(),
-//         ).await;
-//         data
-//     }
-//
-//     //获取历史订单记录(近七天)
-//     pub async fn get_orders_history(&mut self,
-//                                     sprd_id: String,
-//                                     ord_type: String,
-//                                     state: String,
-//                                     begin: String,
-//                                     end: String,
-//                                     limit: String,
-//     ) -> ResponseData {
-//         let mut params = serde_json::json!({
-//          });
-//         if sprd_id.len() > 0 {
-//             params["sprdId"] = serde_json::json!(sprd_id);
-//         }
-//         if ord_type.len() > 0 {
-//             params["ordType"] = serde_json::json!(ord_type);
-//         }
-//         if state.len() > 0 {
-//             params["state"] = serde_json::json!(state);
-//         }
-//         if begin.len() > 0 {
-//             params["begin"] = serde_json::json!(begin);
-//         }
-//         if end.len() > 0 {
-//             params["end"] = serde_json::json!(end);
-//         }
-//         if limit.len() > 0 {
-//             params["limit"] = serde_json::json!(limit);
-//         }
-//         let data = self.request("GET".to_string(),
-//                                 "/api/v5".to_string(),
-//                                 "/sprd/orders-history".to_string(),
-//                                 true,
-//                                 params.to_string(),
-//         ).await;
-//         data
-//     }
-//
-//     //获取历史成交数据(近七天)
-//     pub async fn get_trades(&mut self,
-//                             sprd_id: String,
-//                             trade_id: String,
-//                             ord_id: String,
-//                             begin: String,
-//                             end: String,
-//                             limit: String,
-//     ) -> ResponseData {
-//         let mut params = serde_json::json!({
-//          });
-//         if sprd_id.len() > 0 {
-//             params["sprdId"] = serde_json::json!(sprd_id);
-//         }
-//         if trade_id.len() > 0 {
-//             params["tradeId"] = serde_json::json!(trade_id);
-//         }
-//         if ord_id.len() > 0 {
-//             params["ordId"] = serde_json::json!(ord_id);
-//         }
-//         if begin.len() > 0 {
-//             params["begin"] = serde_json::json!(begin);
-//         }
-//         if end.len() > 0 {
-//             params["end"] = serde_json::json!(end);
-//         }
-//         if limit.len() > 0 {
-//             params["limit"] = serde_json::json!(limit);
-//         }
-//         let data = self.request("GET".to_string(),
-//                                 "/api/v5".to_string(),
-//                                 "/sprd/trades".to_string(),
-//                                 true,
-//                                 params.to_string(),
-//         ).await;
-//         data
-//     }
-//
-//     /*******************************************************************************************************/
-//     /*****************************************工具函数********************************************************/
-//     /*******************************************************************************************************/
-//     pub fn get_delays(&self) -> Vec<i64> {
-//         self.delays.clone()
-//     }
-//     pub fn get_avg_delay(&self) -> Decimal {
-//         self.avg_delay.clone()
-//     }
-//     pub fn get_max_delay(&self) -> i64 {
-//         self.max_delay.clone()
-//     }
-//     fn get_delay_info(&mut self) {
-//         let last_100 = if self.delays.len() > 100 {
-//             self.delays[self.delays.len() - 100..].to_vec()
-//         } else {
-//             self.delays.clone()
-//         };
-//
-//         let max_value = last_100.iter().max().unwrap();
-//         if max_value.clone().to_owned() > self.max_delay {
-//             self.max_delay = max_value.clone().to_owned();
-//         }
-//
-//         let sum: i64 = last_100.iter().sum();
-//         let sum_v = Decimal::from_i64(sum).unwrap();
-//         let len_v = Decimal::from_u64(last_100.len() as u64).unwrap();
-//         self.avg_delay = (sum_v / len_v).round_dp(1);
-//         self.delays = last_100.clone().into_iter().collect();
-//     }
-//     //调用请求
-//     pub async fn request(&mut self,
-//                          method: String,
-//                          prefix_url: String,
-//                          request_url: String,
-//                          is_login: bool,
-//                          params: String) -> ResponseData
-//     {
-//         trace!("login_param:{:?}", self.login_param);
-//         //解析账号信息
-//         let mut access_key = "".to_string();
-//         let mut secret_key = "".to_string();
-//         let mut passphrase = "".to_string();
-//         if self.login_param.contains_key("access_key") {
-//             access_key = self.login_param.get("access_key").unwrap().to_string();
-//         }
-//         if self.login_param.contains_key("secret_key") {
-//             secret_key = self.login_param.get("secret_key").unwrap().to_string();
-//         }
-//         if self.login_param.contains_key("pass_key") {
-//             passphrase = self.login_param.get("pass_key").unwrap().to_string();
-//         }
-//         let mut is_login_param = true;
-//         if access_key == "" || secret_key == "" || passphrase == "" {
-//             is_login_param = false
-//         }
-//
-//
-//         //请求头配置-如果需要登录则存在额外配置
-//         let mut body = "".to_string();
-//         let timestamp = Self::get_timestamp();
-//         let mut headers = HeaderMap::new();
-//         headers.insert("Content-Type", "application/json".parse().unwrap());
-//         if method == "POST" {
-//             body = params.clone();
-//         }
-//
-//
-//         //是否需要登录-- 组装sing
-//         if is_login {
-//             if !is_login_param {
-//                 let e = ResponseData::error(self.label.clone(), "登录参数错误!".to_string());
-//                 return e;
-//             } else {
-//                 //需要登录-且登录参数齐全
-//                 trace!("param:{}", params);
-//                 trace!("body:{}", body);
-//                 //组装sing
-//                 let sing = Self::sign(secret_key.clone(),
-//                                       method.clone(),
-//                                       prefix_url.clone(),
-//                                       request_url.clone(),
-//                                       params.clone(),
-//                                       body.clone(),
-//                                       timestamp.clone(),
-//                 );
-//                 //组装header
-//                 headers.extend(Self::headers(sing, timestamp, passphrase, access_key));
-//             }
-//         }
-//
-//
-//         // trace!("headers:{:?}", headers);
-//         let base_url = format!("{}{}", prefix_url.clone(), request_url.clone());
-//         let start_time = chrono::Utc::now().timestamp_millis();
-//         let get_response = self.http_tool(
-//             format!("{}{}", prefix_url.clone(), request_url.clone()),
-//             method.to_string(),
-//             params.clone(),
-//             headers,
-//         ).await;
-//         let time_array = chrono::Utc::now().timestamp_millis() - start_time;
-//         self.delays.push(time_array);
-//         self.get_delay_info();
-//         let res_data = Self::res_data_analysis(get_response, base_url, params);
-//         res_data
-//     }
-//
-//     pub fn headers(sign: String, timestamp: String, passphrase: String, access_key: String) -> HeaderMap {
-//         let mut headers = HeaderMap::new();
-//         headers.insert("OK-ACCESS-KEY", access_key.parse().unwrap());
-//         headers.insert("OK-ACCESS-SIGN", sign.parse().unwrap());
-//         headers.insert("OK-ACCESS-TIMESTAMP", timestamp.parse().unwrap());
-//         headers.insert("OK-ACCESS-PASSPHRASE", passphrase.parse().unwrap());
-//         headers
-//     }
-//     pub fn sign(secret_key: String,
-//                 method: String, prefix_url: String, request_url: String,
-//                 params: String, body: String, timestamp: String) -> String
-//     {
-//         /*签名生成*/
-//         let url_param_str = RestTool::parse_params_to_str(params);
-//         let base_url = if method == "GET" {
-//             format!("{}{}?{}", prefix_url, request_url, url_param_str)
-//         } else {
-//             format!("{}{}", prefix_url, request_url)
-//         };
-//
-//         // 时间戳 + 请求类型+ 请求参数字符串
-//         let message = format!("{}{}{}{}", timestamp, method, base_url, body);
-//         trace!("message:{}",message);
-//
-//         // 做签名
-//         let hmac_key = ring::hmac::Key::new(hmac::HMAC_SHA256, secret_key.as_bytes());
-//         let result = ring::hmac::sign(&hmac_key, &message.as_bytes());
-//         let sign = base64::encode(result);
-//         sign
-//     }
-//
-//     async fn http_tool(&mut self, request_path: String, request_type: String, params: String, headers: HeaderMap) -> Result<ResponseData, reqwest::Error> {
-//         let res_data: ResponseData;
-//         /****请求接口与 地址*/
-//         let url = format!("{}{}", self.base_url.to_string(), request_path);
-//         let request_type = request_type.clone().to_uppercase();
-//         let addrs_url: String = if RestTool::parse_params_to_str(params.clone()) == "" {
-//             url.clone()
-//         } else {
-//             format!("{}?{}", url.clone(), RestTool::parse_params_to_str(params.clone()))
-//         };
-//         trace!("url:{}", url);
-//         trace!("addrs_url:{}", addrs_url);
-//         let params_json: serde_json::Value = serde_json::from_str(&params).unwrap();
-//         trace!("params_json:{}",params_json);
-//         trace!("headers:{:?}",headers);
-//
-//
-//         let req = match request_type.as_str() {
-//             "GET" => self.client.get(addrs_url.clone()).headers(headers),
-//             "POST" => self.client.post(url.clone()).body(params).headers(headers),
-//             "DELETE" => self.client.delete(addrs_url.clone()).headers(headers),
-//             // "PUT" => self.client.put(url.clone()).json(&params),
-//             _ => return Ok(ResponseData::error(self.label.clone(), format!("错误的请求类型:{}", request_type.clone()))), // 处理未知请求类型
-//         };
-//
-//         let response = req.send().await?;
-//         if response.status().is_success() {
-//             // 读取响应的内容
-//             let body = response.text().await?;
-//             // trace!("ok-----{}", body);
-//             res_data = ResponseData::new(self.label.clone(), "200".to_string(), "success".to_string(), body);
-//         } else {
-//             let body = response.text().await?;
-//             // trace!("error-----{}", body);
-//             res_data = ResponseData::error(self.label.clone(), body.to_string())
-//         }
-//
-//         Ok(res_data)
-//     }
-//
-//
-//     //res_data 解析
-//     pub fn res_data_analysis(result: Result<ResponseData, reqwest::Error>, base_url: String, params: String) -> ResponseData {
-//         // trace!("原始数据:{:?}",result);
-//         match result {
-//             Ok(res_data) => {
-//                 if res_data.code != "200" {
-//                     // trace!("不等于200");
-//                     let message: String = res_data.message;
-//                     let json_value: serde_json::Value = serde_json::from_str(&message).unwrap();
-//                     let code = json_value["code"].as_str().unwrap();
-//                     let msg = json_value["msg"].as_str().unwrap();
-//                     let error = ResponseData::new("".to_string(),
-//                                                   format!("{}", code),
-//                                                   format!("{}", msg),
-//                                                   format!("请求地址:{},请求参数:{}", base_url, params));
-//                     error
-//                 } else {
-//                     // trace!("等于200");
-//                     let body: String = res_data.data;
-//                     let json_value: serde_json::Value = serde_json::from_str(&body).unwrap();
-//
-//                     let code = json_value["code"].as_str().unwrap();
-//                     if code == "0" {
-//                         let data = serde_json::to_string(&json_value["data"]).unwrap();
-//                         let success = ResponseData::new("".to_string(), "200".to_string(), "success".to_string(), data.parse().unwrap());
-//                         success
-//                     } else if code == "1" || code == "0" {
-//                         let msg = json_value["msg"].as_str().unwrap();
-//                         let data = serde_json::to_string(&json_value["data"]).unwrap();
-//
-//                         let data_json: serde_json::Value = serde_json::from_str(&data).unwrap();
-//                         let code_v = data_json[0]["sCode"].as_str().unwrap();
-//                         let msg_v = data_json[0]["sMsg"].as_str().unwrap();
-//                         // trace!("发生错误:??{:?}",data_json.to_string());
-//                         let error = ResponseData::new("".to_string(),
-//                                                       format!("{}", code_v),
-//                                                       format!("{}:{}", msg, msg_v),
-//                                                       format!("请求地址:{},请求参数:{}", base_url, params));
-//                         error
-//                     } else {
-//                         let msg = json_value["msg"].as_str().unwrap();
-//                         // trace!("发生错误:??{:?}",data_json.to_string());
-//                         let error = ResponseData::new("".to_string(),
-//                                                       format!("{}", code),
-//                                                       format!("{}", msg),
-//                                                       format!("请求地址:{},请求参数:{}", base_url, params));
-//                         error
-//                     }
-//                 }
-//             }
-//             Err(err) => {
-//                 let error = ResponseData::error("".to_string(), format!("json 解析失败:{}", err));
-//                 error
-//             }
-//         }
-//     }
-//     fn get_timestamp() -> String {
-//         chrono::Utc::now()
-//             .format("%Y-%m-%dT%H:%M:%S%.3fZ")
-//             .to_string()
-//     }
-// }
+use std::collections::BTreeMap;
+use reqwest::header::HeaderMap;
+use reqwest::{Client};
+use rust_decimal::Decimal;
+use rust_decimal::prelude::FromPrimitive;
+use rust_decimal_macros::dec;
+use tracing::{error, info, trace};
+use crate::http_tool::RestTool;
+use crate::response_base::ResponseData;
+use ring::hmac;
+use serde_json::Value;
+
+#[derive(Clone, Debug)]
+pub struct OkxSwapRest {
+    pub tag: String,
+    base_url: String,
+    client: reqwest::Client,
+    /*******参数*/
+    //是否需要登录
+    //登录所需参数
+    login_param: BTreeMap<String, String>,
+    delays: Vec<i64>,
+    max_delay: i64,
+    avg_delay: Decimal,
+
+}
+
+impl OkxSwapRest {
+    /*******************************************************************************************************/
+    /*****************************************获取一个对象****************************************************/
+    /*******************************************************************************************************/
+
+    pub fn new(is_colo: bool, login_param: BTreeMap<String, String>) -> OkxSwapRest
+    {
+        return OkxSwapRest::new_with_tag("default-OkxSwapRest".to_string(), is_colo, login_param);
+    }
+    pub fn new_with_tag(tag: String, is_colo: bool, login_param: BTreeMap<String, String>) -> OkxSwapRest {
+        let base_url = if is_colo {
+            "https://www.okx.com".to_string()
+        } else {
+            "https://www.okx.com".to_string()
+        };
+
+        if is_colo {
+            info!("开启高速(未配置,走普通:{})通道",base_url);
+        } else {
+            info!("走普通通道:{}",base_url);
+        }
+        /*****返回结构体*******/
+        OkxSwapRest {
+            tag,
+            base_url,
+            client: Client::new(),
+            login_param,
+            delays: vec![],
+            max_delay: 0,
+            avg_delay: dec!(0.0),
+        }
+    }
+
+    /*******************************************************************************************************/
+    /*****************************************rest请求函数********************************************************/
+    /*******************************************************************************************************/
+    //获取合约信息
+    pub async fn get_market(&mut self, params: Value) -> ResponseData {
+        let data = self.request("GET".to_string(),
+                                "/api/v5".to_string(),
+                                "/public/instruments".to_string(),
+                                false,
+                                params,
+        ).await;
+        data
+    }
+
+    /*******************************************************************************************************/
+    /*****************************************工具函数********************************************************/
+    /*******************************************************************************************************/
+    pub fn get_delays(&self) -> Vec<i64> {
+        self.delays.clone()
+    }
+    pub fn get_avg_delay(&self) -> Decimal {
+        self.avg_delay.clone()
+    }
+    pub fn get_max_delay(&self) -> i64 {
+        self.max_delay.clone()
+    }
+    fn get_delay_info(&mut self) {
+        let last_100 = if self.delays.len() > 100 {
+            self.delays[self.delays.len() - 100..].to_vec()
+        } else {
+            self.delays.clone()
+        };
+
+        let max_value = last_100.iter().max().unwrap();
+        if max_value.clone().to_owned() > self.max_delay {
+            self.max_delay = max_value.clone().to_owned();
+        }
+
+        let sum: i64 = last_100.iter().sum();
+        let sum_v = Decimal::from_i64(sum).unwrap();
+        let len_v = Decimal::from_u64(last_100.len() as u64).unwrap();
+        self.avg_delay = (sum_v / len_v).round_dp(1);
+        self.delays = last_100.clone().into_iter().collect();
+    }
+    //调用请求
+    pub async fn request(&mut self,
+                         method: String,
+                         prefix_url: String,
+                         request_url: String,
+                         is_login: bool,
+                         params: Value) -> ResponseData
+    {
+        trace!("login_param:{:?}", self.login_param);
+        //解析账号信息
+        let mut access_key = "".to_string();
+        let mut secret_key = "".to_string();
+        let mut passphrase = "".to_string();
+        if self.login_param.contains_key("access_key") {
+            access_key = self.login_param.get("access_key").unwrap().to_string();
+        }
+        if self.login_param.contains_key("secret_key") {
+            secret_key = self.login_param.get("secret_key").unwrap().to_string();
+        }
+        if self.login_param.contains_key("pass_key") {
+            passphrase = self.login_param.get("pass_key").unwrap().to_string();
+        }
+        let mut is_login_param = true;
+        if access_key == "" || secret_key == "" || passphrase == "" {
+            is_login_param = false
+        }
+
+        //请求类型不同,可能请求头body 不同
+        let mut body = "{}".to_string();
+        let mut headers = HeaderMap::new();
+        if method == "POST" {
+            headers.insert("Content-Type", "application/json".parse().unwrap());
+            body = params.to_string();
+        }
+
+        //是否需要登录-- 组装sing
+        if is_login {
+            if !is_login_param {
+                let e = ResponseData::error(self.tag.clone(), "登录参数错误!".to_string());
+                return e;
+            } else {
+                // //需要登录-且登录参数齐全
+                // trace!("param:{}", params);
+                // trace!("body:{}", body);
+                // //组装sing
+                // let sing = Self::sign(secret_key.clone(),
+                //                       method.clone(),
+                //                       prefix_url.clone(),
+                //                       request_url.clone(),
+                //                       params.clone(),
+                //                       body.clone(),
+                //                       timestamp.clone(),
+                // );
+                // //组装header
+                // headers.extend(Self::headers(sing, timestamp, passphrase, access_key));
+            }
+        }
+
+
+        // trace!("headers:{:?}", headers);
+        // let base_url = format!("{}{}", prefix_url.clone(), request_url.clone());
+        let start_time = chrono::Utc::now().timestamp_millis();
+        let response = self.http_tool(
+            format!("{}{}", prefix_url.clone(), request_url.clone()),
+            method.to_string(),
+            params.to_string(),
+            body,
+            headers,
+        ).await;
+
+        let time_array = chrono::Utc::now().timestamp_millis() - start_time;
+        self.delays.push(time_array);
+        self.get_delay_info();
+
+        response
+        //
+        // let time_array = chrono::Utc::now().timestamp_millis() - start_time;
+        // self.delays.push(time_array);
+        // self.get_delay_info();
+        // let res_data = Self::res_data_analysis(get_response, base_url, params.to_string());
+        // res_data
+    }
+
+    // pub fn headers(_: String, _timestamp: String, passphrase: String, access_key: String) -> HeaderMap {
+    //     let mut headers = HeaderMap::new();
+    //     // headers.insert("OK-ACCESS-KEY", access_key.parse().unwrap());
+    //     // headers.insert("OK-ACCESS-SIGN", sign.parse().unwrap());
+    //     // headers.insert("OK-ACCESS-TIMESTAMP", timestamp.parse().unwrap());
+    //     // headers.insert("OK-ACCESS-PASSPHRASE", passphrase.parse().unwrap());
+    //     headers
+    // }
+    pub fn sign(secret_key: String,
+                method: String, prefix_url: String, request_url: String,
+                params: String, body: String, timestamp: String) -> String
+    {
+        /*签名生成*/
+        let url_param_str = RestTool::parse_params_to_str(params);
+        let base_url = if method == "GET" {
+            format!("{}{}?{}", prefix_url, request_url, url_param_str)
+        } else {
+            format!("{}{}", prefix_url, request_url)
+        };
+
+        // 时间戳 + 请求类型+ 请求参数字符串
+        let message = format!("{}{}{}{}", timestamp, method, base_url, body);
+        trace!("message:{}",message);
+
+        // 做签名
+        let hmac_key = ring::hmac::Key::new(hmac::HMAC_SHA256, secret_key.as_bytes());
+        let result = ring::hmac::sign(&hmac_key, &message.as_bytes());
+        let sign = base64::encode(result);
+        sign
+    }
+
+    // async fn http_tool(&mut self, request_path: String, request_type: String, params: String, headers: HeaderMap) -> Result<ResponseData, reqwest::Error> {
+    async fn http_tool(&mut self, request_path: String,
+                       request_type: String,
+                       params: String,
+                       body: String,
+                       headers: HeaderMap) -> ResponseData {
+        /****请求接口与 地址*/
+        let url = format!("{}{}", self.base_url.to_string(), request_path);
+        let request_type = request_type.clone().to_uppercase();
+
+        let addrs_url: String = if RestTool::parse_params_to_str(params.clone()) == "" {
+            url.clone()
+        } else {
+            format!("{}?{}", url.clone(), RestTool::parse_params_to_str(params.clone()))
+        };
+
+        trace!("url-----:???{}",url.clone());
+        trace!("addrs_url-----:???{}",addrs_url.clone());
+        trace!("params-----:???{}",params.clone());
+        trace!("body-----:???{}",body.clone());
+
+        let request_builder = match request_type.as_str() {
+            "GET" => self.client.get(addrs_url.clone()).headers(headers),
+            "POST" => self.client.post(url.clone()).body(body).headers(headers),
+            // "DELETE" => self.client.delete(addrs_url.clone()).headers(headers),
+            // "PUT" => self.client.put(url.clone()).json(&params),
+            _ => {
+                panic!("{}", format!("错误的请求类型:{}", request_type.clone()))
+            }
+        };
+
+        // 读取响应的内容
+        let response = request_builder.send().await.unwrap();
+        let is_success = response.status().is_success(); // 先检查状态码
+        let text = response.text().await.unwrap();
+        trace!("text:???{:?}",text);
+        return if is_success {
+            self.on_success_data(&text)
+        } else {
+            self.on_error_data(&text, &addrs_url, &params)
+        };
+    }
+    pub fn on_success_data(&mut self, text: &String) -> ResponseData {
+        let json_value = serde_json::from_str::<Value>(&text).unwrap();
+        // return  ResponseData::new(self.tag.clone(), 200, "success".to_string(), json_value)
+        let code = json_value["code"].as_str().unwrap();
+        match code {
+            "0" => {
+                //判断是否有code ,没有表示特殊接口,直接返回
+                if json_value.get("data").is_some() {
+                    let data = json_value.get("data").unwrap();
+                    ResponseData::new(self.tag.clone(), 200, "success".to_string(), data.clone())
+                } else {
+                    ResponseData::new(self.tag.clone(), 200, "success".to_string(), json_value)
+                }
+            }
+            _ => {
+                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 {
+        let json_value = serde_json::from_str::<Value>(&text);
+        match json_value {
+            Ok(data) => {
+                let message;
+
+                if !data["message"].is_null() {
+                    message = format!("{}:{}", data["tag"].as_str().unwrap(), data["message"].as_str().unwrap());
+                } else {
+                    message = data["tag"].to_string();
+                }
+
+                let mut error = ResponseData::error(self.tag.clone(), message);
+                error.message = format!("请求地址:{}, 请求参数:{}, 报错内容:{}。", base_url, params, error.message);
+                error
+            }
+            Err(e) => {
+                error!("解析错误:{:?}", e);
+                let error = ResponseData::error("".to_string(),
+                                                format!("json 解析失败:{},相关参数:{}", e, text));
+                error
+            }
+        }
+    }
+}

+ 314 - 0
exchanges/src/phemex_swap_rest.rs

@@ -0,0 +1,314 @@
+use std::collections::BTreeMap;
+use chrono::Utc;
+use reqwest::header::HeaderMap;
+use reqwest::{Client};
+use rust_decimal::Decimal;
+use rust_decimal::prelude::FromPrimitive;
+use rust_decimal_macros::dec;
+use tracing::{error, info, trace};
+use crate::http_tool::RestTool;
+use crate::response_base::ResponseData;
+use ring::hmac;
+use serde_json::Value;
+
+#[derive(Clone, Debug)]
+pub struct PhemexSwapRest {
+    pub tag: String,
+    base_url: String,
+    client: reqwest::Client,
+    /*******参数*/
+    //是否需要登录
+    //登录所需参数
+    login_param: BTreeMap<String, String>,
+    delays: Vec<i64>,
+    max_delay: i64,
+    avg_delay: Decimal,
+
+}
+
+impl PhemexSwapRest {
+    /*******************************************************************************************************/
+    /*****************************************获取一个对象****************************************************/
+    /*******************************************************************************************************/
+
+    pub fn new(is_colo: bool, login_param: BTreeMap<String, String>) -> PhemexSwapRest
+    {
+        return PhemexSwapRest::new_with_tag("default-PhemexSwapRest".to_string(), is_colo, login_param);
+    }
+    pub fn new_with_tag(tag: String, is_colo: bool, login_param: BTreeMap<String, String>) -> PhemexSwapRest {
+        let base_url = if is_colo {
+            "https://api.phemex.com".to_string()
+        } else {
+            "https://api.phemex.com".to_string()
+        };
+
+        if is_colo {
+            info!("开启高速(未配置,走普通:{})通道",base_url);
+        } else {
+            info!("走普通通道:{}",base_url);
+        }
+        /*****返回结构体*******/
+        PhemexSwapRest {
+            tag,
+            base_url,
+            client: Client::new(),
+            login_param,
+            delays: vec![],
+            max_delay: 0,
+            avg_delay: dec!(0.0),
+        }
+    }
+
+    /*******************************************************************************************************/
+    /*****************************************rest请求函数********************************************************/
+    /*******************************************************************************************************/
+    //查詢合約基礎信息
+    pub async fn get_market(&mut self, params: Value) -> ResponseData {
+        let data = self.request("GET".to_string(),
+                                "".to_string(),
+                                "/public/products".to_string(),
+                                false,
+                                params,
+        ).await;
+        data
+    }
+
+    /*******************************************************************************************************/
+    /*****************************************工具函数********************************************************/
+    /*******************************************************************************************************/
+    pub fn get_delays(&self) -> Vec<i64> {
+        self.delays.clone()
+    }
+    pub fn get_avg_delay(&self) -> Decimal {
+        self.avg_delay.clone()
+    }
+    pub fn get_max_delay(&self) -> i64 {
+        self.max_delay.clone()
+    }
+    fn get_delay_info(&mut self) {
+        let last_100 = if self.delays.len() > 100 {
+            self.delays[self.delays.len() - 100..].to_vec()
+        } else {
+            self.delays.clone()
+        };
+
+        let max_value = last_100.iter().max().unwrap();
+        if max_value.clone().to_owned() > self.max_delay {
+            self.max_delay = max_value.clone().to_owned();
+        }
+
+        let sum: i64 = last_100.iter().sum();
+        let sum_v = Decimal::from_i64(sum).unwrap();
+        let len_v = Decimal::from_u64(last_100.len() as u64).unwrap();
+        self.avg_delay = (sum_v / len_v).round_dp(1);
+        self.delays = last_100.clone().into_iter().collect();
+    }
+    //调用请求
+    pub async fn request(&mut self,
+                         method: String,
+                         prefix_url: String,
+                         request_url: String,
+                         is_login: bool,
+                         mut  params: Value) -> ResponseData
+    {
+        trace!("login_param:{:?}", self.login_param);
+        //解析账号信息
+        let mut access_key = "".to_string();
+        let mut secret_key = "".to_string();
+        let mut passphrase = "".to_string();
+        if self.login_param.contains_key("access_key") {
+            access_key = self.login_param.get("access_key").unwrap().to_string();
+        }
+        if self.login_param.contains_key("secret_key") {
+            secret_key = self.login_param.get("secret_key").unwrap().to_string();
+        }
+        if self.login_param.contains_key("pass_key") {
+            passphrase = self.login_param.get("pass_key").unwrap().to_string();
+        }
+        let mut is_login_param = true;
+        if access_key == "" || secret_key == "" || passphrase == "" {
+            is_login_param = false
+        }
+
+        //每个接口都有的参数
+        let timestamp = Utc::now().timestamp_millis();
+        let recv_window = 3000;
+        params["timestamp"] = serde_json::json!(timestamp);
+        params["recvWindow"] = serde_json::json!(recv_window);
+
+
+        //请求类型不同,可能请求头body 不同
+        let mut body = "{}".to_string();
+        let mut headers = HeaderMap::new();
+        if method == "POST" {
+            headers.insert("Content-Type", "application/x-www-form-urlencoded".parse().unwrap());
+            body = params.to_string();
+        }
+
+        //是否需要登录-- 组装sing
+        if is_login {
+            if !is_login_param {
+                let e = ResponseData::error(self.tag.clone(), "登录参数错误!".to_string());
+                return e;
+            } else {
+                // //需要登录-且登录参数齐全
+                // trace!("param:{}", params);
+                // trace!("body:{}", body);
+                // //组装sing
+                // let sing = Self::sign(secret_key.clone(),
+                //                       method.clone(),
+                //                       prefix_url.clone(),
+                //                       request_url.clone(),
+                //                       params.clone(),
+                //                       body.clone(),
+                //                       timestamp.clone(),
+                // );
+                // //组装header
+                // headers.extend(Self::headers(sing, timestamp, passphrase, access_key));
+            }
+        }
+
+
+        // trace!("headers:{:?}", headers);
+        // let base_url = format!("{}{}", prefix_url.clone(), request_url.clone());
+        let start_time = chrono::Utc::now().timestamp_millis();
+        let response = self.http_tool(
+            format!("{}{}", prefix_url.clone(), request_url.clone()),
+            method.to_string(),
+            params.to_string(),
+            body,
+            headers,
+        ).await;
+
+        let time_array = chrono::Utc::now().timestamp_millis() - start_time;
+        self.delays.push(time_array);
+        self.get_delay_info();
+
+        response
+        //
+        // let time_array = chrono::Utc::now().timestamp_millis() - start_time;
+        // self.delays.push(time_array);
+        // self.get_delay_info();
+        // let res_data = Self::res_data_analysis(get_response, base_url, params.to_string());
+        // res_data
+    }
+
+    // pub fn headers(_: String, _timestamp: String, passphrase: String, access_key: String) -> HeaderMap {
+    //     let mut headers = HeaderMap::new();
+    //     // headers.insert("OK-ACCESS-KEY", access_key.parse().unwrap());
+    //     // headers.insert("OK-ACCESS-SIGN", sign.parse().unwrap());
+    //     // headers.insert("OK-ACCESS-TIMESTAMP", timestamp.parse().unwrap());
+    //     // headers.insert("OK-ACCESS-PASSPHRASE", passphrase.parse().unwrap());
+    //     headers
+    // }
+    pub fn sign(secret_key: String,
+                method: String, prefix_url: String, request_url: String,
+                params: String, body: String, timestamp: String) -> String
+    {
+        /*签名生成*/
+        let url_param_str = RestTool::parse_params_to_str(params);
+        let base_url = if method == "GET" {
+            format!("{}{}?{}", prefix_url, request_url, url_param_str)
+        } else {
+            format!("{}{}", prefix_url, request_url)
+        };
+
+        // 时间戳 + 请求类型+ 请求参数字符串
+        let message = format!("{}{}{}{}", timestamp, method, base_url, body);
+        trace!("message:{}",message);
+
+        // 做签名
+        let hmac_key = ring::hmac::Key::new(hmac::HMAC_SHA256, secret_key.as_bytes());
+        let result = ring::hmac::sign(&hmac_key, &message.as_bytes());
+        let sign = base64::encode(result);
+        sign
+    }
+
+    // async fn http_tool(&mut self, request_path: String, request_type: String, params: String, headers: HeaderMap) -> Result<ResponseData, reqwest::Error> {
+    async fn http_tool(&mut self, request_path: String,
+                       request_type: String,
+                       params: String,
+                       body: String,
+                       headers: HeaderMap) -> ResponseData {
+        /****请求接口与 地址*/
+        let url = format!("{}{}", self.base_url.to_string(), request_path);
+        let request_type = request_type.clone().to_uppercase();
+        let addrs_url: String = if RestTool::parse_params_to_str(params.clone()) == "" {
+            url.clone()
+        } else {
+            format!("{}?{}", url.clone(), RestTool::parse_params_to_str(params.clone()))
+        };
+
+        trace!("url-----:???{}",url.clone());
+        trace!("addrs_url-----:???{}",addrs_url.clone());
+        trace!("params-----:???{}",params.clone());
+        trace!("body-----:???{}",body.clone());
+
+        let request_builder = match request_type.as_str() {
+            "GET" => self.client.get(addrs_url.clone()).headers(headers),
+            "POST" => self.client.post(url.clone()).body(body).headers(headers),
+            // "DELETE" => self.client.delete(addrs_url.clone()).headers(headers),
+            // "PUT" => self.client.put(url.clone()).json(&params),
+            _ => {
+                panic!("{}", format!("错误的请求类型:{}", request_type.clone()))
+            }
+        };
+
+        // 读取响应的内容
+        let response = request_builder.send().await.unwrap();
+        let is_success = response.status().is_success(); // 先检查状态码
+        let text = response.text().await.unwrap();
+        // trace!("text:???{:?}",text);
+        return if is_success {
+            self.on_success_data(&text)
+        } else {
+            self.on_error_data(&text, &addrs_url, &params)
+        };
+    }
+    pub fn on_success_data(&mut self, text: &String) -> ResponseData {
+        let json_value = serde_json::from_str::<Value>(&text).unwrap();
+        // return  ResponseData::new(self.tag.clone(), 200, "success".to_string(), json_value);
+
+        let code = json_value["code"].as_i64().unwrap();
+        match code {
+            0 => {
+                //判断是否有code ,没有表示特殊接口,直接返回
+                if json_value.get("data").is_some() {
+                    let data = json_value.get("data").unwrap();
+                    ResponseData::new(self.tag.clone(), 200, "success".to_string(), data.clone())
+                } else {
+                    ResponseData::new(self.tag.clone(), 200, "success".to_string(), json_value)
+                }
+            }
+            _ => {
+                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 {
+        let json_value = serde_json::from_str::<Value>(&text);
+
+        match json_value {
+            Ok(data) => {
+                let message;
+
+                if !data["message"].is_null() {
+                    message = format!("{}:{}", data["tag"].as_str().unwrap(), data["message"].as_str().unwrap());
+                } else {
+                    message = data["tag"].to_string();
+                }
+
+                let mut error = ResponseData::error(self.tag.clone(), message);
+                error.message = format!("请求地址:{}, 请求参数:{}, 报错内容:{}。", base_url, params, error.message);
+                error
+            }
+            Err(e) => {
+                error!("解析错误:{:?}", e);
+                let error = ResponseData::error("".to_string(),
+                                                format!("json 解析失败:{},相关参数:{}", e, text));
+                error
+            }
+        }
+    }
+}

+ 339 - 0
exchanges/src/phemex_swap_ws.rs

@@ -0,0 +1,339 @@
+use std::io::Read;
+use std::sync::Arc;
+use std::sync::atomic::AtomicBool;
+use std::time::Duration;
+
+use flate2::read::GzDecoder;
+use futures_channel::mpsc::{UnboundedReceiver, UnboundedSender};
+use serde_json::json;
+use serde_json::Value;
+use tokio::sync::Mutex;
+use tokio_tungstenite::tungstenite::{Error, Message};
+use tracing::{error, info, trace};
+
+use crate::response_base::ResponseData;
+use crate::socket_tool::{AbstractWsMode, HeartbeatType};
+
+//类型
+pub enum PhemexSwapWsType {
+    PublicAndPrivate,
+}
+
+
+#[derive(Debug)]
+#[derive(Clone)]
+pub struct PhemexSwapWsParam {
+    pub token: String,
+    pub ws_url: String,
+    pub ws_ping_interval: i64,
+    pub ws_ping_timeout: i64,
+    pub is_ok_subscribe: bool,
+}
+
+//订阅频道
+#[derive(Clone)]
+pub enum PhemexSwapSubscribeType {
+    // 订单
+    PuFuturesOrderBook,
+    // 公开成交
+    PuFuturesTrades,
+    // K线数据
+    PuFuturesRecords,
+}
+
+//账号信息
+#[derive(Clone, Debug)]
+pub struct PhemexSwapLogin {
+    pub access_key: String,
+    pub secret_key: String,
+    pub pass_key: String,
+}
+
+#[derive(Clone)]
+#[allow(dead_code)]
+pub struct PhemexSwapWs {
+    //类型
+    tag: String,
+    //地址
+    address_url: String,
+    //账号
+    login_param: Option<PhemexSwapLogin>,
+    //登录数据
+    ws_param: PhemexSwapWsParam,
+    //币对
+    symbol_s: Vec<String>,
+    //订阅
+    subscribe_types: Vec<PhemexSwapSubscribeType>,
+    //心跳间隔
+    heartbeat_time: u64,
+}
+
+impl PhemexSwapWs {
+    /*******************************************************************************************************/
+    /*****************************************获取一个对象****************************************************/
+    /*******************************************************************************************************/
+    pub fn new(is_colo: bool, login_param: Option<PhemexSwapLogin>, ws_type: PhemexSwapWsType) -> PhemexSwapWs {
+        return Self::new_with_tag("default-PhemexSwapWs".to_string(), is_colo, login_param, ws_type);
+    }
+    pub fn new_with_tag(tag: String, is_colo: bool, login_param: Option<PhemexSwapLogin>, ws_type: PhemexSwapWsType) -> PhemexSwapWs {
+        /*******公共频道-私有频道数据组装*/
+        let address_url = match ws_type {
+            PhemexSwapWsType::PublicAndPrivate => {
+                let url = "wss://ws.phemex.com".to_string();
+                info!("走普通通道(不支持colo通道):{}", url);
+                url
+            }
+        };
+
+        /*******公共频道-私有频道数据组装*/
+        let ws_param = PhemexSwapWsParam {
+            token: "".to_string(),
+            ws_url: "".to_string(),
+            ws_ping_interval: 15 * 1000,
+            ws_ping_timeout: 0,
+            is_ok_subscribe: false,
+        };
+
+        if is_colo {
+            info!("开启高速(未配置,走普通:{})通道",address_url);
+        } else {
+            info!("走普通通道:{}",address_url);
+        }
+
+        PhemexSwapWs {
+            tag,
+            address_url,
+            login_param,
+            ws_param,
+            symbol_s: vec![],
+            subscribe_types: vec![],
+            heartbeat_time: 1000 * 18,
+        }
+    }
+
+    /*******************************************************************************************************/
+    /*****************************************订阅函数********************************************************/
+    /*******************************************************************************************************/
+    //手动添加订阅信息
+    pub fn set_subscribe(&mut self, subscribe_types: Vec<PhemexSwapSubscribeType>) {
+        self.subscribe_types.extend(subscribe_types);
+    }
+    //手动添加币对
+    pub fn set_symbols(&mut self, mut b_array: Vec<String>) {
+        for symbol in b_array.iter_mut() {
+            // 大写
+            *symbol = symbol.to_string();
+            // 字符串替换
+            *symbol = symbol.replace("_", "-");
+        }
+        self.symbol_s = b_array;
+    }
+    fn contains_pr(&self) -> bool {
+        for t in self.subscribe_types.clone() {
+            if match t {
+                PhemexSwapSubscribeType::PuFuturesTrades => false,
+                PhemexSwapSubscribeType::PuFuturesRecords => false,
+                PhemexSwapSubscribeType::PuFuturesOrderBook => false,
+            } {
+                return true;
+            }
+        }
+        false
+    }
+    /*******************************************************************************************************/
+    /*****************************************工具函数********************************************************/
+    /*******************************************************************************************************/
+    //订阅枚举解析
+    pub fn enum_to_string(symbol: String, subscribe_type: PhemexSwapSubscribeType) -> Value {
+        match subscribe_type {
+            PhemexSwapSubscribeType::PuFuturesOrderBook => {
+                // format!("{}@depth5@100ms", symbol)
+                json!({
+                    "id": 999,
+                    "method": "orderbook_p.subscribe",
+                    "params": [
+                        symbol,
+                    ]
+                })
+            }
+            PhemexSwapSubscribeType::PuFuturesRecords => {
+                // format!("{}@kline_1m", symbol)
+                json!({
+                    "id": 999,
+                    "method": "kline_p.subscribe",
+                    "params": [
+                        symbol,
+                        60
+                    ]
+                })
+            }
+            PhemexSwapSubscribeType::PuFuturesTrades => {
+                json!({
+                    "id": 999,
+                    "method": "trade_p.subscribe",
+                    "params": [
+                        symbol
+                    ]
+                })
+            }
+        }
+    }
+    //订阅信息生成
+    pub fn get_subscription(&self) -> Vec<String> {
+        let mut array = vec![];
+        for symbol in &self.symbol_s {
+            for subscribe_type in &self.subscribe_types {
+                let ty_str = Self::enum_to_string(symbol.clone(), subscribe_type.clone());
+                array.push(ty_str.to_string());
+            }
+        }
+        array
+    }
+    /*******************************************************************************************************/
+    /*****************************************socket基本*****************************************************/
+    /*******************************************************************************************************/
+    //链接
+    pub async fn ws_connect_async<F, Future>(&mut self,
+                                             is_shutdown_arc: Arc<AtomicBool>,
+                                             handle_function: F,
+                                             write_tx_am: &Arc<Mutex<UnboundedSender<Message>>>,
+                                             write_to_socket_rx: UnboundedReceiver<Message>) -> Result<(), Error>
+        where
+            F: Fn(ResponseData) -> Future + Clone + Send + 'static + Sync,
+            Future: std::future::Future<Output=()> + Send + 'static, // 确保 Fut 是一个 Future,且输出类型为 ()
+    {
+        let login_is = self.contains_pr();
+        let subscription = self.get_subscription();
+        let address_url = self.address_url.clone();
+        let tag = self.tag.clone();
+        let heartbeat_time = self.ws_param.ws_ping_interval.clone();
+
+        // 心跳-- 方法内部线程启动
+        let write_tx_clone1 = write_tx_am.clone();
+        tokio::spawn(async move {
+            trace!("线程-异步心跳-开始");
+            let info = json!({
+                "id": 0,
+                "method": "server.ping",
+                "params": []
+            });
+            AbstractWsMode::ping_or_pong(write_tx_clone1, HeartbeatType::Custom(info.to_string()), heartbeat_time as u64).await;
+            trace!("线程-异步心跳-结束");
+        });
+
+
+        //设置订阅
+        let subscribe_array = subscription.clone();
+        if login_is {
+            //登录相关
+        }
+
+        //1 链接
+        let t2 = tokio::spawn(async move {
+            let write_to_socket_rx_arc = Arc::new(Mutex::new(write_to_socket_rx));
+
+            loop {
+                info!("Phemex_usdt_swap socket 连接中……");
+                AbstractWsMode::ws_connect_async(is_shutdown_arc.clone(), handle_function.clone(), address_url.clone(),
+                                                 false, tag.clone(), subscribe_array.clone(), write_to_socket_rx_arc.clone(),
+                                                 Self::message_text, Self::message_ping, Self::message_pong, Self::message_binary).await;
+
+                error!("Phemex_usdt_swap socket 断连,1s以后重连……");
+                tokio::time::sleep(Duration::from_secs(1)).await;
+            }
+        });
+
+        tokio::try_join!(t2).unwrap();
+        trace!("线程-心跳与链接-结束");
+
+        Ok(())
+    }
+    /*******************************************************************************************************/
+    /*****************************************数据解析*****************************************************/
+    /*******************************************************************************************************/
+    //数据解析-Text
+    pub fn message_text(text: String) -> Option<ResponseData> {
+        let response_data = Self::ok_text(text);
+        Option::from(response_data)
+    }
+    //数据解析-ping
+    pub fn message_ping(_pi: Vec<u8>) -> Option<ResponseData> {
+        return Option::from(ResponseData::new("".to_string(), -300, "success".to_string(), Value::Null));
+    }
+    //数据解析-pong
+    pub fn message_pong(_po: Vec<u8>) -> Option<ResponseData> {
+        return Option::from(ResponseData::new("".to_string(), -301, "success".to_string(), Value::Null));
+    }
+    //数据解析-二进制
+    pub fn message_binary(po: Vec<u8>) -> Option<ResponseData> {
+        //二进制WebSocket消息
+        // let message_str = format!("Binary:{:?}", _po);
+        // Option::from(ResponseData::new("".to_string(), 2, message_str, Value::Null))
+        // let result = String::from_utf8(bytes);
+        // let result = String::from_utf8(po);
+
+        let mut gz_decoder = GzDecoder::new(&po[..]);
+        let mut decompressed_data = Vec::new();
+
+        // 尝试解压数据
+        if let Ok(_) = gz_decoder.read_to_end(&mut decompressed_data) {
+            // 将解压后的字节向量转换为 UTF-8 字符串
+            match String::from_utf8(decompressed_data) {
+                Ok(text) => {
+                    let response_data = Self::ok_text(text);
+                    return Option::from(response_data);
+                }
+                Err(_) => {
+                    return Option::from(ResponseData::new("".to_string(), 400, "二进制数据转化出错".to_string(), Value::Null));
+                }
+            }
+        } else {
+            return Option::from(ResponseData::new("".to_string(), 400, "二进制数据转化出错".to_string(), Value::Null));
+        }
+    }
+    //数据解析
+    pub fn ok_text(text: String) -> ResponseData
+    {
+        // trace!("原始数据:{:?}",text);
+
+        let mut res_data = ResponseData::new("".to_string(), 200, "success".to_string(), Value::Null);
+        let json_value: serde_json::Value = serde_json::from_str(&text).unwrap();
+
+        // { "id": "id1", "code": 0, "msg": "" }
+        if json_value["id"].as_i64() == Option::from(0) {
+            //订阅
+            if json_value["result"].as_str() == Option::from("pong") {
+                res_data.code = -301;
+                res_data.message = "Pong".to_string();
+            }
+        } else if json_value["id"].as_i64() == Option::from(999) {
+            //订阅
+            if json_value["result"]["status"].as_str() == Option::from("success") {
+                res_data.code = -201;
+                res_data.message = "订阅成功".to_string();
+            } else {
+                res_data.code = 400;
+                res_data.message = "订阅失败".to_string();
+            }
+        } else if json_value["type"].as_str() == Option::from("incremental") {
+            if !json_value["kline_p"].is_null() {
+                res_data.code = 200;
+                res_data.data = json_value.clone();
+                res_data.channel = "futures.candlesticks".to_string();
+            } else if !json_value["trades_p"].is_null() {
+                res_data.code = 200;
+                res_data.data = json_value.clone();
+                res_data.channel = "futures.trades".to_string();
+            } else if !json_value["orderbook_p"].is_null() {
+                res_data.code = 200;
+                res_data.data = json_value.clone();
+                res_data.channel = "futures.order_book".to_string();
+            }
+        } else {
+            res_data.code = -1;
+            res_data.message = "未知解析".to_string();
+        }
+
+        res_data
+    }
+}

+ 305 - 0
exchanges/src/woo_swap_rest.rs

@@ -0,0 +1,305 @@
+use std::collections::BTreeMap;
+// use chrono::Utc;
+use reqwest::header::HeaderMap;
+use reqwest::{Client};
+use rust_decimal::Decimal;
+use rust_decimal::prelude::FromPrimitive;
+use rust_decimal_macros::dec;
+use tracing::{error, info, trace};
+use crate::http_tool::RestTool;
+use crate::response_base::ResponseData;
+use ring::hmac;
+use serde_json::{json, Value};
+
+#[derive(Clone, Debug)]
+pub struct WooSwapRest {
+    pub tag: String,
+    base_url: String,
+    client: reqwest::Client,
+    /*******参数*/
+    //是否需要登录
+    //登录所需参数
+    login_param: BTreeMap<String, String>,
+    delays: Vec<i64>,
+    max_delay: i64,
+    avg_delay: Decimal,
+
+}
+
+impl WooSwapRest {
+    /*******************************************************************************************************/
+    /*****************************************获取一个对象****************************************************/
+    /*******************************************************************************************************/
+
+    pub fn new(is_colo: bool, login_param: BTreeMap<String, String>) -> WooSwapRest
+    {
+        return WooSwapRest::new_with_tag("default-WooSwapRest".to_string(), is_colo, login_param);
+    }
+    pub fn new_with_tag(tag: String, is_colo: bool, login_param: BTreeMap<String, String>) -> WooSwapRest {
+        let base_url = if is_colo {
+            "https://api.woo.org".to_string()
+        } else {
+            "https://api.woo.org".to_string()
+        };
+
+        if is_colo {
+            info!("开启高速(未配置,走普通:{})通道",base_url);
+        } else {
+            info!("走普通通道:{}",base_url);
+        }
+        /*****返回结构体*******/
+        WooSwapRest {
+            tag,
+            base_url,
+            client: Client::new(),
+            login_param,
+            delays: vec![],
+            max_delay: 0,
+            avg_delay: dec!(0.0),
+        }
+    }
+
+    /*******************************************************************************************************/
+    /*****************************************rest请求函数********************************************************/
+    /*******************************************************************************************************/
+    //查询服务器时间是(获取系统维护状态(公共))
+    pub async fn get_server_time(&mut self) -> ResponseData {
+        let params = json!({});
+        let data = self.request("GET".to_string(),
+                                "/v1".to_string(),
+                                "/public/system_info".to_string(),
+                                false,
+                                params,
+        ).await;
+        data
+    }
+    //获取合约信息(获取所有市场的期货信息(公开))
+    pub async fn get_market(&mut self,params:Value) -> ResponseData {
+        let data = self.request("GET".to_string(),
+                                "/v1".to_string(),
+                                "/public/info".to_string(),
+                                false,
+                                params,
+        ).await;
+        data
+    }
+
+    /*******************************************************************************************************/
+    /*****************************************工具函数********************************************************/
+    /*******************************************************************************************************/
+    pub fn get_delays(&self) -> Vec<i64> {
+        self.delays.clone()
+    }
+    pub fn get_avg_delay(&self) -> Decimal {
+        self.avg_delay.clone()
+    }
+    pub fn get_max_delay(&self) -> i64 {
+        self.max_delay.clone()
+    }
+    fn get_delay_info(&mut self) {
+        let last_100 = if self.delays.len() > 100 {
+            self.delays[self.delays.len() - 100..].to_vec()
+        } else {
+            self.delays.clone()
+        };
+
+        let max_value = last_100.iter().max().unwrap();
+        if max_value.clone().to_owned() > self.max_delay {
+            self.max_delay = max_value.clone().to_owned();
+        }
+
+        let sum: i64 = last_100.iter().sum();
+        let sum_v = Decimal::from_i64(sum).unwrap();
+        let len_v = Decimal::from_u64(last_100.len() as u64).unwrap();
+        self.avg_delay = (sum_v / len_v).round_dp(1);
+        self.delays = last_100.clone().into_iter().collect();
+    }
+    //调用请求
+    pub async fn request(&mut self,
+                         method: String,
+                         prefix_url: String,
+                         request_url: String,
+                         is_login: bool,
+                         params: Value) -> ResponseData
+    {
+        trace!("login_param:{:?}", self.login_param);
+        //解析账号信息
+        let mut access_key = "".to_string();
+        let mut secret_key = "".to_string();
+        let mut passphrase = "".to_string();
+        if self.login_param.contains_key("access_key") {
+            access_key = self.login_param.get("access_key").unwrap().to_string();
+        }
+        if self.login_param.contains_key("secret_key") {
+            secret_key = self.login_param.get("secret_key").unwrap().to_string();
+        }
+        if self.login_param.contains_key("pass_key") {
+            passphrase = self.login_param.get("pass_key").unwrap().to_string();
+        }
+        let mut is_login_param = true;
+        if access_key == "" || secret_key == "" || passphrase == "" {
+            is_login_param = false
+        }
+
+        //每个接口都有的参数
+        // let timestamp = Utc::now().timestamp_millis();
+
+        //请求类型不同,可能请求头body 不同
+        let mut body = "{}".to_string();
+        let mut headers = HeaderMap::new();
+        if method == "POST" {
+            headers.insert("Content-Type", "application/json".parse().unwrap());
+            body = params.to_string();
+        }
+
+        //是否需要登录-- 组装sing
+        if is_login {
+            if !is_login_param {
+                let e = ResponseData::error(self.tag.clone(), "登录参数错误!".to_string());
+                return e;
+            } else {
+                // //需要登录-且登录参数齐全
+                // trace!("param:{}", params);
+                // trace!("body:{}", body);
+                // //组装sing
+                // let sing = Self::sign(secret_key.clone(),
+                //                       method.clone(),
+                //                       prefix_url.clone(),
+                //                       request_url.clone(),
+                //                       params.clone(),
+                //                       body.clone(),
+                //                       timestamp.clone(),
+                // );
+                // //组装header
+                // headers.extend(Self::headers(sing, timestamp, passphrase, access_key));
+            }
+        }
+
+
+        // trace!("headers:{:?}", headers);
+        // let base_url = format!("{}{}", prefix_url.clone(), request_url.clone());
+        let start_time = chrono::Utc::now().timestamp_millis();
+        let response = self.http_tool(
+            format!("{}{}", prefix_url.clone(), request_url.clone()),
+            method.to_string(),
+            params.to_string(),
+            body,
+            headers,
+        ).await;
+
+        let time_array = chrono::Utc::now().timestamp_millis() - start_time;
+        self.delays.push(time_array);
+        self.get_delay_info();
+
+        response
+        //
+        // let time_array = chrono::Utc::now().timestamp_millis() - start_time;
+        // self.delays.push(time_array);
+        // self.get_delay_info();
+        // let res_data = Self::res_data_analysis(get_response, base_url, params.to_string());
+        // res_data
+    }
+
+    // pub fn headers(_: String, _timestamp: String, passphrase: String, access_key: String) -> HeaderMap {
+    //     let mut headers = HeaderMap::new();
+    //     // headers.insert("OK-ACCESS-KEY", access_key.parse().unwrap());
+    //     // headers.insert("OK-ACCESS-SIGN", sign.parse().unwrap());
+    //     // headers.insert("OK-ACCESS-TIMESTAMP", timestamp.parse().unwrap());
+    //     // headers.insert("OK-ACCESS-PASSPHRASE", passphrase.parse().unwrap());
+    //     headers
+    // }
+    pub fn sign(secret_key: String,
+                method: String, prefix_url: String, request_url: String,
+                params: String, body: String, timestamp: String) -> String
+    {
+        /*签名生成*/
+        let url_param_str = RestTool::parse_params_to_str(params);
+        let base_url = if method == "GET" {
+            format!("{}{}?{}", prefix_url, request_url, url_param_str)
+        } else {
+            format!("{}{}", prefix_url, request_url)
+        };
+
+        // 时间戳 + 请求类型+ 请求参数字符串
+        let message = format!("{}{}{}{}", timestamp, method, base_url, body);
+        trace!("message:{}",message);
+
+        // 做签名
+        let hmac_key = ring::hmac::Key::new(hmac::HMAC_SHA256, secret_key.as_bytes());
+        let result = ring::hmac::sign(&hmac_key, &message.as_bytes());
+        let sign = base64::encode(result);
+        sign
+    }
+
+    // async fn http_tool(&mut self, request_path: String, request_type: String, params: String, headers: HeaderMap) -> Result<ResponseData, reqwest::Error> {
+    async fn http_tool(&mut self, request_path: String,
+                       request_type: String,
+                       params: String,
+                       body: String,
+                       headers: HeaderMap) -> ResponseData {
+        /****请求接口与 地址*/
+        let url = format!("{}{}", self.base_url.to_string(), request_path);
+        let request_type = request_type.clone().to_uppercase();
+        let addrs_url: String = if RestTool::parse_params_to_str(params.clone()) == "" {
+            url.clone()
+        } else {
+            format!("{}?{}", url.clone(), RestTool::parse_params_to_str(params.clone()))
+        };
+
+        trace!("url-----:???{}",url.clone());
+        trace!("addrs_url-----:???{}",addrs_url.clone());
+        trace!("params-----:???{}",params.clone());
+        trace!("body-----:???{}",body.clone());
+
+        let request_builder = match request_type.as_str() {
+            "GET" => self.client.get(addrs_url.clone()).headers(headers),
+            "POST" => self.client.post(url.clone()).body(body).headers(headers),
+            // "DELETE" => self.client.delete(addrs_url.clone()).headers(headers),
+            // "PUT" => self.client.put(url.clone()).json(&params),
+            _ => {
+                panic!("{}", format!("错误的请求类型:{}", request_type.clone()))
+            }
+        };
+
+        // 读取响应的内容
+        let response = request_builder.send().await.unwrap();
+        let is_success = response.status().is_success(); // 先检查状态码
+        let text = response.text().await.unwrap();
+        // trace!("text:???{:?}",text);
+        return if is_success {
+            self.on_success_data(&text)
+        } else {
+            self.on_error_data(&text, &addrs_url, &params)
+        };
+    }
+    pub fn on_success_data(&mut self, text: &String) -> ResponseData {
+        let json_value = serde_json::from_str::<Value>(&text).unwrap();
+        return ResponseData::new(self.tag.clone(), 200, "success".to_string(), json_value.clone());
+    }
+
+    pub fn on_error_data(&mut self, text: &String, base_url: &String, params: &String) -> ResponseData {
+        let json_value = serde_json::from_str::<Value>(&text);
+
+        match json_value {
+            Ok(data) => {
+                let message;
+
+                if !data["message"].is_null() {
+                    message = format!("{}:{}", data["tag"].as_str().unwrap(), data["message"].as_str().unwrap());
+                } else {
+                    message = data["tag"].to_string();
+                }
+
+                let mut error = ResponseData::error(self.tag.clone(), message);
+                error.message = format!("请求地址:{}, 请求参数:{}, 报错内容:{}。", base_url, params, error.message);
+                error
+            }
+            Err(e) => {
+                error!("解析错误:{:?}", e);
+                let error = ResponseData::error("".to_string(),
+                                                format!("json 解析失败:{},相关参数:{}", e, text));
+                error
+            }
+        }
+    }
+}

+ 411 - 0
exchanges/src/woo_swap_ws.rs

@@ -0,0 +1,411 @@
+use std::io::Read;
+use std::str::from_utf8;
+use std::sync::Arc;
+use std::sync::atomic::AtomicBool;
+use std::time::Duration;
+
+use chrono::Utc;
+use flate2::bufread::GzDecoder;
+use futures_channel::mpsc::{UnboundedReceiver, UnboundedSender};
+use once_cell::sync::Lazy;
+use ring::hmac;
+use serde_json::{json, Value};
+use tokio::sync::Mutex;
+use tokio::task;
+use tokio_tungstenite::tungstenite::{Error, Message};
+use tracing::{error, info, trace};
+
+use crate::response_base::ResponseData;
+use crate::socket_tool::{AbstractWsMode};
+// use crate::socket_tool::{AbstractWsMode, HeartbeatType};
+
+pub(crate) static LOGIN_DATA: Lazy<Mutex<(bool, bool)>> = Lazy::new(|| {
+    println!("初始化...");
+    // 0: 需要登录, 1:是否已经登录
+    Mutex::new((false, false))
+});
+
+
+pub enum WooSwapWsType {
+    Public(String),
+    Private(String),
+}
+
+
+//订阅频道
+#[derive(Clone)]
+pub enum WooSwapSubscribeType {
+    // 深度
+    PuFuturesDepth,
+    // 公开成交
+    PuFuturesTrades,
+    // K线数据
+    PuFuturesRecords,
+
+    // // 深度
+    // PuFuturesDepth,
+    // // 公开成交
+    // PuFuturesTrades,
+    // // K线数据
+    // PuFuturesRecords,
+    //
+    // // 订单
+    // PrFuturesOrders,
+    // // 仓位
+    // PrFuturesPositions,
+    // // 余额
+    // PrFuturesBalances,
+}
+
+//账号信息
+#[derive(Clone)]
+#[allow(dead_code)]
+pub struct WooSwapLogin {
+    pub api_key: String,
+    pub secret: String,
+    pub api_memo: String,
+}
+
+#[derive(Clone)]
+pub struct WooSwapWs {
+    tag: String,
+    // 类型
+    address_url: String,
+    // 地址
+    login_param: Option<WooSwapLogin>,
+    // 账号
+    symbol_s: Vec<String>,
+    // 币对
+    subscribe_types: Vec<WooSwapSubscribeType>,
+    // 订阅
+    _heartbeat_time: u64,                                        // 心跳间隔
+}
+
+
+impl WooSwapWs {
+    /*******************************************************************************************************/
+    /*****************************************实例化一个对象****************************************************/
+    /*******************************************************************************************************/
+    pub fn new(is_colo: bool, login_param: Option<WooSwapLogin>, ws_type: WooSwapWsType) -> WooSwapWs {
+        return Self::new_with_tag("default-BingxSwapWs".to_string(), is_colo, login_param, ws_type);
+    }
+
+    pub fn new_with_tag(tag: String, _is_colo: bool, login_param: Option<WooSwapLogin>, ws_type: WooSwapWsType) -> WooSwapWs {
+        /*******公共频道-私有频道数据组装*/
+        let address_url = match ws_type {
+            WooSwapWsType::Public(v) => {
+                let url = format!("wss://wss.staging.woo.org/ws/stream/{}", v);
+                info!("走普通通道(不支持colo通道):{}", url);
+                url
+            }
+            WooSwapWsType::Private(v) => {
+                let url = format!("wss://wss.staging.woo.org/ws/stream/{}", v);
+                info!("走普通通道(不支持colo通道):{}", url);
+                url
+            }
+        };
+
+        WooSwapWs {
+            tag,
+            address_url,
+            login_param,
+            symbol_s: vec![],
+            subscribe_types: vec![],
+            _heartbeat_time: 1000 * 5,
+        }
+    }
+
+    /*******************************************************************************************************/
+    /*****************************************订阅函数********************************************************/
+    /*******************************************************************************************************/
+    //手动添加订阅信息
+    pub fn set_subscribe(&mut self, subscribe_types: Vec<WooSwapSubscribeType>) {
+        self.subscribe_types.extend(subscribe_types);
+    }
+    //手动添加币对
+    pub fn set_symbols(&mut self, mut b_array: Vec<String>) {
+        for symbol in b_array.iter_mut() {
+            // 大写
+            *symbol = format!("PERP_{}", symbol.to_uppercase());
+            // 字符串替换
+            *symbol = symbol.replace("_", "_");
+        }
+        self.symbol_s = b_array;
+    }
+    //频道是否需要登录
+    fn contains_pr(&self) -> bool {
+        for t in self.subscribe_types.clone() {
+            if match t {
+                WooSwapSubscribeType::PuFuturesDepth => false,
+                WooSwapSubscribeType::PuFuturesTrades => false,
+                WooSwapSubscribeType::PuFuturesRecords => false,
+            } {
+                return true;
+            }
+        }
+        false
+    }
+
+    /*******************************************************************************************************/
+    /*****************************************工具函数********************************************************/
+    /*******************************************************************************************************/
+    //订阅枚举解析
+    pub fn enum_to_string(symbol: String, subscribe_type: WooSwapSubscribeType, _login_param: Option<WooSwapLogin>) -> String {
+        match subscribe_type {
+            WooSwapSubscribeType::PuFuturesDepth => {//深度
+                json!( {
+                    "id": "clientIDsd01",
+                    "topic": format!("{}@orderbook",symbol),
+                    "event": "subscribe"
+                }).to_string()
+            }
+            WooSwapSubscribeType::PuFuturesTrades => {//公开成交
+                json!( {
+                    "id": "clientIDsd01",
+                    "topic": format!("{}@trades",symbol),
+                    "event": "subscribe"
+                }).to_string()
+            }
+            WooSwapSubscribeType::PuFuturesRecords => {//k线数据
+                json!( {
+                    "id": "clientIDsd01",
+                    "topic": format!("{}@kline_1m",symbol),
+                    "event": "subscribe"
+                }).to_string()
+            }
+        }
+    }
+    //订阅信息生成
+    pub fn get_subscription(&self) -> Vec<String> {
+        let mut args = vec![];
+        // 只获取第一个
+        for symbol in &self.symbol_s {
+            for subscribe_type in &self.subscribe_types {
+                let ty_str = Self::enum_to_string(symbol.clone(),
+                                                  subscribe_type.clone(),
+                                                  self.login_param.clone(),
+                );
+                args.push(ty_str);
+            }
+        }
+        return args;
+    }
+
+    /*******************************************************************************************************/
+    /*****************************************socket基本*****************************************************/
+    /*******************************************************************************************************/
+    //链接
+    pub async fn ws_connect_async<F, Future>(&mut self,
+                                             is_shutdown_arc: Arc<AtomicBool>,
+                                             handle_function: F,
+                                             write_tx_am: &Arc<Mutex<UnboundedSender<Message>>>,
+                                             write_to_socket_rx: UnboundedReceiver<Message>) -> Result<(), Error>
+        where
+            F: Fn(ResponseData) -> Future + Clone + Send + 'static + Sync,
+            Future: std::future::Future<Output=()> + Send + 'static, // 确保 Fut 是一个 Future,且输出类型为 ()
+    {
+        let login_is = self.contains_pr();
+        let login_param = self.login_param.clone();
+        let subscription = self.get_subscription();
+        let address_url = self.address_url.clone();
+        let label = self.tag.clone();
+        // let heartbeat_time = self.heartbeat_time.clone();
+
+
+        //心跳-- 方法内部线程启动
+        // let write_tx_clone1 = Arc::clone(write_tx_am);
+        let write_tx_clone2 = Arc::clone(write_tx_am);
+        // tokio::spawn(async move {
+        //     trace!("线程-异步心跳-开始");
+        //     AbstractWsMode::ping_or_pong(write_tx_clone1, HeartbeatType::Ping, heartbeat_time).await;
+        //     trace!("线程-异步心跳-结束");
+        // });
+
+        //设置订阅
+        let mut subscribe_array = vec![];
+        for su in subscription {
+            subscribe_array.push(su);
+        }
+
+
+        //链接
+        let t2 = tokio::spawn(async move {
+            let write_to_socket_rx_arc = Arc::new(Mutex::new(write_to_socket_rx));
+
+            info!("启动连接");
+            loop {
+                info!("Woo_usdt_swap socket 连接中……");
+                // 需要登录
+                if login_is {
+                    let mut login_data = LOGIN_DATA.lock().await;
+                    let login_param_real = login_param.clone().unwrap();
+                    login_data.0 = true;
+
+                    let timestamp = Utc::now().timestamp_millis().to_string();
+                    let api_key = login_param_real.api_key.clone();
+                    let secret_key = login_param_real.secret.clone();
+                    let api_memo = login_param_real.api_memo.clone();
+
+
+                    // let timestamp = "1589267764859".to_string();
+                    // let api_key = "80618e45710812162b04892c7ee5ead4a3cc3e56".to_string();
+                    // let secret_key = "6c6c98544461bbe71db2bca4c6d7fd0021e0ba9efc215f9c6ad41852df9d9df9".to_string();
+                    // let api_memo = "test001".to_string();
+
+                    let sign = {
+                        let message = format!("{}#{}#Woo.WebSocket", timestamp.clone(), api_memo);
+                        trace!("组装数据:\n{}", message);
+
+                        let signed_key = hmac::Key::new(hmac::HMAC_SHA256, secret_key.as_ref());
+                        let sign = hex::encode(hmac::sign(&signed_key, message.as_bytes()).as_ref());
+                        sign
+                    };
+
+
+                    let mut args = vec![];
+                    args.push(api_key.clone());
+                    args.push(timestamp.clone());
+                    args.push(sign.clone());
+                    args.push(String::from("web"));
+                    // {"action":"access","args":["<API_KEY>","<timestamp>","<sign>","<dev>"]}
+                    let login_param = json!({
+                        "action": "access",
+                        "args": [
+                           api_key, timestamp.as_str(),sign.as_str(),"web"
+                        ]
+                    });
+                    let login_str = login_param.to_string();
+                    info!("发起ws登录: {}", login_str);
+                    let write_tx_c = Arc::clone(&write_tx_clone2);
+                    AbstractWsMode::send_subscribe(write_tx_c, Message::Text(login_str)).await;
+                }
+
+                AbstractWsMode::ws_connect_async(is_shutdown_arc.clone(), handle_function.clone(), address_url.clone(),
+                                                 login_is, label.clone(), subscribe_array.clone(), write_to_socket_rx_arc.clone(),
+                                                 Self::message_text_sync, Self::message_ping, Self::message_pong, Self::message_binary_sync,
+                ).await;
+                let mut login_data = LOGIN_DATA.lock().await;
+                // 断联后 设置为没有登录
+                login_data.1 = false;
+                info!("Woo_usdt_swap socket 断连,1s以后重连……");
+                error!("Woo_usdt_swap socket 断连,1s以后重连……");
+                tokio::time::sleep(Duration::from_secs(1)).await;
+            }
+        });
+        tokio::try_join!(t2).unwrap();
+        trace!("线程-心跳与链接-结束");
+
+        Ok(())
+    }
+    /*******************************************************************************************************/
+    /*****************************************数据解析*****************************************************/
+    /*******************************************************************************************************/
+    //数据解析-Text
+    pub async fn message_text(text: String) -> Option<ResponseData> {
+        let response_data = Self::ok_text(text).await;
+        Option::from(response_data)
+    }
+    pub fn message_text_sync(text: String) -> Option<ResponseData> {
+        // 使用 tokio::task::block_in_place 来等待异步函数的结果
+        task::block_in_place(|| {
+            tokio::runtime::Handle::current().block_on(Self::message_text(text))
+        })
+    }
+    //数据解析-ping
+    pub fn message_ping(_pi: Vec<u8>) -> Option<ResponseData> {
+        return Option::from(ResponseData::new("".to_string(), -300, "success".to_string(), Value::Null));
+    }
+    //数据解析-pong
+    pub fn message_pong(_po: Vec<u8>) -> Option<ResponseData> {
+        return Option::from(ResponseData::new("".to_string(), -301, "success".to_string(), Value::Null));
+    }
+    //数据解析-二进制
+    pub async fn message_binary(binary: Vec<u8>) -> Option<ResponseData> {
+        //二进制WebSocket消息
+        let message_str = Self::parse_zip_data(binary);
+        let response_data = Self::ok_text(message_str).await;
+        Option::from(response_data)
+    }
+    pub fn message_binary_sync(binary: Vec<u8>) -> Option<ResponseData> {
+        // 使用 tokio::task::block_in_place 来等待异步函数的结果
+        task::block_in_place(|| {
+            tokio::runtime::Handle::current().block_on(Self::message_binary(binary))
+        })
+    }
+    //数据解析
+    pub async fn ok_text(text: String) -> ResponseData
+    {
+        // info!("原始数据:{}", text);
+        let mut res_data = ResponseData::new("".to_string(), 200, "success".to_string(), Value::Null);
+        let json_value: Value = serde_json::from_str(&text).unwrap();
+
+        let event = json_value["event"].as_str();
+        match event {
+            None => {}
+            Some(v) => {
+                match v {
+                    "subscribe" => {
+                        let success = json_value["success"].as_bool().unwrap();
+                        if success == true {
+                            res_data.code = -201;
+                            res_data.message = format!("订阅成功:{}", json_value["data"].clone().to_string());
+                            return res_data;
+                        } else {
+                            res_data.code = 400;
+                            res_data.message = format!("订阅失败:{}", json_value["errorMsg"].clone().to_string());
+                            return res_data;
+                        }
+                    }
+                    "ping" => {
+                        let data = json!({   "event":"ping"  });
+                        return ResponseData::new("".to_string(), -300, "success".to_string(), Value::String(data.to_string()));
+                    }
+                    _ => {}
+                }
+            }
+        }
+
+        let topic = json_value["topic"].as_str();
+        match topic {
+            None => {}
+            Some(v) => {
+                res_data.code = 200;
+                res_data.data = json_value.clone();
+                if v.contains("orderbook") {
+                    res_data.channel = "futures.order_book".to_string();
+                } else if v.contains("trades") {
+                    res_data.channel = "futures.trades".to_string();
+                } else if v.contains("kline") {
+                    res_data.channel = "futures.candlesticks".to_string();
+                } else {
+                    res_data.code = 400;
+                    res_data.channel = "未知推送数据".to_string();
+                }
+                return res_data;
+            }
+        }
+
+        res_data.code = 400;
+        res_data.message = format!("未知响应内容");
+        res_data.data = text.parse().unwrap();
+        trace!("--------------------------------");
+        res_data
+    }
+
+    fn parse_zip_data(p0: Vec<u8>) -> String {
+        // 创建一个GzDecoder的实例,将压缩数据作为输入
+        let mut decoder = GzDecoder::new(&p0[..]);
+
+        // 创建一个缓冲区来存放解压缩后的数据
+        let mut decompressed_data = Vec::new();
+
+        // 读取解压缩的数据到缓冲区中
+        decoder.read_to_end(&mut decompressed_data).expect("解压缩失败");
+        let result = from_utf8(&decompressed_data)
+            .expect("解压缩后的数据不是有效的UTF-8");
+
+        // info!("解压缩数据 {:?}", result);
+        result.to_string()
+    }
+}
+

+ 68 - 25
standard/src/binance_swap_handle.rs

@@ -1,40 +1,83 @@
 use std::str::FromStr;
 use rust_decimal::Decimal;
-use rust_decimal_macros::dec;
+use rust_decimal::prelude::FromPrimitive;
 use serde_json::Value;
 use exchanges::response_base::ResponseData;
-use crate::{MarketOrder, SpecialDepth, SpecialTicker};
-
+use crate::{OrderBook, Record, Trade};
 
 // 处理特殊Ticker信息
-pub fn handle_book_ticker(res_data: &ResponseData) -> SpecialDepth {
-    let bp = Decimal::from_str((*res_data).data["b"].as_str().unwrap()).unwrap();
-    let bq = Decimal::from_str((*res_data).data["B"].as_str().unwrap()).unwrap();
-    let ap = Decimal::from_str((*res_data).data["a"].as_str().unwrap()).unwrap();
-    let aq = Decimal::from_str((*res_data).data["A"].as_str().unwrap()).unwrap();
-    let mp = (bp + ap) * dec!(0.5);
-    let t = Decimal::from_str(&(*res_data).data["u"].to_string()).unwrap();
-    let create_at = (*res_data).data["E"].as_i64().unwrap() * 1000;
-
-    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 handle_book_ticker(res_data: &ResponseData) -> SpecialDepth {
+//     let bp = Decimal::from_str((*res_data).data["b"].as_str().unwrap()).unwrap();
+//     let bq = Decimal::from_str((*res_data).data["B"].as_str().unwrap()).unwrap();
+//     let ap = Decimal::from_str((*res_data).data["a"].as_str().unwrap()).unwrap();
+//     let aq = Decimal::from_str((*res_data).data["A"].as_str().unwrap()).unwrap();
+//     let mp = (bp + ap) * dec!(0.5);
+//     let t = Decimal::from_str(&(*res_data).data["u"].to_string()).unwrap();
+//     let create_at = (*res_data).data["E"].as_i64().unwrap() * 1000;
+//
+//     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).tag.clone(),
+//         depth: depth_info,
+//         ticker: ticker_info,
+//         t,
+//         create_at,
+//     }
+// }
 
 // 格式化深度信息
-pub fn format_depth_items(value: Value) -> Vec<MarketOrder> {
-    let mut depth_items: Vec<MarketOrder> = vec![];
+pub fn format_depth_items(value: Value) -> Vec<OrderBook> {
+    let mut depth_items: Vec<OrderBook> = vec![];
     for value in value.as_array().unwrap() {
-        depth_items.push(MarketOrder {
+        depth_items.push(OrderBook {
             price: Decimal::from_str(value[0].as_str().unwrap()).unwrap(),
             amount: Decimal::from_str(value[1].as_str().unwrap()).unwrap(),
         })
     }
     return depth_items;
 }
+
+pub fn format_trade_items(response: &ResponseData) -> Vec<Trade> {
+    let data = response.data.clone();
+
+    let id = data["a"].as_i64().unwrap().to_string();
+    let time = Decimal::from_i64(data["T"].as_i64().unwrap()).unwrap();
+    let is_sell = data["m"].as_bool().unwrap(); // 买方是否是做市方。如true,则此次成交是一个主动卖出单,否则是一个主动买入单。
+    let mut size = Decimal::from_str(data["q"].as_str().unwrap().to_string().as_str()).unwrap();
+    if is_sell {
+        size = -size
+    }
+    let price = Decimal::from_str(data["p"].as_str().unwrap().to_string().as_str()).unwrap();
+    let symbol = data["s"].as_str().unwrap().to_string().replace("USDT", "_USDT");
+
+    vec![Trade {
+        id,
+        time,
+        size,
+        price,
+        symbol,
+    }]
+}
+
+pub fn handle_records(value: &Value) -> Vec<Record> {
+    let data = value["k"].clone();
+    let time = Decimal::from_i64(data["t"].as_i64().unwrap()).unwrap();
+
+    let open = Decimal::from_str(data["o"].as_str().unwrap().to_string().as_str()).unwrap();
+    let high = Decimal::from_str(data["h"].as_str().unwrap().to_string().as_str()).unwrap();
+    let low = Decimal::from_str(data["l"].as_str().unwrap().to_string().as_str()).unwrap();
+    let close = Decimal::from_str(data["c"].as_str().unwrap().to_string().as_str()).unwrap();
+    let volume = Decimal::from_str(data["q"].as_str().unwrap().to_string().as_str()).unwrap();
+    let symbol = data["s"].as_str().unwrap().to_string().replace("USDT", "_USDT");
+
+    vec![Record {
+        time,
+        open,
+        high,
+        low,
+        close,
+        volume,
+        symbol,
+    }]
+}

+ 259 - 0
standard/src/bingx_swap.rs

@@ -0,0 +1,259 @@
+// use std::collections::{BTreeMap};
+// use std::io::{Error, ErrorKind};
+// use std::str::FromStr;
+// use tokio::sync::mpsc::Sender;
+// use async_trait::async_trait;
+// use rust_decimal::{Decimal, MathematicalOps};
+// use serde_json::{json, Value};
+// use tracing::{error, info};
+// use crate::{Platform, ExchangeEnum, Account, Position, Ticker, Market, Order, utils};
+// use exchanges::bingx_swap_rest::BingxSwapRest;
+//
+// #[allow(dead_code)]
+// #[derive(Clone)]
+// pub struct BingxSwap {
+//     exchange: ExchangeEnum,
+//     symbol: String,
+//     is_colo: bool,
+//     params: BTreeMap<String, String>,
+//     request: BingxSwapRest,
+//     market: Market,
+//     order_sender: Sender<Order>,
+//     error_sender: Sender<Error>,
+// }
+//
+// impl BingxSwap {
+//     pub async fn new(symbol: String, is_colo: bool, params: BTreeMap<String, String>, order_sender: Sender<Order>, error_sender: Sender<Error>) -> BingxSwap {
+//         let market = Market::new();
+//         let mut bingx_swap = BingxSwap {
+//             exchange: ExchangeEnum::BingxSwap,
+//             symbol: symbol.to_uppercase(),
+//             is_colo,
+//             params: params.clone(),
+//             request: BingxSwapRest::new(is_colo, params.clone()),
+//             market,
+//             order_sender,
+//             error_sender,
+//         };
+//
+//         // 修改持仓模式
+//         let symbol_array: Vec<&str> = symbol.split("_").collect();
+//         let mode_result = bingx_swap.set_dual_mode(symbol_array[1], true).await;
+//         match mode_result {
+//             Ok(ok) => {
+//                 info!("Bingx:设置持仓模式成功!{:?}", ok);
+//             }
+//             Err(error) => {
+//                 error!("Bingx:设置持仓模式失败!mode_result={}", error)
+//             }
+//         }
+//         // 获取市场信息
+//         bingx_swap.market = BingxSwap::get_market(&mut bingx_swap).await.unwrap_or(bingx_swap.market);
+//         return bingx_swap;
+//     }
+// }
+//
+// #[async_trait]
+// impl Platform for BingxSwap {
+//     // 克隆方法
+//     fn clone_box(&self) -> Box<dyn Platform + Send + Sync> { Box::new(self.clone()) }
+//     // 获取交易所模式
+//     fn get_self_exchange(&self) -> ExchangeEnum {
+//         ExchangeEnum::BingxSwap
+//     }
+//     // 获取交易对
+//     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> {
+//         Err(Error::new(ErrorKind::NotFound, "bingx_swap:该交易所方法未实现".to_string()))
+//     }
+//     // 获取账号信息
+//     async fn get_account(&mut self) -> Result<Account, Error> {
+//         Err(Error::new(ErrorKind::NotFound, "bingx_swap:该交易所方法未实现".to_string()))
+//     }
+//
+//     async fn get_spot_account(&mut self) -> Result<Vec<Account>, Error> {
+//         Err(Error::new(ErrorKind::NotFound, "bingx_swap:该交易所方法未实现".to_string()))
+//     }
+//
+//     // 获取持仓信息
+//     async fn get_position(&mut self) -> Result<Vec<Position>, Error> {
+//         Err(Error::new(ErrorKind::NotFound, "bingx_swap:该交易所方法未实现".to_string()))
+//     }
+//     // 获取所有持仓
+//     async fn get_positions(&mut self) -> Result<Vec<Position>, Error> {
+//         Err(Error::new(ErrorKind::NotFound, "bingx_swap:该交易所方法未实现".to_string()))
+//     }
+//     // 获取市场行情
+//     async fn get_ticker(&mut self) -> Result<Ticker, Error> {
+//         Err(Error::new(ErrorKind::NotFound, "bingx_swap:该交易所方法未实现".to_string()))
+//     }
+//
+//     async fn get_ticker_symbol(&mut self, _symbol: String) -> Result<Ticker, Error> {
+//         Err(Error::new(ErrorKind::NotFound, "bingx_swap:该交易所方法未实现".to_string()))
+//     }
+//
+//     async fn get_market(&mut self) -> Result<Market, Error> {
+//         let symbol_format = utils::format_symbol(self.symbol.clone(), "-");
+//         let params = json!({});
+//         let res_data = self.request.get_market(params).await;
+//         if res_data.code == 200 {
+//             let res_data_json = res_data.data.as_array().unwrap();
+//             let market_info = res_data_json.iter().find(|item| item["symbol"].as_str().unwrap() == symbol_format);
+//             match market_info {
+//                 None => {
+//                     error!("bingx_swap:获取Market信息错误!\nget_market:res_data={:?}", res_data);
+//                     Err(Error::new(ErrorKind::Other, res_data.to_string()))
+//                 }
+//                 Some(value) => {
+//                     let name = value["symbol"].as_str().unwrap();
+//                     let name_array: Vec<&str> = name.split("-").collect();
+//                     let price_precision = Decimal::from_str(&value["pricePrecision"].to_string()).unwrap();
+//                     let tick_size = Decimal::TEN.powd(Decimal::NEGATIVE_ONE * price_precision);
+//                     let amount_precision = Decimal::from_str(&value["quantityPrecision"].to_string()).unwrap();
+//                     let amount_size = Decimal::TEN.powd(Decimal::NEGATIVE_ONE * amount_precision);
+//                     let min_qty = Decimal::from_str(&value["tradeMinUSDT"].to_string()).unwrap();
+//                     let max_qty = Decimal::NEGATIVE_ONE;
+//                     let ct_val = Decimal::ONE;
+//
+//                     let result = Market {
+//                         symbol: name_array.join("_"),
+//                         base_asset: name_array[0].to_string(),
+//                         quote_asset: name_array[1].to_string(),
+//                         tick_size,
+//                         amount_size,
+//                         price_precision,
+//                         amount_precision,
+//                         min_qty,
+//                         max_qty,
+//                         min_notional: min_qty,
+//                         max_notional: max_qty,
+//                         ct_val,
+//                     };
+//                     Ok(result)
+//                 }
+//             }
+//         } else {
+//             Err(Error::new(ErrorKind::Other, res_data.to_string()))
+//         }
+//     }
+//
+//     async fn get_market_symbol(&mut self, symbol: String) -> Result<Market, Error> {
+//         let symbol_format = utils::format_symbol(symbol.clone(), "-");
+//         let params = json!({
+//             "symbol": symbol_format.clone()
+//         });
+//         let res_data = self.request.get_market(params).await;
+//         if res_data.code == 200 {
+//             let res_data_json = res_data.data.as_array().unwrap();
+//             let market_info = res_data_json.iter().find(|item| item["symbol"].as_str().unwrap() == symbol_format);
+//             match market_info {
+//                 None => {
+//                     error!("bingx_swap:获取Market信息错误!\nget_market:res_data={:?}", res_data);
+//                     Err(Error::new(ErrorKind::Other, res_data.to_string()))
+//                 }
+//                 Some(value) => {
+//                     let name = value["symbol"].as_str().unwrap();
+//                     let name_array: Vec<&str> = name.split("-").collect();
+//                     let price_precision = Decimal::from_str(&value["pricePrecision"].to_string()).unwrap();
+//                     let tick_size = Decimal::TEN.powd(Decimal::NEGATIVE_ONE * price_precision);
+//                     let amount_precision = Decimal::from_str(&value["quantityPrecision"].to_string()).unwrap();
+//                     let amount_size = Decimal::TEN.powd(Decimal::NEGATIVE_ONE * amount_precision);
+//                     let min_qty = Decimal::from_str(&value["tradeMinUSDT"].to_string()).unwrap();
+//                     let max_qty = Decimal::NEGATIVE_ONE;
+//                     let ct_val = Decimal::ONE;
+//
+//                     let result = Market {
+//                         symbol: name_array.join("_"),
+//                         base_asset: name_array[0].to_string(),
+//                         quote_asset: name_array[1].to_string(),
+//                         tick_size,
+//                         amount_size,
+//                         price_precision,
+//                         amount_precision,
+//                         min_qty,
+//                         max_qty,
+//                         min_notional: min_qty,
+//                         max_notional: max_qty,
+//                         ct_val,
+//                     };
+//                     Ok(result)
+//                 }
+//             }
+//         } else {
+//             Err(Error::new(ErrorKind::Other, res_data.to_string()))
+//         }
+//     }
+//
+//     // 获取订单详情
+//     async fn get_order_detail(&mut self, _order_id: &str, _custom_id: &str) -> Result<Order, Error> {
+//         Err(Error::new(ErrorKind::NotFound, "bingx_swap:该交易所方法未实现".to_string()))
+//     }
+//     // 获取订单列表
+//     async fn get_orders_list(&mut self, _status: &str) -> Result<Vec<Order>, Error> {
+//         Err(Error::new(ErrorKind::NotFound, "bingx_swap:该交易所方法未实现".to_string()))
+//     }
+//     // 下单接口
+//     async fn take_order(&mut self, _custom_id: &str, _origin_side: &str, _price: Decimal, _amount: Decimal) -> Result<Order, Error> {
+//         Err(Error::new(ErrorKind::NotFound, "bingx_swap:该交易所方法未实现".to_string()))
+//     }
+//
+//     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> {
+//         Err(Error::new(ErrorKind::NotFound, "bingx_swap:该交易所方法未实现".to_string()))
+//     }
+//
+//     // 撤销订单
+//     async fn cancel_order(&mut self, _order_id: &str, _custom_id: &str) -> Result<Order, Error> {
+//         Err(Error::new(ErrorKind::NotFound, "bingx_swap:该交易所方法未实现".to_string()))
+//     }
+//     // 批量撤销订单
+//     async fn cancel_orders(&mut self) -> Result<Vec<Order>, Error> {
+//         Err(Error::new(ErrorKind::NotFound, "bingx_swap:该交易所方法未实现".to_string()))
+//     }
+//
+//     async fn cancel_orders_all(&mut self) -> Result<Vec<Order>, Error> {
+//         Err(Error::new(ErrorKind::NotFound, "bingx_swap:该交易所方法未实现".to_string()))
+//     }
+//
+//     async fn take_stop_loss_order(&mut self, _stop_price: Decimal, _price: Decimal, _side: &str) -> Result<Value, Error> {
+//         Err(Error::new(ErrorKind::NotFound, "bingx_swap:该交易所方法未实现".to_string()))
+//     }
+//
+//     async fn cancel_stop_loss_order(&mut self, _order_id: &str) -> Result<Value, Error> {
+//         Err(Error::new(ErrorKind::NotFound, "bingx_swap:该交易所方法未实现".to_string()))
+//     }
+//
+//     // 设置持仓模式
+//     async fn set_dual_mode(&mut self, _coin: &str, _is_dual_mode: bool) -> Result<String, Error> {
+//         Err(Error::new(ErrorKind::NotFound, "bingx_swap:该交易所方法未实现".to_string()))
+//     }
+//
+//     // 更新双持仓模式下杠杆
+//     async fn set_dual_leverage(&mut self, _leverage: &str) -> Result<String, Error> {
+//         Err(Error::new(ErrorKind::NotFound, "bingx_swap:该交易所方法未实现".to_string()))
+//     }
+//
+//     async fn set_auto_deposit_status(&mut self, _status: bool) -> Result<String, Error> { Err(Error::new(ErrorKind::NotFound, "bingx:该交易所方法未实现".to_string())) }
+//
+//     // 交易账户互转
+//     async fn wallet_transfers(&mut self, _coin: &str, _from: &str, _to: &str, _amount: Decimal) -> Result<String, Error> {
+//         Err(Error::new(ErrorKind::NotFound, "bingx_swap:该交易所方法未实现".to_string()))
+//     }
+// }

+ 105 - 0
standard/src/bingx_swap_handle.rs

@@ -0,0 +1,105 @@
+// use std::str::FromStr;
+// use chrono::Utc;
+// use rust_decimal::Decimal;
+// use rust_decimal::prelude::FromPrimitive;
+// use serde_json::Value;
+// use exchanges::response_base::ResponseData;
+// use crate::{OrderBook, Trade, Record};
+// // use crate::{Account, OrderBook, Order, Position, SpecialOrder, Trade, Record};
+//
+// // 处理账号信息
+// // pub fn handle_account_info(_res_data: &ResponseData, _symbol: &String) -> Account {
+// //     Account::new()
+// // }
+// //
+// // pub fn format_account_info(_data: &Vec<Value>, _symbol: &String) -> Account {
+// //     Account::new()
+// // }
+// //
+// // // 处理position信息
+// // pub fn handle_position(_res_data: &ResponseData, _ct_val: &Decimal) -> Vec<Position> {
+// //     vec![Position::new()]
+// // }
+// //
+// // pub fn format_position_item(_position: &Value, _ct_val: &Decimal) -> Position {
+// //     Position::new()
+// // }
+// //
+// // // 处理order信息
+// // pub fn handle_order(_res_data: &ResponseData, _ct_val: Decimal) -> SpecialOrder {
+// //     SpecialOrder::new()
+// // }
+// //
+// // pub fn format_order_item(_order: Value, _ct_val: Decimal) -> Order {
+// //     Order::new()
+// // }
+// // 处理特殊Ticket信息
+// // pub fn handle_book_ticker(res_data: &ResponseData) -> SpecialDepth {
+// //     let bp = Decimal::from_str((*res_data).data["b"].as_str().unwrap()).unwrap();
+// //     let bq = Decimal::from_f64((*res_data).data["B"].as_f64().unwrap()).unwrap();
+// //     let ap = Decimal::from_str((*res_data).data["a"].as_str().unwrap()).unwrap();
+// //     let aq = Decimal::from_f64((*res_data).data["A"].as_f64().unwrap()).unwrap();
+// //     let mp = (bp + ap) * dec!(0.5);
+// //     let t = Decimal::from_u64((*res_data).data["u"].as_u64().unwrap()).unwrap();
+// //     let create_at = (*res_data).data["t"].as_i64().unwrap() * 1000;
+// //
+// //     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).tag.clone(),
+// //         depth: depth_info,
+// //         ticker: ticker_info,
+// //         t,
+// //         create_at,
+// //     }
+// // }
+//
+// pub fn handle_records(value: &Value) -> Vec<Record> {
+//     let mut records = vec![];
+//     let symbol = value["s"].as_str().unwrap().replace("-", "_");
+//
+//     for record_value in value["data"].as_array().unwrap() {
+//         records.push(Record {
+//             time: Decimal::from_i64(Utc::now().timestamp_millis()).unwrap(),
+//             open: Decimal::from_str(record_value["o"].as_str().unwrap()).unwrap(),
+//             high: Decimal::from_str(record_value["h"].as_str().unwrap()).unwrap(),
+//             low: Decimal::from_str(record_value["l"].as_str().unwrap()).unwrap(),
+//             close: Decimal::from_str(record_value["c"].as_str().unwrap()).unwrap(),
+//             volume: Decimal::from_str(record_value["v"].as_str().unwrap()).unwrap(),
+//             symbol: symbol.clone(),
+//         });
+//     }
+//
+//     return records;
+// }
+//
+// pub fn format_depth_items(value: &Value) -> Vec<OrderBook> {
+//     let mut depth_items: Vec<OrderBook> = vec![];
+//     for value in value.as_array().unwrap() {
+//         depth_items.push(OrderBook {
+//             price: Decimal::from_str(value["p"].as_str().unwrap()).unwrap(),
+//             amount: Decimal::from_f64(value["s"].as_f64().unwrap()).unwrap(),
+//         })
+//     }
+//     return depth_items;
+// }
+//
+// pub fn format_trade_items(res_data: &ResponseData) -> Vec<Trade> {
+//     let result = res_data.data["data"].as_array().unwrap();
+//     let mut trades = vec![];
+//
+//     for item in result {
+//         let side = item["m"] == true;
+//         let size = Decimal::from_str(item["q"].as_str().unwrap()).unwrap();
+//         trades.push(Trade {
+//             id: item["T"].to_string(),
+//             time: Decimal::from_i64(item["T"].as_i64().unwrap()).unwrap(),
+//             size: if side { -size } else { size },
+//             price: Decimal::from_str(item["p"].as_str().unwrap().to_string().as_str()).unwrap(),
+//             symbol: item["s"].as_str().unwrap().to_string().replace("-", "_"),
+//         })
+//     }
+//
+//     return trades;
+// }

+ 4 - 4
standard/src/bitget_spot_handle.rs

@@ -55,7 +55,7 @@
 //     }
 //     trace!(?order_info);
 //     SpecialOrder {
-//         name: res_data.label,
+//         name: res_data.tag,
 //         order: order_info,
 //     }
 // }
@@ -112,10 +112,10 @@
 // pub fn handle_special_ticker(res_data: ResponseData) -> SpecialDepth {
 //     let res_data_str = res_data.data;
 //     let res_data_json: Vec<serde_json::Value> = serde_json::from_str(&*res_data_str).unwrap();
-//     format_special_ticker(res_data_json[0].clone(), res_data.label)
+//     format_special_ticker(res_data_json[0].clone(), res_data.tag)
 // }
 //
-// pub fn format_special_ticker(data: serde_json::Value, label: String) -> SpecialDepth {
+// pub fn format_special_ticker(data: serde_json::Value, tag: String) -> SpecialDepth {
 //     let bp = Decimal::from_str(data["bidPr"].as_str().unwrap()).unwrap();
 //     let bq = Decimal::from_str(data["bidSz"].as_str().unwrap()).unwrap();
 //     let ap = Decimal::from_str(data["askPr"].as_str().unwrap()).unwrap();
@@ -127,7 +127,7 @@
 //     let ticker_info = SpecialTicker { sell: ap, buy: bp, mid_price: mp, t, create_at };
 //     let depth_info = vec![bp, bq, ap, aq];
 //     SpecialDepth {
-//         name: label,
+//         name: tag,
 //         depth: depth_info,
 //         ticker: ticker_info,
 //         t,

+ 668 - 668
standard/src/bitget_swap.rs

@@ -1,670 +1,670 @@
-use std::collections::{BTreeMap};
-use exchanges::bitget_swap_rest::BitgetSwapRest;
-use std::io::{Error, ErrorKind};
-use tokio::sync::mpsc::Sender;
-use std::str::FromStr;
-use async_trait::async_trait;
-use futures::stream::FuturesUnordered;
-use futures::TryStreamExt;
-use rust_decimal::{Decimal, MathematicalOps};
-use rust_decimal::prelude::ToPrimitive;
-use rust_decimal_macros::dec;
-use serde_json::{json, Value};
-use tokio::spawn;
-use tokio::time::Instant;
-use tracing::{error, info};
-use global::trace_stack::TraceStack;
-use crate::exchange::ExchangeEnum;
-use crate::{Account, Market, Order, OrderCommand, Platform, Position, PositionModeEnum, Ticker, utils};
-
-#[allow(dead_code)]
-#[derive(Clone)]
-pub struct BitgetSwap {
-    exchange: ExchangeEnum,
-    symbol: String,
-    is_colo: bool,
-    params: BTreeMap<String, String>,
-    request: BitgetSwapRest,
-    market: Market,
-    order_sender: Sender<Order>,
-    error_sender: Sender<Error>,
-}
-
-impl BitgetSwap {
-    pub async fn new(symbol: String, is_colo: bool, params: BTreeMap<String, String>, order_sender: Sender<Order>, error_sender: Sender<Error>) -> BitgetSwap {
-        let market = Market::new();
-        let mut bitget_swap = BitgetSwap {
-            exchange: ExchangeEnum::BitgetSwap,
-            symbol: symbol.to_uppercase(),
-            is_colo,
-            params: params.clone(),
-            request: BitgetSwapRest::new(is_colo, params.clone()),
-            market,
-            order_sender,
-            error_sender,
-        };
-        bitget_swap.market = BitgetSwap::get_market(&mut bitget_swap).await.unwrap();
-        // 修改持仓模式
-        let mode_result = bitget_swap.set_dual_mode("", true).await;
-        match mode_result {
-            Ok(ok) => {
-                info!("BitgetSwap:设置持仓模式成功!{:?}", ok);
-            }
-            Err(error) => {
-                error!("BitgetSwap:设置持仓模式失败!{:?}", error)
-            }
-        }
-        // 设置持仓杠杆
-        // let lever_rate_result = bitget_swap.set_dual_leverage("10").await;
-        // match lever_rate_result {
-        //     Ok(ok) => {
-        //         info!("BitgetSwap:设置持仓杠杆成功!{:?}", ok);
-        //     }
-        //     Err(error) => {
-        //         error!("BitgetSwap:设置持仓杠杆失败!{:?}", error)
-        //     }
-        // }
-
-        return bitget_swap;
-    }
-}
-
-#[async_trait]
-impl Platform for BitgetSwap {
-    fn clone_box(&self) -> Box<dyn Platform + Send + Sync> { Box::new(self.clone()) }
-
-    fn get_self_exchange(&self) -> ExchangeEnum { ExchangeEnum::BitgetSwap }
-
-    fn get_self_symbol(&self) -> String { self.symbol.clone() }
-
-    fn get_self_is_colo(&self) -> bool { self.is_colo }
-
-    fn get_self_params(&self) -> BTreeMap<String, String> { self.params.clone() }
-
-    fn get_self_market(&self) -> Market { self.market.clone() }
-
-    fn get_request_delays(&self) -> Vec<i64> {
-        // self.request.get_delays()
-        vec![]
-    }
-
-    fn get_request_avg_delay(&self) -> Decimal {
-        // self.request.get_avg_delay()
-        Decimal::ZERO
-    }
-
-    fn get_request_max_delay(&self) -> i64 { 0 }
-
-    async fn get_server_time(&mut self) -> Result<String, Error> {
-        let res_data = self.request.get_server_time().await;
-        if res_data.code == 200 {
-            let res_data_json = res_data.data;
-            let result = res_data_json["serverTime"].as_str().unwrap().to_string();
-            Ok(result)
-        } else {
-            Err(Error::new(ErrorKind::Other, res_data.to_string()))
-        }
-    }
-
-    async fn get_account(&mut self) -> Result<Account, Error> {
-        let response = self.request.get_account_info().await;
-
-        if response.code == 200 {
-            for data in response.data.as_array().unwrap() {
-                if data["marginCoin"].as_str().unwrap() != "USDT" {
-                    continue
-                }
-
-                // 格式化account信息
-                let mut account = Account {
-                    coin: data["marginCoin"].to_string(),
-                    balance: Decimal::from_str(data["accountEquity"].as_str().unwrap()).unwrap(),
-                    available_balance: Decimal::from_str(data["available"].as_str().unwrap()).unwrap(),
-                    frozen_balance: Default::default(),
-                    stocks: Default::default(),
-                    available_stocks: Default::default(),
-                    frozen_stocks: Default::default(),
-                };
-                account.frozen_balance = account.balance - account.available_balance;
-
-                return Ok(account)
-            }
-
-            Err(Error::new(ErrorKind::NotFound, format!("bitget_usdt_swap 未能找到USDT账户:{}。", response.to_string())))
-        } else {
-            Err(Error::new(ErrorKind::Other, response.to_string()))
-        }
-    }
-
-    async fn get_spot_account(&mut self) -> Result<Vec<Account>, Error> {
-        Err(Error::new(ErrorKind::NotFound, "bitget_swap get_spot_account:该交易所方法未实现".to_string()))
-    }
-
-    async fn get_position(&mut self) -> Result<Vec<Position>, Error> { Err(Error::new(ErrorKind::NotFound, "bitget_swap get_position:该交易所方法未实现".to_string())) }
-
-    async fn get_positions(&mut self) -> Result<Vec<Position>, Error> {
-        let params = json!({
-            "productType": "USDT-FUTURES",
-            "marginCoin": "USDT"
-        });
-        let response = self.request.get_all_position(params).await;
-        info!(?response);
-
-        if response.code != 200 {
-            return Err(Error::new(ErrorKind::NotFound, format!("bitget_swap 获取仓位异常{:?}", response).to_string()))
-        }
-
-        // 正常处理持仓信息
-        let mut positions: Vec<Position> = vec![];
-        if response.data.is_null() {
-            return Ok(positions)
-        }
-
-        let positions_json = response.data.as_array().unwrap();
-        for position_json in positions_json {
-            let symbol = position_json["symbol"].as_str().unwrap().to_string();
-            let margin_level = Decimal::from_str(position_json["leverage"].as_str().unwrap()).unwrap();
-            let amount = Decimal::from_str(position_json["total"].as_str().unwrap()).unwrap();
-            let frozen_amount = Decimal::from_str(position_json["locked"].as_str().unwrap()).unwrap();
-            let price = Decimal::from_str(position_json["openPriceAvg"].as_str().unwrap()).unwrap();
-            let profit = Decimal::from_str(position_json["unrealizedPL"].as_str().unwrap()).unwrap();
-            let position_mode = match position_json["posMode"].as_str().unwrap() {
-                "hedge_mode" => {
-                    match position_json["holdSide"].as_str().unwrap() {
-                        "short" => {
-                            PositionModeEnum::Short
-                        }
-                        "long" => {
-                            PositionModeEnum::Long
-                        },
-                        _ => {
-                            panic!("bitget_usdt_swap: 未知的持仓模式与持仓方向: {}, {}",
-                                   position_json["posMode"].as_str().unwrap(), position_json["holdSide"].as_str().unwrap())
-                        }
-                    }
-                },
-                "one_way_mode" => {
-                    PositionModeEnum::Both
-                },
-                _ => {
-                    panic!("bitget_usdt_swap: 未知的持仓模式: {}", position_json["posMode"].as_str().unwrap())
-                }
-            };
-            let margin = Decimal::from_str(position_json["marginSize"].as_str().unwrap()).unwrap();
-
-            positions.push(Position {
-                symbol,
-                margin_level,
-                amount,
-                frozen_amount,
-                price,
-                profit,
-                position_mode,
-                margin,
-            });
-        }
-
-        Ok(positions)
-    }
-
-    async fn get_ticker(&mut self) -> Result<Ticker, Error> {
-        return 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(), "");
-        let res_data = self.request.get_tickers(symbol_format).await;
-        if res_data.code == 200 {
-            let res_data_json = res_data.data;
-            let ticker_info = res_data_json[0].clone();
-            let time = (Decimal::from_str(&*ticker_info["ts"].as_str().unwrap()).unwrap() / dec!(1000)).floor().to_i64().unwrap();
-            let result = Ticker {
-                time,
-                high: Decimal::from_str(ticker_info["high24h"].as_str().unwrap()).unwrap(),
-                low: Decimal::from_str(ticker_info["low24h"].as_str().unwrap()).unwrap(),
-                sell: Decimal::from_str(ticker_info["askPr"].as_str().unwrap()).unwrap(),
-                buy: Decimal::from_str(ticker_info["bidPr"].as_str().unwrap()).unwrap(),
-                last: Decimal::from_str(ticker_info["lastPr"].as_str().unwrap()).unwrap(),
-                volume: Decimal::from_str(ticker_info["quoteVolume"].as_str().unwrap()).unwrap(),
-            };
-            Ok(result)
-        } else {
-            Err(Error::new(ErrorKind::Other, res_data.to_string()))
-        }
-    }
-
-    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(), "");
-        let response = self.request.get_contracts(symbol_format.clone()).await;
-
-        if response.code == 200 {
-            let res_data_json = response.data.as_array().unwrap();
-            let market_info = res_data_json[0].clone();
-
-            info!(?market_info);
-            if !market_info["symbol"].as_str().unwrap().to_string().eq(&symbol_format) {
-                return Err(Error::new(ErrorKind::NotFound, format!("符号未找到:symbol={}, response={:?}", symbol_format, response))).unwrap();
-            }
-
-            let base_asset = market_info["baseCoin"].as_str().unwrap().to_string();
-            let quote_asset = market_info["quoteCoin"].as_str().unwrap().to_string();
-            let price_precision = Decimal::from_str(market_info["pricePlace"].as_str().unwrap()).unwrap();
-            let tick_size = Decimal::TEN.powd(Decimal::NEGATIVE_ONE * price_precision);
-            let amount_precision = Decimal::from_str(market_info["volumePlace"].as_str().unwrap()).unwrap();
-            let amount_size = Decimal::TEN.powd(Decimal::NEGATIVE_ONE * amount_precision);
-            let min_qty = Decimal::NEGATIVE_ONE;
-            let max_qty = Decimal::NEGATIVE_ONE;
-            // let ct_val = Decimal::from_str(&market_info["sizeMultiplier"].as_str().unwrap()).unwrap();
-            let ct_val = Decimal::ONE;
-
-            let result = Market {
-                symbol: format!("{}_{}", base_asset, quote_asset),
-                base_asset,
-                quote_asset,
-                tick_size,
-                amount_size,
-                price_precision,
-                amount_precision,
-                min_qty,
-                max_qty,
-                min_notional: min_qty,
-                max_notional: max_qty,
-                ct_val,
-            };
-            Ok(result)
-        } else {
-            Err(Error::new(ErrorKind::Other, response.to_string()))
-        }
-    }
-
-    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(), "");
-        let params = json!({
-            "symbol": symbol_format,
-            "productType": "USDT-FUTURES",
-            "clientOid": custom_id,
-            "orderId": order_id
-        });
-
-        let ct_val = self.market.ct_val;
-        let response = self.request.get_order(params).await;
-        if response.code == 200 {
-            let res_data_json = response.data;
-            let result = format_order_item(res_data_json, ct_val);
-            Ok(result)
-        } else {
-            Err(Error::new(ErrorKind::Other, response.to_string()))
-        }
-    }
-
-    async fn get_orders_list(&mut self, _status: &str) -> Result<Vec<Order>, Error> {
-        Err(Error::new(ErrorKind::NotFound, "bitget_swap get_orders_list:该交易所方法未实现".to_string()))
-        // let symbol_format = utils::format_symbol(self.symbol.clone(), "");
-        // let ct_val = self.market.ct_val;
-        // let res_data = self.request.get_unfilled_orders(symbol_format.to_string(), "".to_string(), "".to_string(), "".to_string(), "100".to_string(), "".to_string()).await;
-        // if res_data.code == 200 {
-        //     let res_data_str = &res_data.data;
-        //     let res_data_json: Vec<serde_json::Value> = serde_json::from_str(res_data_str).unwrap();
-        //     let result = res_data_json.iter().map(|item| format_order_item(item.clone(), ct_val)).collect();
-        //     Ok(result)
-        // } else {
-        //     Err(Error::new(ErrorKind::Other, res_data.to_string()))
-        // }
-    }
-
-    async fn take_order(&mut self, custom_id: &str, origin_side: &str, price: Decimal, amount: Decimal) -> Result<Order, Error> {
-        let ct_val = self.market.ct_val;
-
-        return self.take_order_symbol(self.symbol.clone(), 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, "");
-        let final_size = amount / ct_val;
-        let mut params = json!({
-            "symbol": symbol_format,
-            "clientOid": custom_id,
-            "productType": "USDT-FUTURES",
-            "marginMode": "crossed",
-            "marginCoin": "USDT",
-            "size": final_size.to_string()
-        });
-        if price.eq(&Decimal::ZERO) {
-            params["orderType"] = json!("market");
-            params["force"] = json!("gtc");
-        } else {
-            params["price"] = json!(price.to_string());
-            params["orderType"] = json!("limit");
-            params["force"] = json!("gtc");
-        };
-        match origin_side {
-            "kd" => {
-                params["side"] = json!("buy");
-                params["tradeSide"] = json!("open");
-            }
-            "pd" => {
-                params["side"] = json!("buy");
-                params["tradeSide"] = json!("close");
-            }
-            "kk" => {
-                params["side"] = json!("sell");
-                params["tradeSide"] = json!("open");
-            }
-            "pk" => {
-                params["side"] = json!("sell");
-                params["tradeSide"] = json!("close");
-            }
-            _ => { panic!("bitget_usdt_swap 下单参数错误"); }
-        };
-        let res_data = self.request.swap_order(params).await;
-        if res_data.code != 200 {
-            return Err(Error::new(ErrorKind::Other, res_data.to_string()))
-        }
-
-        let res_data_json = res_data.data;
-        let result = Order {
-            id: res_data_json["orderId"].as_str().unwrap().to_string(),
-            custom_id: res_data_json["clientOid"].as_str().unwrap().to_string(),
-            price: Decimal::ZERO,
-            amount: Decimal::ZERO,
-            deal_amount: Decimal::ZERO,
-            avg_price: Decimal::ZERO,
-            status: "NEW".to_string(),
-            order_type: "".to_string(),
-            trace_stack: TraceStack::new(0, Instant::now()).on_special("328 bitget_swap".to_string()),
-        };
-        return Ok(result)
-    }
-
-    async fn cancel_order(&mut self, order_id: &str, custom_id: &str) -> Result<Order, Error> {
-        let symbol_format = utils::format_symbol(self.symbol.clone(), "");
-        let params = json!({
-            "symbol": symbol_format,
-            "productType": "USDT-FUTURES",
-            "clientOid": custom_id,
-            "orderId": order_id
-        });
-        let response = self.request.cancel_order(params).await;
-
-        // 取消失败,进行报错
-        if response.code != 200 {
-            return Err(Error::new(ErrorKind::NotFound, response.to_string()));
-        }
-
-        let res_data_json = response.data;
-        let result = Order {
-            id: res_data_json["orderId"].as_str().unwrap().to_string(),
-            custom_id: res_data_json["clientOid"].as_str().unwrap().to_string(),
-            price: Decimal::ZERO,
-            amount: Decimal::ZERO,
-            deal_amount: Decimal::ZERO,
-            avg_price: Decimal::ZERO,
-            status: "REMOVE".to_string(),
-            order_type: "".to_string(),
-            trace_stack: TraceStack::new(0, Instant::now()).on_special("443 bitget_swap".to_string()),
-        };
-        Ok(result)
-    }
-
-    async fn cancel_orders(&mut self) -> Result<Vec<Order>, Error> {
-        Err(Error::new(ErrorKind::NotFound, "bitget_swap cancel_orders:该交易所方法未实现".to_string()))
-    }
-
-    async fn cancel_orders_all(&mut self) -> Result<Vec<Order>, Error> {
-        let response = self.request.get_pending_orders().await;
-        if response.code == 200 {
-            info!("{}", response.data.to_string());
-            let mut result = vec![];
-
-            if !response.data["entrustedList"].is_null() {
-                let orders_res_data_json = response.data["entrustedList"].as_array().unwrap();
-                for order in orders_res_data_json {
-                    let symbol = order["symbol"].as_str().unwrap().to_string();
-                    let order_id = order["orderId"].as_str().unwrap().to_string();
-                    let params = json!({
-                        "symbol": symbol,
-                        "productType": "USDT-FUTURES",
-                        "orderId": order_id,
-                    });
-                    let cancel_res_data = self.request.cancel_order(params).await;
-                    if cancel_res_data.code == 200 {
-                        let cancel_res_data_json = cancel_res_data.data;
-                        result.push(Order {
-                            id: cancel_res_data_json["orderId"].as_str().unwrap().to_string(),
-                            custom_id: cancel_res_data_json["clientOid"].as_str().unwrap().to_string(),
-                            price: Decimal::ZERO,
-                            amount: Decimal::ZERO,
-                            deal_amount: Decimal::ZERO,
-                            avg_price: Decimal::ZERO,
-                            status: "REMOVE".to_string(),
-                            order_type: "".to_string(),
-                            trace_stack: TraceStack::new(0, Instant::now()).on_special("457 bitget_swap".to_string()),
-                        });
-                    } else {
-                        return Err(Error::new(ErrorKind::Other, cancel_res_data.to_string()));
-                    }
-                }
-            }
-            Ok(result)
-        } else {
-            Err(Error::new(ErrorKind::Other, response.to_string()))
-        }
-    }
-
-    async fn take_stop_loss_order(&mut self, _stop_price: Decimal, _price: Decimal, _side: &str) -> Result<Value, Error> {
-        Err(Error::new(ErrorKind::NotFound, "bitget_swap take_stop_loss_order:该交易所方法未实现".to_string()))
-    }
-
-    async fn cancel_stop_loss_order(&mut self, _order_id: &str) -> Result<Value, Error> {
-        Err(Error::new(ErrorKind::NotFound, "bitget_swap cancel_stop_loss_order:该交易所方法未实现".to_string()))
-    }
-
-    async fn set_dual_mode(&mut self, _coin: &str, is_dual_mode: bool) -> Result<String, Error> {
-        let pos_mode = if is_dual_mode {
-            "hedge_mode"
-        } else {
-            "one_way_mode"
-        };
-        let params = json!({
-            "productType": "USDT-FUTURES",
-            "posMode": pos_mode,
-        });
-        let response = self.request.set_position_mode(params).await;
-
-        if response.code != 200 {
-            return Err(Error::new(ErrorKind::Other, format!("设置持仓模式失败:{:?}", response).to_string()))
-        }
-
-        return Ok(response.data.to_string());
-    }
-
-    async fn set_dual_leverage(&mut self, leverage: &str) -> Result<String, Error> {
-        let params = json!({
-            "symbol": "ETHUSDT",
-            "productType": "USDT-FUTURES",
-            "marginCoin": "USDT",
-            "leverage": leverage
-        });
-        let response = self.request.set_leverage(params).await;
-
-        if response.code != 200 {
-            return Err(Error::new(ErrorKind::Other, format!("设置杠杆失败:{:?}", response).to_string()))
-        }
-
-        return Ok(response.data.to_string());
-    }
-
-    async fn set_auto_deposit_status(&mut self, _status: bool) -> Result<String, Error> {
-        Err(Error::new(ErrorKind::NotFound, "bitget_swap set_auto_deposit_status:该交易所方法未实现".to_string()))
-    }
-
-    async fn wallet_transfers(&mut self, _coin: &str, _from: &str, _to: &str, _amount: Decimal) -> Result<String, Error> {
-        Err(Error::new(ErrorKind::NotFound, "bitget_swap wallet_transfers:该交易所方法未实现".to_string()))
-        // let coin_format = coin.to_string().to_uppercase();
-        // let res_data = self.request.wallet_transfer(from.to_string(), to.to_string(), amount.to_string(), coin_format.clone(), "".to_string(), "".to_string()).await;
-        // if res_data.code == 200 {
-        //     let res_data_str = &res_data.data;
-        //     let result = res_data_str.clone();
-        //     Ok(result)
-        // } else {
-        //     Err(Error::new(ErrorKind::Other, res_data.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 {
-                // TraceStack::show_delay(&ts.ins);
-                ts.on_before_send();
-                let result = self_clone.take_order(cid.as_str(), side.as_str(), price, amount).await;
-                ts.on_after_send();
-
-                match result {
-                    Ok(mut result) => {
-                        result.trace_stack = ts;
-
-                        self_clone.order_sender.send(result).await.unwrap();
-                    }
-                    Err(error) => {
-                        info!(?error);
-                        let mut err_order = Order::new();
-                        err_order.custom_id = cid.clone();
-                        err_order.status = "REMOVE".to_string();
-
-                        self_clone.order_sender.send(err_order).await.unwrap();
-                        self_clone.error_sender.send(error).await.unwrap();
-                    }
-                }
-            });
-            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(_) => {
-                        // result_sd.send(result).await.unwrap();
-                    }
-                    Err(error) => {
-                        // 取消失败去查订单。
-                        let query_rst = self_clone.get_order_detail(&order_id, &custom_id).await;
-                        match query_rst {
-                            Ok(order) => {
-                                self_clone.order_sender.send(order).await.unwrap();
-                            }
-                            Err(err) => {
-                                error!("撤单失败,而且查单也失败了,bitget_swap,oid={}, cid={}, err={:?}。", order_id.clone(), custom_id.clone(), err);
-                            }
-                        }
-                        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.as_str(), custom_id.as_str()).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_account_info(balance_data: Value) -> Account {
-//     let balance_coin = balance_data["coin"].as_str().unwrap().to_string().to_uppercase();
-//     let available_balance = Decimal::from_str(balance_data["available"].as_str().unwrap()).unwrap();
-//     let frozen_balance = Decimal::from_str(balance_data["frozen"].as_str().unwrap()).unwrap();
-//     let balance = available_balance + frozen_balance;
-//
-//     Account {
-//         coin: balance_coin,
-//         balance,
-//         available_balance,
-//         frozen_balance,
-//         stocks: Decimal::ZERO,
-//         available_stocks: Decimal::ZERO,
-//         frozen_stocks: Decimal::ZERO,
+// use std::collections::{BTreeMap};
+// use exchanges::bitget_swap_rest::BitgetSwapRest;
+// use std::io::{Error, ErrorKind};
+// use tokio::sync::mpsc::Sender;
+// use std::str::FromStr;
+// use async_trait::async_trait;
+// use futures::stream::FuturesUnordered;
+// use futures::TryStreamExt;
+// use rust_decimal::{Decimal, MathematicalOps};
+// use rust_decimal::prelude::ToPrimitive;
+// use rust_decimal_macros::dec;
+// use serde_json::{json, Value};
+// use tokio::spawn;
+// use tokio::time::Instant;
+// use tracing::{error, info};
+// use global::trace_stack::TraceStack;
+// use crate::exchange::ExchangeEnum;
+// use crate::{Account, Market, Order, OrderCommand, Platform, Position, PositionModeEnum, Ticker, utils};
+//
+// #[allow(dead_code)]
+// #[derive(Clone)]
+// pub struct BitgetSwap {
+//     exchange: ExchangeEnum,
+//     symbol: String,
+//     is_colo: bool,
+//     params: BTreeMap<String, String>,
+//     request: BitgetSwapRest,
+//     market: Market,
+//     order_sender: Sender<Order>,
+//     error_sender: Sender<Error>,
+// }
+//
+// impl BitgetSwap {
+//     pub async fn new(symbol: String, is_colo: bool, params: BTreeMap<String, String>, order_sender: Sender<Order>, error_sender: Sender<Error>) -> BitgetSwap {
+//         let market = Market::new();
+//         let mut bitget_swap = BitgetSwap {
+//             exchange: ExchangeEnum::BitgetSwap,
+//             symbol: symbol.to_uppercase(),
+//             is_colo,
+//             params: params.clone(),
+//             request: BitgetSwapRest::new(is_colo, params.clone()),
+//             market,
+//             order_sender,
+//             error_sender,
+//         };
+//         bitget_swap.market = BitgetSwap::get_market(&mut bitget_swap).await.unwrap();
+//         // 修改持仓模式
+//         let mode_result = bitget_swap.set_dual_mode("", true).await;
+//         match mode_result {
+//             Ok(ok) => {
+//                 info!("BitgetSwap:设置持仓模式成功!{:?}", ok);
+//             }
+//             Err(error) => {
+//                 error!("BitgetSwap:设置持仓模式失败!{:?}", error)
+//             }
+//         }
+//         // 设置持仓杠杆
+//         // let lever_rate_result = bitget_swap.set_dual_leverage("10").await;
+//         // match lever_rate_result {
+//         //     Ok(ok) => {
+//         //         info!("BitgetSwap:设置持仓杠杆成功!{:?}", ok);
+//         //     }
+//         //     Err(error) => {
+//         //         error!("BitgetSwap:设置持仓杠杆失败!{:?}", error)
+//         //     }
+//         // }
+//
+//         return bitget_swap;
+//     }
+// }
+//
+// #[async_trait]
+// impl Platform for BitgetSwap {
+//     fn clone_box(&self) -> Box<dyn Platform + Send + Sync> { Box::new(self.clone()) }
+//
+//     fn get_self_exchange(&self) -> ExchangeEnum { ExchangeEnum::BitgetSwap }
+//
+//     fn get_self_symbol(&self) -> String { self.symbol.clone() }
+//
+//     fn get_self_is_colo(&self) -> bool { self.is_colo }
+//
+//     fn get_self_params(&self) -> BTreeMap<String, String> { self.params.clone() }
+//
+//     fn get_self_market(&self) -> Market { self.market.clone() }
+//
+//     fn get_request_delays(&self) -> Vec<i64> {
+//         // self.request.get_delays()
+//         vec![]
+//     }
+//
+//     fn get_request_avg_delay(&self) -> Decimal {
+//         // self.request.get_avg_delay()
+//         Decimal::ZERO
+//     }
+//
+//     fn get_request_max_delay(&self) -> i64 { 0 }
+//
+//     async fn get_server_time(&mut self) -> Result<String, Error> {
+//         let res_data = self.request.get_server_time().await;
+//         if res_data.code == 200 {
+//             let res_data_json = res_data.data;
+//             let result = res_data_json["serverTime"].as_str().unwrap().to_string();
+//             Ok(result)
+//         } else {
+//             Err(Error::new(ErrorKind::Other, res_data.to_string()))
+//         }
+//     }
+//
+//     async fn get_account(&mut self) -> Result<Account, Error> {
+//         let response = self.request.get_account_info().await;
+//
+//         if response.code == 200 {
+//             for data in response.data.as_array().unwrap() {
+//                 if data["marginCoin"].as_str().unwrap() != "USDT" {
+//                     continue
+//                 }
+//
+//                 // 格式化account信息
+//                 let mut account = Account {
+//                     coin: data["marginCoin"].to_string(),
+//                     balance: Decimal::from_str(data["accountEquity"].as_str().unwrap()).unwrap(),
+//                     available_balance: Decimal::from_str(data["available"].as_str().unwrap()).unwrap(),
+//                     frozen_balance: Default::default(),
+//                     stocks: Default::default(),
+//                     available_stocks: Default::default(),
+//                     frozen_stocks: Default::default(),
+//                 };
+//                 account.frozen_balance = account.balance - account.available_balance;
+//
+//                 return Ok(account)
+//             }
+//
+//             Err(Error::new(ErrorKind::NotFound, format!("bitget_usdt_swap 未能找到USDT账户:{}。", response.to_string())))
+//         } else {
+//             Err(Error::new(ErrorKind::Other, response.to_string()))
+//         }
+//     }
+//
+//     async fn get_spot_account(&mut self) -> Result<Vec<Account>, Error> {
+//         Err(Error::new(ErrorKind::NotFound, "bitget_swap get_spot_account:该交易所方法未实现".to_string()))
+//     }
+//
+//     async fn get_position(&mut self) -> Result<Vec<Position>, Error> { Err(Error::new(ErrorKind::NotFound, "bitget_swap get_position:该交易所方法未实现".to_string())) }
+//
+//     async fn get_positions(&mut self) -> Result<Vec<Position>, Error> {
+//         let params = json!({
+//             "productType": "USDT-FUTURES",
+//             "marginCoin": "USDT"
+//         });
+//         let response = self.request.get_all_position(params).await;
+//         info!(?response);
+//
+//         if response.code != 200 {
+//             return Err(Error::new(ErrorKind::NotFound, format!("bitget_swap 获取仓位异常{:?}", response).to_string()))
+//         }
+//
+//         // 正常处理持仓信息
+//         let mut positions: Vec<Position> = vec![];
+//         if response.data.is_null() {
+//             return Ok(positions)
+//         }
+//
+//         let positions_json = response.data.as_array().unwrap();
+//         for position_json in positions_json {
+//             let symbol = position_json["symbol"].as_str().unwrap().to_string();
+//             let margin_level = Decimal::from_str(position_json["leverage"].as_str().unwrap()).unwrap();
+//             let amount = Decimal::from_str(position_json["total"].as_str().unwrap()).unwrap();
+//             let frozen_amount = Decimal::from_str(position_json["locked"].as_str().unwrap()).unwrap();
+//             let price = Decimal::from_str(position_json["openPriceAvg"].as_str().unwrap()).unwrap();
+//             let profit = Decimal::from_str(position_json["unrealizedPL"].as_str().unwrap()).unwrap();
+//             let position_mode = match position_json["posMode"].as_str().unwrap() {
+//                 "hedge_mode" => {
+//                     match position_json["holdSide"].as_str().unwrap() {
+//                         "short" => {
+//                             PositionModeEnum::Short
+//                         }
+//                         "long" => {
+//                             PositionModeEnum::Long
+//                         },
+//                         _ => {
+//                             panic!("bitget_usdt_swap: 未知的持仓模式与持仓方向: {}, {}",
+//                                    position_json["posMode"].as_str().unwrap(), position_json["holdSide"].as_str().unwrap())
+//                         }
+//                     }
+//                 },
+//                 "one_way_mode" => {
+//                     PositionModeEnum::Both
+//                 },
+//                 _ => {
+//                     panic!("bitget_usdt_swap: 未知的持仓模式: {}", position_json["posMode"].as_str().unwrap())
+//                 }
+//             };
+//             let margin = Decimal::from_str(position_json["marginSize"].as_str().unwrap()).unwrap();
+//
+//             positions.push(Position {
+//                 symbol,
+//                 margin_level,
+//                 amount,
+//                 frozen_amount,
+//                 price,
+//                 profit,
+//                 position_mode,
+//                 margin,
+//             });
+//         }
+//
+//         Ok(positions)
+//     }
+//
+//     async fn get_ticker(&mut self) -> Result<Ticker, Error> {
+//         return 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(), "");
+//         let res_data = self.request.get_tickers(symbol_format).await;
+//         if res_data.code == 200 {
+//             let res_data_json = res_data.data;
+//             let ticker_info = res_data_json[0].clone();
+//             let time = (Decimal::from_str(&*ticker_info["ts"].as_str().unwrap()).unwrap() / dec!(1000)).floor().to_i64().unwrap();
+//             let result = Ticker {
+//                 time,
+//                 high: Decimal::from_str(ticker_info["high24h"].as_str().unwrap()).unwrap(),
+//                 low: Decimal::from_str(ticker_info["low24h"].as_str().unwrap()).unwrap(),
+//                 sell: Decimal::from_str(ticker_info["askPr"].as_str().unwrap()).unwrap(),
+//                 buy: Decimal::from_str(ticker_info["bidPr"].as_str().unwrap()).unwrap(),
+//                 last: Decimal::from_str(ticker_info["lastPr"].as_str().unwrap()).unwrap(),
+//                 volume: Decimal::from_str(ticker_info["quoteVolume"].as_str().unwrap()).unwrap(),
+//             };
+//             Ok(result)
+//         } else {
+//             Err(Error::new(ErrorKind::Other, res_data.to_string()))
+//         }
+//     }
+//
+//     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(), "");
+//         let response = self.request.get_contracts(symbol_format.clone()).await;
+//
+//         if response.code == 200 {
+//             let res_data_json = response.data.as_array().unwrap();
+//             let market_info = res_data_json[0].clone();
+//
+//             info!(?market_info);
+//             if !market_info["symbol"].as_str().unwrap().to_string().eq(&symbol_format) {
+//                 return Err(Error::new(ErrorKind::NotFound, format!("符号未找到:symbol={}, response={:?}", symbol_format, response))).unwrap();
+//             }
+//
+//             let base_asset = market_info["baseCoin"].as_str().unwrap().to_string();
+//             let quote_asset = market_info["quoteCoin"].as_str().unwrap().to_string();
+//             let price_precision = Decimal::from_str(market_info["pricePlace"].as_str().unwrap()).unwrap();
+//             let tick_size = Decimal::TEN.powd(Decimal::NEGATIVE_ONE * price_precision);
+//             let amount_precision = Decimal::from_str(market_info["volumePlace"].as_str().unwrap()).unwrap();
+//             let amount_size = Decimal::TEN.powd(Decimal::NEGATIVE_ONE * amount_precision);
+//             let min_qty = Decimal::NEGATIVE_ONE;
+//             let max_qty = Decimal::NEGATIVE_ONE;
+//             // let ct_val = Decimal::from_str(&market_info["sizeMultiplier"].as_str().unwrap()).unwrap();
+//             let ct_val = Decimal::ONE;
+//
+//             let result = Market {
+//                 symbol: format!("{}_{}", base_asset, quote_asset),
+//                 base_asset,
+//                 quote_asset,
+//                 tick_size,
+//                 amount_size,
+//                 price_precision,
+//                 amount_precision,
+//                 min_qty,
+//                 max_qty,
+//                 min_notional: min_qty,
+//                 max_notional: max_qty,
+//                 ct_val,
+//             };
+//             Ok(result)
+//         } else {
+//             Err(Error::new(ErrorKind::Other, response.to_string()))
+//         }
+//     }
+//
+//     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(), "");
+//         let params = json!({
+//             "symbol": symbol_format,
+//             "productType": "USDT-FUTURES",
+//             "clientOid": custom_id,
+//             "orderId": order_id
+//         });
+//
+//         let ct_val = self.market.ct_val;
+//         let response = self.request.get_order(params).await;
+//         if response.code == 200 {
+//             let res_data_json = response.data;
+//             let result = format_order_item(res_data_json, ct_val);
+//             Ok(result)
+//         } else {
+//             Err(Error::new(ErrorKind::Other, response.to_string()))
+//         }
+//     }
+//
+//     async fn get_orders_list(&mut self, _status: &str) -> Result<Vec<Order>, Error> {
+//         Err(Error::new(ErrorKind::NotFound, "bitget_swap get_orders_list:该交易所方法未实现".to_string()))
+//         // let symbol_format = utils::format_symbol(self.symbol.clone(), "");
+//         // let ct_val = self.market.ct_val;
+//         // let res_data = self.request.get_unfilled_orders(symbol_format.to_string(), "".to_string(), "".to_string(), "".to_string(), "100".to_string(), "".to_string()).await;
+//         // if res_data.code == 200 {
+//         //     let res_data_str = &res_data.data;
+//         //     let res_data_json: Vec<serde_json::Value> = serde_json::from_str(res_data_str).unwrap();
+//         //     let result = res_data_json.iter().map(|item| format_order_item(item.clone(), ct_val)).collect();
+//         //     Ok(result)
+//         // } else {
+//         //     Err(Error::new(ErrorKind::Other, res_data.to_string()))
+//         // }
+//     }
+//
+//     async fn take_order(&mut self, custom_id: &str, origin_side: &str, price: Decimal, amount: Decimal) -> Result<Order, Error> {
+//         let ct_val = self.market.ct_val;
+//
+//         return self.take_order_symbol(self.symbol.clone(), 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, "");
+//         let final_size = amount / ct_val;
+//         let mut params = json!({
+//             "symbol": symbol_format,
+//             "clientOid": custom_id,
+//             "productType": "USDT-FUTURES",
+//             "marginMode": "crossed",
+//             "marginCoin": "USDT",
+//             "size": final_size.to_string()
+//         });
+//         if price.eq(&Decimal::ZERO) {
+//             params["orderType"] = json!("market");
+//             params["force"] = json!("gtc");
+//         } else {
+//             params["price"] = json!(price.to_string());
+//             params["orderType"] = json!("limit");
+//             params["force"] = json!("gtc");
+//         };
+//         match origin_side {
+//             "kd" => {
+//                 params["side"] = json!("buy");
+//                 params["tradeSide"] = json!("open");
+//             }
+//             "pd" => {
+//                 params["side"] = json!("buy");
+//                 params["tradeSide"] = json!("close");
+//             }
+//             "kk" => {
+//                 params["side"] = json!("sell");
+//                 params["tradeSide"] = json!("open");
+//             }
+//             "pk" => {
+//                 params["side"] = json!("sell");
+//                 params["tradeSide"] = json!("close");
+//             }
+//             _ => { panic!("bitget_usdt_swap 下单参数错误"); }
+//         };
+//         let res_data = self.request.swap_order(params).await;
+//         if res_data.code != 200 {
+//             return Err(Error::new(ErrorKind::Other, res_data.to_string()))
+//         }
+//
+//         let res_data_json = res_data.data;
+//         let result = Order {
+//             id: res_data_json["orderId"].as_str().unwrap().to_string(),
+//             custom_id: res_data_json["clientOid"].as_str().unwrap().to_string(),
+//             price: Decimal::ZERO,
+//             amount: Decimal::ZERO,
+//             deal_amount: Decimal::ZERO,
+//             avg_price: Decimal::ZERO,
+//             status: "NEW".to_string(),
+//             order_type: "".to_string(),
+//             trace_stack: TraceStack::new(0, Instant::now()).on_special("328 bitget_swap".to_string()),
+//         };
+//         return Ok(result)
+//     }
+//
+//     async fn cancel_order(&mut self, order_id: &str, custom_id: &str) -> Result<Order, Error> {
+//         let symbol_format = utils::format_symbol(self.symbol.clone(), "");
+//         let params = json!({
+//             "symbol": symbol_format,
+//             "productType": "USDT-FUTURES",
+//             "clientOid": custom_id,
+//             "orderId": order_id
+//         });
+//         let response = self.request.cancel_order(params).await;
+//
+//         // 取消失败,进行报错
+//         if response.code != 200 {
+//             return Err(Error::new(ErrorKind::NotFound, response.to_string()));
+//         }
+//
+//         let res_data_json = response.data;
+//         let result = Order {
+//             id: res_data_json["orderId"].as_str().unwrap().to_string(),
+//             custom_id: res_data_json["clientOid"].as_str().unwrap().to_string(),
+//             price: Decimal::ZERO,
+//             amount: Decimal::ZERO,
+//             deal_amount: Decimal::ZERO,
+//             avg_price: Decimal::ZERO,
+//             status: "REMOVE".to_string(),
+//             order_type: "".to_string(),
+//             trace_stack: TraceStack::new(0, Instant::now()).on_special("443 bitget_swap".to_string()),
+//         };
+//         Ok(result)
+//     }
+//
+//     async fn cancel_orders(&mut self) -> Result<Vec<Order>, Error> {
+//         Err(Error::new(ErrorKind::NotFound, "bitget_swap cancel_orders:该交易所方法未实现".to_string()))
+//     }
+//
+//     async fn cancel_orders_all(&mut self) -> Result<Vec<Order>, Error> {
+//         let response = self.request.get_pending_orders().await;
+//         if response.code == 200 {
+//             info!("{}", response.data.to_string());
+//             let mut result = vec![];
+//
+//             if !response.data["entrustedList"].is_null() {
+//                 let orders_res_data_json = response.data["entrustedList"].as_array().unwrap();
+//                 for order in orders_res_data_json {
+//                     let symbol = order["symbol"].as_str().unwrap().to_string();
+//                     let order_id = order["orderId"].as_str().unwrap().to_string();
+//                     let params = json!({
+//                         "symbol": symbol,
+//                         "productType": "USDT-FUTURES",
+//                         "orderId": order_id,
+//                     });
+//                     let cancel_res_data = self.request.cancel_order(params).await;
+//                     if cancel_res_data.code == 200 {
+//                         let cancel_res_data_json = cancel_res_data.data;
+//                         result.push(Order {
+//                             id: cancel_res_data_json["orderId"].as_str().unwrap().to_string(),
+//                             custom_id: cancel_res_data_json["clientOid"].as_str().unwrap().to_string(),
+//                             price: Decimal::ZERO,
+//                             amount: Decimal::ZERO,
+//                             deal_amount: Decimal::ZERO,
+//                             avg_price: Decimal::ZERO,
+//                             status: "REMOVE".to_string(),
+//                             order_type: "".to_string(),
+//                             trace_stack: TraceStack::new(0, Instant::now()).on_special("457 bitget_swap".to_string()),
+//                         });
+//                     } else {
+//                         return Err(Error::new(ErrorKind::Other, cancel_res_data.to_string()));
+//                     }
+//                 }
+//             }
+//             Ok(result)
+//         } else {
+//             Err(Error::new(ErrorKind::Other, response.to_string()))
+//         }
+//     }
+//
+//     async fn take_stop_loss_order(&mut self, _stop_price: Decimal, _price: Decimal, _side: &str) -> Result<Value, Error> {
+//         Err(Error::new(ErrorKind::NotFound, "bitget_swap take_stop_loss_order:该交易所方法未实现".to_string()))
+//     }
+//
+//     async fn cancel_stop_loss_order(&mut self, _order_id: &str) -> Result<Value, Error> {
+//         Err(Error::new(ErrorKind::NotFound, "bitget_swap cancel_stop_loss_order:该交易所方法未实现".to_string()))
+//     }
+//
+//     async fn set_dual_mode(&mut self, _coin: &str, is_dual_mode: bool) -> Result<String, Error> {
+//         let pos_mode = if is_dual_mode {
+//             "hedge_mode"
+//         } else {
+//             "one_way_mode"
+//         };
+//         let params = json!({
+//             "productType": "USDT-FUTURES",
+//             "posMode": pos_mode,
+//         });
+//         let response = self.request.set_position_mode(params).await;
+//
+//         if response.code != 200 {
+//             return Err(Error::new(ErrorKind::Other, format!("设置持仓模式失败:{:?}", response).to_string()))
+//         }
+//
+//         return Ok(response.data.to_string());
+//     }
+//
+//     async fn set_dual_leverage(&mut self, leverage: &str) -> Result<String, Error> {
+//         let params = json!({
+//             "symbol": "ETHUSDT",
+//             "productType": "USDT-FUTURES",
+//             "marginCoin": "USDT",
+//             "leverage": leverage
+//         });
+//         let response = self.request.set_leverage(params).await;
+//
+//         if response.code != 200 {
+//             return Err(Error::new(ErrorKind::Other, format!("设置杠杆失败:{:?}", response).to_string()))
+//         }
+//
+//         return Ok(response.data.to_string());
+//     }
+//
+//     async fn set_auto_deposit_status(&mut self, _status: bool) -> Result<String, Error> {
+//         Err(Error::new(ErrorKind::NotFound, "bitget_swap set_auto_deposit_status:该交易所方法未实现".to_string()))
+//     }
+//
+//     async fn wallet_transfers(&mut self, _coin: &str, _from: &str, _to: &str, _amount: Decimal) -> Result<String, Error> {
+//         Err(Error::new(ErrorKind::NotFound, "bitget_swap wallet_transfers:该交易所方法未实现".to_string()))
+//         // let coin_format = coin.to_string().to_uppercase();
+//         // let res_data = self.request.wallet_transfer(from.to_string(), to.to_string(), amount.to_string(), coin_format.clone(), "".to_string(), "".to_string()).await;
+//         // if res_data.code == 200 {
+//         //     let res_data_str = &res_data.data;
+//         //     let result = res_data_str.clone();
+//         //     Ok(result)
+//         // } else {
+//         //     Err(Error::new(ErrorKind::Other, res_data.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 {
+//                 // TraceStack::show_delay(&ts.ins);
+//                 ts.on_before_send();
+//                 let result = self_clone.take_order(cid.as_str(), side.as_str(), price, amount).await;
+//                 ts.on_after_send();
+//
+//                 match result {
+//                     Ok(mut result) => {
+//                         result.trace_stack = ts;
+//
+//                         self_clone.order_sender.send(result).await.unwrap();
+//                     }
+//                     Err(error) => {
+//                         info!(?error);
+//                         let mut err_order = Order::new();
+//                         err_order.custom_id = cid.clone();
+//                         err_order.status = "REMOVE".to_string();
+//
+//                         self_clone.order_sender.send(err_order).await.unwrap();
+//                         self_clone.error_sender.send(error).await.unwrap();
+//                     }
+//                 }
+//             });
+//             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(_) => {
+//                         // result_sd.send(result).await.unwrap();
+//                     }
+//                     Err(error) => {
+//                         // 取消失败去查订单。
+//                         let query_rst = self_clone.get_order_detail(&order_id, &custom_id).await;
+//                         match query_rst {
+//                             Ok(order) => {
+//                                 self_clone.order_sender.send(order).await.unwrap();
+//                             }
+//                             Err(err) => {
+//                                 error!("撤单失败,而且查单也失败了,bitget_swap,oid={}, cid={}, err={:?}。", order_id.clone(), custom_id.clone(), err);
+//                             }
+//                         }
+//                         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.as_str(), custom_id.as_str()).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_account_info(balance_data: Value) -> Account {
+// //     let balance_coin = balance_data["coin"].as_str().unwrap().to_string().to_uppercase();
+// //     let available_balance = Decimal::from_str(balance_data["available"].as_str().unwrap()).unwrap();
+// //     let frozen_balance = Decimal::from_str(balance_data["frozen"].as_str().unwrap()).unwrap();
+// //     let balance = available_balance + frozen_balance;
+// //
+// //     Account {
+// //         coin: balance_coin,
+// //         balance,
+// //         available_balance,
+// //         frozen_balance,
+// //         stocks: Decimal::ZERO,
+// //         available_stocks: Decimal::ZERO,
+// //         frozen_stocks: Decimal::ZERO,
+// //     }
+// // }
+//
+// pub fn format_order_item(order: Value, ct_val: Decimal) -> Order {
+//     let price = Decimal::from_str(order["price"].as_str().unwrap_or(order["priceAvg"].as_str().unwrap())).unwrap();
+//     let size = Decimal::from_str(order["size"].as_str().unwrap()).unwrap();
+//     let status = order["state"].as_str().unwrap();
+//     let base_volume = Decimal::from_str(order["quoteVolume"].as_str().unwrap()).unwrap();
+//     let avg_price = if order["priceAvg"].is_null() || order["priceAvg"].as_str().unwrap().is_empty() {
+//         Decimal::ZERO
+//     } else {
+//         Decimal::from_str(order["priceAvg"].as_str().unwrap().to_string().as_str()).unwrap()
+//     };
+//
+//     let amount = size * ct_val;
+//     let deal_amount = base_volume * ct_val;
+//     let custom_status = if ["filled", "cancelled"].contains(&status) {
+//         "REMOVE".to_string()
+//     } else if ["init", "live", "new", "partially_filled"].contains(&status) {
+//         "NEW".to_string()
+//     } else {
+//         "NULL".to_string()
+//     };
+//     Order {
+//         id: order["orderId"].as_str().unwrap().to_string(),
+//         custom_id: order["clientOid"].as_str().unwrap().to_string(),
+//         price,
+//         amount,
+//         deal_amount,
+//         avg_price,
+//         status: custom_status,
+//         order_type: order["orderType"].as_str().unwrap().to_string(),
+//         trace_stack: TraceStack::new(0, Instant::now()).on_special("700 bitget_swap".to_string()),
 //     }
 // }
-
-pub fn format_order_item(order: Value, ct_val: Decimal) -> Order {
-    let price = Decimal::from_str(order["price"].as_str().unwrap_or(order["priceAvg"].as_str().unwrap())).unwrap();
-    let size = Decimal::from_str(order["size"].as_str().unwrap()).unwrap();
-    let status = order["state"].as_str().unwrap();
-    let base_volume = Decimal::from_str(order["quoteVolume"].as_str().unwrap()).unwrap();
-    let avg_price = if order["priceAvg"].is_null() || order["priceAvg"].as_str().unwrap().is_empty() {
-        Decimal::ZERO
-    } else {
-        Decimal::from_str(order["priceAvg"].as_str().unwrap().to_string().as_str()).unwrap()
-    };
-
-    let amount = size * ct_val;
-    let deal_amount = base_volume * ct_val;
-    let custom_status = if ["filled", "cancelled"].contains(&status) {
-        "REMOVE".to_string()
-    } else if ["init", "live", "new", "partially_filled"].contains(&status) {
-        "NEW".to_string()
-    } else {
-        "NULL".to_string()
-    };
-    Order {
-        id: order["orderId"].as_str().unwrap().to_string(),
-        custom_id: order["clientOid"].as_str().unwrap().to_string(),
-        price,
-        amount,
-        deal_amount,
-        avg_price,
-        status: custom_status,
-        order_type: order["orderType"].as_str().unwrap().to_string(),
-        trace_stack: TraceStack::new(0, Instant::now()).on_special("700 bitget_swap".to_string()),
-    }
-}

+ 220 - 177
standard/src/bitget_swap_handle.rs

@@ -1,181 +1,224 @@
-use std::str::FromStr;
-use rust_decimal::Decimal;
-use rust_decimal::prelude::FromPrimitive;
-use serde_json::Value;
-use tokio::time::Instant;
-use exchanges::response_base::ResponseData;
-use global::trace_stack::TraceStack;
-use crate::{Account, MarketOrder, Order, Position, PositionModeEnum, SpecialOrder};
-
-// 处理账号信息
-pub fn handle_account_info(response: &ResponseData, _symbol: &String) -> Account {
-    let mut rst = Account::new();
-
-    for data in response.data.as_array().unwrap() {
-        if data["marginCoin"].as_str().unwrap() != "USDT" {
-            continue
-        }
-
-        // 格式化account信息
-        let mut account = Account {
-            coin: data["marginCoin"].to_string(),
-            balance: Decimal::from_str(data["usdtEquity"].as_str().unwrap()).unwrap(),
-            available_balance: Decimal::from_str(data["available"].as_str().unwrap()).unwrap(),
-            frozen_balance: Decimal::from_str(data["frozen"].as_str().unwrap()).unwrap(),
-            stocks: Default::default(),
-            available_stocks: Default::default(),
-            frozen_stocks: Default::default(),
-        };
-        account.frozen_balance = account.balance - account.available_balance;
-
-        rst = account
-    }
-
-    return rst;
-}
-
-// 处理order信息
-pub fn handle_order(res_data: ResponseData, ct_val: Decimal) -> SpecialOrder {
-    let res_data_json = res_data.data.as_array().unwrap();
-    let mut order_info = Vec::new();
-    for item in res_data_json.iter() {
-        order_info.push(format_order_item(item.clone(), ct_val));
-    }
-    SpecialOrder {
-        name: res_data.label,
-        order: order_info,
-    }
-}
-
-// 处理订单信息
-pub fn format_order_item(order: Value, ct_val: Decimal) -> Order {
-    let price = Decimal::from_str(order["price"].as_str().unwrap().to_string().as_str()).unwrap();
-    let size = Decimal::from_str(order["size"].as_str().unwrap().to_string().as_str()).unwrap();
-    let binding = order["status"].clone().as_str().unwrap().to_string();
-    let status = binding.as_str();
-    let acc_base_volume = Decimal::from_str(order["accBaseVolume"].as_str().unwrap().to_string().as_str()).unwrap();
-    let avg_price = if order["priceAvg"].is_null() || order["priceAvg"].as_str().unwrap().is_empty() {
-        Decimal::ZERO
-    } else {
-        Decimal::from_str(order["priceAvg"].as_str().unwrap().to_string().as_str()).unwrap()
-    };
-    let c_id = if order["clientOid"].is_null() {
-        ""
-    } else {
-        order["clientOid"].as_str().unwrap()
-    };
-
-    let amount = size * ct_val;
-    let deal_amount = acc_base_volume * ct_val;
-    let custom_status = if ["filled", "canceled"].contains(&status) {
-        "REMOVE".to_string()
-    } else if ["init", "live", "new", "partially_filled"].contains(&status) {
-        "NEW".to_string()
-    } else {
-        "NULL".to_string()
-    };
-    Order {
-        id: order["orderId"].as_str().unwrap().to_string(),
-        custom_id: c_id.to_string(),
-        price,
-        amount,
-        deal_amount,
-        avg_price,
-        status: custom_status,
-        order_type: order["orderType"].as_str().unwrap().to_string(),
-        trace_stack: TraceStack::new(0, Instant::now()).on_special("86 bitget_swap_handle".to_string()),
-    }
-}
-
-// 格式化深度信息
-pub fn format_depth_items(value: Value) -> Vec<MarketOrder> {
-    let mut depth_items: Vec<MarketOrder> = vec![];
-    for value in value.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;
-}
-
-// 处理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_json: &Value, ct_val: &Decimal) -> Position {
-    let symbol = position_json["instId"].as_str().unwrap().to_string();
-    let margin_level = Decimal::from_i64(position_json["leverage"].as_i64().unwrap()).unwrap();
-    let amount = Decimal::from_str(position_json["total"].as_str().unwrap()).unwrap() * ct_val;
-    let frozen_amount = Decimal::from_str(position_json["frozen"].as_str().unwrap()).unwrap() * ct_val;
-    let price = Decimal::from_str(position_json["openPriceAvg"].as_str().unwrap()).unwrap();
-    let profit = Decimal::from_str(position_json["unrealizedPL"].as_str().unwrap()).unwrap();
-    let position_mode = match position_json["posMode"].as_str().unwrap() {
-        "hedge_mode" => {
-            match position_json["holdSide"].as_str().unwrap() {
-                "short" => {
-                    PositionModeEnum::Short
-                }
-                "long" => {
-                    PositionModeEnum::Long
-                },
-                _ => {
-                    panic!("bitget_usdt_swap: 未知的持仓模式与持仓方向: {}, {}",
-                           position_json["posMode"].as_str().unwrap(), position_json["holdSide"].as_str().unwrap())
-                }
-            }
-        },
-        "one_way_mode" => {
-            PositionModeEnum::Both
-        },
-        _ => {
-            panic!("bitget_usdt_swap: 未知的持仓模式: {}", position_json["posMode"].as_str().unwrap())
-        }
-    };
-    let margin = Decimal::from_str(position_json["marginSize"].as_str().unwrap()).unwrap();
-
-    Position {
-        symbol,
-        margin_level,
-        amount,
-        frozen_amount,
-        price,
-        profit,
-        position_mode,
-        margin,
-    }
-}
-
-// 处理特殊深度数据
-// pub fn handle_special_depth(res_data: ResponseData) -> SpecialDepth {
-//     HandleSwapInfo::handle_special_depth(ExchangeEnum::BitgetSwap, res_data)
+// use std::str::FromStr;
+// use rust_decimal::Decimal;
+// use rust_decimal::prelude::FromPrimitive;
+// use serde_json::Value;
+// use exchanges::response_base::ResponseData;
+// use crate::{Account, OrderBook, Order, Position, PositionModeEnum, SpecialOrder, Trade, Record};
+//
+// // 处理账号信息
+// pub fn handle_account_info(response: &ResponseData, _symbol: &String) -> Account {
+//     let mut rst = Account::new();
+//
+//     for data in response.data.as_array().unwrap() {
+//         if data["marginCoin"].as_str().unwrap() != "USDT" {
+//             continue
+//         }
+//
+//         // 格式化account信息
+//         let mut account = Account {
+//             coin: data["marginCoin"].to_string(),
+//             balance: Decimal::from_str(data["usdtEquity"].as_str().unwrap()).unwrap(),
+//             available_balance: Decimal::from_str(data["available"].as_str().unwrap()).unwrap(),
+//             frozen_balance: Decimal::from_str(data["frozen"].as_str().unwrap()).unwrap(),
+//             stocks: Default::default(),
+//             available_stocks: Default::default(),
+//             frozen_stocks: Default::default(),
+//         };
+//         account.frozen_balance = account.balance - account.available_balance;
+//
+//         rst = account
+//     }
+//
+//     return rst;
+// }
+//
+// // 处理order信息
+// pub fn handle_order(res_data: &ResponseData, ct_val: Decimal) -> SpecialOrder {
+//     let res_data_json = res_data.data.as_array().unwrap();
+//     let mut order_info = Vec::new();
+//     for item in res_data_json.iter() {
+//         order_info.push(format_order_item(item.clone(), ct_val));
+//     }
+//     SpecialOrder {
+//         name: res_data.label.clone(),
+//         order: order_info,
+//     }
+// }
+//
+// // 处理订单信息
+// pub fn format_order_item(order: Value, ct_val: Decimal) -> Order {
+//     let price = Decimal::from_str(order["price"].as_str().unwrap().to_string().as_str()).unwrap();
+//     let size = Decimal::from_str(order["size"].as_str().unwrap().to_string().as_str()).unwrap();
+//     let binding = order["status"].clone().as_str().unwrap().to_string();
+//     let status = binding.as_str();
+//     let acc_base_volume = Decimal::from_str(order["accBaseVolume"].as_str().unwrap().to_string().as_str()).unwrap();
+//     let avg_price = if order["priceAvg"].is_null() || order["priceAvg"].as_str().unwrap().is_empty() {
+//         Decimal::ZERO
+//     } else {
+//         Decimal::from_str(order["priceAvg"].as_str().unwrap().to_string().as_str()).unwrap()
+//     };
+//     let c_id = if order["clientOid"].is_null() {
+//         ""
+//     } else {
+//         order["clientOid"].as_str().unwrap()
+//     };
+//
+//     let amount = size * ct_val;
+//     let deal_amount = acc_base_volume * ct_val;
+//     let custom_status = if ["filled", "canceled"].contains(&status) {
+//         "REMOVE".to_string()
+//     } else if ["init", "live", "new", "partially_filled"].contains(&status) {
+//         "NEW".to_string()
+//     } else {
+//         "NULL".to_string()
+//     };
+//     Order {
+//         id: order["orderId"].as_str().unwrap().to_string(),
+//         custom_id: c_id.to_string(),
+//         price,
+//         amount,
+//         deal_amount,
+//         avg_price,
+//         status: custom_status,
+//         order_type: order["orderType"].as_str().unwrap().to_string()
+//     }
+// }
+//
+// // 格式化深度信息
+// pub fn format_depth_items(value: Value) -> Vec<OrderBook> {
+//     let mut depth_items: Vec<OrderBook> = vec![];
+//     for value in value.as_array().unwrap() {
+//         depth_items.push(OrderBook {
+//             price: Decimal::from_str(value[0].as_str().unwrap()).unwrap(),
+//             amount: Decimal::from_str(value[1].as_str().unwrap()).unwrap(),
+//         })
+//     }
+//     return depth_items;
 // }
-
-// // 处理特殊Ticker信息
-// pub fn handle_special_ticker(res_data: ResponseData) -> SpecialDepth {
-//     let res_data_str = res_data.data;
-//     let res_data_json: Vec<serde_json::Value> = serde_json::from_str(&*res_data_str).unwrap();
-//     format_special_ticker(res_data_json[0].clone(), res_data.label)
+//
+// // 处理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_special_ticker(data: serde_json::Value, label: String) -> SpecialDepth {
-//     let bp = Decimal::from_str(data["bidPr"].as_str().unwrap()).unwrap();
-//     let bq = Decimal::from_str(data["bidSz"].as_str().unwrap()).unwrap();
-//     let ap = Decimal::from_str(data["askPr"].as_str().unwrap()).unwrap();
-//     let aq = Decimal::from_str(data["askSz"].as_str().unwrap()).unwrap();
-//     let mp = (bp + ap) * dec!(0.5);
-//     let t = Decimal::from_str(data["ts"].as_str().unwrap()).unwrap();
-//     let create_at = data["ts"].as_str().unwrap().parse::<i64>().unwrap() * 1000;
-//
-//     let ticker_info = SpecialTicker { sell: ap, buy: bp, mid_price: mp, t, create_at };
-//     let depth_info = vec![bp, bq, ap, aq];
-//     SpecialDepth {
-//         name: label,
-//         depth: depth_info,
-//         ticker: ticker_info,
-//         t,
-//         create_at,
+// pub fn format_position_item(position_json: &Value, ct_val: &Decimal) -> Position {
+//     let symbol = position_json["instId"].as_str().unwrap().to_string();
+//     let margin_level = Decimal::from_i64(position_json["leverage"].as_i64().unwrap()).unwrap();
+//     let amount = Decimal::from_str(position_json["total"].as_str().unwrap()).unwrap() * ct_val;
+//     let frozen_amount = Decimal::from_str(position_json["frozen"].as_str().unwrap()).unwrap() * ct_val;
+//     let price = Decimal::from_str(position_json["openPriceAvg"].as_str().unwrap()).unwrap();
+//     let profit = Decimal::from_str(position_json["unrealizedPL"].as_str().unwrap()).unwrap();
+//     let position_mode = match position_json["posMode"].as_str().unwrap() {
+//         "hedge_mode" => {
+//             match position_json["holdSide"].as_str().unwrap() {
+//                 "short" => {
+//                     PositionModeEnum::Short
+//                 }
+//                 "long" => {
+//                     PositionModeEnum::Long
+//                 },
+//                 _ => {
+//                     panic!("bitget_usdt_swap: 未知的持仓模式与持仓方向: {}, {}",
+//                            position_json["posMode"].as_str().unwrap(), position_json["holdSide"].as_str().unwrap())
+//                 }
+//             }
+//         },
+//         "one_way_mode" => {
+//             PositionModeEnum::Both
+//         },
+//         _ => {
+//             panic!("bitget_usdt_swap: 未知的持仓模式: {}", position_json["posMode"].as_str().unwrap())
+//         }
+//     };
+//     let margin = Decimal::from_str(position_json["marginSize"].as_str().unwrap()).unwrap();
+//
+//     Position {
+//         symbol,
+//         margin_level,
+//         amount,
+//         frozen_amount,
+//         price,
+//         profit,
+//         position_mode,
+//         margin,
 //     }
-// }
+// }
+//
+// pub fn format_trade_items(res_data: &ResponseData) -> Vec<Trade> {
+//     let arg = res_data.data["arg"].clone();
+//     let symbol = arg["instId"].as_str().unwrap().to_string().replace("USDT", "_USDT");
+//     let result = res_data.data["data"].as_array().unwrap();
+//     let mut trades = vec![];
+//
+//     for item in result {
+//         let mut trade = Trade {
+//             id: item["tradeId"].as_str().unwrap().to_string(),
+//             time: Decimal::from_str(item["ts"].as_str().unwrap()).unwrap(),
+//             size: Decimal::from_str(item["size"].as_str().unwrap()).unwrap(),
+//             price: Decimal::from_str(item["price"].as_str().unwrap().to_string().as_str()).unwrap(),
+//             symbol: symbol.to_string(),
+//         };
+//
+//         if item["side"].as_str().unwrap().eq("sell") {
+//             trade.size = trade.size * Decimal::NEGATIVE_ONE;
+//         }
+//
+//         trades.push(trade)
+//     }
+//
+//     return trades
+// }
+//
+// pub fn handle_records(value: &Value) -> Vec<Record> {
+//     let mut records = vec![];
+//
+//     let record_value_vec = value["data"].as_array().unwrap();
+//     let symbol = value["arg"]["instId"].as_str().unwrap().to_string().replace("USDT", "_USDT");
+//     for record_value in record_value_vec {
+//         let arr = record_value.as_array().unwrap();
+//         records.push(Record {
+//             time: Decimal::from_str(arr[0].as_str().unwrap()).unwrap(),
+//             open: Decimal::from_str(arr[1].as_str().unwrap()).unwrap(),
+//             high: Decimal::from_str(arr[2].as_str().unwrap()).unwrap(),
+//             low: Decimal::from_str(arr[3].as_str().unwrap()).unwrap(),
+//             close: Decimal::from_str(arr[4].as_str().unwrap()).unwrap(),
+//             volume: Decimal::from_str(arr[6].as_str().unwrap()).unwrap(),
+//             symbol: symbol.clone(),
+//         });
+//     }
+//
+//     return records
+// }
+//
+// // 处理特殊深度数据
+// // pub fn handle_special_depth(res_data: ResponseData) -> SpecialDepth {
+// //     HandleSwapInfo::handle_special_depth(ExchangeEnum::BitgetSwap, res_data)
+// // }
+//
+// // // 处理特殊Ticker信息
+// // pub fn handle_special_ticker(res_data: ResponseData) -> SpecialDepth {
+// //     let res_data_str = res_data.data;
+// //     let res_data_json: Vec<serde_json::Value> = serde_json::from_str(&*res_data_str).unwrap();
+// //     format_special_ticker(res_data_json[0].clone(), res_data.tag)
+// // }
+// //
+// // pub fn format_special_ticker(data: serde_json::Value, tag: String) -> SpecialDepth {
+// //     let bp = Decimal::from_str(data["bidPr"].as_str().unwrap()).unwrap();
+// //     let bq = Decimal::from_str(data["bidSz"].as_str().unwrap()).unwrap();
+// //     let ap = Decimal::from_str(data["askPr"].as_str().unwrap()).unwrap();
+// //     let aq = Decimal::from_str(data["askSz"].as_str().unwrap()).unwrap();
+// //     let mp = (bp + ap) * dec!(0.5);
+// //     let t = Decimal::from_str(data["ts"].as_str().unwrap()).unwrap();
+// //     let create_at = data["ts"].as_str().unwrap().parse::<i64>().unwrap() * 1000;
+// //
+// //     let ticker_info = SpecialTicker { sell: ap, buy: bp, mid_price: mp, t, create_at };
+// //     let depth_info = vec![bp, bq, ap, aq];
+// //     SpecialDepth {
+// //         name: tag,
+// //         depth: depth_info,
+// //         ticker: ticker_info,
+// //         t,
+// //         create_at,
+// //     }
+// // }

+ 220 - 0
standard/src/bitmart_swap.rs

@@ -0,0 +1,220 @@
+// use std::collections::{BTreeMap};
+// use std::io::{Error, ErrorKind};
+// use std::str::FromStr;
+// use tokio::sync::mpsc::Sender;
+// use async_trait::async_trait;
+// use rust_decimal::{Decimal};
+// use serde_json::{json, Value};
+// use tracing::{error, info};
+// use crate::{Platform, ExchangeEnum, Account, Position, Ticker, Market, Order, utils};
+// use exchanges::bitmart_swap_rest::BitMartSwapRest;
+// use rust_decimal::prelude::FromPrimitive;
+//
+// #[allow(dead_code)]
+// #[derive(Clone)]
+// pub struct BitMartSwap {
+//     exchange: ExchangeEnum,
+//     symbol: String,
+//     is_colo: bool,
+//     params: BTreeMap<String, String>,
+//     request: BitMartSwapRest,
+//     market: Market,
+//     order_sender: Sender<Order>,
+//     error_sender: Sender<Error>,
+// }
+//
+// impl BitMartSwap {
+//     pub async fn new(symbol: String, is_colo: bool, params: BTreeMap<String, String>, order_sender: Sender<Order>, error_sender: Sender<Error>) -> BitMartSwap {
+//         let market = Market::new();
+//         let mut bitmart_swap = BitMartSwap {
+//             exchange: ExchangeEnum::BitMartSwap,
+//             symbol: symbol.to_uppercase(),
+//             is_colo,
+//             params: params.clone(),
+//             request: BitMartSwapRest::new(is_colo, params.clone()),
+//             market,
+//             order_sender,
+//             error_sender,
+//         };
+//
+//         // 修改持仓模式
+//         let symbol_array: Vec<&str> = symbol.split("_").collect();
+//         let mode_result = bitmart_swap.set_dual_mode(symbol_array[1], true).await;
+//         match mode_result {
+//             Ok(ok) => {
+//                 info!("BitMart:设置持仓模式成功!{:?}", ok);
+//             }
+//             Err(error) => {
+//                 error!("BitMart:设置持仓模式失败!mode_result={}", error)
+//             }
+//         }
+//         // 获取市场信息
+//         bitmart_swap.market = BitMartSwap::get_market(&mut bitmart_swap).await.unwrap_or(bitmart_swap.market);
+//         return bitmart_swap;
+//     }
+// }
+//
+// #[async_trait]
+// impl Platform for BitMartSwap {
+//     // 克隆方法
+//     fn clone_box(&self) -> Box<dyn Platform + Send + Sync> { Box::new(self.clone()) }
+//     // 获取交易所模式
+//     fn get_self_exchange(&self) -> ExchangeEnum {
+//         ExchangeEnum::BitMartSwap
+//     }
+//     // 获取交易对
+//     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> {
+//         Err(Error::new(ErrorKind::NotFound, "bitmart_swap:该交易所方法未实现".to_string()))
+//     }
+//     // 获取账号信息
+//     async fn get_account(&mut self) -> Result<Account, Error> {
+//         Err(Error::new(ErrorKind::NotFound, "bitmart_swap:该交易所方法未实现".to_string()))
+//     }
+//
+//     async fn get_spot_account(&mut self) -> Result<Vec<Account>, Error> {
+//         Err(Error::new(ErrorKind::NotFound, "bitmart_swap:该交易所方法未实现".to_string()))
+//     }
+//
+//     // 获取持仓信息
+//     async fn get_position(&mut self) -> Result<Vec<Position>, Error> {
+//         Err(Error::new(ErrorKind::NotFound, "bitmart_swap:该交易所方法未实现".to_string()))
+//     }
+//     // 获取所有持仓
+//     async fn get_positions(&mut self) -> Result<Vec<Position>, Error> {
+//         Err(Error::new(ErrorKind::NotFound, "bitmart_swap:该交易所方法未实现".to_string()))
+//     }
+//     // 获取市场行情
+//     async fn get_ticker(&mut self) -> Result<Ticker, Error> {
+//         Err(Error::new(ErrorKind::NotFound, "bitmart_swap:该交易所方法未实现".to_string()))
+//     }
+//
+//     async fn get_ticker_symbol(&mut self, _symbol: String) -> Result<Ticker, Error> {
+//         Err(Error::new(ErrorKind::NotFound, "bitmart_swap:该交易所方法未实现".to_string()))
+//     }
+//
+//     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(), "");
+//         let params = json!({
+//             "symbol": symbol_format.clone()
+//         });
+//         let res_data = self.request.get_market(params).await;
+//         if res_data.code == 200 {
+//             let res_data_json = res_data.data["symbols"].as_array().unwrap();
+//             let market_info = res_data_json.iter().find(|item| item["symbol"].as_str().unwrap() == symbol_format);
+//             match market_info {
+//                 None => {
+//                     error!("bitmart_swap:获取Market信息错误!\nget_market:res_data={:?}", res_data);
+//                     Err(Error::new(ErrorKind::Other, res_data.to_string()))
+//                 }
+//                 Some(value) => {
+//                     let base_asset = value["base_currency"].as_str().unwrap().to_string();
+//                     let quote_asset = value["quote_currency"].as_str().unwrap().to_string();
+//
+//                     let tick_size = Decimal::from_str(value["price_precision"].as_str().unwrap()).unwrap();
+//                     let price_precision = Decimal::from_u32(tick_size.scale()).unwrap();
+//                     let amount_size = Decimal::from_str(value["vol_precision"].as_str().unwrap()).unwrap();
+//                     let amount_precision = Decimal::from_u32(amount_size.scale()).unwrap();
+//                     let min_qty = Decimal::from_str(value["min_volume"].as_str().unwrap()).unwrap();
+//                     let max_qty = Decimal::from_str(value["max_volume"].as_str().unwrap()).unwrap();
+//                     let ct_val = Decimal::from_str(value["contract_size"].as_str().unwrap()).unwrap();
+//
+//                     let result = Market {
+//                         symbol: format!("{}_{}", base_asset, quote_asset),
+//                         base_asset,
+//                         quote_asset,
+//                         tick_size,
+//                         amount_size,
+//                         price_precision,
+//                         amount_precision,
+//                         min_qty,
+//                         max_qty,
+//                         min_notional: min_qty * ct_val,
+//                         max_notional: max_qty * ct_val,
+//                         ct_val,
+//                     };
+//                     Ok(result)
+//                 }
+//             }
+//         } else {
+//             Err(Error::new(ErrorKind::Other, res_data.to_string()))
+//         }
+//     }
+//
+//     // 获取订单详情
+//     async fn get_order_detail(&mut self, _order_id: &str, _custom_id: &str) -> Result<Order, Error> {
+//         Err(Error::new(ErrorKind::NotFound, "bitmart_swap:该交易所方法未实现".to_string()))
+//     }
+//     // 获取订单列表
+//     async fn get_orders_list(&mut self, _status: &str) -> Result<Vec<Order>, Error> {
+//         Err(Error::new(ErrorKind::NotFound, "bitmart_swap:该交易所方法未实现".to_string()))
+//     }
+//     // 下单接口
+//     async fn take_order(&mut self, _custom_id: &str, _origin_side: &str, _price: Decimal, _amount: Decimal) -> Result<Order, Error> {
+//         Err(Error::new(ErrorKind::NotFound, "bitmart_swap:该交易所方法未实现".to_string()))
+//     }
+//
+//     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> {
+//         Err(Error::new(ErrorKind::NotFound, "bitmart_swap:该交易所方法未实现".to_string()))
+//     }
+//
+//     // 撤销订单
+//     async fn cancel_order(&mut self, _order_id: &str, _custom_id: &str) -> Result<Order, Error> {
+//         Err(Error::new(ErrorKind::NotFound, "bitmart_swap:该交易所方法未实现".to_string()))
+//     }
+//     // 批量撤销订单
+//     async fn cancel_orders(&mut self) -> Result<Vec<Order>, Error> {
+//         Err(Error::new(ErrorKind::NotFound, "bitmart_swap:该交易所方法未实现".to_string()))
+//     }
+//
+//     async fn cancel_orders_all(&mut self) -> Result<Vec<Order>, Error> {
+//         Err(Error::new(ErrorKind::NotFound, "bitmart_swap:该交易所方法未实现".to_string()))
+//     }
+//
+//     async fn take_stop_loss_order(&mut self, _stop_price: Decimal, _price: Decimal, _side: &str) -> Result<Value, Error> {
+//         Err(Error::new(ErrorKind::NotFound, "bitmart_swap:该交易所方法未实现".to_string()))
+//     }
+//
+//     async fn cancel_stop_loss_order(&mut self, _order_id: &str) -> Result<Value, Error> {
+//         Err(Error::new(ErrorKind::NotFound, "bitmart_swap:该交易所方法未实现".to_string()))
+//     }
+//
+//     // 设置持仓模式
+//     async fn set_dual_mode(&mut self, _coin: &str, _is_dual_mode: bool) -> Result<String, Error> {
+//         Err(Error::new(ErrorKind::NotFound, "bitmart_swap:该交易所方法未实现".to_string()))
+//     }
+//
+//     // 更新双持仓模式下杠杆
+//     async fn set_dual_leverage(&mut self, _leverage: &str) -> Result<String, Error> {
+//         Err(Error::new(ErrorKind::NotFound, "bitmart_swap:该交易所方法未实现".to_string()))
+//     }
+//
+//     async fn set_auto_deposit_status(&mut self, _status: bool) -> Result<String, Error> { Err(Error::new(ErrorKind::NotFound, "bitmart:该交易所方法未实现".to_string())) }
+//
+//     // 交易账户互转
+//     async fn wallet_transfers(&mut self, _coin: &str, _from: &str, _to: &str, _amount: Decimal) -> Result<String, Error> {
+//         Err(Error::new(ErrorKind::NotFound, "bitmart_swap:该交易所方法未实现".to_string()))
+//     }
+// }

+ 105 - 0
standard/src/bitmart_swap_handle.rs

@@ -0,0 +1,105 @@
+// use std::str::FromStr;
+// use rust_decimal::Decimal;
+// use rust_decimal::prelude::FromPrimitive;
+// use serde_json::Value;
+// use exchanges::response_base::ResponseData;
+// use crate::{Trade, Record};
+// // use crate::{OrderBook, Trade, Record};
+// // use crate::{Account, OrderBook, Order, Position, SpecialOrder, Trade, Record};
+//
+// // 处理账号信息
+// // pub fn handle_account_info(_res_data: &ResponseData, _symbol: &String) -> Account {
+// //     Account::new()
+// // }
+// //
+// // pub fn format_account_info(_data: &Vec<Value>, _symbol: &String) -> Account {
+// //     Account::new()
+// // }
+// //
+// // // 处理position信息
+// // pub fn handle_position(_res_data: &ResponseData, _ct_val: &Decimal) -> Vec<Position> {
+// //     vec![Position::new()]
+// // }
+// //
+// // pub fn format_position_item(_position: &Value, _ct_val: &Decimal) -> Position {
+// //     Position::new()
+// // }
+// //
+// // // 处理order信息
+// // pub fn handle_order(_res_data: &ResponseData, _ct_val: Decimal) -> SpecialOrder {
+// //     SpecialOrder::new()
+// // }
+// //
+// // pub fn format_order_item(_order: Value, _ct_val: Decimal) -> Order {
+// //     Order::new()
+// // }
+// // 处理特殊Ticket信息
+// // pub fn handle_book_ticker(res_data: &ResponseData) -> SpecialDepth {
+// //     let bp = Decimal::from_str((*res_data).data["b"].as_str().unwrap()).unwrap();
+// //     let bq = Decimal::from_f64((*res_data).data["B"].as_f64().unwrap()).unwrap();
+// //     let ap = Decimal::from_str((*res_data).data["a"].as_str().unwrap()).unwrap();
+// //     let aq = Decimal::from_f64((*res_data).data["A"].as_f64().unwrap()).unwrap();
+// //     let mp = (bp + ap) * dec!(0.5);
+// //     let t = Decimal::from_u64((*res_data).data["u"].as_u64().unwrap()).unwrap();
+// //     let create_at = (*res_data).data["t"].as_i64().unwrap() * 1000;
+// //
+// //     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).tag.clone(),
+// //         depth: depth_info,
+// //         ticker: ticker_info,
+// //         t,
+// //         create_at,
+// //     }
+// // }
+//
+// pub fn handle_records(value: &Value) -> Vec<Record> {
+//     let mut records = vec![];
+//     let symbol = value["symbol"].as_str().unwrap().replace("USDT", "_USDT");
+//     for record_value in value["items"].as_array().unwrap() {
+//         records.push(Record {
+//             time: Decimal::from_i64(record_value["ts"].as_i64().unwrap() * 1000).unwrap(),
+//             open: Decimal::from_str(record_value["o"].as_str().unwrap()).unwrap(),
+//             high: Decimal::from_str(record_value["h"].as_str().unwrap()).unwrap(),
+//             low: Decimal::from_str(record_value["l"].as_str().unwrap()).unwrap(),
+//             close: Decimal::from_str(record_value["c"].as_str().unwrap()).unwrap(),
+//             volume: Decimal::from_str(record_value["v"].as_str().unwrap()).unwrap(),
+//             symbol: symbol.clone(),
+//         });
+//     }
+//
+//     return records;
+// }
+//
+// // pub fn format_depth_items(value: &Value) -> Vec<OrderBook> {
+// //     let mut depth_items: Vec<OrderBook> = vec![];
+// //     for value in value.as_array().unwrap() {
+// //         depth_items.push(OrderBook {
+// //             price: Decimal::from_str(value["price"].as_str().unwrap()).unwrap(),
+// //             amount: Decimal::from_str(value["vol"].as_str().unwrap()).unwrap(),
+// //         })
+// //     }
+// //     return depth_items;
+// // }
+//
+// pub fn format_trade_items(res_data: &ResponseData) -> Vec<Trade> {
+//     let result = res_data.data.as_array().unwrap();
+//     let mut trades = vec![];
+//
+//     for item in result {
+//         let way = [1, 2, 3, 4].contains(&item["way"].as_i64().unwrap());
+//         let size = Decimal::from_str(item["deal_vol"].as_str().unwrap().to_string().as_str()).unwrap();
+//
+//         trades.push(Trade {
+//             id: item["trade_id"].to_string(),
+//             time: Decimal::from_i64(item["create_time_mill"].as_i64().unwrap()).unwrap(),
+//             size: if way { size } else { -size },
+//             price: Decimal::from_str(item["deal_price"].as_str().unwrap().to_string().as_str()).unwrap(),
+//             symbol: item["symbol"].as_str().unwrap().to_string().replace("USDT", "_USDT"),
+//         })
+//     }
+//
+//     return trades;
+// }

+ 748 - 748
standard/src/bybit_swap.rs

@@ -1,748 +1,748 @@
-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 serde_json::{from_value, json, Value};
-use rust_decimal::prelude::FromPrimitive;
-use serde::{Deserialize, Serialize};
-use tokio::time::Instant;
-use tracing::{error, info, trace};
-use exchanges::bybit_swap_rest::BybitSwapRest;
-use crate::{Platform, ExchangeEnum, Account, Position, Ticker, Market, Order, OrderCommand, PositionModeEnum};
-use global::trace_stack::TraceStack;
-
-#[derive(Debug, Clone, Deserialize, Serialize)]
-#[serde(rename_all = "camelCase")]
-struct SwapTicker {
-    symbol: String,
-    high_price24h: Decimal,
-    low_price24h: Decimal,
-    bid1_price: Decimal,
-    ask1_price: Decimal,
-    last_price: Decimal,
-    volume24h: Decimal
-}
-
-#[allow(dead_code)]
-#[derive(Clone)]
-pub struct BybitSwap {
-    exchange: ExchangeEnum,
-    symbol: String,
-    symbol_uppercase: String,
-    is_colo: bool,
-    params: BTreeMap<String, String>,
-    request: BybitSwapRest,
-    market: Market,
-    order_sender: Sender<Order>,
-    error_sender: Sender<Error>,
-}
-
-impl BybitSwap {
-    pub async fn new(symbol: String, is_colo: bool, params: BTreeMap<String, String>, order_sender: Sender<Order>, error_sender: Sender<Error>) -> BybitSwap {
-        let market = Market::new();
-        let mut bybit_swap = BybitSwap {
-            exchange: ExchangeEnum::BybitSwap,
-            symbol: symbol.to_uppercase(),
-            symbol_uppercase: symbol.replace("_", "").to_uppercase(),
-            is_colo,
-            params: params.clone(),
-            request: BybitSwapRest::new(is_colo, params.clone()),
-            market,
-            order_sender,
-            error_sender,
-        };
-
-        // 修改持仓模式
-        let symbol_array: Vec<&str> = symbol.split("_").collect();
-        let mode_result = bybit_swap.set_dual_mode(symbol_array[1], true).await;
-        match mode_result {
-            Ok(_) => {
-                trace!("Bybit:设置持仓模式成功!")
-            }
-            Err(error) => {
-                error!("Bybit:设置持仓模式失败!mode_result={}", error)
-            }
-        }
-        // 获取市场信息
-        bybit_swap.market = BybitSwap::get_market(&mut bybit_swap).await.unwrap_or(bybit_swap.market);
-        return bybit_swap;
-    }
-}
-
-#[async_trait]
-impl Platform for BybitSwap {
-    // 克隆方法
-    fn clone_box(&self) -> Box<dyn Platform + Send + Sync> { Box::new(self.clone()) }
-    // 获取交易所模式
-    fn get_self_exchange(&self) -> ExchangeEnum {
-        ExchangeEnum::GateSwap
-    }
-    // 获取交易对
-    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_time().await;
-        if res_data.code == 200 {
-            let result = res_data.data["server_time"].to_string();
-            Ok(result)
-        } else {
-            Err(Error::new(ErrorKind::Other, res_data.to_string()))
-        }
-    }
-    // 获取账号信息
-    async fn get_account(&mut self) -> Result<Account, Error> {
-        let symbol_array: Vec<&str> = self.symbol.split("_").collect();
-        let res_data = self.request.get_account_balance(symbol_array[1].parse().unwrap()).await;
-        if res_data.code == 200 {
-            let arr_infos: Vec<Value> = from_value(res_data.data["list"].clone()).unwrap();
-            if arr_infos.len() < 1usize{
-                return Err(Error::new(ErrorKind::NotFound, format!("{} 无账户信息", symbol_array[1])));
-            }
-            let coin_infos: Vec<Value> = from_value(arr_infos[0]["coin"].clone()).unwrap();
-            if coin_infos.len() < 1usize{
-               return Err(Error::new(ErrorKind::NotFound, format!("{} 无账户信息", symbol_array[1])));
-            }
-            let balance = Decimal::from_str(coin_infos[0]["equity"].as_str().unwrap()).unwrap();
-            let available_balance = Decimal::from_str(coin_infos[0]["walletBalance"].as_str().unwrap()).unwrap();
-            let frozen_balance = balance - available_balance;
-            let result = Account {
-                coin: symbol_array[1].to_string(),
-                balance,
-                available_balance,
-                frozen_balance,
-                stocks: Decimal::ZERO,
-                available_stocks: Decimal::ZERO,
-                frozen_stocks: Decimal::ZERO,
-            };
-            Ok(result)
-        } else {
-            Err(Error::new(ErrorKind::Other, res_data.to_string()))
-        }
-    }
-
-    async fn get_spot_account(&mut self) -> Result<Vec<Account>, Error> {
-        Err(Error::new(ErrorKind::NotFound, "bybit_swap:该交易所方法未实现".to_string()))
-    }
-
-    // 获取持仓信息
-    async fn get_position(&mut self) -> Result<Vec<Position>, Error> {
-        let symbol = self.symbol_uppercase.clone();
-        let ct_val = self.market.ct_val;
-        let res_data = self.request.get_positions(symbol, "".to_string()).await;
-        if res_data.code == 200 {
-            let result = res_data.data["list"].as_array().unwrap().iter().map(|item| { format_position_item(item, ct_val) }).collect();
-            Ok(result)
-        } else {
-            Err(Error::new(ErrorKind::Other, res_data.to_string()))
-        }
-    }
-    // 获取所有持仓
-    async fn get_positions(&mut self) -> Result<Vec<Position>, Error> {
-        let symbol_array: Vec<&str> = self.symbol.split("_").collect();
-        let ct_val = self.market.ct_val;
-        let res_data = self.request.get_positions("".to_string(), symbol_array[1].to_string().to_uppercase()).await;
-        if res_data.code == 200 {
-            info!("{}", res_data.data.to_string());
-            let result = res_data.data["list"].as_array().unwrap().iter().map(|item| { format_position_item(item, ct_val) }).collect();
-            Ok(result)
-        } else {
-            Err(Error::new(ErrorKind::Other, res_data.to_string()))
-        }
-    }
-    // 获取市场行情
-    async fn get_ticker(&mut self) -> Result<Ticker, Error> {
-        let symbol = self.symbol_uppercase.clone();
-        let res_data = self.request.get_tickers(symbol).await;
-        if res_data.code == 200 {
-            let list :Vec<SwapTicker> = from_value(res_data.data["list"].clone()).unwrap_or(Vec::new());
-
-            if list.len() < 1usize {
-                error!("bybit_swap:获取Ticker信息错误!\nget_ticker:res_data={:?}", res_data);
-                return Err(Error::new(ErrorKind::Other, res_data.to_string()));
-            }
-            let value = list[0].clone();
-            Ok(Ticker{
-                time: chrono::Utc::now().timestamp_millis(),
-                high: value.high_price24h,
-                low: value.low_price24h,
-                sell: value.ask1_price,
-                buy: value.bid1_price,
-                last: value.last_price,
-                volume: value.volume24h
-            })
-        } else {
-            Err(Error::new(ErrorKind::Other, res_data.to_string()))
-        }
-    }
-
-    async fn get_ticker_symbol(&mut self, symbol: String) -> Result<Ticker, Error> {
-        let symbol_upper = symbol.replace("_", "").to_uppercase();
-        let res_data = self.request.get_tickers(symbol_upper.clone()).await;
-        if res_data.code == 200 {
-            let list: Vec<SwapTicker> = from_value(res_data.data["list"].clone()).unwrap();
-            let ticker_info = list.iter().find(|&item| item.symbol == symbol_upper);
-
-            match ticker_info {
-                None => {
-                    error!("bybit_swap:获取Ticker信息错误!\nget_ticker:res_data={:?}", res_data);
-                    Err(Error::new(ErrorKind::Other, res_data.to_string()))
-                }
-                Some(value) => {
-                    let result = Ticker {
-                        time: chrono::Utc::now().timestamp_millis(),
-                        high: value.high_price24h,
-                        low: value.low_price24h,
-                        sell: value.ask1_price,
-                        buy: value.bid1_price,
-                        last: value.last_price,
-                        volume: value.volume24h
-                    };
-                    Ok(result)
-                }
-            }
-        } else {
-            Err(Error::new(ErrorKind::Other, res_data.to_string()))
-        }
-    }
-
-    async fn get_market(&mut self) -> Result<Market, Error> {
-        let symbol = self.symbol_uppercase.clone();
-        let res_data = self.request.get_instruments_info(symbol.clone()).await;
-        if res_data.code == 200 {
-            let arr_data: Vec<Value> = from_value(res_data.data["list"].clone()).unwrap();
-            let market_info = arr_data.iter().find(|&item| item["symbol"].as_str().unwrap() == symbol);
-            match market_info {
-                None => {
-                    error!("bybit_swap:获取Market信息错误!\nget_market:res_data={:?}", res_data);
-                    Err(Error::new(ErrorKind::Other, res_data.to_string()))
-                }
-                Some(value) => {
-                    let base_coin = value["baseCoin"].as_str().unwrap();
-                    let quote_coin = value["quoteCoin"].as_str().unwrap();
-                    let name = format!("{}_{}",base_coin, quote_coin);
-                    let tick_size = Decimal::from_str(value["priceFilter"]["minPrice"].as_str().unwrap().trim()).unwrap();
-                    let min_qty = Decimal::from_str(value["lotSizeFilter"]["minOrderQty"].as_str().unwrap().trim()).unwrap();
-                    let max_qty = Decimal::from_str(value["lotSizeFilter"]["maxOrderQty"].as_str().unwrap().trim()).unwrap();
-                    let ct_val = Decimal::ONE;
-
-                    let amount_size = min_qty * ct_val;
-                    let price_precision = Decimal::from_u32(tick_size.scale()).unwrap();
-                    let amount_precision = Decimal::from_u32(amount_size.scale()).unwrap();
-                    let min_notional = min_qty * ct_val;
-                    let max_notional = max_qty * ct_val;
-
-                    let result = Market {
-                        symbol: name,
-                        base_asset: base_coin.to_string(),
-                        quote_asset: quote_coin.to_string(),
-                        tick_size,
-                        amount_size,
-                        price_precision,
-                        amount_precision,
-                        min_qty,
-                        max_qty,
-                        min_notional,
-                        max_notional,
-                        ct_val,
-                    };
-                    Ok(result)
-                }
-            }
-        } else {
-            Err(Error::new(ErrorKind::Other, res_data.to_string()))
-        }
-    }
-
-    async fn get_market_symbol(&mut self, symbol: String) -> Result<Market, Error> {
-        let symbol = symbol.replace("_", "").to_uppercase();
-        let res_data = self.request.get_instruments_info(symbol.clone()).await;
-        if res_data.code == 200 {
-            let arr_data: Vec<Value> = from_value(res_data.data["list"].clone()).unwrap();
-            let market_info = arr_data.iter().find(|item| item["symbol"].as_str().unwrap() == symbol);
-            match market_info {
-                None => {
-                    error!("bybit_swap:获取Market信息错误!\nget_market:res_data={:?}", res_data);
-                    Err(Error::new(ErrorKind::Other, res_data.to_string()))
-                }
-                Some(value) => {
-                    let base_coin = value["baseCoin"].as_str().unwrap();
-                    let quote_coin = value["quoteCoin"].as_str().unwrap();
-                    let name = format!("{}_{}",base_coin, quote_coin);
-                    let tick_size = Decimal::from_str(value["priceFilter"]["minPrice"].as_str().unwrap().trim()).unwrap();
-                    let min_qty = Decimal::from_str(value["lotSizeFilter"]["minOrderQty"].as_str().unwrap().trim()).unwrap();
-                    let max_qty = Decimal::from_str(value["lotSizeFilter"]["maxOrderQty"].as_str().unwrap().trim()).unwrap();
-                    let ct_val = Decimal::ONE;
-
-                    let amount_size = min_qty * ct_val;
-                    let price_precision = Decimal::from_u32(tick_size.scale()).unwrap();
-                    let amount_precision = Decimal::from_u32(amount_size.scale()).unwrap();
-                    let min_notional = min_qty * ct_val;
-                    let max_notional = max_qty * ct_val;
-
-                    let result = Market {
-                        symbol: name,
-                        base_asset: base_coin.to_string(),
-                        quote_asset: quote_coin.to_string(),
-                        tick_size,
-                        amount_size,
-                        price_precision,
-                        amount_precision,
-                        min_qty,
-                        max_qty,
-                        min_notional,
-                        max_notional,
-                        ct_val,
-                    };
-                    Ok(result)
-                }
-            }
-        } else {
-            Err(Error::new(ErrorKind::Other, res_data.to_string()))
-        }
-    }
-
-    // 获取订单详情
-    async fn get_order_detail(&mut self, order_id: &str, custom_id: &str) -> Result<Order, Error> {
-        let symbol = self.symbol_uppercase.clone();
-        let ct_val = self.market.ct_val;
-        let id = if !custom_id.trim().eq("") { format!("t-{}", custom_id) } else { String::new() };
-        let res_data = self.request.get_order(symbol, order_id.parse().unwrap(), id).await;
-        if res_data.code == 200 {
-            let res_data_json: Value = res_data.data["list"].clone();
-            if res_data_json.is_array() && res_data_json.as_array().unwrap().len() == 0 {
-                return Err(Error::new(ErrorKind::Other, "没有该订单!"));
-            }
-            let result = format_order_item(res_data_json.as_array().unwrap()[0].clone(), ct_val);
-            Ok(result)
-        } else {
-            Err(Error::new(ErrorKind::Other, res_data.to_string()))
-        }
-    }
-    // 获取订单列表
-    async fn get_orders_list(&mut self, _status: &str) -> Result<Vec<Order>, Error> {
-       Err(Error::new(ErrorKind::Other, "bybit获取订单列表暂未实现".to_string()))
-    }
-    // 下单接口
-    async fn take_order(&mut self, custom_id: &str, origin_side: &str, price: Decimal, amount: Decimal) -> Result<Order, Error> {
-        let symbol = self.symbol_uppercase.clone();
-        let ct_val = self.market.ct_val;
-        let size = amount / ct_val;
-        let mut params = json!({
-            "orderLinkId": format!("t-{}", custom_id),
-            "symbol": symbol.to_string(),
-            "price": price.to_string(),
-            "category": "linear",
-            "orderType":"Limit",
-            "qty": json!(size),
-            // 0.單向持倉 1.買側雙向持倉 2.賣側雙向持倉
-            "positionIdx": json!(1),
-            "reduceOnly": json!(false)
-        });
-
-        if price.eq(&Decimal::ZERO) {
-            params["timeInForce"] = json!("IOC".to_string());
-        }
-        match origin_side {
-            "kd" => {
-                params["side"] = json!("Buy");
-            }
-            "pd" => {
-                params["side"] = json!("Sell");
-                // 减仓
-                params["reduceOnly"] = json!(true);
-            }
-            "kk" => {
-                params["side"] = json!("Sell");
-                params["positionIdx"] = json!(2);
-            }
-            "pk" => {
-                params["side"] = json!("Buy");
-                // 减仓
-                params["reduceOnly"] = json!(true);
-                params["positionIdx"] = json!(2);
-            }
-            _ => { error!("下单参数错误"); }
-        };
-        let res_data = self.request.swap_order(params).await;
-        if res_data.code == 200 {
-            let result = format_new_order_item(res_data.data, price, size);
-            Ok(result)
-        } else {
-            Err(Error::new(ErrorKind::Other, res_data.to_string()))
-        }
-    }
-
-    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_upper = symbol.replace("_", "").trim().to_uppercase();
-        let size = (amount / ct_val).floor();
-        let order_type = if price == Decimal::ZERO {
-            "Market"
-        } else {
-            "Limit"
-        };
-        let mut params = json!({
-            "orderLinkId": format!("t-{}", custom_id),
-            "symbol": symbol_upper,
-            "price": price.to_string(),
-            "category": "linear",
-            "orderType": order_type,
-            "qty": json!(size),
-            // 0.單向持倉 1.買側雙向持倉 2.賣側雙向持倉
-            "positionIdx": json!(1),
-            "reduceOnly": json!(false)
-        });
-
-        if price.eq(&Decimal::ZERO) {
-            params["timeInForce"] = json!("IOC".to_string());
-        }
-        match origin_side {
-            "kd" => {
-                params["side"] = json!("Buy");
-            }
-            "pd" => {
-                params["side"] = json!("Sell");
-                params["positionIdx"] = json!(1);
-                // 减仓
-                params["reduceOnly"] = json!(true);
-            }
-            "kk" => {
-                params["side"] = json!("Sell");
-                params["positionIdx"] = json!(2);
-            }
-            "pk" => {
-                params["side"] = json!("Buy");
-                params["positionIdx"] = json!(2);
-                // 减仓
-                params["reduceOnly"] = json!(true);
-            }
-            _ => { error!("下单参数错误"); }
-        };
-        let res_data = self.request.swap_order(params.clone()).await;
-        if res_data.code == 200 {
-            let result = format_new_order_item(res_data.data, price, size);
-            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 = self.symbol_uppercase.clone();
-        let id = format!("t-{}", custom_id);
-        let res_data = self.request.cancel_order(symbol, String::from(order_id), id.clone()).await;
-        if res_data.code == 200 {
-            let result = format_cancel_order_item(res_data.data);
-            Ok(result)
-        } else {
-            Err(Error::new(ErrorKind::Other, res_data.to_string()))
-        }
-    }
-    // 批量撤销订单
-    async fn cancel_orders(&mut self) -> Result<Vec<Order>, Error> {
-        let symbol = self.symbol_uppercase.clone();
-        let res_data = self.request.cancel_orders(symbol).await;
-        if res_data.code == 200 {
-            info!("{}", res_data.data.to_string());
-            let res_arr: Vec<Value> = from_value(res_data.data).unwrap();
-            let result = res_arr.iter().map(|item| format_cancel_order_item(item.clone())).collect();
-            Ok(result)
-        } else {
-            Err(Error::new(ErrorKind::Other, res_data.to_string()))
-        }
-    }
-
-    async fn cancel_orders_all(&mut self) -> Result<Vec<Order>, Error> {
-        let symbol = self.symbol_uppercase.clone();
-        let res_data = self.request.cancel_orders(symbol).await;
-        if res_data.code == 200 {
-            info!("{}", res_data.data.to_string());
-            let res_arr: Vec<Value> = from_value(res_data.data["list"].clone()).unwrap();
-            let result = res_arr.iter().map(|item| format_cancel_order_item(item.clone())).collect();
-            Ok(result)
-        } else {
-            Err(Error::new(ErrorKind::Other, res_data.to_string()))
-        }
-    }
-
-    async fn take_stop_loss_order(&mut self, _stop_price: Decimal, _price: Decimal, _side: &str) -> Result<Value, Error> {
-        Err(Error::new(ErrorKind::NotFound, "bybit_swap:该交易所方法未实现".to_string()))
-    }
-
-    async fn cancel_stop_loss_order(&mut self, _order_id: &str) -> Result<Value, Error> {
-        Err(Error::new(ErrorKind::NotFound, "bybit_swap:该交易所方法未实现".to_string()))
-    }
-
-    // 设置持仓模式
-    async fn set_dual_mode(&mut self, _coin: &str, is_dual_mode: bool) -> Result<String, Error> {
-        let coin_format = self.symbol_uppercase.clone();
-        let mut mod_num = 0;
-        if is_dual_mode {
-            mod_num = 3;
-        }
-        let res_data = self.request.set_position_mode(coin_format, mod_num).await;
-        if res_data.code == 200 {
-            Ok(res_data.data.to_string())
-        } else {
-            Err(Error::new(ErrorKind::Other, res_data.to_string()))
-        }
-    }
-
-    // 更新双持仓模式下杠杆
-    async fn set_dual_leverage(&mut self, leverage: &str) -> Result<String, Error> {
-        let symbol = self.symbol_uppercase.clone();
-        let res_data = self.request.set_leverage(symbol, leverage.to_string()).await;
-        if res_data.code == 200 {
-            Ok(res_data.data.to_string())
-        } else {
-            Err(Error::new(ErrorKind::Other, res_data.to_string()))
-        }
-    }
-
-    async fn set_auto_deposit_status(&mut self, _status: bool) -> Result<String, Error> { Err(Error::new(ErrorKind::NotFound, "gate:该交易所方法未实现".to_string())) }
-
-    // 交易账户互转
-    async fn wallet_transfers(&mut self, _coin: &str, _from: &str, _to: &str, _amount: Decimal) -> Result<String, Error> {
-        // let coin_format = coin.to_string().to_lowercase();
-        // let res_data = self.request.wallet_transfers(coin_format.clone(), from.to_string(), to.to_string(), amount.to_string(), coin_format.clone()).await;
-        // if res_data.code == 200 {
-        //     let res_data_str = &res_data.data;
-        //     let result = res_data_str.clone();
-        //     Ok(result)
-        // } else {
-        //     Err(Error::new(ErrorKind::Other, res_data.to_string()))
-        // }
-        Err(Error::new(ErrorKind::Other, "暂未实现!"))
-    }
-
-    // 指令下单
-    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 self_clone = self.clone();
-
-            let amount = Decimal::from_str(order_command.limits_open[item].get(0).unwrap_or(&"0".to_string())).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_or(&"0".to_string())).unwrap();
-            let cid = order_command.limits_open[item].get(3).unwrap().clone();
-
-            let mut ts = trace_stack.clone();
-
-            let handle = tokio::spawn(async move {
-                ts.on_before_send();
-                // TraceStack::show_delay(&ts.ins);
-                let result = self_clone.take_order(cid.as_str(), side.as_str(), price, amount).await;
-                ts.on_after_send();
-                match result {
-                    Ok(mut result) => {
-                        // 记录此订单完成时间
-                        result.trace_stack = ts;
-
-                        self_clone.order_sender.send(result).await.unwrap();
-                    }
-                    Err(error) => {
-                        error!("bybit:下单失败:{:?}", error);
-
-                        let mut err_order = Order::new();
-                        err_order.custom_id = cid.clone();
-                        err_order.status = "REMOVE".to_string();
-
-                        self_clone.order_sender.send(err_order).await.unwrap();
-                        self_clone.error_sender.send(error).await.unwrap();
-                    }
-                }
-            });
-            handles.push(handle)
-        }
-        let futures = FuturesUnordered::from_iter(handles);
-        let _: Result<Vec<_>, _> = futures.try_collect().await;
-
-        // 撤销订单
-        let mut cancel_handles = vec![];
-        for item in order_command.cancel.keys() {
-            let mut self_clone = self.clone();
-
-            let order_id = order_command.cancel[item].get(1).unwrap().clone();
-            let custom_id = order_command.cancel[item].get(0).unwrap().clone();
-
-            let handle = tokio::spawn(async move {
-                let result = self_clone.cancel_order(&order_id, &custom_id).await;
-                match result {
-                    Ok(_) => {
-                        // result_sd.send(result).await.unwrap();
-                    }
-                    Err(error) => {
-                        // 取消失败去查订单。
-                        let query_rst = self_clone.get_order_detail(&order_id, &custom_id).await;
-                        match query_rst {
-                            Ok(order) => {
-                                self_clone.order_sender.send(order).await.unwrap();
-                            }
-                            Err(_err) => {
-                                error!("bybit:撤单失败,而且查单也失败了,oid={}, cid={}。", order_id.clone(), custom_id.clone());
-                            }
-                        }
-                        self_clone.error_sender.send(error).await.unwrap();
-                    }
-                }
-            });
-            cancel_handles.push(handle)
-        }
-        let futures = FuturesUnordered::from_iter(cancel_handles);
-        let _: Result<Vec<_>, _> = futures.try_collect().await;
-
-        // 检查订单指令
-        let mut check_handles = vec![];
-        for item in order_command.check.keys() {
-            let mut self_clone = self.clone();
-
-            let order_id = order_command.check[item].get(1).unwrap().clone();
-            let custom_id = order_command.check[item].get(0).unwrap().clone();
-
-            let handle = tokio::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_handles.push(handle)
-        }
-        let futures = FuturesUnordered::from_iter(check_handles);
-        let _: Result<Vec<_>, _> = futures.try_collect().await;
-    }
-}
-
-pub fn format_position_item(position: &Value, ct_val: Decimal) -> Position {
-    let position_idx = position["positionIdx"].to_string();
-    let mut position_mode = match position_idx.as_str() {
-        "0" => PositionModeEnum::Both,
-        "1" => PositionModeEnum::Long,
-        "2" => PositionModeEnum::Short,
-        _ => {
-            error!("bybit_swap:格式化持仓模式错误!\nformat_position_item:position={:?}", position);
-            panic!("bybit_swap:格式化持仓模式错误!\nformat_position_item:position={:?}", position)
-        }
-    };
-    let size_str: String = from_value(position["size"].clone()).unwrap();
-    let size = Decimal::from_str(size_str.as_str()).unwrap();
-    let amount = size * ct_val;
-    let mut profit = Decimal::ZERO;
-    let profit_str = position["unrealisedPnl"].as_str().unwrap_or("0");
-    if profit_str != "" {
-        profit = Decimal::from_str(profit_str).unwrap();
-    }
-
-    match position_mode {
-        PositionModeEnum::Both => {
-            position_mode = match amount {
-                amount if amount > Decimal::ZERO => PositionModeEnum::Long,
-                amount if amount < Decimal::ZERO => PositionModeEnum::Short,
-                _ => { PositionModeEnum::Both }
-            }
-        }
-        _ => {}
-    }
-    Position {
-        symbol: position["symbol"].as_str().unwrap_or("").parse().unwrap(),
-        margin_level: Decimal::from_str(position["leverage"].as_str().unwrap()).unwrap(),
-        amount,
-        frozen_amount: Decimal::ZERO,
-        price: Decimal::from_str(position["avgPrice"].as_str().unwrap()).unwrap(),
-        profit,
-        position_mode,
-        margin: Decimal::from_str(position["positionBalance"].as_str().unwrap()).unwrap(),
-    }
-}
-
-fn format_cancel_order_item(order: Value) -> Order {
-     Order {
-        id: format!("{}", order["orderId"].as_str().unwrap()),
-        custom_id: order["orderLinkId"].as_str().unwrap().replace("t-my-custom-id_", "").replace("t-", ""),
-        price: Decimal::ZERO,
-        amount: Decimal::ZERO,
-        deal_amount: Decimal::ZERO,
-        avg_price: Decimal::ZERO,
-        status: "REMOVE".to_string(),
-        order_type: "limit".to_string(),
-        trace_stack: TraceStack::new(0, Instant::now()).on_special("688 trace_stack".to_string())
-    }
-}
-
-fn format_new_order_item(order: Value, price: Decimal, amount: Decimal) -> Order {
-    Order {
-        id: format!("{}", order["orderId"].as_str().unwrap()),
-        custom_id: order["orderLinkId"].as_str().unwrap().replace("t-my-custom-id_", "").replace("t-", ""),
-        price,
-        amount,
-        deal_amount: Decimal::ZERO,
-        avg_price: price,
-        status: "NEW".to_string(),
-        order_type: "limit".to_string(),
-        trace_stack: TraceStack::new(0, Instant::now()).on_special("688 trace_stack".to_string())
-    }
-}
-
-pub fn format_order_item(order: Value, ct_val: Decimal) -> Order {
-    let status = order["orderStatus"].as_str().unwrap_or("");
-    let text = order["orderLinkId"].as_str().unwrap_or("");
-    let mut size = Decimal::ZERO;
-    let mut deal_amount = Decimal::ZERO;
-    let mut avg_price = Decimal::ZERO;
-
-    let right_str = order["cumExecQty"].to_string();
-    let size_str = order["qty"].to_string();
-
-    if !order.get("qty").is_some() {
-        size = Decimal::from_str(size_str.as_str()).unwrap();
-        let right_val = Decimal::from_str(order["cumExecValue"].as_str().unwrap()).unwrap();
-        let right = Decimal::from_str(right_str.as_str()).unwrap();
-        if right != Decimal::ZERO {
-            avg_price = right_val / right;
-        }
-        deal_amount = right * ct_val;
-    }
-
-    let amount = size * ct_val;
-    let custom_status = if status == "Filled" || status == "Cancelled" { "REMOVE".to_string() } else if status == "New" { "NEW".to_string() } else {
-        "NULL".to_string()
-    };
-    let rst_order = Order {
-        id: format!("{}", order["orderId"].as_str().unwrap()),
-        custom_id: text.replace("t-my-custom-id_", "").replace("t-", ""),
-        price: Decimal::from_str(order["price"].as_str().unwrap()).unwrap(),
-        amount,
-        deal_amount,
-        avg_price,
-        status: custom_status,
-        order_type: "limit".to_string(),
-        trace_stack: TraceStack::new(0, Instant::now()).on_special("688 trace_stack".to_string()),
-    };
-    return rst_order;
-}
+// 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 serde_json::{from_value, json, Value};
+// use rust_decimal::prelude::FromPrimitive;
+// use serde::{Deserialize, Serialize};
+// use tokio::time::Instant;
+// use tracing::{error, info, trace};
+// use exchanges::bybit_swap_rest::BybitSwapRest;
+// use crate::{Platform, ExchangeEnum, Account, Position, Ticker, Market, Order, OrderCommand, PositionModeEnum};
+// use global::trace_stack::TraceStack;
+//
+// #[derive(Debug, Clone, Deserialize, Serialize)]
+// #[serde(rename_all = "camelCase")]
+// struct SwapTicker {
+//     symbol: String,
+//     high_price24h: Decimal,
+//     low_price24h: Decimal,
+//     bid1_price: Decimal,
+//     ask1_price: Decimal,
+//     last_price: Decimal,
+//     volume24h: Decimal
+// }
+//
+// #[allow(dead_code)]
+// #[derive(Clone)]
+// pub struct BybitSwap {
+//     exchange: ExchangeEnum,
+//     symbol: String,
+//     symbol_uppercase: String,
+//     is_colo: bool,
+//     params: BTreeMap<String, String>,
+//     request: BybitSwapRest,
+//     market: Market,
+//     order_sender: Sender<Order>,
+//     error_sender: Sender<Error>,
+// }
+//
+// impl BybitSwap {
+//     pub async fn new(symbol: String, is_colo: bool, params: BTreeMap<String, String>, order_sender: Sender<Order>, error_sender: Sender<Error>) -> BybitSwap {
+//         let market = Market::new();
+//         let mut bybit_swap = BybitSwap {
+//             exchange: ExchangeEnum::BybitSwap,
+//             symbol: symbol.to_uppercase(),
+//             symbol_uppercase: symbol.replace("_", "").to_uppercase(),
+//             is_colo,
+//             params: params.clone(),
+//             request: BybitSwapRest::new(is_colo, params.clone()),
+//             market,
+//             order_sender,
+//             error_sender,
+//         };
+//
+//         // 修改持仓模式
+//         let symbol_array: Vec<&str> = symbol.split("_").collect();
+//         let mode_result = bybit_swap.set_dual_mode(symbol_array[1], true).await;
+//         match mode_result {
+//             Ok(_) => {
+//                 trace!("Bybit:设置持仓模式成功!")
+//             }
+//             Err(error) => {
+//                 error!("Bybit:设置持仓模式失败!mode_result={}", error)
+//             }
+//         }
+//         // 获取市场信息
+//         bybit_swap.market = BybitSwap::get_market(&mut bybit_swap).await.unwrap_or(bybit_swap.market);
+//         return bybit_swap;
+//     }
+// }
+//
+// #[async_trait]
+// impl Platform for BybitSwap {
+//     // 克隆方法
+//     fn clone_box(&self) -> Box<dyn Platform + Send + Sync> { Box::new(self.clone()) }
+//     // 获取交易所模式
+//     fn get_self_exchange(&self) -> ExchangeEnum {
+//         ExchangeEnum::GateSwap
+//     }
+//     // 获取交易对
+//     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_time().await;
+//         if res_data.code == 200 {
+//             let result = res_data.data["server_time"].to_string();
+//             Ok(result)
+//         } else {
+//             Err(Error::new(ErrorKind::Other, res_data.to_string()))
+//         }
+//     }
+//     // 获取账号信息
+//     async fn get_account(&mut self) -> Result<Account, Error> {
+//         let symbol_array: Vec<&str> = self.symbol.split("_").collect();
+//         let res_data = self.request.get_account_balance(symbol_array[1].parse().unwrap()).await;
+//         if res_data.code == 200 {
+//             let arr_infos: Vec<Value> = from_value(res_data.data["list"].clone()).unwrap();
+//             if arr_infos.len() < 1usize{
+//                 return Err(Error::new(ErrorKind::NotFound, format!("{} 无账户信息", symbol_array[1])));
+//             }
+//             let coin_infos: Vec<Value> = from_value(arr_infos[0]["coin"].clone()).unwrap();
+//             if coin_infos.len() < 1usize{
+//                return Err(Error::new(ErrorKind::NotFound, format!("{} 无账户信息", symbol_array[1])));
+//             }
+//             let balance = Decimal::from_str(coin_infos[0]["equity"].as_str().unwrap()).unwrap();
+//             let available_balance = Decimal::from_str(coin_infos[0]["walletBalance"].as_str().unwrap()).unwrap();
+//             let frozen_balance = balance - available_balance;
+//             let result = Account {
+//                 coin: symbol_array[1].to_string(),
+//                 balance,
+//                 available_balance,
+//                 frozen_balance,
+//                 stocks: Decimal::ZERO,
+//                 available_stocks: Decimal::ZERO,
+//                 frozen_stocks: Decimal::ZERO,
+//             };
+//             Ok(result)
+//         } else {
+//             Err(Error::new(ErrorKind::Other, res_data.to_string()))
+//         }
+//     }
+//
+//     async fn get_spot_account(&mut self) -> Result<Vec<Account>, Error> {
+//         Err(Error::new(ErrorKind::NotFound, "bybit_swap:该交易所方法未实现".to_string()))
+//     }
+//
+//     // 获取持仓信息
+//     async fn get_position(&mut self) -> Result<Vec<Position>, Error> {
+//         let symbol = self.symbol_uppercase.clone();
+//         let ct_val = self.market.ct_val;
+//         let res_data = self.request.get_positions(symbol, "".to_string()).await;
+//         if res_data.code == 200 {
+//             let result = res_data.data["list"].as_array().unwrap().iter().map(|item| { format_position_item(item, ct_val) }).collect();
+//             Ok(result)
+//         } else {
+//             Err(Error::new(ErrorKind::Other, res_data.to_string()))
+//         }
+//     }
+//     // 获取所有持仓
+//     async fn get_positions(&mut self) -> Result<Vec<Position>, Error> {
+//         let symbol_array: Vec<&str> = self.symbol.split("_").collect();
+//         let ct_val = self.market.ct_val;
+//         let res_data = self.request.get_positions("".to_string(), symbol_array[1].to_string().to_uppercase()).await;
+//         if res_data.code == 200 {
+//             info!("{}", res_data.data.to_string());
+//             let result = res_data.data["list"].as_array().unwrap().iter().map(|item| { format_position_item(item, ct_val) }).collect();
+//             Ok(result)
+//         } else {
+//             Err(Error::new(ErrorKind::Other, res_data.to_string()))
+//         }
+//     }
+//     // 获取市场行情
+//     async fn get_ticker(&mut self) -> Result<Ticker, Error> {
+//         let symbol = self.symbol_uppercase.clone();
+//         let res_data = self.request.get_tickers(symbol).await;
+//         if res_data.code == 200 {
+//             let list :Vec<SwapTicker> = from_value(res_data.data["list"].clone()).unwrap_or(Vec::new());
+//
+//             if list.len() < 1usize {
+//                 error!("bybit_swap:获取Ticker信息错误!\nget_ticker:res_data={:?}", res_data);
+//                 return Err(Error::new(ErrorKind::Other, res_data.to_string()));
+//             }
+//             let value = list[0].clone();
+//             Ok(Ticker{
+//                 time: chrono::Utc::now().timestamp_millis(),
+//                 high: value.high_price24h,
+//                 low: value.low_price24h,
+//                 sell: value.ask1_price,
+//                 buy: value.bid1_price,
+//                 last: value.last_price,
+//                 volume: value.volume24h
+//             })
+//         } else {
+//             Err(Error::new(ErrorKind::Other, res_data.to_string()))
+//         }
+//     }
+//
+//     async fn get_ticker_symbol(&mut self, symbol: String) -> Result<Ticker, Error> {
+//         let symbol_upper = symbol.replace("_", "").to_uppercase();
+//         let res_data = self.request.get_tickers(symbol_upper.clone()).await;
+//         if res_data.code == 200 {
+//             let list: Vec<SwapTicker> = from_value(res_data.data["list"].clone()).unwrap();
+//             let ticker_info = list.iter().find(|&item| item.symbol == symbol_upper);
+//
+//             match ticker_info {
+//                 None => {
+//                     error!("bybit_swap:获取Ticker信息错误!\nget_ticker:res_data={:?}", res_data);
+//                     Err(Error::new(ErrorKind::Other, res_data.to_string()))
+//                 }
+//                 Some(value) => {
+//                     let result = Ticker {
+//                         time: chrono::Utc::now().timestamp_millis(),
+//                         high: value.high_price24h,
+//                         low: value.low_price24h,
+//                         sell: value.ask1_price,
+//                         buy: value.bid1_price,
+//                         last: value.last_price,
+//                         volume: value.volume24h
+//                     };
+//                     Ok(result)
+//                 }
+//             }
+//         } else {
+//             Err(Error::new(ErrorKind::Other, res_data.to_string()))
+//         }
+//     }
+//
+//     async fn get_market(&mut self) -> Result<Market, Error> {
+//         let symbol = self.symbol_uppercase.clone();
+//         let res_data = self.request.get_instruments_info(symbol.clone()).await;
+//         if res_data.code == 200 {
+//             let arr_data: Vec<Value> = from_value(res_data.data["list"].clone()).unwrap();
+//             let market_info = arr_data.iter().find(|&item| item["symbol"].as_str().unwrap() == symbol);
+//             match market_info {
+//                 None => {
+//                     error!("bybit_swap:获取Market信息错误!\nget_market:res_data={:?}", res_data);
+//                     Err(Error::new(ErrorKind::Other, res_data.to_string()))
+//                 }
+//                 Some(value) => {
+//                     let base_coin = value["baseCoin"].as_str().unwrap();
+//                     let quote_coin = value["quoteCoin"].as_str().unwrap();
+//                     let name = format!("{}_{}",base_coin, quote_coin);
+//                     let tick_size = Decimal::from_str(value["priceFilter"]["minPrice"].as_str().unwrap().trim()).unwrap();
+//                     let min_qty = Decimal::from_str(value["lotSizeFilter"]["minOrderQty"].as_str().unwrap().trim()).unwrap();
+//                     let max_qty = Decimal::from_str(value["lotSizeFilter"]["maxOrderQty"].as_str().unwrap().trim()).unwrap();
+//                     let ct_val = Decimal::ONE;
+//
+//                     let amount_size = min_qty * ct_val;
+//                     let price_precision = Decimal::from_u32(tick_size.scale()).unwrap();
+//                     let amount_precision = Decimal::from_u32(amount_size.scale()).unwrap();
+//                     let min_notional = min_qty * ct_val;
+//                     let max_notional = max_qty * ct_val;
+//
+//                     let result = Market {
+//                         symbol: name,
+//                         base_asset: base_coin.to_string(),
+//                         quote_asset: quote_coin.to_string(),
+//                         tick_size,
+//                         amount_size,
+//                         price_precision,
+//                         amount_precision,
+//                         min_qty,
+//                         max_qty,
+//                         min_notional,
+//                         max_notional,
+//                         ct_val,
+//                     };
+//                     Ok(result)
+//                 }
+//             }
+//         } else {
+//             Err(Error::new(ErrorKind::Other, res_data.to_string()))
+//         }
+//     }
+//
+//     async fn get_market_symbol(&mut self, symbol: String) -> Result<Market, Error> {
+//         let symbol = symbol.replace("_", "").to_uppercase();
+//         let res_data = self.request.get_instruments_info(symbol.clone()).await;
+//         if res_data.code == 200 {
+//             let arr_data: Vec<Value> = from_value(res_data.data["list"].clone()).unwrap();
+//             let market_info = arr_data.iter().find(|item| item["symbol"].as_str().unwrap() == symbol);
+//             match market_info {
+//                 None => {
+//                     error!("bybit_swap:获取Market信息错误!\nget_market:res_data={:?}", res_data);
+//                     Err(Error::new(ErrorKind::Other, res_data.to_string()))
+//                 }
+//                 Some(value) => {
+//                     let base_coin = value["baseCoin"].as_str().unwrap();
+//                     let quote_coin = value["quoteCoin"].as_str().unwrap();
+//                     let name = format!("{}_{}",base_coin, quote_coin);
+//                     let tick_size = Decimal::from_str(value["priceFilter"]["minPrice"].as_str().unwrap().trim()).unwrap();
+//                     let min_qty = Decimal::from_str(value["lotSizeFilter"]["minOrderQty"].as_str().unwrap().trim()).unwrap();
+//                     let max_qty = Decimal::from_str(value["lotSizeFilter"]["maxOrderQty"].as_str().unwrap().trim()).unwrap();
+//                     let ct_val = Decimal::ONE;
+//
+//                     let amount_size = min_qty * ct_val;
+//                     let price_precision = Decimal::from_u32(tick_size.scale()).unwrap();
+//                     let amount_precision = Decimal::from_u32(amount_size.scale()).unwrap();
+//                     let min_notional = min_qty * ct_val;
+//                     let max_notional = max_qty * ct_val;
+//
+//                     let result = Market {
+//                         symbol: name,
+//                         base_asset: base_coin.to_string(),
+//                         quote_asset: quote_coin.to_string(),
+//                         tick_size,
+//                         amount_size,
+//                         price_precision,
+//                         amount_precision,
+//                         min_qty,
+//                         max_qty,
+//                         min_notional,
+//                         max_notional,
+//                         ct_val,
+//                     };
+//                     Ok(result)
+//                 }
+//             }
+//         } else {
+//             Err(Error::new(ErrorKind::Other, res_data.to_string()))
+//         }
+//     }
+//
+//     // 获取订单详情
+//     async fn get_order_detail(&mut self, order_id: &str, custom_id: &str) -> Result<Order, Error> {
+//         let symbol = self.symbol_uppercase.clone();
+//         let ct_val = self.market.ct_val;
+//         let id = if !custom_id.trim().eq("") { format!("t-{}", custom_id) } else { String::new() };
+//         let res_data = self.request.get_order(symbol, order_id.parse().unwrap(), id).await;
+//         if res_data.code == 200 {
+//             let res_data_json: Value = res_data.data["list"].clone();
+//             if res_data_json.is_array() && res_data_json.as_array().unwrap().len() == 0 {
+//                 return Err(Error::new(ErrorKind::Other, "没有该订单!"));
+//             }
+//             let result = format_order_item(res_data_json.as_array().unwrap()[0].clone(), ct_val);
+//             Ok(result)
+//         } else {
+//             Err(Error::new(ErrorKind::Other, res_data.to_string()))
+//         }
+//     }
+//     // 获取订单列表
+//     async fn get_orders_list(&mut self, _status: &str) -> Result<Vec<Order>, Error> {
+//        Err(Error::new(ErrorKind::Other, "bybit获取订单列表暂未实现".to_string()))
+//     }
+//     // 下单接口
+//     async fn take_order(&mut self, custom_id: &str, origin_side: &str, price: Decimal, amount: Decimal) -> Result<Order, Error> {
+//         let symbol = self.symbol_uppercase.clone();
+//         let ct_val = self.market.ct_val;
+//         let size = amount / ct_val;
+//         let mut params = json!({
+//             "orderLinkId": format!("t-{}", custom_id),
+//             "symbol": symbol.to_string(),
+//             "price": price.to_string(),
+//             "category": "linear",
+//             "orderType":"Limit",
+//             "qty": json!(size),
+//             // 0.單向持倉 1.買側雙向持倉 2.賣側雙向持倉
+//             "positionIdx": json!(1),
+//             "reduceOnly": json!(false)
+//         });
+//
+//         if price.eq(&Decimal::ZERO) {
+//             params["timeInForce"] = json!("IOC".to_string());
+//         }
+//         match origin_side {
+//             "kd" => {
+//                 params["side"] = json!("Buy");
+//             }
+//             "pd" => {
+//                 params["side"] = json!("Sell");
+//                 // 减仓
+//                 params["reduceOnly"] = json!(true);
+//             }
+//             "kk" => {
+//                 params["side"] = json!("Sell");
+//                 params["positionIdx"] = json!(2);
+//             }
+//             "pk" => {
+//                 params["side"] = json!("Buy");
+//                 // 减仓
+//                 params["reduceOnly"] = json!(true);
+//                 params["positionIdx"] = json!(2);
+//             }
+//             _ => { error!("下单参数错误"); }
+//         };
+//         let res_data = self.request.swap_order(params).await;
+//         if res_data.code == 200 {
+//             let result = format_new_order_item(res_data.data, price, size);
+//             Ok(result)
+//         } else {
+//             Err(Error::new(ErrorKind::Other, res_data.to_string()))
+//         }
+//     }
+//
+//     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_upper = symbol.replace("_", "").trim().to_uppercase();
+//         let size = (amount / ct_val).floor();
+//         let order_type = if price == Decimal::ZERO {
+//             "Market"
+//         } else {
+//             "Limit"
+//         };
+//         let mut params = json!({
+//             "orderLinkId": format!("t-{}", custom_id),
+//             "symbol": symbol_upper,
+//             "price": price.to_string(),
+//             "category": "linear",
+//             "orderType": order_type,
+//             "qty": json!(size),
+//             // 0.單向持倉 1.買側雙向持倉 2.賣側雙向持倉
+//             "positionIdx": json!(1),
+//             "reduceOnly": json!(false)
+//         });
+//
+//         if price.eq(&Decimal::ZERO) {
+//             params["timeInForce"] = json!("IOC".to_string());
+//         }
+//         match origin_side {
+//             "kd" => {
+//                 params["side"] = json!("Buy");
+//             }
+//             "pd" => {
+//                 params["side"] = json!("Sell");
+//                 params["positionIdx"] = json!(1);
+//                 // 减仓
+//                 params["reduceOnly"] = json!(true);
+//             }
+//             "kk" => {
+//                 params["side"] = json!("Sell");
+//                 params["positionIdx"] = json!(2);
+//             }
+//             "pk" => {
+//                 params["side"] = json!("Buy");
+//                 params["positionIdx"] = json!(2);
+//                 // 减仓
+//                 params["reduceOnly"] = json!(true);
+//             }
+//             _ => { error!("下单参数错误"); }
+//         };
+//         let res_data = self.request.swap_order(params.clone()).await;
+//         if res_data.code == 200 {
+//             let result = format_new_order_item(res_data.data, price, size);
+//             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 = self.symbol_uppercase.clone();
+//         let id = format!("t-{}", custom_id);
+//         let res_data = self.request.cancel_order(symbol, String::from(order_id), id.clone()).await;
+//         if res_data.code == 200 {
+//             let result = format_cancel_order_item(res_data.data);
+//             Ok(result)
+//         } else {
+//             Err(Error::new(ErrorKind::Other, res_data.to_string()))
+//         }
+//     }
+//     // 批量撤销订单
+//     async fn cancel_orders(&mut self) -> Result<Vec<Order>, Error> {
+//         let symbol = self.symbol_uppercase.clone();
+//         let res_data = self.request.cancel_orders(symbol).await;
+//         if res_data.code == 200 {
+//             info!("{}", res_data.data.to_string());
+//             let res_arr: Vec<Value> = from_value(res_data.data).unwrap();
+//             let result = res_arr.iter().map(|item| format_cancel_order_item(item.clone())).collect();
+//             Ok(result)
+//         } else {
+//             Err(Error::new(ErrorKind::Other, res_data.to_string()))
+//         }
+//     }
+//
+//     async fn cancel_orders_all(&mut self) -> Result<Vec<Order>, Error> {
+//         let symbol = self.symbol_uppercase.clone();
+//         let res_data = self.request.cancel_orders(symbol).await;
+//         if res_data.code == 200 {
+//             info!("{}", res_data.data.to_string());
+//             let res_arr: Vec<Value> = from_value(res_data.data["list"].clone()).unwrap();
+//             let result = res_arr.iter().map(|item| format_cancel_order_item(item.clone())).collect();
+//             Ok(result)
+//         } else {
+//             Err(Error::new(ErrorKind::Other, res_data.to_string()))
+//         }
+//     }
+//
+//     async fn take_stop_loss_order(&mut self, _stop_price: Decimal, _price: Decimal, _side: &str) -> Result<Value, Error> {
+//         Err(Error::new(ErrorKind::NotFound, "bybit_swap:该交易所方法未实现".to_string()))
+//     }
+//
+//     async fn cancel_stop_loss_order(&mut self, _order_id: &str) -> Result<Value, Error> {
+//         Err(Error::new(ErrorKind::NotFound, "bybit_swap:该交易所方法未实现".to_string()))
+//     }
+//
+//     // 设置持仓模式
+//     async fn set_dual_mode(&mut self, _coin: &str, is_dual_mode: bool) -> Result<String, Error> {
+//         let coin_format = self.symbol_uppercase.clone();
+//         let mut mod_num = 0;
+//         if is_dual_mode {
+//             mod_num = 3;
+//         }
+//         let res_data = self.request.set_position_mode(coin_format, mod_num).await;
+//         if res_data.code == 200 {
+//             Ok(res_data.data.to_string())
+//         } else {
+//             Err(Error::new(ErrorKind::Other, res_data.to_string()))
+//         }
+//     }
+//
+//     // 更新双持仓模式下杠杆
+//     async fn set_dual_leverage(&mut self, leverage: &str) -> Result<String, Error> {
+//         let symbol = self.symbol_uppercase.clone();
+//         let res_data = self.request.set_leverage(symbol, leverage.to_string()).await;
+//         if res_data.code == 200 {
+//             Ok(res_data.data.to_string())
+//         } else {
+//             Err(Error::new(ErrorKind::Other, res_data.to_string()))
+//         }
+//     }
+//
+//     async fn set_auto_deposit_status(&mut self, _status: bool) -> Result<String, Error> { Err(Error::new(ErrorKind::NotFound, "gate:该交易所方法未实现".to_string())) }
+//
+//     // 交易账户互转
+//     async fn wallet_transfers(&mut self, _coin: &str, _from: &str, _to: &str, _amount: Decimal) -> Result<String, Error> {
+//         // let coin_format = coin.to_string().to_lowercase();
+//         // let res_data = self.request.wallet_transfers(coin_format.clone(), from.to_string(), to.to_string(), amount.to_string(), coin_format.clone()).await;
+//         // if res_data.code == 200 {
+//         //     let res_data_str = &res_data.data;
+//         //     let result = res_data_str.clone();
+//         //     Ok(result)
+//         // } else {
+//         //     Err(Error::new(ErrorKind::Other, res_data.to_string()))
+//         // }
+//         Err(Error::new(ErrorKind::Other, "暂未实现!"))
+//     }
+//
+//     // 指令下单
+//     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 self_clone = self.clone();
+//
+//             let amount = Decimal::from_str(order_command.limits_open[item].get(0).unwrap_or(&"0".to_string())).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_or(&"0".to_string())).unwrap();
+//             let cid = order_command.limits_open[item].get(3).unwrap().clone();
+//
+//             let mut ts = trace_stack.clone();
+//
+//             let handle = tokio::spawn(async move {
+//                 ts.on_before_send();
+//                 // TraceStack::show_delay(&ts.ins);
+//                 let result = self_clone.take_order(cid.as_str(), side.as_str(), price, amount).await;
+//                 ts.on_after_send();
+//                 match result {
+//                     Ok(mut result) => {
+//                         // 记录此订单完成时间
+//                         result.trace_stack = ts;
+//
+//                         self_clone.order_sender.send(result).await.unwrap();
+//                     }
+//                     Err(error) => {
+//                         error!("bybit:下单失败:{:?}", error);
+//
+//                         let mut err_order = Order::new();
+//                         err_order.custom_id = cid.clone();
+//                         err_order.status = "REMOVE".to_string();
+//
+//                         self_clone.order_sender.send(err_order).await.unwrap();
+//                         self_clone.error_sender.send(error).await.unwrap();
+//                     }
+//                 }
+//             });
+//             handles.push(handle)
+//         }
+//         let futures = FuturesUnordered::from_iter(handles);
+//         let _: Result<Vec<_>, _> = futures.try_collect().await;
+//
+//         // 撤销订单
+//         let mut cancel_handles = vec![];
+//         for item in order_command.cancel.keys() {
+//             let mut self_clone = self.clone();
+//
+//             let order_id = order_command.cancel[item].get(1).unwrap().clone();
+//             let custom_id = order_command.cancel[item].get(0).unwrap().clone();
+//
+//             let handle = tokio::spawn(async move {
+//                 let result = self_clone.cancel_order(&order_id, &custom_id).await;
+//                 match result {
+//                     Ok(_) => {
+//                         // result_sd.send(result).await.unwrap();
+//                     }
+//                     Err(error) => {
+//                         // 取消失败去查订单。
+//                         let query_rst = self_clone.get_order_detail(&order_id, &custom_id).await;
+//                         match query_rst {
+//                             Ok(order) => {
+//                                 self_clone.order_sender.send(order).await.unwrap();
+//                             }
+//                             Err(_err) => {
+//                                 error!("bybit:撤单失败,而且查单也失败了,oid={}, cid={}。", order_id.clone(), custom_id.clone());
+//                             }
+//                         }
+//                         self_clone.error_sender.send(error).await.unwrap();
+//                     }
+//                 }
+//             });
+//             cancel_handles.push(handle)
+//         }
+//         let futures = FuturesUnordered::from_iter(cancel_handles);
+//         let _: Result<Vec<_>, _> = futures.try_collect().await;
+//
+//         // 检查订单指令
+//         let mut check_handles = vec![];
+//         for item in order_command.check.keys() {
+//             let mut self_clone = self.clone();
+//
+//             let order_id = order_command.check[item].get(1).unwrap().clone();
+//             let custom_id = order_command.check[item].get(0).unwrap().clone();
+//
+//             let handle = tokio::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_handles.push(handle)
+//         }
+//         let futures = FuturesUnordered::from_iter(check_handles);
+//         let _: Result<Vec<_>, _> = futures.try_collect().await;
+//     }
+// }
+//
+// pub fn format_position_item(position: &Value, ct_val: Decimal) -> Position {
+//     let position_idx = position["positionIdx"].to_string();
+//     let mut position_mode = match position_idx.as_str() {
+//         "0" => PositionModeEnum::Both,
+//         "1" => PositionModeEnum::Long,
+//         "2" => PositionModeEnum::Short,
+//         _ => {
+//             error!("bybit_swap:格式化持仓模式错误!\nformat_position_item:position={:?}", position);
+//             panic!("bybit_swap:格式化持仓模式错误!\nformat_position_item:position={:?}", position)
+//         }
+//     };
+//     let size_str: String = from_value(position["size"].clone()).unwrap();
+//     let size = Decimal::from_str(size_str.as_str()).unwrap();
+//     let amount = size * ct_val;
+//     let mut profit = Decimal::ZERO;
+//     let profit_str = position["unrealisedPnl"].as_str().unwrap_or("0");
+//     if profit_str != "" {
+//         profit = Decimal::from_str(profit_str).unwrap();
+//     }
+//
+//     match position_mode {
+//         PositionModeEnum::Both => {
+//             position_mode = match amount {
+//                 amount if amount > Decimal::ZERO => PositionModeEnum::Long,
+//                 amount if amount < Decimal::ZERO => PositionModeEnum::Short,
+//                 _ => { PositionModeEnum::Both }
+//             }
+//         }
+//         _ => {}
+//     }
+//     Position {
+//         symbol: position["symbol"].as_str().unwrap_or("").parse().unwrap(),
+//         margin_level: Decimal::from_str(position["leverage"].as_str().unwrap()).unwrap(),
+//         amount,
+//         frozen_amount: Decimal::ZERO,
+//         price: Decimal::from_str(position["avgPrice"].as_str().unwrap()).unwrap(),
+//         profit,
+//         position_mode,
+//         margin: Decimal::from_str(position["positionBalance"].as_str().unwrap()).unwrap(),
+//     }
+// }
+//
+// fn format_cancel_order_item(order: Value) -> Order {
+//      Order {
+//         id: format!("{}", order["orderId"].as_str().unwrap()),
+//         custom_id: order["orderLinkId"].as_str().unwrap().replace("t-my-custom-id_", "").replace("t-", ""),
+//         price: Decimal::ZERO,
+//         amount: Decimal::ZERO,
+//         deal_amount: Decimal::ZERO,
+//         avg_price: Decimal::ZERO,
+//         status: "REMOVE".to_string(),
+//         order_type: "limit".to_string(),
+//         trace_stack: TraceStack::new(0, Instant::now()).on_special("688 trace_stack".to_string())
+//     }
+// }
+//
+// fn format_new_order_item(order: Value, price: Decimal, amount: Decimal) -> Order {
+//     Order {
+//         id: format!("{}", order["orderId"].as_str().unwrap()),
+//         custom_id: order["orderLinkId"].as_str().unwrap().replace("t-my-custom-id_", "").replace("t-", ""),
+//         price,
+//         amount,
+//         deal_amount: Decimal::ZERO,
+//         avg_price: price,
+//         status: "NEW".to_string(),
+//         order_type: "limit".to_string(),
+//         trace_stack: TraceStack::new(0, Instant::now()).on_special("688 trace_stack".to_string())
+//     }
+// }
+//
+// pub fn format_order_item(order: Value, ct_val: Decimal) -> Order {
+//     let status = order["orderStatus"].as_str().unwrap_or("");
+//     let text = order["orderLinkId"].as_str().unwrap_or("");
+//     let mut size = Decimal::ZERO;
+//     let mut deal_amount = Decimal::ZERO;
+//     let mut avg_price = Decimal::ZERO;
+//
+//     let right_str = order["cumExecQty"].to_string();
+//     let size_str = order["qty"].to_string();
+//
+//     if !order.get("qty").is_some() {
+//         size = Decimal::from_str(size_str.as_str()).unwrap();
+//         let right_val = Decimal::from_str(order["cumExecValue"].as_str().unwrap()).unwrap();
+//         let right = Decimal::from_str(right_str.as_str()).unwrap();
+//         if right != Decimal::ZERO {
+//             avg_price = right_val / right;
+//         }
+//         deal_amount = right * ct_val;
+//     }
+//
+//     let amount = size * ct_val;
+//     let custom_status = if status == "Filled" || status == "Cancelled" { "REMOVE".to_string() } else if status == "New" { "NEW".to_string() } else {
+//         "NULL".to_string()
+//     };
+//     let rst_order = Order {
+//         id: format!("{}", order["orderId"].as_str().unwrap()),
+//         custom_id: text.replace("t-my-custom-id_", "").replace("t-", ""),
+//         price: Decimal::from_str(order["price"].as_str().unwrap()).unwrap(),
+//         amount,
+//         deal_amount,
+//         avg_price,
+//         status: custom_status,
+//         order_type: "limit".to_string(),
+//         trace_stack: TraceStack::new(0, Instant::now()).on_special("688 trace_stack".to_string()),
+//     };
+//     return rst_order;
+// }

+ 167 - 172
standard/src/bybit_swap_handle.rs

@@ -1,172 +1,167 @@
-use std::str::FromStr;
-use rust_decimal::Decimal;
-use rust_decimal::prelude::{FromPrimitive, ToPrimitive};
-use rust_decimal_macros::dec;
-use serde_json::{from_value, 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 {
-    format_account_info(res_data.data.as_array().unwrap().clone(), symbol)
-}
-
-pub fn format_account_info(data: Vec<Value>, symbol: &String) -> Account {
-    let account = data.iter().find(| &item | item["accountType"] == "UNIFIED");
-    match account {
-        None => {
-            error!("Bybit:格式化统一账户信息错误!\nformat_account_info: data={:?}", data);
-            panic!("Bybit:格式化统一账户信息错误!\nformat_account_info: data={:?}", data)
-        }
-        Some(val) =>{
-            let arr: Vec<Value> = from_value(val["coin"].clone()).unwrap();
-            let upper_str = symbol.to_uppercase();
-            let symbol_array: Vec<&str> = upper_str.split("_").collect();
-            let balance_info = arr.iter().find(|&item| item["coin"].as_str().unwrap() == symbol_array[1]);
-            match balance_info {
-                None => {
-                    error!("Bybit:格式化usdt余额信息错误!\nformat_account_info: data={:?}", balance_info);
-                    panic!("Bybit:格式化usdt余额信息错误!\nformat_account_info: data={:?}", balance_info)
-                }
-                Some(value) => {
-                    let balance = Decimal::from_str(&value["walletBalance"].as_str().unwrap().to_string()).unwrap();
-                    Account {
-                        coin: symbol_array[1].to_string(),
-                        balance,
-                        available_balance: Decimal::ZERO,
-                        frozen_balance: Decimal::ZERO,
-                        stocks: Decimal::ZERO,
-                        available_stocks: Decimal::ZERO,
-                        frozen_stocks: Decimal::ZERO,
-                    }
-                }
-            }
-        }
-    }
-}
-
-// 处理position信息
-pub fn handle_position(res_data: &ResponseData, ct_val: &Decimal) -> Vec<Position> {
-    res_data.data.as_array().unwrap().iter().map(|item| { format_position_item(item, ct_val) }).collect()
-}
-
-pub fn format_position_item(position: &Value, ct_val: &Decimal) -> Position {
-    let position_idx: String = position["positionIdx"].to_string();
-    let mut position_mode = match position_idx.as_str() {
-        "0" => PositionModeEnum::Both,
-        "1" => PositionModeEnum::Long,
-        "2" => PositionModeEnum::Short,
-        _ => {
-            error!("bybit_swap:格式化持仓模式错误!\nformat_position_item:position={:?}", position);
-            panic!("bybit_swap:格式化持仓模式错误!\nformat_position_item:position={:?}", position)
-        }
-    };
-    let symbol_mapper =  position["symbol"].as_str().unwrap().to_string();
-    let currency = "USDT";
-    let coin = &symbol_mapper[..symbol_mapper.find(currency).unwrap_or(0)];
-    let size_str: String = from_value(position["size"].clone()).unwrap();
-    let size = Decimal::from_str(size_str.as_str()).unwrap();
-    let amount = size * ct_val;
-    match position_mode {
-        PositionModeEnum::Both => {
-            position_mode = match amount {
-                amount if amount > Decimal::ZERO => PositionModeEnum::Long,
-                amount if amount < Decimal::ZERO => PositionModeEnum::Short,
-                _ => { PositionModeEnum::Both }
-            }
-        }
-        _ => {}
-    }
-    Position {
-        symbol: format!{"{}_{}", coin, currency},
-        margin_level: Decimal::from_str(position["leverage"].as_str().unwrap()).unwrap(),
-        amount,
-        frozen_amount: Decimal::ZERO,
-        price: Decimal::from_str(position["entryPrice"].as_str().unwrap()).unwrap(),
-        profit: Decimal::from_str(position["unrealisedPnl"].as_str().unwrap()).unwrap(),
-        position_mode,
-        margin: Decimal::from_str(position["positionBalance"].as_str().unwrap()).unwrap(),
-    }
-}
-
-// 处理order信息
-pub fn handle_order(res_data: ResponseData, ct_val: Decimal) -> SpecialOrder {
-    let res_data_json: Vec<Value> = res_data.data.as_array().unwrap().clone();
-    let mut order_info = Vec::new();
-    for item in res_data_json.iter() {
-        order_info.push(format_order_item(item.clone(), ct_val));
-    };
-
-    SpecialOrder {
-        name: res_data.label,
-        order: order_info,
-    }
-}
-
-pub fn format_order_item(order: Value, ct_val: Decimal) -> Order {
-    let status = order["orderStatus"].as_str().unwrap_or("");
-    let text = order["orderLinkId"].as_str().unwrap_or("");
-    let size = Decimal::from_str(order["qty"].as_str().unwrap()).unwrap();
-    let right = Decimal::from_str(order["cumExecQty"].as_str().unwrap()).unwrap();
-    let right_val = Decimal::from_str(order["cumExecValue"].as_str().unwrap()).unwrap();
-    let price = Decimal::from_str(order["price"].as_str().unwrap()).unwrap();
-    let amount = size * ct_val;
-    let mut avg_price = Decimal::ZERO;
-    if right != Decimal::ZERO {
-        avg_price = right_val / right;
-    }
-    let deal_amount = right * ct_val;
-    let custom_status = if status == "Filled" || status == "Cancelled" { "REMOVE".to_string() } else if status == "New" { "NEW".to_string() } else {
-        "NULL".to_string()
-    };
-    let rst_order = Order {
-        id: format!("{}", order["orderId"].as_str().unwrap()),
-        custom_id: text.replace("t-my-custom-id_", "").replace("t-", ""),
-        price,
-        amount,
-        deal_amount,
-        avg_price,
-        status: custom_status,
-        order_type: "limit".to_string(),
-        trace_stack: TraceStack::new(0, Instant::now()).on_special("120 bybit_handle".to_string()),
-    };
-
-    return rst_order;
-}
-
-// 处理特殊Ticket信息
-pub fn handle_ticker(res_data: &ResponseData) -> SpecialDepth {
-    let ap = Decimal::from_str(res_data.data["ask1Price"].as_str().unwrap()).unwrap();
-    let bp = Decimal::from_str(res_data.data["bid1Price"].as_str().unwrap()).unwrap();
-    let aq = Decimal::from_str(res_data.data["ask1Size"].as_str().unwrap()).unwrap();
-    let bq = Decimal::from_str(res_data.data["bid1Size"].as_str().unwrap()).unwrap();
-    let mp = (bp + ap) * dec!(0.5);
-
-    let t = Decimal::from_i64(res_data.data["ts"].as_i64().unwrap()).unwrap();
-    let create_at = t.to_i64().unwrap();
-
-    let ticker_info = SpecialTicker { sell: ap, buy: bp, mid_price: mp, t, create_at: 0 };
-    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(value: serde_json::Value) -> Vec<MarketOrder> {
-    let mut depth_items: Vec<MarketOrder> = vec![];
-    for val in value.as_array().unwrap() {
-        let arr = val.as_array().unwrap();
-        depth_items.push(MarketOrder {
-            price: Decimal::from_str(arr[0].as_str().unwrap()).unwrap(),
-            amount: Decimal::from_str(arr[1].as_str().unwrap()).unwrap(),
-        })
-    }
-    return depth_items;
-}
+// use std::str::FromStr;
+// use rust_decimal::Decimal;
+// use serde_json::{from_value, Value};
+// use tracing::{error};
+// use exchanges::response_base::ResponseData;
+// use crate::{Account, OrderBook, Order, Position, PositionModeEnum, SpecialOrder};
+//
+// // 处理账号信息
+// pub fn handle_account_info(res_data: &ResponseData, symbol: &String) -> Account {
+//     format_account_info(res_data.data.as_array().unwrap().clone(), symbol)
+// }
+//
+// pub fn format_account_info(data: Vec<Value>, symbol: &String) -> Account {
+//     let account = data.iter().find(| &item | item["accountType"] == "UNIFIED");
+//     match account {
+//         None => {
+//             error!("Bybit:格式化统一账户信息错误!\nformat_account_info: data={:?}", data);
+//             panic!("Bybit:格式化统一账户信息错误!\nformat_account_info: data={:?}", data)
+//         }
+//         Some(val) =>{
+//             let arr: Vec<Value> = from_value(val["coin"].clone()).unwrap();
+//             let upper_str = symbol.to_uppercase();
+//             let symbol_array: Vec<&str> = upper_str.split("_").collect();
+//             let balance_info = arr.iter().find(|&item| item["coin"].as_str().unwrap() == symbol_array[1]);
+//             match balance_info {
+//                 None => {
+//                     error!("Bybit:格式化usdt余额信息错误!\nformat_account_info: data={:?}", balance_info);
+//                     panic!("Bybit:格式化usdt余额信息错误!\nformat_account_info: data={:?}", balance_info)
+//                 }
+//                 Some(value) => {
+//                     let balance = Decimal::from_str(&value["walletBalance"].as_str().unwrap().to_string()).unwrap();
+//                     Account {
+//                         coin: symbol_array[1].to_string(),
+//                         balance,
+//                         available_balance: Decimal::ZERO,
+//                         frozen_balance: Decimal::ZERO,
+//                         stocks: Decimal::ZERO,
+//                         available_stocks: Decimal::ZERO,
+//                         frozen_stocks: Decimal::ZERO,
+//                     }
+//                 }
+//             }
+//         }
+//     }
+// }
+//
+// // 处理position信息
+// pub fn handle_position(res_data: &ResponseData, ct_val: &Decimal) -> Vec<Position> {
+//     res_data.data.as_array().unwrap().iter().map(|item| { format_position_item(item, ct_val) }).collect()
+// }
+//
+// pub fn format_position_item(position: &Value, ct_val: &Decimal) -> Position {
+//     let position_idx: String = position["positionIdx"].to_string();
+//     let mut position_mode = match position_idx.as_str() {
+//         "0" => PositionModeEnum::Both,
+//         "1" => PositionModeEnum::Long,
+//         "2" => PositionModeEnum::Short,
+//         _ => {
+//             error!("bybit_swap:格式化持仓模式错误!\nformat_position_item:position={:?}", position);
+//             panic!("bybit_swap:格式化持仓模式错误!\nformat_position_item:position={:?}", position)
+//         }
+//     };
+//     let symbol_mapper =  position["symbol"].as_str().unwrap().to_string();
+//     let currency = "USDT";
+//     let coin = &symbol_mapper[..symbol_mapper.find(currency).unwrap_or(0)];
+//     let size_str: String = from_value(position["size"].clone()).unwrap();
+//     let size = Decimal::from_str(size_str.as_str()).unwrap();
+//     let amount = size * ct_val;
+//     match position_mode {
+//         PositionModeEnum::Both => {
+//             position_mode = match amount {
+//                 amount if amount > Decimal::ZERO => PositionModeEnum::Long,
+//                 amount if amount < Decimal::ZERO => PositionModeEnum::Short,
+//                 _ => { PositionModeEnum::Both }
+//             }
+//         }
+//         _ => {}
+//     }
+//     Position {
+//         symbol: format!{"{}_{}", coin, currency},
+//         margin_level: Decimal::from_str(position["leverage"].as_str().unwrap()).unwrap(),
+//         amount,
+//         frozen_amount: Decimal::ZERO,
+//         price: Decimal::from_str(position["entryPrice"].as_str().unwrap()).unwrap(),
+//         profit: Decimal::from_str(position["unrealisedPnl"].as_str().unwrap()).unwrap(),
+//         position_mode,
+//         margin: Decimal::from_str(position["positionBalance"].as_str().unwrap()).unwrap(),
+//     }
+// }
+//
+// // 处理order信息
+// pub fn handle_order(res_data: &ResponseData, ct_val: Decimal) -> SpecialOrder {
+//     let res_data_json: Vec<Value> = res_data.data.as_array().unwrap().clone();
+//     let mut order_info = Vec::new();
+//     for item in res_data_json.iter() {
+//         order_info.push(format_order_item(item.clone(), ct_val));
+//     };
+//
+//     SpecialOrder {
+//         name: res_data.label.clone(),
+//         order: order_info,
+//     }
+// }
+//
+// pub fn format_order_item(order: Value, ct_val: Decimal) -> Order {
+//     let status = order["orderStatus"].as_str().unwrap_or("");
+//     let text = order["orderLinkId"].as_str().unwrap_or("");
+//     let size = Decimal::from_str(order["qty"].as_str().unwrap()).unwrap();
+//     let right = Decimal::from_str(order["cumExecQty"].as_str().unwrap()).unwrap();
+//     let right_val = Decimal::from_str(order["cumExecValue"].as_str().unwrap()).unwrap();
+//     let price = Decimal::from_str(order["price"].as_str().unwrap()).unwrap();
+//     let amount = size * ct_val;
+//     let mut avg_price = Decimal::ZERO;
+//     if right != Decimal::ZERO {
+//         avg_price = right_val / right;
+//     }
+//     let deal_amount = right * ct_val;
+//     let custom_status = if status == "Filled" || status == "Cancelled" { "REMOVE".to_string() } else if status == "New" { "NEW".to_string() } else {
+//         "NULL".to_string()
+//     };
+//     let rst_order = Order {
+//         id: format!("{}", order["orderId"].as_str().unwrap()),
+//         custom_id: text.replace("t-my-custom-id_", "").replace("t-", ""),
+//         price,
+//         amount,
+//         deal_amount,
+//         avg_price,
+//         status: custom_status,
+//         order_type: "limit".to_string()
+//     };
+//
+//     return rst_order;
+// }
+//
+// // 处理特殊Ticket信息
+// // pub fn handle_ticker(res_data: &ResponseData) -> SpecialDepth {
+// //     let ap = Decimal::from_str(res_data.data["ask1Price"].as_str().unwrap()).unwrap();
+// //     let bp = Decimal::from_str(res_data.data["bid1Price"].as_str().unwrap()).unwrap();
+// //     let aq = Decimal::from_str(res_data.data["ask1Size"].as_str().unwrap()).unwrap();
+// //     let bq = Decimal::from_str(res_data.data["bid1Size"].as_str().unwrap()).unwrap();
+// //     let mp = (bp + ap) * dec!(0.5);
+// //
+// //     let t = Decimal::from_i64(res_data.data["ts"].as_i64().unwrap()).unwrap();
+// //     let create_at = t.to_i64().unwrap();
+// //
+// //     let ticker_info = SpecialTicker { sell: ap, buy: bp, mid_price: mp, t, create_at: 0 };
+// //     let depth_info = vec![bp, bq, ap, aq];
+// //     SpecialDepth {
+// //         name: res_data.tag.clone(),
+// //         depth: depth_info,
+// //         ticker: ticker_info,
+// //         t,
+// //         create_at,
+// //     }
+// // }
+//
+// pub fn format_depth_items(value: serde_json::Value) -> Vec<OrderBook> {
+//     let mut depth_items: Vec<OrderBook> = vec![];
+//     for val in value.as_array().unwrap() {
+//         let arr = val.as_array().unwrap();
+//         depth_items.push(OrderBook {
+//             price: Decimal::from_str(arr[0].as_str().unwrap()).unwrap(),
+//             amount: Decimal::from_str(arr[1].as_str().unwrap()).unwrap(),
+//         })
+//     }
+//     return depth_items;
+// }

+ 771 - 771
standard/src/coinex_swap.rs

@@ -1,771 +1,771 @@
-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::prelude::{FromPrimitive, ToPrimitive};
-use serde_json::{Value};
-use tokio::spawn;
-use tokio::time::Instant;
-use tracing::{error, info, trace};
-use exchanges::coinex_swap_rest::CoinexSwapRest;
-use crate::{Platform, ExchangeEnum, Account, Position, Ticker, Market, Order, OrderCommand, PositionModeEnum, utils};
-use global::trace_stack::TraceStack;
-use crate::utils::get_tick_size;
-
-#[allow(dead_code)]
-#[derive(Clone)]
-pub struct CoinexSwap {
-    exchange: ExchangeEnum,
-    symbol: String,
-    is_colo: bool,
-    params: BTreeMap<String, String>,
-    request: CoinexSwapRest,
-    market: Market,
-    order_sender: Sender<Order>,
-    error_sender: Sender<Error>,
-}
-
-impl CoinexSwap {
-    pub async fn new(symbol: String, is_colo: bool, params: BTreeMap<String, String>, order_sender: Sender<Order>, error_sender: Sender<Error>) -> CoinexSwap {
-        let market = Market::new();
-        let mut coinex_swap = CoinexSwap {
-            exchange: ExchangeEnum::CoinexSwap,
-            symbol: symbol.to_uppercase(),
-            is_colo,
-            params: params.clone(),
-            request: CoinexSwapRest::new(params.clone()),
-            market,
-            order_sender,
-            error_sender,
-        };
-
-        // 修改持仓模式
-        let symbol_array: Vec<&str> = symbol.split("_").collect();
-        let mode_result = coinex_swap.set_dual_mode(symbol_array[1], true).await;
-        match mode_result {
-            Ok(_) => {
-                trace!("Coinex:设置持仓模式成功!")
-            }
-            Err(error) => {
-                error!("Coinex:设置持仓模式失败!mode_result={}", error)
-            }
-        }
-        // 获取市场信息
-        coinex_swap.market = CoinexSwap::get_market(&mut coinex_swap).await.unwrap_or(coinex_swap.market);
-        // 设置持仓杠杆
-        let lever_rate_result = coinex_swap.set_dual_leverage("10").await;
-        match lever_rate_result {
-            Ok(ok) => {
-                info!("Coinex:设置持仓杠杆成功!{:?}", ok);
-            }
-            Err(error) => {
-                error!("Coinex:设置持仓杠杆失败!{:?}", error)
-            }
-        }
-        return coinex_swap;
-    }
-}
-
-#[async_trait]
-impl Platform for CoinexSwap {
-    // 克隆方法
-    fn clone_box(&self) -> Box<dyn Platform + Send + Sync> { Box::new(self.clone()) }
-    // 获取交易所模式
-    fn get_self_exchange(&self) -> ExchangeEnum {
-        ExchangeEnum::CoinexSwap
-    }
-    // 获取交易对
-    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_time().await;
-        if res_data.code == 200 {
-            let res_data_json: Value = res_data.data;
-            let result = res_data_json["timestamp"].to_string();
-            Ok(result)
-        } else {
-            Err(Error::new(ErrorKind::Other, res_data.to_string()))
-        }
-    }
-    // 获取账号信息
-    async fn get_account(&mut self) -> Result<Account, Error> {
-        let symbol_array: Vec<&str> = self.symbol.split("_").collect();
-        let coin = symbol_array[1].to_string().to_uppercase();
-        let res_data = self.request.get_account().await;
-        if res_data.code == 200 {
-            if res_data.data.is_array() {
-                let res_data_array = res_data.data.as_array().unwrap();
-                for res_data_json in res_data_array.iter() {
-                    if res_data_json["ccy"].as_str().unwrap() == coin {
-                        let frozen_balance= Decimal::from_str(res_data_json["frozen"].as_str().unwrap()).unwrap();
-                        let available_balance = Decimal::from_str(res_data_json["available"].as_str().unwrap()).unwrap();
-                        let balance = frozen_balance + available_balance;
-                        let result = Account {
-                            coin: symbol_array[1].to_string(),
-                            balance,
-                            available_balance,
-                            frozen_balance,
-                            stocks: Decimal::ZERO,
-                            available_stocks: Decimal::ZERO,
-                            frozen_stocks: Decimal::ZERO,
-                        };
-                        return Ok(result);
-                    }
-                }
-            }
-        }
-        Err(Error::new(ErrorKind::Other, res_data.to_string()))
-    }
-
-    async fn get_spot_account(&mut self) -> Result<Vec<Account>, Error> {
-        Err(Error::new(ErrorKind::NotFound, "coinex_swap:该方法暂未实现".to_string()))
-    }
-
-    // 获取持仓信息
-    async fn get_position(&mut self) -> Result<Vec<Position>, Error> {
-        let symbol: String = self.symbol.replace("_", "").to_uppercase();
-        let ct_val = self.market.ct_val;
-        let res_data = self.request.get_position(symbol).await;
-        if res_data.code == 200 {
-            let res_data_json = res_data.data.as_array().unwrap();
-            let result = res_data_json.iter().map(|item| { format_position_item(item, ct_val) }).collect();
-            Ok(result)
-        } else {
-            Err(Error::new(ErrorKind::Other, res_data.to_string()))
-        }
-    }
-
-    // 获取所有持仓
-    async fn get_positions(&mut self) -> Result<Vec<Position>, Error> {
-        let res_data = self.request.get_user_position().await;
-        if res_data.code == 200 {
-            info!("{}", res_data.data.to_string());
-            let res_data_json = res_data.data.as_array().unwrap();
-            let result = res_data_json.iter().map(|item| { format_position_item(item, Decimal::ONE) }).collect();
-            Ok(result)
-        } else {
-            Err(Error::new(ErrorKind::Other, res_data.to_string()))
-        }
-    }
-    // 获取市场行情
-    async fn get_ticker(&mut self) -> Result<Ticker, Error> {
-        let symbol: String = self.symbol.replace("_", "");
-        let res_data = self.request.get_ticker(symbol.clone()).await;
-        if res_data.code == 200 {
-            let res_data_json = res_data.data.as_array().unwrap();
-            let ticker_info = res_data_json.iter().find(|item| item["market"].as_str().unwrap() == symbol);
-            match ticker_info {
-                None => {
-                    error!("coinex_swap:获取Ticker信息错误!\nget_ticker:res_data={:?}", res_data);
-                    Err(Error::new(ErrorKind::Other, res_data.to_string()))
-                }
-                Some(value) => {
-                    let result = Ticker {
-                        time: chrono::Utc::now().timestamp_millis(),
-                        high: Decimal::from_str(value["high"].as_str().unwrap()).unwrap(),
-                        low: Decimal::from_str(value["low"].as_str().unwrap()).unwrap(),
-                        sell: Decimal::from_str(value["last"].as_str().unwrap()).unwrap(),
-                        buy: Decimal::from_str(value["last"].as_str().unwrap()).unwrap(),
-                        last: Decimal::from_str(value["last"].as_str().unwrap()).unwrap(),
-                        volume: Decimal::from_str(value["volume"].as_str().unwrap()).unwrap(),
-                    };
-                    Ok(result)
-                }
-            }
-        } else {
-            Err(Error::new(ErrorKind::Other, res_data.to_string()))
-        }
-    }
-
-    async fn get_ticker_symbol(&mut self, symbol_param: String) -> Result<Ticker, Error> {
-        let symbol: String = symbol_param.replace("_", "").to_uppercase();
-        let res_data = self.request.get_ticker(symbol.clone()).await;
-        if res_data.code == 200 {
-            let res_data_json = res_data.data.as_array().unwrap();
-            let ticker_info = res_data_json.iter().find(|item| item["contract"].as_str().unwrap() == symbol);
-            match ticker_info {
-                None => {
-                    error!("coinex_swap:获取Ticker信息错误!\nget_ticker:res_data={:?}", res_data);
-                    Err(Error::new(ErrorKind::Other, res_data.to_string()))
-                }
-                Some(value) => {
-                    let result = Ticker {
-                        time: chrono::Utc::now().timestamp_millis(),
-                        high: Decimal::from_str(value["high"].as_str().unwrap()).unwrap(),
-                        low: Decimal::from_str(value["low"].as_str().unwrap()).unwrap(),
-                        sell: Decimal::from_str(value["last"].as_str().unwrap()).unwrap(),
-                        buy: Decimal::from_str(value["last"].as_str().unwrap()).unwrap(),
-                        last: Decimal::from_str(value["last"].as_str().unwrap()).unwrap(),
-                        volume: Decimal::from_str(value["volume"].as_str().unwrap()).unwrap(),
-                    };
-                    Ok(result)
-                }
-            }
-        } else {
-            Err(Error::new(ErrorKind::Other, res_data.to_string()))
-        }
-    }
-
-    async fn get_market(&mut self) -> Result<Market, Error> {
-        let symbol_array: Vec<&str> = self.symbol.split("_").collect();
-        let symbol = format!("{}{}", symbol_array[0], symbol_array[1]);
-        let res_data = self.request.get_market_details(symbol.clone()).await;
-        if res_data.code == 200 {
-            let res_data_json = res_data.data.as_array().unwrap();
-            let market_info = res_data_json.iter().find(|item| item["market"].as_str().unwrap() == symbol);
-            match market_info {
-                None => {
-                    error!("coinex_swap:获取Market信息错误!\nget_market:res_data={:?}", res_data);
-                    Err(Error::new(ErrorKind::Other, res_data.to_string()))
-                }
-                Some(value) => {
-                    // 报价精度字符串
-                    let price_precision_i64 = value["quote_ccy_precision"].as_i64().unwrap();
-                    // 价格最小变动数值
-                    let tick_size = get_tick_size(price_precision_i64.to_u32().unwrap());
-                    // 报价精度
-                    let price_precision = Decimal::from_i64(price_precision_i64).unwrap();
-                    // 最小数量
-                    let min_qty = Decimal::from_str(value["min_amount"].as_str().unwrap()).unwrap();
-                    // 数量没有最大值
-                    let max_qty = Decimal::MAX;
-                    // 没有张数
-                    let ct_val = Decimal::ONE;
-
-                    let amount_size = min_qty * ct_val;
-                    let amount_precision = Decimal::from_u32(amount_size.scale()).unwrap();
-                    let min_notional = min_qty * ct_val;
-                    let max_notional = max_qty * ct_val;
-
-                    let result = Market {
-                        symbol: self.symbol.clone(),
-                        base_asset: symbol_array[0].to_string(),
-                        quote_asset: symbol_array[1].to_string(),
-                        tick_size,
-                        amount_size,
-                        price_precision,
-                        amount_precision,
-                        min_qty,
-                        max_qty,
-                        min_notional,
-                        max_notional,
-                        ct_val,
-                    };
-                    Ok(result)
-                }
-            }
-        } else {
-            Err(Error::new(ErrorKind::Other, res_data.to_string()))
-        }
-    }
-
-    async fn get_market_symbol(&mut self, symbol: String) -> Result<Market, Error> {
-        let symbol_upper = symbol.to_uppercase();
-        let symbol_array: Vec<&str> = symbol_upper.split("_").collect();
-        let symbol = format!("{}{}", symbol_array[0], symbol_array[1]);
-        let res_data = self.request.get_market_details(symbol.clone()).await;
-        if res_data.code == 200 {
-            let res_data_json = res_data.data.as_array().unwrap();
-            let market_info = res_data_json.iter().find(|item| item["name"].as_str().unwrap() == symbol.clone());
-            match market_info {
-                None => {
-                    error!("coinex_swap:获取Market信息错误!\nget_market:res_data={:?}", res_data);
-                    Err(Error::new(ErrorKind::Other, res_data.to_string()))
-                }
-                Some(value) => {
-                    let tick_size = Decimal::from_str(value["quote_ccy_precision"].as_str().unwrap()).unwrap();
-                    let min_qty = Decimal::from_str(&value["min_amount"].to_string()).unwrap();
-                    // 数量没有最大值
-                    let max_qty = Decimal::MAX;
-                    // 没有张数
-                    let ct_val = Decimal::ONE;
-
-                    let amount_size = min_qty * ct_val;
-                    let price_precision = Decimal::from_u32(tick_size.scale()).unwrap();
-                    let amount_precision = Decimal::from_u32(amount_size.scale()).unwrap();
-                    let min_notional = min_qty * ct_val;
-                    let max_notional = max_qty * ct_val;
-
-                    let result = Market {
-                        symbol: self.symbol.clone(),
-                        base_asset: symbol_array[0].to_string(),
-                        quote_asset: symbol_array[1].to_string(),
-                        tick_size,
-                        amount_size,
-                        price_precision,
-                        amount_precision,
-                        min_qty,
-                        max_qty,
-                        min_notional,
-                        max_notional,
-                        ct_val,
-                    };
-                    Ok(result)
-                }
-            }
-        } else {
-            Err(Error::new(ErrorKind::Other, res_data.to_string()))
-        }
-    }
-
-    // 获取订单详情
-    async fn get_order_detail(&mut self, order_id: &str, custom_id: &str) -> Result<Order, Error> {
-        let symbol = self.symbol.replace("_", "").to_uppercase();
-        let ct_val = self.market.ct_val;
-        let res_data;
-        let status ;
-        if order_id != "" {
-            status = "";
-            res_data = self.request.get_order_details(order_id.to_string(), symbol).await;
-        } else if custom_id != "" {
-            // 通过客户端id查询  只有未完成的订单才能查询出来
-            res_data = self.request.get_pending_order(custom_id.to_string()).await;
-            status = "open";
-        } else {
-            return Err(Error::new(ErrorKind::Other, format!("订单id和客户端id都为空,查询失败!order_id :{}, custom_id: {}", order_id, custom_id)));
-        }
-
-        if res_data.code == 200 {
-            // info!("order_detail {}", res_data.data);
-            if res_data.data.is_array() {
-                let res_data_json = res_data.data.as_array().unwrap();
-                if res_data_json.len() == 0 { // 已取消或已成交
-                    return Ok(Order{
-                        id: order_id.to_string(),
-                        custom_id: custom_id.to_string(),
-                        price: Default::default(),
-                        amount: Default::default(),
-                        deal_amount: Default::default(),
-                        avg_price: Default::default(),
-                        status: "NULL".to_string(),
-                        order_type: "".to_string(),
-                        trace_stack: TraceStack::new(0, Instant::now()).on_special("358 coinex_swap".to_string()),
-                    })
-                } else { // 待成交
-                    let mut result = format_order_item(res_data_json[0].clone(), ct_val, status);
-                    result.custom_id = custom_id.to_string();
-                    result.id = order_id.to_string();
-                    Ok(result)
-                }
-            } else {
-                let mut result = format_order_item(res_data.data, ct_val, status);
-                result.custom_id = custom_id.to_string();
-                result.id = order_id.to_string();
-                Ok(result)
-            }
-        } else {
-            Err(Error::new(ErrorKind::Other, res_data.to_string()))
-        }
-    }
-
-    // 获取未完成订单列表
-    async fn get_orders_list(&mut self, status: &str) -> Result<Vec<Order>, Error> {
-        let symbol = self.symbol.replace("_", "").to_uppercase();
-        let ct_val = self.market.ct_val;
-        let status_order;
-        let res_data;
-        if status == "pending" {
-            res_data = self.request.get_pending_orders().await;
-            status_order = "open";
-        } else if status == "finish" {
-            res_data = self.request.get_finished_orders().await;
-            status_order = "filled";
-        }else{
-            return Err(Error::new(ErrorKind::Other, status));
-        }
-        if res_data.code == 200 {
-            let res_data_json = res_data.data.as_array().unwrap();
-            if res_data_json.len() ==0 {
-               return Ok(vec![])
-            }
-            let order_info: Vec<_> = res_data_json.iter().filter(|item| item["market"].as_str().unwrap_or("") == symbol).collect();
-            let result = order_info.iter().map(|&item| format_order_item(item.clone(), ct_val, status_order)).collect();
-            Ok(result)
-        } else {
-            Err(Error::new(ErrorKind::Other, res_data.to_string()))
-        }
-    }
-
-    // 下单接口
-    async fn take_order(&mut self, custom_id: &str, origin_side: &str, price: Decimal, amount: Decimal) -> Result<Order, Error> {
-        let symbol = self.symbol.replace("_", "").to_uppercase();
-        let ct_val = self.market.ct_val;
-        let order_side;
-        let position_side;
-        let size = utils::truncate_decimal(amount, self.market.amount_precision.to_u32().unwrap());
-        if size <= Decimal::ZERO {
-            error!("下单数量异常 amount {} amount_precision {} size {}", amount, self.market.amount_precision.to_u32().unwrap(), size);
-            return Err(Error::new(ErrorKind::Other, format!("下单数量错误 amount:{}", amount)));
-        }
-        match origin_side {
-            "kd" => {
-                position_side = "long";
-                order_side = "buy";
-            }
-            "pd" => {
-                position_side = "long";
-                order_side = "sell";
-            }
-            "kk" => {
-                position_side = "short";
-                order_side = "sell";
-            }
-            "pk" => {
-                position_side = "short";
-                order_side = "buy";
-            }
-            _ => {
-                error!("下单参数错误");
-                position_side = "error";
-                order_side = "error";
-            }
-        };
-        let res_data = self.request.order(symbol, position_side.to_string(), order_side.to_string(), size, price, custom_id.to_string()).await;
-        if res_data.code == 200 {
-            let res_data_json: Value = res_data.data;
-            // info!("take_order {}", res_data_json);
-            let result = format_order_item(res_data_json, ct_val, "open");
-            Ok(result)
-        } else {
-            // error!("take_order error {}", res_data.data);
-            Err(Error::new(ErrorKind::Other, res_data.to_string()))
-        }
-    }
-
-    async fn take_order_symbol(&mut self, symbol_y: String, ct_val: Decimal, custom_id: &str, origin_side: &str, price: Decimal, amount: Decimal) -> Result<Order, Error> {
-        let symbol = symbol_y.replace("_", "").to_uppercase();
-        let order_side;
-        let position_side;
-        let size = (amount / ct_val).floor();
-        match origin_side {
-            "kd" => {
-                position_side = "long";
-                order_side = "buy";
-            }
-            "pd" => {
-                position_side = "long";
-                order_side = "sell";
-            }
-            "kk" => {
-                position_side = "short";
-                order_side = "sell";
-            }
-            "pk" => {
-                position_side = "short";
-                order_side = "buy";
-            }
-            _ => {
-                error!("下单参数错误");
-                position_side = "error";
-                order_side = "error";
-            }
-        };
-        let res_data = self.request.order(symbol, position_side.to_string(), order_side.to_string(), size, price, custom_id.to_string()).await;
-        if res_data.code == 200 {
-            let res_data_json: Value = res_data.data;
-            let result = format_order_item(res_data_json, ct_val, "open");
-            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 = self.symbol.replace("_", "").to_uppercase();
-
-        let ct_val = self.market.ct_val;
-        let res_data = self.request.cancel_order(symbol, order_id, custom_id).await;
-        if res_data.code == 200 {
-            let res_data_json: Value = res_data.data;
-            let mut result;
-            if res_data_json.is_null(){
-                result = Order{
-                    id: custom_id.to_string(),
-                    custom_id: order_id.to_string(),
-                    price: Default::default(),
-                    amount: Default::default(),
-                    deal_amount: Default::default(),
-                    avg_price: Default::default(),
-                    status: "NULL".to_string(),
-                    order_type: "".to_string(),
-                    trace_stack:  TraceStack::new(0, Instant::now()).on_special("513 coinex_swap".to_string())
-                };
-            } else {
-                result = format_order_item(res_data_json, ct_val, "canceled");
-                result.custom_id = custom_id.to_string();
-                result.id = order_id.to_string();
-            }
-            Ok(result)
-        } else {
-            let message = format!("撤单HTTP请求失败  order_id: {}, custom_id: {}, res_data: {:?}", order_id, custom_id, res_data);
-            Err(Error::new(ErrorKind::Other, message))
-        }
-    }
-    // 批量撤销订单
-    async fn cancel_orders(&mut self) -> Result<Vec<Order>, Error> {
-        let symbol = self.symbol.replace("_", "").to_uppercase();
-        let res_data = self.request.cancel_order_all(symbol).await;
-        if res_data.code == 200 {
-            info!("{}", res_data.data.to_string());
-            let result = vec![];
-            Ok(result)
-        } else {
-            Err(Error::new(ErrorKind::Other, res_data.to_string()))
-        }
-    }
-
-    async fn cancel_orders_all(&mut self) -> Result<Vec<Order>, Error> {
-        let orders_res_data = self.request.get_pending_orders().await;
-        if orders_res_data.code == 200 {
-            let result = vec![];
-            let orders_res_data_json = orders_res_data.data.as_array().unwrap();
-            for order in orders_res_data_json {
-                let cancel_res_data = self.request.cancel_order_all( order["market"].as_str().unwrap().to_string()).await;
-                if cancel_res_data.code != 200 {
-                    return Err(Error::new(ErrorKind::Other, cancel_res_data.to_string()));
-                }
-            }
-            Ok(result)
-        } else {
-            Err(Error::new(ErrorKind::Other, orders_res_data.to_string()))
-        }
-    }
-
-    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> {
-        Err(Error::new(ErrorKind::NotFound, "coin_ex:该交易所只允许单向持仓,无法设置持仓模式".to_string()))
-    }
-
-    // 更新杠杆
-    async fn set_dual_leverage(&mut self, leverage: &str) -> Result<String, Error> {
-        let leverage_int = leverage.parse::<i32>().unwrap();
-        let symbol = self.symbol.replace("_", "").to_uppercase();
-        let res_data = self.request.setting_dual_leverage(symbol, leverage_int).await;
-        if res_data.code == 200 {
-            let res_data_str = &res_data.data;
-            let result = res_data_str.clone();
-            Ok(result.to_string())
-        } else {
-            Err(Error::new(ErrorKind::Other, res_data.to_string()))
-        }
-    }
-
-    async fn set_auto_deposit_status(&mut self, _status: bool) -> Result<String, Error> { Err(Error::new(ErrorKind::NotFound, "Coinex:该交易所方法未实现".to_string())) }
-
-    async fn wallet_transfers(&mut self, _coin: &str, _from: &str, _to: &str, _amount: Decimal) -> Result<String, Error> {
-        Err(Error::new(ErrorKind::NotFound, "Coinex 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!("coinex下单error 数量: {},方向: {},价格: {},c_id: {}, err: {}", amount, side, price, cid, error);
-                        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(order) => {
-                        if order.status == "REMOVE" {
-                            // 由于有时撤单成功ws不推送,所以加入rest
-                            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) => {
-                                // warn!("撤单失败,而且查单也失败了,Coinex_io_swap,oid={}, cid={} err={:?}", order_id.clone(), custom_id.clone(), err);
-                                // panic!("撤单失败,而且查单也失败了,Coinex_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["side"].as_str().unwrap_or("") {
-        "long" => PositionModeEnum::Long,
-        "short" => PositionModeEnum::Short,
-        _ => {
-            error!("coinex_swap:格式化持仓模式错误!\nformat_position_item:position={:?}", position);
-            panic!("coinex_swap:格式化持仓模式错误!\nformat_position_item:position={:?}", position)
-        }
-    };
-    let size = Decimal::from_str(&position["open_interest"].as_str().unwrap()).unwrap();
-    let amount = size * ct_val;
-    Position {
-        symbol: position["market"].as_str().unwrap_or("").parse().unwrap(),
-        margin_level: Decimal::from_str(position["leverage"].as_str().unwrap()).unwrap(),
-        amount,
-        frozen_amount: Decimal::ZERO,
-        price: Decimal::from_str(position["avg_entry_price"].as_str().unwrap()).unwrap(),
-        profit: Decimal::from_str(position["unrealized_pnl"].as_str().unwrap()).unwrap(),
-        position_mode,
-        margin: Decimal::from_str(position["ath_margin_size"].as_str().unwrap()).unwrap(),
-    }
-}
-
-pub fn format_order_item(order: Value, ct_val: Decimal, status: &str) -> Order {
-    // info!("order_format {}", order);
-    let size;
-    match order["amount"].as_str() {
-        Some(val) => {
-            size = Decimal::from_str(val).unwrap()
-        },
-        None => {
-            error!("coinex_swap:格式化订单大小错误!\nformat_order_item:order={:?} status={}", order, status);
-            panic!("coinex_swap:格式化订单大小失败,退出程序!");
-        }
-    }
-    // info!("order {}", order);
-    // 通过客户端id查询订单 只能查出未完成订单(没有状态字段)
-    let status = order["status"].as_str().unwrap_or(status);
-    let text = order["client_id"].as_str().unwrap_or("");
-
-    let deal_amount = Decimal::from_str(&order["filled_amount"].as_str().unwrap()).unwrap();
-    let filled_value = Decimal::from_str(&order["filled_value"].as_str().unwrap()).unwrap();
-
-    let amount = size * ct_val;
-    let mut avg_price = Decimal::ZERO;
-    if deal_amount != Decimal::ZERO{
-        avg_price = filled_value/deal_amount;
-    }
-    let custom_status = if status == "filled" || status == "canceled" {
-        "REMOVE".to_string()
-    } else if status == "open" || status == "part_filled" || status == "part_canceled" {
-        "NEW".to_string()
-    } else {
-        error!("coinex_swap:格式化订单状态错误!\nformat_order_item:order={:?}", order);
-        "NULL".to_string()
-    };
-    let rst_order = Order {
-        id: order["order_id"].to_string(),
-        custom_id: text.to_string(),
-        price: Decimal::from_str(order["price"].as_str().unwrap()).unwrap(),
-        amount,
-        deal_amount,
-        avg_price,
-        status: custom_status,
-        order_type: "limit".to_string(),
-        trace_stack: TraceStack::new(0, Instant::now()).on_special("765 trace_stack".to_string()),
-    };
-    return rst_order;
-}
+// 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::prelude::{FromPrimitive, ToPrimitive};
+// use serde_json::{Value};
+// use tokio::spawn;
+// use tokio::time::Instant;
+// use tracing::{error, info, trace};
+// use exchanges::coinex_swap_rest::CoinexSwapRest;
+// use crate::{Platform, ExchangeEnum, Account, Position, Ticker, Market, Order, OrderCommand, PositionModeEnum, utils};
+// use global::trace_stack::TraceStack;
+// use crate::utils::get_tick_size;
+//
+// #[allow(dead_code)]
+// #[derive(Clone)]
+// pub struct CoinexSwap {
+//     exchange: ExchangeEnum,
+//     symbol: String,
+//     is_colo: bool,
+//     params: BTreeMap<String, String>,
+//     request: CoinexSwapRest,
+//     market: Market,
+//     order_sender: Sender<Order>,
+//     error_sender: Sender<Error>,
+// }
+//
+// impl CoinexSwap {
+//     pub async fn new(symbol: String, is_colo: bool, params: BTreeMap<String, String>, order_sender: Sender<Order>, error_sender: Sender<Error>) -> CoinexSwap {
+//         let market = Market::new();
+//         let mut coinex_swap = CoinexSwap {
+//             exchange: ExchangeEnum::CoinexSwap,
+//             symbol: symbol.to_uppercase(),
+//             is_colo,
+//             params: params.clone(),
+//             request: CoinexSwapRest::new(params.clone()),
+//             market,
+//             order_sender,
+//             error_sender,
+//         };
+//
+//         // 修改持仓模式
+//         let symbol_array: Vec<&str> = symbol.split("_").collect();
+//         let mode_result = coinex_swap.set_dual_mode(symbol_array[1], true).await;
+//         match mode_result {
+//             Ok(_) => {
+//                 trace!("Coinex:设置持仓模式成功!")
+//             }
+//             Err(error) => {
+//                 error!("Coinex:设置持仓模式失败!mode_result={}", error)
+//             }
+//         }
+//         // 获取市场信息
+//         coinex_swap.market = CoinexSwap::get_market(&mut coinex_swap).await.unwrap_or(coinex_swap.market);
+//         // 设置持仓杠杆
+//         let lever_rate_result = coinex_swap.set_dual_leverage("10").await;
+//         match lever_rate_result {
+//             Ok(ok) => {
+//                 info!("Coinex:设置持仓杠杆成功!{:?}", ok);
+//             }
+//             Err(error) => {
+//                 error!("Coinex:设置持仓杠杆失败!{:?}", error)
+//             }
+//         }
+//         return coinex_swap;
+//     }
+// }
+//
+// #[async_trait]
+// impl Platform for CoinexSwap {
+//     // 克隆方法
+//     fn clone_box(&self) -> Box<dyn Platform + Send + Sync> { Box::new(self.clone()) }
+//     // 获取交易所模式
+//     fn get_self_exchange(&self) -> ExchangeEnum {
+//         ExchangeEnum::CoinexSwap
+//     }
+//     // 获取交易对
+//     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_time().await;
+//         if res_data.code == 200 {
+//             let res_data_json: Value = res_data.data;
+//             let result = res_data_json["timestamp"].to_string();
+//             Ok(result)
+//         } else {
+//             Err(Error::new(ErrorKind::Other, res_data.to_string()))
+//         }
+//     }
+//     // 获取账号信息
+//     async fn get_account(&mut self) -> Result<Account, Error> {
+//         let symbol_array: Vec<&str> = self.symbol.split("_").collect();
+//         let coin = symbol_array[1].to_string().to_uppercase();
+//         let res_data = self.request.get_account().await;
+//         if res_data.code == 200 {
+//             if res_data.data.is_array() {
+//                 let res_data_array = res_data.data.as_array().unwrap();
+//                 for res_data_json in res_data_array.iter() {
+//                     if res_data_json["ccy"].as_str().unwrap() == coin {
+//                         let frozen_balance= Decimal::from_str(res_data_json["frozen"].as_str().unwrap()).unwrap();
+//                         let available_balance = Decimal::from_str(res_data_json["available"].as_str().unwrap()).unwrap();
+//                         let balance = frozen_balance + available_balance;
+//                         let result = Account {
+//                             coin: symbol_array[1].to_string(),
+//                             balance,
+//                             available_balance,
+//                             frozen_balance,
+//                             stocks: Decimal::ZERO,
+//                             available_stocks: Decimal::ZERO,
+//                             frozen_stocks: Decimal::ZERO,
+//                         };
+//                         return Ok(result);
+//                     }
+//                 }
+//             }
+//         }
+//         Err(Error::new(ErrorKind::Other, res_data.to_string()))
+//     }
+//
+//     async fn get_spot_account(&mut self) -> Result<Vec<Account>, Error> {
+//         Err(Error::new(ErrorKind::NotFound, "coinex_swap:该方法暂未实现".to_string()))
+//     }
+//
+//     // 获取持仓信息
+//     async fn get_position(&mut self) -> Result<Vec<Position>, Error> {
+//         let symbol: String = self.symbol.replace("_", "").to_uppercase();
+//         let ct_val = self.market.ct_val;
+//         let res_data = self.request.get_position(symbol).await;
+//         if res_data.code == 200 {
+//             let res_data_json = res_data.data.as_array().unwrap();
+//             let result = res_data_json.iter().map(|item| { format_position_item(item, ct_val) }).collect();
+//             Ok(result)
+//         } else {
+//             Err(Error::new(ErrorKind::Other, res_data.to_string()))
+//         }
+//     }
+//
+//     // 获取所有持仓
+//     async fn get_positions(&mut self) -> Result<Vec<Position>, Error> {
+//         let res_data = self.request.get_user_position().await;
+//         if res_data.code == 200 {
+//             info!("{}", res_data.data.to_string());
+//             let res_data_json = res_data.data.as_array().unwrap();
+//             let result = res_data_json.iter().map(|item| { format_position_item(item, Decimal::ONE) }).collect();
+//             Ok(result)
+//         } else {
+//             Err(Error::new(ErrorKind::Other, res_data.to_string()))
+//         }
+//     }
+//     // 获取市场行情
+//     async fn get_ticker(&mut self) -> Result<Ticker, Error> {
+//         let symbol: String = self.symbol.replace("_", "");
+//         let res_data = self.request.get_ticker(symbol.clone()).await;
+//         if res_data.code == 200 {
+//             let res_data_json = res_data.data.as_array().unwrap();
+//             let ticker_info = res_data_json.iter().find(|item| item["market"].as_str().unwrap() == symbol);
+//             match ticker_info {
+//                 None => {
+//                     error!("coinex_swap:获取Ticker信息错误!\nget_ticker:res_data={:?}", res_data);
+//                     Err(Error::new(ErrorKind::Other, res_data.to_string()))
+//                 }
+//                 Some(value) => {
+//                     let result = Ticker {
+//                         time: chrono::Utc::now().timestamp_millis(),
+//                         high: Decimal::from_str(value["high"].as_str().unwrap()).unwrap(),
+//                         low: Decimal::from_str(value["low"].as_str().unwrap()).unwrap(),
+//                         sell: Decimal::from_str(value["last"].as_str().unwrap()).unwrap(),
+//                         buy: Decimal::from_str(value["last"].as_str().unwrap()).unwrap(),
+//                         last: Decimal::from_str(value["last"].as_str().unwrap()).unwrap(),
+//                         volume: Decimal::from_str(value["volume"].as_str().unwrap()).unwrap(),
+//                     };
+//                     Ok(result)
+//                 }
+//             }
+//         } else {
+//             Err(Error::new(ErrorKind::Other, res_data.to_string()))
+//         }
+//     }
+//
+//     async fn get_ticker_symbol(&mut self, symbol_param: String) -> Result<Ticker, Error> {
+//         let symbol: String = symbol_param.replace("_", "").to_uppercase();
+//         let res_data = self.request.get_ticker(symbol.clone()).await;
+//         if res_data.code == 200 {
+//             let res_data_json = res_data.data.as_array().unwrap();
+//             let ticker_info = res_data_json.iter().find(|item| item["contract"].as_str().unwrap() == symbol);
+//             match ticker_info {
+//                 None => {
+//                     error!("coinex_swap:获取Ticker信息错误!\nget_ticker:res_data={:?}", res_data);
+//                     Err(Error::new(ErrorKind::Other, res_data.to_string()))
+//                 }
+//                 Some(value) => {
+//                     let result = Ticker {
+//                         time: chrono::Utc::now().timestamp_millis(),
+//                         high: Decimal::from_str(value["high"].as_str().unwrap()).unwrap(),
+//                         low: Decimal::from_str(value["low"].as_str().unwrap()).unwrap(),
+//                         sell: Decimal::from_str(value["last"].as_str().unwrap()).unwrap(),
+//                         buy: Decimal::from_str(value["last"].as_str().unwrap()).unwrap(),
+//                         last: Decimal::from_str(value["last"].as_str().unwrap()).unwrap(),
+//                         volume: Decimal::from_str(value["volume"].as_str().unwrap()).unwrap(),
+//                     };
+//                     Ok(result)
+//                 }
+//             }
+//         } else {
+//             Err(Error::new(ErrorKind::Other, res_data.to_string()))
+//         }
+//     }
+//
+//     async fn get_market(&mut self) -> Result<Market, Error> {
+//         let symbol_array: Vec<&str> = self.symbol.split("_").collect();
+//         let symbol = format!("{}{}", symbol_array[0], symbol_array[1]);
+//         let res_data = self.request.get_market_details(symbol.clone()).await;
+//         if res_data.code == 200 {
+//             let res_data_json = res_data.data.as_array().unwrap();
+//             let market_info = res_data_json.iter().find(|item| item["market"].as_str().unwrap() == symbol);
+//             match market_info {
+//                 None => {
+//                     error!("coinex_swap:获取Market信息错误!\nget_market:res_data={:?}", res_data);
+//                     Err(Error::new(ErrorKind::Other, res_data.to_string()))
+//                 }
+//                 Some(value) => {
+//                     // 报价精度字符串
+//                     let price_precision_i64 = value["quote_ccy_precision"].as_i64().unwrap();
+//                     // 价格最小变动数值
+//                     let tick_size = get_tick_size(price_precision_i64.to_u32().unwrap());
+//                     // 报价精度
+//                     let price_precision = Decimal::from_i64(price_precision_i64).unwrap();
+//                     // 最小数量
+//                     let min_qty = Decimal::from_str(value["min_amount"].as_str().unwrap()).unwrap();
+//                     // 数量没有最大值
+//                     let max_qty = Decimal::MAX;
+//                     // 没有张数
+//                     let ct_val = Decimal::ONE;
+//
+//                     let amount_size = min_qty * ct_val;
+//                     let amount_precision = Decimal::from_u32(amount_size.scale()).unwrap();
+//                     let min_notional = min_qty * ct_val;
+//                     let max_notional = max_qty * ct_val;
+//
+//                     let result = Market {
+//                         symbol: self.symbol.clone(),
+//                         base_asset: symbol_array[0].to_string(),
+//                         quote_asset: symbol_array[1].to_string(),
+//                         tick_size,
+//                         amount_size,
+//                         price_precision,
+//                         amount_precision,
+//                         min_qty,
+//                         max_qty,
+//                         min_notional,
+//                         max_notional,
+//                         ct_val,
+//                     };
+//                     Ok(result)
+//                 }
+//             }
+//         } else {
+//             Err(Error::new(ErrorKind::Other, res_data.to_string()))
+//         }
+//     }
+//
+//     async fn get_market_symbol(&mut self, symbol: String) -> Result<Market, Error> {
+//         let symbol_upper = symbol.to_uppercase();
+//         let symbol_array: Vec<&str> = symbol_upper.split("_").collect();
+//         let symbol = format!("{}{}", symbol_array[0], symbol_array[1]);
+//         let res_data = self.request.get_market_details(symbol.clone()).await;
+//         if res_data.code == 200 {
+//             let res_data_json = res_data.data.as_array().unwrap();
+//             let market_info = res_data_json.iter().find(|item| item["name"].as_str().unwrap() == symbol.clone());
+//             match market_info {
+//                 None => {
+//                     error!("coinex_swap:获取Market信息错误!\nget_market:res_data={:?}", res_data);
+//                     Err(Error::new(ErrorKind::Other, res_data.to_string()))
+//                 }
+//                 Some(value) => {
+//                     let tick_size = Decimal::from_str(value["quote_ccy_precision"].as_str().unwrap()).unwrap();
+//                     let min_qty = Decimal::from_str(&value["min_amount"].to_string()).unwrap();
+//                     // 数量没有最大值
+//                     let max_qty = Decimal::MAX;
+//                     // 没有张数
+//                     let ct_val = Decimal::ONE;
+//
+//                     let amount_size = min_qty * ct_val;
+//                     let price_precision = Decimal::from_u32(tick_size.scale()).unwrap();
+//                     let amount_precision = Decimal::from_u32(amount_size.scale()).unwrap();
+//                     let min_notional = min_qty * ct_val;
+//                     let max_notional = max_qty * ct_val;
+//
+//                     let result = Market {
+//                         symbol: self.symbol.clone(),
+//                         base_asset: symbol_array[0].to_string(),
+//                         quote_asset: symbol_array[1].to_string(),
+//                         tick_size,
+//                         amount_size,
+//                         price_precision,
+//                         amount_precision,
+//                         min_qty,
+//                         max_qty,
+//                         min_notional,
+//                         max_notional,
+//                         ct_val,
+//                     };
+//                     Ok(result)
+//                 }
+//             }
+//         } else {
+//             Err(Error::new(ErrorKind::Other, res_data.to_string()))
+//         }
+//     }
+//
+//     // 获取订单详情
+//     async fn get_order_detail(&mut self, order_id: &str, custom_id: &str) -> Result<Order, Error> {
+//         let symbol = self.symbol.replace("_", "").to_uppercase();
+//         let ct_val = self.market.ct_val;
+//         let res_data;
+//         let status ;
+//         if order_id != "" {
+//             status = "";
+//             res_data = self.request.get_order_details(order_id.to_string(), symbol).await;
+//         } else if custom_id != "" {
+//             // 通过客户端id查询  只有未完成的订单才能查询出来
+//             res_data = self.request.get_pending_order(custom_id.to_string()).await;
+//             status = "open";
+//         } else {
+//             return Err(Error::new(ErrorKind::Other, format!("订单id和客户端id都为空,查询失败!order_id :{}, custom_id: {}", order_id, custom_id)));
+//         }
+//
+//         if res_data.code == 200 {
+//             // info!("order_detail {}", res_data.data);
+//             if res_data.data.is_array() {
+//                 let res_data_json = res_data.data.as_array().unwrap();
+//                 if res_data_json.len() == 0 { // 已取消或已成交
+//                     return Ok(Order{
+//                         id: order_id.to_string(),
+//                         custom_id: custom_id.to_string(),
+//                         price: Default::default(),
+//                         amount: Default::default(),
+//                         deal_amount: Default::default(),
+//                         avg_price: Default::default(),
+//                         status: "NULL".to_string(),
+//                         order_type: "".to_string(),
+//                         trace_stack: TraceStack::new(0, Instant::now()).on_special("358 coinex_swap".to_string()),
+//                     })
+//                 } else { // 待成交
+//                     let mut result = format_order_item(res_data_json[0].clone(), ct_val, status);
+//                     result.custom_id = custom_id.to_string();
+//                     result.id = order_id.to_string();
+//                     Ok(result)
+//                 }
+//             } else {
+//                 let mut result = format_order_item(res_data.data, ct_val, status);
+//                 result.custom_id = custom_id.to_string();
+//                 result.id = order_id.to_string();
+//                 Ok(result)
+//             }
+//         } else {
+//             Err(Error::new(ErrorKind::Other, res_data.to_string()))
+//         }
+//     }
+//
+//     // 获取未完成订单列表
+//     async fn get_orders_list(&mut self, status: &str) -> Result<Vec<Order>, Error> {
+//         let symbol = self.symbol.replace("_", "").to_uppercase();
+//         let ct_val = self.market.ct_val;
+//         let status_order;
+//         let res_data;
+//         if status == "pending" {
+//             res_data = self.request.get_pending_orders().await;
+//             status_order = "open";
+//         } else if status == "finish" {
+//             res_data = self.request.get_finished_orders().await;
+//             status_order = "filled";
+//         }else{
+//             return Err(Error::new(ErrorKind::Other, status));
+//         }
+//         if res_data.code == 200 {
+//             let res_data_json = res_data.data.as_array().unwrap();
+//             if res_data_json.len() ==0 {
+//                return Ok(vec![])
+//             }
+//             let order_info: Vec<_> = res_data_json.iter().filter(|item| item["market"].as_str().unwrap_or("") == symbol).collect();
+//             let result = order_info.iter().map(|&item| format_order_item(item.clone(), ct_val, status_order)).collect();
+//             Ok(result)
+//         } else {
+//             Err(Error::new(ErrorKind::Other, res_data.to_string()))
+//         }
+//     }
+//
+//     // 下单接口
+//     async fn take_order(&mut self, custom_id: &str, origin_side: &str, price: Decimal, amount: Decimal) -> Result<Order, Error> {
+//         let symbol = self.symbol.replace("_", "").to_uppercase();
+//         let ct_val = self.market.ct_val;
+//         let order_side;
+//         let position_side;
+//         let size = utils::truncate_decimal(amount, self.market.amount_precision.to_u32().unwrap());
+//         if size <= Decimal::ZERO {
+//             error!("下单数量异常 amount {} amount_precision {} size {}", amount, self.market.amount_precision.to_u32().unwrap(), size);
+//             return Err(Error::new(ErrorKind::Other, format!("下单数量错误 amount:{}", amount)));
+//         }
+//         match origin_side {
+//             "kd" => {
+//                 position_side = "long";
+//                 order_side = "buy";
+//             }
+//             "pd" => {
+//                 position_side = "long";
+//                 order_side = "sell";
+//             }
+//             "kk" => {
+//                 position_side = "short";
+//                 order_side = "sell";
+//             }
+//             "pk" => {
+//                 position_side = "short";
+//                 order_side = "buy";
+//             }
+//             _ => {
+//                 error!("下单参数错误");
+//                 position_side = "error";
+//                 order_side = "error";
+//             }
+//         };
+//         let res_data = self.request.order(symbol, position_side.to_string(), order_side.to_string(), size, price, custom_id.to_string()).await;
+//         if res_data.code == 200 {
+//             let res_data_json: Value = res_data.data;
+//             // info!("take_order {}", res_data_json);
+//             let result = format_order_item(res_data_json, ct_val, "open");
+//             Ok(result)
+//         } else {
+//             // error!("take_order error {}", res_data.data);
+//             Err(Error::new(ErrorKind::Other, res_data.to_string()))
+//         }
+//     }
+//
+//     async fn take_order_symbol(&mut self, symbol_y: String, ct_val: Decimal, custom_id: &str, origin_side: &str, price: Decimal, amount: Decimal) -> Result<Order, Error> {
+//         let symbol = symbol_y.replace("_", "").to_uppercase();
+//         let order_side;
+//         let position_side;
+//         let size = (amount / ct_val).floor();
+//         match origin_side {
+//             "kd" => {
+//                 position_side = "long";
+//                 order_side = "buy";
+//             }
+//             "pd" => {
+//                 position_side = "long";
+//                 order_side = "sell";
+//             }
+//             "kk" => {
+//                 position_side = "short";
+//                 order_side = "sell";
+//             }
+//             "pk" => {
+//                 position_side = "short";
+//                 order_side = "buy";
+//             }
+//             _ => {
+//                 error!("下单参数错误");
+//                 position_side = "error";
+//                 order_side = "error";
+//             }
+//         };
+//         let res_data = self.request.order(symbol, position_side.to_string(), order_side.to_string(), size, price, custom_id.to_string()).await;
+//         if res_data.code == 200 {
+//             let res_data_json: Value = res_data.data;
+//             let result = format_order_item(res_data_json, ct_val, "open");
+//             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 = self.symbol.replace("_", "").to_uppercase();
+//
+//         let ct_val = self.market.ct_val;
+//         let res_data = self.request.cancel_order(symbol, order_id, custom_id).await;
+//         if res_data.code == 200 {
+//             let res_data_json: Value = res_data.data;
+//             let mut result;
+//             if res_data_json.is_null(){
+//                 result = Order{
+//                     id: custom_id.to_string(),
+//                     custom_id: order_id.to_string(),
+//                     price: Default::default(),
+//                     amount: Default::default(),
+//                     deal_amount: Default::default(),
+//                     avg_price: Default::default(),
+//                     status: "NULL".to_string(),
+//                     order_type: "".to_string(),
+//                     trace_stack:  TraceStack::new(0, Instant::now()).on_special("513 coinex_swap".to_string())
+//                 };
+//             } else {
+//                 result = format_order_item(res_data_json, ct_val, "canceled");
+//                 result.custom_id = custom_id.to_string();
+//                 result.id = order_id.to_string();
+//             }
+//             Ok(result)
+//         } else {
+//             let message = format!("撤单HTTP请求失败  order_id: {}, custom_id: {}, res_data: {:?}", order_id, custom_id, res_data);
+//             Err(Error::new(ErrorKind::Other, message))
+//         }
+//     }
+//     // 批量撤销订单
+//     async fn cancel_orders(&mut self) -> Result<Vec<Order>, Error> {
+//         let symbol = self.symbol.replace("_", "").to_uppercase();
+//         let res_data = self.request.cancel_order_all(symbol).await;
+//         if res_data.code == 200 {
+//             info!("{}", res_data.data.to_string());
+//             let result = vec![];
+//             Ok(result)
+//         } else {
+//             Err(Error::new(ErrorKind::Other, res_data.to_string()))
+//         }
+//     }
+//
+//     async fn cancel_orders_all(&mut self) -> Result<Vec<Order>, Error> {
+//         let orders_res_data = self.request.get_pending_orders().await;
+//         if orders_res_data.code == 200 {
+//             let result = vec![];
+//             let orders_res_data_json = orders_res_data.data.as_array().unwrap();
+//             for order in orders_res_data_json {
+//                 let cancel_res_data = self.request.cancel_order_all( order["market"].as_str().unwrap().to_string()).await;
+//                 if cancel_res_data.code != 200 {
+//                     return Err(Error::new(ErrorKind::Other, cancel_res_data.to_string()));
+//                 }
+//             }
+//             Ok(result)
+//         } else {
+//             Err(Error::new(ErrorKind::Other, orders_res_data.to_string()))
+//         }
+//     }
+//
+//     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> {
+//         Err(Error::new(ErrorKind::NotFound, "coin_ex:该交易所只允许单向持仓,无法设置持仓模式".to_string()))
+//     }
+//
+//     // 更新杠杆
+//     async fn set_dual_leverage(&mut self, leverage: &str) -> Result<String, Error> {
+//         let leverage_int = leverage.parse::<i32>().unwrap();
+//         let symbol = self.symbol.replace("_", "").to_uppercase();
+//         let res_data = self.request.setting_dual_leverage(symbol, leverage_int).await;
+//         if res_data.code == 200 {
+//             let res_data_str = &res_data.data;
+//             let result = res_data_str.clone();
+//             Ok(result.to_string())
+//         } else {
+//             Err(Error::new(ErrorKind::Other, res_data.to_string()))
+//         }
+//     }
+//
+//     async fn set_auto_deposit_status(&mut self, _status: bool) -> Result<String, Error> { Err(Error::new(ErrorKind::NotFound, "Coinex:该交易所方法未实现".to_string())) }
+//
+//     async fn wallet_transfers(&mut self, _coin: &str, _from: &str, _to: &str, _amount: Decimal) -> Result<String, Error> {
+//         Err(Error::new(ErrorKind::NotFound, "Coinex 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!("coinex下单error 数量: {},方向: {},价格: {},c_id: {}, err: {}", amount, side, price, cid, error);
+//                         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(order) => {
+//                         if order.status == "REMOVE" {
+//                             // 由于有时撤单成功ws不推送,所以加入rest
+//                             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) => {
+//                                 // warn!("撤单失败,而且查单也失败了,Coinex_io_swap,oid={}, cid={} err={:?}", order_id.clone(), custom_id.clone(), err);
+//                                 // panic!("撤单失败,而且查单也失败了,Coinex_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["side"].as_str().unwrap_or("") {
+//         "long" => PositionModeEnum::Long,
+//         "short" => PositionModeEnum::Short,
+//         _ => {
+//             error!("coinex_swap:格式化持仓模式错误!\nformat_position_item:position={:?}", position);
+//             panic!("coinex_swap:格式化持仓模式错误!\nformat_position_item:position={:?}", position)
+//         }
+//     };
+//     let size = Decimal::from_str(&position["open_interest"].as_str().unwrap()).unwrap();
+//     let amount = size * ct_val;
+//     Position {
+//         symbol: position["market"].as_str().unwrap_or("").parse().unwrap(),
+//         margin_level: Decimal::from_str(position["leverage"].as_str().unwrap()).unwrap(),
+//         amount,
+//         frozen_amount: Decimal::ZERO,
+//         price: Decimal::from_str(position["avg_entry_price"].as_str().unwrap()).unwrap(),
+//         profit: Decimal::from_str(position["unrealized_pnl"].as_str().unwrap()).unwrap(),
+//         position_mode,
+//         margin: Decimal::from_str(position["ath_margin_size"].as_str().unwrap()).unwrap(),
+//     }
+// }
+//
+// pub fn format_order_item(order: Value, ct_val: Decimal, status: &str) -> Order {
+//     // info!("order_format {}", order);
+//     let size;
+//     match order["amount"].as_str() {
+//         Some(val) => {
+//             size = Decimal::from_str(val).unwrap()
+//         },
+//         None => {
+//             error!("coinex_swap:格式化订单大小错误!\nformat_order_item:order={:?} status={}", order, status);
+//             panic!("coinex_swap:格式化订单大小失败,退出程序!");
+//         }
+//     }
+//     // info!("order {}", order);
+//     // 通过客户端id查询订单 只能查出未完成订单(没有状态字段)
+//     let status = order["status"].as_str().unwrap_or(status);
+//     let text = order["client_id"].as_str().unwrap_or("");
+//
+//     let deal_amount = Decimal::from_str(&order["filled_amount"].as_str().unwrap()).unwrap();
+//     let filled_value = Decimal::from_str(&order["filled_value"].as_str().unwrap()).unwrap();
+//
+//     let amount = size * ct_val;
+//     let mut avg_price = Decimal::ZERO;
+//     if deal_amount != Decimal::ZERO{
+//         avg_price = filled_value/deal_amount;
+//     }
+//     let custom_status = if status == "filled" || status == "canceled" {
+//         "REMOVE".to_string()
+//     } else if status == "open" || status == "part_filled" || status == "part_canceled" {
+//         "NEW".to_string()
+//     } else {
+//         error!("coinex_swap:格式化订单状态错误!\nformat_order_item:order={:?}", order);
+//         "NULL".to_string()
+//     };
+//     let rst_order = Order {
+//         id: order["order_id"].to_string(),
+//         custom_id: text.to_string(),
+//         price: Decimal::from_str(order["price"].as_str().unwrap()).unwrap(),
+//         amount,
+//         deal_amount,
+//         avg_price,
+//         status: custom_status,
+//         order_type: "limit".to_string(),
+//         trace_stack: TraceStack::new(0, Instant::now()).on_special("765 trace_stack".to_string()),
+//     };
+//     return rst_order;
+// }

+ 180 - 158
standard/src/coinex_swap_handle.rs

@@ -1,158 +1,180 @@
-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["balance_list"].as_array().unwrap();
-    format_account_info(res_data_json, symbol)
-}
-
-pub fn format_account_info(data: &Vec<Value>, symbol: &String) -> Account {
-    let symbol_upper = symbol.to_uppercase();
-    let symbol_array: Vec<&str> = symbol_upper.split("_").collect();
-    let balance_info = data.iter().find(|&item| item["ccy"].as_str().unwrap().contains(symbol_array[1]));
-
-    match balance_info {
-        None => {
-            error!("Coinex:格式化账号信息错误!\nformat_account_info: data={:?}", data);
-            panic!("Coinex:格式化账号信息错误!\nformat_account_info: data={:?}", data)
-        }
-        Some(value) => {
-            let frozen_balance= Decimal::from_str(&value["frozen"].as_str().unwrap()).unwrap();
-            let available_balance = Decimal::from_str(&value["available"].as_str().unwrap()).unwrap();
-            let margin = Decimal::from_str(&value["margin"].as_str().unwrap()).unwrap();
-            // let profit_unreal = Decimal::from_str(&value["unrealized_pnl"].as_str().unwrap()).unwrap();
-            let balance = frozen_balance + available_balance + margin;
-            Account {
-                coin: symbol_array[1].to_string(),
-                balance,
-                available_balance: Decimal::ZERO,
-                frozen_balance: Decimal::ZERO,
-                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["position"];
-    let position =  format_position_item(res_data_json, ct_val);
-    vec![position]
-}
-
-pub fn format_position_item(position: &Value, ct_val: &Decimal) -> Position {
-    let position_mode = match position["side"].as_str().unwrap_or("") {
-        "long" => PositionModeEnum::Long,
-        "short" => PositionModeEnum::Short,
-        _ => {
-            error!("Coinex:格式化持仓模式错误!\nformat_position_item:position={:?}", position);
-            panic!("Coinex:格式化持仓模式错误!\nformat_position_item:position={:?}", position)
-        }
-    };
-    let size = Decimal::from_str(&position["open_interest"].as_str().unwrap()).unwrap();
-    let amount = size * ct_val;
-    Position {
-        symbol: position["market"].as_str().unwrap().to_string(),
-        margin_level: Decimal::from_str(&position["leverage"].as_str().unwrap()).unwrap(),
-        amount,
-        frozen_amount: Decimal::ZERO,
-        price: Decimal::from_str(&position["avg_entry_price"].as_str().unwrap()).unwrap(),
-        profit: Decimal::from_str(&position["unrealized_pnl"].as_str().unwrap()).unwrap(),
-        position_mode,
-        margin: Decimal::from_str(&position["ath_margin_size"].as_str().unwrap()).unwrap(),
-    }
-}
-
-// 处理order信息
-pub fn handle_order(res_data: ResponseData, ct_val: Decimal) -> SpecialOrder {
-    let status = res_data.data["event"].as_str().unwrap();
-    let res_data_json = &res_data.data["order"];
-    let order_info = format_order_item(res_data_json, ct_val, status);
-
-    SpecialOrder {
-        name: res_data.label,
-        order: vec![order_info],
-    }
-}
-
-pub fn format_order_item(order: &Value, ct_val: Decimal, status: &str) -> Order {
-    let text = order["client_id"].as_str().unwrap_or("");
-    let size = Decimal::from_str(order["amount"].as_str().unwrap()).unwrap();
-    let left = Decimal::from_str(order["unfilled_amount"].as_str().unwrap()).unwrap();
-    // 已成交量
-    let filled_amount = size - left;
-    // 成交额
-    let filled_value = Decimal::from_str(order["filled_value"].as_str().unwrap()).unwrap();
-    // 成交均价
-    let mut avg_price = Decimal::ZERO;
-    if filled_amount > Decimal::ZERO{
-        avg_price = filled_value/filled_amount;
-    }
-    let amount = size * ct_val;
-    let deal_amount = filled_amount * ct_val;
-    let custom_status = if status == "finish" { "REMOVE".to_string() } else if status == "put" || status == "update" { "NEW".to_string() } else {
-        "NULL".to_string()
-    };
-    let rst_order = Order {
-        id: order["order_id"].to_string(),
-        custom_id: text.replace("t-my-custom-id_", "").replace("t-", ""),
-        price: Decimal::from_str(order["price"].as_str().unwrap()).unwrap(),
-        amount,
-        deal_amount,
-        avg_price,
-        status: custom_status,
-        order_type: "limit".to_string(),
-        trace_stack: TraceStack::new(0, Instant::now()).on_special("120 Coinex_handle".to_string()),
-    };
-    return rst_order;
-}
-
-// 处理特殊Ticket信息
-pub fn handle_ticker(res_data: &ResponseData) -> SpecialDepth {
-    let depth = &res_data.data["depth"];
-
-    let bp = Decimal::from_str(depth["bids"][0][0].as_str().unwrap()).unwrap();
-    let bq = Decimal::from_str(depth["bids"][0][1].as_str().unwrap()).unwrap();
-    let ap = Decimal::from_str(depth["asks"][0][0].as_str().unwrap()).unwrap();
-    let aq = Decimal::from_str(depth["asks"][0][1].as_str().unwrap()).unwrap();
-    let mp = (bp + ap) * dec!(0.5);
-    let t = Decimal::from_i64(depth.get("checksum").unwrap().as_i64().unwrap_or(0i64)).unwrap();
-    let create_at = depth.get("updated_at").unwrap().as_i64().unwrap() * 1000;
-
-    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(value: &Value) -> Vec<MarketOrder> {
-    if value.is_null() {
-        return vec![];
-    }
-    let mut depth_items: Vec<MarketOrder> = vec![];
-    for value in value.as_array().unwrap() {
-        let values = value.as_array().unwrap();
-        depth_items.push(MarketOrder {
-            price: Decimal::from_str(values[0].as_str().unwrap()).unwrap(),
-            amount: Decimal::from_str(values[1].as_str().unwrap()).unwrap(),
-        })
-    }
-    return depth_items;
-}
+// use std::str::FromStr;
+// use rust_decimal::Decimal;
+// use rust_decimal::prelude::FromPrimitive;
+// use exchanges::response_base::ResponseData;
+// use crate::{Trade};
+//
+// // 处理账号信息
+// // pub fn handle_account_info(res_data: &ResponseData, symbol: &String) -> Account {
+// //     let res_data_json = res_data.data["balance_list"].as_array().unwrap();
+// //     format_account_info(res_data_json, symbol)
+// // }
+//
+// // pub fn format_account_info(data: &Vec<Value>, symbol: &String) -> Account {
+// //     let symbol_upper = symbol.to_uppercase();
+// //     let symbol_array: Vec<&str> = symbol_upper.split("_").collect();
+// //     let balance_info = data.iter().find(|&item| item["ccy"].as_str().unwrap().contains(symbol_array[1]));
+// //
+// //     match balance_info {
+// //         None => {
+// //             error!("Coinex:格式化账号信息错误!\nformat_account_info: data={:?}", data);
+// //             panic!("Coinex:格式化账号信息错误!\nformat_account_info: data={:?}", data)
+// //         }
+// //         Some(value) => {
+// //             let frozen_balance= Decimal::from_str(&value["frozen"].as_str().unwrap()).unwrap();
+// //             let available_balance = Decimal::from_str(&value["available"].as_str().unwrap()).unwrap();
+// //             let margin = Decimal::from_str(&value["margin"].as_str().unwrap()).unwrap();
+// //             let profit_unreal = Decimal::from_str(&value["unrealized_pnl"].as_str().unwrap()).unwrap();
+// //             let balance = frozen_balance + available_balance + margin + profit_unreal;
+// //             Account {
+// //                 coin: symbol_array[1].to_string(),
+// //                 balance,
+// //                 available_balance: Decimal::ZERO,
+// //                 frozen_balance: Decimal::ZERO,
+// //                 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["position"];
+// //     let position =  format_position_item(res_data_json, ct_val);
+// //     vec![position]
+// // }
+//
+// // pub fn format_position_item(position: &Value, ct_val: &Decimal) -> Position {
+// //     let position_mode = match position["side"].as_str().unwrap_or("") {
+// //         "long" => PositionModeEnum::Long,
+// //         "short" => PositionModeEnum::Short,
+// //         _ => {
+// //             error!("Coinex:格式化持仓模式错误!\nformat_position_item:position={:?}", position);
+// //             panic!("Coinex:格式化持仓模式错误!\nformat_position_item:position={:?}", position)
+// //         }
+// //     };
+// //     let size = Decimal::from_str(&position["open_interest"].as_str().unwrap()).unwrap();
+// //     let amount = size * ct_val;
+// //     Position {
+// //         symbol: position["market"].as_str().unwrap().to_string(),
+// //         margin_level: Decimal::from_str(&position["leverage"].as_str().unwrap()).unwrap(),
+// //         amount,
+// //         frozen_amount: Decimal::ZERO,
+// //         price: Decimal::from_str(&position["avg_entry_price"].as_str().unwrap()).unwrap(),
+// //         profit: Decimal::from_str(&position["unrealized_pnl"].as_str().unwrap()).unwrap(),
+// //         position_mode,
+// //         margin: Decimal::from_str(&position["ath_margin_size"].as_str().unwrap()).unwrap(),
+// //     }
+// // }
+//
+// // 处理order信息
+// // pub fn handle_order(res_data: ResponseData, ct_val: Decimal) -> SpecialOrder {
+// //     let status = res_data.data["event"].as_str().unwrap();
+// //     let res_data_json = &res_data.data["order"];
+// //     let order_info = format_order_item(res_data_json, ct_val, status);
+// //
+// //     SpecialOrder {
+// //         name: res_data.tag,
+// //         order: vec![order_info],
+// //     }
+// // }
+//
+// // pub fn format_order_item(order: &Value, ct_val: Decimal, status: &str) -> Order {
+// //     let text = order["client_id"].as_str().unwrap_or("");
+// //     let size = Decimal::from_str(order["amount"].as_str().unwrap()).unwrap();
+// //     let left = Decimal::from_str(order["unfilled_amount"].as_str().unwrap()).unwrap();
+// //     // 已成交量
+// //     let filled_amount = size - left;
+// //     // 成交额
+// //     let filled_value = Decimal::from_str(order["filled_value"].as_str().unwrap()).unwrap();
+// //     // 成交均价
+// //     let mut avg_price = Decimal::ZERO;
+// //     if filled_amount > Decimal::ZERO{
+// //         avg_price = filled_value/filled_amount;
+// //     }
+// //     let amount = size * ct_val;
+// //     let deal_amount = filled_amount * ct_val;
+// //     let custom_status = if status == "finish" { "REMOVE".to_string() } else if status == "put" || status == "update" { "NEW".to_string() } else {
+// //         "NULL".to_string()
+// //     };
+// //     let rst_order = Order {
+// //         id: order["order_id"].to_string(),
+// //         custom_id: text.replace("t-my-custom-id_", "").replace("t-", ""),
+// //         price: Decimal::from_str(order["price"].as_str().unwrap()).unwrap(),
+// //         amount,
+// //         deal_amount,
+// //         avg_price,
+// //         status: custom_status,
+// //         order_type: "limit".to_string(),
+// //     };
+// //     return rst_order;
+// // }
+//
+// pub fn format_trade_items(response: &ResponseData) -> Vec<Trade> {
+//     let symbol = response.data["market"].as_str().unwrap().to_string().replace("USDT", "_USDT");
+//     let result = response.data["deal_list"].as_array().unwrap();
+//     let mut trades = vec![];
+//
+//     for item in result {
+//         let id = format!("{}", item["deal_id"].as_i64().unwrap());
+//         let time = Decimal::from_i64(item["created_at"].as_i64().unwrap()).unwrap();
+//         let mut size = Decimal::from_str(item["amount"].as_str().unwrap()).unwrap();
+//         if item["side"].as_str().unwrap().eq("sell") {
+//             size = size * Decimal::NEGATIVE_ONE;
+//         }
+//         let price = Decimal::from_str(item["price"].as_str().unwrap().to_string().as_str()).unwrap();
+//
+//         let trade = Trade {
+//             id,
+//             time,
+//             size,
+//             price,
+//             symbol: symbol.clone(),
+//         };
+//
+//         trades.push(trade)
+//     }
+//
+//     return trades
+// }
+//
+// // 处理特殊Ticket信息
+// // pub fn handle_ticker(res_data: &ResponseData) -> SpecialDepth {
+// //     let depth = &res_data.data["depth"];
+// //
+// //     let bp = Decimal::from_str(depth["bids"][0][0].as_str().unwrap()).unwrap();
+// //     let bq = Decimal::from_str(depth["bids"][0][1].as_str().unwrap()).unwrap();
+// //     let ap = Decimal::from_str(depth["asks"][0][0].as_str().unwrap()).unwrap();
+// //     let aq = Decimal::from_str(depth["asks"][0][1].as_str().unwrap()).unwrap();
+// //     let mp = (bp + ap) * dec!(0.5);
+// //     let t = Decimal::from_i64(depth.get("checksum").unwrap().as_i64().unwrap_or(0i64)).unwrap();
+// //     let create_at = depth.get("updated_at").unwrap().as_i64().unwrap() * 1000;
+// //
+// //     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).tag.clone(),
+// //         depth: depth_info,
+// //         ticker: ticker_info,
+// //         t,
+// //         create_at,
+// //     }
+// // }
+//
+// // pub fn format_depth_items(value: &Value) -> Vec<MarketOrder> {
+// //     if value.is_null() {
+// //         return vec![];
+// //     }
+// //     let mut depth_items: Vec<MarketOrder> = vec![];
+// //     for value in value.as_array().unwrap() {
+// //         let values = value.as_array().unwrap();
+// //         depth_items.push(MarketOrder {
+// //             price: Decimal::from_str(values[0].as_str().unwrap()).unwrap(),
+// //             amount: Decimal::from_str(values[1].as_str().unwrap()).unwrap(),
+// //         })
+// //     }
+// //     return depth_items;
+// // }

+ 252 - 0
standard/src/coinsph_swap.rs

@@ -0,0 +1,252 @@
+// use std::collections::{BTreeMap};
+// use std::io::{Error, ErrorKind};
+// use std::str::FromStr;
+// use tokio::sync::mpsc::Sender;
+// use async_trait::async_trait;
+// use rust_decimal::{Decimal};
+// use serde_json::{json, Value};
+// use tracing::{error, info};
+// use crate::{Platform, ExchangeEnum, Account, Position, Ticker, Market, Order, utils};
+// use exchanges::coinsph_swap_rest::CoinsphSwapRest;
+// use rust_decimal::prelude::FromPrimitive;
+//
+// #[allow(dead_code)]
+// #[derive(Clone)]
+// pub struct CoinsphSwap {
+//     exchange: ExchangeEnum,
+//     symbol: String,
+//     is_colo: bool,
+//     params: BTreeMap<String, String>,
+//     request: CoinsphSwapRest,
+//     market: Market,
+//     order_sender: Sender<Order>,
+//     error_sender: Sender<Error>,
+// }
+//
+// impl CoinsphSwap {
+//     pub async fn new(symbol: String, is_colo: bool, params: BTreeMap<String, String>, order_sender: Sender<Order>, error_sender: Sender<Error>) -> CoinsphSwap {
+//         let market = Market::new();
+//         let mut coinsph_swap = CoinsphSwap {
+//             exchange: ExchangeEnum::CoinsphSwap,
+//             symbol: symbol.to_uppercase(),
+//             is_colo,
+//             params: params.clone(),
+//             request: CoinsphSwapRest::new(is_colo, params.clone()),
+//             market,
+//             order_sender,
+//             error_sender,
+//         };
+//
+//         // 修改持仓模式
+//         let symbol_array: Vec<&str> = symbol.split("_").collect();
+//         let mode_result = coinsph_swap.set_dual_mode(symbol_array[1], true).await;
+//         match mode_result {
+//             Ok(ok) => {
+//                 info!("Coinsph:设置持仓模式成功!{:?}", ok);
+//             }
+//             Err(error) => {
+//                 error!("Coinsph:设置持仓模式失败!mode_result={}", error)
+//             }
+//         }
+//         // 获取市场信息
+//         coinsph_swap.market = CoinsphSwap::get_market(&mut coinsph_swap).await.unwrap_or(coinsph_swap.market);
+//         return coinsph_swap;
+//     }
+// }
+//
+// #[async_trait]
+// impl Platform for CoinsphSwap {
+//     // 克隆方法
+//     fn clone_box(&self) -> Box<dyn Platform + Send + Sync> { Box::new(self.clone()) }
+//     // 获取交易所模式
+//     fn get_self_exchange(&self) -> ExchangeEnum {
+//         ExchangeEnum::CoinsphSwap
+//     }
+//     // 获取交易对
+//     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> {
+//         Err(Error::new(ErrorKind::NotFound, "coinsph_swap:该交易所方法未实现".to_string()))
+//     }
+//     // 获取账号信息
+//     async fn get_account(&mut self) -> Result<Account, Error> {
+//         Err(Error::new(ErrorKind::NotFound, "coinsph_swap:该交易所方法未实现".to_string()))
+//     }
+//
+//     async fn get_spot_account(&mut self) -> Result<Vec<Account>, Error> {
+//         Err(Error::new(ErrorKind::NotFound, "coinsph_swap:该交易所方法未实现".to_string()))
+//     }
+//
+//     // 获取持仓信息
+//     async fn get_position(&mut self) -> Result<Vec<Position>, Error> {
+//         Err(Error::new(ErrorKind::NotFound, "coinsph_swap:该交易所方法未实现".to_string()))
+//     }
+//     // 获取所有持仓
+//     async fn get_positions(&mut self) -> Result<Vec<Position>, Error> {
+//         Err(Error::new(ErrorKind::NotFound, "coinsph_swap:该交易所方法未实现".to_string()))
+//     }
+//     // 获取市场行情
+//     async fn get_ticker(&mut self) -> Result<Ticker, Error> {
+//         Err(Error::new(ErrorKind::NotFound, "coinsph_swap:该交易所方法未实现".to_string()))
+//     }
+//
+//     async fn get_ticker_symbol(&mut self, _symbol: String) -> Result<Ticker, Error> {
+//         Err(Error::new(ErrorKind::NotFound, "coinsph_swap:该交易所方法未实现".to_string()))
+//     }
+//
+//     async fn get_market(&mut self) -> Result<Market, Error> {
+//         let symbol_format = utils::format_symbol(self.symbol.clone(), "");
+//         let params = json!({});
+//         let res_data = self.request.get_market(params).await;
+//         if res_data.code == 200 {
+//             let symbols = res_data.data["symbols"].as_array().unwrap();
+//             let market_info = symbols.iter().find(|&item| item["symbol"].as_str().unwrap() == symbol_format);
+//             match market_info {
+//                 None => {
+//                     error!("coinsph_swap:获取Market信息错误!\nget_market:res_data={:?}", res_data);
+//                     Err(Error::new(ErrorKind::Other, res_data.to_string()))
+//                 }
+//                 Some(value) => {
+//                     let base_asset = value["baseAsset"].as_str().unwrap().to_string();
+//                     let quote_asset = value["quoteAsset"].as_str().unwrap().to_string();
+//
+//                     let filter_array = value["filters"].as_array().unwrap().clone();
+//                     let price_filter = filter_array.iter().find(|&item| item["filterType"].as_str().unwrap() == "PRICE_FILTER").unwrap();
+//                     let lot_size_filter = filter_array.iter().find(|&item| item["filterType"].as_str().unwrap() == "LOT_SIZE").unwrap();
+//
+//                     let result = Market {
+//                         symbol: format!("{}_{}", base_asset, quote_asset),
+//                         base_asset,
+//                         quote_asset,
+//                         tick_size: Decimal::from_str(&price_filter["tickSize"].as_str().unwrap()).unwrap(),
+//                         amount_size: Decimal::from_str(lot_size_filter["stepSize"].as_str().unwrap()).unwrap(),
+//                         price_precision: Decimal::from_f64(value["pricePrecision"].as_f64().unwrap()).unwrap(),
+//                         amount_precision: Decimal::from_f64(value["quantityPrecision"].as_f64().unwrap()).unwrap(),
+//                         min_qty: Decimal::from_str(lot_size_filter["minQty"].as_str().unwrap()).unwrap(),
+//                         max_qty: Decimal::from_str(lot_size_filter["maxQty"].as_str().unwrap()).unwrap(),
+//                         min_notional: Decimal::from_str(price_filter["minPrice"].as_str().unwrap()).unwrap(),
+//                         max_notional: Decimal::from_str(price_filter["maxPrice"].as_str().unwrap()).unwrap(),
+//                         ct_val: Decimal::ONE,
+//                     };
+//                     Ok(result)
+//                 }
+//             }
+//         } else {
+//             Err(Error::new(ErrorKind::Other, res_data.to_string()))
+//         }
+//     }
+//
+//     async fn get_market_symbol(&mut self, symbol: String) -> Result<Market, Error> {
+//         let symbol_format = utils::format_symbol(symbol.clone(), "");
+//         let params = json!({});
+//         let res_data = self.request.get_market(params).await;
+//         if res_data.code == 200 {
+//             let symbols = res_data.data["symbols"].as_array().unwrap();
+//             let market_info = symbols.iter().find(|&item| item["symbol"].as_str().unwrap() == symbol_format);
+//             match market_info {
+//                 None => {
+//                     error!("coinsph_swap:获取Market信息错误!\nget_market:res_data={:?}", res_data);
+//                     Err(Error::new(ErrorKind::Other, res_data.to_string()))
+//                 }
+//                 Some(value) => {
+//                     let base_asset = value["baseAsset"].as_str().unwrap().to_string();
+//                     let quote_asset = value["quoteAsset"].as_str().unwrap().to_string();
+//
+//                     let filter_array = value["filters"].as_array().unwrap().clone();
+//                     let price_filter = filter_array.iter().find(|&item| item["filterType"].as_str().unwrap() == "PRICE_FILTER").unwrap();
+//                     let lot_size_filter = filter_array.iter().find(|&item| item["filterType"].as_str().unwrap() == "LOT_SIZE").unwrap();
+//
+//                     let result = Market {
+//                         symbol: format!("{}_{}", base_asset, quote_asset),
+//                         base_asset,
+//                         quote_asset,
+//                         tick_size: Decimal::from_str(&price_filter["tickSize"].as_str().unwrap()).unwrap(),
+//                         amount_size: Decimal::from_str(lot_size_filter["stepSize"].as_str().unwrap()).unwrap(),
+//                         price_precision: Decimal::from_f64(value["pricePrecision"].as_f64().unwrap()).unwrap(),
+//                         amount_precision: Decimal::from_f64(value["quantityPrecision"].as_f64().unwrap()).unwrap(),
+//                         min_qty: Decimal::from_str(lot_size_filter["minQty"].as_str().unwrap()).unwrap(),
+//                         max_qty: Decimal::from_str(lot_size_filter["maxQty"].as_str().unwrap()).unwrap(),
+//                         min_notional: Decimal::from_str(price_filter["minPrice"].as_str().unwrap()).unwrap(),
+//                         max_notional: Decimal::from_str(price_filter["maxPrice"].as_str().unwrap()).unwrap(),
+//                         ct_val: Decimal::ONE,
+//                     };
+//                     Ok(result)
+//                 }
+//             }
+//         } else {
+//             Err(Error::new(ErrorKind::Other, res_data.to_string()))
+//         }
+//     }
+//
+//     // 获取订单详情
+//     async fn get_order_detail(&mut self, _order_id: &str, _custom_id: &str) -> Result<Order, Error> {
+//         Err(Error::new(ErrorKind::NotFound, "coinsph_swap:该交易所方法未实现".to_string()))
+//     }
+//     // 获取订单列表
+//     async fn get_orders_list(&mut self, _status: &str) -> Result<Vec<Order>, Error> {
+//         Err(Error::new(ErrorKind::NotFound, "coinsph_swap:该交易所方法未实现".to_string()))
+//     }
+//     // 下单接口
+//     async fn take_order(&mut self, _custom_id: &str, _origin_side: &str, _price: Decimal, _amount: Decimal) -> Result<Order, Error> {
+//         Err(Error::new(ErrorKind::NotFound, "coinsph_swap:该交易所方法未实现".to_string()))
+//     }
+//
+//     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> {
+//         Err(Error::new(ErrorKind::NotFound, "coinsph_swap:该交易所方法未实现".to_string()))
+//     }
+//
+//     // 撤销订单
+//     async fn cancel_order(&mut self, _order_id: &str, _custom_id: &str) -> Result<Order, Error> {
+//         Err(Error::new(ErrorKind::NotFound, "coinsph_swap:该交易所方法未实现".to_string()))
+//     }
+//     // 批量撤销订单
+//     async fn cancel_orders(&mut self) -> Result<Vec<Order>, Error> {
+//         Err(Error::new(ErrorKind::NotFound, "coinsph_swap:该交易所方法未实现".to_string()))
+//     }
+//
+//     async fn cancel_orders_all(&mut self) -> Result<Vec<Order>, Error> {
+//         Err(Error::new(ErrorKind::NotFound, "coinsph_swap:该交易所方法未实现".to_string()))
+//     }
+//
+//     async fn take_stop_loss_order(&mut self, _stop_price: Decimal, _price: Decimal, _side: &str) -> Result<Value, Error> {
+//         Err(Error::new(ErrorKind::NotFound, "coinsph_swap:该交易所方法未实现".to_string()))
+//     }
+//
+//     async fn cancel_stop_loss_order(&mut self, _order_id: &str) -> Result<Value, Error> {
+//         Err(Error::new(ErrorKind::NotFound, "coinsph_swap:该交易所方法未实现".to_string()))
+//     }
+//
+//     // 设置持仓模式
+//     async fn set_dual_mode(&mut self, _coin: &str, _is_dual_mode: bool) -> Result<String, Error> {
+//         Err(Error::new(ErrorKind::NotFound, "coinsph_swap:该交易所方法未实现".to_string()))
+//     }
+//
+//     // 更新双持仓模式下杠杆
+//     async fn set_dual_leverage(&mut self, _leverage: &str) -> Result<String, Error> {
+//         Err(Error::new(ErrorKind::NotFound, "coinsph_swap:该交易所方法未实现".to_string()))
+//     }
+//
+//     async fn set_auto_deposit_status(&mut self, _status: bool) -> Result<String, Error> { Err(Error::new(ErrorKind::NotFound, "coinsph:该交易所方法未实现".to_string())) }
+//
+//     // 交易账户互转
+//     async fn wallet_transfers(&mut self, _coin: &str, _from: &str, _to: &str, _amount: Decimal) -> Result<String, Error> {
+//         Err(Error::new(ErrorKind::NotFound, "coinsph_swap:该交易所方法未实现".to_string()))
+//     }
+// }

+ 94 - 0
standard/src/coinsph_swap_handle.rs

@@ -0,0 +1,94 @@
+// use std::str::FromStr;
+// use rust_decimal::Decimal;
+// use rust_decimal::prelude::FromPrimitive;
+// use serde_json::Value;
+// use exchanges::response_base::ResponseData;
+// use crate::{Trade, Record};
+// // use crate::{OrderBook, Trade, Record};
+// // use crate::{Account, OrderBook, Order, Position, SpecialOrder, Trade, Record};
+//
+// // 处理账号信息
+// // pub fn handle_account_info(res_data: &ResponseData, symbol: &String) -> Account {
+// //     Account::new()
+// // }
+// //
+// // pub fn format_account_info(_data: &Vec<Value>, _symbol: &String) -> Account {
+// //     Account::new()
+// // }
+// //
+// // // 处理position信息
+// // pub fn handle_position(_res_data: &ResponseData, _ct_val: &Decimal) -> Vec<Position> {
+// //     vec![Position::new()]
+// // }
+// //
+// // pub fn format_position_item(_position: &Value, _ct_val: &Decimal) -> Position {
+// //     Position::new()
+// // }
+// //
+// // // 处理order信息
+// // pub fn handle_order(_res_data: &ResponseData, _ct_val: Decimal) -> SpecialOrder {
+// //     SpecialOrder::new()
+// // }
+// //
+// // pub fn format_order_item(_order: Value, _ct_val: Decimal) -> Order {
+// //     Order::new()
+// // }
+// // 处理特殊Ticket信息
+// // pub fn handle_book_ticker(res_data: &ResponseData) -> SpecialDepth {
+// //     let bp = Decimal::from_str((*res_data).data["b"].as_str().unwrap()).unwrap();
+// //     let bq = Decimal::from_f64((*res_data).data["B"].as_f64().unwrap()).unwrap();
+// //     let ap = Decimal::from_str((*res_data).data["a"].as_str().unwrap()).unwrap();
+// //     let aq = Decimal::from_f64((*res_data).data["A"].as_f64().unwrap()).unwrap();
+// //     let mp = (bp + ap) * dec!(0.5);
+// //     let t = Decimal::from_u64((*res_data).data["u"].as_u64().unwrap()).unwrap();
+// //     let create_at = (*res_data).data["t"].as_i64().unwrap() * 1000;
+// //
+// //     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).tag.clone(),
+// //         depth: depth_info,
+// //         ticker: ticker_info,
+// //         t,
+// //         create_at,
+// //     }
+// // }
+//
+// pub fn handle_records(value: &Value) -> Vec<Record> {
+//     let data = value["k"].clone();
+//     return vec![Record {
+//         time: Decimal::from_i64(data["t"].as_i64().unwrap()).unwrap(),
+//         open: Decimal::from_str(data["o"].as_str().unwrap()).unwrap(),
+//         high: Decimal::from_str(data["h"].as_str().unwrap()).unwrap(),
+//         low: Decimal::from_str(data["l"].as_str().unwrap()).unwrap(),
+//         close: Decimal::from_str(data["c"].as_str().unwrap()).unwrap(),
+//         volume: Decimal::from_str(data["q"].as_str().unwrap()).unwrap(),
+//         symbol: data["s"].as_str().unwrap().replace("USDT","_USDT"),
+//     }];
+// }
+//
+// // pub fn format_depth_items(value: &Value) -> Vec<OrderBook> {
+// //     let mut depth_items: Vec<OrderBook> = vec![];
+// //     for value in value.as_array().unwrap() {
+// //         depth_items.push(OrderBook {
+// //             price: Decimal::from_f64(value[0].as_f64().unwrap()).unwrap(),
+// //             amount: Decimal::from_f64(value[1].as_f64().unwrap()).unwrap(),
+// //         })
+// //     }
+// //     return depth_items;
+// // }
+//
+// pub fn format_trade_items(res_data: &ResponseData) -> Vec<Trade> {
+//     let result = res_data.data.clone();
+//
+//     let side = result["m"] == true;
+//     let size = Decimal::from_str(result["q"].as_str().unwrap()).unwrap();
+//     return vec![Trade {
+//         id: result["a"].to_string(),
+//         time: Decimal::from_i64(result["T"].as_i64().unwrap()).unwrap(),
+//         size: if side { -size } else { size },
+//         price: Decimal::from_str(result["p"].as_str().unwrap()).unwrap(),
+//         symbol: result["s"].as_str().unwrap().replace("USDT","_USDT"),
+//     }];
+// }

+ 268 - 0
standard/src/cointr_swap.rs

@@ -0,0 +1,268 @@
+// use std::collections::{BTreeMap};
+// use std::io::{Error, ErrorKind};
+// use std::str::FromStr;
+// use tokio::sync::mpsc::Sender;
+// use async_trait::async_trait;
+// use rust_decimal::{Decimal};
+// use serde_json::{json, Value};
+// use tracing::{error, info};
+// use crate::{Platform, ExchangeEnum, Account, Position, Ticker, Market, Order, utils};
+// use exchanges::cointr_swap_rest::CointrSwapRest;
+// use rust_decimal::prelude::FromPrimitive;
+//
+// #[allow(dead_code)]
+// #[derive(Clone)]
+// pub struct CointrSwap {
+//     exchange: ExchangeEnum,
+//     symbol: String,
+//     is_colo: bool,
+//     params: BTreeMap<String, String>,
+//     request: CointrSwapRest,
+//     market: Market,
+//     order_sender: Sender<Order>,
+//     error_sender: Sender<Error>,
+// }
+//
+// impl CointrSwap {
+//     pub async fn new(symbol: String, is_colo: bool, params: BTreeMap<String, String>, order_sender: Sender<Order>, error_sender: Sender<Error>) -> CointrSwap {
+//         let market = Market::new();
+//         let mut cointr_swap = CointrSwap {
+//             exchange: ExchangeEnum::CointrSwap,
+//             symbol: symbol.to_uppercase(),
+//             is_colo,
+//             params: params.clone(),
+//             request: CointrSwapRest::new(is_colo, params.clone()),
+//             market,
+//             order_sender,
+//             error_sender,
+//         };
+//
+//         // 修改持仓模式
+//         let symbol_array: Vec<&str> = symbol.split("_").collect();
+//         let mode_result = cointr_swap.set_dual_mode(symbol_array[1], true).await;
+//         match mode_result {
+//             Ok(ok) => {
+//                 info!("Cointr:设置持仓模式成功!{:?}", ok);
+//             }
+//             Err(error) => {
+//                 error!("Cointr:设置持仓模式失败!mode_result={}", error)
+//             }
+//         }
+//         // 获取市场信息
+//         cointr_swap.market = CointrSwap::get_market(&mut cointr_swap).await.unwrap_or(cointr_swap.market);
+//         return cointr_swap;
+//     }
+// }
+//
+// #[async_trait]
+// impl Platform for CointrSwap {
+//     // 克隆方法
+//     fn clone_box(&self) -> Box<dyn Platform + Send + Sync> { Box::new(self.clone()) }
+//     // 获取交易所模式
+//     fn get_self_exchange(&self) -> ExchangeEnum {
+//         ExchangeEnum::CointrSwap
+//     }
+//     // 获取交易对
+//     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> {
+//         Err(Error::new(ErrorKind::NotFound, "cointr_swap:该交易所方法未实现".to_string()))
+//     }
+//     // 获取账号信息
+//     async fn get_account(&mut self) -> Result<Account, Error> {
+//         Err(Error::new(ErrorKind::NotFound, "cointr_swap:该交易所方法未实现".to_string()))
+//     }
+//
+//     async fn get_spot_account(&mut self) -> Result<Vec<Account>, Error> {
+//         Err(Error::new(ErrorKind::NotFound, "cointr_swap:该交易所方法未实现".to_string()))
+//     }
+//
+//     // 获取持仓信息
+//     async fn get_position(&mut self) -> Result<Vec<Position>, Error> {
+//         Err(Error::new(ErrorKind::NotFound, "cointr_swap:该交易所方法未实现".to_string()))
+//     }
+//     // 获取所有持仓
+//     async fn get_positions(&mut self) -> Result<Vec<Position>, Error> {
+//         Err(Error::new(ErrorKind::NotFound, "cointr_swap:该交易所方法未实现".to_string()))
+//     }
+//     // 获取市场行情
+//     async fn get_ticker(&mut self) -> Result<Ticker, Error> {
+//         Err(Error::new(ErrorKind::NotFound, "cointr_swap:该交易所方法未实现".to_string()))
+//     }
+//
+//     async fn get_ticker_symbol(&mut self, _symbol: String) -> Result<Ticker, Error> {
+//         Err(Error::new(ErrorKind::NotFound, "cointr_swap:该交易所方法未实现".to_string()))
+//     }
+//
+//     async fn get_market(&mut self) -> Result<Market, Error> {
+//         let symbol_format = utils::format_symbol(self.symbol.clone(), "");
+//         let params = json!({});
+//         let res_data = self.request.get_market(params).await;
+//         if res_data.code == 200 {
+//             let res_data_json = res_data.data["data"].as_array().unwrap();
+//             let market_info = res_data_json.iter().find(|item| item["instId"].as_str().unwrap() == symbol_format);
+//             match market_info {
+//                 None => {
+//                     error!("cointr_swap:获取Market信息错误!\nget_market:res_data={:?}", res_data);
+//                     Err(Error::new(ErrorKind::Other, res_data.to_string()))
+//                 }
+//                 Some(value) => {
+//                     let symbol = value["instId"].as_str().unwrap().to_string();
+//                     let base_asset = value["baseCcy"].as_str().unwrap().to_string();
+//                     let quote_asset = value["quoteCcy"].as_str().unwrap().to_string();
+//
+//                     let tick_size = Decimal::from_str(value["tickSz"].as_str().unwrap()).unwrap();
+//                     let step: Vec<&str> = value["steps"].as_str().unwrap().split(",").collect();
+//                     let amount_size = tick_size * Decimal::from_str(step[0]).unwrap();
+//                     let price_precision = Decimal::from_str(value["pxPrecision"].as_str().unwrap()).unwrap();
+//                     let amount_precision = Decimal::from_u32(amount_size.scale()).unwrap();
+//                     let min_qty = Decimal::from_str(value["minSz"].as_str().unwrap()).unwrap();
+//                     let max_qty = Decimal::from_str(value["maxSz"].as_str().unwrap()).unwrap();
+//                     let min_notional = min_qty;
+//                     let max_notional = max_qty;
+//                     let ct_val = Decimal::from_str(value["ctVal"].as_str().unwrap()).unwrap();
+//
+//                     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)
+//                 }
+//             }
+//         } else {
+//             Err(Error::new(ErrorKind::Other, res_data.to_string()))
+//         }
+//     }
+//
+//     async fn get_market_symbol(&mut self, symbol: String) -> Result<Market, Error> {
+//         let symbol_format = format!("PERP_{}", symbol.clone().to_uppercase());
+//         let params = json!({});
+//         let res_data = self.request.get_market(params).await;
+//         if res_data.code == 200 {
+//             let res_data_json = res_data.data["rows"].as_array().unwrap();
+//             let market_info = res_data_json.iter().find(|item| item["symbol"].as_str().unwrap() == symbol_format);
+//             match market_info {
+//                 None => {
+//                     error!("cointr_swap:获取Market信息错误!\nget_market:res_data={:?}", res_data);
+//                     Err(Error::new(ErrorKind::Other, res_data.to_string()))
+//                 }
+//                 Some(value) => {
+//                     let symbol = value["symbol"].as_str().unwrap().to_string().replace("PERP_", "");
+//                     let symbol_array: Vec<&str> = symbol.split("_").collect();
+//                     let base_asset = symbol_array[0].to_string();
+//                     let quote_asset = symbol_array[1].to_string();
+//
+//                     let tick_size = Decimal::from_str(value["quote_min"].as_str().unwrap()).unwrap();
+//                     let amount_size = Decimal::from_str(&value["base_min"].as_str().unwrap()).unwrap();
+//                     let price_precision = Decimal::from_u32(tick_size.scale()).unwrap();
+//                     let amount_precision = Decimal::from_u32(amount_size.scale()).unwrap();
+//                     let min_qty = Decimal::from_str(value["quote_min"].as_str().unwrap()).unwrap();
+//                     let max_qty = Decimal::from_str(value["quote_max"].as_str().unwrap()).unwrap();
+//                     let min_notional = Decimal::from_str(value["min_notional"].as_str().unwrap()).unwrap();
+//                     let max_notional = 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)
+//                 }
+//             }
+//         } else {
+//             Err(Error::new(ErrorKind::Other, res_data.to_string()))
+//         }
+//     }
+//
+//     // 获取订单详情
+//     async fn get_order_detail(&mut self, _order_id: &str, _custom_id: &str) -> Result<Order, Error> {
+//         Err(Error::new(ErrorKind::NotFound, "cointr_swap:该交易所方法未实现".to_string()))
+//     }
+//     // 获取订单列表
+//     async fn get_orders_list(&mut self, _status: &str) -> Result<Vec<Order>, Error> {
+//         Err(Error::new(ErrorKind::NotFound, "cointr_swap:该交易所方法未实现".to_string()))
+//     }
+//     // 下单接口
+//     async fn take_order(&mut self, _custom_id: &str, _origin_side: &str, _price: Decimal, _amount: Decimal) -> Result<Order, Error> {
+//         Err(Error::new(ErrorKind::NotFound, "cointr_swap:该交易所方法未实现".to_string()))
+//     }
+//
+//     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> {
+//         Err(Error::new(ErrorKind::NotFound, "cointr_swap:该交易所方法未实现".to_string()))
+//     }
+//
+//     // 撤销订单
+//     async fn cancel_order(&mut self, _order_id: &str, _custom_id: &str) -> Result<Order, Error> {
+//         Err(Error::new(ErrorKind::NotFound, "cointr_swap:该交易所方法未实现".to_string()))
+//     }
+//     // 批量撤销订单
+//     async fn cancel_orders(&mut self) -> Result<Vec<Order>, Error> {
+//         Err(Error::new(ErrorKind::NotFound, "cointr_swap:该交易所方法未实现".to_string()))
+//     }
+//
+//     async fn cancel_orders_all(&mut self) -> Result<Vec<Order>, Error> {
+//         Err(Error::new(ErrorKind::NotFound, "cointr_swap:该交易所方法未实现".to_string()))
+//     }
+//
+//     async fn take_stop_loss_order(&mut self, _stop_price: Decimal, _price: Decimal, _side: &str) -> Result<Value, Error> {
+//         Err(Error::new(ErrorKind::NotFound, "cointr_swap:该交易所方法未实现".to_string()))
+//     }
+//
+//     async fn cancel_stop_loss_order(&mut self, _order_id: &str) -> Result<Value, Error> {
+//         Err(Error::new(ErrorKind::NotFound, "cointr_swap:该交易所方法未实现".to_string()))
+//     }
+//
+//     // 设置持仓模式
+//     async fn set_dual_mode(&mut self, _coin: &str, _is_dual_mode: bool) -> Result<String, Error> {
+//         Err(Error::new(ErrorKind::NotFound, "cointr_swap:该交易所方法未实现".to_string()))
+//     }
+//
+//     // 更新双持仓模式下杠杆
+//     async fn set_dual_leverage(&mut self, _leverage: &str) -> Result<String, Error> {
+//         Err(Error::new(ErrorKind::NotFound, "cointr_swap:该交易所方法未实现".to_string()))
+//     }
+//
+//     async fn set_auto_deposit_status(&mut self, _status: bool) -> Result<String, Error> { Err(Error::new(ErrorKind::NotFound, "cointr:该交易所方法未实现".to_string())) }
+//
+//     // 交易账户互转
+//     async fn wallet_transfers(&mut self, _coin: &str, _from: &str, _to: &str, _amount: Decimal) -> Result<String, Error> {
+//         Err(Error::new(ErrorKind::NotFound, "cointr_swap:该交易所方法未实现".to_string()))
+//     }
+// }

+ 55 - 0
standard/src/cointr_swap_handle.rs

@@ -0,0 +1,55 @@
+// use std::str::FromStr;
+// use rust_decimal::Decimal;
+// use rust_decimal::prelude::FromPrimitive;
+// use serde_json::Value;
+// use exchanges::response_base::ResponseData;
+// use crate::{OrderBook, Trade, Record};
+//
+// pub fn handle_records(value: &Value) -> Vec<Record> {
+//     let mut records = vec![];
+//     let records_list = value["data"].as_array().unwrap();
+//
+//     for record_value in records_list {
+//         records.push(Record {
+//             time: Decimal::from_i64(record_value[0].as_i64().unwrap() * 1000).unwrap(),
+//             open: Decimal::from_str(record_value[1].as_str().unwrap()).unwrap(),
+//             high: Decimal::from_str(record_value[2].as_str().unwrap()).unwrap(),
+//             low: Decimal::from_str(record_value[3].as_str().unwrap()).unwrap(),
+//             close: Decimal::from_str(record_value[4].as_str().unwrap()).unwrap(),
+//             volume: Decimal::from_str(record_value[5].as_str().unwrap()).unwrap(),
+//             symbol: value["instId"].as_str().unwrap().replace("USDT", "_USDT"),
+//         });
+//     }
+//     records
+// }
+//
+// pub fn format_depth_items(value: &Value) -> Vec<OrderBook> {
+//     let mut depth_items: Vec<OrderBook> = vec![];
+//     for value in value.as_array().unwrap() {
+//         depth_items.push(OrderBook {
+//             price: Decimal::from_str(value[0].as_str().unwrap()).unwrap(),
+//             amount: Decimal::from_str(value[1].as_str().unwrap()).unwrap(),
+//         })
+//     }
+//     return depth_items;
+// }
+//
+// pub fn format_trade_items(res_data: &ResponseData) -> Vec<Trade> {
+//     let result = res_data.data["data"].as_array().unwrap();
+//     let mut trades = vec![];
+//     for item in result {
+//         let side = item["side"] == "BUY";
+//         let size = Decimal::from_str(item["sz"].as_str().unwrap()).unwrap();
+//         let price = Decimal::from_str(item["px"].as_str().unwrap()).unwrap();
+//         trades.push(Trade {
+//             id: item["tradeId"].to_string(),
+//             time: Decimal::from_i64(item["mTime"].as_i64().unwrap()).unwrap(),
+//             size: if side { size * price } else { -size * price },
+//             price,
+//             symbol: res_data.data["instId"].as_str().unwrap().replace("USDT", "_USDT"),
+//
+//         })
+//     }
+//
+//     return trades;
+// }

+ 49 - 31
standard/src/exchange.rs

@@ -3,17 +3,7 @@ use std::io::Error;
 use tokio::sync::mpsc::Sender;
 use crate::{Order, Platform};
 use crate::binance_swap::BinanceSwap;
-// use crate::binance_spot::BinanceSpot;
-// use crate::gate_spot::GateSpot;
 use crate::gate_swap::GateSwap;
-use crate::kucoin_swap::KucoinSwap;
-// use crate::bitget_spot::BitgetSpot;
-use crate::bybit_swap::BybitSwap;
-use crate::bitget_swap::BitgetSwap;
-use crate::coinex_swap::CoinexSwap;
-// use crate::kucoin_spot::KucoinSpot;
-// use crate::okx_swap::OkxSwap;
-use crate::htx_swap::HtxSwap;
 
 /// 交易所交易模式枚举
 /// - `BinanceSwap`: Binance交易所期货;
@@ -24,17 +14,24 @@ use crate::htx_swap::HtxSwap;
 #[derive(Debug, Clone, PartialEq, Eq)]
 pub enum ExchangeEnum {
     BinanceSwap,
+    // CoinexSwap,
     // BinanceSpot,
     GateSwap,
     // GateSpot,
-    KucoinSwap,
+    // KucoinSwap,
     // KucoinSpot,
     // OkxSwap,
     // BitgetSpot,
-    CoinexSwap,
-    BitgetSwap,
-    BybitSwap,
-    HtxSwap
+    // BitgetSwap,
+    // BybitSwap,
+    // HtxSwap,
+    // BingxSwap,
+    // MexcSwap,
+    // BitMartSwap,
+    // CoinsphSwap,
+    // PhemexSwap,
+    // WooSwap,
+    // CointrSwap
 }
 
 /// Exchange结构体
@@ -86,11 +83,11 @@ impl Exchange {
                 Box::new(GateSwap::new(symbol, is_colo, params, order_sender, error_sender).await)
             }
             // ExchangeEnum::GateSpot => {
-            //     Box::new(GateSpot::new(symbol, is_colo, params))
+            //     Box::new(GateSpot::new(symbol, is_colo, params, order_sender, error_sender).await)
+            // }
+            // ExchangeEnum::KucoinSwap => {
+            //     Box::new(KucoinSwap::new(symbol, is_colo, params, order_sender, error_sender).await)
             // }
-            ExchangeEnum::KucoinSwap => {
-                Box::new(KucoinSwap::new(symbol, is_colo, params, order_sender, error_sender).await)
-            }
             // ExchangeEnum::KucoinSpot =>{
             //     Box::new(KucoinSpot::new(symbol, is_colo, params, order_sender, error_sender).await)
             // }
@@ -100,18 +97,39 @@ impl Exchange {
             // ExchangeEnum::BitgetSpot => {
             //     Box::new(BitgetSpot::new(symbol, is_colo, params, order_sender, error_sender).await)
             // }
-            ExchangeEnum::BitgetSwap => {
-                Box::new(BitgetSwap::new(symbol, is_colo, params, order_sender, error_sender).await)
-            }
-            ExchangeEnum::BybitSwap => {
-                Box::new(BybitSwap::new(symbol, is_colo, params, order_sender, error_sender).await)
-            }
-            ExchangeEnum::CoinexSwap => {
-                Box::new(CoinexSwap::new(symbol, is_colo, params, order_sender, error_sender).await)
-            }
-            ExchangeEnum::HtxSwap => {
-                Box::new(HtxSwap::new(symbol, is_colo, params, order_sender, error_sender).await)
-            }
+            // ExchangeEnum::BitgetSwap => {
+            //     Box::new(BitgetSwap::new(symbol, is_colo, params, order_sender, error_sender).await)
+            // }
+            // ExchangeEnum::BybitSwap => {
+            //     Box::new(BybitSwap::new(symbol, is_colo, params, order_sender, error_sender).await)
+            // }
+            // ExchangeEnum::CoinexSwap => {
+            //     Box::new(CoinexSwap::new(symbol, is_colo, params, order_sender, error_sender).await)
+            // }
+            // ExchangeEnum::HtxSwap => {
+            //     Box::new(HtxSwap::new(symbol, is_colo, params, order_sender, error_sender).await)
+            // }
+            // ExchangeEnum::BingxSwap => {
+            //     Box::new(BingxSwap::new(symbol, is_colo, params, order_sender, error_sender).await)
+            // }
+            // ExchangeEnum::MexcSwap => {
+            //     Box::new(MexcSwap::new(symbol, is_colo, params, order_sender, error_sender).await)
+            // }
+            // ExchangeEnum::BitMartSwap => {
+            //     Box::new(BitMartSwap::new(symbol, is_colo, params, order_sender, error_sender).await)
+            // }
+            // ExchangeEnum::CoinsphSwap => {
+            //     Box::new(CoinsphSwap::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)
+            // }
+            // ExchangeEnum::WooSwap => {
+            //     Box::new(WooSwap::new(symbol, is_colo, params, order_sender, error_sender).await)
+            // }
+            // ExchangeEnum::CointrSwap => {
+            //     Box::new(CointrSwap::new(symbol, is_colo, params, order_sender, error_sender).await)
+            // }
         }
     }
 }

+ 270 - 0
standard/src/exchange_struct_handler.rs

@@ -0,0 +1,270 @@
+use std::str::FromStr;
+use rust_decimal::{Decimal};
+use tracing::{error};
+use exchanges::response_base::ResponseData;
+use crate::exchange::ExchangeEnum;
+use crate::{binance_swap_handle, gate_swap_handle};
+use crate::{Record, Ticker, Trade, Depth};
+use crate::{Account, OrderBook, Position, SpecialOrder};
+
+#[allow(dead_code)]
+pub struct ExchangeStructHandler;
+
+#[allow(dead_code)]
+impl ExchangeStructHandler {
+    // 处理深度信息
+    pub fn order_book_handle(exchange: ExchangeEnum, res_data: &ResponseData) -> Depth {
+        let depth_asks: Vec<OrderBook>;
+        let depth_bids: Vec<OrderBook>;
+        let t: Decimal;
+        let symbol = match exchange {
+            ExchangeEnum::BinanceSwap => {
+                depth_asks = binance_swap_handle::format_depth_items(res_data.data["a"].clone());
+                depth_bids = binance_swap_handle::format_depth_items(res_data.data["b"].clone());
+                t = Decimal::from_str(&res_data.data["E"].to_string()).unwrap();
+
+                res_data.data["s"].as_str().unwrap().to_string().replace("USDT", "_USDT")
+            }
+            ExchangeEnum::GateSwap => {
+                depth_asks = gate_swap_handle::format_depth_items(&res_data.data["asks"]);
+                depth_bids = gate_swap_handle::format_depth_items(&res_data.data["bids"]);
+                t = Decimal::from_str(&res_data.data["t"].to_string()).unwrap();
+
+                res_data.data["contract"].as_str().unwrap().to_string()
+            }
+            // ExchangeEnum::GateSpot => {
+            //     depth_asks = gate_spot_handle::format_depth_items(&res_data.data["asks"]);
+            //     depth_bids = gate_spot_handle::format_depth_items(&res_data.data["bids"]);
+            //     t = Decimal::from_str(&res_data.data["t"].to_string()).unwrap();
+            //     symbol = res_data.data["s"].as_str().unwrap().to_string()
+            // }
+            // ExchangeEnum::KucoinSwap => {
+            //     depth_asks = kucoin_swap_handle::format_depth_items(res_data.data["asks"].clone());
+            //     depth_bids = kucoin_swap_handle::format_depth_items(res_data.data["bids"].clone());
+            //     t = Decimal::from_str(&res_data.data["ts"].to_string()).unwrap();
+            // }
+            // ExchangeEnum::BitgetSwap => {
+            //     depth_asks = bitget_swap_handle::format_depth_items(res_data.data[0]["asks"].clone());
+            //     depth_bids = bitget_swap_handle::format_depth_items(res_data.data[0]["bids"].clone());
+            //     t = Decimal::from_str(res_data.data[0]["ts"].as_str().unwrap()).unwrap();
+            // }
+            // ExchangeEnum::BybitSwap => {
+            //     depth_asks = bybit_swap_handle::format_depth_items(res_data.data["a"].clone());
+            //     depth_bids = bybit_swap_handle::format_depth_items(res_data.data["b"].clone());
+            //     t = Decimal::from_i64(res_data.reach_time).unwrap();
+            // }
+            // ExchangeEnum::BingxSwap => {
+            //     depth_asks = bingx_swap_handle::format_depth_items(&res_data.data["data"]["asks"].clone());
+            //     depth_bids = bingx_swap_handle::format_depth_items(&res_data.data["data"]["bids"].clone());
+            //     t = Decimal::from_i64(res_data.reach_time).unwrap();
+            // }
+            // ExchangeEnum::MexcSwap => {
+            //     depth_asks = mexc_swap_handle::format_depth_items(&res_data.data["data"]["asks"].clone());
+            //     depth_bids = mexc_swap_handle::format_depth_items(&res_data.data["data"]["bids"].clone());
+            //     t = Decimal::from_i64(res_data.data["ts"].as_i64().unwrap()).unwrap();
+            // }
+            // ExchangeEnum::PhemexSwap => {
+            //     depth_asks = phemex_swap_handle::format_depth_items(&res_data.data["orderbook_p"]["asks"].clone());
+            //     depth_bids = phemex_swap_handle::format_depth_items(&res_data.data["orderbook_p"]["bids"].clone());
+            //     t = Decimal::from_i64(res_data.data["timestamp"].as_i64().unwrap() / 1000 / 1000).unwrap();
+            // }
+            // ExchangeEnum::WooSwap => {
+            //     depth_asks = woo_swap_handle::format_depth_items(&res_data.data["asks"].clone());
+            //     depth_bids = woo_swap_handle::format_depth_items(&res_data.data["bids"].clone());
+            //     t = Decimal::from_i64(res_data.data["ts"].as_i64().unwrap()).unwrap();
+            //     symbol = res_data.data["data"]["symbol"].as_str().unwrap().replace("PERP_", "")
+            // }
+            // ExchangeEnum::CointrSwap => {
+            //     depth_asks = cointr_swap_handle::format_depth_items(&res_data.data["asks"].clone());
+            //     depth_bids = cointr_swap_handle::format_depth_items(&res_data.data["bids"].clone());
+            //     t = Decimal::from_i64(res_data.data["pTime"].as_i64().unwrap()).unwrap();
+            //     symbol = res_data.data["instId"].as_str().unwrap().replace("USDT", "_USDT")
+            // }
+            // _ => {
+            //     error!("未找到该交易所!order_book_handle: {:?}", exchange);
+            //     panic!("未找到该交易所!order_book_handle: {:?}", exchange);
+            // }
+        };
+
+        Depth {
+            asks: depth_asks,
+            bids: depth_bids,
+            time: t,
+            symbol,
+        }
+    }
+    // 处理成交信息
+    pub fn trades_handle(exchange: ExchangeEnum, res_data: &ResponseData) -> Vec<Trade> {
+        match exchange {
+            ExchangeEnum::GateSwap => {
+                gate_swap_handle::format_trade_items(&res_data)
+            }
+            // ExchangeEnum::GateSpot => {
+            //     gate_spot_handle::format_trade_items(&res_data)
+            // }
+            // ExchangeEnum::BitgetSwap => {
+            //     bitget_swap_handle::format_trade_items(&res_data)
+            // }
+            ExchangeEnum::BinanceSwap => {
+                binance_swap_handle::format_trade_items(&res_data)
+            }
+            // ExchangeEnum::CoinexSwap => {
+            //     coinex_swap_handle::format_trade_items(&res_data)
+            // }
+            // ExchangeEnum::HtxSwap => {
+            //     htx_swap_handle::format_trade_items(&res_data)
+            // }
+            // ExchangeEnum::BingxSwap => {
+            //     bingx_swap_handle::format_trade_items(&res_data)
+            // }
+            // ExchangeEnum::MexcSwap => {
+            //     mexc_swap_handle::format_trade_items(&res_data)
+            // }
+            // ExchangeEnum::OkxSwap => {
+            //     okx_swap_handle::format_trade_items(&res_data)
+            // }
+            // ExchangeEnum::BitMartSwap => {
+            //     bitmart_swap_handle::format_trade_items(&res_data)
+            // }
+            // ExchangeEnum::KucoinSwap => {
+            //     kucoin_swap_handle::format_trade_items(&res_data)
+            // }
+            // ExchangeEnum::CoinsphSwap => {
+            //     coinsph_swap_handle::format_trade_items(&res_data)
+            // }
+            // ExchangeEnum::PhemexSwap => {
+            //     phemex_swap_handle::format_trade_items(&res_data)
+            // }
+            // ExchangeEnum::WooSwap => {
+            //     woo_swap_handle::format_trade_items(&res_data)
+            // }
+            // ExchangeEnum::CointrSwap => {
+            //     cointr_swap_handle::format_trade_items(&res_data)
+            // }
+            // _ => {
+            //     error!("未找到该交易所!trades_handle: {:?}", exchange);
+            //     panic!("未找到该交易所!trades_handle: {:?}", exchange);
+            // }
+        }
+    }
+    // 处理Ticker信息
+    pub fn book_ticker_handle(exchange: ExchangeEnum, _res_data: &ResponseData) -> Ticker {
+        match exchange {
+            _ => {
+                error!("未找到该交易所!book_ticker_handle: {:?}", exchange);
+                panic!("未找到该交易所!book_ticker_handle: {:?}", exchange);
+            }
+        }
+    }
+    // 处理蜡烛信息
+    pub fn records_handle(exchange: ExchangeEnum, res_data: &ResponseData) -> Vec<Record> {
+        match exchange {
+            ExchangeEnum::GateSwap => {
+                gate_swap_handle::handle_records(&res_data.data)
+            }
+            // ExchangeEnum::GateSpot => {
+            //     gate_spot_handle::handle_records(&res_data.data)
+            // }
+            // ExchangeEnum::BitgetSwap => {
+            //     bitget_swap_handle::handle_records(&res_data.data)
+            // }
+            ExchangeEnum::BinanceSwap => {
+                binance_swap_handle::handle_records(&res_data.data)
+            }
+            // ExchangeEnum::HtxSwap => {
+            //     htx_swap_handle::handle_records(&res_data.data)
+            // }
+            // ExchangeEnum::BingxSwap => {
+            //     bingx_swap_handle::handle_records(&res_data.data)
+            // }
+            // ExchangeEnum::MexcSwap => {
+            //     mexc_swap_handle::handle_records(&res_data.data)
+            // }
+            // ExchangeEnum::OkxSwap => {
+            //     okx_swap_handle::handle_records(&res_data.data)
+            // }
+            // ExchangeEnum::BitMartSwap => {
+            //     bitmart_swap_handle::handle_records(&res_data.data)
+            // }
+            // ExchangeEnum::KucoinSwap => {
+            //     kucoin_swap_handle::handle_records(&res_data.data)
+            // }
+            // ExchangeEnum::CoinsphSwap => {
+            //     coinsph_swap_handle::handle_records(&res_data.data)
+            // }
+            // ExchangeEnum::PhemexSwap => {
+            //     phemex_swap_handle::handle_records(&res_data.data)
+            // }
+            // ExchangeEnum::WooSwap => {
+            //     woo_swap_handle::handle_records(&res_data.data)
+            // }
+            // ExchangeEnum::CointrSwap => {
+            //     cointr_swap_handle::handle_records(&res_data.data)
+            // }
+            // _ => {
+            //     error!("未找到该交易所!records_handle: {:?}", exchange);
+            //     panic!("未找到该交易所!records_handle: {:?}", exchange);
+            // }
+        }
+    }
+    // 处理账号信息
+    pub fn account_info_handle(exchange: ExchangeEnum, res_data: &ResponseData, symbol: &String) -> Account {
+        match exchange {
+            ExchangeEnum::GateSwap => {
+                gate_swap_handle::handle_account_info(res_data, symbol)
+            }
+            // ExchangeEnum::BitgetSwap => {
+            //     bitget_swap_handle::handle_account_info(res_data, symbol)
+            // }
+            // ExchangeEnum::BybitSwap => {
+            //     bybit_swap_handle::handle_account_info(res_data, symbol)
+            // }
+            _ => {
+                error!("未找到该交易所!handle_account_info: {:?}", exchange);
+                panic!("未找到该交易所!handle_account_info: {:?}", exchange);
+            }
+        }
+    }
+    // 处理position信息
+    pub fn position_handle(exchange: ExchangeEnum, res_data: &ResponseData, ct_val: &Decimal) -> Vec<Position> {
+        match exchange {
+            ExchangeEnum::GateSwap => {
+                gate_swap_handle::handle_position(res_data, ct_val)
+            }
+            // ExchangeEnum::KucoinSwap => {
+            //     kucoin_swap_handle::handle_position(res_data, ct_val)
+            // }
+            // ExchangeEnum::BitgetSwap => {
+            //     bitget_swap_handle::handle_position(res_data, ct_val)
+            // }
+            // ExchangeEnum::BybitSwap => {
+            //     bybit_swap_handle::handle_position(res_data, ct_val)
+            // }
+            _ => {
+                error!("暂未提供此交易所方法!handle_position:{:?}", exchange);
+                panic!("暂未提供此交易所方法!handle_position:{:?}", exchange);
+            }
+        }
+    }
+    // 处理订单信息
+    pub fn order_handle(exchange: ExchangeEnum, res_data: &ResponseData, ct_val: Decimal) -> SpecialOrder {
+        match exchange {
+            ExchangeEnum::GateSwap => {
+                gate_swap_handle::handle_order(res_data, ct_val)
+            }
+            // ExchangeEnum::KucoinSwap => {
+            //     kucoin_swap_handle::handle_order(res_data, ct_val)
+            // }
+            // ExchangeEnum::BitgetSwap => {
+            //     bitget_swap_handle::handle_order(res_data, ct_val)
+            // }
+            // ExchangeEnum::BybitSwap => {
+            //     bybit_swap_handle::handle_order(res_data, ct_val)
+            // }
+            _ => {
+                error!("暂未提供此交易所方法!order_handle:{:?}", exchange);
+                panic!("暂未提供此交易所方法!order_handle:{:?}", exchange);
+            }
+        }
+    }
+}

+ 67 - 8
standard/src/gate_spot.rs

@@ -1,12 +1,15 @@
 // use std::collections::BTreeMap;
 // use std::io::{Error, ErrorKind};
+// use std::str::FromStr;
+// use tokio::sync::mpsc::Sender;
 // use async_trait::async_trait;
 // use rust_decimal::Decimal;
 // use rust_decimal_macros::dec;
-// use tracing::warn;
-// use crate::{Platform, ExchangeEnum, Account, Position, Ticker, Market, Order, OrderCommand};
+// use tracing::{error, warn};
+// use crate::{Platform, ExchangeEnum, Account, Position, Ticker, Market, Order};
 // use exchanges::gate_spot_rest::GateSpotRest;
-// use global::trace_stack::TraceStack;
+// use rust_decimal::prelude::FromPrimitive;
+// use serde_json::{json, Value};
 //
 // #[allow(dead_code)]
 // #[derive(Clone)]
@@ -16,17 +19,26 @@
 //     is_colo: bool,
 //     params: BTreeMap<String, String>,
 //     request: GateSpotRest,
+//     market: Market,
+//     order_sender: Sender<Order>,
+//     error_sender: Sender<Error>,
 // }
 //
 // impl GateSpot {
-//     pub fn new(symbol: String, is_colo: bool, params: BTreeMap<String, String>) -> GateSpot {
-//         GateSpot {
+//     pub async fn new(symbol: String, is_colo: bool, params: BTreeMap<String, String>, order_sender: Sender<Order>, error_sender: Sender<Error>) -> GateSpot {
+//         let market = Market::new();
+//         let mut gate_spot = GateSpot {
 //             exchange: ExchangeEnum::GateSpot,
 //             symbol: symbol.to_uppercase(),
 //             is_colo,
 //             params: params.clone(),
 //             request: GateSpotRest::new(is_colo, params.clone()),
-//         }
+//             market,
+//             order_sender,
+//             error_sender,
+//         };
+//         gate_spot.market = GateSpot::get_market(&mut gate_spot).await.unwrap_or(gate_spot.market);
+//         return gate_spot;
 //     }
 // }
 //
@@ -83,7 +95,52 @@
 //
 //     async fn get_ticker_symbol(&mut self, _symbol: String) -> Result<Ticker, Error> { Err(Error::new(ErrorKind::NotFound, "gate_spot:该交易所方法未实现".to_string())) }
 //
-//     async fn get_market(&mut self) -> Result<Market, Error> { Err(Error::new(ErrorKind::NotFound, "gate_spot:该交易所方法未实现".to_string())) }
+//     async fn get_market(&mut self) -> Result<Market, Error> {
+//         let params = json!({});
+//         let res_data = self.request.get_market_details(params).await;
+//         if res_data.code == 200 {
+//             let res_data_json = res_data.data.as_array().unwrap();
+//             let market_info = res_data_json.iter().find(|item| item["id"].as_str().unwrap() == self.symbol);
+//             match market_info {
+//                 None => {
+//                     error!("gate_swap:获取Market信息错误!\nget_market:res_data={:?}", res_data);
+//                     Err(Error::new(ErrorKind::Other, res_data.to_string()))
+//                 }
+//                 Some(value) => {
+//                     let symbol = value["id"].as_str().unwrap().to_string();
+//                     let base_asset = value["base"].as_str().unwrap().to_string();
+//                     let quote_asset = value["quote"].as_str().unwrap().to_string();
+//                     let tick_size = dec!(-1);
+//                     let amount_size = dec!(-1);
+//                     let price_precision = Decimal::from_f64(value["precision"].as_f64().unwrap()).unwrap();
+//                     let amount_precision = Decimal::from_f64(value["amount_precision"].as_f64().unwrap()).unwrap();
+//                     let min_qty = Decimal::from_str(value["min_base_amount"].as_str().unwrap()).unwrap();
+//                     let max_qty = Decimal::from_str(value["max_base_amount"].as_str().unwrap()).unwrap();
+//                     let min_notional = dec!(-1);
+//                     let max_notional = dec!(-1);
+//                     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)
+//                 }
+//             }
+//         } else {
+//             Err(Error::new(ErrorKind::Other, res_data.to_string()))
+//         }
+//     }
 //
 //     async fn get_market_symbol(&mut self, _symbol: String) -> Result<Market, Error> { Err(Error::new(ErrorKind::NotFound, "gate_spot:该交易所方法未实现".to_string())) }
 //
@@ -109,5 +166,7 @@
 //
 //     async fn wallet_transfers(&mut self, _coin: &str, _from: &str, _to: &str, _amount: Decimal) -> Result<String, Error> { Err(Error::new(ErrorKind::NotFound, "gate_spot:该交易所方法未实现".to_string())) }
 //
-//     async fn command_order(&mut self, _order_command: OrderCommand, _trace_stack: TraceStack) { warn!("gate_spot:该交易所方法未实现"); }
+//     async fn take_stop_loss_order(&mut self, _stop_price: Decimal, _price: Decimal, _side: &str) -> Result<Value, Error> { Err(Error::new(ErrorKind::NotFound, "gate_spot:该交易所方法未实现".to_string())) }
+//
+//     async fn cancel_stop_loss_order(&mut self, _order_id: &str) -> Result<Value, Error> { Err(Error::new(ErrorKind::NotFound, "gate_spot:该交易所方法未实现".to_string())) }
 // }

+ 45 - 0
standard/src/gate_spot_handle.rs

@@ -0,0 +1,45 @@
+use std::str::FromStr;
+use rust_decimal::Decimal;
+use serde_json::Value;
+use exchanges::response_base::ResponseData;
+use crate::{Trade, Record, OrderBook};
+
+pub fn handle_records(value: &Value) -> Vec<Record> {
+    let mut records = vec![];
+
+    let n = value["n"].as_str().unwrap().to_string();
+    let n_split: Vec<String> = n.split("_").map(|s| s.to_string()).collect();
+    let symbol = format!("{}_{}", n_split[n_split.len() - 2], n_split[n_split.len() - 1]);
+    records.push(Record {
+        time: Decimal::from_str(value["t"].as_str().unwrap()).unwrap() * Decimal::ONE_THOUSAND,
+        open: Decimal::from_str(value["o"].as_str().unwrap()).unwrap(),
+        high: Decimal::from_str(value["h"].as_str().unwrap()).unwrap(),
+        low: Decimal::from_str(value["l"].as_str().unwrap()).unwrap(),
+        close: Decimal::from_str(value["c"].as_str().unwrap()).unwrap(),
+        volume: Decimal::from_str(value["v"].as_str().unwrap()).unwrap(),
+        symbol,
+    });
+
+    return records;
+}
+pub fn format_depth_items(value: &Value) -> Vec<OrderBook> {
+    let mut depth_items: Vec<OrderBook> = vec![];
+    for value in value.as_array().unwrap() {
+        let info = value.as_array().unwrap();
+        depth_items.push(OrderBook {
+            price: Decimal::from_str(info[0].as_str().unwrap()).unwrap(),
+            amount: Decimal::from_str(info[1].as_str().unwrap()).unwrap(),
+        })
+    }
+    return depth_items;
+}
+pub fn format_trade_items(res_data: &ResponseData) -> Vec<Trade> {
+    return vec![Trade {
+        id: res_data.data["id"].to_string(),
+        time: Decimal::from_str(res_data.data["create_time_ms"].as_str().unwrap()).unwrap().floor(),
+        size: Decimal::from_str(res_data.data["amount"].as_str().unwrap()).unwrap(),
+        price: Decimal::from_str(res_data.data["price"].as_str().unwrap().to_string().as_str()).unwrap(),
+        symbol: res_data.data["currency_pair"].as_str().unwrap().to_string(),
+    }];
+}
+

+ 64 - 26
standard/src/gate_swap_handle.rs

@@ -1,13 +1,12 @@
 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};
+use crate::{Account, OrderBook, Order, Position, PositionModeEnum, SpecialOrder, Trade, Record};
 
 // 处理账号信息
 pub fn handle_account_info(res_data: &ResponseData, symbol: &String) -> Account {
@@ -80,7 +79,7 @@ pub fn format_position_item(position: &Value, ct_val: &Decimal) -> Position {
 }
 
 // 处理order信息
-pub fn handle_order(res_data: ResponseData, ct_val: Decimal) -> SpecialOrder {
+pub fn handle_order(res_data: &ResponseData, ct_val: Decimal) -> SpecialOrder {
     let res_data_json = res_data.data.as_array().unwrap();
     let mut order_info = Vec::new();
     for item in res_data_json.iter() {
@@ -88,7 +87,7 @@ pub fn handle_order(res_data: ResponseData, ct_val: Decimal) -> SpecialOrder {
     };
 
     SpecialOrder {
-        name: res_data.label,
+        name: res_data.label.clone(),
         order: order_info,
     }
 }
@@ -120,34 +119,73 @@ pub fn format_order_item(order: serde_json::Value, ct_val: Decimal) -> Order {
     return rst_order;
 }
 // 处理特殊Ticket信息
-pub fn handle_book_ticker(res_data: &ResponseData) -> SpecialDepth {
-    let bp = Decimal::from_str((*res_data).data["b"].as_str().unwrap_or("0")).unwrap();
-    let bq = Decimal::from_f64((*res_data).data["B"].as_f64().unwrap()).unwrap();
-    let ap = Decimal::from_str((*res_data).data["a"].as_str().unwrap_or("0")).unwrap();
-    let aq = Decimal::from_f64((*res_data).data["A"].as_f64().unwrap()).unwrap();
-    let mp = (bp + ap) * dec!(0.5);
-    let t = Decimal::from_u64((*res_data).data["u"].as_u64().unwrap()).unwrap();
-    let create_at = (*res_data).data["t"].as_i64().unwrap() * 1000;
-
-    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 handle_book_ticker(res_data: &ResponseData) -> SpecialDepth {
+//     let bp = Decimal::from_str((*res_data).data["b"].as_str().unwrap()).unwrap();
+//     let bq = Decimal::from_f64((*res_data).data["B"].as_f64().unwrap()).unwrap();
+//     let ap = Decimal::from_str((*res_data).data["a"].as_str().unwrap()).unwrap();
+//     let aq = Decimal::from_f64((*res_data).data["A"].as_f64().unwrap()).unwrap();
+//     let mp = (bp + ap) * dec!(0.5);
+//     let t = Decimal::from_u64((*res_data).data["u"].as_u64().unwrap()).unwrap();
+//     let create_at = (*res_data).data["t"].as_i64().unwrap() * 1000;
+//
+//     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).tag.clone(),
+//         depth: depth_info,
+//         ticker: ticker_info,
+//         t,
+//         create_at,
+//     }
+// }
+
+pub fn handle_records(value: &Value) -> Vec<Record> {
+    let mut records = vec![];
+
+    for record_value in value.as_array().unwrap() {
+        let n = record_value["n"].as_str().unwrap().to_string();
+        let n_split: Vec<String> = n.split("_").map(|s| s.to_string()).collect();
+        let symbol = format!("{}_{}", n_split[n_split.len() - 2], n_split[n_split.len() - 1]);
+
+        records.push(Record {
+            time: Decimal::from(record_value["t"].as_i64().unwrap()) * Decimal::ONE_THOUSAND,
+            open: Decimal::from_str(record_value["o"].as_str().unwrap()).unwrap(),
+            high: Decimal::from_str(record_value["h"].as_str().unwrap()).unwrap(),
+            low: Decimal::from_str(record_value["l"].as_str().unwrap()).unwrap(),
+            close: Decimal::from_str(record_value["c"].as_str().unwrap()).unwrap(),
+            volume: Decimal::from(record_value["v"].as_i64().unwrap()),
+            symbol,
+        });
     }
+
+    return records
 }
 
-pub fn format_depth_items(value: &Value) -> Vec<MarketOrder> {
-    let mut depth_items: Vec<MarketOrder> = vec![];
+pub fn format_depth_items(value: &Value) -> Vec<OrderBook> {
+    let mut depth_items: Vec<OrderBook> = vec![];
     for value in value.as_array().unwrap() {
-        depth_items.push(MarketOrder {
+        depth_items.push(OrderBook {
             price: Decimal::from_str(value["p"].as_str().unwrap()).unwrap(),
             amount: Decimal::from_f64(value["s"].as_f64().unwrap()).unwrap(),
         })
     }
     return depth_items;
-}
+}
+
+pub fn format_trade_items(res_data: &ResponseData) -> Vec<Trade> {
+    let result = res_data.data.as_array().unwrap();
+    let mut trades = vec![];
+
+    for item in result {
+        trades.push(Trade {
+            id: item["id"].to_string(),
+            time: Decimal::from_i64(item["create_time_ms"].as_i64().unwrap()).unwrap(),
+            size: Decimal::from_i64(item["size"].as_i64().unwrap()).unwrap(),
+            price: Decimal::from_str(item["price"].as_str().unwrap().to_string().as_str()).unwrap(),
+            symbol: item["contract"].as_str().unwrap().to_string(),
+        })
+    }
+
+    return trades
+}

+ 639 - 639
standard/src/htx_swap.rs

@@ -1,641 +1,641 @@
-use std::collections::{BTreeMap};
-use exchanges::htx_swap_rest::HtxSwapRest;
-use std::io::{Error, ErrorKind};
-use tokio::sync::mpsc::Sender;
-use std::str::FromStr;
-use async_trait::async_trait;
-use futures::stream::FuturesUnordered;
-use futures::TryStreamExt;
-use rust_decimal::Decimal;
-use rust_decimal::prelude::{FromPrimitive};
-use serde_json::json;
-use serde_json::Value::Null;
-use tokio::spawn;
-use tokio::time::Instant;
-use tracing::{error, info};
-use global::trace_stack::TraceStack;
-use crate::exchange::ExchangeEnum;
-use crate::{Account, Market, Order, OrderCommand, Platform, Position, PositionModeEnum, Ticker, utils};
-
-#[allow(dead_code)]
-#[derive(Clone)]
-pub struct HtxSwap {
-    exchange: ExchangeEnum,
-    symbol: String,
-    is_colo: bool,
-    params: BTreeMap<String, String>,
-    request: HtxSwapRest,
-    market: Market,
-    order_sender: Sender<Order>,
-    error_sender: Sender<Error>,
-}
-
-impl HtxSwap {
-    pub async fn new(symbol: String, is_colo: bool, params: BTreeMap<String, String>, order_sender: Sender<Order>, error_sender: Sender<Error>) -> HtxSwap {
-        let market = Market::new();
-        let mut htx_swap = HtxSwap {
-            exchange: ExchangeEnum::HtxSwap,
-            symbol: symbol.to_uppercase(),
-            is_colo,
-            params: params.clone(),
-            request: HtxSwapRest::new(is_colo, params.clone()),
-            market,
-            order_sender,
-            error_sender,
-        };
-        htx_swap.market = HtxSwap::get_market(&mut htx_swap).await.unwrap();
-        // 修改持仓模式
-        let mode_result = htx_swap.set_dual_mode("", true).await;
-        match mode_result {
-            Ok(ok) => {
-                info!("HtxSwap:设置持仓模式成功!{:?}", ok);
-            }
-            Err(error) => {
-                error!("HtxSwap:设置持仓模式失败!{:?}", error)
-            }
-        }
-        // 设置持仓杠杆
-        let lever_rate_result = htx_swap.set_dual_leverage("10").await;
-        match lever_rate_result {
-            Ok(ok) => {
-                info!("HtxSwap:设置持仓杠杆成功!{:?}", ok);
-            }
-            Err(error) => {
-                error!("HtxSwap:设置持仓杠杆失败!{:?}", error)
-            }
-        }
-
-        return htx_swap;
-    }
-}
-
-#[async_trait]
-impl Platform for HtxSwap {
-    fn clone_box(&self) -> Box<dyn Platform + Send + Sync> { Box::new(self.clone()) }
-
-    fn get_self_exchange(&self) -> ExchangeEnum { ExchangeEnum::HtxSwap }
-
-    fn get_self_symbol(&self) -> String { self.symbol.clone() }
-
-    fn get_self_is_colo(&self) -> bool { self.is_colo }
-
-    fn get_self_params(&self) -> BTreeMap<String, String> { self.params.clone() }
-
-    fn get_self_market(&self) -> Market { self.market.clone() }
-
-    fn get_request_delays(&self) -> Vec<i64> {
-        // self.request.get_delays()
-        vec![]
-    }
-
-    fn get_request_avg_delay(&self) -> Decimal {
-        // self.request.get_avg_delay()
-        Decimal::ZERO
-    }
-
-    fn get_request_max_delay(&self) -> i64 { 0 }
-
-    async fn get_server_time(&mut self) -> Result<String, Error> {
-        let response = self.request.get_server_time().await;
-        if response.code != 200 {
-            return Err(Error::new(ErrorKind::NotFound, format!("htx_swap 获取服务器时间异常{:?}", response).to_string()));
-        }
-
-        let res_data_json = response.data;
-        let result = res_data_json["ts"].to_string();
-        Ok(result)
-    }
-
-    async fn get_account(&mut self) -> Result<Account, Error> {
-        let params = json!({
-            "margin_account": "USDT"
-        });
-        let response = self.request.get_account(params).await;
-        if response.code != 200 {
-            return Err(Error::new(ErrorKind::NotFound, format!("htx_swap 获取账户信息异常{:?}", response).to_string()));
-        }
-
-        let res_data_json = response.data;
-        let mut account = Account::new();
-        for data in res_data_json.as_array().unwrap() {
-            let margin_position = Decimal::from_f64(data["margin_position"].as_f64().unwrap()).unwrap();
-
-            let balance = Decimal::from_f64(data["margin_static"].as_f64().unwrap()).unwrap();
-            let frozen_balance = Decimal::from_f64(data["margin_frozen"].as_f64().unwrap()).unwrap();
-            let available_balance = balance - margin_position - frozen_balance;
-            // 格式化account信息
-            account = Account {
-                coin: data["margin_asset"].as_str().unwrap().to_string(),
-                balance,
-                available_balance,
-                frozen_balance,
-                stocks: Default::default(),
-                available_stocks: Default::default(),
-                frozen_stocks: Default::default(),
-            };
-        }
-        return Ok(account);
-    }
-
-    async fn get_spot_account(&mut self) -> Result<Vec<Account>, Error> {
-        Err(Error::new(ErrorKind::NotFound, "htx_swap get_spot_account:该交易所方法未实现".to_string()))
-    }
-
-    async fn get_position(&mut self) -> Result<Vec<Position>, Error> {
-        let symbol_format = utils::format_symbol(self.symbol.clone(), "-");
-        let ct_val = self.market.ct_val;
-        let params = json!({
-            "contract_type": "swap",
-            "contract_code": symbol_format
-        });
-        let response = self.request.get_user_position(params).await;
-        if response.code != 200 {
-            return Err(Error::new(ErrorKind::NotFound, format!("htx_swap 获取仓位异常{:?}", response).to_string()));
-        }
-
-        let res_data_json = response.data;
-        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!({
-            "contract_type": "swap"
-        });
-        let response = self.request.get_user_position(params).await;
-
-        if response.code != 200 {
-            return Err(Error::new(ErrorKind::NotFound, format!("htx_swap 获取仓位异常{:?}", response).to_string()));
-        }
-
-        let res_data_json = response.data;
-        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> {
-        return 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(), "-");
-        let params = json!({
-            "contract_code": symbol_format,
-        });
-        let response = self.request.get_ticker(params).await;
-        if response.code != 200 {
-            return Err(Error::new(ErrorKind::NotFound, format!("htx_swap 获取行情信息异常{:?}", response).to_string()));
-        }
-
-        let res_data_json = response.data;
-        let ticker_info = res_data_json["tick"].clone();
-        let time = ticker_info["ts"].as_i64().unwrap();
-        let result = Ticker {
-            time,
-            high: Decimal::from_str(ticker_info["high"].as_str().unwrap()).unwrap(),
-            low: Decimal::from_str(ticker_info["low"].as_str().unwrap()).unwrap(),
-            sell: Decimal::from_f64(ticker_info["bid"][0].as_f64().unwrap()).unwrap(),
-            buy: Decimal::from_f64(ticker_info["ask"][0].as_f64().unwrap()).unwrap(),
-            last: Decimal::from_str(ticker_info["close"].as_str().unwrap()).unwrap(),
-            volume: Decimal::from_str(ticker_info["amount"].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(), "-");
-        let symbol_array: Vec<&str> = self.symbol.split("_").collect();
-
-        let params = json!({
-            "pair": symbol_format,
-            "contract_type":"swap"
-        });
-        let response = self.request.get_market(params).await;
-        if response.code != 200 {
-            return Err(Error::new(ErrorKind::NotFound, format!("htx_swap 获取市场信息异常{:?}", response).to_string()));
-        }
-        let res_data_json = response.data.as_array().unwrap();
-        let market_info = res_data_json[0].clone();
-
-        if !market_info["pair"].as_str().unwrap().to_string().eq(&symbol_format) {
-            return Err(Error::new(ErrorKind::NotFound, format!("符号未找到:symbol={}, response={:?}", symbol_format, response))).unwrap();
-        }
-
-        let base_asset = market_info["symbol"].as_str().unwrap().to_string();
-        let quote_asset = symbol_array[1].to_string();
-
-        let tick_size = Decimal::from_f64(market_info["price_tick"].as_f64().unwrap()).unwrap();
-        let price_precision = Decimal::from_u32(tick_size.scale()).unwrap();
-        let amount_size = Decimal::from_f64(market_info["contract_size"].as_f64().unwrap()).unwrap();
-        let amount_precision = Decimal::ZERO;
-        let min_qty = Decimal::NEGATIVE_ONE;
-        let max_qty = Decimal::NEGATIVE_ONE;
-        let ct_val = Decimal::from_f64(market_info["contract_size"].as_f64().unwrap()).unwrap();
-
-        let result = Market {
-            symbol: format!("{}_{}", base_asset, quote_asset),
-            base_asset,
-            quote_asset,
-            tick_size,
-            amount_size,
-            price_precision,
-            amount_precision,
-            min_qty,
-            max_qty,
-            min_notional: min_qty,
-            max_notional: max_qty,
-            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(), "-");
-        let ct_val = self.market.ct_val;
-
-        let mut params = json!({
-            "pair": symbol_format
-        });
-        if order_id.eq("") { params["client_order_id"] = json!(custom_id) } else { params["order_id"] = json!(order_id) };
-        let response = self.request.get_order_details(params).await;
-        if response.code != 200 || response.data == Null {
-            return Err(Error::new(ErrorKind::NotFound, format!("htx_swap 获取订单详情异常{:?}", response).to_string()));
-        }
-
-        let res_data_json = response.data;
-        let orders = res_data_json.as_array().unwrap();
-        let result = format_order_item(orders[0].clone(), ct_val);
-        Ok(result)
-    }
-
-    async fn get_orders_list(&mut self, _status: &str) -> Result<Vec<Order>, Error> {
-        Err(Error::new(ErrorKind::NotFound, "htx_swap get_orders_list:该交易所方法未实现".to_string()))
-    }
-
-    async fn take_order(&mut self, custom_id: &str, origin_side: &str, price: Decimal, amount: Decimal) -> Result<Order, Error> {
-        let ct_val = self.market.ct_val;
-
-        return self.take_order_symbol(self.symbol.clone(), 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, "-");
-        let final_size = (amount / ct_val).floor();
-        let mut params = json!({
-            "pair": symbol_format,
-            "client_order_id": custom_id,
-            "contract_type": "swap",
-            "volume": final_size.to_string(),
-            "lever_rate": 10
-        });
-        if price.eq(&Decimal::ZERO) {
-            params["order_price_type"] = json!("market");
-        } else {
-            params["price"] = json!(price.to_string());
-            params["order_price_type"] = json!("limit");
-        };
-        match origin_side {
-            "kd" => {
-                params["direction"] = json!("buy");
-                params["offset"] = json!("open");
-            }
-            "pd" => {
-                params["direction"] = json!("sell");
-                params["offset"] = json!("close");
-            }
-            "kk" => {
-                params["direction"] = json!("sell");
-                params["offset"] = json!("open");
-            }
-            "pk" => {
-                params["direction"] = json!("buy");
-                params["offset"] = json!("close");
-            }
-            _ => { panic!("htx_usdt_swap 下单参数错误"); }
-        };
-        let response = self.request.swap_order(params).await;
-        if response.code != 200 {
-            return Err(Error::new(ErrorKind::NotFound, format!("htx_swap 下单异常{:?}", response).to_string()));
-        }
-
-        let res_data_json = response.data;
-        let result = Order {
-            id: res_data_json["order_id"].to_string(),
-            custom_id: res_data_json["client_order_id"].to_string(),
-            price: Decimal::ZERO,
-            amount: Decimal::ZERO,
-            deal_amount: Decimal::ZERO,
-            avg_price: Decimal::ZERO,
-            status: "NEW".to_string(),
-            order_type: "".to_string(),
-            trace_stack: TraceStack::new(0, Instant::now()).on_special("339 htx_swap".to_string()),
-        };
-        return Ok(result);
-    }
-
-    async fn cancel_order(&mut self, order_id: &str, custom_id: &str) -> Result<Order, Error> {
-        let symbol_format = utils::format_symbol(self.symbol.clone(), "-");
-        let mut params = json!({
-            "pair": symbol_format,
-            "contract_type": "swap"
-        });
-        if order_id.eq("") { params["client_order_id"] = json!(custom_id) } else { params["order_id"] = json!(order_id) };
-        let response = self.request.cancel_order(params).await;
-
-        // 取消失败,进行报错
-        if response.code != 200 || response.data["errors"].as_array().unwrap_or(&vec![]).len() > 0 {
-            return Err(Error::new(ErrorKind::NotFound, format!("htx_swap 取消订单异常{:?}", response).to_string()));
-        }
-        let res_data_json = response.data;
-        let mut id = order_id.to_string();
-        let mut custom_id = custom_id.to_string();
-        if order_id.eq("") {
-            custom_id = res_data_json["successes"].as_str().unwrap().to_string()
-        } else {
-            id = res_data_json["successes"].as_str().unwrap().to_string()
-        };
-        let result = Order {
-            id,
-            custom_id,
-            price: Decimal::ZERO,
-            amount: Decimal::ZERO,
-            deal_amount: Decimal::ZERO,
-            avg_price: Decimal::ZERO,
-            status: "REMOVE".to_string(),
-            order_type: "".to_string(),
-            trace_stack: TraceStack::new(0, Instant::now()).on_special("374 htx_swap".to_string()),
-        };
-        Ok(result)
-    }
-
-    async fn cancel_orders(&mut self) -> Result<Vec<Order>, Error> {
-        Err(Error::new(ErrorKind::NotFound, "htx_swap cancel_orders:该交易所方法未实现".to_string()))
-    }
-
-    async fn cancel_orders_all(&mut self) -> Result<Vec<Order>, Error> {
-        let symbol_format = utils::format_symbol(self.symbol.clone(), "-");
-        let params = json!({
-            "pair": symbol_format,
-            "contract_type": "swap"
-        });
-        let response = self.request.cancel_price_order(params).await;
-        if response.code != 200 {
-            if response.data.to_string().contains("No cancellable orders") { return Ok(vec![]); }
-            return Err(Error::new(ErrorKind::NotFound, format!("htx_swap 撤销所有订单异常{:?}", response).to_string()));
-        }
-
-        Ok(vec![])
-    }
-
-    async fn take_stop_loss_order(&mut self, _stop_price: Decimal, _price: Decimal, _side: &str) -> Result<serde_json::Value, Error> {
-        Err(Error::new(ErrorKind::NotFound, "htx_swap take_stop_loss_order:该交易所方法未实现".to_string()))
-    }
-
-    async fn cancel_stop_loss_order(&mut self, _order_id: &str) -> Result<serde_json::Value, Error> {
-        Err(Error::new(ErrorKind::NotFound, "htx_swap cancel_stop_loss_order:该交易所方法未实现".to_string()))
-    }
-
-    async fn set_dual_mode(&mut self, _coin: &str, is_dual_mode: bool) -> Result<String, Error> {
-        let pos_mode = if is_dual_mode { "dual_side" } else { "single_side" };
-        let params = json!({
-            "margin_account": "USDT",
-            "position_mode": pos_mode,
-        });
-        let response = self.request.setting_dual_mode(params).await;
-        if response.code != 200 {
-            return Err(Error::new(ErrorKind::Other, format!("设置持仓模式失败:{:?}", response).to_string()));
-        }
-
-        return Ok(response.data.to_string());
-    }
-
-    async fn set_dual_leverage(&mut self, leverage: &str) -> Result<String, Error> {
-        let symbol_format = utils::format_symbol(self.symbol.clone(), "-");
-        let params = json!({
-            "pair": symbol_format,
-            "contract_type": "swap",
-            "lever_rate": leverage
-        });
-        let response = self.request.setting_dual_leverage(params).await;
-
-        if response.code != 200 {
-            return Err(Error::new(ErrorKind::Other, format!("设置杠杆失败:{:?}", response).to_string()));
-        }
-
-        return Ok(response.data.to_string());
-    }
-
-    async fn set_auto_deposit_status(&mut self, _status: bool) -> Result<String, Error> {
-        Err(Error::new(ErrorKind::NotFound, "htx_swap set_auto_deposit_status:该交易所方法未实现".to_string()))
-    }
-
-    async fn wallet_transfers(&mut self, _coin: &str, _from: &str, _to: &str, _amount: Decimal) -> Result<String, Error> {
-        Err(Error::new(ErrorKind::NotFound, "htx_swap 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 {
-                // TraceStack::show_delay(&ts.ins);
-                ts.on_before_send();
-                let result = self_clone.take_order(cid.as_str(), side.as_str(), price, amount).await;
-                ts.on_after_send();
-                // info!("下单 custom_id {}", cid);
-                match result {
-                    Ok(mut result) => {
-                        result.trace_stack = ts;
-                        // info!("下单完成 order_id {}", result.id);
-                        self_clone.order_sender.send(result).await.unwrap();
-                    }
-                    Err(error) => {
-                        info!(?error);
-                        let mut err_order = Order::new();
-                        err_order.custom_id = cid.clone();
-                        err_order.status = "REMOVE".to_string();
-                        ts.source = "htx_swap 474".to_string();
-                        err_order.trace_stack = ts;
-
-                        self_clone.order_sender.send(err_order).await.unwrap();
-                        self_clone.error_sender.send(error).await.unwrap();
-                    }
-                }
-            });
-            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();
-            // info!("取消订单 order_id {}, custom_id {}", order_id, custom_id);
-            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(_) => {
-                        // result_sd.send(result).await.unwrap();
-                    }
-                    Err(error) => {
-                        // 已经取消的订单不去撤单了
-                        if !error.to_string().contains("Your order has been canceled") {
-                            // 取消失败去查订单。
-                            let query_rst = self_clone.get_order_detail(&order_id, &custom_id).await;
-                            match query_rst {
-                                Ok(order) => {
-                                    self_clone.order_sender.send(order).await.unwrap();
-                                }
-                                Err(err) => {
-                                    error!("撤单失败,而且查单也失败了,htx_swap,oid={}, cid={}, err={:?}。", order_id.clone(), custom_id.clone(), err);
-                                }
-                            }
-                            error!("撤单失败,异常:{}", error);
-                            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.as_str(), custom_id.as_str()).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_account_info(balance_data: Value) -> Account {
-//     let balance_coin = balance_data["coin"].as_str().unwrap().to_string().to_uppercase();
-//     let available_balance = Decimal::from_str(balance_data["available"].as_str().unwrap()).unwrap();
-//     let frozen_balance = Decimal::from_str(balance_data["frozen"].as_str().unwrap()).unwrap();
-//     let balance = available_balance + frozen_balance;
-//
-//     Account {
-//         coin: balance_coin,
-//         balance,
-//         available_balance,
-//         frozen_balance,
-//         stocks: Decimal::ZERO,
-//         available_stocks: Decimal::ZERO,
-//         frozen_stocks: Decimal::ZERO,
+// use std::collections::{BTreeMap};
+// use exchanges::htx_swap_rest::HtxSwapRest;
+// use std::io::{Error, ErrorKind};
+// use tokio::sync::mpsc::Sender;
+// use std::str::FromStr;
+// use async_trait::async_trait;
+// use futures::stream::FuturesUnordered;
+// use futures::TryStreamExt;
+// use rust_decimal::Decimal;
+// use rust_decimal::prelude::{FromPrimitive};
+// use serde_json::json;
+// use serde_json::Value::Null;
+// use tokio::spawn;
+// use tokio::time::Instant;
+// use tracing::{error, info};
+// use global::trace_stack::TraceStack;
+// use crate::exchange::ExchangeEnum;
+// use crate::{Account, Market, Order, OrderCommand, Platform, Position, PositionModeEnum, Ticker, utils};
+//
+// #[allow(dead_code)]
+// #[derive(Clone)]
+// pub struct HtxSwap {
+//     exchange: ExchangeEnum,
+//     symbol: String,
+//     is_colo: bool,
+//     params: BTreeMap<String, String>,
+//     request: HtxSwapRest,
+//     market: Market,
+//     order_sender: Sender<Order>,
+//     error_sender: Sender<Error>,
+// }
+//
+// impl HtxSwap {
+//     pub async fn new(symbol: String, is_colo: bool, params: BTreeMap<String, String>, order_sender: Sender<Order>, error_sender: Sender<Error>) -> HtxSwap {
+//         let market = Market::new();
+//         let mut htx_swap = HtxSwap {
+//             exchange: ExchangeEnum::HtxSwap,
+//             symbol: symbol.to_uppercase(),
+//             is_colo,
+//             params: params.clone(),
+//             request: HtxSwapRest::new(is_colo, params.clone()),
+//             market,
+//             order_sender,
+//             error_sender,
+//         };
+//         htx_swap.market = HtxSwap::get_market(&mut htx_swap).await.unwrap();
+//         // 修改持仓模式
+//         let mode_result = htx_swap.set_dual_mode("", true).await;
+//         match mode_result {
+//             Ok(ok) => {
+//                 info!("HtxSwap:设置持仓模式成功!{:?}", ok);
+//             }
+//             Err(error) => {
+//                 error!("HtxSwap:设置持仓模式失败!{:?}", error)
+//             }
+//         }
+//         // 设置持仓杠杆
+//         let lever_rate_result = htx_swap.set_dual_leverage("10").await;
+//         match lever_rate_result {
+//             Ok(ok) => {
+//                 info!("HtxSwap:设置持仓杠杆成功!{:?}", ok);
+//             }
+//             Err(error) => {
+//                 error!("HtxSwap:设置持仓杠杆失败!{:?}", error)
+//             }
+//         }
+//
+//         return htx_swap;
+//     }
+// }
+//
+// #[async_trait]
+// impl Platform for HtxSwap {
+//     fn clone_box(&self) -> Box<dyn Platform + Send + Sync> { Box::new(self.clone()) }
+//
+//     fn get_self_exchange(&self) -> ExchangeEnum { ExchangeEnum::HtxSwap }
+//
+//     fn get_self_symbol(&self) -> String { self.symbol.clone() }
+//
+//     fn get_self_is_colo(&self) -> bool { self.is_colo }
+//
+//     fn get_self_params(&self) -> BTreeMap<String, String> { self.params.clone() }
+//
+//     fn get_self_market(&self) -> Market { self.market.clone() }
+//
+//     fn get_request_delays(&self) -> Vec<i64> {
+//         // self.request.get_delays()
+//         vec![]
+//     }
+//
+//     fn get_request_avg_delay(&self) -> Decimal {
+//         // self.request.get_avg_delay()
+//         Decimal::ZERO
+//     }
+//
+//     fn get_request_max_delay(&self) -> i64 { 0 }
+//
+//     async fn get_server_time(&mut self) -> Result<String, Error> {
+//         let response = self.request.get_server_time().await;
+//         if response.code != 200 {
+//             return Err(Error::new(ErrorKind::NotFound, format!("htx_swap 获取服务器时间异常{:?}", response).to_string()));
+//         }
+//
+//         let res_data_json = response.data;
+//         let result = res_data_json["ts"].to_string();
+//         Ok(result)
+//     }
+//
+//     async fn get_account(&mut self) -> Result<Account, Error> {
+//         let params = json!({
+//             "margin_account": "USDT"
+//         });
+//         let response = self.request.get_account(params).await;
+//         if response.code != 200 {
+//             return Err(Error::new(ErrorKind::NotFound, format!("htx_swap 获取账户信息异常{:?}", response).to_string()));
+//         }
+//
+//         let res_data_json = response.data;
+//         let mut account = Account::new();
+//         for data in res_data_json.as_array().unwrap() {
+//             let margin_position = Decimal::from_f64(data["margin_position"].as_f64().unwrap()).unwrap();
+//
+//             let balance = Decimal::from_f64(data["margin_static"].as_f64().unwrap()).unwrap();
+//             let frozen_balance = Decimal::from_f64(data["margin_frozen"].as_f64().unwrap()).unwrap();
+//             let available_balance = balance - margin_position - frozen_balance;
+//             // 格式化account信息
+//             account = Account {
+//                 coin: data["margin_asset"].as_str().unwrap().to_string(),
+//                 balance,
+//                 available_balance,
+//                 frozen_balance,
+//                 stocks: Default::default(),
+//                 available_stocks: Default::default(),
+//                 frozen_stocks: Default::default(),
+//             };
+//         }
+//         return Ok(account);
+//     }
+//
+//     async fn get_spot_account(&mut self) -> Result<Vec<Account>, Error> {
+//         Err(Error::new(ErrorKind::NotFound, "htx_swap get_spot_account:该交易所方法未实现".to_string()))
+//     }
+//
+//     async fn get_position(&mut self) -> Result<Vec<Position>, Error> {
+//         let symbol_format = utils::format_symbol(self.symbol.clone(), "-");
+//         let ct_val = self.market.ct_val;
+//         let params = json!({
+//             "contract_type": "swap",
+//             "contract_code": symbol_format
+//         });
+//         let response = self.request.get_user_position(params).await;
+//         if response.code != 200 {
+//             return Err(Error::new(ErrorKind::NotFound, format!("htx_swap 获取仓位异常{:?}", response).to_string()));
+//         }
+//
+//         let res_data_json = response.data;
+//         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!({
+//             "contract_type": "swap"
+//         });
+//         let response = self.request.get_user_position(params).await;
+//
+//         if response.code != 200 {
+//             return Err(Error::new(ErrorKind::NotFound, format!("htx_swap 获取仓位异常{:?}", response).to_string()));
+//         }
+//
+//         let res_data_json = response.data;
+//         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> {
+//         return 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(), "-");
+//         let params = json!({
+//             "contract_code": symbol_format,
+//         });
+//         let response = self.request.get_ticker(params).await;
+//         if response.code != 200 {
+//             return Err(Error::new(ErrorKind::NotFound, format!("htx_swap 获取行情信息异常{:?}", response).to_string()));
+//         }
+//
+//         let res_data_json = response.data;
+//         let ticker_info = res_data_json["tick"].clone();
+//         let time = ticker_info["ts"].as_i64().unwrap();
+//         let result = Ticker {
+//             time,
+//             high: Decimal::from_str(ticker_info["high"].as_str().unwrap()).unwrap(),
+//             low: Decimal::from_str(ticker_info["low"].as_str().unwrap()).unwrap(),
+//             sell: Decimal::from_f64(ticker_info["bid"][0].as_f64().unwrap()).unwrap(),
+//             buy: Decimal::from_f64(ticker_info["ask"][0].as_f64().unwrap()).unwrap(),
+//             last: Decimal::from_str(ticker_info["close"].as_str().unwrap()).unwrap(),
+//             volume: Decimal::from_str(ticker_info["amount"].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(), "-");
+//         let symbol_array: Vec<&str> = self.symbol.split("_").collect();
+//
+//         let params = json!({
+//             "pair": symbol_format,
+//             "contract_type":"swap"
+//         });
+//         let response = self.request.get_market(params).await;
+//         if response.code != 200 {
+//             return Err(Error::new(ErrorKind::NotFound, format!("htx_swap 获取市场信息异常{:?}", response).to_string()));
+//         }
+//         let res_data_json = response.data.as_array().unwrap();
+//         let market_info = res_data_json[0].clone();
+//
+//         if !market_info["pair"].as_str().unwrap().to_string().eq(&symbol_format) {
+//             return Err(Error::new(ErrorKind::NotFound, format!("符号未找到:symbol={}, response={:?}", symbol_format, response))).unwrap();
+//         }
+//
+//         let base_asset = market_info["symbol"].as_str().unwrap().to_string();
+//         let quote_asset = symbol_array[1].to_string();
+//
+//         let tick_size = Decimal::from_f64(market_info["price_tick"].as_f64().unwrap()).unwrap();
+//         let price_precision = Decimal::from_u32(tick_size.scale()).unwrap();
+//         let amount_size = Decimal::from_f64(market_info["contract_size"].as_f64().unwrap()).unwrap();
+//         let amount_precision = Decimal::ZERO;
+//         let min_qty = Decimal::NEGATIVE_ONE;
+//         let max_qty = Decimal::NEGATIVE_ONE;
+//         let ct_val = Decimal::from_f64(market_info["contract_size"].as_f64().unwrap()).unwrap();
+//
+//         let result = Market {
+//             symbol: format!("{}_{}", base_asset, quote_asset),
+//             base_asset,
+//             quote_asset,
+//             tick_size,
+//             amount_size,
+//             price_precision,
+//             amount_precision,
+//             min_qty,
+//             max_qty,
+//             min_notional: min_qty,
+//             max_notional: max_qty,
+//             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(), "-");
+//         let ct_val = self.market.ct_val;
+//
+//         let mut params = json!({
+//             "pair": symbol_format
+//         });
+//         if order_id.eq("") { params["client_order_id"] = json!(custom_id) } else { params["order_id"] = json!(order_id) };
+//         let response = self.request.get_order_details(params).await;
+//         if response.code != 200 || response.data == Null {
+//             return Err(Error::new(ErrorKind::NotFound, format!("htx_swap 获取订单详情异常{:?}", response).to_string()));
+//         }
+//
+//         let res_data_json = response.data;
+//         let orders = res_data_json.as_array().unwrap();
+//         let result = format_order_item(orders[0].clone(), ct_val);
+//         Ok(result)
+//     }
+//
+//     async fn get_orders_list(&mut self, _status: &str) -> Result<Vec<Order>, Error> {
+//         Err(Error::new(ErrorKind::NotFound, "htx_swap get_orders_list:该交易所方法未实现".to_string()))
+//     }
+//
+//     async fn take_order(&mut self, custom_id: &str, origin_side: &str, price: Decimal, amount: Decimal) -> Result<Order, Error> {
+//         let ct_val = self.market.ct_val;
+//
+//         return self.take_order_symbol(self.symbol.clone(), 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, "-");
+//         let final_size = (amount / ct_val).floor();
+//         let mut params = json!({
+//             "pair": symbol_format,
+//             "client_order_id": custom_id,
+//             "contract_type": "swap",
+//             "volume": final_size.to_string(),
+//             "lever_rate": 10
+//         });
+//         if price.eq(&Decimal::ZERO) {
+//             params["order_price_type"] = json!("market");
+//         } else {
+//             params["price"] = json!(price.to_string());
+//             params["order_price_type"] = json!("limit");
+//         };
+//         match origin_side {
+//             "kd" => {
+//                 params["direction"] = json!("buy");
+//                 params["offset"] = json!("open");
+//             }
+//             "pd" => {
+//                 params["direction"] = json!("sell");
+//                 params["offset"] = json!("close");
+//             }
+//             "kk" => {
+//                 params["direction"] = json!("sell");
+//                 params["offset"] = json!("open");
+//             }
+//             "pk" => {
+//                 params["direction"] = json!("buy");
+//                 params["offset"] = json!("close");
+//             }
+//             _ => { panic!("htx_usdt_swap 下单参数错误"); }
+//         };
+//         let response = self.request.swap_order(params).await;
+//         if response.code != 200 {
+//             return Err(Error::new(ErrorKind::NotFound, format!("htx_swap 下单异常{:?}", response).to_string()));
+//         }
+//
+//         let res_data_json = response.data;
+//         let result = Order {
+//             id: res_data_json["order_id"].to_string(),
+//             custom_id: res_data_json["client_order_id"].to_string(),
+//             price: Decimal::ZERO,
+//             amount: Decimal::ZERO,
+//             deal_amount: Decimal::ZERO,
+//             avg_price: Decimal::ZERO,
+//             status: "NEW".to_string(),
+//             order_type: "".to_string(),
+//             trace_stack: TraceStack::new(0, Instant::now()).on_special("339 htx_swap".to_string()),
+//         };
+//         return Ok(result);
+//     }
+//
+//     async fn cancel_order(&mut self, order_id: &str, custom_id: &str) -> Result<Order, Error> {
+//         let symbol_format = utils::format_symbol(self.symbol.clone(), "-");
+//         let mut params = json!({
+//             "pair": symbol_format,
+//             "contract_type": "swap"
+//         });
+//         if order_id.eq("") { params["client_order_id"] = json!(custom_id) } else { params["order_id"] = json!(order_id) };
+//         let response = self.request.cancel_order(params).await;
+//
+//         // 取消失败,进行报错
+//         if response.code != 200 || response.data["errors"].as_array().unwrap_or(&vec![]).len() > 0 {
+//             return Err(Error::new(ErrorKind::NotFound, format!("htx_swap 取消订单异常{:?}", response).to_string()));
+//         }
+//         let res_data_json = response.data;
+//         let mut id = order_id.to_string();
+//         let mut custom_id = custom_id.to_string();
+//         if order_id.eq("") {
+//             custom_id = res_data_json["successes"].as_str().unwrap().to_string()
+//         } else {
+//             id = res_data_json["successes"].as_str().unwrap().to_string()
+//         };
+//         let result = Order {
+//             id,
+//             custom_id,
+//             price: Decimal::ZERO,
+//             amount: Decimal::ZERO,
+//             deal_amount: Decimal::ZERO,
+//             avg_price: Decimal::ZERO,
+//             status: "REMOVE".to_string(),
+//             order_type: "".to_string(),
+//             trace_stack: TraceStack::new(0, Instant::now()).on_special("374 htx_swap".to_string()),
+//         };
+//         Ok(result)
+//     }
+//
+//     async fn cancel_orders(&mut self) -> Result<Vec<Order>, Error> {
+//         Err(Error::new(ErrorKind::NotFound, "htx_swap cancel_orders:该交易所方法未实现".to_string()))
+//     }
+//
+//     async fn cancel_orders_all(&mut self) -> Result<Vec<Order>, Error> {
+//         let symbol_format = utils::format_symbol(self.symbol.clone(), "-");
+//         let params = json!({
+//             "pair": symbol_format,
+//             "contract_type": "swap"
+//         });
+//         let response = self.request.cancel_price_order(params).await;
+//         if response.code != 200 {
+//             if response.data.to_string().contains("No cancellable orders") { return Ok(vec![]); }
+//             return Err(Error::new(ErrorKind::NotFound, format!("htx_swap 撤销所有订单异常{:?}", response).to_string()));
+//         }
+//
+//         Ok(vec![])
+//     }
+//
+//     async fn take_stop_loss_order(&mut self, _stop_price: Decimal, _price: Decimal, _side: &str) -> Result<serde_json::Value, Error> {
+//         Err(Error::new(ErrorKind::NotFound, "htx_swap take_stop_loss_order:该交易所方法未实现".to_string()))
+//     }
+//
+//     async fn cancel_stop_loss_order(&mut self, _order_id: &str) -> Result<serde_json::Value, Error> {
+//         Err(Error::new(ErrorKind::NotFound, "htx_swap cancel_stop_loss_order:该交易所方法未实现".to_string()))
+//     }
+//
+//     async fn set_dual_mode(&mut self, _coin: &str, is_dual_mode: bool) -> Result<String, Error> {
+//         let pos_mode = if is_dual_mode { "dual_side" } else { "single_side" };
+//         let params = json!({
+//             "margin_account": "USDT",
+//             "position_mode": pos_mode,
+//         });
+//         let response = self.request.setting_dual_mode(params).await;
+//         if response.code != 200 {
+//             return Err(Error::new(ErrorKind::Other, format!("设置持仓模式失败:{:?}", response).to_string()));
+//         }
+//
+//         return Ok(response.data.to_string());
+//     }
+//
+//     async fn set_dual_leverage(&mut self, leverage: &str) -> Result<String, Error> {
+//         let symbol_format = utils::format_symbol(self.symbol.clone(), "-");
+//         let params = json!({
+//             "pair": symbol_format,
+//             "contract_type": "swap",
+//             "lever_rate": leverage
+//         });
+//         let response = self.request.setting_dual_leverage(params).await;
+//
+//         if response.code != 200 {
+//             return Err(Error::new(ErrorKind::Other, format!("设置杠杆失败:{:?}", response).to_string()));
+//         }
+//
+//         return Ok(response.data.to_string());
+//     }
+//
+//     async fn set_auto_deposit_status(&mut self, _status: bool) -> Result<String, Error> {
+//         Err(Error::new(ErrorKind::NotFound, "htx_swap set_auto_deposit_status:该交易所方法未实现".to_string()))
+//     }
+//
+//     async fn wallet_transfers(&mut self, _coin: &str, _from: &str, _to: &str, _amount: Decimal) -> Result<String, Error> {
+//         Err(Error::new(ErrorKind::NotFound, "htx_swap 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 {
+//                 // TraceStack::show_delay(&ts.ins);
+//                 ts.on_before_send();
+//                 let result = self_clone.take_order(cid.as_str(), side.as_str(), price, amount).await;
+//                 ts.on_after_send();
+//                 // info!("下单 custom_id {}", cid);
+//                 match result {
+//                     Ok(mut result) => {
+//                         result.trace_stack = ts;
+//                         // info!("下单完成 order_id {}", result.id);
+//                         self_clone.order_sender.send(result).await.unwrap();
+//                     }
+//                     Err(error) => {
+//                         info!(?error);
+//                         let mut err_order = Order::new();
+//                         err_order.custom_id = cid.clone();
+//                         err_order.status = "REMOVE".to_string();
+//                         ts.source = "htx_swap 474".to_string();
+//                         err_order.trace_stack = ts;
+//
+//                         self_clone.order_sender.send(err_order).await.unwrap();
+//                         self_clone.error_sender.send(error).await.unwrap();
+//                     }
+//                 }
+//             });
+//             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();
+//             // info!("取消订单 order_id {}, custom_id {}", order_id, custom_id);
+//             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(_) => {
+//                         // result_sd.send(result).await.unwrap();
+//                     }
+//                     Err(error) => {
+//                         // 已经取消的订单不去撤单了
+//                         if !error.to_string().contains("Your order has been canceled") {
+//                             // 取消失败去查订单。
+//                             let query_rst = self_clone.get_order_detail(&order_id, &custom_id).await;
+//                             match query_rst {
+//                                 Ok(order) => {
+//                                     self_clone.order_sender.send(order).await.unwrap();
+//                                 }
+//                                 Err(err) => {
+//                                     error!("撤单失败,而且查单也失败了,htx_swap,oid={}, cid={}, err={:?}。", order_id.clone(), custom_id.clone(), err);
+//                                 }
+//                             }
+//                             error!("撤单失败,异常:{}", error);
+//                             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.as_str(), custom_id.as_str()).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_account_info(balance_data: Value) -> Account {
+// //     let balance_coin = balance_data["coin"].as_str().unwrap().to_string().to_uppercase();
+// //     let available_balance = Decimal::from_str(balance_data["available"].as_str().unwrap()).unwrap();
+// //     let frozen_balance = Decimal::from_str(balance_data["frozen"].as_str().unwrap()).unwrap();
+// //     let balance = available_balance + frozen_balance;
+// //
+// //     Account {
+// //         coin: balance_coin,
+// //         balance,
+// //         available_balance,
+// //         frozen_balance,
+// //         stocks: Decimal::ZERO,
+// //         available_stocks: Decimal::ZERO,
+// //         frozen_stocks: Decimal::ZERO,
+// //     }
+// // }
+//
+// pub fn format_order_item(order: serde_json::Value, ct_val: Decimal) -> Order {
+//     let id = order["order_id"].to_string();
+//     let custom_id = order["client_order_id"].to_string();
+//     let price = Decimal::from_f64(order["price"].as_f64().unwrap()).unwrap();
+//     let amount = Decimal::from_f64(order["volume"].as_f64().unwrap()).unwrap() * ct_val;
+//     let deal_amount = Decimal::from_f64(order["trade_volume"].as_f64().unwrap()).unwrap() * ct_val;
+//     let avg_price = Decimal::from_f64(order["trade_avg_price"].as_f64().unwrap_or(0.0)).unwrap();
+//
+//     let status = order["status"].to_string();
+//
+//     let custom_status = if ["5", "6", "7"].contains(&&**&status) {
+//         "REMOVE".to_string()
+//     } else if ["1", "2", "3", "4"].contains(&&**&status) {
+//         "NEW".to_string()
+//     } else {
+//         "NULL".to_string()
+//     };
+//     Order {
+//         id,
+//         custom_id,
+//         price,
+//         amount,
+//         deal_amount,
+//         avg_price,
+//         status: custom_status,
+//         order_type: order["order_price_type"].as_str().unwrap().to_string(),
+//         trace_stack: TraceStack::new(0, Instant::now()).on_special("630 htx_swap".to_string()),
+//     }
+// }
+//
+// pub fn format_position_item(position: &serde_json::Value, ct_val: &Decimal) -> Position {
+//     let symbol = position["pair"].as_str().unwrap().to_string();
+//     let margin_level = Decimal::from_str(&position["lever_rate"].to_string()).unwrap();
+//     let amount = Decimal::from_f64(position["volume"].as_f64().unwrap()).unwrap() * ct_val;
+//
+//     let frozen_amount = Decimal::from_f64(position["frozen"].as_f64().unwrap()).unwrap();
+//     let price = Decimal::from_f64(position["cost_hold"].as_f64().unwrap()).unwrap();
+//     let profit = Decimal::from_f64(position["profit_unreal"].as_f64().unwrap()).unwrap();
+//     let position_mode = match position["position_mode"].as_str().unwrap() {
+//         "dual_side" => {
+//             match position["direction"].as_str().unwrap() {
+//                 "sell" => {
+//                     PositionModeEnum::Short
+//                 }
+//                 "buy" => {
+//                     PositionModeEnum::Long
+//                 }
+//                 _ => {
+//                     panic!("htx_usdt_swap: 未知的持仓模式与持仓方向: {}, {}",
+//                            position["direction"].as_str().unwrap(), position["direction"].as_str().unwrap())
+//                 }
+//             }
+//         }
+//         "single_side" => {
+//             PositionModeEnum::Both
+//         }
+//         _ => {
+//             panic!("htx_usdt_swap: 未知的持仓模式: {}", position["position_mode"].as_str().unwrap())
+//         }
+//     };
+//     let margin = Decimal::from_f64(position["position_margin"].as_f64().unwrap()).unwrap();
+//
+//     Position {
+//         symbol,
+//         margin_level,
+//         amount,
+//         frozen_amount,
+//         price,
+//         profit,
+//         position_mode,
+//         margin,
 //     }
 // }
-
-pub fn format_order_item(order: serde_json::Value, ct_val: Decimal) -> Order {
-    let id = order["order_id"].to_string();
-    let custom_id = order["client_order_id"].to_string();
-    let price = Decimal::from_f64(order["price"].as_f64().unwrap()).unwrap();
-    let amount = Decimal::from_f64(order["volume"].as_f64().unwrap()).unwrap() * ct_val;
-    let deal_amount = Decimal::from_f64(order["trade_volume"].as_f64().unwrap()).unwrap() * ct_val;
-    let avg_price = Decimal::from_f64(order["trade_avg_price"].as_f64().unwrap_or(0.0)).unwrap();
-
-    let status = order["status"].to_string();
-
-    let custom_status = if ["5", "6", "7"].contains(&&**&status) {
-        "REMOVE".to_string()
-    } else if ["1", "2", "3", "4"].contains(&&**&status) {
-        "NEW".to_string()
-    } else {
-        "NULL".to_string()
-    };
-    Order {
-        id,
-        custom_id,
-        price,
-        amount,
-        deal_amount,
-        avg_price,
-        status: custom_status,
-        order_type: order["order_price_type"].as_str().unwrap().to_string(),
-        trace_stack: TraceStack::new(0, Instant::now()).on_special("630 htx_swap".to_string()),
-    }
-}
-
-pub fn format_position_item(position: &serde_json::Value, ct_val: &Decimal) -> Position {
-    let symbol = position["pair"].as_str().unwrap().to_string();
-    let margin_level = Decimal::from_str(&position["lever_rate"].to_string()).unwrap();
-    let amount = Decimal::from_f64(position["volume"].as_f64().unwrap()).unwrap() * ct_val;
-
-    let frozen_amount = Decimal::from_f64(position["frozen"].as_f64().unwrap()).unwrap();
-    let price = Decimal::from_f64(position["cost_hold"].as_f64().unwrap()).unwrap();
-    let profit = Decimal::from_f64(position["profit_unreal"].as_f64().unwrap()).unwrap();
-    let position_mode = match position["position_mode"].as_str().unwrap() {
-        "dual_side" => {
-            match position["direction"].as_str().unwrap() {
-                "sell" => {
-                    PositionModeEnum::Short
-                }
-                "buy" => {
-                    PositionModeEnum::Long
-                }
-                _ => {
-                    panic!("htx_usdt_swap: 未知的持仓模式与持仓方向: {}, {}",
-                           position["direction"].as_str().unwrap(), position["direction"].as_str().unwrap())
-                }
-            }
-        }
-        "single_side" => {
-            PositionModeEnum::Both
-        }
-        _ => {
-            panic!("htx_usdt_swap: 未知的持仓模式: {}", position["position_mode"].as_str().unwrap())
-        }
-    };
-    let margin = Decimal::from_f64(position["position_margin"].as_f64().unwrap()).unwrap();
-
-    Position {
-        symbol,
-        margin_level,
-        amount,
-        frozen_amount,
-        price,
-        profit,
-        position_mode,
-        margin,
-    }
-}

+ 182 - 135
standard/src/htx_swap_handle.rs

@@ -1,135 +1,182 @@
-use std::str::FromStr;
-use rust_decimal::Decimal;
-use rust_decimal::prelude::FromPrimitive;
-use tokio::time::Instant;
-use exchanges::response_base::ResponseData;
-use global::trace_stack::TraceStack;
-use crate::{Account, MarketOrder, Order, Position, PositionModeEnum, SpecialOrder};
-
-// 处理账号信息
-pub fn handle_account_info(response: &ResponseData, _symbol: &String) -> Account {
-    let mut result = Account::new();
-    let account_infos = response.data.as_array().unwrap();
-    for data in account_infos {
-        if data["margin_asset"].as_str().unwrap() != "USDT" { continue; }
-        let margin_position = Decimal::from_f64(data["margin_position"].as_f64().unwrap()).unwrap();
-        let balance = Decimal::from_f64(data["margin_static"].as_f64().unwrap()).unwrap();
-        let frozen_balance = Decimal::from_f64(data["margin_frozen"].as_f64().unwrap()).unwrap();
-        let available_balance = balance - margin_position - frozen_balance;
-        // 格式化account信息
-        let account = Account {
-            coin: data["margin_asset"].as_str().unwrap().to_string(),
-            balance,
-            available_balance,
-            frozen_balance,
-            stocks: Default::default(),
-            available_stocks: Default::default(),
-            frozen_stocks: Default::default(),
-        };
-        result = account
-    }
-    return result;
-}
-
-// 处理order信息
-pub fn handle_order(res_data: ResponseData, ct_val: Decimal) -> SpecialOrder {
-    let res_data_json = res_data.data;
-    let order_info = vec![format_order_item(res_data_json.clone(), ct_val)];
-    SpecialOrder {
-        name: res_data.label,
-        order: order_info,
-    }
-}
-
-// 处理订单信息
-pub fn format_order_item(order: serde_json::Value, ct_val: Decimal) -> Order {
-    let id = order["order_id"].to_string();
-    let custom_id = order["client_order_id"].to_string();
-    let price = Decimal::from_f64(order["price"].as_f64().unwrap()).unwrap();
-    let amount = Decimal::from_f64(order["volume"].as_f64().unwrap()).unwrap() * ct_val;
-    let deal_amount = Decimal::from_f64(order["trade_volume"].as_f64().unwrap()).unwrap() * ct_val;
-    let avg_price = Decimal::from_f64(order["trade_avg_price"].as_f64().unwrap_or(0.0)).unwrap();
-
-    let status = order["status"].to_string();
-
-    let custom_status = if ["5", "6", "7"].contains(&&**&status) {
-        "REMOVE".to_string()
-    } else if ["1", "2", "3", "4"].contains(&&**&status) {
-        "NEW".to_string()
-    } else {
-        "NULL".to_string()
-    };
-    Order {
-        id,
-        custom_id,
-        price,
-        amount,
-        deal_amount,
-        avg_price,
-        status: custom_status,
-        order_type: order["order_price_type"].as_str().unwrap().to_string(),
-        trace_stack: TraceStack::new(0, Instant::now()).on_special("73 htx_swap_handle".to_string()),
-    }
-}
-
-// 格式化深度信息
-pub fn format_depth_items(value: serde_json::Value) -> Vec<MarketOrder> {
-    let mut depth_items: Vec<MarketOrder> = vec![];
-    for value in value.as_array().unwrap() {
-        depth_items.push(MarketOrder {
-            price: Decimal::from_f64(value[0].as_f64().unwrap()).unwrap(),
-            amount: Decimal::from_f64(value[1].as_f64().unwrap()).unwrap(),
-        })
-    }
-    return depth_items;
-}
-
-// 处理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: &serde_json::Value, ct_val: &Decimal) -> Position {
-    let symbol = position["pair"].as_str().unwrap().to_string();
-    let margin_level = Decimal::from_str(&position["lever_rate"].to_string()).unwrap();
-    let amount = Decimal::from_f64(position["volume"].as_f64().unwrap()).unwrap() * ct_val;
-
-    let frozen_amount = Decimal::from_f64(position["frozen"].as_f64().unwrap()).unwrap();
-    let price = Decimal::from_f64(position["cost_hold"].as_f64().unwrap()).unwrap();
-    let profit = Decimal::from_f64(position["profit_unreal"].as_f64().unwrap()).unwrap();
-    let position_mode = match position["position_mode"].as_str().unwrap() {
-        "dual_side" => {
-            match position["direction"].as_str().unwrap() {
-                "sell" => {
-                    PositionModeEnum::Short
-                }
-                "buy" => {
-                    PositionModeEnum::Long
-                }
-                _ => {
-                    panic!("htx_usdt_swap: 未知的持仓模式与持仓方向: {}, {}",
-                           position["direction"].as_str().unwrap(), position["direction"].as_str().unwrap())
-                }
-            }
-        }
-        "single_side" => {
-            PositionModeEnum::Both
-        }
-        _ => {
-            panic!("htx_usdt_swap: 未知的持仓模式: {}", position["position_mode"].as_str().unwrap())
-        }
-    };
-    let margin = Decimal::from_f64(position["position_margin"].as_f64().unwrap()).unwrap();
-
-    Position {
-        symbol,
-        margin_level,
-        amount,
-        frozen_amount,
-        price,
-        profit,
-        position_mode,
-        margin,
-    }
-}
+// use rust_decimal::Decimal;
+// use rust_decimal::prelude::FromPrimitive;
+// use serde_json::Value;
+// use exchanges::response_base::ResponseData;
+// use crate::{Record, Trade};
+//
+// pub fn format_trade_items(response: &ResponseData) -> Vec<Trade> {
+//     let symbol = response.data["symbol"].as_str().unwrap().to_string();
+//     let data = response.data["data"].as_array().unwrap();
+//     let mut trades = vec![];
+//
+//     for item in data {
+//         let id = format!("{}", item["id"].as_i64().unwrap());
+//         let time = Decimal::from_i64(item["ts"].as_i64().unwrap()).unwrap();
+//         let mut size = Decimal::from_i64(item["amount"].as_i64().unwrap()).unwrap();
+//         if item["direction"].as_str().unwrap().eq("sell") {
+//             size = size * Decimal::NEGATIVE_ONE;
+//         }
+//         let price = Decimal::from_f64(item["price"].as_f64().unwrap()).unwrap();
+//
+//         let trade = Trade {
+//             id,
+//             time,
+//             size,
+//             price,
+//             symbol: symbol.clone(),
+//         };
+//
+//         trades.push(trade)
+//     }
+//
+//     return trades
+// }
+//
+// pub fn handle_records(value: &Value) -> Vec<Record> {
+//     let time = Decimal::from_i64(value["id"].as_i64().unwrap() * 1000).unwrap();
+//
+//     let open = Decimal::from_f64(value["open"].as_f64().unwrap()).unwrap();
+//     let high = Decimal::from_f64(value["high"].as_f64().unwrap()).unwrap();
+//     let low = Decimal::from_f64(value["low"].as_f64().unwrap()).unwrap();
+//     let close = Decimal::from_f64(value["close"].as_f64().unwrap()).unwrap();
+//     let volume = Decimal::from_f64(value["trade_turnover"].as_f64().unwrap()).unwrap();
+//     let symbol = value["symbol"].as_str().unwrap().to_string();
+//
+//     vec![Record {
+//         time,
+//         open,
+//         high,
+//         low,
+//         close,
+//         volume,
+//         symbol,
+//     }]
+// }
+//
+// // 处理账号信息
+// // pub fn handle_account_info(response: &ResponseData, _symbol: &String) -> Account {
+// //     let mut result = Account::new();
+// //     let account_infos = response.data.as_array().unwrap();
+// //     for data in account_infos {
+// //         if data["margin_asset"].as_str().unwrap() != "USDT" { continue; }
+// //         let margin_position = Decimal::from_str(&data["margin_position"].to_string()).unwrap();
+// //
+// //         let balance = Decimal::from_str(&data["margin_balance"].to_string()).unwrap();
+// //         let frozen_balance = Decimal::from_str(&data["margin_frozen"].to_string()).unwrap();
+// //         let available_balance = balance - margin_position - frozen_balance;
+// //         // 格式化account信息
+// //         let account = Account {
+// //             coin: data["margin_asset"].as_str().unwrap().to_string(),
+// //             balance,
+// //             available_balance,
+// //             frozen_balance,
+// //             stocks: Default::default(),
+// //             available_stocks: Default::default(),
+// //             frozen_stocks: Default::default(),
+// //         };
+// //         result = account
+// //     }
+// //     return result;
+// // }
+//
+// // 处理order信息
+// // pub fn handle_order(res_data: ResponseData, ct_val: Decimal) -> SpecialOrder {
+// //     let res_data_json = res_data.data;
+// //     let order_info = vec![format_order_item(res_data_json.clone(), ct_val)];
+// //     SpecialOrder {
+// //         name: res_data.tag,
+// //         order: order_info,
+// //     }
+// // }
+//
+// // 处理订单信息
+// // pub fn format_order_item(order: serde_json::Value, ct_val: Decimal) -> Order {
+// //     let id = order["order_id"].to_string();
+// //     let custom_id = order["client_order_id"].to_string();
+// //     let price = Decimal::from_str(&order["price"].to_string()).unwrap();
+// //     let amount = Decimal::from_str(&order["volume"].to_string()).unwrap() * ct_val;
+// //     let deal_amount = Decimal::from_str(&order["trade_volume"].to_string()).unwrap() * ct_val;
+// //     let avg_price = Decimal::from_f64(order["trade_avg_price"].as_f64().unwrap_or(0.0)).unwrap() * ct_val;
+// //
+// //     let status = order["status"].to_string();
+// //
+// //     let custom_status = if ["6", "7", "11"].contains(&&**&status) {
+// //         "REMOVE".to_string()
+// //     } else if ["1", "2", "3", "4", "5"].contains(&&**&status) {
+// //         "NEW".to_string()
+// //     } else {
+// //         "NULL".to_string()
+// //     };
+// //     Order {
+// //         id,
+// //         custom_id,
+// //         price,
+// //         amount,
+// //         deal_amount,
+// //         avg_price,
+// //         status: custom_status,
+// //         order_type: order["order_price_type"].as_str().unwrap().to_string(),
+// //     }
+// // }
+//
+// // 格式化深度信息
+// // pub fn format_depth_items(value: serde_json::Value) -> Vec<OrderBook> {
+// //     let mut depth_items: Vec<OrderBook> = vec![];
+// //     for value in value.as_array().unwrap() {
+// //         depth_items.push(OrderBook {
+// //             price: Decimal::from_str(&value[0].to_string()).unwrap(),
+// //             amount: Decimal::from_str(&value[1].to_string()).unwrap(),
+// //         })
+// //     }
+// //     return depth_items;
+// // }
+//
+// // 处理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: &serde_json::Value, ct_val: &Decimal) -> Position {
+// //     let symbol = position["symbol"].as_str().unwrap().to_string();
+// //     let margin_level = Decimal::from_str(&position["lever_rate"].to_string()).unwrap();
+// //     let amount = Decimal::from_f64(position["volume"].as_f64().unwrap()).unwrap() * ct_val;
+// //
+// //     let frozen_amount = Decimal::from_f64(position["frozen"].as_f64().unwrap()).unwrap();
+// //     let price = Decimal::from_f64(position["cost_hold"].as_f64().unwrap()).unwrap();
+// //     let profit = Decimal::from_f64(position["profit_unreal"].as_f64().unwrap()).unwrap();
+// //     let position_mode = match position["position_mode"].as_str().unwrap() {
+// //         "dual_side" => {
+// //             match position["direction"].as_str().unwrap() {
+// //                 "sell" => {
+// //                     PositionModeEnum::Short
+// //                 }
+// //                 "buy" => {
+// //                     PositionModeEnum::Long
+// //                 }
+// //                 _ => {
+// //                     panic!("htx_usdt_swap: 未知的持仓模式与持仓方向: {}, {}",
+// //                            position["direction"].as_str().unwrap(), position["direction"].as_str().unwrap())
+// //                 }
+// //             }
+// //         }
+// //         "single_side" => {
+// //             PositionModeEnum::Both
+// //         }
+// //         _ => {
+// //             panic!("htx_usdt_swap: 未知的持仓模式: {}", position["position_mode"].as_str().unwrap())
+// //         }
+// //     };
+// //     let margin = Decimal::from_f64(position["position_margin"].as_f64().unwrap()).unwrap();
+// //
+// //     Position {
+// //         symbol,
+// //         margin_level,
+// //         amount,
+// //         frozen_amount,
+// //         price,
+// //         profit,
+// //         position_mode,
+// //         margin,
+// //     }
+// // }

+ 4 - 4
standard/src/kucoin_spot_handle.rs

@@ -55,7 +55,7 @@
 //     }
 //     trace!(?order_info);
 //     SpecialOrder {
-//         name: res_data.label,
+//         name: res_data.tag,
 //         order: order_info,
 //     }
 // }
@@ -112,10 +112,10 @@
 // pub fn handle_special_ticker(res_data: ResponseData) -> SpecialDepth {
 //     let res_data_str = res_data.data;
 //     let res_data_json: serde_json::Value = serde_json::from_str(&*res_data_str).unwrap();
-//     format_special_ticker(res_data_json, res_data.label)
+//     format_special_ticker(res_data_json, res_data.tag)
 // }
 //
-// pub fn format_special_ticker(data: serde_json::Value, label: String) -> SpecialDepth {
+// pub fn format_special_ticker(data: serde_json::Value, tag: String) -> SpecialDepth {
 //     let bp = Decimal::from_str(data["bestBid"].as_str().unwrap()).unwrap();
 //     let bq = Decimal::from_str(data["bestBidSize"].as_str().unwrap()).unwrap();
 //     let ap = Decimal::from_str(data["bestAsk"].as_str().unwrap()).unwrap();
@@ -127,7 +127,7 @@
 //     let ticker_info = SpecialTicker { sell: ap, buy: bp, mid_price: mp, t, create_at };
 //     let depth_info = vec![bp, bq, ap, aq];
 //     SpecialDepth {
-//         name: label,
+//         name: tag,
 //         depth: depth_info,
 //         ticker: ticker_info,
 //         t,

+ 671 - 671
standard/src/kucoin_swap.rs

@@ -1,671 +1,671 @@
-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::prelude::{FromPrimitive, ToPrimitive};
-use rust_decimal_macros::dec;
-use serde_json::{json, Value};
-use tokio::time::Instant;
-use tracing::{error, info};
-use exchanges::kucoin_swap_rest::KucoinSwapRest;
-use global::trace_stack::TraceStack;
-use crate::exchange::ExchangeEnum;
-use crate::{Account, kucoin_handle, Market, Order, OrderCommand, Platform, Position, Ticker, utils};
-
-#[allow(dead_code)]
-#[derive(Clone)]
-pub struct KucoinSwap {
-    exchange: ExchangeEnum,
-    symbol: String,
-    is_colo: bool,
-    params: BTreeMap<String, String>,
-    request: KucoinSwapRest,
-    market: Market,
-    order_sender: Sender<Order>,
-    error_sender: Sender<Error>,
-}
-
-impl KucoinSwap {
-    pub async fn new(symbol: String, is_colo: bool, params: BTreeMap<String, String>, order_sender: Sender<Order>, error_sender: Sender<Error>) -> KucoinSwap {
-        let market = Market::new();
-        let mut kucoin_swap = KucoinSwap {
-            exchange: ExchangeEnum::KucoinSwap,
-            symbol: symbol.to_uppercase(),
-            is_colo,
-            params: params.clone(),
-            request: KucoinSwapRest::new(is_colo, params.clone()),
-            market,
-            order_sender,
-            error_sender,
-        };
-        kucoin_swap.market = KucoinSwap::get_market(&mut kucoin_swap).await.unwrap_or(kucoin_swap.market);
-
-        // 开启自动追加保证金
-        let append_rst = kucoin_swap.set_auto_deposit_status(true).await;
-
-        info!("设置自动追加保证金:{:?}", append_rst.unwrap());
-
-        return kucoin_swap;
-    }
-}
-
-#[async_trait]
-impl Platform for KucoinSwap {
-    // 克隆方法
-    fn clone_box(&self) -> Box<dyn Platform + Send + Sync> { Box::new(self.clone()) }
-    fn get_self_exchange(&self) -> ExchangeEnum {
-        ExchangeEnum::KucoinSwap
-    }
-    // 获取交易对
-    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_time().await;
-        if res_data.code == 200 {
-            Ok(res_data.data.to_string())
-        } else {
-            Err(Error::new(ErrorKind::Other, res_data.to_string()))
-        }
-    }
-    // 获取账号信息
-    async fn get_account(&mut self) -> Result<Account, Error> {
-        let symbol_mapper = utils::symbol_enter_mapper(ExchangeEnum::KucoinSwap, self.symbol.as_str());
-        let symbol_array: Vec<&str> = symbol_mapper.split("_").collect();
-        let res_data = self.request.get_account(symbol_array[1].to_string()).await;
-        if res_data.code == 200 {
-            let res_data_json = res_data.data;
-
-            let balance = Decimal::from_f64(res_data_json["marginBalance"].as_f64().unwrap()).unwrap();
-            let available_balance = Decimal::from_f64(res_data_json["availableBalance"].as_f64().unwrap()).unwrap();
-            let frozen_balance = balance - available_balance;
-            let result = Account {
-                coin: symbol_array[1].to_string(),
-                balance,
-                available_balance,
-                frozen_balance,
-                stocks: Decimal::ZERO,
-                available_stocks: Decimal::ZERO,
-                frozen_stocks: Decimal::ZERO,
-            };
-            Ok(result)
-        } else {
-            Err(Error::new(ErrorKind::Other, res_data.to_string()))
-        }
-    }
-
-    async fn get_spot_account(&mut self) -> Result<Vec<Account>, Error> {
-        Err(Error::new(ErrorKind::NotFound, "kucoin_swap:该交易所方法未实现".to_string()))
-    }
-
-    async fn get_position(&mut self) -> Result<Vec<Position>, Error> {
-        let symbol_mapper = utils::symbol_enter_mapper(ExchangeEnum::KucoinSwap, self.symbol.as_str());
-        let symbol_format = format!("{}M", utils::format_symbol(symbol_mapper.clone(), ""));
-        let ct_val = self.market.ct_val;
-        let res_data = self.request.get_position(symbol_format).await;
-        if res_data.code == 200 {
-            let result = kucoin_handle::format_position_item(&res_data.data, &ct_val);
-            Ok(vec![result])
-        } else {
-            Err(Error::new(ErrorKind::Other, res_data.to_string()))
-        }
-    }
-
-    async fn get_positions(&mut self) -> Result<Vec<Position>, Error> {
-        let symbol_mapper = utils::symbol_enter_mapper(ExchangeEnum::KucoinSwap, self.symbol.as_str());
-        let symbol_array: Vec<&str> = symbol_mapper.split("_").collect();
-        let res_data = self.request.get_positions(symbol_array[1].to_string()).await;
-        if res_data.code == 200 {
-            info!("{}", res_data.data.to_string());
-            let res_data_json = res_data.data.as_array().unwrap();
-            let mut result = Vec::new();
-            for item in res_data_json.iter() {
-                result.push(kucoin_handle::format_position_item(item, &Decimal::ONE))
-            }
-            Ok(result)
-        } else {
-            Err(Error::new(ErrorKind::Other, res_data.to_string()))
-        }
-    }
-
-    async fn get_ticker(&mut self) -> Result<Ticker, Error> {
-        let symbol_mapper = utils::symbol_enter_mapper(ExchangeEnum::KucoinSwap, self.symbol.as_str());
-        let symbol_format = format!("{}M", utils::format_symbol(symbol_mapper.clone(), ""));
-        let res_data = self.request.get_ticker(symbol_format).await;
-        if res_data.code == 200 {
-            let res_data_json = res_data.data;
-            let ticker_info = res_data_json;
-            let time = (Decimal::from_str(&*ticker_info["ts"].to_string()).unwrap() / dec!(1000000)).floor().to_i64().unwrap();
-
-            let result = Ticker {
-                time,
-                high: Decimal::from_str(ticker_info["bestAskPrice"].as_str().unwrap()).unwrap(),
-                low: Decimal::from_str(ticker_info["bestBidPrice"].as_str().unwrap()).unwrap(),
-                sell: Decimal::from_str(ticker_info["bestAskPrice"].as_str().unwrap()).unwrap(),
-                buy: Decimal::from_str(ticker_info["bestBidPrice"].as_str().unwrap()).unwrap(),
-                last: Decimal::from_str(ticker_info["price"].as_str().unwrap()).unwrap(),
-                volume: Decimal::from_str(&ticker_info["size"].to_string()).unwrap(),
-            };
-            Ok(result)
-        } else {
-            Err(Error::new(ErrorKind::Other, res_data.to_string()))
-        }
-    }
-
-    async fn get_ticker_symbol(&mut self, symbol: String) -> Result<Ticker, Error> {
-        let symbol_mapper = utils::symbol_enter_mapper(ExchangeEnum::KucoinSwap, symbol.as_str());
-        let symbol_format = format!("{}M", utils::format_symbol(symbol_mapper, ""));
-        let res_data = self.request.get_ticker(symbol_format).await;
-        if res_data.code == 200 {
-            let res_data_json = res_data.data;
-            let ticker_info = res_data_json;
-            let time = (Decimal::from_str(&*ticker_info["ts"].to_string()).unwrap() / dec!(1000000)).floor().to_i64().unwrap();
-            let result = Ticker {
-                time,
-                high: Decimal::from_str(ticker_info["bestAskPrice"].as_str().unwrap()).unwrap(),
-                low: Decimal::from_str(ticker_info["bestBidPrice"].as_str().unwrap()).unwrap(),
-                sell: Decimal::from_str(ticker_info["bestAskPrice"].as_str().unwrap()).unwrap(),
-                buy: Decimal::from_str(ticker_info["bestBidPrice"].as_str().unwrap()).unwrap(),
-                last: Decimal::from_str(ticker_info["price"].as_str().unwrap()).unwrap(),
-                volume: Decimal::from_str(&ticker_info["size"].to_string()).unwrap(),
-            };
-            Ok(result)
-        } else {
-            Err(Error::new(ErrorKind::Other, res_data.to_string()))
-        }
-    }
-
-    async fn get_market(&mut self) -> Result<Market, Error> {
-        let symbol_mapper = utils::symbol_enter_mapper(ExchangeEnum::KucoinSwap, self.symbol.as_str());
-        let symbol_format = format!("{}M", utils::format_symbol(symbol_mapper.clone(), ""));
-        let res_data = self.request.get_market_details().await;
-        if res_data.code == 200 {
-            let res_data_json = res_data.data.as_array().unwrap();
-
-            let market_info = res_data_json.iter().find(|item| item["symbol"].as_str().unwrap() == symbol_format);
-            match market_info {
-                None => {
-                    error!("kucoin_swap:获取Market信息错误!\nget_market:res_data={:?}", res_data);
-                    Err(Error::new(ErrorKind::Other, res_data.to_string()))
-                }
-                Some(value) => {
-                    let base_asset = value["baseCurrency"].as_str().unwrap_or("").to_string();
-                    let base_asset_mapper = utils::symbol_out_mapper(ExchangeEnum::KucoinSwap, base_asset.as_str());
-                    let quote_asset = value["quoteCurrency"].as_str().unwrap_or("").to_string();
-                    let quote_asset_mapper = utils::symbol_out_mapper(ExchangeEnum::KucoinSwap, quote_asset.as_str());
-                    let tick_size = Decimal::from_f64(value["tickSize"].as_f64().unwrap()).unwrap();
-                    let min_qty = Decimal::from_f64(value["lotSize"].as_f64().unwrap()).unwrap();
-                    let ct_val = Decimal::from_f64(value["multiplier"].as_f64().unwrap()).unwrap();
-
-                    let amount_size = min_qty * ct_val;
-                    let price_precision = Decimal::from_u32(tick_size.scale()).unwrap();
-                    let amount_precision = Decimal::from_u32(ct_val.scale()).unwrap();
-                    let min_notional = min_qty * ct_val;
-
-                    let result = Market {
-                        symbol: format!("{}_{}", base_asset_mapper, quote_asset_mapper),
-                        base_asset: base_asset_mapper,
-                        quote_asset: quote_asset_mapper,
-                        tick_size,
-                        amount_size,
-                        price_precision,
-                        amount_precision,
-                        min_qty,
-                        max_qty: Decimal::from_f64(value["maxOrderQty"].as_f64().unwrap()).unwrap(),
-                        min_notional,
-                        max_notional: Decimal::from_f64(value["maxPrice"].as_f64().unwrap()).unwrap(),
-                        ct_val,
-                    };
-                    Ok(result)
-                }
-            }
-        } else {
-            Err(Error::new(ErrorKind::Other, res_data.to_string()))
-        }
-    }
-
-    async fn get_market_symbol(&mut self, symbol: String) -> Result<Market, Error> {
-        let symbol_mapper = utils::symbol_enter_mapper(ExchangeEnum::KucoinSwap, symbol.as_str());
-        let symbol_format = format!("{}M", utils::format_symbol(symbol_mapper.clone(), ""));
-        let res_data = self.request.get_market_details().await;
-        if res_data.code == 200 {
-            let res_data_json = res_data.data.as_array().unwrap();
-            let market_info = res_data_json.iter().find(|item| item["symbol"].as_str().unwrap() == symbol_format);
-            match market_info {
-                None => {
-                    error!("kucoin_swap:获取Market信息错误!\nget_market:res_data={:?}", res_data);
-                    Err(Error::new(ErrorKind::Other, res_data.to_string()))
-                }
-                Some(value) => {
-                    let base_asset = value["baseCurrency"].as_str().unwrap_or("").to_string();
-                    let base_asset_mapper = utils::symbol_out_mapper(ExchangeEnum::KucoinSwap, base_asset.as_str());
-                    let quote_asset = value["quoteCurrency"].as_str().unwrap_or("").to_string();
-                    let quote_asset_mapper = utils::symbol_out_mapper(ExchangeEnum::KucoinSwap, quote_asset.as_str());
-                    let tick_size = Decimal::from_f64(value["tickSize"].as_f64().unwrap()).unwrap();
-                    let min_qty = Decimal::from_f64(value["lotSize"].as_f64().unwrap()).unwrap();
-                    let ct_val = Decimal::from_f64(value["multiplier"].as_f64().unwrap()).unwrap();
-
-                    let amount_size = min_qty * ct_val;
-                    let price_precision = Decimal::from_u32(tick_size.scale()).unwrap();
-                    let amount_precision = Decimal::from_u32(ct_val.scale()).unwrap();
-                    let min_notional = min_qty * ct_val;
-
-                    let result = Market {
-                        symbol: format!("{}_{}", base_asset_mapper, quote_asset_mapper),
-                        base_asset: base_asset_mapper,
-                        quote_asset: quote_asset_mapper,
-                        tick_size,
-                        amount_size,
-                        price_precision,
-                        amount_precision,
-                        min_qty,
-                        max_qty: Decimal::from_f64(value["maxOrderQty"].as_f64().unwrap()).unwrap(),
-                        min_notional,
-                        max_notional: Decimal::from_f64(value["maxPrice"].as_f64().unwrap()).unwrap(),
-                        ct_val,
-                    };
-                    Ok(result)
-                }
-            }
-        } else {
-            Err(Error::new(ErrorKind::Other, res_data.to_string()))
-        }
-    }
-
-    async fn get_order_detail(&mut self, order_id: &str, custom_id: &str) -> Result<Order, Error> {
-        let ct_val = self.market.ct_val;
-        let res_data = self.request.get_orders_details(order_id.to_string(), custom_id.to_string()).await;
-        if res_data.code == 200 {
-            let res_data_json = 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 get_orders_list(&mut self, status: &str) -> Result<Vec<Order>, Error> {
-        let symbol_mapper = utils::symbol_enter_mapper(ExchangeEnum::KucoinSwap, self.symbol.as_str());
-        let symbol_format = format!("{}M", utils::format_symbol(symbol_mapper.clone(), ""));
-        let ct_val = self.market.ct_val;
-        let res_data = self.request.get_orders(status.to_string(), symbol_format.clone()).await;
-        if res_data.code == 200 {
-            let res_data_json = res_data.data;
-            let order_list = res_data_json["items"].as_array().unwrap().clone();
-            let order_info: Vec<_> = order_list.iter().filter(|item| item["symbol"].as_str().unwrap_or("") == symbol_format.clone()).collect();
-            let result = order_info.iter().map(|&item| format_order_item(item.clone(), ct_val)).collect();
-            Ok(result)
-        } else {
-            Err(Error::new(ErrorKind::Other, res_data.to_string()))
-        }
-    }
-
-    async fn take_order(&mut self, custom_id: &str, origin_side: &str, price: Decimal, amount: Decimal) -> Result<Order, Error> {
-        let symbol_mapper = utils::symbol_enter_mapper(ExchangeEnum::KucoinSwap, self.symbol.as_str());
-        let symbol_format = format!("{}M", utils::format_symbol(symbol_mapper.clone(), ""));
-        let ct_val = self.market.ct_val;
-        let mut params = json!({
-            "clientOid": custom_id,
-            "symbol": symbol_format,
-            "leverage": "10",
-            "reduceOnly":false,
-            "price": price.to_string(),
-        });
-        params["type"] = if price.eq(&Decimal::ZERO) { json!("market") } else { json!("limit") };
-        let size = (amount / ct_val).floor();
-        params["size"] = json!(size);
-        match origin_side {
-            "kd" => {
-                params["side"] = json!("buy");
-            }
-            "pd" => {
-                params["side"] = json!("sell");
-            }
-            "kk" => {
-                params["side"] = json!("sell");
-            }
-            "pk" => {
-                params["side"] = json!("buy");
-            }
-            _ => { error!("下单参数错误"); }
-        };
-
-        let res_data = self.request.swap_order(params).await;
-        if res_data.code == 200 {
-            let res_data_json = res_data.data;
-            let id = res_data_json["orderId"].as_str().unwrap().to_string();
-            let result = Order {
-                id,
-                custom_id: custom_id.to_string(),
-                price,
-                amount,
-                deal_amount: Decimal::ZERO,
-                avg_price: Decimal::ZERO,
-                status: "NEW".to_string(),
-                order_type: "".to_string(),
-                trace_stack: TraceStack::new(0, Instant::now()).on_special("359 kucoin_swap".to_string()),
-            };
-            Ok(result)
-        } else {
-            Err(Error::new(ErrorKind::Other, res_data.to_string()))
-        }
-    }
-
-    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_mapper = utils::symbol_enter_mapper(ExchangeEnum::KucoinSwap, symbol.as_str());
-        let symbol_format = format!("{}M", utils::format_symbol(symbol_mapper.clone(), ""));
-        let mut params = json!({
-            "clientOid": custom_id,
-            "symbol": symbol_format,
-            "leverage": "10",
-            "reduceOnly":false,
-            "price": price.to_string(),
-        });
-        let size = (amount / ct_val).floor();
-        params["size"] = json!(size);
-        if price.eq(&Decimal::ZERO){
-            params["type"] = json!("market");
-        }
-        match origin_side {
-            "kd" => {
-                params["side"] = json!("buy");
-            }
-            "pd" => {
-                params["side"] = json!("sell");
-            }
-            "kk" => {
-                params["side"] = json!("sell");
-            }
-            "pk" => {
-                params["side"] = json!("buy");
-            }
-            _ => { error!("下单参数错误"); }
-        };
-
-        let res_data = self.request.swap_order(params).await;
-        if res_data.code == 200 {
-            let res_data_json = res_data.data;
-            let id = res_data_json["orderId"].as_str().unwrap().to_string();
-            let result = Order {
-                id,
-                custom_id: custom_id.to_string(),
-                price,
-                amount,
-                deal_amount: Decimal::ZERO,
-                avg_price: Decimal::ZERO,
-                status: "NEW".to_string(),
-                order_type: "".to_string(),
-                trace_stack: TraceStack::new(0, Instant::now()).on_special("408 kucoin_swap".to_string()),
-            };
-            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 res_data = self.request.cancel_order(order_id.to_string(), custom_id.to_string()).await;
-        if order_id == "" {
-            error!("Kucoin:撤销订单错误,该交易所为提供自定义订单号撤销订单!\ncancel_order:order_id={:?},custom_id={:?}", order_id, custom_id);
-            panic!("Kucoin:撤销订单错误,该交易所为提供自定义订单号撤销订单!\ncancel_order:order_id={:?},custom_id={:?}", order_id, custom_id)
-        }
-        if res_data.code == 200 {
-            let res_data_json = res_data.data;
-            let cancel_ids = res_data_json["cancelledOrderIds"].as_array().unwrap();
-            let id = cancel_ids[0].as_str().unwrap().to_string();
-            let result = Order {
-                id,
-                custom_id: custom_id.to_string(),
-                price: Decimal::ZERO,
-                amount: Decimal::ZERO,
-                deal_amount: Decimal::ZERO,
-                avg_price: Decimal::ZERO,
-                status: "REMOVE".to_string(),
-                order_type: "".to_string(),
-                trace_stack: TraceStack::new(0, Instant::now()).on_special("436 kucoin_swap".to_string()),
-            };
-            Ok(result)
-        } else {
-            Err(Error::new(ErrorKind::Other, res_data.to_string()))
-        }
-    }
-
-    async fn cancel_orders(&mut self) -> Result<Vec<Order>, Error> {
-        let symbol_mapper = utils::symbol_enter_mapper(ExchangeEnum::KucoinSwap, self.symbol.as_str());
-        let symbol_format = format!("{}M", utils::format_symbol(symbol_mapper.clone(), ""));
-        let res_data = self.request.cancel_orders(symbol_format).await;
-        if res_data.code == 200 {
-            info!("{}", res_data.data.to_string());
-            let res_data_json = res_data.data;
-            let cancel_ids = res_data_json["cancelledOrderIds"].as_array().unwrap();
-            let result = cancel_ids.iter().map(|item|
-                Order {
-                    id: item.as_str().unwrap().to_string(),
-                    custom_id: "".to_string(),
-                    price: Decimal::ZERO,
-                    amount: Decimal::ZERO,
-                    deal_amount: Decimal::ZERO,
-                    avg_price: Decimal::ZERO,
-                    status: "REMOVE".to_string(),
-                    order_type: "".to_string(),
-                    trace_stack: TraceStack::new(0, Instant::now()).on_special("461 kucoin_swap".to_string()),
-                }
-            ).collect();
-            Ok(result)
-        } else {
-            Err(Error::new(ErrorKind::Other, res_data.to_string()))
-        }
-    }
-
-    async fn cancel_orders_all(&mut self) -> Result<Vec<Order>, Error> {
-        let res_data = self.request.cancel_order_all().await;
-        if res_data.code == 200 {
-            info!("{}", res_data.data.to_string());
-            let res_data_json = res_data.data;
-            let cancel_ids = res_data_json["cancelledOrderIds"].as_array().unwrap();
-            let result = cancel_ids.iter().map(|item|
-                Order {
-                    id: item.as_str().unwrap().to_string(),
-                    custom_id: "".to_string(),
-                    price: Decimal::ZERO,
-                    amount: Decimal::ZERO,
-                    deal_amount: Decimal::ZERO,
-                    avg_price: Decimal::ZERO,
-                    status: "REMOVE".to_string(),
-                    order_type: "".to_string(),
-                    trace_stack: TraceStack::new(0, Instant::now()).on_special("486 kucoin_swap".to_string()),
-                }
-            ).collect();
-            Ok(result)
-        } else {
-            Err(Error::new(ErrorKind::Other, res_data.to_string()))
-        }
-    }
-
-    async fn take_stop_loss_order(&mut self, _stop_price: Decimal, _price: Decimal, _side: &str) -> Result<Value, Error> {
-        Err(Error::new(ErrorKind::NotFound, "kucoin_swap:该交易所方法未实现".to_string()))
-    }
-
-    async fn cancel_stop_loss_order(&mut self, _order_id: &str) -> Result<Value, Error> {
-        Err(Error::new(ErrorKind::NotFound, "kucoin_swap:该交易所方法未实现".to_string()))
-    }
-
-    async fn set_dual_mode(&mut self, _coin: &str, _is_dual_mode: bool) -> Result<String, Error> {
-        Err(Error::new(ErrorKind::NotFound, "kucoin_swap:该交易所方法未实现".to_string()))
-    }
-
-    async fn set_dual_leverage(&mut self, _leverage: &str) -> Result<String, Error> {
-        Err(Error::new(ErrorKind::NotFound, "kucoin_swap:该交易所方法未实现".to_string()))
-    }
-
-    async fn set_auto_deposit_status(&mut self, status: bool) -> Result<String, Error> {
-        let symbol_mapper = utils::symbol_enter_mapper(ExchangeEnum::KucoinSwap, self.symbol.as_str());
-        let symbol_format = format!("{}M", utils::format_symbol(symbol_mapper.clone(), ""));
-        let res_data = self.request.auto_deposit_status(symbol_format, status).await;
-        if res_data.code == 200 {
-            Ok(res_data.data.to_string())
-        } else {
-            Err(Error::new(ErrorKind::Other, res_data.to_string()))
-        }
-    }
-
-    async fn wallet_transfers(&mut self, _coin: &str, _from: &str, _to: &str, _amount: Decimal) -> Result<String, Error> {
-        Err(Error::new(ErrorKind::NotFound, "kucoin_swap:该交易所方法未实现".to_string()))
-    }
-
-    // 指令下单
-    async fn command_order(&mut self, order_command: &mut OrderCommand, trace_stack: &TraceStack) {
-        let mut handles = vec![];
-        // 下单指令,limits_open里已经包含了limits_close,在core里面处理过了
-        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();
-
-            let mut self_clone = self.clone();
-            let handle = tokio::spawn(async move {
-                ts.on_before_send();
-                let result = self_clone.take_order(&cid, &side, price, amount).await;
-                ts.on_after_send();
-
-                match result {
-                    Ok(mut result) => {
-                        // ts.on_after_send();
-                        result.trace_stack = ts.clone();
-
-                        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();
-
-                        self_clone.order_sender.send(err_order).await.unwrap();
-                        self_clone.error_sender.send(error).await.unwrap();
-                    }
-                }
-            });
-            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 = tokio::spawn(async move {
-                if order_id != "" {
-                    let result = self_clone.cancel_order(&order_id, &custom_id).await;
-                    match result {
-                        Ok(_) => {
-                            // result_sd.send(result).await.unwrap();
-                        }
-                        Err(error) => {
-                            // 取消失败去查订单。
-                            let query_rst = self_clone.get_order_detail(&order_id, &custom_id).await;
-                            match query_rst {
-                                Ok(order) => {
-                                    self_clone.order_sender.send(order).await.unwrap();
-                                }
-                                Err(_query_err) => {
-                                    // error!(?_query_err);
-                                    // error!("撤单失败,而且查单也失败了,kucoin_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 = tokio::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_order_item(order: Value, ct_val: Decimal) -> Order {
-    let price = Decimal::from_str(order["price"].as_str().unwrap()).unwrap();
-    let size = Decimal::from_f64(order["size"].as_f64().unwrap()).unwrap();
-    let status = order["status"].as_str().unwrap_or("");
-    let filled_size = Decimal::from_f64(order["filledSize"].as_f64().unwrap()).unwrap();
-    let filled_value = Decimal::from_str(order["filledValue"].as_str().unwrap()).unwrap();
-
-    let amount = size * ct_val;
-    let deal_amount = filled_size * ct_val;
-    let avg_price = if deal_amount.is_zero() { Decimal::ZERO } else { filled_value / deal_amount };
-    let custom_status;
-    if ["cancelled", "closed", "finished"].contains(&status) {
-        custom_status = "REMOVE".to_string();
-    } else if status == "open" {
-        custom_status = "NEW".to_string();
-    } else {
-        custom_status = "NULL".to_string();
-    };
-    Order {
-        id: order["id"].as_str().unwrap().to_string(),
-        custom_id: order["clientOid"].as_str().unwrap_or("").to_string(),
-        price,
-        amount,
-        deal_amount,
-        avg_price,
-        status: custom_status,
-        order_type: order["type"].as_str().unwrap().to_string(),
-        trace_stack: TraceStack::new(0, Instant::now()).on_special("655 kucoin_swap".to_string()),
-    }
-}
+// 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::prelude::{FromPrimitive, ToPrimitive};
+// use rust_decimal_macros::dec;
+// use serde_json::{json, Value};
+// use tokio::time::Instant;
+// use tracing::{error, info};
+// use exchanges::kucoin_swap_rest::KucoinSwapRest;
+// use global::trace_stack::TraceStack;
+// use crate::exchange::ExchangeEnum;
+// use crate::{Account, kucoin_handle, Market, Order, OrderCommand, Platform, Position, Ticker, utils};
+//
+// #[allow(dead_code)]
+// #[derive(Clone)]
+// pub struct KucoinSwap {
+//     exchange: ExchangeEnum,
+//     symbol: String,
+//     is_colo: bool,
+//     params: BTreeMap<String, String>,
+//     request: KucoinSwapRest,
+//     market: Market,
+//     order_sender: Sender<Order>,
+//     error_sender: Sender<Error>,
+// }
+//
+// impl KucoinSwap {
+//     pub async fn new(symbol: String, is_colo: bool, params: BTreeMap<String, String>, order_sender: Sender<Order>, error_sender: Sender<Error>) -> KucoinSwap {
+//         let market = Market::new();
+//         let mut kucoin_swap = KucoinSwap {
+//             exchange: ExchangeEnum::KucoinSwap,
+//             symbol: symbol.to_uppercase(),
+//             is_colo,
+//             params: params.clone(),
+//             request: KucoinSwapRest::new(is_colo, params.clone()),
+//             market,
+//             order_sender,
+//             error_sender,
+//         };
+//         kucoin_swap.market = KucoinSwap::get_market(&mut kucoin_swap).await.unwrap_or(kucoin_swap.market);
+//
+//         // 开启自动追加保证金
+//         let append_rst = kucoin_swap.set_auto_deposit_status(true).await;
+//
+//         info!("设置自动追加保证金:{:?}", append_rst.unwrap());
+//
+//         return kucoin_swap;
+//     }
+// }
+//
+// #[async_trait]
+// impl Platform for KucoinSwap {
+//     // 克隆方法
+//     fn clone_box(&self) -> Box<dyn Platform + Send + Sync> { Box::new(self.clone()) }
+//     fn get_self_exchange(&self) -> ExchangeEnum {
+//         ExchangeEnum::KucoinSwap
+//     }
+//     // 获取交易对
+//     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_time().await;
+//         if res_data.code == 200 {
+//             Ok(res_data.data.to_string())
+//         } else {
+//             Err(Error::new(ErrorKind::Other, res_data.to_string()))
+//         }
+//     }
+//     // 获取账号信息
+//     async fn get_account(&mut self) -> Result<Account, Error> {
+//         let symbol_mapper = utils::symbol_enter_mapper(ExchangeEnum::KucoinSwap, self.symbol.as_str());
+//         let symbol_array: Vec<&str> = symbol_mapper.split("_").collect();
+//         let res_data = self.request.get_account(symbol_array[1].to_string()).await;
+//         if res_data.code == 200 {
+//             let res_data_json = res_data.data;
+//
+//             let balance = Decimal::from_f64(res_data_json["marginBalance"].as_f64().unwrap()).unwrap();
+//             let available_balance = Decimal::from_f64(res_data_json["availableBalance"].as_f64().unwrap()).unwrap();
+//             let frozen_balance = balance - available_balance;
+//             let result = Account {
+//                 coin: symbol_array[1].to_string(),
+//                 balance,
+//                 available_balance,
+//                 frozen_balance,
+//                 stocks: Decimal::ZERO,
+//                 available_stocks: Decimal::ZERO,
+//                 frozen_stocks: Decimal::ZERO,
+//             };
+//             Ok(result)
+//         } else {
+//             Err(Error::new(ErrorKind::Other, res_data.to_string()))
+//         }
+//     }
+//
+//     async fn get_spot_account(&mut self) -> Result<Vec<Account>, Error> {
+//         Err(Error::new(ErrorKind::NotFound, "kucoin_swap:该交易所方法未实现".to_string()))
+//     }
+//
+//     async fn get_position(&mut self) -> Result<Vec<Position>, Error> {
+//         let symbol_mapper = utils::symbol_enter_mapper(ExchangeEnum::KucoinSwap, self.symbol.as_str());
+//         let symbol_format = format!("{}M", utils::format_symbol(symbol_mapper.clone(), ""));
+//         let ct_val = self.market.ct_val;
+//         let res_data = self.request.get_position(symbol_format).await;
+//         if res_data.code == 200 {
+//             let result = kucoin_handle::format_position_item(&res_data.data, &ct_val);
+//             Ok(vec![result])
+//         } else {
+//             Err(Error::new(ErrorKind::Other, res_data.to_string()))
+//         }
+//     }
+//
+//     async fn get_positions(&mut self) -> Result<Vec<Position>, Error> {
+//         let symbol_mapper = utils::symbol_enter_mapper(ExchangeEnum::KucoinSwap, self.symbol.as_str());
+//         let symbol_array: Vec<&str> = symbol_mapper.split("_").collect();
+//         let res_data = self.request.get_positions(symbol_array[1].to_string()).await;
+//         if res_data.code == 200 {
+//             info!("{}", res_data.data.to_string());
+//             let res_data_json = res_data.data.as_array().unwrap();
+//             let mut result = Vec::new();
+//             for item in res_data_json.iter() {
+//                 result.push(kucoin_handle::format_position_item(item, &Decimal::ONE))
+//             }
+//             Ok(result)
+//         } else {
+//             Err(Error::new(ErrorKind::Other, res_data.to_string()))
+//         }
+//     }
+//
+//     async fn get_ticker(&mut self) -> Result<Ticker, Error> {
+//         let symbol_mapper = utils::symbol_enter_mapper(ExchangeEnum::KucoinSwap, self.symbol.as_str());
+//         let symbol_format = format!("{}M", utils::format_symbol(symbol_mapper.clone(), ""));
+//         let res_data = self.request.get_ticker(symbol_format).await;
+//         if res_data.code == 200 {
+//             let res_data_json = res_data.data;
+//             let ticker_info = res_data_json;
+//             let time = (Decimal::from_str(&*ticker_info["ts"].to_string()).unwrap() / dec!(1000000)).floor().to_i64().unwrap();
+//
+//             let result = Ticker {
+//                 time,
+//                 high: Decimal::from_str(ticker_info["bestAskPrice"].as_str().unwrap()).unwrap(),
+//                 low: Decimal::from_str(ticker_info["bestBidPrice"].as_str().unwrap()).unwrap(),
+//                 sell: Decimal::from_str(ticker_info["bestAskPrice"].as_str().unwrap()).unwrap(),
+//                 buy: Decimal::from_str(ticker_info["bestBidPrice"].as_str().unwrap()).unwrap(),
+//                 last: Decimal::from_str(ticker_info["price"].as_str().unwrap()).unwrap(),
+//                 volume: Decimal::from_str(&ticker_info["size"].to_string()).unwrap(),
+//             };
+//             Ok(result)
+//         } else {
+//             Err(Error::new(ErrorKind::Other, res_data.to_string()))
+//         }
+//     }
+//
+//     async fn get_ticker_symbol(&mut self, symbol: String) -> Result<Ticker, Error> {
+//         let symbol_mapper = utils::symbol_enter_mapper(ExchangeEnum::KucoinSwap, symbol.as_str());
+//         let symbol_format = format!("{}M", utils::format_symbol(symbol_mapper, ""));
+//         let res_data = self.request.get_ticker(symbol_format).await;
+//         if res_data.code == 200 {
+//             let res_data_json = res_data.data;
+//             let ticker_info = res_data_json;
+//             let time = (Decimal::from_str(&*ticker_info["ts"].to_string()).unwrap() / dec!(1000000)).floor().to_i64().unwrap();
+//             let result = Ticker {
+//                 time,
+//                 high: Decimal::from_str(ticker_info["bestAskPrice"].as_str().unwrap()).unwrap(),
+//                 low: Decimal::from_str(ticker_info["bestBidPrice"].as_str().unwrap()).unwrap(),
+//                 sell: Decimal::from_str(ticker_info["bestAskPrice"].as_str().unwrap()).unwrap(),
+//                 buy: Decimal::from_str(ticker_info["bestBidPrice"].as_str().unwrap()).unwrap(),
+//                 last: Decimal::from_str(ticker_info["price"].as_str().unwrap()).unwrap(),
+//                 volume: Decimal::from_str(&ticker_info["size"].to_string()).unwrap(),
+//             };
+//             Ok(result)
+//         } else {
+//             Err(Error::new(ErrorKind::Other, res_data.to_string()))
+//         }
+//     }
+//
+//     async fn get_market(&mut self) -> Result<Market, Error> {
+//         let symbol_mapper = utils::symbol_enter_mapper(ExchangeEnum::KucoinSwap, self.symbol.as_str());
+//         let symbol_format = format!("{}M", utils::format_symbol(symbol_mapper.clone(), ""));
+//         let res_data = self.request.get_market_details().await;
+//         if res_data.code == 200 {
+//             let res_data_json = res_data.data.as_array().unwrap();
+//
+//             let market_info = res_data_json.iter().find(|item| item["symbol"].as_str().unwrap() == symbol_format);
+//             match market_info {
+//                 None => {
+//                     error!("kucoin_swap:获取Market信息错误!\nget_market:res_data={:?}", res_data);
+//                     Err(Error::new(ErrorKind::Other, res_data.to_string()))
+//                 }
+//                 Some(value) => {
+//                     let base_asset = value["baseCurrency"].as_str().unwrap_or("").to_string();
+//                     let base_asset_mapper = utils::symbol_out_mapper(ExchangeEnum::KucoinSwap, base_asset.as_str());
+//                     let quote_asset = value["quoteCurrency"].as_str().unwrap_or("").to_string();
+//                     let quote_asset_mapper = utils::symbol_out_mapper(ExchangeEnum::KucoinSwap, quote_asset.as_str());
+//                     let tick_size = Decimal::from_f64(value["tickSize"].as_f64().unwrap()).unwrap();
+//                     let min_qty = Decimal::from_f64(value["lotSize"].as_f64().unwrap()).unwrap();
+//                     let ct_val = Decimal::from_f64(value["multiplier"].as_f64().unwrap()).unwrap();
+//
+//                     let amount_size = min_qty * ct_val;
+//                     let price_precision = Decimal::from_u32(tick_size.scale()).unwrap();
+//                     let amount_precision = Decimal::from_u32(ct_val.scale()).unwrap();
+//                     let min_notional = min_qty * ct_val;
+//
+//                     let result = Market {
+//                         symbol: format!("{}_{}", base_asset_mapper, quote_asset_mapper),
+//                         base_asset: base_asset_mapper,
+//                         quote_asset: quote_asset_mapper,
+//                         tick_size,
+//                         amount_size,
+//                         price_precision,
+//                         amount_precision,
+//                         min_qty,
+//                         max_qty: Decimal::from_f64(value["maxOrderQty"].as_f64().unwrap()).unwrap(),
+//                         min_notional,
+//                         max_notional: Decimal::from_f64(value["maxPrice"].as_f64().unwrap()).unwrap(),
+//                         ct_val,
+//                     };
+//                     Ok(result)
+//                 }
+//             }
+//         } else {
+//             Err(Error::new(ErrorKind::Other, res_data.to_string()))
+//         }
+//     }
+//
+//     async fn get_market_symbol(&mut self, symbol: String) -> Result<Market, Error> {
+//         let symbol_mapper = utils::symbol_enter_mapper(ExchangeEnum::KucoinSwap, symbol.as_str());
+//         let symbol_format = format!("{}M", utils::format_symbol(symbol_mapper.clone(), ""));
+//         let res_data = self.request.get_market_details().await;
+//         if res_data.code == 200 {
+//             let res_data_json = res_data.data.as_array().unwrap();
+//             let market_info = res_data_json.iter().find(|item| item["symbol"].as_str().unwrap() == symbol_format);
+//             match market_info {
+//                 None => {
+//                     error!("kucoin_swap:获取Market信息错误!\nget_market:res_data={:?}", res_data);
+//                     Err(Error::new(ErrorKind::Other, res_data.to_string()))
+//                 }
+//                 Some(value) => {
+//                     let base_asset = value["baseCurrency"].as_str().unwrap_or("").to_string();
+//                     let base_asset_mapper = utils::symbol_out_mapper(ExchangeEnum::KucoinSwap, base_asset.as_str());
+//                     let quote_asset = value["quoteCurrency"].as_str().unwrap_or("").to_string();
+//                     let quote_asset_mapper = utils::symbol_out_mapper(ExchangeEnum::KucoinSwap, quote_asset.as_str());
+//                     let tick_size = Decimal::from_f64(value["tickSize"].as_f64().unwrap()).unwrap();
+//                     let min_qty = Decimal::from_f64(value["lotSize"].as_f64().unwrap()).unwrap();
+//                     let ct_val = Decimal::from_f64(value["multiplier"].as_f64().unwrap()).unwrap();
+//
+//                     let amount_size = min_qty * ct_val;
+//                     let price_precision = Decimal::from_u32(tick_size.scale()).unwrap();
+//                     let amount_precision = Decimal::from_u32(ct_val.scale()).unwrap();
+//                     let min_notional = min_qty * ct_val;
+//
+//                     let result = Market {
+//                         symbol: format!("{}_{}", base_asset_mapper, quote_asset_mapper),
+//                         base_asset: base_asset_mapper,
+//                         quote_asset: quote_asset_mapper,
+//                         tick_size,
+//                         amount_size,
+//                         price_precision,
+//                         amount_precision,
+//                         min_qty,
+//                         max_qty: Decimal::from_f64(value["maxOrderQty"].as_f64().unwrap()).unwrap(),
+//                         min_notional,
+//                         max_notional: Decimal::from_f64(value["maxPrice"].as_f64().unwrap()).unwrap(),
+//                         ct_val,
+//                     };
+//                     Ok(result)
+//                 }
+//             }
+//         } else {
+//             Err(Error::new(ErrorKind::Other, res_data.to_string()))
+//         }
+//     }
+//
+//     async fn get_order_detail(&mut self, order_id: &str, custom_id: &str) -> Result<Order, Error> {
+//         let ct_val = self.market.ct_val;
+//         let res_data = self.request.get_orders_details(order_id.to_string(), custom_id.to_string()).await;
+//         if res_data.code == 200 {
+//             let res_data_json = 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 get_orders_list(&mut self, status: &str) -> Result<Vec<Order>, Error> {
+//         let symbol_mapper = utils::symbol_enter_mapper(ExchangeEnum::KucoinSwap, self.symbol.as_str());
+//         let symbol_format = format!("{}M", utils::format_symbol(symbol_mapper.clone(), ""));
+//         let ct_val = self.market.ct_val;
+//         let res_data = self.request.get_orders(status.to_string(), symbol_format.clone()).await;
+//         if res_data.code == 200 {
+//             let res_data_json = res_data.data;
+//             let order_list = res_data_json["items"].as_array().unwrap().clone();
+//             let order_info: Vec<_> = order_list.iter().filter(|item| item["symbol"].as_str().unwrap_or("") == symbol_format.clone()).collect();
+//             let result = order_info.iter().map(|&item| format_order_item(item.clone(), ct_val)).collect();
+//             Ok(result)
+//         } else {
+//             Err(Error::new(ErrorKind::Other, res_data.to_string()))
+//         }
+//     }
+//
+//     async fn take_order(&mut self, custom_id: &str, origin_side: &str, price: Decimal, amount: Decimal) -> Result<Order, Error> {
+//         let symbol_mapper = utils::symbol_enter_mapper(ExchangeEnum::KucoinSwap, self.symbol.as_str());
+//         let symbol_format = format!("{}M", utils::format_symbol(symbol_mapper.clone(), ""));
+//         let ct_val = self.market.ct_val;
+//         let mut params = json!({
+//             "clientOid": custom_id,
+//             "symbol": symbol_format,
+//             "leverage": "10",
+//             "reduceOnly":false,
+//             "price": price.to_string(),
+//         });
+//         params["type"] = if price.eq(&Decimal::ZERO) { json!("market") } else { json!("limit") };
+//         let size = (amount / ct_val).floor();
+//         params["size"] = json!(size);
+//         match origin_side {
+//             "kd" => {
+//                 params["side"] = json!("buy");
+//             }
+//             "pd" => {
+//                 params["side"] = json!("sell");
+//             }
+//             "kk" => {
+//                 params["side"] = json!("sell");
+//             }
+//             "pk" => {
+//                 params["side"] = json!("buy");
+//             }
+//             _ => { error!("下单参数错误"); }
+//         };
+//
+//         let res_data = self.request.swap_order(params).await;
+//         if res_data.code == 200 {
+//             let res_data_json = res_data.data;
+//             let id = res_data_json["orderId"].as_str().unwrap().to_string();
+//             let result = Order {
+//                 id,
+//                 custom_id: custom_id.to_string(),
+//                 price,
+//                 amount,
+//                 deal_amount: Decimal::ZERO,
+//                 avg_price: Decimal::ZERO,
+//                 status: "NEW".to_string(),
+//                 order_type: "".to_string(),
+//                 trace_stack: TraceStack::new(0, Instant::now()).on_special("359 kucoin_swap".to_string()),
+//             };
+//             Ok(result)
+//         } else {
+//             Err(Error::new(ErrorKind::Other, res_data.to_string()))
+//         }
+//     }
+//
+//     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_mapper = utils::symbol_enter_mapper(ExchangeEnum::KucoinSwap, symbol.as_str());
+//         let symbol_format = format!("{}M", utils::format_symbol(symbol_mapper.clone(), ""));
+//         let mut params = json!({
+//             "clientOid": custom_id,
+//             "symbol": symbol_format,
+//             "leverage": "10",
+//             "reduceOnly":false,
+//             "price": price.to_string(),
+//         });
+//         let size = (amount / ct_val).floor();
+//         params["size"] = json!(size);
+//         if price.eq(&Decimal::ZERO){
+//             params["type"] = json!("market");
+//         }
+//         match origin_side {
+//             "kd" => {
+//                 params["side"] = json!("buy");
+//             }
+//             "pd" => {
+//                 params["side"] = json!("sell");
+//             }
+//             "kk" => {
+//                 params["side"] = json!("sell");
+//             }
+//             "pk" => {
+//                 params["side"] = json!("buy");
+//             }
+//             _ => { error!("下单参数错误"); }
+//         };
+//
+//         let res_data = self.request.swap_order(params).await;
+//         if res_data.code == 200 {
+//             let res_data_json = res_data.data;
+//             let id = res_data_json["orderId"].as_str().unwrap().to_string();
+//             let result = Order {
+//                 id,
+//                 custom_id: custom_id.to_string(),
+//                 price,
+//                 amount,
+//                 deal_amount: Decimal::ZERO,
+//                 avg_price: Decimal::ZERO,
+//                 status: "NEW".to_string(),
+//                 order_type: "".to_string(),
+//                 trace_stack: TraceStack::new(0, Instant::now()).on_special("408 kucoin_swap".to_string()),
+//             };
+//             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 res_data = self.request.cancel_order(order_id.to_string(), custom_id.to_string()).await;
+//         if order_id == "" {
+//             error!("Kucoin:撤销订单错误,该交易所为提供自定义订单号撤销订单!\ncancel_order:order_id={:?},custom_id={:?}", order_id, custom_id);
+//             panic!("Kucoin:撤销订单错误,该交易所为提供自定义订单号撤销订单!\ncancel_order:order_id={:?},custom_id={:?}", order_id, custom_id)
+//         }
+//         if res_data.code == 200 {
+//             let res_data_json = res_data.data;
+//             let cancel_ids = res_data_json["cancelledOrderIds"].as_array().unwrap();
+//             let id = cancel_ids[0].as_str().unwrap().to_string();
+//             let result = Order {
+//                 id,
+//                 custom_id: custom_id.to_string(),
+//                 price: Decimal::ZERO,
+//                 amount: Decimal::ZERO,
+//                 deal_amount: Decimal::ZERO,
+//                 avg_price: Decimal::ZERO,
+//                 status: "REMOVE".to_string(),
+//                 order_type: "".to_string(),
+//                 trace_stack: TraceStack::new(0, Instant::now()).on_special("436 kucoin_swap".to_string()),
+//             };
+//             Ok(result)
+//         } else {
+//             Err(Error::new(ErrorKind::Other, res_data.to_string()))
+//         }
+//     }
+//
+//     async fn cancel_orders(&mut self) -> Result<Vec<Order>, Error> {
+//         let symbol_mapper = utils::symbol_enter_mapper(ExchangeEnum::KucoinSwap, self.symbol.as_str());
+//         let symbol_format = format!("{}M", utils::format_symbol(symbol_mapper.clone(), ""));
+//         let res_data = self.request.cancel_orders(symbol_format).await;
+//         if res_data.code == 200 {
+//             info!("{}", res_data.data.to_string());
+//             let res_data_json = res_data.data;
+//             let cancel_ids = res_data_json["cancelledOrderIds"].as_array().unwrap();
+//             let result = cancel_ids.iter().map(|item|
+//                 Order {
+//                     id: item.as_str().unwrap().to_string(),
+//                     custom_id: "".to_string(),
+//                     price: Decimal::ZERO,
+//                     amount: Decimal::ZERO,
+//                     deal_amount: Decimal::ZERO,
+//                     avg_price: Decimal::ZERO,
+//                     status: "REMOVE".to_string(),
+//                     order_type: "".to_string(),
+//                     trace_stack: TraceStack::new(0, Instant::now()).on_special("461 kucoin_swap".to_string()),
+//                 }
+//             ).collect();
+//             Ok(result)
+//         } else {
+//             Err(Error::new(ErrorKind::Other, res_data.to_string()))
+//         }
+//     }
+//
+//     async fn cancel_orders_all(&mut self) -> Result<Vec<Order>, Error> {
+//         let res_data = self.request.cancel_order_all().await;
+//         if res_data.code == 200 {
+//             info!("{}", res_data.data.to_string());
+//             let res_data_json = res_data.data;
+//             let cancel_ids = res_data_json["cancelledOrderIds"].as_array().unwrap();
+//             let result = cancel_ids.iter().map(|item|
+//                 Order {
+//                     id: item.as_str().unwrap().to_string(),
+//                     custom_id: "".to_string(),
+//                     price: Decimal::ZERO,
+//                     amount: Decimal::ZERO,
+//                     deal_amount: Decimal::ZERO,
+//                     avg_price: Decimal::ZERO,
+//                     status: "REMOVE".to_string(),
+//                     order_type: "".to_string(),
+//                     trace_stack: TraceStack::new(0, Instant::now()).on_special("486 kucoin_swap".to_string()),
+//                 }
+//             ).collect();
+//             Ok(result)
+//         } else {
+//             Err(Error::new(ErrorKind::Other, res_data.to_string()))
+//         }
+//     }
+//
+//     async fn take_stop_loss_order(&mut self, _stop_price: Decimal, _price: Decimal, _side: &str) -> Result<Value, Error> {
+//         Err(Error::new(ErrorKind::NotFound, "kucoin_swap:该交易所方法未实现".to_string()))
+//     }
+//
+//     async fn cancel_stop_loss_order(&mut self, _order_id: &str) -> Result<Value, Error> {
+//         Err(Error::new(ErrorKind::NotFound, "kucoin_swap:该交易所方法未实现".to_string()))
+//     }
+//
+//     async fn set_dual_mode(&mut self, _coin: &str, _is_dual_mode: bool) -> Result<String, Error> {
+//         Err(Error::new(ErrorKind::NotFound, "kucoin_swap:该交易所方法未实现".to_string()))
+//     }
+//
+//     async fn set_dual_leverage(&mut self, _leverage: &str) -> Result<String, Error> {
+//         Err(Error::new(ErrorKind::NotFound, "kucoin_swap:该交易所方法未实现".to_string()))
+//     }
+//
+//     async fn set_auto_deposit_status(&mut self, status: bool) -> Result<String, Error> {
+//         let symbol_mapper = utils::symbol_enter_mapper(ExchangeEnum::KucoinSwap, self.symbol.as_str());
+//         let symbol_format = format!("{}M", utils::format_symbol(symbol_mapper.clone(), ""));
+//         let res_data = self.request.auto_deposit_status(symbol_format, status).await;
+//         if res_data.code == 200 {
+//             Ok(res_data.data.to_string())
+//         } else {
+//             Err(Error::new(ErrorKind::Other, res_data.to_string()))
+//         }
+//     }
+//
+//     async fn wallet_transfers(&mut self, _coin: &str, _from: &str, _to: &str, _amount: Decimal) -> Result<String, Error> {
+//         Err(Error::new(ErrorKind::NotFound, "kucoin_swap:该交易所方法未实现".to_string()))
+//     }
+//
+//     // 指令下单
+//     async fn command_order(&mut self, order_command: &mut OrderCommand, trace_stack: &TraceStack) {
+//         let mut handles = vec![];
+//         // 下单指令,limits_open里已经包含了limits_close,在core里面处理过了
+//         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();
+//
+//             let mut self_clone = self.clone();
+//             let handle = tokio::spawn(async move {
+//                 ts.on_before_send();
+//                 let result = self_clone.take_order(&cid, &side, price, amount).await;
+//                 ts.on_after_send();
+//
+//                 match result {
+//                     Ok(mut result) => {
+//                         // ts.on_after_send();
+//                         result.trace_stack = ts.clone();
+//
+//                         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();
+//
+//                         self_clone.order_sender.send(err_order).await.unwrap();
+//                         self_clone.error_sender.send(error).await.unwrap();
+//                     }
+//                 }
+//             });
+//             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 = tokio::spawn(async move {
+//                 if order_id != "" {
+//                     let result = self_clone.cancel_order(&order_id, &custom_id).await;
+//                     match result {
+//                         Ok(_) => {
+//                             // result_sd.send(result).await.unwrap();
+//                         }
+//                         Err(error) => {
+//                             // 取消失败去查订单。
+//                             let query_rst = self_clone.get_order_detail(&order_id, &custom_id).await;
+//                             match query_rst {
+//                                 Ok(order) => {
+//                                     self_clone.order_sender.send(order).await.unwrap();
+//                                 }
+//                                 Err(_query_err) => {
+//                                     // error!(?_query_err);
+//                                     // error!("撤单失败,而且查单也失败了,kucoin_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 = tokio::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_order_item(order: Value, ct_val: Decimal) -> Order {
+//     let price = Decimal::from_str(order["price"].as_str().unwrap()).unwrap();
+//     let size = Decimal::from_f64(order["size"].as_f64().unwrap()).unwrap();
+//     let status = order["status"].as_str().unwrap_or("");
+//     let filled_size = Decimal::from_f64(order["filledSize"].as_f64().unwrap()).unwrap();
+//     let filled_value = Decimal::from_str(order["filledValue"].as_str().unwrap()).unwrap();
+//
+//     let amount = size * ct_val;
+//     let deal_amount = filled_size * ct_val;
+//     let avg_price = if deal_amount.is_zero() { Decimal::ZERO } else { filled_value / deal_amount };
+//     let custom_status;
+//     if ["cancelled", "closed", "finished"].contains(&status) {
+//         custom_status = "REMOVE".to_string();
+//     } else if status == "open" {
+//         custom_status = "NEW".to_string();
+//     } else {
+//         custom_status = "NULL".to_string();
+//     };
+//     Order {
+//         id: order["id"].as_str().unwrap().to_string(),
+//         custom_id: order["clientOid"].as_str().unwrap_or("").to_string(),
+//         price,
+//         amount,
+//         deal_amount,
+//         avg_price,
+//         status: custom_status,
+//         order_type: order["type"].as_str().unwrap().to_string(),
+//         trace_stack: TraceStack::new(0, Instant::now()).on_special("655 kucoin_swap".to_string()),
+//     }
+// }

+ 136 - 0
standard/src/kucoin_swap_handle.rs

@@ -0,0 +1,136 @@
+// use std::str::FromStr;
+// use rust_decimal::Decimal;
+// use rust_decimal::prelude::FromPrimitive;
+// use serde_json::Value;
+// use exchanges::response_base::ResponseData;
+// use crate::{Order, OrderBook, Position, PositionModeEnum, Record, SpecialOrder, Trade, utils};
+// use crate::exchange::ExchangeEnum;
+// use crate::utils::symbol_out_mapper;
+//
+// pub fn format_trade_items(response: &ResponseData) -> Vec<Trade> {
+//     let data = response.clone().data;
+//     let symbol = symbol_out_mapper(ExchangeEnum::KucoinSwap, &data["symbol"].as_str().unwrap().to_string().replace("USDTM", "_USDT"));
+//     let side = data["side"].as_str().unwrap() == "buy";
+//
+//     let id = data["tradeId"].as_str().unwrap().to_string();
+//     let time = Decimal::from_i64(data["ts"].as_i64().unwrap() / 1000 / 1000).unwrap();
+//     let size = Decimal::from_f64(data["size"].as_f64().unwrap()).unwrap();
+//     let price = Decimal::from_f64(data["price"].as_str().unwrap().parse::<f64>().unwrap()).unwrap();
+//
+//     return vec![Trade {
+//         id,
+//         time,
+//         size: if side { size } else { -size },
+//         price,
+//         symbol: symbol.clone(),
+//     }];
+// }
+//
+// pub fn handle_records(value: &Value) -> Vec<Record> {
+//     let time = Decimal::from_i64(value["time"].as_i64().unwrap()).unwrap();
+//     let info = value["candles"].as_array().unwrap();
+//     let open = Decimal::from_f64(info[1].as_str().unwrap().parse::<f64>().unwrap()).unwrap();
+//     let high = Decimal::from_f64(info[3].as_str().unwrap().parse::<f64>().unwrap()).unwrap();
+//     let low = Decimal::from_f64(info[4].as_str().unwrap().parse::<f64>().unwrap()).unwrap();
+//     let close = Decimal::from_f64(info[2].as_str().unwrap().parse::<f64>().unwrap()).unwrap();
+//     let volume = Decimal::from_f64(info[6].as_str().unwrap().parse::<f64>().unwrap()).unwrap();
+//     let symbol = symbol_out_mapper(ExchangeEnum::KucoinSwap, &value["symbol"].as_str().unwrap().to_string().replace("USDTM", "_USDT"));
+//
+//     vec![Record {
+//         time,
+//         open,
+//         high,
+//         low,
+//         close,
+//         volume,
+//         symbol,
+//     }]
+// }
+//
+// pub fn format_depth_items(value: serde_json::Value) -> Vec<OrderBook> {
+//     let mut depth_items: Vec<OrderBook> = vec![];
+//     for value in value.as_array().unwrap() {
+//         depth_items.push(OrderBook {
+//             price: Decimal::from_str(value[0].as_str().unwrap()).unwrap(),
+//             amount: Decimal::from_f64(value[1].as_f64().unwrap()).unwrap(),
+//         })
+//     }
+//     return depth_items;
+// }
+//
+// pub fn format_position_item(position: &Value, ct_val: &Decimal) -> Position {
+//     let symbol = position["symbol"].as_str().unwrap_or("");
+//     let symbol_mapper = utils::symbol_out_mapper(ExchangeEnum::KucoinSwap, symbol);
+//     let real_leverage = Decimal::from_f64(position["realLeverage"].as_f64().unwrap()).unwrap();
+//     let currency = position["settleCurrency"].as_str().unwrap_or("");
+//     let coin = &symbol_mapper[..symbol_mapper.find(currency).unwrap_or(0)];
+//     let avg_entry_price = Decimal::from_f64(position["avgEntryPrice"].as_f64().unwrap()).unwrap();
+//     let unrealised_pnl = Decimal::from_f64(position["unrealisedPnl"].as_f64().unwrap()).unwrap();
+//     let pos_margin = Decimal::from_f64(position["posMargin"].as_f64().unwrap()).unwrap();
+//
+//     let current_qty = Decimal::from_f64(position["currentQty"].as_f64().unwrap()).unwrap();
+//     let amount = current_qty * ct_val;
+//     let position_mode = match amount {
+//         amount if amount > Decimal::ZERO => PositionModeEnum::Long,
+//         amount if amount < Decimal::ZERO => PositionModeEnum::Short,
+//         _ => { PositionModeEnum::Both }
+//     };
+//     Position {
+//         symbol: format!("{}_{}", coin, currency),
+//         margin_level: real_leverage,
+//         amount,
+//         frozen_amount: Decimal::ZERO,
+//         price: avg_entry_price,
+//         profit: unrealised_pnl,
+//         position_mode,
+//         margin: pos_margin,
+//     }
+// }
+//
+// // 处理position信息
+// pub fn handle_position(res_data: &ResponseData, ct_val: &Decimal) -> Vec<Position> {
+//     let result = format_position_item(&res_data.data, ct_val);
+//     return vec![result];
+// }
+//
+// // 处理order信息
+// pub fn handle_order(res_data: &ResponseData, ct_val: Decimal) -> SpecialOrder {
+//     let order_info = vec![format_order_item(&res_data.data, ct_val)];
+//
+//     SpecialOrder {
+//         name: res_data.label.clone(),
+//         order: order_info,
+//     }
+// }
+//
+// // ws处理
+// pub fn format_order_item(order: &Value, ct_val: Decimal) -> Order {
+//     let price = Decimal::from_str(order["price"].as_str().unwrap()).unwrap();
+//     let size = Decimal::from_str(order["size"].as_str().unwrap()).unwrap();
+//     let status = order["status"].as_str().unwrap_or("");
+//     let type_ = order["type"].as_str().unwrap_or("");
+//     let filled_size = Decimal::from_str(order["filledSize"].as_str().unwrap()).unwrap();
+//
+//     let avg_price = price;
+//
+//     let amount = size * ct_val;
+//     let deal_amount = filled_size * ct_val;
+//     let custom_status;
+//     if ["filled", "canceled"].contains(&type_) {
+//         custom_status = "REMOVE".to_string();
+//     } else if ["open"].contains(&status) {
+//         custom_status = "NEW".to_string();
+//     } else {
+//         custom_status = "NULL".to_string();
+//     }
+//     Order {
+//         id: order["orderId"].as_str().unwrap().to_string(),
+//         custom_id: order["clientOid"].as_str().unwrap_or("").to_string(),
+//         price,
+//         amount,
+//         deal_amount,
+//         avg_price,
+//         status: custom_status,
+//         order_type: order["type"].as_str().unwrap().to_string()
+//     }
+// }

+ 142 - 48
standard/src/lib.rs

@@ -5,16 +5,16 @@ use std::io::{Error};
 use async_trait::async_trait;
 use rust_decimal::Decimal;
 use serde_json::Value;
+use serde::{Serialize, Deserialize};
 use tokio::time::Instant;
 use global::trace_stack::TraceStack;
-
 use crate::exchange::ExchangeEnum;
 
 // 引入工具模块
 pub mod utils;
 // 引入exchange模块
 pub mod exchange;
-pub mod handle_info;
+pub mod exchange_struct_handler;
 // 引入binance模块
 mod binance_swap;
 mod binance_spot;
@@ -24,10 +24,11 @@ pub mod binance_spot_handle;
 mod gate_swap;
 mod gate_spot;
 pub mod gate_swap_handle;
+pub mod gate_spot_handle;
 mod kucoin_swap;
-pub mod kucoin_handle;
+mod kucoin_swap_handle;
 mod okx_swap;
-pub mod okx_handle;
+pub mod okx_swap_handle;
 mod bitget_spot;
 pub mod bitget_spot_handle;
 mod kucoin_spot;
@@ -38,19 +39,22 @@ mod bitget_swap;
 mod bitget_swap_handle;
 mod coinex_swap;
 mod coinex_swap_handle;
+mod htx_swap_handle;
 mod htx_swap;
-pub mod htx_swap_handle;
-
-/// 持仓模式枚举
-/// - `Both`:单持仓方向
-/// - `LONG`:多仓
-/// - `SHORT`:空仓
-#[derive(Debug, Clone, PartialEq, Eq)]
-pub enum PositionModeEnum {
-    Both,
-    Long,
-    Short,
-}
+mod bingx_swap;
+mod bingx_swap_handle;
+mod mexc_swap;
+mod mexc_swap_handle;
+mod bitmart_swap;
+mod bitmart_swap_handle;
+mod coinsph_swap;
+mod coinsph_swap_handle;
+mod phemex_swap;
+mod phemex_swap_handle;
+mod woo_swap;
+mod woo_swap_handle;
+mod cointr_swap;
+mod cointr_swap_handle;
 
 /// OrderCommand结构体(下单指令)
 /// - `cancel(HashMap<String, Vec<String>)`: 取消订单指令 `{"order_name": [c_id, o_id]}`;
@@ -95,6 +99,17 @@ impl fmt::Display for OrderCommand {
     }
 }
 
+/// 持仓模式枚举
+/// - `Both`:单持仓方向
+/// - `LONG`:多仓
+/// - `SHORT`:空仓
+#[derive(Debug, Clone, PartialEq, Eq)]
+pub enum PositionModeEnum {
+    Both,
+    Long,
+    Short,
+}
+
 /// Account结构体(账户信息)
 /// - `coin(String)`: 货币;
 /// - `balance(Decimal)`: 总计计价币数量;
@@ -128,50 +143,126 @@ impl Account {
     }
 }
 
+/// 交易结构体(订单流)
+/// - `id(String)`: id
+/// - `time(Decimal)`: 交易更新时间戳(ms)
+/// - `size(Decimal)`: 交易量,负数是卖方
+/// - `price(Decimal)`: 成交价格
+/// - `symbol(String)`: 成交符号
+#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
+pub struct Trade {
+    pub id: String,
+    pub time: Decimal,
+    pub size: Decimal,
+    pub price: Decimal,
+    pub symbol: String
+}
+
+/// 特殊压缩结构体(订单流)
+/// - `0(Decimal)`: id
+/// - `1(Decimal)`: 交易更新时间戳(ms)
+/// - `2(Decimal)`: 交易量,负数是卖方
+/// - `3(Decimal)`: 成交价格
+#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
+pub struct SpecialTrade(pub Vec<String>);
+impl SpecialTrade {
+    // 获取内部 Vec<Decimal> 的引用
+    pub fn inner(&self) -> &Vec<String> {
+        &self.0
+    }
+
+    // 获取内部 Vec<Decimal> 的可变引用
+    pub fn inner_mut(&mut self) -> &mut Vec<String> {
+        &mut self.0
+    }
+
+    // 索引访问特定元素
+    pub fn get(&self, index: usize) -> Option<&String> {
+        self.0.get(index)
+    }
+
+    pub fn new(trade: &Trade) -> SpecialTrade {
+        SpecialTrade(vec![trade.id.clone(), trade.time.to_string(), trade.size.to_string(), trade.price.to_string()])
+    }
+}
+
 /// Depth结构体(市场深度)
-/// - `time(i64)`: 深度更新时间戳(ms);
+/// - `time(Decimal)`: 深度更新时间戳(ms);
+/// - `symbol(String)`: 币对符号;
 /// - `asks(Vec<MarketOrder>)`: 卖方深度列表;
 /// - `bids(Vec<MarketOrder>)`: 买方深度列表;
-#[derive(Debug, Clone, PartialEq, Eq)]
+#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
 pub struct Depth {
-    pub time: i64,
-    pub asks: Vec<MarketOrder>,
-    pub bids: Vec<MarketOrder>,
+    pub time: Decimal,
+    pub symbol: String,
+    pub asks: Vec<OrderBook>,
+    pub bids: Vec<OrderBook>,
 }
 
 impl Depth {
     pub fn new() -> Depth {
         Depth {
-            time: 0,
+            time: Decimal::ZERO,
+            symbol: String::new(),
             asks: vec![],
             bids: vec![],
         }
     }
 }
 
-/// 特殊Depth结构体(市场深度)
-/// - `name<String>`: 平台信息;
-/// - `depth(Vec<Decimal>)`: 深度信息;
-/// - `ticker(SpecialTicker)`: 市场行情;
-/// - `t(Decimal)`: 数据更新id
-/// - `create_at(i64)`: 数据生成时间
-#[derive(Debug, Clone, PartialEq, Eq)]
+/// 特殊Depth结构体(市场深度),用于存放到本地数据库中
+/// - `a(Vec<Vec<Decimal>>)`: asks;
+/// - `b(Vec<Vec<Decimal>>)`: bids;
+/// - `t(Decimal)`: 数据生成时间
+#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
 pub struct SpecialDepth {
-    pub name: String,
-    pub depth: Vec<Decimal>,
-    pub ticker: SpecialTicker,
+    pub b: Vec<Vec<Decimal>>,
+    pub a: Vec<Vec<Decimal>>,
     pub t: Decimal,
-    pub create_at: i64,
 }
 
 impl SpecialDepth {
-    pub fn new() -> SpecialDepth {
+    pub fn new(depth: &Depth) -> SpecialDepth {
+        let bids = depth.bids.iter().map(|ob| vec![ob.price, ob.amount]).collect::<Vec<_>>();
+        let asks = depth.asks.iter().map(|ob| vec![ob.price, ob.amount]).collect::<Vec<_>>();
         SpecialDepth {
-            name: "".to_string(),
-            depth: vec![],
-            ticker: SpecialTicker::new(),
-            t: Default::default(),
-            create_at: 0,
+            b: bids,
+            a: asks,
+            t: depth.time,
+        }
+    }
+}
+
+// 简易深度信息
+#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
+pub struct SimpleDepth {
+    pub time: Decimal,
+    pub size: Decimal,
+    pub b1: Decimal,
+    pub a1: Decimal,
+    pub symbol: String,
+}
+
+impl SimpleDepth {
+    pub fn new(depth: &Depth) -> SimpleDepth {
+        let mut total_size = Decimal::ZERO;
+
+        for ask in &depth.asks {
+            total_size += ask.price * ask.amount;
+        }
+
+        for bid in &depth.bids {
+            total_size += bid.price * bid.amount;
+        }
+
+        total_size.rescale(2);
+
+        SimpleDepth {
+            time: depth.time,
+            size: total_size,
+            b1: depth.bids[0].price,
+            a1: depth.asks[0].price,
+            symbol: depth.symbol.clone(),
         }
     }
 }
@@ -203,18 +294,18 @@ impl SpecialTicker {
     }
 }
 
-/// MarketOrder结构体(市场深度单)
+/// OrderBook结构体(市场深度单)
 /// - `price(Decimal)`: 价格
 /// - `amount(Decimal)`: 数量
-#[derive(Debug, Clone, PartialEq, Eq)]
-pub struct MarketOrder {
+#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
+pub struct OrderBook {
     pub price: Decimal,
     pub amount: Decimal,
 }
 
-impl MarketOrder {
-    pub fn new() -> MarketOrder {
-        MarketOrder {
+impl OrderBook {
+    pub fn new() -> OrderBook {
+        OrderBook {
             price: Default::default(),
             amount: Default::default(),
         }
@@ -228,25 +319,28 @@ impl MarketOrder {
 /// - `low(Decimal):` 最低价;
 /// - `close(Decimal)`: 收盘价;
 /// - `volume(Decimal)`: 交易量;
-#[derive(Debug, Clone, PartialEq, Eq)]
+/// - `symbol(String)`: 交易对;
+#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
 pub struct Record {
-    pub time: i64,
+    pub time: Decimal,
     pub open: Decimal,
     pub high: Decimal,
     pub low: Decimal,
     pub close: Decimal,
     pub volume: Decimal,
+    pub symbol: String
 }
 
 impl Record {
     pub fn new() -> Record {
         Record {
-            time: 0,
+            time: Default::default(),
             open: Default::default(),
             high: Default::default(),
             low: Default::default(),
             close: Default::default(),
             volume: Default::default(),
+            symbol: "".to_string(),
         }
     }
 }

+ 261 - 0
standard/src/mexc_swap.rs

@@ -0,0 +1,261 @@
+// use std::collections::{BTreeMap};
+// use std::io::{Error, ErrorKind};
+// use tokio::sync::mpsc::Sender;
+// use async_trait::async_trait;
+// use rust_decimal::{Decimal};
+// use serde_json::{json, Value};
+// use tracing::{error, info};
+// use crate::{Platform, ExchangeEnum, Account, Position, Ticker, Market, Order, utils};
+// use exchanges::mexc_swap_rest::MexcSwapRest;
+// use rust_decimal::prelude::FromPrimitive;
+//
+// #[allow(dead_code)]
+// #[derive(Clone)]
+// pub struct MexcSwap {
+//     exchange: ExchangeEnum,
+//     symbol: String,
+//     is_colo: bool,
+//     params: BTreeMap<String, String>,
+//     request: MexcSwapRest,
+//     market: Market,
+//     order_sender: Sender<Order>,
+//     error_sender: Sender<Error>,
+// }
+//
+// impl MexcSwap {
+//     pub async fn new(symbol: String, is_colo: bool, params: BTreeMap<String, String>, order_sender: Sender<Order>, error_sender: Sender<Error>) -> MexcSwap {
+//         let market = Market::new();
+//         let mut mexc_swap = MexcSwap {
+//             exchange: ExchangeEnum::MexcSwap,
+//             symbol: symbol.to_uppercase(),
+//             is_colo,
+//             params: params.clone(),
+//             request: MexcSwapRest::new(is_colo, params.clone()),
+//             market,
+//             order_sender,
+//             error_sender,
+//         };
+//
+//         // 修改持仓模式
+//         let symbol_array: Vec<&str> = symbol.split("_").collect();
+//         let mode_result = mexc_swap.set_dual_mode(symbol_array[1], true).await;
+//         match mode_result {
+//             Ok(ok) => {
+//                 info!("Mexc:设置持仓模式成功!{:?}", ok);
+//             }
+//             Err(error) => {
+//                 error!("Mexc:设置持仓模式失败!mode_result={}", error)
+//             }
+//         }
+//         // 获取市场信息
+//         mexc_swap.market = MexcSwap::get_market(&mut mexc_swap).await.unwrap_or(mexc_swap.market);
+//         return mexc_swap;
+//     }
+// }
+//
+// #[async_trait]
+// impl Platform for MexcSwap {
+//     // 克隆方法
+//     fn clone_box(&self) -> Box<dyn Platform + Send + Sync> { Box::new(self.clone()) }
+//     // 获取交易所模式
+//     fn get_self_exchange(&self) -> ExchangeEnum {
+//         ExchangeEnum::MexcSwap
+//     }
+//     // 获取交易对
+//     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> {
+//         Err(Error::new(ErrorKind::NotFound, "mexc_swap:该交易所方法未实现".to_string()))
+//     }
+//     // 获取账号信息
+//     async fn get_account(&mut self) -> Result<Account, Error> {
+//         Err(Error::new(ErrorKind::NotFound, "mexc_swap:该交易所方法未实现".to_string()))
+//     }
+//
+//     async fn get_spot_account(&mut self) -> Result<Vec<Account>, Error> {
+//         Err(Error::new(ErrorKind::NotFound, "mexc_swap:该交易所方法未实现".to_string()))
+//     }
+//
+//     // 获取持仓信息
+//     async fn get_position(&mut self) -> Result<Vec<Position>, Error> {
+//         Err(Error::new(ErrorKind::NotFound, "mexc_swap:该交易所方法未实现".to_string()))
+//     }
+//     // 获取所有持仓
+//     async fn get_positions(&mut self) -> Result<Vec<Position>, Error> {
+//         Err(Error::new(ErrorKind::NotFound, "mexc_swap:该交易所方法未实现".to_string()))
+//     }
+//     // 获取市场行情
+//     async fn get_ticker(&mut self) -> Result<Ticker, Error> {
+//         Err(Error::new(ErrorKind::NotFound, "mexc_swap:该交易所方法未实现".to_string()))
+//     }
+//
+//     async fn get_ticker_symbol(&mut self, _symbol: String) -> Result<Ticker, Error> {
+//         Err(Error::new(ErrorKind::NotFound, "mexc_swap:该交易所方法未实现".to_string()))
+//     }
+//
+//     async fn get_market(&mut self) -> Result<Market, Error> {
+//         let symbol_format = utils::format_symbol(self.symbol.clone(), "_");
+//         let params = json!({});
+//         let res_data = self.request.get_market(params).await;
+//         if res_data.code == 200 {
+//             let res_data_json = res_data.data.as_array().unwrap();
+//             let market_info = res_data_json.iter().find(|item| item["symbol"].as_str().unwrap() == symbol_format);
+//             match market_info {
+//                 None => {
+//                     error!("mexc_swap:获取Market信息错误!\nget_market:res_data={:?}", res_data);
+//                     Err(Error::new(ErrorKind::Other, res_data.to_string()))
+//                 }
+//                 Some(value) => {
+//                     let symbol = value["symbol"].as_str().unwrap().to_string();
+//                     let base_asset = value["baseCoin"].as_str().unwrap().to_string();
+//                     let quote_asset = value["quoteCoin"].as_str().unwrap().to_string();
+//                     let tick_size = Decimal::from_i64(value["priceUnit"].as_i64().unwrap()).unwrap();
+//                     let amount_size = Decimal::from_i64(value["volUnit"].as_i64().unwrap()).unwrap();
+//                     let price_precision = Decimal::from_i64(value["priceScale"].as_i64().unwrap()).unwrap();
+//                     let amount_precision = Decimal::from_i64(value["volScale"].as_i64().unwrap()).unwrap();
+//                     let min_qty = Decimal::from_i64(value["minVol"].as_i64().unwrap()).unwrap();
+//                     let max_qty = Decimal::from_i64(value["maxVol"].as_i64().unwrap()).unwrap();
+//                     let ct_val = Decimal::from_i64(value["contractSize"].as_i64().unwrap()).unwrap();
+//
+//                     let result = Market {
+//                         symbol,
+//                         base_asset,
+//                         quote_asset,
+//                         tick_size,
+//                         amount_size,
+//                         price_precision,
+//                         amount_precision,
+//                         min_qty,
+//                         max_qty,
+//                         min_notional: min_qty,
+//                         max_notional: max_qty,
+//                         ct_val,
+//                     };
+//                     Ok(result)
+//                 }
+//             }
+//         } else {
+//             Err(Error::new(ErrorKind::Other, res_data.to_string()))
+//         }
+//     }
+//
+//     async fn get_market_symbol(&mut self, symbol: String) -> Result<Market, Error> {
+//         let symbol_format = utils::format_symbol(symbol.clone(), "-");
+//         let params = json!({
+//             "symbol": symbol_format.clone()
+//         });
+//         let res_data = self.request.get_market(params).await;
+//         if res_data.code == 200 {
+//             let res_data_json = res_data.data.as_array().unwrap();
+//             let market_info = res_data_json.iter().find(|item| item["symbol"].as_str().unwrap() == symbol_format);
+//             match market_info {
+//                 None => {
+//                     error!("mexc_swap:获取Market信息错误!\nget_market:res_data={:?}", res_data);
+//                     Err(Error::new(ErrorKind::Other, res_data.to_string()))
+//                 }
+//                 Some(value) => {
+//                     let symbol = value["symbol"].as_str().unwrap().to_string();
+//                     let base_asset = value["baseCoin"].as_str().unwrap().to_string();
+//                     let quote_asset = value["quoteCoin"].as_str().unwrap().to_string();
+//                     let tick_size = Decimal::from_i64(value["priceUnit"].as_i64().unwrap()).unwrap();
+//                     let amount_size = Decimal::from_i64(value["volUnit"].as_i64().unwrap()).unwrap();
+//                     let price_precision = Decimal::from_i64(value["priceScale"].as_i64().unwrap()).unwrap();
+//                     let amount_precision = Decimal::from_i64(value["volScale"].as_i64().unwrap()).unwrap();
+//                     let min_qty = Decimal::from_i64(value["minVol"].as_i64().unwrap()).unwrap();
+//                     let max_qty = Decimal::from_i64(value["maxVol"].as_i64().unwrap()).unwrap();
+//                     let ct_val = Decimal::from_i64(value["contractSize"].as_i64().unwrap()).unwrap();
+//
+//                     let result = Market {
+//                         symbol,
+//                         base_asset,
+//                         quote_asset,
+//                         tick_size,
+//                         amount_size,
+//                         price_precision,
+//                         amount_precision,
+//                         min_qty,
+//                         max_qty,
+//                         min_notional: min_qty,
+//                         max_notional: max_qty,
+//                         ct_val,
+//                     };
+//                     Ok(result)
+//                 }
+//             }
+//         } else {
+//             Err(Error::new(ErrorKind::Other, res_data.to_string()))
+//         }
+//     }
+//
+//     // 获取订单详情
+//     async fn get_order_detail(&mut self, _order_id: &str, _custom_id: &str) -> Result<Order, Error> {
+//         Err(Error::new(ErrorKind::NotFound, "mexc_swap:该交易所方法未实现".to_string()))
+//     }
+//     // 获取订单列表
+//     async fn get_orders_list(&mut self, _status: &str) -> Result<Vec<Order>, Error> {
+//         Err(Error::new(ErrorKind::NotFound, "mexc_swap:该交易所方法未实现".to_string()))
+//     }
+//     // 下单接口
+//     async fn take_order(&mut self, _custom_id: &str, _origin_side: &str, _price: Decimal, _amount: Decimal) -> Result<Order, Error> {
+//         Err(Error::new(ErrorKind::NotFound, "mexc_swap:该交易所方法未实现".to_string()))
+//     }
+//
+//     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> {
+//         Err(Error::new(ErrorKind::NotFound, "mexc_swap:该交易所方法未实现".to_string()))
+//     }
+//
+//     // 撤销订单
+//     async fn cancel_order(&mut self, _order_id: &str, _custom_id: &str) -> Result<Order, Error> {
+//         Err(Error::new(ErrorKind::NotFound, "mexc_swap:该交易所方法未实现".to_string()))
+//     }
+//     // 批量撤销订单
+//     async fn cancel_orders(&mut self) -> Result<Vec<Order>, Error> {
+//         Err(Error::new(ErrorKind::NotFound, "mexc_swap:该交易所方法未实现".to_string()))
+//     }
+//
+//     async fn cancel_orders_all(&mut self) -> Result<Vec<Order>, Error> {
+//         Err(Error::new(ErrorKind::NotFound, "mexc_swap:该交易所方法未实现".to_string()))
+//     }
+//
+//     async fn take_stop_loss_order(&mut self, _stop_price: Decimal, _price: Decimal, _side: &str) -> Result<Value, Error> {
+//         Err(Error::new(ErrorKind::NotFound, "mexc_swap:该交易所方法未实现".to_string()))
+//     }
+//
+//     async fn cancel_stop_loss_order(&mut self, _order_id: &str) -> Result<Value, Error> {
+//         Err(Error::new(ErrorKind::NotFound, "mexc_swap:该交易所方法未实现".to_string()))
+//     }
+//
+//     // 设置持仓模式
+//     async fn set_dual_mode(&mut self, _coin: &str, _is_dual_mode: bool) -> Result<String, Error> {
+//         Err(Error::new(ErrorKind::NotFound, "mexc_swap:该交易所方法未实现".to_string()))
+//     }
+//
+//     // 更新双持仓模式下杠杆
+//     async fn set_dual_leverage(&mut self, _leverage: &str) -> Result<String, Error> {
+//         Err(Error::new(ErrorKind::NotFound, "mexc_swap:该交易所方法未实现".to_string()))
+//     }
+//
+//     async fn set_auto_deposit_status(&mut self, _status: bool) -> Result<String, Error> { Err(Error::new(ErrorKind::NotFound, "mexc:该交易所方法未实现".to_string())) }
+//
+//     // 交易账户互转
+//     async fn wallet_transfers(&mut self, _coin: &str, _from: &str, _to: &str, _amount: Decimal) -> Result<String, Error> {
+//         Err(Error::new(ErrorKind::NotFound, "mexc_swap:该交易所方法未实现".to_string()))
+//     }
+// }

+ 92 - 0
standard/src/mexc_swap_handle.rs

@@ -0,0 +1,92 @@
+// use rust_decimal::Decimal;
+// use rust_decimal::prelude::FromPrimitive;
+// use serde_json::Value;
+// use exchanges::response_base::ResponseData;
+// use crate::{OrderBook, Trade, Record};
+// // use crate::{Account, OrderBook, Order, Position, SpecialOrder, Trade, Record};
+//
+// // 处理账号信息
+// // pub fn handle_account_info(res_data: &ResponseData, symbol: &String) -> Account {
+// //     Account::new()
+// // }
+// //
+// // pub fn format_account_info(_data: &Vec<Value>, _symbol: &String) -> Account {
+// //     Account::new()
+// // }
+// //
+// // // 处理position信息
+// // pub fn handle_position(_res_data: &ResponseData, _ct_val: &Decimal) -> Vec<Position> {
+// //     vec![Position::new()]
+// // }
+// //
+// // pub fn format_position_item(_position: &Value, _ct_val: &Decimal) -> Position {
+// //     Position::new()
+// // }
+// //
+// // // 处理order信息
+// // pub fn handle_order(_res_data: &ResponseData, _ct_val: Decimal) -> SpecialOrder {
+// //     SpecialOrder::new()
+// // }
+// //
+// // pub fn format_order_item(_order: Value, _ct_val: Decimal) -> Order {
+// //     Order::new()
+// // }
+// // 处理特殊Ticket信息
+// // pub fn handle_book_ticker(res_data: &ResponseData) -> SpecialDepth {
+// //     let bp = Decimal::from_str((*res_data).data["b"].as_str().unwrap()).unwrap();
+// //     let bq = Decimal::from_f64((*res_data).data["B"].as_f64().unwrap()).unwrap();
+// //     let ap = Decimal::from_str((*res_data).data["a"].as_str().unwrap()).unwrap();
+// //     let aq = Decimal::from_f64((*res_data).data["A"].as_f64().unwrap()).unwrap();
+// //     let mp = (bp + ap) * dec!(0.5);
+// //     let t = Decimal::from_u64((*res_data).data["u"].as_u64().unwrap()).unwrap();
+// //     let create_at = (*res_data).data["t"].as_i64().unwrap() * 1000;
+// //
+// //     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).tag.clone(),
+// //         depth: depth_info,
+// //         ticker: ticker_info,
+// //         t,
+// //         create_at,
+// //     }
+// // }
+//
+// pub fn handle_records(value: &Value) -> Vec<Record> {
+//     let data = value["data"].clone();
+//     return vec![Record {
+//         time: Decimal::from_i64(data["t"].as_i64().unwrap() * 1000).unwrap(),
+//         open: Decimal::from_f64(data["o"].as_f64().unwrap()).unwrap(),
+//         high: Decimal::from_f64(data["h"].as_f64().unwrap()).unwrap(),
+//         low: Decimal::from_f64(data["l"].as_f64().unwrap()).unwrap(),
+//         close: Decimal::from_f64(data["c"].as_f64().unwrap()).unwrap(),
+//         volume: Decimal::from_f64(data["q"].as_f64().unwrap()).unwrap(),
+//         symbol: data["symbol"].as_str().unwrap().to_string(),
+//     }];
+// }
+//
+// pub fn format_depth_items(value: &Value) -> Vec<OrderBook> {
+//     let mut depth_items: Vec<OrderBook> = vec![];
+//     for value in value.as_array().unwrap() {
+//         depth_items.push(OrderBook {
+//             price: Decimal::from_f64(value[0].as_f64().unwrap()).unwrap(),
+//             amount: Decimal::from_f64(value[1].as_f64().unwrap()).unwrap(),
+//         })
+//     }
+//     return depth_items;
+// }
+//
+// pub fn format_trade_items(res_data: &ResponseData) -> Vec<Trade> {
+//     let result = res_data.data["data"].clone();
+//
+//     let side = result["T"].as_i64().unwrap() == 1;
+//     let size = Decimal::from_f64(result["v"].as_f64().unwrap()).unwrap();
+//     return vec![Trade {
+//         id: result["t"].to_string(),
+//         time: Decimal::from_i64(result["t"].as_i64().unwrap()).unwrap(),
+//         size: if side { size } else { -size },
+//         price: Decimal::from_f64(result["p"].as_f64().unwrap()).unwrap(),
+//         symbol: res_data.data["symbol"].as_str().unwrap().to_string(),
+//     }];
+// }

+ 54 - 0
standard/src/okx_swap_handle.rs

@@ -0,0 +1,54 @@
+use std::str::FromStr;
+use rust_decimal::Decimal;
+use rust_decimal::prelude::FromPrimitive;
+use serde_json::Value;
+use exchanges::response_base::ResponseData;
+use crate::{OrderBook, Trade, Record};
+
+pub fn handle_records(value: &Value) -> Vec<Record> {
+    let symbol = value["arg"]["instId"].as_str().unwrap().to_string().replace("-", "_");
+    let records_list = value["data"].as_array().unwrap();
+    let mut records = vec![];
+
+    for record_value in records_list {
+        records.push(Record {
+            time: Decimal::from_str(record_value[0].as_str().unwrap()).unwrap(),
+            open: Decimal::from_str(record_value[1].as_str().unwrap()).unwrap(),
+            high: Decimal::from_str(record_value[2].as_str().unwrap()).unwrap(),
+            low: Decimal::from_str(record_value[3].as_str().unwrap()).unwrap(),
+            close: Decimal::from_str(record_value[4].as_str().unwrap()).unwrap(),
+            volume: Decimal::from_str(record_value[5].as_str().unwrap()).unwrap(),
+            symbol: symbol.clone(),
+        });
+    }
+    records
+}
+
+pub fn format_depth_items(value: &Value) -> Vec<OrderBook> {
+    let mut depth_items: Vec<OrderBook> = vec![];
+    for value in value.as_array().unwrap() {
+        depth_items.push(OrderBook {
+            price: Decimal::from_f64(value[0].as_f64().unwrap()).unwrap(),
+            amount: Decimal::from_f64(value[1].as_f64().unwrap()).unwrap(),
+        })
+    }
+    return depth_items;
+}
+
+pub fn format_trade_items(res_data: &ResponseData) -> Vec<Trade> {
+    let result = res_data.data["data"].as_array().unwrap();
+    let mut trades = vec![];
+
+    for item in result {
+        let side = item["side"].as_str().unwrap() == "buy";
+        let size = Decimal::from_str(item["sz"].as_str().unwrap()).unwrap();
+        trades.push(Trade {
+            id: item["tradeId"].as_str().unwrap().to_string(),
+            time: Decimal::from_str(item["ts"].as_str().unwrap()).unwrap(),
+            size: if side { size } else { -size },
+            price: Decimal::from_str(item["px"].as_str().unwrap().to_string().as_str()).unwrap(),
+            symbol: item["instId"].as_str().unwrap().to_string().replace("-", "_"),
+        })
+    }
+    trades
+}

+ 265 - 0
standard/src/phemex_swap.rs

@@ -0,0 +1,265 @@
+// use std::collections::{BTreeMap};
+// use std::io::{Error, ErrorKind};
+// use std::str::FromStr;
+// use tokio::sync::mpsc::Sender;
+// use async_trait::async_trait;
+// use rust_decimal::{Decimal};
+// use serde_json::{json, Value};
+// use tracing::{error, info};
+// use crate::{Platform, ExchangeEnum, Account, Position, Ticker, Market, Order, utils};
+// use exchanges::phemex_swap_rest::PhemexSwapRest;
+//
+// #[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 symbol_array: Vec<&str> = symbol.split("_").collect();
+//         let mode_result = phemex_swap.set_dual_mode(symbol_array[1], true).await;
+//         match mode_result {
+//             Ok(ok) => {
+//                 info!("Phemex:设置持仓模式成功!{:?}", ok);
+//             }
+//             Err(error) => {
+//                 error!("Phemex:设置持仓模式失败!mode_result={}", error)
+//             }
+//         }
+//         // 获取市场信息
+//         phemex_swap.market = PhemexSwap::get_market(&mut phemex_swap).await.unwrap_or(phemex_swap.market);
+//         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> {
+//         Err(Error::new(ErrorKind::NotFound, "phemex_swap:该交易所方法未实现".to_string()))
+//     }
+//     // 获取账号信息
+//     async fn get_account(&mut self) -> Result<Account, Error> {
+//         Err(Error::new(ErrorKind::NotFound, "phemex_swap:该交易所方法未实现".to_string()))
+//     }
+//
+//     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> {
+//         Err(Error::new(ErrorKind::NotFound, "phemex_swap:该交易所方法未实现".to_string()))
+//     }
+//     // 获取所有持仓
+//     async fn get_positions(&mut self) -> Result<Vec<Position>, Error> {
+//         Err(Error::new(ErrorKind::NotFound, "phemex_swap:该交易所方法未实现".to_string()))
+//     }
+//     // 获取市场行情
+//     async fn get_ticker(&mut self) -> Result<Ticker, Error> {
+//         Err(Error::new(ErrorKind::NotFound, "phemex_swap:该交易所方法未实现".to_string()))
+//     }
+//
+//     async fn get_ticker_symbol(&mut self, _symbol: String) -> Result<Ticker, Error> {
+//         Err(Error::new(ErrorKind::NotFound, "phemex_swap:该交易所方法未实现".to_string()))
+//     }
+//
+//     async fn get_market(&mut self) -> Result<Market, Error> {
+//         let symbol_format = utils::format_symbol(self.symbol.clone(), "");
+//         let params = json!({});
+//         let res_data = self.request.get_market(params).await;
+//         if res_data.code == 200 {
+//             let res_data_json = res_data.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={:?}", res_data);
+//                     Err(Error::new(ErrorKind::Other, res_data.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)
+//                 }
+//             }
+//         } else {
+//             Err(Error::new(ErrorKind::Other, res_data.to_string()))
+//         }
+//     }
+//
+//     async fn get_market_symbol(&mut self, symbol: String) -> Result<Market, Error> {
+//         let symbol_format = utils::format_symbol(symbol.clone(), "");
+//         let params = json!({});
+//         let res_data = self.request.get_market(params).await;
+//         if res_data.code == 200 {
+//             let res_data_json = res_data.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={:?}", res_data);
+//                     Err(Error::new(ErrorKind::Other, res_data.to_string()))
+//                 }
+//                 Some(value) => {
+//                     let symbol = value["symbol"].as_str().unwrap().to_string();
+//                     let base_asset = value["baseCurrency"].as_str().unwrap().to_string();
+//                     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)
+//                 }
+//             }
+//         } else {
+//             Err(Error::new(ErrorKind::Other, res_data.to_string()))
+//         }
+//     }
+//
+//     // 获取订单详情
+//     async fn get_order_detail(&mut self, _order_id: &str, _custom_id: &str) -> Result<Order, Error> {
+//         Err(Error::new(ErrorKind::NotFound, "phemex_swap:该交易所方法未实现".to_string()))
+//     }
+//     // 获取订单列表
+//     async fn get_orders_list(&mut self, _status: &str) -> Result<Vec<Order>, Error> {
+//         Err(Error::new(ErrorKind::NotFound, "phemex_swap:该交易所方法未实现".to_string()))
+//     }
+//     // 下单接口
+//     async fn take_order(&mut self, _custom_id: &str, _origin_side: &str, _price: Decimal, _amount: Decimal) -> Result<Order, Error> {
+//         Err(Error::new(ErrorKind::NotFound, "phemex_swap:该交易所方法未实现".to_string()))
+//     }
+//
+//     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> {
+//         Err(Error::new(ErrorKind::NotFound, "phemex_swap:该交易所方法未实现".to_string()))
+//     }
+//
+//     // 撤销订单
+//     async fn cancel_order(&mut self, _order_id: &str, _custom_id: &str) -> Result<Order, Error> {
+//         Err(Error::new(ErrorKind::NotFound, "phemex_swap:该交易所方法未实现".to_string()))
+//     }
+//     // 批量撤销订单
+//     async fn cancel_orders(&mut self) -> Result<Vec<Order>, Error> {
+//         Err(Error::new(ErrorKind::NotFound, "phemex_swap:该交易所方法未实现".to_string()))
+//     }
+//
+//     async fn cancel_orders_all(&mut self) -> Result<Vec<Order>, Error> {
+//         Err(Error::new(ErrorKind::NotFound, "phemex_swap:该交易所方法未实现".to_string()))
+//     }
+//
+//     async fn take_stop_loss_order(&mut self, _stop_price: Decimal, _price: Decimal, _side: &str) -> Result<Value, Error> {
+//         Err(Error::new(ErrorKind::NotFound, "phemex_swap:该交易所方法未实现".to_string()))
+//     }
+//
+//     async fn cancel_stop_loss_order(&mut self, _order_id: &str) -> Result<Value, Error> {
+//         Err(Error::new(ErrorKind::NotFound, "phemex_swap:该交易所方法未实现".to_string()))
+//     }
+//
+//     // 设置持仓模式
+//     async fn set_dual_mode(&mut self, _coin: &str, _is_dual_mode: bool) -> Result<String, Error> {
+//         Err(Error::new(ErrorKind::NotFound, "phemex_swap:该交易所方法未实现".to_string()))
+//     }
+//
+//     // 更新双持仓模式下杠杆
+//     async fn set_dual_leverage(&mut self, _leverage: &str) -> Result<String, Error> {
+//         Err(Error::new(ErrorKind::NotFound, "phemex_swap:该交易所方法未实现".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_swap:该交易所方法未实现".to_string()))
+//     }
+// }

+ 55 - 0
standard/src/phemex_swap_handle.rs

@@ -0,0 +1,55 @@
+// use std::str::FromStr;
+// use rust_decimal::Decimal;
+// use rust_decimal::prelude::FromPrimitive;
+// use serde_json::Value;
+// use exchanges::response_base::ResponseData;
+// use crate::{OrderBook, Trade, Record};
+//
+// pub fn handle_records(value: &Value) -> Vec<Record> {
+//     let mut records = vec![];
+//     let symbol = value["symbol"].as_str().unwrap().replace("USDT", "_USDT").replace("u1000", "1000");
+//
+//     for record_value in value["kline_p"].as_array().unwrap() {
+//         records.push(Record {
+//             time: Decimal::from_i64(record_value[0].as_i64().unwrap() * 1000).unwrap(),
+//             open: Decimal::from_str(record_value[3].as_str().unwrap()).unwrap(),
+//             high: Decimal::from_str(record_value[4].as_str().unwrap()).unwrap(),
+//             low: Decimal::from_str(record_value[5].as_str().unwrap()).unwrap(),
+//             close: Decimal::from_str(record_value[6].as_str().unwrap()).unwrap(),
+//             volume: Decimal::from_str(record_value[7].as_str().unwrap()).unwrap(),
+//             symbol: symbol.clone(),
+//         });
+//     }
+//
+//     return records;
+// }
+//
+// pub fn format_depth_items(value: &Value) -> Vec<OrderBook> {
+//     let mut depth_items: Vec<OrderBook> = vec![];
+//     for value in value.as_array().unwrap() {
+//         depth_items.push(OrderBook {
+//             price: Decimal::from_str(value[0].as_str().unwrap()).unwrap(),
+//             amount: Decimal::from_str(value[1].as_str().unwrap()).unwrap(),
+//         })
+//     }
+//     return depth_items;
+// }
+//
+// pub fn format_trade_items(res_data: &ResponseData) -> Vec<Trade> {
+//     let result = res_data.data["trades_p"].as_array().unwrap();
+//     let mut trades = vec![];
+//
+//     for item in result {
+//         let side = item[1] == "Buy";
+//         let size = Decimal::from_str(item[3].as_str().unwrap()).unwrap();
+//         trades.push(Trade {
+//             id: item[0].to_string(),
+//             time: Decimal::from_i64(item[0].as_i64().unwrap() / 1000 / 1000).unwrap(),
+//             size: if side { size } else { -size },
+//             price: Decimal::from_str(item[2].as_str().unwrap().to_string().as_str()).unwrap(),
+//             symbol: res_data.data["symbol"].as_str().unwrap().replace("USDT", "_USDT").replace("u1000", "1000"),
+//         })
+//     }
+//
+//     return trades;
+// }

+ 10 - 10
standard/src/utils.rs

@@ -22,11 +22,11 @@ pub fn proxy_handle() {
 pub fn symbol_enter_mapper(exchange_enum: ExchangeEnum, symbol: &str) -> String {
     let symbol_upper = symbol.to_uppercase();
     match exchange_enum {
-        ExchangeEnum::KucoinSwap => {
-            if symbol_upper.contains("BTC") {
-                symbol_upper.replace("BTC", "XBT")
-            } else { symbol_upper.to_string() }
-        }
+        // ExchangeEnum::KucoinSwap => {
+        //     if symbol_upper.contains("BTC") {
+        //         symbol_upper.replace("BTC", "XBT")
+        //     } else { symbol_upper.to_string() }
+        // }
         _ => {
             symbol_upper.to_string()
         }
@@ -49,11 +49,11 @@ pub fn get_tick_size(precision: u32) -> Decimal {
 pub fn symbol_out_mapper(exchange_enum: ExchangeEnum, symbol: &str) -> String {
     let symbol_upper = symbol.to_uppercase();
     match exchange_enum {
-        ExchangeEnum::KucoinSwap => {
-            if symbol_upper.contains("XBT") {
-                symbol_upper.replace("XBT", "BTC")
-            } else { symbol_upper.to_string() }
-        }
+        // ExchangeEnum::KucoinSwap => {
+        //     if symbol_upper.contains("XBT") {
+        //         symbol_upper.replace("XBT", "BTC")
+        //     } else { symbol_upper.to_string() }
+        // }
         _ => {
             symbol_upper.to_string()
         }

+ 268 - 0
standard/src/woo_swap.rs

@@ -0,0 +1,268 @@
+// use std::collections::{BTreeMap};
+// use std::io::{Error, ErrorKind};
+// use std::str::FromStr;
+// use tokio::sync::mpsc::Sender;
+// use async_trait::async_trait;
+// use rust_decimal::{Decimal};
+// use serde_json::{json, Value};
+// use tracing::{error, info};
+// use crate::{Platform, ExchangeEnum, Account, Position, Ticker, Market, Order};
+// use exchanges::woo_swap_rest::WooSwapRest;
+// use rust_decimal::prelude::FromPrimitive;
+//
+// #[allow(dead_code)]
+// #[derive(Clone)]
+// pub struct WooSwap {
+//     exchange: ExchangeEnum,
+//     symbol: String,
+//     is_colo: bool,
+//     params: BTreeMap<String, String>,
+//     request: WooSwapRest,
+//     market: Market,
+//     order_sender: Sender<Order>,
+//     error_sender: Sender<Error>,
+// }
+//
+// impl WooSwap {
+//     pub async fn new(symbol: String, is_colo: bool, params: BTreeMap<String, String>, order_sender: Sender<Order>, error_sender: Sender<Error>) -> WooSwap {
+//         let market = Market::new();
+//         let mut woo_swap = WooSwap {
+//             exchange: ExchangeEnum::WooSwap,
+//             symbol: symbol.to_uppercase(),
+//             is_colo,
+//             params: params.clone(),
+//             request: WooSwapRest::new(is_colo, params.clone()),
+//             market,
+//             order_sender,
+//             error_sender,
+//         };
+//
+//         // 修改持仓模式
+//         let symbol_array: Vec<&str> = symbol.split("_").collect();
+//         let mode_result = woo_swap.set_dual_mode(symbol_array[1], true).await;
+//         match mode_result {
+//             Ok(ok) => {
+//                 info!("Woo:设置持仓模式成功!{:?}", ok);
+//             }
+//             Err(error) => {
+//                 error!("Woo:设置持仓模式失败!mode_result={}", error)
+//             }
+//         }
+//         // 获取市场信息
+//         woo_swap.market = WooSwap::get_market(&mut woo_swap).await.unwrap_or(woo_swap.market);
+//         return woo_swap;
+//     }
+// }
+//
+// #[async_trait]
+// impl Platform for WooSwap {
+//     // 克隆方法
+//     fn clone_box(&self) -> Box<dyn Platform + Send + Sync> { Box::new(self.clone()) }
+//     // 获取交易所模式
+//     fn get_self_exchange(&self) -> ExchangeEnum {
+//         ExchangeEnum::WooSwap
+//     }
+//     // 获取交易对
+//     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> {
+//         Err(Error::new(ErrorKind::NotFound, "woo_swap:该交易所方法未实现".to_string()))
+//     }
+//     // 获取账号信息
+//     async fn get_account(&mut self) -> Result<Account, Error> {
+//         Err(Error::new(ErrorKind::NotFound, "woo_swap:该交易所方法未实现".to_string()))
+//     }
+//
+//     async fn get_spot_account(&mut self) -> Result<Vec<Account>, Error> {
+//         Err(Error::new(ErrorKind::NotFound, "woo_swap:该交易所方法未实现".to_string()))
+//     }
+//
+//     // 获取持仓信息
+//     async fn get_position(&mut self) -> Result<Vec<Position>, Error> {
+//         Err(Error::new(ErrorKind::NotFound, "woo_swap:该交易所方法未实现".to_string()))
+//     }
+//     // 获取所有持仓
+//     async fn get_positions(&mut self) -> Result<Vec<Position>, Error> {
+//         Err(Error::new(ErrorKind::NotFound, "woo_swap:该交易所方法未实现".to_string()))
+//     }
+//     // 获取市场行情
+//     async fn get_ticker(&mut self) -> Result<Ticker, Error> {
+//         Err(Error::new(ErrorKind::NotFound, "woo_swap:该交易所方法未实现".to_string()))
+//     }
+//
+//     async fn get_ticker_symbol(&mut self, _symbol: String) -> Result<Ticker, Error> {
+//         Err(Error::new(ErrorKind::NotFound, "woo_swap:该交易所方法未实现".to_string()))
+//     }
+//
+//     async fn get_market(&mut self) -> Result<Market, Error> {
+//         let symbol_format = format!("PERP_{}", self.symbol.clone().to_uppercase());
+//         let params = json!({});
+//         let res_data = self.request.get_market(params).await;
+//         if res_data.code == 200 {
+//             let res_data_json = res_data.data["rows"].as_array().unwrap();
+//             let market_info = res_data_json.iter().find(|item| item["symbol"].as_str().unwrap() == symbol_format);
+//             match market_info {
+//                 None => {
+//                     error!("woo_swap:获取Market信息错误!\nget_market:res_data={:?}", res_data);
+//                     Err(Error::new(ErrorKind::Other, res_data.to_string()))
+//                 }
+//                 Some(value) => {
+//                     let symbol = value["symbol"].as_str().unwrap().to_string().replace("PERP_", "");
+//                     let symbol_array: Vec<&str> = symbol.split("_").collect();
+//                     let base_asset = symbol_array[0].to_string();
+//                     let quote_asset = symbol_array[1].to_string();
+//
+//                     let tick_size = Decimal::from_str(value["quote_min"].as_str().unwrap()).unwrap();
+//                     let amount_size = Decimal::from_str(&value["base_min"].as_str().unwrap()).unwrap();
+//                     let price_precision =Decimal::from_u32(tick_size.scale()).unwrap();
+//                     let amount_precision = Decimal::from_u32(amount_size.scale()).unwrap();
+//                     let min_qty = Decimal::from_str(value["quote_min"].as_str().unwrap()).unwrap();
+//                     let max_qty = Decimal::from_str(value["quote_max"].as_str().unwrap()).unwrap();
+//                     let min_notional = Decimal::from_str(value["min_notional"].as_str().unwrap()).unwrap();
+//                     let max_notional = 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)
+//                 }
+//             }
+//         } else {
+//             Err(Error::new(ErrorKind::Other, res_data.to_string()))
+//         }
+//     }
+//
+//     async fn get_market_symbol(&mut self, symbol: String) -> Result<Market, Error> {
+//         let symbol_format = format!("PERP_{}", symbol.clone().to_uppercase());
+//         let params = json!({});
+//         let res_data = self.request.get_market(params).await;
+//         if res_data.code == 200 {
+//             let res_data_json = res_data.data["rows"].as_array().unwrap();
+//             let market_info = res_data_json.iter().find(|item| item["symbol"].as_str().unwrap() == symbol_format);
+//             match market_info {
+//                 None => {
+//                     error!("woo_swap:获取Market信息错误!\nget_market:res_data={:?}", res_data);
+//                     Err(Error::new(ErrorKind::Other, res_data.to_string()))
+//                 }
+//                 Some(value) => {
+//                     let symbol = value["symbol"].as_str().unwrap().to_string().replace("PERP_", "");
+//                     let symbol_array: Vec<&str> = symbol.split("_").collect();
+//                     let base_asset = symbol_array[0].to_string();
+//                     let quote_asset = symbol_array[1].to_string();
+//
+//                     let tick_size = Decimal::from_str(value["quote_min"].as_str().unwrap()).unwrap();
+//                     let amount_size = Decimal::from_str(&value["base_min"].as_str().unwrap()).unwrap();
+//                     let price_precision =Decimal::from_u32(tick_size.scale()).unwrap();
+//                     let amount_precision = Decimal::from_u32(amount_size.scale()).unwrap();
+//                     let min_qty = Decimal::from_str(value["quote_min"].as_str().unwrap()).unwrap();
+//                     let max_qty = Decimal::from_str(value["quote_max"].as_str().unwrap()).unwrap();
+//                     let min_notional = Decimal::from_str(value["min_notional"].as_str().unwrap()).unwrap();
+//                     let max_notional = 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)
+//                 }
+//             }
+//         } else {
+//             Err(Error::new(ErrorKind::Other, res_data.to_string()))
+//         }
+//     }
+//
+//     // 获取订单详情
+//     async fn get_order_detail(&mut self, _order_id: &str, _custom_id: &str) -> Result<Order, Error> {
+//         Err(Error::new(ErrorKind::NotFound, "woo_swap:该交易所方法未实现".to_string()))
+//     }
+//     // 获取订单列表
+//     async fn get_orders_list(&mut self, _status: &str) -> Result<Vec<Order>, Error> {
+//         Err(Error::new(ErrorKind::NotFound, "woo_swap:该交易所方法未实现".to_string()))
+//     }
+//     // 下单接口
+//     async fn take_order(&mut self, _custom_id: &str, _origin_side: &str, _price: Decimal, _amount: Decimal) -> Result<Order, Error> {
+//         Err(Error::new(ErrorKind::NotFound, "woo_swap:该交易所方法未实现".to_string()))
+//     }
+//
+//     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> {
+//         Err(Error::new(ErrorKind::NotFound, "woo_swap:该交易所方法未实现".to_string()))
+//     }
+//
+//     // 撤销订单
+//     async fn cancel_order(&mut self, _order_id: &str, _custom_id: &str) -> Result<Order, Error> {
+//         Err(Error::new(ErrorKind::NotFound, "woo_swap:该交易所方法未实现".to_string()))
+//     }
+//     // 批量撤销订单
+//     async fn cancel_orders(&mut self) -> Result<Vec<Order>, Error> {
+//         Err(Error::new(ErrorKind::NotFound, "woo_swap:该交易所方法未实现".to_string()))
+//     }
+//
+//     async fn cancel_orders_all(&mut self) -> Result<Vec<Order>, Error> {
+//         Err(Error::new(ErrorKind::NotFound, "woo_swap:该交易所方法未实现".to_string()))
+//     }
+//
+//     async fn take_stop_loss_order(&mut self, _stop_price: Decimal, _price: Decimal, _side: &str) -> Result<Value, Error> {
+//         Err(Error::new(ErrorKind::NotFound, "woo_swap:该交易所方法未实现".to_string()))
+//     }
+//
+//     async fn cancel_stop_loss_order(&mut self, _order_id: &str) -> Result<Value, Error> {
+//         Err(Error::new(ErrorKind::NotFound, "woo_swap:该交易所方法未实现".to_string()))
+//     }
+//
+//     // 设置持仓模式
+//     async fn set_dual_mode(&mut self, _coin: &str, _is_dual_mode: bool) -> Result<String, Error> {
+//         Err(Error::new(ErrorKind::NotFound, "woo_swap:该交易所方法未实现".to_string()))
+//     }
+//
+//     // 更新双持仓模式下杠杆
+//     async fn set_dual_leverage(&mut self, _leverage: &str) -> Result<String, Error> {
+//         Err(Error::new(ErrorKind::NotFound, "woo_swap:该交易所方法未实现".to_string()))
+//     }
+//
+//     async fn set_auto_deposit_status(&mut self, _status: bool) -> Result<String, Error> { Err(Error::new(ErrorKind::NotFound, "woo:该交易所方法未实现".to_string())) }
+//
+//     // 交易账户互转
+//     async fn wallet_transfers(&mut self, _coin: &str, _from: &str, _to: &str, _amount: Decimal) -> Result<String, Error> {
+//         Err(Error::new(ErrorKind::NotFound, "woo_swap:该交易所方法未实现".to_string()))
+//     }
+// }

+ 52 - 0
standard/src/woo_swap_handle.rs

@@ -0,0 +1,52 @@
+// use std::str::FromStr;
+// use rust_decimal::Decimal;
+// use rust_decimal::prelude::FromPrimitive;
+// use serde_json::Value;
+// use exchanges::response_base::ResponseData;
+// use crate::{OrderBook, Trade, Record};
+//
+// pub fn handle_records(value: &Value) -> Vec<Record> {
+//     let mut records = vec![];
+//     let record = value["data"].clone();
+//     records.push(Record {
+//         time: Decimal::from_i64(record["startTime"].as_i64().unwrap()).unwrap(),
+//         open: Decimal::from_f64(record["open"].as_f64().unwrap()).unwrap(),
+//         high: Decimal::from_f64(record["high"].as_f64().unwrap()).unwrap(),
+//         low: Decimal::from_f64(record["low"].as_f64().unwrap()).unwrap(),
+//         close: Decimal::from_f64(record["close"].as_f64().unwrap()).unwrap(),
+//         volume: Decimal::from_f64(record["volume"].as_f64().unwrap()).unwrap(),
+//         symbol: record["symbol"].as_str().unwrap().replace("PERP_", ""),
+//     });
+//
+//     return records;
+// }
+//
+// pub fn format_depth_items(value: &Value) -> Vec<OrderBook> {
+//     let mut depth_items: Vec<OrderBook> = vec![];
+//     for value in value.as_array().unwrap() {
+//         depth_items.push(OrderBook {
+//             price: Decimal::from_str(value[0].as_str().unwrap()).unwrap(),
+//             amount: Decimal::from_str(value[1].as_str().unwrap()).unwrap(),
+//         })
+//     }
+//     return depth_items;
+// }
+//
+// pub fn format_trade_items(res_data: &ResponseData) -> Vec<Trade> {
+//     let result = res_data.data["data"].as_array().unwrap();
+//     let mut trades = vec![];
+//     for item in result {
+//         let side = item["b"] == "BUY";
+//         let size = Decimal::from_f64(item["a"].as_f64().unwrap()).unwrap();
+//         let price = Decimal::from_f64(item["p"].as_f64().unwrap()).unwrap();
+//         trades.push(Trade {
+//             id: res_data.data["ts"].to_string(),
+//             time: Decimal::from_i64(res_data.data["ts"].as_i64().unwrap()).unwrap(),
+//             size: if side { size * price } else { -size * price },
+//             price,
+//             symbol: item["s"].as_str().unwrap().replace("PERP_", ""),
+//         })
+//     }
+//
+//     return trades;
+// }

+ 41 - 43
strategy/src/binance_usdt_swap.rs

@@ -7,10 +7,8 @@ use tokio_tungstenite::tungstenite::Message;
 use tracing::error;
 use exchanges::response_base::ResponseData;
 use global::trace_stack::{TraceStack};
-use standard::exchange::ExchangeEnum::BinanceSwap;
 use crate::core::Core;
 use exchanges::binance_swap_ws::{BinanceSwapSubscribeType, BinanceSwapWs, BinanceSwapWsType};
-use crate::exchange_disguise::{on_special_depth};
 
 // 参考 币安 合约 启动
 pub(crate) async fn reference_binance_swap_run(is_shutdown_arc: Arc<AtomicBool>,
@@ -50,52 +48,52 @@ pub(crate) async fn reference_binance_swap_run(is_shutdown_arc: Arc<AtomicBool>,
     });
 }
 
-async fn on_data(core_arc_clone: Arc<Mutex<Core>>,
-                 update_flag_u: &mut Decimal,
+async fn on_data(_core_arc_clone: Arc<Mutex<Core>>,
+                 _update_flag_u: &mut Decimal,
                  response: ResponseData) {
     let mut trace_stack = TraceStack::new(response.time, response.ins);
     trace_stack.on_after_span_line();
 
     match response.channel.as_str() {
-        "aggTrade" => {
-            // let trade: OriginalTradeBa = serde_json::from_str(data.data.as_str()).unwrap();
-            // let name = data.label.clone();
-
-            // 订单流逻辑
-            // on_trade(trade.clone(), core_arc_clone.clone()).await;
-
-            // 原本的逻辑
-            // let mut core = core_arc_clone.lock().await;
-            // let str = data.label.clone();
-            // if core.is_update.contains_key(&data.label) && *core.is_update.get(str.as_str()).unwrap() {
-            //     *_max_buy = Decimal::ZERO;
-            //     *_min_sell = Decimal::ZERO;
-            //     core.is_update.remove(str.as_str());
-            // }
-            // if trade.p > *_max_buy || *_max_buy == Decimal::ZERO {
-            //     *_max_buy = trade.p
-            // }
-            // if trade.p < *_min_sell || *_min_sell == Decimal::ZERO {
-            //     *_min_sell = trade.p
-            // }
-            // core.max_buy_min_sell_cache.insert(data.label, vec![*_max_buy, *_min_sell]);
-        }
-        "bookTicker" => {
-            trace_stack.set_source("binance_usdt_swap.bookTicker".to_string());
-            // 将ticker数据转换为模拟深度
-            let special_depth = standard::handle_info::HandleSwapInfo::handle_book_ticker(BinanceSwap, &response);
-            trace_stack.on_after_format();
-
-            on_special_depth(core_arc_clone, update_flag_u, &response.label, &mut trace_stack, &special_depth).await;
-        }
-        "depth" => {
-            trace_stack.set_source("binance_usdt_swap.depth".to_string());
-            // 将depth数据转换为模拟深度
-            let special_depth = standard::handle_info::HandleSwapInfo::handle_special_depth(BinanceSwap, &response);
-            trace_stack.on_after_format();
-
-            on_special_depth(core_arc_clone, update_flag_u, &response.label, &mut trace_stack, &special_depth).await;
-        }
+        // "aggTrade" => {
+        //     // let trade: OriginalTradeBa = serde_json::from_str(data.data.as_str()).unwrap();
+        //     // let name = data.label.clone();
+        //
+        //     // 订单流逻辑
+        //     // on_trade(trade.clone(), core_arc_clone.clone()).await;
+        //
+        //     // 原本的逻辑
+        //     // let mut core = core_arc_clone.lock().await;
+        //     // let str = data.label.clone();
+        //     // if core.is_update.contains_key(&data.label) && *core.is_update.get(str.as_str()).unwrap() {
+        //     //     *_max_buy = Decimal::ZERO;
+        //     //     *_min_sell = Decimal::ZERO;
+        //     //     core.is_update.remove(str.as_str());
+        //     // }
+        //     // if trade.p > *_max_buy || *_max_buy == Decimal::ZERO {
+        //     //     *_max_buy = trade.p
+        //     // }
+        //     // if trade.p < *_min_sell || *_min_sell == Decimal::ZERO {
+        //     //     *_min_sell = trade.p
+        //     // }
+        //     // core.max_buy_min_sell_cache.insert(data.label, vec![*_max_buy, *_min_sell]);
+        // }
+        // "bookTicker" => {
+        //     trace_stack.set_source("binance_usdt_swap.bookTicker".to_string());
+        //     // 将ticker数据转换为模拟深度
+        //     let special_depth = standard::handle_info::HandleSwapInfo::handle_book_ticker(BinanceSwap, &response);
+        //     trace_stack.on_after_format();
+        //
+        //     on_special_depth(core_arc_clone, update_flag_u, &response.label, &mut trace_stack, &special_depth).await;
+        // }
+        // "depth" => {
+        //     trace_stack.set_source("binance_usdt_swap.depth".to_string());
+        //     // 将depth数据转换为模拟深度
+        //     let special_depth = standard::handle_info::HandleSwapInfo::handle_special_depth(BinanceSwap, &response);
+        //     trace_stack.on_after_format();
+        //
+        //     on_special_depth(core_arc_clone, update_flag_u, &response.label, &mut trace_stack, &special_depth).await;
+        // }
         _ => {
             error!("未知推送类型");
             error!(?response);

+ 190 - 189
strategy/src/bitget_usdt_swap.rs

@@ -1,189 +1,190 @@
-use std::collections::BTreeMap;
-use std::sync::Arc;
-use std::sync::atomic::AtomicBool;
-use rust_decimal::Decimal;
-use tokio::spawn;
-use tokio::sync::Mutex;
-use tracing::{error, info};
-use exchanges::bitget_swap_ws::{BitgetSwapLogin, BitgetSwapSubscribeType, BitgetSwapWs, BitgetSwapWsType};
-use exchanges::response_base::ResponseData;
-use global::trace_stack::TraceStack;
-use standard::exchange::ExchangeEnum::{BitgetSwap};
-use standard::{Position, PositionModeEnum};
-use crate::core::Core;
-use crate::exchange_disguise::on_special_depth;
-use crate::model::OrderInfo;
-
-pub async fn bitget_usdt_swap_run(is_shutdown_arc :Arc<AtomicBool>,
-                                  is_trade: bool,
-                                  core_arc: Arc<Mutex<Core>>,
-                                  name: String,
-                                  symbols: Vec<String>,
-                                  is_colo: bool,
-                                  exchange_params: BTreeMap<String, String>) {
-    // 开启公共频道
-    let (write_tx_public, write_rx_public) = futures_channel::mpsc::unbounded();
-
-    // 开启公共连接
-    let is_shutdown_arc_c1 = is_shutdown_arc.clone();
-    let write_tx_am_public = Arc::new(Mutex::new(write_tx_public));
-    let name_clone = name.clone();
-    let core_arc_clone = core_arc.clone();
-    let symbols_clone = symbols.clone();
-    spawn(async move {
-        // 构建链接ws
-        let mut bg_public = BitgetSwapWs::new_label(name_clone.clone(),
-                                                    is_colo,
-                                                    None,
-                                                    BitgetSwapWsType::Public);
-
-        // 消费数据的函数
-        let mut update_flag_u = Decimal::ZERO;
-        let fun = move |data: ResponseData| {
-            let core_arc_cc = core_arc_clone.clone();
-
-            async move {
-                on_public_data(core_arc_cc, &mut update_flag_u, data).await
-            }
-        };
-
-        // 准备链接
-        bg_public.set_subscribe(vec![BitgetSwapSubscribeType::PuBooks1]); // 只用订阅深度数据
-        bg_public.set_symbols(symbols_clone);
-        bg_public.ws_connect_async(is_shutdown_arc_c1, fun, &write_tx_am_public, write_rx_public).await.expect("bitget_usdt_swap 链接有异常")
-    });
-
-    // 不需要交易就不用开启私有频道了
-    if !is_trade {
-        return;
-    }
-
-    // 开启私有频道
-    let (write_tx_private, write_rx_private) = futures_channel::mpsc::unbounded();
-
-    // 开启公共连接
-    let is_shutdown_arc_c1 = is_shutdown_arc.clone();
-    let write_tx_am_private = Arc::new(Mutex::new(write_tx_private));
-    spawn(async move {
-        // 构建链接ws
-        let mut bg_private = BitgetSwapWs::new_label(name.clone(),
-                                                     is_colo,
-                                                     Some(parse_btree_map_to_bitget_swap_login(exchange_params)),
-                                                     BitgetSwapWsType::Private);
-
-        // 消费数据的函数
-        let core_arc_clone = core_arc.clone();
-        let run_symbol = symbols[0].clone();
-        let ct_val = core_arc_clone.lock().await.platform_rest.get_self_market().ct_val;
-        let fun = move |data: ResponseData| {
-            let core_arc_cc = core_arc_clone.clone();
-            let run_symbol_c = run_symbol.clone();
-
-            async move {
-                on_private_data(core_arc_cc, ct_val, data, &run_symbol_c).await
-            }
-        };
-
-        // 准备链接
-        bg_private.set_subscribe(vec![
-            BitgetSwapSubscribeType::PrOrders,
-            BitgetSwapSubscribeType::PrAccount,
-            BitgetSwapSubscribeType::PrPosition
-        ]);
-        bg_private.set_symbols(symbols.clone());
-        bg_private.ws_connect_async(is_shutdown_arc_c1, fun, &write_tx_am_private, write_rx_private).await.expect("bitget_usdt_swap 链接有异常")
-    });
-}
-
-async fn on_private_data(core_arc_clone: Arc<Mutex<Core>>,
-                         ct_val: Decimal,
-                         response: ResponseData,
-                         run_symbol: &String) {
-    let mut trace_stack = TraceStack::new(response.time, response.ins);
-    trace_stack.on_after_span_line();
-
-    // public类型,目前只考虑订单流数据
-    match response.channel.as_str() {
-        "account" => {
-            let account = standard::handle_info::HandleSwapInfo::handle_account_info(BitgetSwap, &response, run_symbol);
-            let mut core = core_arc_clone.lock().await;
-            core.update_equity(account).await;
-        },
-        "positions" => {
-            let mut positions = standard::handle_info::HandleSwapInfo::handle_position(BitgetSwap, &response, &ct_val);
-
-            // bitget如果没有仓位不会给0,会给个空数组
-            if positions.is_empty() {
-                positions.push(Position {
-                    symbol: run_symbol.replace("_", "").to_uppercase(),
-                    margin_level: Default::default(),
-                    amount: Default::default(),
-                    frozen_amount: Default::default(),
-                    price: Default::default(),
-                    profit: Default::default(),
-                    position_mode: PositionModeEnum::Both,
-                    margin: Default::default(),
-                });
-            }
-
-            let mut core = core_arc_clone.lock().await;
-            core.update_position(positions).await;
-        },
-        "orders" => {
-            trace_stack.set_source("gate_swap.orders".to_string());
-            let orders = standard::handle_info::HandleSwapInfo::handle_order(BitgetSwap, response.clone(), ct_val.clone());
-
-            let mut order_infos:Vec<OrderInfo> = Vec::new();
-            for mut order in orders.order {
-                if order.status == "NULL" {
-                    error!("bitget_usdt_swap 未识别的订单状态:{:?}", response);
-
-                    continue;
-                }
-
-                let order_info = OrderInfo::parse_order_to_order_info(&mut order);
-                order_infos.push(order_info);
-            }
-
-            {
-                let mut core = core_arc_clone.lock().await;
-                core.update_order(order_infos, trace_stack).await;
-            }
-        },
-        "pong" => {}
-        _ => {
-            info!("bitget_usdt_swap 113 未知的订阅数据: {:?}", response);
-        }
-    }
-}
-
-async fn on_public_data(core_arc_clone: Arc<Mutex<Core>>,
-                        update_flag_u: &mut Decimal,
-                        response: ResponseData) {
-    let mut trace_stack = TraceStack::new(response.time, response.ins);
-    trace_stack.on_after_span_line();
-
-    // public类型,目前只考虑订单流数据
-    match response.channel.as_str() {
-        "books1" => {
-            trace_stack.set_source("bitget_usdt_swap.books1".to_string());
-            let special_depth = standard::handle_info::HandleSwapInfo::handle_special_depth(BitgetSwap, &response);
-            trace_stack.on_after_format();
-
-            on_special_depth(core_arc_clone, update_flag_u, &response.label, &mut trace_stack, &special_depth).await;
-        },
-        "pong" => {},
-        _ => {
-            info!("bitget_usdt_swap 125 未知的订阅数据");
-            info!(?response)
-        }
-    }
-}
-
-fn parse_btree_map_to_bitget_swap_login(exchange_params: BTreeMap<String, String>) -> BitgetSwapLogin {
-    BitgetSwapLogin {
-        api_key: exchange_params.get("access_key").unwrap().clone(),
-        secret_key: exchange_params.get("secret_key").unwrap().clone(),
-        passphrase_key: exchange_params.get("pass_key").unwrap().clone(),
-    }
-}
+// use std::collections::BTreeMap;
+// use std::sync::Arc;
+// use std::sync::atomic::AtomicBool;
+// use rust_decimal::Decimal;
+// use tokio::spawn;
+// use tokio::sync::Mutex;
+// use tracing::{error, info};
+// use tokio_tungstenite::tungstenite::Message;
+// use exchanges::bitget_swap_ws::{BitgetSwapLogin, BitgetSwapSubscribeType, BitgetSwapWs, BitgetSwapWsType};
+// use exchanges::response_base::ResponseData;
+// use global::trace_stack::TraceStack;
+// use standard::exchange::ExchangeEnum::{BitgetSwap};
+// use standard::{Position, PositionModeEnum};
+// use crate::core::Core;
+// use crate::exchange_disguise::on_special_depth;
+// use crate::model::OrderInfo;
+//
+// pub async fn bitget_usdt_swap_run(is_shutdown_arc :Arc<AtomicBool>,
+//                                   is_trade: bool,
+//                                   core_arc: Arc<Mutex<Core>>,
+//                                   name: String,
+//                                   symbols: Vec<String>,
+//                                   is_colo: bool,
+//                                   exchange_params: BTreeMap<String, String>) {
+//     // 开启公共频道
+//     let (write_tx_public, write_rx_public) = futures_channel::mpsc::unbounded::<Message>();
+//
+//     // 开启公共连接
+//     let is_shutdown_arc_c1 = is_shutdown_arc.clone();
+//     let write_tx_am_public = Arc::new(Mutex::new(write_tx_public));
+//     let name_clone = name.clone();
+//     let core_arc_clone = core_arc.clone();
+//     let symbols_clone = symbols.clone();
+//     spawn(async move {
+//         // 构建链接ws
+//         let mut bg_public = BitgetSwapWs::new_label(name_clone.clone(),
+//                                                     is_colo,
+//                                                     None,
+//                                                     BitgetSwapWsType::Public);
+//
+//         // 消费数据的函数
+//         let mut update_flag_u = Decimal::ZERO;
+//         let fun = move |data: ResponseData| {
+//             let core_arc_cc = core_arc_clone.clone();
+//
+//             async move {
+//                 on_public_data(core_arc_cc, &mut update_flag_u, data).await
+//             }
+//         };
+//
+//         // 准备链接
+//         bg_public.set_subscribe(vec![BitgetSwapSubscribeType::PuBooks1]); // 只用订阅深度数据
+//         bg_public.set_symbols(symbols_clone);
+//         // bg_public.ws_connect_async(is_shutdown_arc_c1, fun, &write_tx_am_public, write_rx_public).await.expect("bitget_usdt_swap 链接有异常")
+//     });
+//
+//     // 不需要交易就不用开启私有频道了
+//     if !is_trade {
+//         return;
+//     }
+//
+//     // 开启私有频道
+//     let (write_tx_private, write_rx_private) = futures_channel::mpsc::unbounded();
+//
+//     // 开启公共连接
+//     let is_shutdown_arc_c1 = is_shutdown_arc.clone();
+//     let write_tx_am_private = Arc::new(Mutex::new(write_tx_private));
+//     spawn(async move {
+//         // 构建链接ws
+//         let mut bg_private = BitgetSwapWs::new_label(name.clone(),
+//                                                      is_colo,
+//                                                      Some(parse_btree_map_to_bitget_swap_login(exchange_params)),
+//                                                      BitgetSwapWsType::Private);
+//
+//         // 消费数据的函数
+//         let core_arc_clone = core_arc.clone();
+//         let run_symbol = symbols[0].clone();
+//         let ct_val = core_arc_clone.lock().await.platform_rest.get_self_market().ct_val;
+//         let fun = move |data: ResponseData| {
+//             let core_arc_cc = core_arc_clone.clone();
+//             let run_symbol_c = run_symbol.clone();
+//
+//             async move {
+//                 on_private_data(core_arc_cc, ct_val, data, &run_symbol_c).await
+//             }
+//         };
+//
+//         // 准备链接
+//         bg_private.set_subscribe(vec![
+//             BitgetSwapSubscribeType::PrOrders,
+//             BitgetSwapSubscribeType::PrAccount,
+//             BitgetSwapSubscribeType::PrPosition
+//         ]);
+//         bg_private.set_symbols(symbols.clone());
+//         bg_private.ws_connect_async(is_shutdown_arc_c1, fun, &write_tx_am_private, write_rx_private).await.expect("bitget_usdt_swap 链接有异常")
+//     });
+// }
+//
+// async fn on_private_data(core_arc_clone: Arc<Mutex<Core>>,
+//                          ct_val: Decimal,
+//                          response: ResponseData,
+//                          run_symbol: &String) {
+//     let mut trace_stack = TraceStack::new(response.time, response.ins);
+//     trace_stack.on_after_span_line();
+//
+//     // public类型,目前只考虑订单流数据
+//     match response.channel.as_str() {
+//         // "account" => {
+//         //     let account = standard::handle_info::HandleSwapInfo::handle_account_info(BitgetSwap, &response, run_symbol);
+//         //     let mut core = core_arc_clone.lock().await;
+//         //     core.update_equity(account).await;
+//         // },
+//         // "positions" => {
+//         //     let mut positions = standard::handle_info::HandleSwapInfo::handle_position(BitgetSwap, &response, &ct_val);
+//         //
+//         //     // bitget如果没有仓位不会给0,会给个空数组
+//         //     if positions.is_empty() {
+//         //         positions.push(Position {
+//         //             symbol: run_symbol.replace("_", "").to_uppercase(),
+//         //             margin_level: Default::default(),
+//         //             amount: Default::default(),
+//         //             frozen_amount: Default::default(),
+//         //             price: Default::default(),
+//         //             profit: Default::default(),
+//         //             position_mode: PositionModeEnum::Both,
+//         //             margin: Default::default(),
+//         //         });
+//         //     }
+//         //
+//         //     let mut core = core_arc_clone.lock().await;
+//         //     core.update_position(positions).await;
+//         // },
+//         // "orders" => {
+//         //     trace_stack.set_source("gate_swap.orders".to_string());
+//         //     let orders = standard::handle_info::HandleSwapInfo::handle_order(BitgetSwap, response.clone(), ct_val.clone());
+//         //
+//         //     let mut order_infos:Vec<OrderInfo> = Vec::new();
+//         //     for mut order in orders.order {
+//         //         if order.status == "NULL" {
+//         //             error!("bitget_usdt_swap 未识别的订单状态:{:?}", response);
+//         //
+//         //             continue;
+//         //         }
+//         //
+//         //         let order_info = OrderInfo::parse_order_to_order_info(&mut order);
+//         //         order_infos.push(order_info);
+//         //     }
+//         //
+//         //     {
+//         //         let mut core = core_arc_clone.lock().await;
+//         //         core.update_order(order_infos, trace_stack).await;
+//         //     }
+//         // },
+//         "pong" => {}
+//         _ => {
+//             info!("bitget_usdt_swap 113 未知的订阅数据: {:?}", response);
+//         }
+//     }
+// }
+//
+// async fn on_public_data(_core_arc_clone: Arc<Mutex<Core>>,
+//                         _update_flag_u: &mut Decimal,
+//                         response: ResponseData) {
+//     let mut trace_stack = TraceStack::new(response.time, response.ins);
+//     trace_stack.on_after_span_line();
+//
+//     // public类型,目前只考虑订单流数据
+//     match response.channel.as_str() {
+//         "books1" => {
+//             // trace_stack.set_source("bitget_usdt_swap.books1".to_string());
+//             // let special_depth = standard::handle_info::HandleSwapInfo::handle_special_depth(BitgetSwap, &response);
+//             // trace_stack.on_after_format();
+//             //
+//             // on_special_depth(core_arc_clone, update_flag_u, &response.label, &mut trace_stack, &special_depth).await;
+//         },
+//         "pong" => {},
+//         _ => {
+//             info!("bitget_usdt_swap 125 未知的订阅数据");
+//             info!(?response)
+//         }
+//     }
+// }
+//
+// fn parse_btree_map_to_bitget_swap_login(exchange_params: BTreeMap<String, String>) -> BitgetSwapLogin {
+//     BitgetSwapLogin {
+//         api_key: exchange_params.get("access_key").unwrap().clone(),
+//         secret_key: exchange_params.get("secret_key").unwrap().clone(),
+//         passphrase_key: exchange_params.get("pass_key").unwrap().clone(),
+//     }
+// }

+ 246 - 245
strategy/src/bybit_usdt_swap.rs

@@ -1,252 +1,253 @@
-use std::collections::BTreeMap;
-use std::sync::Arc;
-use std::sync::atomic::{AtomicBool};
-use rust_decimal::Decimal;
-use tokio::{spawn};
-use tokio::sync::Mutex;
-use tracing::{error, info};
-use exchanges::bybit_swap_ws::{BybitSwapLogin, BybitSwapSubscribeType, BybitSwapWs, BybitSwapWsType};
-use exchanges::response_base::ResponseData;
-use global::trace_stack::TraceStack;
-use standard::exchange::ExchangeEnum::BybitSwap;
-use crate::core::Core;
-use crate::exchange_disguise::on_special_depth;
-use crate::model::OrderInfo;
-
-// 1交易、0参考 bybit 合约 启动
-pub async fn bybit_swap_run(is_shutdown_arc: Arc<AtomicBool>,
-                            is_trade: bool,
-                            core_arc: Arc<Mutex<Core>>,
-                            name: String,
-                            symbols: Vec<String>,
-                            is_colo: bool,
-                            exchange_params: BTreeMap<String, String>) {
-    // 启动公共频道
-    let (write_tx_public, write_rx_public) = futures_channel::mpsc::unbounded();
-
-    let mut ws_public = BybitSwapWs::new_label(name.clone(), is_colo, None, BybitSwapWsType::Public);
-    ws_public.set_symbols(symbols.clone());
-    ws_public.set_subscribe(vec![
-        BybitSwapSubscribeType::PuTickers
-    ]);
-    // if is_trade {
-    //     ws_public.set_subscribe(vec![
-    //         BybitSwapSubscribeType::PuBlicTrade
-    //     ]);
-    // }
-    // 挂起公共ws
-    let write_tx_am_public = Arc::new(Mutex::new(write_tx_public));
-    let is_shutdown_clone_public = Arc::clone(&is_shutdown_arc);
-    let core_arc_clone_public = core_arc.clone();
-    spawn(async move {
-        // 消费数据
-        let mut update_flag_u = Decimal::ZERO;
-
-        let fun = move |data: ResponseData| {
-            let core_arc = core_arc_clone_public.clone();
-
-            async move {
-                on_public_data(core_arc,
-                               &mut update_flag_u,
-                               data).await;
-            }
-        };
-
-        ws_public.ws_connect_async(is_shutdown_clone_public,
-                                   fun,
-                                   &write_tx_am_public,
-                                   write_rx_public).await.expect("链接失败(内部一个心跳线程应该已经关闭了)");
-    });
-    let trade_symbols = symbols.clone();
-    // 交易交易所需要启动私有ws
-    if is_trade {
-        let (write_tx_private, write_rx_private) = futures_channel::mpsc::unbounded();
-        let auth = Some(parse_btree_map_to_bybit_swap_login(exchange_params));
-
-        let mut ws_private = BybitSwapWs::new_label(name.clone(), is_colo, auth, BybitSwapWsType::Private);
-        ws_private.set_symbols(trade_symbols);
-        ws_private.set_subscribe(vec![
-            BybitSwapSubscribeType::PrPosition,
-            BybitSwapSubscribeType::PrOrder,
-            BybitSwapSubscribeType::PrWallet
-        ]);
-
-        // 挂起私有ws
-        let write_tx_am_private = Arc::new(Mutex::new(write_tx_private));
-        let is_shutdown_clone_private = Arc::clone(&is_shutdown_arc);
-        let core_arc_clone_private = core_arc.clone();
-        spawn(async move {
-            let ct_val = core_arc_clone_private.lock().await.platform_rest.get_self_market().ct_val;
-            let run_symbol = symbols.clone()[0].clone();
-
-            let fun = move |data: ResponseData| {
-                let core_arc_clone = core_arc_clone_private.clone();
-                let run_symbol_clone = run_symbol.clone();
-
-                async move {
-                    on_private_data(core_arc_clone.clone(), &ct_val, &run_symbol_clone, data).await;
-                }
-            };
-
-            ws_private.ws_connect_async(is_shutdown_clone_private,
-                                        fun,
-                                        &write_tx_am_private,
-                                        write_rx_private).await.expect("链接失败(内部一个心跳线程应该已经关闭了)");
-        });
-    }
-}
-
-async fn on_private_data(core_arc_clone: Arc<Mutex<Core>>, ct_val: &Decimal, run_symbol: &String, response: ResponseData) {
-    let mut trace_stack = TraceStack::new(response.time, response.ins);
-    trace_stack.on_after_span_line();
-
-    match response.channel.as_str() {
-        "wallet" => {
-            let account = standard::handle_info::HandleSwapInfo::handle_account_info(BybitSwap, &response, run_symbol);
-            let mut core = core_arc_clone.lock().await;
-            core.update_equity(account).await;
-        }
-        "order" => {
-            let orders = standard::handle_info::HandleSwapInfo::handle_order(BybitSwap, response.clone(), ct_val.clone());
-            trace_stack.on_after_format();
-
-            let mut order_infos:Vec<OrderInfo> = Vec::new();
-            for mut order in orders.order {
-                if order.status == "NULL" {
-                    error!("bybit_usdt_swap 未识别的订单状态:{:?}", response);
-
-                    continue;
-                }
-
-                if order.deal_amount != Decimal::ZERO {
-                    info!("bybit order 消息原文:{:?}", response);
-                }
-
-                let order_info = OrderInfo::parse_order_to_order_info(&mut order);
-                order_infos.push(order_info);
-            }
-
-            let mut core = core_arc_clone.lock().await;
-            core.update_order(order_infos, trace_stack).await;
-        }
-        "position" => {
-            let positions = standard::handle_info::HandleSwapInfo::handle_position(BybitSwap, &response, ct_val);
-            let mut core = core_arc_clone.lock().await;
-            core.update_position(positions).await;
-        }
-        _ => {
-            error!("未知推送类型");
-            error!(?response);
-        }
-    }
-}
-
-async fn on_public_data(core_arc_clone: Arc<Mutex<Core>>, update_flag_u: &mut Decimal, response: ResponseData) {
-    if response.code != 200 {
-        return;
-    }
-
-    let mut trace_stack = TraceStack::new(response.time, response.ins);
-    trace_stack.on_after_span_line();
-
-    match response.channel.as_str() {
-        "tickers" => {
-            trace_stack.set_source("bybit_usdt_swap.tickers".to_string());
-
-            // 处理ticker信息
-            let special_depth = standard::handle_info::HandleSwapInfo::handle_book_ticker(BybitSwap, &response);
-            trace_stack.on_after_format();
-
-            on_special_depth(core_arc_clone, update_flag_u, &response.label, &mut trace_stack, &special_depth).await;
-        }
-        "orderbook" => {
-            // let mut is_update = false;
-            // let data_type = data.data_type.clone();
-            // let label = data.label.clone();
-            // if data_type == "delta"  {
-            //     is_update = true;
-            // }
-            // let mut depth_format: DepthParam = format_depth(BybitSwap, &data);
-            // // 是增量更新
-            // if is_update {
-            //     update_order_book(depth_asks, depth_bids, depth_format.depth_asks, depth_format.depth_bids);
-            // } else { // 全量
-            //     depth_asks.clear();
-            //     depth_asks.append(&mut depth_format.depth_asks);
-            //     depth_bids.clear();
-            //     depth_bids.append(&mut depth_format.depth_bids);
-            // }
-            // let depth = make_special_depth(label.clone(), depth_asks, depth_bids, depth_format.t, depth_format.create_at);
-            // trace_stack.on_before_network(depth_format.create_at.clone());
-            // trace_stack.on_after_format();
-            //
-            // on_special_depth(core_arc_clone, update_flag_u, &label, &mut trace_stack, &depth).await;
-        }
-        "trade" => {
-            // let mut core = core_arc_clone.lock().await;
-            // let str = data.label.clone();
-            // if core.is_update.contains_key(&data.label) && *core.is_update.get(str.as_str()).unwrap(){
-            //     *max_buy = Decimal::ZERO;
-            //     *min_sell = Decimal::ZERO;
-            //     core.is_update.remove(str.as_str());
-            // }
-            // let trades: Vec<OriginalTradeBy> = serde_json::from_str(data.data.as_str()).unwrap();
-            // for trade in trades {
-            //     if trade.p > *max_buy || *max_buy == Decimal::ZERO{
-            //         *max_buy = trade.p
-            //     }
-            //     if trade.p < *min_sell || *min_sell == Decimal::ZERO{
-            //         *min_sell = trade.p
-            //     }
-            // }
-            // core.max_buy_min_sell_cache.insert(data.label, vec![*max_buy, *min_sell]);
-        }
-        _ => {}
-    }
-}
-
-fn parse_btree_map_to_bybit_swap_login(exchange_params: BTreeMap<String, String>) -> BybitSwapLogin {
-    BybitSwapLogin {
-        api_key: exchange_params.get("access_key").unwrap().clone(),
-        secret_key: exchange_params.get("secret_key").unwrap().clone(),
-    }
-}
-
-// fn update_order_book(depth_asks: &mut Vec<MarketOrder>, depth_bids: &mut Vec<MarketOrder>, asks : Vec<MarketOrder>, bids: Vec<MarketOrder>) {
-//     for i in asks {
-//         let index_of_value = depth_asks.iter().position(|x| x.price == i.price);
-//         match index_of_value {
-//             Some(index) => {
-//                 if i.amount == Decimal::ZERO {
-//                     depth_asks.remove(index);
-//                 } else {
-//                     depth_asks[index].amount = i.amount.clone();
+// use std::collections::BTreeMap;
+// use std::sync::Arc;
+// use std::sync::atomic::{AtomicBool};
+// use rust_decimal::Decimal;
+// use tokio::{spawn};
+// use tokio::sync::Mutex;
+// use tracing::{error, info};
+// use tokio_tungstenite::tungstenite::Message;
+// use exchanges::bybit_swap_ws::{BybitSwapLogin, BybitSwapSubscribeType, BybitSwapWs, BybitSwapWsType};
+// use exchanges::response_base::ResponseData;
+// use global::trace_stack::TraceStack;
+// use standard::exchange::ExchangeEnum::BybitSwap;
+// use crate::core::Core;
+// use crate::exchange_disguise::on_special_depth;
+// use crate::model::OrderInfo;
+//
+// // 1交易、0参考 bybit 合约 启动
+// pub async fn bybit_swap_run(is_shutdown_arc: Arc<AtomicBool>,
+//                             is_trade: bool,
+//                             core_arc: Arc<Mutex<Core>>,
+//                             name: String,
+//                             symbols: Vec<String>,
+//                             is_colo: bool,
+//                             exchange_params: BTreeMap<String, String>) {
+//     // 启动公共频道
+//     let (write_tx_public, write_rx_public) = futures_channel::mpsc::unbounded::<Message>();
+//
+//     let mut ws_public = BybitSwapWs::new_label(name.clone(), is_colo, None, BybitSwapWsType::Public);
+//     ws_public.set_symbols(symbols.clone());
+//     ws_public.set_subscribe(vec![
+//         BybitSwapSubscribeType::PuTickers
+//     ]);
+//     // if is_trade {
+//     //     ws_public.set_subscribe(vec![
+//     //         BybitSwapSubscribeType::PuBlicTrade
+//     //     ]);
+//     // }
+//     // 挂起公共ws
+//     let write_tx_am_public = Arc::new(Mutex::new(write_tx_public));
+//     let is_shutdown_clone_public = Arc::clone(&is_shutdown_arc);
+//     let core_arc_clone_public = core_arc.clone();
+//     spawn(async move {
+//         // 消费数据
+//         let mut update_flag_u = Decimal::ZERO;
+//
+//         let fun = move |data: ResponseData| {
+//             let core_arc = core_arc_clone_public.clone();
+//
+//             async move {
+//                 on_public_data(core_arc,
+//                                &mut update_flag_u,
+//                                data).await;
+//             }
+//         };
+//
+//         // ws_public.ws_connect_async(is_shutdown_clone_public,
+//         //                            fun,
+//         //                            &write_tx_am_public,
+//         //                            write_rx_public).await.expect("链接失败(内部一个心跳线程应该已经关闭了)");
+//     });
+//     let trade_symbols = symbols.clone();
+//     // 交易交易所需要启动私有ws
+//     if is_trade {
+//         let (write_tx_private, write_rx_private) = futures_channel::mpsc::unbounded();
+//         let auth = Some(parse_btree_map_to_bybit_swap_login(exchange_params));
+//
+//         let mut ws_private = BybitSwapWs::new_label(name.clone(), is_colo, auth, BybitSwapWsType::Private);
+//         ws_private.set_symbols(trade_symbols);
+//         ws_private.set_subscribe(vec![
+//             BybitSwapSubscribeType::PrPosition,
+//             BybitSwapSubscribeType::PrOrder,
+//             BybitSwapSubscribeType::PrWallet
+//         ]);
+//
+//         // 挂起私有ws
+//         let write_tx_am_private = Arc::new(Mutex::new(write_tx_private));
+//         let is_shutdown_clone_private = Arc::clone(&is_shutdown_arc);
+//         let core_arc_clone_private = core_arc.clone();
+//         spawn(async move {
+//             let ct_val = core_arc_clone_private.lock().await.platform_rest.get_self_market().ct_val;
+//             let run_symbol = symbols.clone()[0].clone();
+//
+//             let fun = move |data: ResponseData| {
+//                 let core_arc_clone = core_arc_clone_private.clone();
+//                 let run_symbol_clone = run_symbol.clone();
+//
+//                 async move {
+//                     on_private_data(core_arc_clone.clone(), &ct_val, &run_symbol_clone, data).await;
 //                 }
-//             },
-//             None => {
-//                 depth_asks.push(i.clone());
-//             },
+//             };
+//
+//             ws_private.ws_connect_async(is_shutdown_clone_private,
+//                                         fun,
+//                                         &write_tx_am_private,
+//                                         write_rx_private).await.expect("链接失败(内部一个心跳线程应该已经关闭了)");
+//         });
+//     }
+// }
+//
+// async fn on_private_data(core_arc_clone: Arc<Mutex<Core>>, ct_val: &Decimal, run_symbol: &String, response: ResponseData) {
+//     let mut trace_stack = TraceStack::new(response.time, response.ins);
+//     trace_stack.on_after_span_line();
+//
+//     match response.channel.as_str() {
+//         // "wallet" => {
+//         //     let account = standard::handle_info::HandleSwapInfo::handle_account_info(BybitSwap, &response, run_symbol);
+//         //     let mut core = core_arc_clone.lock().await;
+//         //     core.update_equity(account).await;
+//         // }
+//         // "order" => {
+//         //     let orders = standard::handle_info::HandleSwapInfo::handle_order(BybitSwap, response.clone(), ct_val.clone());
+//         //     trace_stack.on_after_format();
+//         //
+//         //     let mut order_infos:Vec<OrderInfo> = Vec::new();
+//         //     for mut order in orders.order {
+//         //         if order.status == "NULL" {
+//         //             error!("bybit_usdt_swap 未识别的订单状态:{:?}", response);
+//         //
+//         //             continue;
+//         //         }
+//         //
+//         //         if order.deal_amount != Decimal::ZERO {
+//         //             info!("bybit order 消息原文:{:?}", response);
+//         //         }
+//         //
+//         //         let order_info = OrderInfo::parse_order_to_order_info(&mut order);
+//         //         order_infos.push(order_info);
+//         //     }
+//         //
+//         //     let mut core = core_arc_clone.lock().await;
+//         //     core.update_order(order_infos, trace_stack).await;
+//         // }
+//         // "position" => {
+//         //     let positions = standard::handle_info::HandleSwapInfo::handle_position(BybitSwap, &response, ct_val);
+//         //     let mut core = core_arc_clone.lock().await;
+//         //     core.update_position(positions).await;
+//         // }
+//         _ => {
+//             error!("未知推送类型");
+//             error!(?response);
 //         }
 //     }
-//     for i in bids {
-//         let index_of_value = depth_bids.iter().position(|x| x.price == i.price);
-//         match index_of_value {
-//             Some(index) => {
-//                 if i.amount == Decimal::ZERO {
-//                     depth_bids.remove(index);
-//                 } else {
-//                     depth_bids[index].amount = i.amount.clone();
-//                 }
-//             },
-//             None => {
-//                 depth_bids.push(i.clone());
-//             },
+// }
+//
+// async fn on_public_data(core_arc_clone: Arc<Mutex<Core>>, update_flag_u: &mut Decimal, response: ResponseData) {
+//     if response.code != 200 {
+//         return;
+//     }
+//
+//     let mut trace_stack = TraceStack::new(response.time, response.ins);
+//     trace_stack.on_after_span_line();
+//
+//     match response.channel.as_str() {
+//         "tickers" => {
+//             // trace_stack.set_source("bybit_usdt_swap.tickers".to_string());
+//             //
+//             // // 处理ticker信息
+//             // let special_depth = standard::handle_info::HandleSwapInfo::handle_book_ticker(BybitSwap, &response);
+//             // trace_stack.on_after_format();
+//             //
+//             // on_special_depth(core_arc_clone, update_flag_u, &response.label, &mut trace_stack, &special_depth).await;
+//         }
+//         "orderbook" => {
+//             // let mut is_update = false;
+//             // let data_type = data.data_type.clone();
+//             // let label = data.label.clone();
+//             // if data_type == "delta"  {
+//             //     is_update = true;
+//             // }
+//             // let mut depth_format: DepthParam = format_depth(BybitSwap, &data);
+//             // // 是增量更新
+//             // if is_update {
+//             //     update_order_book(depth_asks, depth_bids, depth_format.depth_asks, depth_format.depth_bids);
+//             // } else { // 全量
+//             //     depth_asks.clear();
+//             //     depth_asks.append(&mut depth_format.depth_asks);
+//             //     depth_bids.clear();
+//             //     depth_bids.append(&mut depth_format.depth_bids);
+//             // }
+//             // let depth = make_special_depth(label.clone(), depth_asks, depth_bids, depth_format.t, depth_format.create_at);
+//             // trace_stack.on_before_network(depth_format.create_at.clone());
+//             // trace_stack.on_after_format();
+//             //
+//             // on_special_depth(core_arc_clone, update_flag_u, &label, &mut trace_stack, &depth).await;
+//         }
+//         "trade" => {
+//             // let mut core = core_arc_clone.lock().await;
+//             // let str = data.label.clone();
+//             // if core.is_update.contains_key(&data.label) && *core.is_update.get(str.as_str()).unwrap(){
+//             //     *max_buy = Decimal::ZERO;
+//             //     *min_sell = Decimal::ZERO;
+//             //     core.is_update.remove(str.as_str());
+//             // }
+//             // let trades: Vec<OriginalTradeBy> = serde_json::from_str(data.data.as_str()).unwrap();
+//             // for trade in trades {
+//             //     if trade.p > *max_buy || *max_buy == Decimal::ZERO{
+//             //         *max_buy = trade.p
+//             //     }
+//             //     if trade.p < *min_sell || *min_sell == Decimal::ZERO{
+//             //         *min_sell = trade.p
+//             //     }
+//             // }
+//             // core.max_buy_min_sell_cache.insert(data.label, vec![*max_buy, *min_sell]);
 //         }
+//         _ => {}
 //     }
-//     depth_asks.sort_by(|a, b| a.price.partial_cmp(&b.price).unwrap_or(Ordering::Equal));
-//     depth_bids.sort_by(|a, b| b.price.partial_cmp(&a.price).unwrap_or(Ordering::Equal));
+// }
 //
-//     // 限制总长度100
-//     depth_asks.truncate(100);
-//     depth_bids.truncate(100);
+// fn parse_btree_map_to_bybit_swap_login(exchange_params: BTreeMap<String, String>) -> BybitSwapLogin {
+//     BybitSwapLogin {
+//         api_key: exchange_params.get("access_key").unwrap().clone(),
+//         secret_key: exchange_params.get("secret_key").unwrap().clone(),
+//     }
 // }
+//
+// // fn update_order_book(depth_asks: &mut Vec<MarketOrder>, depth_bids: &mut Vec<MarketOrder>, asks : Vec<MarketOrder>, bids: Vec<MarketOrder>) {
+// //     for i in asks {
+// //         let index_of_value = depth_asks.iter().position(|x| x.price == i.price);
+// //         match index_of_value {
+// //             Some(index) => {
+// //                 if i.amount == Decimal::ZERO {
+// //                     depth_asks.remove(index);
+// //                 } else {
+// //                     depth_asks[index].amount = i.amount.clone();
+// //                 }
+// //             },
+// //             None => {
+// //                 depth_asks.push(i.clone());
+// //             },
+// //         }
+// //     }
+// //     for i in bids {
+// //         let index_of_value = depth_bids.iter().position(|x| x.price == i.price);
+// //         match index_of_value {
+// //             Some(index) => {
+// //                 if i.amount == Decimal::ZERO {
+// //                     depth_bids.remove(index);
+// //                 } else {
+// //                     depth_bids[index].amount = i.amount.clone();
+// //                 }
+// //             },
+// //             None => {
+// //                 depth_bids.push(i.clone());
+// //             },
+// //         }
+// //     }
+// //     depth_asks.sort_by(|a, b| a.price.partial_cmp(&b.price).unwrap_or(Ordering::Equal));
+// //     depth_bids.sort_by(|a, b| b.price.partial_cmp(&a.price).unwrap_or(Ordering::Equal));
+// //
+// //     // 限制总长度100
+// //     depth_asks.truncate(100);
+// //     depth_bids.truncate(100);
+// // }

+ 16 - 16
strategy/src/clear_core.rs

@@ -18,7 +18,7 @@ use global::params::Params;
 use global::trace_stack::TraceStack;
 use standard::{Account, Market, Order, Platform, Position, PositionModeEnum, SpecialTicker};
 use standard::exchange::{Exchange};
-use standard::exchange::ExchangeEnum::{BinanceSwap, BitgetSwap, BybitSwap, CoinexSwap, GateSwap, HtxSwap, KucoinSwap};
+use standard::exchange::ExchangeEnum::{BinanceSwap, GateSwap};
 
 use crate::model::{LocalPosition, OrderInfo};
 use crate::predictor::Predictor;
@@ -199,9 +199,9 @@ impl ClearCore {
                 amount_size: Default::default(),
             },
             platform_rest: match exchange.as_str() {
-                "kucoin_usdt_swap" => {
-                    Exchange::new(KucoinSwap, symbol, params.colo != 0i8, exchange_params, order_sender, error_sender).await
-                }
+                // "kucoin_usdt_swap" => {
+                //     Exchange::new(KucoinSwap, symbol, params.colo != 0i8, exchange_params, order_sender, error_sender).await
+                // }
                 "gate_usdt_swap" => {
                     Exchange::new(GateSwap, symbol, params.colo != 0i8, exchange_params, order_sender, error_sender).await
                 }
@@ -217,21 +217,21 @@ impl ClearCore {
                 // "bitget_spot" => {
                 //     Exchange::new(BitgetSpot, symbol, params.colo != 0i8, exchange_params, order_sender, error_sender).await
                 // }
-                "bitget_usdt_swap" => {
-                    Exchange::new(BitgetSwap, symbol, params.colo != 0i8, exchange_params, order_sender, error_sender).await
-                }
+                // "bitget_usdt_swap" => {
+                //     Exchange::new(BitgetSwap, symbol, params.colo != 0i8, exchange_params, order_sender, error_sender).await
+                // }
                 // "okex_usdt_swap" => {
                 //     Exchange::new(OkxSwap, symbol, params.colo != 0i8, exchange_params, order_sender, error_sender).await
                 // }
-                "bybit_usdt_swap" => {
-                    Exchange::new(BybitSwap, symbol, params.colo != 0i8, exchange_params, order_sender, error_sender).await
-                }
-                "coinex_usdt_swap" => {
-                    Exchange::new(CoinexSwap, symbol, params.colo != 0i8, exchange_params, order_sender, error_sender).await
-                }
-                "htx_usdt_swap" => {
-                    Exchange::new(HtxSwap, symbol, params.colo != 0i8, exchange_params, order_sender, error_sender).await
-                }
+                // "bybit_usdt_swap" => {
+                //     Exchange::new(BybitSwap, symbol, params.colo != 0i8, exchange_params, order_sender, error_sender).await
+                // }
+                // "coinex_usdt_swap" => {
+                //     Exchange::new(CoinexSwap, symbol, params.colo != 0i8, exchange_params, order_sender, error_sender).await
+                // }
+                // "htx_usdt_swap" => {
+                //     Exchange::new(HtxSwap, symbol, params.colo != 0i8, exchange_params, order_sender, error_sender).await
+                // }
                 _ => {
                     error!("203未找到对应的交易所rest枚举!");
                     panic!("203未找到对应的交易所rest枚举!");

+ 270 - 270
strategy/src/coinex_usdt_swap.rs

@@ -1,270 +1,270 @@
-use tracing::{error};
-use std::collections::BTreeMap;
-use std::sync::Arc;
-use std::sync::atomic::AtomicBool;
-use rust_decimal::Decimal;
-use tokio::spawn;
-use tokio::sync::Mutex;
-use exchanges::coinex_swap_ws::{CoinexSwapLogin, CoinexSwapSubscribeType, CoinexSwapWs};
-use exchanges::response_base::ResponseData;
-use global::trace_stack::{TraceStack};
-use standard::exchange::ExchangeEnum::{CoinexSwap};
-use crate::model::{OrderInfo};
-use crate::core::Core;
-use crate::exchange_disguise::on_special_depth;
-
-// 1交易、0参考 coinex 合约 启动
-pub async fn coinex_swap_run(is_shutdown_arc: Arc<AtomicBool>,
-                           is_trade: bool,
-                           core_arc: Arc<Mutex<Core>>,
-                           name: String,
-                           symbols: Vec<String>,
-                           _is_colo: bool,
-                           exchange_params: BTreeMap<String, String>) {
-    let (write_tx, write_rx) = futures_channel::mpsc::unbounded();
-
-    let write_tx_am = Arc::new(Mutex::new(write_tx));
-    let symbols_clone = symbols.clone();
-    spawn(async move {
-        let mut ws;
-        // 交易
-        if is_trade {
-            let login_param = parse_btree_map_to_coinex_swap_login(exchange_params);
-            ws = CoinexSwapWs::new_label(name.clone(), Some(login_param));
-            ws.set_subscribe(vec![
-                // CoinexSwapSubscribeType::PuFuturesDeals,
-                CoinexSwapSubscribeType::PuFuturesDepth,
-
-                CoinexSwapSubscribeType::PrFuturesOrders,
-                CoinexSwapSubscribeType::PrFuturesPositions,
-                CoinexSwapSubscribeType::PrFuturesBalances,
-            ]);
-        } else { // 参考
-            ws = CoinexSwapWs::new_label(name.clone(), None);
-            ws.set_subscribe(vec![
-                // CoinexSwapSubscribeType::PuFuturesDeals,
-                CoinexSwapSubscribeType::PuFuturesDepth
-            ]);
-        }
-
-        // 读取数据
-        let mut update_flag_u = Decimal::ZERO;
-        let core_arc_clone = Arc::clone(&core_arc);
-        let multiplier = core_arc_clone.lock().await.platform_rest.get_self_market().ct_val;
-        let run_symbol = symbols.clone()[0].clone();
-
-        let fun = move |data: ResponseData| {
-            let core_arc_cc = core_arc_clone.clone();
-            // 在 async 块之前克隆 Arc
-            let mul = multiplier.clone();
-            let rs = run_symbol.clone();
-
-            async move {
-                on_data(core_arc_cc,
-                        &mut update_flag_u,
-                        &mul,
-                        &rs,
-                        data,
-                ).await
-            }
-        };
-
-        // 建立链接
-        ws.set_symbols(symbols_clone);
-        ws.ws_connect_async(is_shutdown_arc, fun, &write_tx_am, write_rx).await.expect("链接失败(内部一个心跳线程应该已经关闭了)");
-    });
-}
-
-async fn on_data(core_arc_clone: Arc<Mutex<Core>>,
-                 update_flag_u: &mut Decimal,
-                 multiplier: &Decimal,
-                 run_symbol: &String,
-                 response: ResponseData) {
-    let mut trace_stack = TraceStack::new(response.time, response.ins);
-    trace_stack.on_after_span_line();
-
-    match response.channel.as_str() {
-        "depth.update" => {
-            trace_stack.set_source("coinex_usdt_swap.order_book".to_string());
-            let special_depth = standard::handle_info::HandleSwapInfo::handle_special_depth(CoinexSwap, &response);
-            trace_stack.on_after_format();
-
-            on_special_depth(core_arc_clone, update_flag_u, &response.label, &mut trace_stack, &special_depth).await;
-        }
-        "balance.update" => {
-            let account = standard::handle_info::HandleSwapInfo::handle_account_info(CoinexSwap, &response, run_symbol);
-            let mut core = core_arc_clone.lock().await;
-            core.update_equity(account).await;
-        }
-        "order.update" => {
-            trace_stack.set_source("coinex_swap.orders".to_string());
-            let orders = standard::handle_info::HandleSwapInfo::handle_order(CoinexSwap, response.clone(), multiplier.clone());
-            let mut order_infos:Vec<OrderInfo> = Vec::new();
-            for mut order in orders.order {
-                if order.status == "NULL" {
-                    error!("coinex_usdt_swap 未识别的订单状态:{:?}", response);
-                    continue;
-                }
-
-                let order_info = OrderInfo::parse_order_to_order_info(&mut order);
-                order_infos.push(order_info);
-            }
-
-            if order_infos.is_empty() {
-                error!("coinex_usdt_swap 未识别的订单 格式化失败:{:?}", response);
-                return
-            }
-            let mut new_order = order_infos[0].clone();
-            let mut core = core_arc_clone.lock().await;
-            // 本地订单缓存判断
-            if !core.local_orders_backup.contains_key(&new_order.client_id) {
-                return
-            }
-
-            // 获取订单目的
-            let mut rst = vec![];
-            let side = core.local_orders_backup.get(&new_order.client_id).unwrap().side.as_str();
-            let local_position_by_orders = &core.local_position_by_orders;
-            let long_pos = local_position_by_orders.long_pos;
-            let short_pos = local_position_by_orders.short_pos;
-
-            // 部分成交和新订单的处理,不用走下面的逻辑
-            if new_order.status != "REMOVE" || new_order.filled == Decimal::ZERO {
-                core.update_order(order_infos, trace_stack).await;
-                return
-            }
-
-            // 单向持仓的处理
-            match side {
-                "kd" => {
-                    if short_pos != Decimal::ZERO {
-                        let vir_order_filled;
-                        if short_pos >= new_order.amount {
-                            vir_order_filled = new_order.amount;
-                        } else {
-                            vir_order_filled = short_pos
-                        }
-                        // 构造虚拟订单
-                        let vir_client_id = format!("{}vir", new_order.client_id.clone());
-                        let vir_order = OrderInfo {
-                            symbol: "".to_string(),
-                            amount: vir_order_filled,
-                            side: "pk".to_string(),
-                            price: new_order.price,
-                            client_id: vir_client_id.clone(),
-                            filled_price: new_order.price,
-                            filled: vir_order_filled,
-                            order_id: "".to_string(),
-                            local_time: 0,
-                            create_time: 0,
-                            status: new_order.status.clone(),
-                            fee: Default::default(),
-                            trace_stack: trace_stack.clone(),
-                        };
-                        core.local_orders_backup.insert(vir_client_id.clone(), vir_order.clone());
-
-                        // 原始订单处理
-                        new_order.amount -= vir_order_filled;
-                        new_order.filled -= vir_order_filled;
-
-                        rst.push(vir_order.clone());
-                        if new_order.amount > Decimal::ZERO {
-                            rst.push(new_order.clone());
-                        } else {
-                            core.local_cancel_log.remove(&new_order.client_id);
-                            core.local_orders_backup.remove(&new_order.client_id);
-                            core.local_orders.remove(&new_order.client_id);
-                        }
-                    } else {
-                        rst.push(new_order.clone());
-                    }
-                }
-                "kk" => {
-                    if long_pos != Decimal::ZERO {
-                        let vir_order_filled;
-                        if long_pos >= new_order.amount {
-                            vir_order_filled = new_order.amount;
-                        } else {
-                            vir_order_filled = long_pos
-                        }
-                        // 构造虚拟订单
-                        let vir_client_id = format!("{}vir", new_order.client_id.clone());
-                        let vir_order = OrderInfo {
-                            symbol: "".to_string(),
-                            amount: vir_order_filled,
-                            side: "pd".to_string(),
-                            price: new_order.price,
-                            client_id: vir_client_id.clone(),
-                            filled_price: new_order.price,
-                            filled: vir_order_filled,
-                            order_id: "".to_string(),
-                            local_time: 0,
-                            create_time: 0,
-                            status: new_order.status.clone(),
-                            fee: Default::default(),
-                            trace_stack: trace_stack.clone(),
-                        };
-                        core.local_orders_backup.insert(vir_client_id.clone(), vir_order.clone());
-
-                        // 原始订单处理
-                        new_order.amount -= vir_order_filled;
-                        new_order.filled -= vir_order_filled;
-
-                        rst.push(vir_order.clone());
-                        if new_order.amount > Decimal::ZERO {
-                            rst.push(new_order.clone());
-                        } else {
-                            core.local_cancel_log.remove(&new_order.client_id);
-                            core.local_orders_backup.remove(&new_order.client_id);
-                            core.local_orders.remove(&new_order.client_id);
-                        }
-                    } else {
-                        rst.push(new_order.clone());
-                    }
-                }
-                _ => {
-                    rst = order_infos;
-                }
-            }
-
-            core.update_order(rst, trace_stack).await;
-        }
-        "position.update" => {
-            // info!("coinex_usdt_swap 仓位推送:{:?}", response.data);
-            let positions = standard::handle_info::HandleSwapInfo::handle_position(CoinexSwap, &response, multiplier);
-            let mut core = core_arc_clone.lock().await;
-
-            core.update_position(positions).await;
-        }
-        "deals.update" => {
-            // let mut core = core_arc_clone.lock().await;
-            // let str = data.label.clone();
-            // if core.is_update.contains_key(&data.label) && *core.is_update.get(str.as_str()).unwrap(){
-            //     *max_buy = Decimal::ZERO;
-            //     *min_sell = Decimal::ZERO;
-            //     core.is_update.remove(str.as_str());
-            // }
-            // let trades: Vec<OriginalTradeGa> = serde_json::from_str(data.data.as_str()).unwrap();
-            // for trade in trades {
-            //     if trade.price > *max_buy || *max_buy == Decimal::ZERO{
-            //         *max_buy = trade.price
-            //     }
-            //     if trade.price < *min_sell || *min_sell == Decimal::ZERO{
-            //         *min_sell = trade.price
-            //     }
-            // }
-            // core.max_buy_min_sell_cache.insert(data.label, vec![*max_buy, *min_sell]);
-        }
-        _ => {
-            error!("未知推送类型");
-            error!(?response);
-        }
-    }
-}
-
-fn parse_btree_map_to_coinex_swap_login(exchange_params: BTreeMap<String, String>) -> CoinexSwapLogin {
-    CoinexSwapLogin {
-        api_key: exchange_params.get("access_key").unwrap().clone(),
-        secret: exchange_params.get("secret_key").unwrap().clone()
-    }
-}
+// use tracing::{error};
+// use std::collections::BTreeMap;
+// use std::sync::Arc;
+// use std::sync::atomic::AtomicBool;
+// use rust_decimal::Decimal;
+// use tokio::spawn;
+// use tokio::sync::Mutex;
+// use exchanges::coinex_swap_ws::{CoinexSwapLogin, CoinexSwapSubscribeType, CoinexSwapWs};
+// use exchanges::response_base::ResponseData;
+// use global::trace_stack::{TraceStack};
+// use standard::exchange::ExchangeEnum::{CoinexSwap};
+// use crate::model::{OrderInfo};
+// use crate::core::Core;
+// use crate::exchange_disguise::on_special_depth;
+//
+// // 1交易、0参考 coinex 合约 启动
+// pub async fn coinex_swap_run(is_shutdown_arc: Arc<AtomicBool>,
+//                            is_trade: bool,
+//                            core_arc: Arc<Mutex<Core>>,
+//                            name: String,
+//                            symbols: Vec<String>,
+//                            _is_colo: bool,
+//                            exchange_params: BTreeMap<String, String>) {
+//     let (write_tx, write_rx) = futures_channel::mpsc::unbounded();
+//
+//     let write_tx_am = Arc::new(Mutex::new(write_tx));
+//     let symbols_clone = symbols.clone();
+//     spawn(async move {
+//         let mut ws;
+//         // 交易
+//         if is_trade {
+//             let login_param = parse_btree_map_to_coinex_swap_login(exchange_params);
+//             ws = CoinexSwapWs::new_label(name.clone(), Some(login_param));
+//             ws.set_subscribe(vec![
+//                 // CoinexSwapSubscribeType::PuFuturesDeals,
+//                 CoinexSwapSubscribeType::PuFuturesDepth,
+//
+//                 CoinexSwapSubscribeType::PrFuturesOrders,
+//                 CoinexSwapSubscribeType::PrFuturesPositions,
+//                 CoinexSwapSubscribeType::PrFuturesBalances,
+//             ]);
+//         } else { // 参考
+//             ws = CoinexSwapWs::new_label(name.clone(), None);
+//             ws.set_subscribe(vec![
+//                 // CoinexSwapSubscribeType::PuFuturesDeals,
+//                 CoinexSwapSubscribeType::PuFuturesDepth
+//             ]);
+//         }
+//
+//         // 读取数据
+//         let mut update_flag_u = Decimal::ZERO;
+//         let core_arc_clone = Arc::clone(&core_arc);
+//         let multiplier = core_arc_clone.lock().await.platform_rest.get_self_market().ct_val;
+//         let run_symbol = symbols.clone()[0].clone();
+//
+//         let fun = move |data: ResponseData| {
+//             let core_arc_cc = core_arc_clone.clone();
+//             // 在 async 块之前克隆 Arc
+//             let mul = multiplier.clone();
+//             let rs = run_symbol.clone();
+//
+//             async move {
+//                 on_data(core_arc_cc,
+//                         &mut update_flag_u,
+//                         &mul,
+//                         &rs,
+//                         data,
+//                 ).await
+//             }
+//         };
+//
+//         // 建立链接
+//         ws.set_symbols(symbols_clone);
+//         ws.ws_connect_async(is_shutdown_arc, fun, &write_tx_am, write_rx).await.expect("链接失败(内部一个心跳线程应该已经关闭了)");
+//     });
+// }
+//
+// async fn on_data(core_arc_clone: Arc<Mutex<Core>>,
+//                  update_flag_u: &mut Decimal,
+//                  multiplier: &Decimal,
+//                  run_symbol: &String,
+//                  response: ResponseData) {
+//     let mut trace_stack = TraceStack::new(response.time, response.ins);
+//     trace_stack.on_after_span_line();
+//
+//     match response.channel.as_str() {
+//         // "depth.update" => {
+//         //     trace_stack.set_source("coinex_usdt_swap.order_book".to_string());
+//         //     let special_depth = standard::handle_info::HandleSwapInfo::handle_special_depth(CoinexSwap, &response);
+//         //     trace_stack.on_after_format();
+//         //
+//         //     on_special_depth(core_arc_clone, update_flag_u, &response.label, &mut trace_stack, &special_depth).await;
+//         // }
+//         // "balance.update" => {
+//         //     let account = standard::handle_info::HandleSwapInfo::handle_account_info(CoinexSwap, &response, run_symbol);
+//         //     let mut core = core_arc_clone.lock().await;
+//         //     core.update_equity(account).await;
+//         // }
+//         // "order.update" => {
+//         //     trace_stack.set_source("coinex_swap.orders".to_string());
+//         //     let orders = standard::handle_info::HandleSwapInfo::handle_order(CoinexSwap, response.clone(), multiplier.clone());
+//         //     let mut order_infos:Vec<OrderInfo> = Vec::new();
+//         //     for mut order in orders.order {
+//         //         if order.status == "NULL" {
+//         //             error!("coinex_usdt_swap 未识别的订单状态:{:?}", response);
+//         //             continue;
+//         //         }
+//         //
+//         //         let order_info = OrderInfo::parse_order_to_order_info(&mut order);
+//         //         order_infos.push(order_info);
+//         //     }
+//         //
+//         //     if order_infos.is_empty() {
+//         //         error!("coinex_usdt_swap 未识别的订单 格式化失败:{:?}", response);
+//         //         return
+//         //     }
+//         //     let mut new_order = order_infos[0].clone();
+//         //     let mut core = core_arc_clone.lock().await;
+//         //     // 本地订单缓存判断
+//         //     if !core.local_orders_backup.contains_key(&new_order.client_id) {
+//         //         return
+//         //     }
+//         //
+//         //     // 获取订单目的
+//         //     let mut rst = vec![];
+//         //     let side = core.local_orders_backup.get(&new_order.client_id).unwrap().side.as_str();
+//         //     let local_position_by_orders = &core.local_position_by_orders;
+//         //     let long_pos = local_position_by_orders.long_pos;
+//         //     let short_pos = local_position_by_orders.short_pos;
+//         //
+//         //     // 部分成交和新订单的处理,不用走下面的逻辑
+//         //     if new_order.status != "REMOVE" || new_order.filled == Decimal::ZERO {
+//         //         core.update_order(order_infos, trace_stack).await;
+//         //         return
+//         //     }
+//         //
+//         //     // 单向持仓的处理
+//         //     match side {
+//         //         "kd" => {
+//         //             if short_pos != Decimal::ZERO {
+//         //                 let vir_order_filled;
+//         //                 if short_pos >= new_order.amount {
+//         //                     vir_order_filled = new_order.amount;
+//         //                 } else {
+//         //                     vir_order_filled = short_pos
+//         //                 }
+//         //                 // 构造虚拟订单
+//         //                 let vir_client_id = format!("{}vir", new_order.client_id.clone());
+//         //                 let vir_order = OrderInfo {
+//         //                     symbol: "".to_string(),
+//         //                     amount: vir_order_filled,
+//         //                     side: "pk".to_string(),
+//         //                     price: new_order.price,
+//         //                     client_id: vir_client_id.clone(),
+//         //                     filled_price: new_order.price,
+//         //                     filled: vir_order_filled,
+//         //                     order_id: "".to_string(),
+//         //                     local_time: 0,
+//         //                     create_time: 0,
+//         //                     status: new_order.status.clone(),
+//         //                     fee: Default::default(),
+//         //                     trace_stack: trace_stack.clone(),
+//         //                 };
+//         //                 core.local_orders_backup.insert(vir_client_id.clone(), vir_order.clone());
+//         //
+//         //                 // 原始订单处理
+//         //                 new_order.amount -= vir_order_filled;
+//         //                 new_order.filled -= vir_order_filled;
+//         //
+//         //                 rst.push(vir_order.clone());
+//         //                 if new_order.amount > Decimal::ZERO {
+//         //                     rst.push(new_order.clone());
+//         //                 } else {
+//         //                     core.local_cancel_log.remove(&new_order.client_id);
+//         //                     core.local_orders_backup.remove(&new_order.client_id);
+//         //                     core.local_orders.remove(&new_order.client_id);
+//         //                 }
+//         //             } else {
+//         //                 rst.push(new_order.clone());
+//         //             }
+//         //         }
+//         //         "kk" => {
+//         //             if long_pos != Decimal::ZERO {
+//         //                 let vir_order_filled;
+//         //                 if long_pos >= new_order.amount {
+//         //                     vir_order_filled = new_order.amount;
+//         //                 } else {
+//         //                     vir_order_filled = long_pos
+//         //                 }
+//         //                 // 构造虚拟订单
+//         //                 let vir_client_id = format!("{}vir", new_order.client_id.clone());
+//         //                 let vir_order = OrderInfo {
+//         //                     symbol: "".to_string(),
+//         //                     amount: vir_order_filled,
+//         //                     side: "pd".to_string(),
+//         //                     price: new_order.price,
+//         //                     client_id: vir_client_id.clone(),
+//         //                     filled_price: new_order.price,
+//         //                     filled: vir_order_filled,
+//         //                     order_id: "".to_string(),
+//         //                     local_time: 0,
+//         //                     create_time: 0,
+//         //                     status: new_order.status.clone(),
+//         //                     fee: Default::default(),
+//         //                     trace_stack: trace_stack.clone(),
+//         //                 };
+//         //                 core.local_orders_backup.insert(vir_client_id.clone(), vir_order.clone());
+//         //
+//         //                 // 原始订单处理
+//         //                 new_order.amount -= vir_order_filled;
+//         //                 new_order.filled -= vir_order_filled;
+//         //
+//         //                 rst.push(vir_order.clone());
+//         //                 if new_order.amount > Decimal::ZERO {
+//         //                     rst.push(new_order.clone());
+//         //                 } else {
+//         //                     core.local_cancel_log.remove(&new_order.client_id);
+//         //                     core.local_orders_backup.remove(&new_order.client_id);
+//         //                     core.local_orders.remove(&new_order.client_id);
+//         //                 }
+//         //             } else {
+//         //                 rst.push(new_order.clone());
+//         //             }
+//         //         }
+//         //         _ => {
+//         //             rst = order_infos;
+//         //         }
+//         //     }
+//         //
+//         //     core.update_order(rst, trace_stack).await;
+//         // }
+//         // "position.update" => {
+//         //     // info!("coinex_usdt_swap 仓位推送:{:?}", response.data);
+//         //     let positions = standard::handle_info::HandleSwapInfo::handle_position(CoinexSwap, &response, multiplier);
+//         //     let mut core = core_arc_clone.lock().await;
+//         //
+//         //     core.update_position(positions).await;
+//         // }
+//         // "deals.update" => {
+//         //     // let mut core = core_arc_clone.lock().await;
+//         //     // let str = data.label.clone();
+//         //     // if core.is_update.contains_key(&data.label) && *core.is_update.get(str.as_str()).unwrap(){
+//         //     //     *max_buy = Decimal::ZERO;
+//         //     //     *min_sell = Decimal::ZERO;
+//         //     //     core.is_update.remove(str.as_str());
+//         //     // }
+//         //     // let trades: Vec<OriginalTradeGa> = serde_json::from_str(data.data.as_str()).unwrap();
+//         //     // for trade in trades {
+//         //     //     if trade.price > *max_buy || *max_buy == Decimal::ZERO{
+//         //     //         *max_buy = trade.price
+//         //     //     }
+//         //     //     if trade.price < *min_sell || *min_sell == Decimal::ZERO{
+//         //     //         *min_sell = trade.price
+//         //     //     }
+//         //     // }
+//         //     // core.max_buy_min_sell_cache.insert(data.label, vec![*max_buy, *min_sell]);
+//         // }
+//         _ => {
+//             error!("未知推送类型");
+//             error!(?response);
+//         }
+//     }
+// }
+//
+// fn parse_btree_map_to_coinex_swap_login(exchange_params: BTreeMap<String, String>) -> CoinexSwapLogin {
+//     CoinexSwapLogin {
+//         api_key: exchange_params.get("access_key").unwrap().clone(),
+//         secret: exchange_params.get("secret_key").unwrap().clone()
+//     }
+// }

+ 20 - 18
strategy/src/core.rs

@@ -23,7 +23,7 @@ use global::trace_stack::TraceStack;
 use global::trade::Trade;
 use standard::{Account, Market, Order, OrderCommand, Platform, Position, PositionModeEnum, SpecialTicker, Ticker};
 use standard::exchange::{Exchange};
-use standard::exchange::ExchangeEnum::{BinanceSwap, BitgetSwap, BybitSwap, CoinexSwap, GateSwap, HtxSwap, KucoinSwap};
+use standard::exchange::ExchangeEnum::{BinanceSwap, GateSwap};
 
 use crate::model::{LocalPosition, OrderInfo, TokenParam};
 use crate::predictor::Predictor;
@@ -210,9 +210,9 @@ impl Core {
                 amount_size: Default::default(),
             },
             platform_rest: match exchange.as_str() {
-                "kucoin_usdt_swap" => {
-                    Exchange::new(KucoinSwap, symbol, params.colo != 0i8, exchange_params, order_sender, error_sender).await
-                }
+                // "kucoin_usdt_swap" => {
+                //     Exchange::new(KucoinSwap, symbol, params.colo != 0i8, exchange_params, order_sender, error_sender).await
+                // }
                 "gate_usdt_swap" => {
                     Exchange::new(GateSwap, symbol, params.colo != 0i8, exchange_params, order_sender, error_sender).await
                 }
@@ -228,21 +228,21 @@ impl Core {
                 // "bitget_spot" => {
                 //     Exchange::new(BitgetSpot, symbol, params.colo != 0i8, exchange_params, order_sender, error_sender).await
                 // }
-                "bitget_usdt_swap" => {
-                    Exchange::new(BitgetSwap, symbol, params.colo != 0i8, exchange_params, order_sender, error_sender).await
-                }
+                // "bitget_usdt_swap" => {
+                //     Exchange::new(BitgetSwap, symbol, params.colo != 0i8, exchange_params, order_sender, error_sender).await
+                // }
                 // "okex_usdt_swap" => {
                 //     Exchange::new(OkxSwap, symbol, params.colo != 0i8, exchange_params, order_sender, error_sender).await
                 // }
-                "bybit_usdt_swap" => {
-                    Exchange::new(BybitSwap, symbol, params.colo != 0i8, exchange_params, order_sender, error_sender).await
-                }
-                "coinex_usdt_swap" => {
-                    Exchange::new(CoinexSwap, symbol, params.colo != 0i8, exchange_params, order_sender, error_sender).await
-                }
-                "htx_usdt_swap" => {
-                    Exchange::new(HtxSwap, symbol, params.colo != 0i8, exchange_params, order_sender, error_sender).await
-                }
+                // "bybit_usdt_swap" => {
+                //     Exchange::new(BybitSwap, symbol, params.colo != 0i8, exchange_params, order_sender, error_sender).await
+                // }
+                // "coinex_usdt_swap" => {
+                //     Exchange::new(CoinexSwap, symbol, params.colo != 0i8, exchange_params, order_sender, error_sender).await
+                // }
+                // "htx_usdt_swap" => {
+                //     Exchange::new(HtxSwap, symbol, params.colo != 0i8, exchange_params, order_sender, error_sender).await
+                // }
                 _ => {
                     error!("203未找到对应的交易所rest枚举!");
                     panic!("203未找到对应的交易所rest枚举!");
@@ -1856,8 +1856,10 @@ pub fn on_timer(core_arc: Arc<Mutex<Core>>) -> JoinHandle<()> {
                 // 计算预估成交额
                 let total_trade_value = core.local_buy_value + core.local_sell_value;
                 let time_diff = Decimal::from(Utc::now().timestamp_millis() - core.start_time);
-                let trade_vol_24h = (total_trade_value / time_diff) * dec!(86400);
-                core.strategy.trade_vol_24h_w = trade_vol_24h / dec!(10000);
+                let _86400 = dec!(86400);
+                let _10000 = dec!(10000);
+                let trade_vol_24h = (total_trade_value / time_diff) * _86400;
+                core.strategy.trade_vol_24h_w = trade_vol_24h / _10000;
                 core.strategy.trade_vol_24h_w.rescale(2);
 
                 // TODO core没有rest

+ 42 - 52
strategy/src/exchange_disguise.rs

@@ -1,24 +1,14 @@
 use std::collections::BTreeMap;
 use std::sync::Arc;
 use std::sync::atomic::AtomicBool;
-use std::time::Duration;
 use rust_decimal::Decimal;
 use tokio::sync::Mutex;
 use global::trace_stack::TraceStack;
 use standard::SpecialDepth;
 
 use crate::binance_usdt_swap::reference_binance_swap_run;
-use crate::bitget_usdt_swap::bitget_usdt_swap_run;
 use crate::gate_usdt_swap::gate_swap_run;
-// use crate::binance_spot::reference_binance_spot_run;
-// use crate::bitget_spot::bitget_spot_run;
-use crate::bybit_usdt_swap::bybit_swap_run;
-use crate::coinex_usdt_swap::coinex_swap_run;
-// use crate::kucoin_spot::kucoin_spot_run;
-use crate::kucoin_swap::kucoin_swap_run;
-// use crate::okx_usdt_swap::okex_swap_run;
 use crate::core::Core;
-use crate::htx_usdt_swap::htx_swap_run;
 
 // 交易交易所启动
 pub async fn run_transactional_exchange(is_shutdown_arc :Arc<AtomicBool>,
@@ -32,28 +22,28 @@ pub async fn run_transactional_exchange(is_shutdown_arc :Arc<AtomicBool>,
         "gate_usdt_swap" => {
             gate_swap_run(is_shutdown_arc, true, core_arc, name, symbols, is_colo, exchange_params).await;
         }
-        "kucoin_usdt_swap" => {
-            kucoin_swap_run(is_shutdown_arc, true, core_arc, name, symbols, is_colo, exchange_params).await;
-        },
+        // "kucoin_usdt_swap" => {
+        //     kucoin_swap_run(is_shutdown_arc, true, core_arc, name, symbols, is_colo, exchange_params).await;
+        // },
         // "okex_usdt_swap" => {
         //     okex_swap_run(is_shutdown_arc,true, core_arc, name, symbols, is_colo, exchange_params).await;
         // },
         // "bitget_spot" => {
         //     bitget_spot_run(is_shutdown_arc,true, core_arc, name, symbols, is_colo, exchange_params).await;
         // },
-        "bitget_usdt_swap" => {
-            bitget_usdt_swap_run(is_shutdown_arc, true, core_arc, name, symbols, is_colo, exchange_params).await;
-        }
-        "bybit_usdt_swap" => {
-            bybit_swap_run(is_shutdown_arc,true, core_arc, name, symbols, is_colo, exchange_params).await;
-        }
-        "coinex_usdt_swap" => {
-            tokio::time::sleep(Duration::from_secs(1)).await;
-            coinex_swap_run(is_shutdown_arc,true, core_arc, name, symbols, is_colo, exchange_params).await;
-        }
-        "htx_usdt_swap" =>{
-            htx_swap_run(is_shutdown_arc,true, core_arc, name, symbols, is_colo, exchange_params).await;
-        }
+        // "bitget_usdt_swap" => {
+        //     bitget_usdt_swap_run(is_shutdown_arc, true, core_arc, name, symbols, is_colo, exchange_params).await;
+        // }
+        // "bybit_usdt_swap" => {
+        //     bybit_swap_run(is_shutdown_arc,true, core_arc, name, symbols, is_colo, exchange_params).await;
+        // }
+        // "coinex_usdt_swap" => {
+        //     tokio::time::sleep(Duration::from_secs(1)).await;
+        //     coinex_swap_run(is_shutdown_arc,true, core_arc, name, symbols, is_colo, exchange_params).await;
+        // }
+        // "htx_usdt_swap" =>{
+        //     htx_swap_run(is_shutdown_arc,true, core_arc, name, symbols, is_colo, exchange_params).await;
+        // }
         _ => {
             let msg = format!("不支持的交易交易所:{}", exchange_name);
             panic!("{}", msg);
@@ -82,28 +72,28 @@ pub async fn run_reference_exchange(is_shutdown_arc: Arc<AtomicBool>,
         // "okex_usdt_swap" => {
         //     okex_swap_run(is_shutdown_arc, false, core_arc, name, symbols, is_colo, exchange_params).await;
         // },
-        "kucoin_usdt_swap" => {
-            kucoin_swap_run(is_shutdown_arc, false, core_arc, name, symbols, is_colo, exchange_params).await;
-        },
+        // "kucoin_usdt_swap" => {
+        //     kucoin_swap_run(is_shutdown_arc, false, core_arc, name, symbols, is_colo, exchange_params).await;
+        // },
         // "kucoin_spot" => {
         //     kucoin_spot_run(is_shutdown_arc, false, core_arc, name, symbols, is_colo, exchange_params).await;
         // },
         // "bitget_spot" => {
         //     bitget_spot_run(is_shutdown_arc, false, core_arc, name, symbols, is_colo, exchange_params).await;
         // },
-        "bitget_usdt_swap" => {
-            bitget_usdt_swap_run(is_shutdown_arc, false, core_arc, name, symbols, is_colo, exchange_params).await;
-        }
-        "bybit_usdt_swap" => {
-            bybit_swap_run(is_shutdown_arc, false, core_arc, name, symbols, is_colo, exchange_params).await;
-        },
-        "coinex_usdt_swap" => {
-            coinex_swap_run(is_shutdown_arc,false, core_arc, name, symbols, is_colo, exchange_params).await;
-
-        }
-        "htx_usdt_swap" =>{
-            htx_swap_run(is_shutdown_arc, false, core_arc, name, symbols, is_colo, exchange_params).await;
-        }
+        // "bitget_usdt_swap" => {
+        //     bitget_usdt_swap_run(is_shutdown_arc, false, core_arc, name, symbols, is_colo, exchange_params).await;
+        // }
+        // "bybit_usdt_swap" => {
+        //     bybit_swap_run(is_shutdown_arc, false, core_arc, name, symbols, is_colo, exchange_params).await;
+        // },
+        // "coinex_usdt_swap" => {
+        //     coinex_swap_run(is_shutdown_arc,false, core_arc, name, symbols, is_colo, exchange_params).await;
+        //
+        // }
+        // "htx_usdt_swap" =>{
+        //     htx_swap_run(is_shutdown_arc, false, core_arc, name, symbols, is_colo, exchange_params).await;
+        // }
         _ => {
             let msg = format!("不支持的参考交易所:{}", exchange_name);
             panic!("{}", msg);
@@ -111,22 +101,22 @@ pub async fn run_reference_exchange(is_shutdown_arc: Arc<AtomicBool>,
     }
 }
 
-pub async fn on_special_depth(core_arc: Arc<Mutex<Core>>,
+pub async fn on_special_depth(_core_arc: Arc<Mutex<Core>>,
                               update_flag_u: &mut Decimal,
-                              label: &String,
+                              _label: &String,
                               trace_stack: &mut TraceStack,
                               special_depth: &SpecialDepth) {
     if special_depth.t > *update_flag_u {
-        let mut core = core_arc.lock().await;
+        // let mut core = core_arc.lock().await;
         trace_stack.on_after_unlock_core();
 
-        core.tickers.insert(label.clone(), special_depth.ticker.clone());
-        core.depths.insert(label.clone(), special_depth.depth.clone());
-
-        // 触发depth更新
-        core.on_depth_update(&(special_depth.depth), &label, trace_stack).await;
-
-        core.local_depths.insert(special_depth.name.clone(), special_depth.depth.clone());
+        // core.tickers.insert(label.clone(), special_depth.ticker.clone());
+        // core.depths.insert(label.clone(), special_depth.depth.clone());
+        //
+        // // 触发depth更新
+        // core.on_depth_update(&(special_depth.depth), &label, trace_stack).await;
+        //
+        // core.local_depths.insert(special_depth.name.clone(), special_depth.depth.clone());
 
         *update_flag_u = special_depth.t;
     }

+ 61 - 72
strategy/src/gate_usdt_swap.rs

@@ -9,10 +9,7 @@ use exchanges::gate_swap_rest::GateSwapRest;
 use exchanges::gate_swap_ws::{GateSwapLogin, GateSwapSubscribeType, GateSwapWs, GateSwapWsType};
 use exchanges::response_base::ResponseData;
 use global::trace_stack::{TraceStack};
-use standard::exchange::ExchangeEnum::{GateSwap};
-use crate::model::{OrderInfo};
 use crate::core::Core;
-use crate::exchange_disguise::on_special_depth;
 
 // 1交易、0参考 gate 合约 启动
 pub async fn gate_swap_run(is_shutdown_arc: Arc<AtomicBool>,
@@ -92,80 +89,72 @@ pub async fn gate_swap_run(is_shutdown_arc: Arc<AtomicBool>,
     });
 }
 
-async fn on_data(core_arc_clone: Arc<Mutex<Core>>,
-                 update_flag_u: &mut Decimal,
-                 multiplier: &Decimal,
-                 run_symbol: &String,
+async fn on_data(_core_arc_clone: Arc<Mutex<Core>>,
+                 _update_flag_u: &mut Decimal,
+                 _multiplier: &Decimal,
+                 _run_symbol: &String,
                  response: ResponseData) {
     let mut trace_stack = TraceStack::new(response.time, response.ins);
     trace_stack.on_after_span_line();
 
     match response.channel.as_str() {
-        "futures.order_book" => {
-            trace_stack.set_source("gate_usdt_swap.order_book".to_string());
-            let special_depth = standard::handle_info::HandleSwapInfo::handle_special_depth(GateSwap, &response);
-            trace_stack.on_after_format();
-
-            on_special_depth(core_arc_clone, update_flag_u, &response.label, &mut trace_stack, &special_depth).await;
-        }
-        "futures.book_ticker" => {
-            trace_stack.set_source("gate_usdt_swap.book_ticker".to_string());
-            // 将ticker数据转换为模拟深度
-            let special_depth = standard::handle_info::HandleSwapInfo::handle_book_ticker(GateSwap, &response);
-            trace_stack.on_after_format();
-
-            on_special_depth(core_arc_clone, update_flag_u, &response.label, &mut trace_stack, &special_depth).await;
-        }
-        "futures.balances" => {
-            let account = standard::handle_info::HandleSwapInfo::handle_account_info(GateSwap, &response, run_symbol);
-            let mut core = core_arc_clone.lock().await;
-            core.update_equity(account).await;
-        }
-        "futures.orders" => {
-            trace_stack.set_source("gate_swap.orders".to_string());
-            let orders = standard::handle_info::HandleSwapInfo::handle_order(GateSwap, response.clone(), multiplier.clone());
-
-            let mut order_infos:Vec<OrderInfo> = Vec::new();
-            for mut order in orders.order {
-                if order.status == "NULL" {
-                    error!("gate_usdt_swap 未识别的订单状态:{:?}", response);
-
-                    continue;
-                }
-
-                let order_info = OrderInfo::parse_order_to_order_info(&mut order);
-                order_infos.push(order_info);
-            }
-
-            {
-                let mut core = core_arc_clone.lock().await;
-                core.update_order(order_infos, trace_stack).await;
-            }
-        }
-        "futures.positions" => {
-            let positions = standard::handle_info::HandleSwapInfo::handle_position(GateSwap, &response, multiplier);
-            let mut core = core_arc_clone.lock().await;
-            core.update_position(positions).await;
-        }
-        "futures.trades" => {
-            // let mut core = core_arc_clone.lock().await;
-            // let str = data.label.clone();
-            // if core.is_update.contains_key(&data.label) && *core.is_update.get(str.as_str()).unwrap(){
-            //     *max_buy = Decimal::ZERO;
-            //     *min_sell = Decimal::ZERO;
-            //     core.is_update.remove(str.as_str());
-            // }
-            // let trades: Vec<OriginalTradeGa> = serde_json::from_str(data.data.as_str()).unwrap();
-            // for trade in trades {
-            //     if trade.price > *max_buy || *max_buy == Decimal::ZERO{
-            //         *max_buy = trade.price
-            //     }
-            //     if trade.price < *min_sell || *min_sell == Decimal::ZERO{
-            //         *min_sell = trade.price
-            //     }
-            // }
-            // core.max_buy_min_sell_cache.insert(data.label, vec![*max_buy, *min_sell]);
-        }
+        // "futures.order_book" => {
+        //     trace_stack.set_source("gate_usdt_swap.order_book".to_string());
+        //     let special_depth = standard::handle_info::HandleSwapInfo::handle_special_depth(GateSwap, &response);
+        //     trace_stack.on_after_format();
+        //
+        //     on_special_depth(core_arc_clone, update_flag_u, &response.label, &mut trace_stack, &special_depth).await;
+        // }
+        // "futures.balances" => {
+        //     let account = standard::handle_info::HandleSwapInfo::handle_account_info(GateSwap, &response, run_symbol);
+        //     let mut core = core_arc_clone.lock().await;
+        //     core.update_equity(account).await;
+        // }
+        // "futures.orders" => {
+        //     trace_stack.set_source("gate_swap.orders".to_string());
+        //     let orders = standard::handle_info::HandleSwapInfo::handle_order(GateSwap, response.clone(), multiplier.clone());
+        //
+        //     let mut order_infos:Vec<OrderInfo> = Vec::new();
+        //     for mut order in orders.order {
+        //         if order.status == "NULL" {
+        //             error!("gate_usdt_swap 未识别的订单状态:{:?}", response);
+        //
+        //             continue;
+        //         }
+        //
+        //         let order_info = OrderInfo::parse_order_to_order_info(&mut order);
+        //         order_infos.push(order_info);
+        //     }
+        //
+        //     {
+        //         let mut core = core_arc_clone.lock().await;
+        //         core.update_order(order_infos, trace_stack).await;
+        //     }
+        // }
+        // "futures.positions" => {
+        //     let positions = standard::handle_info::HandleSwapInfo::handle_position(GateSwap, &response, multiplier);
+        //     let mut core = core_arc_clone.lock().await;
+        //     core.update_position(positions).await;
+        // }
+        // "futures.trades" => {
+        //     // let mut core = core_arc_clone.lock().await;
+        //     // let str = data.label.clone();
+        //     // if core.is_update.contains_key(&data.label) && *core.is_update.get(str.as_str()).unwrap(){
+        //     //     *max_buy = Decimal::ZERO;
+        //     //     *min_sell = Decimal::ZERO;
+        //     //     core.is_update.remove(str.as_str());
+        //     // }
+        //     // let trades: Vec<OriginalTradeGa> = serde_json::from_str(data.data.as_str()).unwrap();
+        //     // for trade in trades {
+        //     //     if trade.price > *max_buy || *max_buy == Decimal::ZERO{
+        //     //         *max_buy = trade.price
+        //     //     }
+        //     //     if trade.price < *min_sell || *min_sell == Decimal::ZERO{
+        //     //         *min_sell = trade.price
+        //     //     }
+        //     // }
+        //     // core.max_buy_min_sell_cache.insert(data.label, vec![*max_buy, *min_sell]);
+        // }
         _ => {
             error!("未知推送类型");
             error!(?response);

+ 168 - 168
strategy/src/htx_usdt_swap.rs

@@ -1,168 +1,168 @@
-use tracing::{error};
-use std::collections::BTreeMap;
-use std::sync::Arc;
-use std::sync::atomic::AtomicBool;
-use rust_decimal::Decimal;
-use tokio::spawn;
-use tokio::sync::Mutex;
-use exchanges::htx_swap_ws::{HtxSwapLogin, HtxSwapSubscribeType, HtxSwapWs, HtxSwapWsType};
-use exchanges::response_base::ResponseData;
-use global::trace_stack::{TraceStack};
-use standard::exchange::ExchangeEnum::{HtxSwap};
-use crate::model::{OrderInfo};
-use crate::core::Core;
-use crate::exchange_disguise::on_special_depth;
-
-// 1交易、0参考 htx 合约 启动
-pub async fn htx_swap_run(is_shutdown_arc: Arc<AtomicBool>,
-                           is_trade: bool,
-                           core_arc: Arc<Mutex<Core>>,
-                           name: String,
-                           symbols: Vec<String>,
-                           _is_colo: bool,
-                           exchange_params: BTreeMap<String, String>) {
-    // 开启公共频道
-    let (write_tx_public, write_rx_public) = futures_channel::mpsc::unbounded();
-
-    // 开启公共连接
-    let is_shutdown_arc_c1 = is_shutdown_arc.clone();
-    let write_tx_am_public = Arc::new(Mutex::new(write_tx_public));
-    let name_clone = name.clone();
-    let core_arc_clone = core_arc.clone();
-    let symbols_clone = symbols.clone();
-    let symbol = symbols.clone()[0].clone();
-    spawn(async move {
-        // 构建链接ws
-        let mut bg_public = HtxSwapWs::new_label(name_clone.clone(),
-                                                    None,
-                                                 HtxSwapWsType::Public);
-
-        // 消费数据的函数
-        let mut update_flag_u = Decimal::ZERO;
-        let fun = move |data: ResponseData| {
-            let core_arc_cc = core_arc_clone.clone();
-            let rs = symbol.clone();
-            async move {
-                on_public_data(core_arc_cc, &mut update_flag_u, rs, data).await
-            }
-        };
-
-        // 准备链接
-        bg_public.set_subscribe(vec![HtxSwapSubscribeType::PuFuturesDepth]); // 只用订阅深度数据
-        bg_public.set_symbols(symbols_clone);
-        bg_public.ws_connect_async(is_shutdown_arc_c1, fun, &write_tx_am_public, write_rx_public).await.expect("htx_usdt_swap 链接有异常")
-    });
-
-    // 不需要交易就不用开启私有频道了
-    if !is_trade {
-        return;
-    }
-
-    // 开启私有频道
-    let (write_tx_private, write_rx_private) = futures_channel::mpsc::unbounded();
-
-    // 开启公共连接
-    let is_shutdown_arc_c1 = is_shutdown_arc.clone();
-    let write_tx_am_private = Arc::new(Mutex::new(write_tx_private));
-    spawn(async move {
-        let login_param = parse_btree_map_to_htx_swap_login(exchange_params);
-        // 构建链接ws
-        let mut bg_private = HtxSwapWs::new_label(name.clone(),
-                                                     Some(login_param),
-                                                  HtxSwapWsType::Private);
-
-        // 消费数据的函数
-        let core_arc_clone = core_arc.clone();
-        let run_symbol = symbols[0].clone();
-        let ct_val = core_arc_clone.lock().await.platform_rest.get_self_market().ct_val;
-        let fun = move |data: ResponseData| {
-            let core_arc_cc = core_arc_clone.clone();
-            let run_symbol_c = run_symbol.clone();
-
-            async move {
-                on_private_data(core_arc_cc, ct_val, data, &run_symbol_c).await
-            }
-        };
-
-        // 准备链接
-        bg_private.set_subscribe(vec![
-            HtxSwapSubscribeType::PrFuturesOrders,
-            HtxSwapSubscribeType::PrFuturesBalances,
-            HtxSwapSubscribeType::PrFuturesPositions
-        ]);
-        bg_private.set_symbols(symbols.clone());
-        bg_private.ws_connect_async(is_shutdown_arc_c1, fun, &write_tx_am_private, write_rx_private).await.expect("htx_usdt_swap 链接有异常")
-    });
-}
-
-async fn on_private_data(core_arc_clone: Arc<Mutex<Core>>,
-                         ct_val: Decimal,
-                         response: ResponseData,
-                         run_symbol: &String) {
-    let mut trace_stack = TraceStack::new(response.time, response.ins);
-    trace_stack.on_after_span_line();
-
-    let order_channel = "orders_cross";
-    let position_channel = "positions_cross";
-    let balance_channel = "accounts_cross";
-    if response.channel.contains(order_channel) { // 订单频道
-        trace_stack.set_source("htx_swap.orders".to_string());
-        let orders = standard::handle_info::HandleSwapInfo::handle_order(HtxSwap, response.clone(), ct_val.clone());
-        let mut order_infos:Vec<OrderInfo> = Vec::new();
-        for mut order in orders.order {
-            if order.status == "NULL" {
-                error!("htx_usdt_swap 未识别的订单状态:{:?}", response);
-                continue;
-            }
-            let mut order_info = OrderInfo::parse_order_to_order_info(&mut order);
-            order_info.trace_stack.source = "htx_usdt_swap 118".to_string();
-            order_infos.push(order_info);
-        }
-
-        {
-            let mut core = core_arc_clone.lock().await;
-            core.update_order(order_infos, trace_stack).await;
-        }
-    } else if response.channel.contains(position_channel) { // 仓位频道
-        let positions = standard::handle_info::HandleSwapInfo::handle_position(HtxSwap, &response, &ct_val);
-        let mut core = core_arc_clone.lock().await;
-
-        core.update_position(positions).await;
-    } else if response.channel.contains(balance_channel)  { // 余额频道
-        let account = standard::handle_info::HandleSwapInfo::handle_account_info(HtxSwap, &response, run_symbol);
-        let mut core = core_arc_clone.lock().await;
-
-        core.update_equity(account).await;
-    } else {
-        error!("未知推送类型");
-        error!(?response);
-    }
-}
-
-async fn on_public_data(core_arc_clone: Arc<Mutex<Core>>,
-                        update_flag_u: &mut Decimal,
-                        run_symbol: String,
-                        response: ResponseData) {
-    let mut trace_stack = TraceStack::new(response.time, response.ins);
-    trace_stack.on_after_span_line();
-    let channel_symbol = run_symbol.replace("_", "-");
-    let depth_channel = format!("market.{}.depth.step0", channel_symbol.to_uppercase());
-    // public类型,目前只考虑订单流数据
-    if response.channel == depth_channel { // 深度频道
-        trace_stack.set_source("htx_usdt_swap.depth".to_string());
-        let special_depth = standard::handle_info::HandleSwapInfo::handle_special_depth(HtxSwap, &response);
-        trace_stack.on_after_format();
-
-        on_special_depth(core_arc_clone, update_flag_u, &response.label, &mut trace_stack, &special_depth).await;
-    } else {
-        error!("未知推送类型");
-        error!(?response);
-    }
-}
-
-fn parse_btree_map_to_htx_swap_login(exchange_params: BTreeMap<String, String>) -> HtxSwapLogin {
-    HtxSwapLogin {
-        api_key: exchange_params.get("access_key").unwrap().clone(),
-        secret: exchange_params.get("secret_key").unwrap().clone()
-    }
-}
+// use tracing::{error};
+// use std::collections::BTreeMap;
+// use std::sync::Arc;
+// use std::sync::atomic::AtomicBool;
+// use rust_decimal::Decimal;
+// use tokio::spawn;
+// use tokio::sync::Mutex;
+// use exchanges::htx_swap_ws::{HtxSwapLogin, HtxSwapSubscribeType, HtxSwapWs, HtxSwapWsType};
+// use exchanges::response_base::ResponseData;
+// use global::trace_stack::{TraceStack};
+// use standard::exchange::ExchangeEnum::{HtxSwap};
+// use crate::model::{OrderInfo};
+// use crate::core::Core;
+// use crate::exchange_disguise::on_special_depth;
+//
+// // 1交易、0参考 htx 合约 启动
+// pub async fn htx_swap_run(is_shutdown_arc: Arc<AtomicBool>,
+//                            is_trade: bool,
+//                            core_arc: Arc<Mutex<Core>>,
+//                            name: String,
+//                            symbols: Vec<String>,
+//                            _is_colo: bool,
+//                            exchange_params: BTreeMap<String, String>) {
+//     // 开启公共频道
+//     let (write_tx_public, write_rx_public) = futures_channel::mpsc::unbounded();
+//
+//     // 开启公共连接
+//     let is_shutdown_arc_c1 = is_shutdown_arc.clone();
+//     let write_tx_am_public = Arc::new(Mutex::new(write_tx_public));
+//     let name_clone = name.clone();
+//     let core_arc_clone = core_arc.clone();
+//     let symbols_clone = symbols.clone();
+//     let symbol = symbols.clone()[0].clone();
+//     spawn(async move {
+//         // 构建链接ws
+//         let mut bg_public = HtxSwapWs::new_label(name_clone.clone(),
+//                                                     None,
+//                                                  HtxSwapWsType::Public);
+//
+//         // 消费数据的函数
+//         let mut update_flag_u = Decimal::ZERO;
+//         let fun = move |data: ResponseData| {
+//             let core_arc_cc = core_arc_clone.clone();
+//             let rs = symbol.clone();
+//             async move {
+//                 on_public_data(core_arc_cc, &mut update_flag_u, rs, data).await
+//             }
+//         };
+//
+//         // 准备链接
+//         bg_public.set_subscribe(vec![HtxSwapSubscribeType::PuFuturesDepth]); // 只用订阅深度数据
+//         bg_public.set_symbols(symbols_clone);
+//         bg_public.ws_connect_async(is_shutdown_arc_c1, fun, &write_tx_am_public, write_rx_public).await.expect("htx_usdt_swap 链接有异常")
+//     });
+//
+//     // 不需要交易就不用开启私有频道了
+//     if !is_trade {
+//         return;
+//     }
+//
+//     // 开启私有频道
+//     let (write_tx_private, write_rx_private) = futures_channel::mpsc::unbounded();
+//
+//     // 开启公共连接
+//     let is_shutdown_arc_c1 = is_shutdown_arc.clone();
+//     let write_tx_am_private = Arc::new(Mutex::new(write_tx_private));
+//     spawn(async move {
+//         let login_param = parse_btree_map_to_htx_swap_login(exchange_params);
+//         // 构建链接ws
+//         let mut bg_private = HtxSwapWs::new_label(name.clone(),
+//                                                      Some(login_param),
+//                                                   HtxSwapWsType::Private);
+//
+//         // 消费数据的函数
+//         let core_arc_clone = core_arc.clone();
+//         let run_symbol = symbols[0].clone();
+//         let ct_val = core_arc_clone.lock().await.platform_rest.get_self_market().ct_val;
+//         let fun = move |data: ResponseData| {
+//             let core_arc_cc = core_arc_clone.clone();
+//             let run_symbol_c = run_symbol.clone();
+//
+//             async move {
+//                 on_private_data(core_arc_cc, ct_val, data, &run_symbol_c).await
+//             }
+//         };
+//
+//         // 准备链接
+//         bg_private.set_subscribe(vec![
+//             HtxSwapSubscribeType::PrFuturesOrders,
+//             HtxSwapSubscribeType::PrFuturesBalances,
+//             HtxSwapSubscribeType::PrFuturesPositions
+//         ]);
+//         bg_private.set_symbols(symbols.clone());
+//         bg_private.ws_connect_async(is_shutdown_arc_c1, fun, &write_tx_am_private, write_rx_private).await.expect("htx_usdt_swap 链接有异常")
+//     });
+// }
+//
+// async fn on_private_data(_core_arc_clone: Arc<Mutex<Core>>,
+//                          _ct_val: Decimal,
+//                          response: ResponseData,
+//                          _run_symbol: &String) {
+//     let mut trace_stack = TraceStack::new(response.time, response.ins);
+//     trace_stack.on_after_span_line();
+//
+//     let order_channel = "orders_cross";
+//     let position_channel = "positions_cross";
+//     let balance_channel = "accounts_cross";
+//     if response.channel.contains(order_channel) { // 订单频道
+//         // trace_stack.set_source("htx_swap.orders".to_string());
+//         // let orders = standard::handle_info::HandleSwapInfo::handle_order(HtxSwap, response.clone(), ct_val.clone());
+//         // let mut order_infos:Vec<OrderInfo> = Vec::new();
+//         // for mut order in orders.order {
+//         //     if order.status == "NULL" {
+//         //         error!("htx_usdt_swap 未识别的订单状态:{:?}", response);
+//         //         continue;
+//         //     }
+//         //     let mut order_info = OrderInfo::parse_order_to_order_info(&mut order);
+//         //     order_info.trace_stack.source = "htx_usdt_swap 118".to_string();
+//         //     order_infos.push(order_info);
+//         // }
+//         //
+//         // {
+//         //     let mut core = core_arc_clone.lock().await;
+//         //     core.update_order(order_infos, trace_stack).await;
+//         // }
+//     } else if response.channel.contains(position_channel) { // 仓位频道
+//         // let positions = standard::handle_info::HandleSwapInfo::handle_position(HtxSwap, &response, &ct_val);
+//         // let mut core = core_arc_clone.lock().await;
+//         //
+//         // core.update_position(positions).await;
+//     } else if response.channel.contains(balance_channel)  { // 余额频道
+//         // let account = standard::handle_info::HandleSwapInfo::handle_account_info(HtxSwap, &response, run_symbol);
+//         // let mut core = core_arc_clone.lock().await;
+//         //
+//         // core.update_equity(account).await;
+//     } else {
+//         error!("未知推送类型");
+//         error!(?response);
+//     }
+// }
+//
+// async fn on_public_data(_core_arc_clone: Arc<Mutex<Core>>,
+//                         _update_flag_u: &mut Decimal,
+//                         run_symbol: String,
+//                         response: ResponseData) {
+//     let mut trace_stack = TraceStack::new(response.time, response.ins);
+//     trace_stack.on_after_span_line();
+//     let channel_symbol = run_symbol.replace("_", "-");
+//     let depth_channel = format!("market.{}.depth.step0", channel_symbol.to_uppercase());
+//     // public类型,目前只考虑订单流数据
+//     if response.channel == depth_channel { // 深度频道
+//         // trace_stack.set_source("htx_usdt_swap.depth".to_string());
+//         // let special_depth = standard::handle_info::HandleSwapInfo::handle_special_depth(HtxSwap, &response);
+//         // trace_stack.on_after_format();
+//         //
+//         // on_special_depth(core_arc_clone, update_flag_u, &response.label, &mut trace_stack, &special_depth).await;
+//     } else {
+//         error!("未知推送类型");
+//         error!(?response);
+//     }
+// }
+//
+// fn parse_btree_map_to_htx_swap_login(exchange_params: BTreeMap<String, String>) -> HtxSwapLogin {
+//     HtxSwapLogin {
+//         api_key: exchange_params.get("access_key").unwrap().clone(),
+//         secret: exchange_params.get("secret_key").unwrap().clone()
+//     }
+// }

+ 165 - 165
strategy/src/kucoin_swap.rs

@@ -1,165 +1,165 @@
-use std::collections::{BTreeMap};
-use std::sync::Arc;
-use std::sync::atomic::{AtomicBool};
-use std::time::Duration;
-
-use rust_decimal::Decimal;
-use tokio::spawn;
-use tokio::sync::Mutex;
-use tokio::time::sleep;
-use tracing::error;
-
-use exchanges::kucoin_swap_ws::{KucoinSwapLogin, KucoinSwapSubscribeType, KucoinSwapWs, KucoinSwapWsType};
-use exchanges::response_base::ResponseData;
-use global::trace_stack::TraceStack;
-use standard::exchange::ExchangeEnum::KucoinSwap;
-use crate::exchange_disguise::on_special_depth;
-
-use crate::model::{OrderInfo};
-use crate::core::Core;
-
-// 1交易、0参考 kucoin 合约 启动
-pub async fn kucoin_swap_run(is_shutdown_arc :Arc<AtomicBool>,
-                             is_trade: bool,
-                             core_arc: Arc<Mutex<Core>>,
-                             name: String,
-                             symbols: Vec<String>,
-                             is_colo: bool,
-                             exchange_params: BTreeMap<String, String>) {
-    let mut symbol_arr = Vec::new();
-    for symbol in &symbols {
-        let symbol_mapper = standard::utils::symbol_enter_mapper(KucoinSwap,symbol.as_str());
-        let new_symbol = symbol_mapper.replace("_", "").to_uppercase() + "M";
-        symbol_arr.push(new_symbol);
-    }
-
-    // 新增定期获取余额的协程
-    let account_core_arc = core_arc.clone();
-    spawn(async move {
-        loop {
-            // 每30秒重新获取一次
-            sleep(Duration::from_secs(30)).await;
-
-            {
-                let mut core = account_core_arc.lock().await;
-                core.update_equity_rest_swap().await;
-            }
-        }
-    });
-
-    let (write_tx, write_rx) = futures_channel::mpsc::unbounded();
-    let write_tx_am = Arc::new(Mutex::new(write_tx));
-    spawn(async move {
-        //创建读写通道
-        spawn( async move {
-            let mut ws;
-            // 交易
-            if is_trade {
-                let login_params = parse_btree_map_to_kucoin_swap_login(exchange_params);
-                ws = KucoinSwapWs::new_label(name.clone(), is_colo, Option::from(login_params), KucoinSwapWsType::Private).await;
-                ws.set_subscribe(vec![
-                    KucoinSwapSubscribeType::PuContractMarketLevel2Depth50,
-
-                    KucoinSwapSubscribeType::PrContractPosition,
-                    KucoinSwapSubscribeType::PrContractMarketTradeOrders
-                ]);
-            } else { // 参考
-                ws = KucoinSwapWs::new_label(name.clone(), is_colo, None, KucoinSwapWsType::Public).await;
-                ws.set_subscribe(vec![
-                    KucoinSwapSubscribeType::PuContractMarketLevel2Depth50,
-
-                    // KucoinSwapSubscribeType::PuContractMarketExecution
-                ]);
-            }
-
-            // 数据处理
-            let core_arc_clone = Arc::clone(&core_arc);
-
-            let mut update_flag_u = Decimal::ZERO;
-            // let mut max_buy = Decimal::ZERO;
-            // let mut min_sell = Decimal::ZERO;
-            let multiplier = core_arc.lock().await.platform_rest.get_self_market().ct_val;
-
-            let fun = move |data: ResponseData| {
-                // 在 async 块之前克隆 Arc
-                let core_arc_cc = core_arc_clone.clone();
-                let mul = multiplier.clone();
-
-                async move {
-                    on_data(core_arc_cc,
-                            &mut update_flag_u,
-                            &mul,
-                            // &mut max_buy,
-                            // &mut min_sell,
-                            data).await
-                }
-            };
-
-            // 建立链接
-            ws.set_symbols(symbol_arr);
-            ws.ws_connect_async(is_shutdown_arc, fun, &write_tx_am, write_rx).await.expect("链接失败(内部一个心跳线程应该已经关闭了)");
-        });
-    });
-}
-
-async fn on_data(core_arc_clone: Arc<Mutex<Core>>,
-                 update_flag_u: &mut Decimal,
-                 multiplier: &Decimal,
-                 // max_buy: &mut Decimal,
-                 // min_sell: &mut Decimal,
-                 response: ResponseData) {
-    let mut trace_stack = TraceStack::new(response.time, response.ins);
-    trace_stack.on_after_span_line();
-
-    match response.channel.as_str() {
-        "level2" => {
-            trace_stack.set_source("kucoin_usdt_swap.level2".to_string());
-            let special_depth = standard::handle_info::HandleSwapInfo::handle_special_depth(KucoinSwap, &response);
-            trace_stack.on_after_format();
-
-            on_special_depth(core_arc_clone, update_flag_u, &response.label, &mut trace_stack, &special_depth).await
-        }
-        "tickerV2" => {
-            trace_stack.set_source("kucoin_swap.tickerV2".to_string());
-
-            let special_depth = standard::handle_info::HandleSwapInfo::handle_book_ticker(KucoinSwap, &response);
-            trace_stack.on_before_network(special_depth.create_at.clone());
-
-            on_special_depth(core_arc_clone, update_flag_u, &response.label, &mut trace_stack, &special_depth).await
-        }
-        "symbolOrderChange" => {
-            trace_stack.set_source("kucoin_swap.symbolOrderChange".to_string());
-
-            let orders = standard::handle_info::HandleSwapInfo::handle_order(KucoinSwap, response, multiplier.clone());
-            let mut order_infos:Vec<OrderInfo> = Vec::new();
-            for mut order in orders.order {
-                if order.status == "NULL" {
-                    continue;
-                }
-
-                let order_info = OrderInfo::parse_order_to_order_info(&mut order);
-                order_infos.push(order_info);
-            }
-
-            let mut core = core_arc_clone.lock().await;
-            core.update_order(order_infos, trace_stack).await;
-        }
-        "position.change" => {
-            let positions = standard::handle_info::HandleSwapInfo::handle_position(KucoinSwap, &response, multiplier);
-            let mut core = core_arc_clone.lock().await;
-            core.update_position(positions).await;
-        }
-        _ => {
-            error!("kucoin_swap 未知推送类型");
-            error!(?response);
-        }
-    }
-}
-
-fn parse_btree_map_to_kucoin_swap_login(exchange_params: BTreeMap<String, String>) -> KucoinSwapLogin {
-    KucoinSwapLogin {
-        access_key: exchange_params.get("access_key").unwrap().clone(),
-        secret_key: exchange_params.get("secret_key").unwrap().clone(),
-        pass_key: exchange_params.get("pass_key").unwrap().clone(),
-    }
-}
+// use std::collections::{BTreeMap};
+// use std::sync::Arc;
+// use std::sync::atomic::{AtomicBool};
+// use std::time::Duration;
+//
+// use rust_decimal::Decimal;
+// use tokio::spawn;
+// use tokio::sync::Mutex;
+// use tokio::time::sleep;
+// use tracing::error;
+//
+// use exchanges::kucoin_swap_ws::{KucoinSwapLogin, KucoinSwapSubscribeType, KucoinSwapWs, KucoinSwapWsType};
+// use exchanges::response_base::ResponseData;
+// use global::trace_stack::TraceStack;
+// use standard::exchange::ExchangeEnum::KucoinSwap;
+// use crate::exchange_disguise::on_special_depth;
+//
+// use crate::model::{OrderInfo};
+// use crate::core::Core;
+//
+// // 1交易、0参考 kucoin 合约 启动
+// pub async fn kucoin_swap_run(is_shutdown_arc :Arc<AtomicBool>,
+//                              is_trade: bool,
+//                              core_arc: Arc<Mutex<Core>>,
+//                              name: String,
+//                              symbols: Vec<String>,
+//                              is_colo: bool,
+//                              exchange_params: BTreeMap<String, String>) {
+//     let mut symbol_arr = Vec::new();
+//     for symbol in &symbols {
+//         let symbol_mapper = standard::utils::symbol_enter_mapper(KucoinSwap,symbol.as_str());
+//         let new_symbol = symbol_mapper.replace("_", "").to_uppercase() + "M";
+//         symbol_arr.push(new_symbol);
+//     }
+//
+//     // 新增定期获取余额的协程
+//     let account_core_arc = core_arc.clone();
+//     spawn(async move {
+//         loop {
+//             // 每30秒重新获取一次
+//             sleep(Duration::from_secs(30)).await;
+//
+//             {
+//                 let mut core = account_core_arc.lock().await;
+//                 core.update_equity_rest_swap().await;
+//             }
+//         }
+//     });
+//
+//     let (write_tx, write_rx) = futures_channel::mpsc::unbounded();
+//     let write_tx_am = Arc::new(Mutex::new(write_tx));
+//     spawn(async move {
+//         //创建读写通道
+//         spawn( async move {
+//             let mut ws;
+//             // 交易
+//             if is_trade {
+//                 let login_params = parse_btree_map_to_kucoin_swap_login(exchange_params);
+//                 ws = KucoinSwapWs::new_label(name.clone(), is_colo, Option::from(login_params), KucoinSwapWsType::Private).await;
+//                 ws.set_subscribe(vec![
+//                     KucoinSwapSubscribeType::PuContractMarketLevel2Depth50,
+//
+//                     KucoinSwapSubscribeType::PrContractPosition,
+//                     KucoinSwapSubscribeType::PrContractMarketTradeOrders
+//                 ]);
+//             } else { // 参考
+//                 ws = KucoinSwapWs::new_label(name.clone(), is_colo, None, KucoinSwapWsType::Public).await;
+//                 ws.set_subscribe(vec![
+//                     KucoinSwapSubscribeType::PuContractMarketLevel2Depth50,
+//
+//                     // KucoinSwapSubscribeType::PuContractMarketExecution
+//                 ]);
+//             }
+//
+//             // 数据处理
+//             let core_arc_clone = Arc::clone(&core_arc);
+//
+//             let mut update_flag_u = Decimal::ZERO;
+//             // let mut max_buy = Decimal::ZERO;
+//             // let mut min_sell = Decimal::ZERO;
+//             let multiplier = core_arc.lock().await.platform_rest.get_self_market().ct_val;
+//
+//             let fun = move |data: ResponseData| {
+//                 // 在 async 块之前克隆 Arc
+//                 let core_arc_cc = core_arc_clone.clone();
+//                 let mul = multiplier.clone();
+//
+//                 async move {
+//                     on_data(core_arc_cc,
+//                             &mut update_flag_u,
+//                             &mul,
+//                             // &mut max_buy,
+//                             // &mut min_sell,
+//                             data).await
+//                 }
+//             };
+//
+//             // 建立链接
+//             ws.set_symbols(symbol_arr);
+//             ws.ws_connect_async(is_shutdown_arc, fun, &write_tx_am, write_rx).await.expect("链接失败(内部一个心跳线程应该已经关闭了)");
+//         });
+//     });
+// }
+//
+// async fn on_data(core_arc_clone: Arc<Mutex<Core>>,
+//                  update_flag_u: &mut Decimal,
+//                  multiplier: &Decimal,
+//                  // max_buy: &mut Decimal,
+//                  // min_sell: &mut Decimal,
+//                  response: ResponseData) {
+//     let mut trace_stack = TraceStack::new(response.time, response.ins);
+//     trace_stack.on_after_span_line();
+//
+//     match response.channel.as_str() {
+//         // "level2" => {
+//         //     trace_stack.set_source("kucoin_usdt_swap.level2".to_string());
+//         //     let special_depth = standard::handle_info::HandleSwapInfo::handle_special_depth(KucoinSwap, &response);
+//         //     trace_stack.on_after_format();
+//         //
+//         //     on_special_depth(core_arc_clone, update_flag_u, &response.label, &mut trace_stack, &special_depth).await
+//         // }
+//         // "tickerV2" => {
+//         //     trace_stack.set_source("kucoin_swap.tickerV2".to_string());
+//         //
+//         //     let special_depth = standard::handle_info::HandleSwapInfo::handle_book_ticker(KucoinSwap, &response);
+//         //     trace_stack.on_before_network(special_depth.create_at.clone());
+//         //
+//         //     on_special_depth(core_arc_clone, update_flag_u, &response.label, &mut trace_stack, &special_depth).await
+//         // }
+//         // "symbolOrderChange" => {
+//         //     trace_stack.set_source("kucoin_swap.symbolOrderChange".to_string());
+//         //
+//         //     let orders = standard::handle_info::HandleSwapInfo::handle_order(KucoinSwap, response, multiplier.clone());
+//         //     let mut order_infos:Vec<OrderInfo> = Vec::new();
+//         //     for mut order in orders.order {
+//         //         if order.status == "NULL" {
+//         //             continue;
+//         //         }
+//         //
+//         //         let order_info = OrderInfo::parse_order_to_order_info(&mut order);
+//         //         order_infos.push(order_info);
+//         //     }
+//         //
+//         //     let mut core = core_arc_clone.lock().await;
+//         //     core.update_order(order_infos, trace_stack).await;
+//         // }
+//         // "position.change" => {
+//         //     let positions = standard::handle_info::HandleSwapInfo::handle_position(KucoinSwap, &response, multiplier);
+//         //     let mut core = core_arc_clone.lock().await;
+//         //     core.update_position(positions).await;
+//         // }
+//         _ => {
+//             error!("kucoin_swap 未知推送类型");
+//             error!(?response);
+//         }
+//     }
+// }
+//
+// fn parse_btree_map_to_kucoin_swap_login(exchange_params: BTreeMap<String, String>) -> KucoinSwapLogin {
+//     KucoinSwapLogin {
+//         access_key: exchange_params.get("access_key").unwrap().clone(),
+//         secret_key: exchange_params.get("secret_key").unwrap().clone(),
+//         pass_key: exchange_params.get("pass_key").unwrap().clone(),
+//     }
+// }