소스 검색

kucoin封装完成,等待测试。

skyffire 1 년 전
부모
커밋
0380279998

+ 625 - 625
exchanges/src/kucoin_swap_rest.rs

@@ -1,625 +1,625 @@
-// use std::collections::BTreeMap;
-// use reqwest::header::HeaderMap;
-// use hmac::{Hmac, Mac, NewMac};
-// use reqwest::{Client};
-// use rust_decimal::Decimal;
-// use rust_decimal::prelude::FromPrimitive;
-// use rust_decimal_macros::dec;
-// use sha2::Sha256;
-// use tracing::{info, trace};
-// use crate::http_tool::RestTool;
-// use crate::response_base::ResponseData;
-//
-// #[derive(Clone, Debug)]
-// pub struct KucoinSwapRest {
-//     pub label: String,
-//     base_url: String,
-//     client: reqwest::Client,
-//     /*******参数*/
-//     //是否需要登陆
-//     //登陆所需参数
-//     login_param: BTreeMap<String, String>,
-//     delays: Vec<i64>,
-//     max_delay: i64,
-//     avg_delay: Decimal,
-// }
-//
-// impl KucoinSwapRest {
-//     /*******************************************************************************************************/
-//     /*****************************************获取一个对象****************************************************/
-//     /*******************************************************************************************************/
-//
-//     pub fn new(is_colo: bool, login_param: BTreeMap<String, String>) -> KucoinSwapRest
-//     {
-//         return KucoinSwapRest::new_label("default-KucoinSwapRest".to_string(), is_colo, login_param);
-//     }
-//     pub fn new_label(label: String, is_colo: bool, login_param: BTreeMap<String, String>) -> KucoinSwapRest {
-//         let base_url = if is_colo {
-//             "https://api-futures.kucoin.com".to_string()
-//         } else {
-//             "https://api-futures.kucoin.com".to_string()
-//         };
-//
-//         if is_colo {
-//             info!("开启高速(未配置,走普通:{})通道",base_url);
-//         } else {
-//             info!("走普通通道:{}",base_url);
-//         }
-//         /*****返回结构体*******/
-//         KucoinSwapRest {
-//             label,
-//             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 = serde_json::json!({
-//          });
-//         let data = self.request("GET".to_string(),
-//                                 "/api/v1".to_string(),
-//                                 "/timestamp".to_string(),
-//                                 false,
-//                                 params.to_string(),
-//         ).await;
-//         data
-//     }
-//
-//     // 获取成交记录
-//     pub async fn get_fills(&mut self,
-//                            symbol: String,
-//                            order_id: String,
-//                            side: String,
-//                            start_at: i64,
-//                            end_at: i64,
-//                            page_size: i64,
-//     ) -> ResponseData {
-//         let mut params = serde_json::json!({
-//             "symbol":symbol,
-//             "pageSize":1000
-//          });
-//         if order_id.len() > 0 {
-//             params["orderId"] = serde_json::json!(order_id);
-//         }
-//         if side.len() > 0 {
-//             params["side"] = serde_json::json!(side);
-//         }
-//         if start_at > 0 {
-//             params["startAt"] = serde_json::json!(start_at);
-//         }
-//         if end_at > 0 {
-//             params["endAt"] = serde_json::json!(end_at);
-//         }
-//         if page_size > 0 {
-//             params["pageSize"] = serde_json::json!(page_size);
-//         }
-//         let data = self.request("GET".to_string(),
-//                                 "/api/v1".to_string(),
-//                                 "/fills".to_string(),
-//                                 true,
-//                                 params.to_string(),
-//         ).await;
-//         data
-//     }
-//     //查询合约账户
-//     pub async fn get_account(&mut self, contract: String) -> ResponseData {
-//         let params = serde_json::json!({
-//             "currency":contract
-//          });
-//         let data = self.request("GET".to_string(),
-//                                 "/api/v1".to_string(),
-//                                 "/account-overview".to_string(),
-//                                 true,
-//                                 params.to_string(),
-//         ).await;
-//         data
-//     }
-//     //获取仓位信息
-//     pub async fn get_position(&mut self, symbol: String) -> ResponseData {
-//         let params = serde_json::json!({
-//             "symbol":symbol
-//          });
-//         let data = self.request("GET".to_string(),
-//                                 "/api/v1".to_string(),
-//                                 "/position".to_string(),
-//                                 true,
-//                                 params.to_string(),
-//         ).await;
-//         data
-//     }
-//     //查询所有的合约信息
-//     pub async fn get_market_details(&mut self) -> ResponseData {
-//         let params = serde_json::json!({});
-//
-//         let data = self.request("GET".to_string(),
-//                                 "/api/v1".to_string(),
-//                                 format!("/contracts/active"),
-//                                 true,
-//                                 params.to_string(),
-//         ).await;
-//         data
-//     }
-//     //实时行情
-//     pub async fn get_ticker(&mut self, symbol: String) -> ResponseData {
-//         let params = serde_json::json!({
-//             "symbol":symbol
-//          });
-//         let data = self.request("GET".to_string(),
-//                                 "/api/v1".to_string(),
-//                                 format!("/ticker"),
-//                                 true,
-//                                 params.to_string(),
-//         ).await;
-//         data
-//     }
-//     //查看订单列表
-//     pub async fn get_orders(&mut self, status: String, symbol: String) -> ResponseData {
-//         let mut params = serde_json::json!({
-//             // "symbol":symbol
-//          });
-//         if symbol.len() > 0 {
-//             params.as_object_mut().unwrap().insert("symbol".parse().unwrap(), serde_json::Value::from(symbol));
-//         }
-//         if status.len() > 0 {
-//             params.as_object_mut().unwrap().insert("status".parse().unwrap(), serde_json::Value::from(status));
-//         }
-//         trace!("??{}",params.to_string());
-//         let data = self.request("GET".to_string(),
-//                                 "/api/v1".to_string(),
-//                                 format!("/orders"),
-//                                 true,
-//                                 params.to_string(),
-//         ).await;
-//         data
-//     }
-//     //获取用户仓位列表
-//     pub async fn get_positions(&mut self, currency: String) -> ResponseData {
-//         let params = serde_json::json!({
-//             "currency":currency
-//          });
-//         let data = self.request("GET".to_string(),
-//                                 "/api/v1".to_string(),
-//                                 format!("/positions"),
-//                                 true,
-//                                 params.to_string(),
-//         ).await;
-//         data
-//     }
-//     //单个订单详情
-//     pub async fn get_orders_details(&mut self, order_id: String, client_id: String) -> ResponseData {
-//         let mut params = serde_json::json!({   });
-//         let mut url = String::from("");
-//         if order_id != "" {
-//             url = format!("/orders/{}", order_id);
-//         } else if client_id != "" {
-//             url = format!("/orders/byClientOid");
-//             params.as_object_mut().unwrap().insert("clientOid".parse().unwrap(), serde_json::Value::from(client_id));
-//         }
-//
-//         let data = self.request("GET".to_string(),
-//                                 "/api/v1".to_string(),
-//                                 url,
-//                                 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/v1".to_string(),
-//                                 format!("/orders"),
-//                                 true,
-//                                 params.to_string(),
-//         ).await;
-//         data
-//     }
-//     //下单
-//     pub async fn swap_bazaar_order(&mut self,
-//                                    client_oid: String,
-//                                    symbol: String,
-//                                    origin_side: String,
-//                                    size: u64,
-//                                    leverage: String,
-//                                    price: String,
-//                                    order_type: String) -> ResponseData
-//     {
-//         let mut side = String::from("");
-//         let mut params = serde_json::json!({
-//             "clientOid":client_oid,
-//             "symbol": symbol,
-//             "size":size,
-//             "leverage":leverage,
-//             "reduceOnly":false,
-//             "price":price,
-//             "type":order_type,
-//         });
-//
-//         let req = match origin_side.as_str() {
-//             "kd" => {
-//                 side = "buy".to_string();
-//                 true
-//             }
-//             "pd" => {
-//                 side = "sell".to_string();
-//                 true
-//             }
-//             "kk" => {
-//                 side = "sell".to_string();
-//                 true
-//             }
-//             "pk" => {
-//                 side = "buy".to_string();
-//                 true
-//             }
-//             _ => { false } // 处理未知请求类型
-//         };
-//         if req {
-//             params.as_object_mut().unwrap().insert("side".to_string(), serde_json::json!(side));
-//         }
-//
-//         let data = self.swap_order(params).await;
-//         data
-//     }
-//
-//     //单个撤单
-//     pub async fn cancel_order(&mut self, order_id: String, client_id: String) -> ResponseData {
-//         let mut params = serde_json::json!({   });
-//         let mut url = String::from("");
-//         if order_id != "" {
-//             url = format!("/orders/{}", order_id);
-//         } else if client_id != "" {
-//             url = format!("/orders/byClientOid");
-//             params.as_object_mut().unwrap().insert("clientOid".parse().unwrap(), serde_json::Value::from(client_id));
-//         }
-//         let data = self.request("DELETE".to_string(),
-//                                 "/api/v1".to_string(),
-//                                 url,
-//                                 true,
-//                                 params.to_string(),
-//         ).await;
-//         data
-//     }
-//     //批量撤单
-//     pub async fn cancel_orders(&mut self, symbol: String) -> ResponseData {
-//         let params = serde_json::json!({   });
-//         let data = self.request("DELETE".to_string(),
-//                                 "/api/v1".to_string(),
-//                                 format!("/orders?symbol={}", symbol),
-//                                 true,
-//                                 params.to_string(),
-//         ).await;
-//         data
-//     }
-//     //全部撤單
-//     pub async fn cancel_order_all(&mut self) -> ResponseData {
-//         let params = serde_json::json!({   });
-//         let data = self.request("DELETE".to_string(),
-//                                 "/api/v1".to_string(),
-//                                 format!("/orders"),
-//                                 true,
-//                                 params.to_string(),
-//         ).await;
-//         data
-//     }
-//
-//
-//     //获取合约令牌-公共
-//     pub async fn get_public_token(&mut self) -> ResponseData {
-//         let params = serde_json::json!({});
-//         let data = self.request("POST".to_string(),
-//                                 "/api/v1".to_string(),
-//                                 "/bullet-public".to_string(),
-//                                 false,
-//                                 params.to_string(),
-//         ).await;
-//         data
-//     }
-//     //获取合约令牌-私有
-//     pub async fn get_private_token(&mut self) -> ResponseData {
-//         let params = serde_json::json!({});
-//         let data = self.request("POST".to_string(),
-//                                 "/api/v1".to_string(),
-//                                 "/bullet-private".to_string(),
-//                                 true,
-//                                 params.to_string(),
-//         ).await;
-//         data
-//     }
-//     //设置杠杆(修改階梯風險限額等級)
-//     pub async fn set_leverage(&mut self, symbol: String, level: i8) -> ResponseData {
-//         let params = serde_json::json!({
-//             "symbol":symbol,
-//             "level":level,
-//         });
-//         let data = self.request("POST".to_string(),
-//                                 "/api/v1".to_string(),
-//                                 format!("/position/risk-limit-level/change"),
-//                                 true,
-//                                 params.to_string(),
-//         ).await;
-//         data
-//     }
-//     //查看杠杆(查詢杠桿代幣信息)
-//     pub async fn get_leverage(&mut self, symbol: String) -> ResponseData {
-//         let params = serde_json::json!({
-//         });
-//         let data = self.request("GET".to_string(),
-//                                 "/api/v1".to_string(),
-//                                 format!("/contracts/risk-limit/{}", symbol),
-//                                 true,
-//                                 params.to_string(),
-//         ).await;
-//         data
-//     }
-//     //设置 自动追加保证金
-//     pub async fn auto_deposit_status(&mut self, symbol: String, status: bool) -> ResponseData {
-//         let params = serde_json::json!({
-//                 "symbol":symbol,
-//                 "status":status
-//         });
-//         let data = self.request("POST".to_string(),
-//                                 "/api/v1".to_string(),
-//                                 format!("/position/margin/auto-deposit-status"),
-//                                 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 pass_key = "".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") {
-//             pass_key = self.login_param.get("pass_key").unwrap().to_string();
-//         }
-//         let mut is_login_param = true;
-//         if access_key == "" || secret_key == "" || pass_key == "" {
-//             is_login_param = false
-//         }
-//
-//
-//         //请求头配置-如果需要登陆则存在额外配置
-//         let mut body = "".to_string();
-//
-//         let timestamp = chrono::Utc::now().timestamp_millis().to_string();
-//
-//         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(),
-//                 );
-//                 trace!("sing:{}", sing);
-//                 let passphrase = Self::passphrase(secret_key, pass_key);
-//                 trace!("passphrase:{}", passphrase);
-//                 //组装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_toll(
-//             base_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("KC-API-KEY", access_key.parse().unwrap());
-//         headers.insert("KC-API-SIGN", sign.parse().unwrap());
-//         headers.insert("KC-API-TIMESTAMP", timestamp.parse().unwrap());
-//         headers.insert("KC-API-PASSPHRASE", passphrase.parse().unwrap());
-//         headers.insert("KC-API-KEY-VERSION", "2".parse().unwrap());
-//         headers
-//     }
-//     pub fn sign(secret_key: String,
-//                 method: String, prefix_url: String, request_url: String,
-//                 params: String, body_data: String, timestamp: String) -> String
-//     {
-//         let url = format!("{}{}", prefix_url, request_url);
-//         let params_str = RestTool::parse_params_to_str(params.clone());
-//         trace!("body_data:{}", body_data);
-//         // let body = Some(body_data);
-//         // let hashed_payload = if let Some(body) = body {
-//         //     let mut m = digest::Context::new(&digest::SHA256);
-//         //     m.update(body.as_bytes());
-//         //     hex::encode(m.finish().as_ref())
-//         // } else {
-//         //     String::new()
-//         // };
-//         // trace!("hashed_payload:{}", hashed_payload);
-//
-//         let mut message = format!("{}{}{}",
-//                                   timestamp,
-//                                   method,
-//                                   url
-//         );
-//         if method == "GET" || method == "DELETE" {
-//             message = if params_str.len() > 0 {
-//                 format!("{}?{}", message, params_str)
-//             } else {
-//                 format!("{}", message)
-//             };
-//         } else if method == "POST" || method == "PUT" {
-//             message = format!("{}{}", message, body_data);
-//         }
-//
-//         trace!("**********", );
-//         trace!("组装数据:{}", message);
-//         trace!("**********", );
-//
-//         let mut mac = Hmac::<Sha256>::new_varkey(secret_key.as_bytes()).expect("Failed to create HMAC");
-//         mac.update(message.as_bytes());
-//         let result = mac.finalize().into_bytes();
-//         let base64_encoded = base64::encode(result);
-//         base64_encoded
-//     }
-//
-//     pub fn passphrase(secret_key: String, pass_key: String) -> String
-//     {
-//         let mut mac = Hmac::<Sha256>::new_varkey(secret_key.as_bytes()).expect("Failed to create HMAC");
-//         mac.update(pass_key.as_bytes());
-//         let result = mac.finalize().into_bytes();
-//         let base64_encoded = base64::encode(result);
-//         base64_encoded
-//     }
-//
-//
-//     async fn http_toll(&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 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 {
-//         match result {
-//             Ok(res_data) => {
-//                 if res_data.code != "200" {
-//                     // res_data
-//                     let mut error = res_data;
-//                     error.message = format!("错误:{},url:{},相关参数:{}", error.message, base_url, params);
-//                     error
-//                 } else {
-//                     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 != "200000" {
-//                         let msg = json_value["msg"].as_str().unwrap();
-//                         // let error = ResponseData::new("".to_string(), code.to_string(),
-//                         //                               format!("错误:{},url:{},相关参数:{}", msg, base_url, params),
-//                         //                               "".parse().unwrap());
-//                         // error
-//
-//                         let mut error = ResponseData::error(res_data.label, msg.parse().unwrap());
-//                         error.code = code.parse().unwrap();
-//                         error.data = format!("请求地址:{},请求参数:{}", base_url, params);
-//                         error
-//                     } else {
-//                         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
-//                     }
-//                 }
-//             }
-//             Err(err) => {
-//                 let error = ResponseData::error("".to_string(), format!("json 解析失败:{},相关参数:{}", err, params));
-//                 error
-//             }
-//         }
-//     }
-// }
+use std::collections::BTreeMap;
+use reqwest::header::HeaderMap;
+use hmac::{Hmac, Mac, NewMac};
+use reqwest::{Client};
+use rust_decimal::Decimal;
+use rust_decimal::prelude::FromPrimitive;
+use rust_decimal_macros::dec;
+use sha2::Sha256;
+use tracing::{info, trace};
+use crate::http_tool::RestTool;
+use crate::response_base::ResponseData;
+
+#[derive(Clone, Debug)]
+pub struct KucoinSwapRest {
+    pub label: String,
+    base_url: String,
+    client: reqwest::Client,
+    /*******参数*/
+    //是否需要登陆
+    //登陆所需参数
+    login_param: BTreeMap<String, String>,
+    delays: Vec<i64>,
+    max_delay: i64,
+    avg_delay: Decimal,
+}
+
+impl KucoinSwapRest {
+    /*******************************************************************************************************/
+    /*****************************************获取一个对象****************************************************/
+    /*******************************************************************************************************/
+
+    pub fn new(is_colo: bool, login_param: BTreeMap<String, String>) -> KucoinSwapRest
+    {
+        return KucoinSwapRest::new_label("default-KucoinSwapRest".to_string(), is_colo, login_param);
+    }
+    pub fn new_label(label: String, is_colo: bool, login_param: BTreeMap<String, String>) -> KucoinSwapRest {
+        let base_url = if is_colo {
+            "https://api-futures.kucoin.com".to_string()
+        } else {
+            "https://api-futures.kucoin.com".to_string()
+        };
+
+        if is_colo {
+            info!("开启高速(未配置,走普通:{})通道",base_url);
+        } else {
+            info!("走普通通道:{}",base_url);
+        }
+        /*****返回结构体*******/
+        KucoinSwapRest {
+            label,
+            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 = serde_json::json!({
+         });
+        let data = self.request("GET".to_string(),
+                                "/api/v1".to_string(),
+                                "/timestamp".to_string(),
+                                false,
+                                params.to_string(),
+        ).await;
+        data
+    }
+
+    // 获取成交记录
+    pub async fn get_fills(&mut self,
+                           symbol: String,
+                           order_id: String,
+                           side: String,
+                           start_at: i64,
+                           end_at: i64,
+                           page_size: i64,
+    ) -> ResponseData {
+        let mut params = serde_json::json!({
+            "symbol":symbol,
+            "pageSize":1000
+         });
+        if order_id.len() > 0 {
+            params["orderId"] = serde_json::json!(order_id);
+        }
+        if side.len() > 0 {
+            params["side"] = serde_json::json!(side);
+        }
+        if start_at > 0 {
+            params["startAt"] = serde_json::json!(start_at);
+        }
+        if end_at > 0 {
+            params["endAt"] = serde_json::json!(end_at);
+        }
+        if page_size > 0 {
+            params["pageSize"] = serde_json::json!(page_size);
+        }
+        let data = self.request("GET".to_string(),
+                                "/api/v1".to_string(),
+                                "/fills".to_string(),
+                                true,
+                                params.to_string(),
+        ).await;
+        data
+    }
+    //查询合约账户
+    pub async fn get_account(&mut self, contract: String) -> ResponseData {
+        let params = serde_json::json!({
+            "currency":contract
+         });
+        let data = self.request("GET".to_string(),
+                                "/api/v1".to_string(),
+                                "/account-overview".to_string(),
+                                true,
+                                params.to_string(),
+        ).await;
+        data
+    }
+    //获取仓位信息
+    pub async fn get_position(&mut self, symbol: String) -> ResponseData {
+        let params = serde_json::json!({
+            "symbol":symbol
+         });
+        let data = self.request("GET".to_string(),
+                                "/api/v1".to_string(),
+                                "/position".to_string(),
+                                true,
+                                params.to_string(),
+        ).await;
+        data
+    }
+    //查询所有的合约信息
+    pub async fn get_market_details(&mut self) -> ResponseData {
+        let params = serde_json::json!({});
+
+        let data = self.request("GET".to_string(),
+                                "/api/v1".to_string(),
+                                format!("/contracts/active"),
+                                true,
+                                params.to_string(),
+        ).await;
+        data
+    }
+    //实时行情
+    pub async fn get_ticker(&mut self, symbol: String) -> ResponseData {
+        let params = serde_json::json!({
+            "symbol":symbol
+         });
+        let data = self.request("GET".to_string(),
+                                "/api/v1".to_string(),
+                                format!("/ticker"),
+                                true,
+                                params.to_string(),
+        ).await;
+        data
+    }
+    //查看订单列表
+    pub async fn get_orders(&mut self, status: String, symbol: String) -> ResponseData {
+        let mut params = serde_json::json!({
+            // "symbol":symbol
+         });
+        if symbol.len() > 0 {
+            params.as_object_mut().unwrap().insert("symbol".parse().unwrap(), serde_json::Value::from(symbol));
+        }
+        if status.len() > 0 {
+            params.as_object_mut().unwrap().insert("status".parse().unwrap(), serde_json::Value::from(status));
+        }
+        trace!("??{}",params.to_string());
+        let data = self.request("GET".to_string(),
+                                "/api/v1".to_string(),
+                                format!("/orders"),
+                                true,
+                                params.to_string(),
+        ).await;
+        data
+    }
+    //获取用户仓位列表
+    pub async fn get_positions(&mut self, currency: String) -> ResponseData {
+        let params = serde_json::json!({
+            "currency":currency
+         });
+        let data = self.request("GET".to_string(),
+                                "/api/v1".to_string(),
+                                format!("/positions"),
+                                true,
+                                params.to_string(),
+        ).await;
+        data
+    }
+    //单个订单详情
+    pub async fn get_orders_details(&mut self, order_id: String, client_id: String) -> ResponseData {
+        let mut params = serde_json::json!({   });
+        let mut url = String::from("");
+        if order_id != "" {
+            url = format!("/orders/{}", order_id);
+        } else if client_id != "" {
+            url = format!("/orders/byClientOid");
+            params.as_object_mut().unwrap().insert("clientOid".parse().unwrap(), serde_json::Value::from(client_id));
+        }
+
+        let data = self.request("GET".to_string(),
+                                "/api/v1".to_string(),
+                                url,
+                                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/v1".to_string(),
+                                format!("/orders"),
+                                true,
+                                params.to_string(),
+        ).await;
+        data
+    }
+    //下单
+    pub async fn swap_bazaar_order(&mut self,
+                                   client_oid: String,
+                                   symbol: String,
+                                   origin_side: String,
+                                   size: u64,
+                                   leverage: String,
+                                   price: String,
+                                   order_type: String) -> ResponseData
+    {
+        let mut side = String::from("");
+        let mut params = serde_json::json!({
+            "clientOid":client_oid,
+            "symbol": symbol,
+            "size":size,
+            "leverage":leverage,
+            "reduceOnly":false,
+            "price":price,
+            "type":order_type,
+        });
+
+        let req = match origin_side.as_str() {
+            "kd" => {
+                side = "buy".to_string();
+                true
+            }
+            "pd" => {
+                side = "sell".to_string();
+                true
+            }
+            "kk" => {
+                side = "sell".to_string();
+                true
+            }
+            "pk" => {
+                side = "buy".to_string();
+                true
+            }
+            _ => { false } // 处理未知请求类型
+        };
+        if req {
+            params.as_object_mut().unwrap().insert("side".to_string(), serde_json::json!(side));
+        }
+
+        let data = self.swap_order(params).await;
+        data
+    }
+
+    //单个撤单
+    pub async fn cancel_order(&mut self, order_id: String, client_id: String) -> ResponseData {
+        let mut params = serde_json::json!({   });
+        let mut url = String::from("");
+        if order_id != "" {
+            url = format!("/orders/{}", order_id);
+        } else if client_id != "" {
+            url = format!("/orders/byClientOid");
+            params.as_object_mut().unwrap().insert("clientOid".parse().unwrap(), serde_json::Value::from(client_id));
+        }
+        let data = self.request("DELETE".to_string(),
+                                "/api/v1".to_string(),
+                                url,
+                                true,
+                                params.to_string(),
+        ).await;
+        data
+    }
+    //批量撤单
+    pub async fn cancel_orders(&mut self, symbol: String) -> ResponseData {
+        let params = serde_json::json!({   });
+        let data = self.request("DELETE".to_string(),
+                                "/api/v1".to_string(),
+                                format!("/orders?symbol={}", symbol),
+                                true,
+                                params.to_string(),
+        ).await;
+        data
+    }
+    //全部撤單
+    pub async fn cancel_order_all(&mut self) -> ResponseData {
+        let params = serde_json::json!({   });
+        let data = self.request("DELETE".to_string(),
+                                "/api/v1".to_string(),
+                                format!("/orders"),
+                                true,
+                                params.to_string(),
+        ).await;
+        data
+    }
+
+
+    //获取合约令牌-公共
+    pub async fn get_public_token(&mut self) -> ResponseData {
+        let params = serde_json::json!({});
+        let data = self.request("POST".to_string(),
+                                "/api/v1".to_string(),
+                                "/bullet-public".to_string(),
+                                false,
+                                params.to_string(),
+        ).await;
+        data
+    }
+    //获取合约令牌-私有
+    pub async fn get_private_token(&mut self) -> ResponseData {
+        let params = serde_json::json!({});
+        let data = self.request("POST".to_string(),
+                                "/api/v1".to_string(),
+                                "/bullet-private".to_string(),
+                                true,
+                                params.to_string(),
+        ).await;
+        data
+    }
+    //设置杠杆(修改階梯風險限額等級)
+    pub async fn set_leverage(&mut self, symbol: String, level: i8) -> ResponseData {
+        let params = serde_json::json!({
+            "symbol":symbol,
+            "level":level,
+        });
+        let data = self.request("POST".to_string(),
+                                "/api/v1".to_string(),
+                                format!("/position/risk-limit-level/change"),
+                                true,
+                                params.to_string(),
+        ).await;
+        data
+    }
+    //查看杠杆(查詢杠桿代幣信息)
+    pub async fn get_leverage(&mut self, symbol: String) -> ResponseData {
+        let params = serde_json::json!({
+        });
+        let data = self.request("GET".to_string(),
+                                "/api/v1".to_string(),
+                                format!("/contracts/risk-limit/{}", symbol),
+                                true,
+                                params.to_string(),
+        ).await;
+        data
+    }
+    //设置 自动追加保证金
+    pub async fn auto_deposit_status(&mut self, symbol: String, status: bool) -> ResponseData {
+        let params = serde_json::json!({
+                "symbol":symbol,
+                "status":status
+        });
+        let data = self.request("POST".to_string(),
+                                "/api/v1".to_string(),
+                                format!("/position/margin/auto-deposit-status"),
+                                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 pass_key = "".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") {
+            pass_key = self.login_param.get("pass_key").unwrap().to_string();
+        }
+        let mut is_login_param = true;
+        if access_key == "" || secret_key == "" || pass_key == "" {
+            is_login_param = false
+        }
+
+
+        //请求头配置-如果需要登陆则存在额外配置
+        let mut body = "".to_string();
+
+        let timestamp = chrono::Utc::now().timestamp_millis().to_string();
+
+        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(),
+                );
+                trace!("sing:{}", sing);
+                let passphrase = Self::passphrase(secret_key, pass_key);
+                trace!("passphrase:{}", passphrase);
+                //组装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_toll(
+            base_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("KC-API-KEY", access_key.parse().unwrap());
+        headers.insert("KC-API-SIGN", sign.parse().unwrap());
+        headers.insert("KC-API-TIMESTAMP", timestamp.parse().unwrap());
+        headers.insert("KC-API-PASSPHRASE", passphrase.parse().unwrap());
+        headers.insert("KC-API-KEY-VERSION", "2".parse().unwrap());
+        headers
+    }
+    pub fn sign(secret_key: String,
+                method: String, prefix_url: String, request_url: String,
+                params: String, body_data: String, timestamp: String) -> String
+    {
+        let url = format!("{}{}", prefix_url, request_url);
+        let params_str = RestTool::parse_params_to_str(params.clone());
+        trace!("body_data:{}", body_data);
+        // let body = Some(body_data);
+        // let hashed_payload = if let Some(body) = body {
+        //     let mut m = digest::Context::new(&digest::SHA256);
+        //     m.update(body.as_bytes());
+        //     hex::encode(m.finish().as_ref())
+        // } else {
+        //     String::new()
+        // };
+        // trace!("hashed_payload:{}", hashed_payload);
+
+        let mut message = format!("{}{}{}",
+                                  timestamp,
+                                  method,
+                                  url
+        );
+        if method == "GET" || method == "DELETE" {
+            message = if params_str.len() > 0 {
+                format!("{}?{}", message, params_str)
+            } else {
+                format!("{}", message)
+            };
+        } else if method == "POST" || method == "PUT" {
+            message = format!("{}{}", message, body_data);
+        }
+
+        trace!("**********", );
+        trace!("组装数据:{}", message);
+        trace!("**********", );
+
+        let mut mac = Hmac::<Sha256>::new_varkey(secret_key.as_bytes()).expect("Failed to create HMAC");
+        mac.update(message.as_bytes());
+        let result = mac.finalize().into_bytes();
+        let base64_encoded = base64::encode(result);
+        base64_encoded
+    }
+
+    pub fn passphrase(secret_key: String, pass_key: String) -> String
+    {
+        let mut mac = Hmac::<Sha256>::new_varkey(secret_key.as_bytes()).expect("Failed to create HMAC");
+        mac.update(pass_key.as_bytes());
+        let result = mac.finalize().into_bytes();
+        let base64_encoded = base64::encode(result);
+        base64_encoded
+    }
+
+
+    async fn http_toll(&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 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?;
+
+            let data = serde_json::from_str(body.as_str()).unwrap();
+            res_data = ResponseData::new(self.label.clone(), "200".to_string(), "success".to_string(), data);
+        } 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 {
+        match result {
+            Ok(res_data) => {
+                if res_data.code != "200" {
+                    // res_data
+                    let mut error = res_data;
+                    error.message = format!("错误:{},url:{},相关参数:{}", error.message, base_url, params);
+                    error
+                } else {
+                    let json_value = res_data.data;
+
+                    let code = json_value["code"].as_str().unwrap();
+
+                    if code != "200000" {
+                        let msg = json_value["msg"].as_str().unwrap();
+                        // let error = ResponseData::new("".to_string(), code.to_string(),
+                        //                               format!("错误:{},url:{},相关参数:{}", msg, base_url, params),
+                        //                               "".parse().unwrap());
+                        // error
+
+                        let mut error = ResponseData::error(res_data.label, msg.parse().unwrap());
+                        error.code = code.parse().unwrap();
+                        error.message = format!("请求地址:{},请求参数:{},响应:{}。", base_url, params, json_value.to_string());
+                        error
+                    } else {
+                        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
+                    }
+                }
+            }
+            Err(err) => {
+                let error = ResponseData::error("".to_string(), format!("json 解析失败:{},相关参数:{}", err, params));
+                error
+            }
+        }
+    }
+}

+ 396 - 393
exchanges/src/kucoin_swap_ws.rs

@@ -1,393 +1,396 @@
-// use std::collections::BTreeMap;
-// use std::sync::Arc;
-// use std::sync::atomic::AtomicBool;
-//
-// use futures_channel::mpsc::{UnboundedReceiver, UnboundedSender};
-// use tokio::sync::Mutex;
-// use tokio_tungstenite::tungstenite::{Error, Message};
-// use tracing::{error, info, trace};
-//
-// use crate::kucoin_swap_rest::KucoinSwapRest;
-// use crate::response_base::ResponseData;
-// use crate::socket_tool::{AbstractWsMode, HeartbeatType};
-//
-// //类型
-// pub enum KucoinSwapWsType {
-//     Public,
-//     Private,
-// }
-//
-//
-// #[derive(Debug)]
-// #[derive(Clone)]
-// pub struct KucoinSwapWsParam {
-//     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 KucoinSwapSubscribeType {
-//     PuContractMarketLevel2Depth50,
-//     //买卖盘 快照,asks:卖,bids:买入
-//     PuContractMarketExecution,
-//     PuContractMarkettickerV2,
-//
-//     PrContractAccountWallet,
-//     PrContractPosition,
-//     PrContractMarketTradeOrdersSys,
-//     PrContractMarketTradeOrders,
-// }
-//
-// //账号信息
-// #[derive(Clone, Debug)]
-// pub struct KucoinSwapLogin {
-//     pub access_key: String,
-//     pub secret_key: String,
-//     pub pass_key: String,
-// }
-//
-// #[derive(Clone)]
-// #[allow(dead_code)]
-// pub struct KucoinSwapWs {
-//     //类型
-//     label: String,
-//     //地址
-//     address_url: String,
-//     //账号
-//     login_param: Option<KucoinSwapLogin>,
-//     //登陆数据
-//     ws_param: KucoinSwapWsParam,
-//     //币对
-//     symbol_s: Vec<String>,
-//     //订阅
-//     subscribe_types: Vec<KucoinSwapSubscribeType>,
-//     //心跳间隔
-//     heartbeat_time: u64,
-// }
-//
-// impl KucoinSwapWs {
-//     /*******************************************************************************************************/
-//     /*****************************************获取一个对象****************************************************/
-//     /*******************************************************************************************************/
-//     pub async fn new(is_colo: bool, login_param: Option<KucoinSwapLogin>, ws_type: KucoinSwapWsType) -> KucoinSwapWs {
-//         return Self::new_label("default-KucoinSwapWs".to_string(), is_colo, login_param, ws_type).await;
-//     }
-//     pub async fn new_label(label: String, is_colo: bool, login_param: Option<KucoinSwapLogin>, ws_type: KucoinSwapWsType) -> KucoinSwapWs {
-//         /*******公共频道-私有频道数据组装*/
-//         let mut ws_param = KucoinSwapWsParam {
-//             token: "".to_string(),
-//             ws_url: "".to_string(),
-//             ws_ping_interval: 0,
-//             ws_ping_timeout: 0,
-//             is_ok_subscribe: false,
-//         };
-//
-//         /*******公共频道-私有频道数据组装*/
-//         let res_data = Self::get_rul_token(ws_type, login_param.clone()).await;
-//         let address_url = match res_data {
-//             Ok(param) => {
-//                 ws_param = param;
-//                 format!("{}?token={}", ws_param.ws_url, ws_param.token)
-//             }
-//             Err(error) => {
-//                 error!("-链接地址等参数错误:{:?}", error);
-//                 "".to_string()
-//             }
-//         };
-//
-//         if is_colo {
-//             info!("开启高速(未配置,走普通:{})通道",address_url);
-//         } else {
-//             info!("走普通通道:{}",address_url);
-//         }
-//
-//         KucoinSwapWs {
-//             label,
-//             address_url,
-//             login_param,
-//             ws_param,
-//             symbol_s: vec![],
-//             subscribe_types: vec![],
-//             heartbeat_time: 1000 * 18,
-//         }
-//     }
-//
-//     /*******************************************************************************************************/
-//     /*****************************************订阅函数********************************************************/
-//     /*******************************************************************************************************/
-//     //根据当前类型获取对应的频道 地址 与 token
-//     async fn get_rul_token(ws_type: KucoinSwapWsType, login_param: Option<KucoinSwapLogin>) -> Result<KucoinSwapWsParam, reqwest::Error> {
-//         let mut kucoin_exc = KucoinSwapRest::new(false, match login_param {
-//             None => {
-//                 let btree_map: BTreeMap<String, String> = BTreeMap::new();
-//                 btree_map
-//             }
-//             Some(d) => {
-//                 let mut btree_map: BTreeMap<String, String> = BTreeMap::new();
-//                 btree_map.insert("access_key".to_string(), d.access_key);
-//                 btree_map.insert("secret_key".to_string(), d.secret_key);
-//                 btree_map.insert("pass_key".to_string(), d.pass_key);
-//                 btree_map
-//             }
-//         });
-//
-//
-//         let res_data = match ws_type {
-//             KucoinSwapWsType::Public => {
-//                 kucoin_exc.get_public_token().await
-//             }
-//             KucoinSwapWsType::Private => {
-//                 kucoin_exc.get_private_token().await
-//             }
-//         };
-//
-//         trace!("kucoin-swap-rest 获取ws连接地址:{:?}",res_data);
-//
-//         if res_data.code == "200" {
-//             let mut ws_url = "".to_string();
-//             let mut ws_token = "".to_string();
-//             let mut ws_ping_interval: i64 = 0;
-//             let mut ws_ping_timeout: i64 = 0;
-//
-//
-//             //数据解析
-//             let parsed_json: serde_json::Value = serde_json::from_str(res_data.data.as_str()).unwrap();
-//             if let Some(value) = parsed_json.get("token") {
-//                 let formatted_value = match value {
-//                     serde_json::Value::String(s) => s.clone(),
-//                     _ => value.to_string()
-//                 };
-//                 ws_token = format!("{}", formatted_value);
-//             }
-//             if let Some(endpoint) = parsed_json["instanceServers"][0]["endpoint"].as_str() {
-//                 ws_url = format!("{}", endpoint);
-//             }
-//             if let Some(ping_interval) = parsed_json["instanceServers"][0]["pingInterval"].as_i64() {
-//                 ws_ping_interval = ping_interval;
-//             }
-//             if let Some(ping_timeout) = parsed_json["instanceServers"][0]["pingTimeout"].as_i64() {
-//                 ws_ping_timeout = ping_timeout;
-//             }
-//
-//
-//             Ok(KucoinSwapWsParam { ws_url, token: ws_token, ws_ping_interval, ws_ping_timeout, is_ok_subscribe: false })
-//         } else {
-//             error!("公共/私有-频道获取失败:{:?}", res_data);
-//             panic!("公共/私有-频道获取失败:{:?}", res_data);
-//         }
-//     }
-//     //手动添加订阅信息
-//     pub fn set_subscribe(&mut self, subscribe_types: Vec<KucoinSwapSubscribeType>) {
-//         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("_", "");
-//             *symbol = symbol.replace("-", "");
-//         }
-//         self.symbol_s = b_array;
-//     }
-//     fn contains_pr(&self) -> bool {
-//         for t in self.subscribe_types.clone() {
-//             if match t {
-//                 KucoinSwapSubscribeType::PuContractMarketLevel2Depth50 => false,
-//                 KucoinSwapSubscribeType::PuContractMarketExecution => false,
-//                 KucoinSwapSubscribeType::PuContractMarkettickerV2 => false,
-//
-//                 KucoinSwapSubscribeType::PrContractAccountWallet => true,
-//                 KucoinSwapSubscribeType::PrContractPosition => true,
-//                 KucoinSwapSubscribeType::PrContractMarketTradeOrdersSys => true,
-//                 KucoinSwapSubscribeType::PrContractMarketTradeOrders => true,
-//             } {
-//                 return true;
-//             }
-//         }
-//         false
-//     }
-//     /*******************************************************************************************************/
-//     /*****************************************工具函数********************************************************/
-//     /*******************************************************************************************************/
-//     //订阅枚举解析
-//     pub fn enum_to_string(symbol: String, subscribe_type: KucoinSwapSubscribeType) -> serde_json::Value {
-//         match subscribe_type {
-//             KucoinSwapSubscribeType::PuContractMarketLevel2Depth50 => {//level2
-//                 serde_json::json!({
-//                      "topic": format!("/contractMarket/level2Depth50:{}", symbol),
-//                      "type": "subscribe",
-//                      "response": true
-//                 })
-//             }
-//             KucoinSwapSubscribeType::PuContractMarketExecution => {//match
-//                 serde_json::json!({
-//                      "topic": format!("/contractMarket/execution:{}", symbol),
-//                      "type": "subscribe",
-//                      "response": true
-//                 })
-//             }
-//             KucoinSwapSubscribeType::PuContractMarkettickerV2 => {//tickerV2
-//                 serde_json::json!({
-//                      "topic": format!("/contractMarket/tickerV2:{}", symbol),
-//                      "type": "subscribe",
-//                      "response": true
-//                 })
-//             }
-//             KucoinSwapSubscribeType::PrContractAccountWallet => {//orderMargin.change
-//                 serde_json::json!({
-//                     "type": "subscribe",
-//                     "topic": "/contractAccount/wallet",
-//                     "privateChannel":true,
-//                     "response":true,
-//                 })
-//             }
-//             KucoinSwapSubscribeType::PrContractPosition => {//position.change
-//                 serde_json::json!({
-//                     "type": "subscribe",
-//                     "topic": format!("/contract/position:{}", symbol),
-//                     "privateChannel":true,
-//                     "response":true,
-//                 })
-//             }
-//             KucoinSwapSubscribeType::PrContractMarketTradeOrdersSys => {//orderChange
-//                 serde_json::json!({
-//                     "type": "subscribe",
-//                     "topic": format!("/contractMarket/tradeOrders"),
-//                     "privateChannel":true,
-//                     "response":true,
-//                 })
-//             }
-//             KucoinSwapSubscribeType::PrContractMarketTradeOrders => {//symbolOrderChange
-//                 serde_json::json!({
-//                     "type": "subscribe",
-//                     "topic": format!("/contractMarket/tradeOrders:{}", symbol),
-//                     "privateChannel":true,
-//                     "response":true,
-//                 })
-//             }
-//         }
-//     }
-//     //订阅信息生成
-//     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(&mut self,
-//                                   is_shutdown_arc: Arc<AtomicBool>,
-//                                   write_tx_am: &Arc<Mutex<UnboundedSender<Message>>>,
-//                                   write_rx: UnboundedReceiver<Message>,
-//                                   read_tx: UnboundedSender<ResponseData>,
-//     ) -> Result<(), Error>
-//     {
-//         let login_is = self.contains_pr();
-//         let subscription = self.get_subscription();
-//         let address_url = self.address_url.clone();
-//         let label = self.label.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 {
-//             trace!("线程-异步链接-开始");
-//             match AbstractWsMode::ws_connect_async(is_shutdown_arc, address_url.clone(),
-//                                                    label.clone(), subscribe_array,
-//                                                    write_rx, read_tx,
-//                                                    Self::message_text,
-//                                                    Self::message_ping,
-//                                                    Self::message_pong,
-//             ).await {
-//                 Ok(_) => { trace!("线程-异步链接-结束"); }
-//                 Err(e) => { trace!("发生异常:kucoin-期货链接关闭-{:?}",e); }
-//             }
-//         });
-//         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".to_string(), "success".to_string(), "".to_string()));
-//     }
-//     //数据解析-pong
-//     pub fn message_pong(_po: Vec<u8>) -> Option<ResponseData> {
-//         return Option::from(ResponseData::new("".to_string(), "-301".to_string(), "success".to_string(), "".to_string()));
-//     }
-//     //数据解析
-//     pub fn ok_text(text: String) -> ResponseData
-//     {
-//         // trace!("原始数据:{:?}",text);
-//         let mut res_data = ResponseData::new("".to_string(), "200".to_string(), "success".to_string(), "".to_string());
-//         let json_value: serde_json::Value = serde_json::from_str(&text).unwrap();
-//
-//         //订阅 相应
-//         if json_value["type"].as_str() == Option::from("welcome") {
-//             //链接成功
-//             res_data.code = "-200".to_string();
-//             res_data.message = "链接成功,主动发起订阅".to_string();
-//         } else if json_value["type"].as_str() == Option::from("ack") {
-//             res_data.code = "-201".to_string();
-//             res_data.message = "订阅成功".to_string();
-//         } else if json_value["type"].as_str() == Option::from("error") {
-//             res_data.code = format!("{}", json_value["code"]);
-//             res_data.message = format!("{}", json_value["data"].as_str().unwrap());
-//         } else if json_value.get("topic").is_some() {
-//             res_data.channel = format!("{}", json_value["subject"].as_str().unwrap());
-//
-//             if json_value["topic"].as_str() == Option::from("/contractAccount/wallet") {
-//                 res_data.code = "".to_string();
-//                 if json_value["subject"].as_str() == Option::from("availableBalance.change") {
-//                     res_data.code = "200".to_string();
-//                     res_data.data = json_value["data"].to_string();
-//                 } else {}
-//             } else {
-//                 res_data.data = json_value["data"].to_string();
-//             }
-//         } else {
-//             res_data.code = "".to_string();
-//             res_data.message = "未知解析".to_string();
-//         }
-//         res_data
-//     }
-// }
+use std::collections::BTreeMap;
+use std::sync::Arc;
+use std::sync::atomic::AtomicBool;
+use std::time::Duration;
+
+use futures_channel::mpsc::{UnboundedReceiver, UnboundedSender};
+use serde_json::Value;
+use tokio::sync::Mutex;
+use tokio_tungstenite::tungstenite::{Error, Message};
+use tracing::{error, info, trace};
+
+use crate::kucoin_swap_rest::KucoinSwapRest;
+use crate::response_base::ResponseData;
+use crate::socket_tool::{AbstractWsMode, HeartbeatType};
+
+//类型
+pub enum KucoinSwapWsType {
+    Public,
+    Private,
+}
+
+
+#[derive(Debug)]
+#[derive(Clone)]
+pub struct KucoinSwapWsParam {
+    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 KucoinSwapSubscribeType {
+    //买卖盘 快照,asks:卖,bids:买入
+    PuContractMarketLevel2Depth50,
+
+    PuContractMarketExecution,
+    PuContractMarkettickerV2,
+
+    PrContractAccountWallet,
+    PrContractPosition,
+    PrContractMarketTradeOrdersSys,
+    PrContractMarketTradeOrders,
+}
+
+//账号信息
+#[derive(Clone, Debug)]
+pub struct KucoinSwapLogin {
+    pub access_key: String,
+    pub secret_key: String,
+    pub pass_key: String,
+}
+
+#[derive(Clone)]
+#[allow(dead_code)]
+pub struct KucoinSwapWs {
+    //类型
+    label: String,
+    //地址
+    address_url: String,
+    //账号
+    login_param: Option<KucoinSwapLogin>,
+    //登陆数据
+    ws_param: KucoinSwapWsParam,
+    //币对
+    symbol_s: Vec<String>,
+    //订阅
+    subscribe_types: Vec<KucoinSwapSubscribeType>,
+    //心跳间隔
+    heartbeat_time: u64,
+}
+
+impl KucoinSwapWs {
+    /*******************************************************************************************************/
+    /*****************************************获取一个对象****************************************************/
+    /*******************************************************************************************************/
+    pub async fn new(is_colo: bool, login_param: Option<KucoinSwapLogin>, ws_type: KucoinSwapWsType) -> KucoinSwapWs {
+        return Self::new_label("default-KucoinSwapWs".to_string(), is_colo, login_param, ws_type).await;
+    }
+    pub async fn new_label(label: String, is_colo: bool, login_param: Option<KucoinSwapLogin>, ws_type: KucoinSwapWsType) -> KucoinSwapWs {
+        /*******公共频道-私有频道数据组装*/
+        let mut ws_param = KucoinSwapWsParam {
+            token: "".to_string(),
+            ws_url: "".to_string(),
+            ws_ping_interval: 0,
+            ws_ping_timeout: 0,
+            is_ok_subscribe: false,
+        };
+
+        /*******公共频道-私有频道数据组装*/
+        let res_data = Self::get_rul_token(ws_type, login_param.clone()).await;
+        let address_url = match res_data {
+            Ok(param) => {
+                ws_param = param;
+                format!("{}?token={}", ws_param.ws_url, ws_param.token)
+            }
+            Err(error) => {
+                error!("-链接地址等参数错误:{:?}", error);
+                "".to_string()
+            }
+        };
+
+        if is_colo {
+            info!("开启高速(未配置,走普通:{})通道",address_url);
+        } else {
+            info!("走普通通道:{}",address_url);
+        }
+
+        KucoinSwapWs {
+            label,
+            address_url,
+            login_param,
+            ws_param,
+            symbol_s: vec![],
+            subscribe_types: vec![],
+            heartbeat_time: 1000 * 18,
+        }
+    }
+
+    /*******************************************************************************************************/
+    /*****************************************订阅函数********************************************************/
+    /*******************************************************************************************************/
+    //根据当前类型获取对应的频道 地址 与 token
+    async fn get_rul_token(ws_type: KucoinSwapWsType, login_param: Option<KucoinSwapLogin>) -> Result<KucoinSwapWsParam, reqwest::Error> {
+        let mut kucoin_exc = KucoinSwapRest::new(false, match login_param {
+            None => {
+                let btree_map: BTreeMap<String, String> = BTreeMap::new();
+                btree_map
+            }
+            Some(d) => {
+                let mut btree_map: BTreeMap<String, String> = BTreeMap::new();
+                btree_map.insert("access_key".to_string(), d.access_key);
+                btree_map.insert("secret_key".to_string(), d.secret_key);
+                btree_map.insert("pass_key".to_string(), d.pass_key);
+                btree_map
+            }
+        });
+
+
+        let res_data = match ws_type {
+            KucoinSwapWsType::Public => {
+                kucoin_exc.get_public_token().await
+            }
+            KucoinSwapWsType::Private => {
+                kucoin_exc.get_private_token().await
+            }
+        };
+
+        trace!("kucoin-swap-rest 获取ws连接地址:{:?}",res_data);
+
+        if res_data.code == "200" {
+            let mut ws_url = "".to_string();
+            let mut ws_token = "".to_string();
+            let mut ws_ping_interval: i64 = 0;
+            let mut ws_ping_timeout: i64 = 0;
+
+
+            //数据解析
+            let parsed_json = res_data.data;
+            if let Some(value) = parsed_json.get("token") {
+                let formatted_value = match value {
+                    serde_json::Value::String(s) => s.clone(),
+                    _ => value.to_string()
+                };
+                ws_token = format!("{}", formatted_value);
+            }
+            if let Some(endpoint) = parsed_json["instanceServers"][0]["endpoint"].as_str() {
+                ws_url = format!("{}", endpoint);
+            }
+            if let Some(ping_interval) = parsed_json["instanceServers"][0]["pingInterval"].as_i64() {
+                ws_ping_interval = ping_interval;
+            }
+            if let Some(ping_timeout) = parsed_json["instanceServers"][0]["pingTimeout"].as_i64() {
+                ws_ping_timeout = ping_timeout;
+            }
+
+
+            Ok(KucoinSwapWsParam { ws_url, token: ws_token, ws_ping_interval, ws_ping_timeout, is_ok_subscribe: false })
+        } else {
+            error!("公共/私有-频道获取失败:{:?}", res_data);
+            panic!("公共/私有-频道获取失败:{:?}", res_data);
+        }
+    }
+    //手动添加订阅信息
+    pub fn set_subscribe(&mut self, subscribe_types: Vec<KucoinSwapSubscribeType>) {
+        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("_", "");
+            *symbol = symbol.replace("-", "");
+        }
+        self.symbol_s = b_array;
+    }
+    fn contains_pr(&self) -> bool {
+        for t in self.subscribe_types.clone() {
+            if match t {
+                KucoinSwapSubscribeType::PuContractMarketLevel2Depth50 => false,
+                KucoinSwapSubscribeType::PuContractMarketExecution => false,
+                KucoinSwapSubscribeType::PuContractMarkettickerV2 => false,
+
+                KucoinSwapSubscribeType::PrContractAccountWallet => true,
+                KucoinSwapSubscribeType::PrContractPosition => true,
+                KucoinSwapSubscribeType::PrContractMarketTradeOrdersSys => true,
+                KucoinSwapSubscribeType::PrContractMarketTradeOrders => true,
+            } {
+                return true;
+            }
+        }
+        false
+    }
+    /*******************************************************************************************************/
+    /*****************************************工具函数********************************************************/
+    /*******************************************************************************************************/
+    //订阅枚举解析
+    pub fn enum_to_string(symbol: String, subscribe_type: KucoinSwapSubscribeType) -> serde_json::Value {
+        match subscribe_type {
+            KucoinSwapSubscribeType::PuContractMarketLevel2Depth50 => {//level2
+                serde_json::json!({
+                     "topic": format!("/contractMarket/level2Depth50:{}", symbol),
+                     "type": "subscribe",
+                     "response": true
+                })
+            }
+            KucoinSwapSubscribeType::PuContractMarketExecution => {//match
+                serde_json::json!({
+                     "topic": format!("/contractMarket/execution:{}", symbol),
+                     "type": "subscribe",
+                     "response": true
+                })
+            }
+            KucoinSwapSubscribeType::PuContractMarkettickerV2 => {//tickerV2
+                serde_json::json!({
+                     "topic": format!("/contractMarket/tickerV2:{}", symbol),
+                     "type": "subscribe",
+                     "response": true
+                })
+            }
+            KucoinSwapSubscribeType::PrContractAccountWallet => {//orderMargin.change
+                serde_json::json!({
+                    "type": "subscribe",
+                    "topic": "/contractAccount/wallet",
+                    "privateChannel":true,
+                    "response":true,
+                })
+            }
+            KucoinSwapSubscribeType::PrContractPosition => {//position.change
+                serde_json::json!({
+                    "type": "subscribe",
+                    "topic": format!("/contract/position:{}", symbol),
+                    "privateChannel":true,
+                    "response":true,
+                })
+            }
+            KucoinSwapSubscribeType::PrContractMarketTradeOrdersSys => {//orderChange
+                serde_json::json!({
+                    "type": "subscribe",
+                    "topic": format!("/contractMarket/tradeOrders"),
+                    "privateChannel":true,
+                    "response":true,
+                })
+            }
+            KucoinSwapSubscribeType::PrContractMarketTradeOrders => {//symbolOrderChange
+                serde_json::json!({
+                    "type": "subscribe",
+                    "topic": format!("/contractMarket/tradeOrders:{}", symbol),
+                    "privateChannel":true,
+                    "response":true,
+                })
+            }
+        }
+    }
+    //订阅信息生成
+    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 label = self.label.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!("kucoin_usdt_swap socket 连接中……");
+                AbstractWsMode::ws_connect_async(is_shutdown_arc.clone(), handle_function.clone(), address_url.clone(),
+                                                 label.clone(), subscribe_array.clone(), write_to_socket_rx_arc.clone(),
+                                                 Self::message_text, Self::message_ping, Self::message_pong).await;
+
+                error!("kucoin_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".to_string(), "success".to_string(), Value::Null));
+    }
+    //数据解析-pong
+    pub fn message_pong(_po: Vec<u8>) -> Option<ResponseData> {
+        return Option::from(ResponseData::new("".to_string(), "-301".to_string(), "success".to_string(), Value::Null));
+    }
+    //数据解析
+    pub fn ok_text(text: String) -> ResponseData
+    {
+        // trace!("原始数据:{:?}",text);
+        let mut res_data = ResponseData::new("".to_string(), "200".to_string(), "success".to_string(), Value::Null);
+        let json_value: serde_json::Value = serde_json::from_str(&text).unwrap();
+
+        //订阅 相应
+        if json_value["type"].as_str() == Option::from("welcome") {
+            //链接成功
+            res_data.code = "-200".to_string();
+            res_data.message = "链接成功,主动发起订阅".to_string();
+        } else if json_value["type"].as_str() == Option::from("ack") {
+            res_data.code = "-201".to_string();
+            res_data.message = "订阅成功".to_string();
+        } else if json_value["type"].as_str() == Option::from("error") {
+            res_data.code = format!("{}", json_value["code"]);
+            res_data.message = format!("{}", json_value["data"].as_str().unwrap());
+        } else if json_value.get("topic").is_some() {
+            res_data.channel = format!("{}", json_value["subject"].as_str().unwrap());
+
+            if json_value["topic"].as_str() == Option::from("/contractAccount/wallet") {
+                res_data.code = "".to_string();
+                if json_value["subject"].as_str() == Option::from("availableBalance.change") {
+                    res_data.code = "200".to_string();
+                    res_data.data = json_value["data"].clone();
+                } else {}
+            } else {
+                res_data.data = json_value["data"].clone();
+            }
+        } else {
+            res_data.code = "".to_string();
+            res_data.message = "未知解析".to_string();
+        }
+        res_data
+    }
+}

+ 5 - 8
standard/src/exchange.rs

@@ -6,7 +6,7 @@ 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::kucoin_swap::KucoinSwap;
 // use crate::bitget_spot::BitgetSpot;
 use crate::bybit_swap::BybitSwap;
 // use crate::kucoin_spot::KucoinSpot;
@@ -24,7 +24,7 @@ pub enum ExchangeEnum {
     // BinanceSpot,
     GateSwap,
     // GateSpot,
-    // KucoinSwap,
+    KucoinSwap,
     // KucoinSpot,
     // OkxSwap,
     // BitgetSpot,
@@ -82,9 +82,9 @@ impl Exchange {
             // ExchangeEnum::GateSpot => {
             //     Box::new(GateSpot::new(symbol, is_colo, params))
             // }
-            // 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,6 +100,3 @@ impl Exchange {
         }
     }
 }
-
-
-

+ 1 - 1
standard/src/gate_swap.rs

@@ -593,7 +593,7 @@ impl Platform for GateSwap {
     async fn command_order(&mut self, order_command: &mut OrderCommand, trace_stack: &TraceStack) {
         let mut handles = vec![];
 
-        // 下单指令
+        // 下单指令,limits_open里已经包含了limits_close
         for item in order_command.limits_open.keys() {
             let mut ts = trace_stack.clone();
 

+ 19 - 19
standard/src/handle_info.rs

@@ -7,7 +7,7 @@ use tracing::{error};
 use exchanges::response_base::ResponseData;
 use global::public_params;
 use crate::exchange::ExchangeEnum;
-use crate::{binance_swap_handle, gate_swap_handle, bybit_swap_handle};
+use crate::{binance_swap_handle, gate_swap_handle, bybit_swap_handle, kucoin_handle};
 use crate::{Account, MarketOrder, Position, SpecialDepth, SpecialOrder, SpecialTicker};
 
 #[allow(dead_code)]
@@ -32,9 +32,9 @@ impl HandleSwapInfo {
             ExchangeEnum::GateSwap => {
                 gate_swap_handle::handle_account_info(res_data, symbol)
             }
-            // ExchangeEnum::KucoinSwap => {
-            //     kucoin_handle::handle_account_info(res_data, symbol)
-            // }
+            ExchangeEnum::KucoinSwap => {
+                kucoin_handle::handle_account_info(res_data, symbol)
+            }
             // ExchangeEnum::KucoinSpot => {
             //     kucoin_spot_handle::handle_account_info(res_data, symbol)
             // }
@@ -65,9 +65,9 @@ impl HandleSwapInfo {
             ExchangeEnum::GateSwap => {
                 gate_swap_handle::handle_book_ticker(res_data)
             }
-            // ExchangeEnum::KucoinSwap => {
-            //     kucoin_handle::handle_special_ticker(res_data)
-            // }
+            ExchangeEnum::KucoinSwap => {
+                kucoin_handle::handle_book_ticker(res_data)
+            }
             // ExchangeEnum::KucoinSpot => {
             //     kucoin_spot_handle::handle_special_ticker(res_data)
             // }
@@ -92,9 +92,9 @@ impl HandleSwapInfo {
             ExchangeEnum::GateSwap => {
                 gate_swap_handle::handle_position(res_data, ct_val)
             }
-            // ExchangeEnum::KucoinSwap => {
-            //     kucoin_handle::handle_position(res_data, ct_val)
-            // }
+            ExchangeEnum::KucoinSwap => {
+                kucoin_handle::handle_position(res_data, ct_val)
+            }
             // ExchangeEnum::KucoinSpot => {
             //     error!("暂未提供此交易所方法!handle_position:{:?}", exchange);
             //     panic!("暂未提供此交易所方法!handle_position:{:?}", exchange);
@@ -121,9 +121,9 @@ impl HandleSwapInfo {
             ExchangeEnum::GateSwap => {
                 gate_swap_handle::handle_order(res_data, ct_val)
             }
-            // ExchangeEnum::KucoinSwap => {
-            //     kucoin_handle::handle_order(res_data, ct_val)
-            // }
+            ExchangeEnum::KucoinSwap => {
+                kucoin_handle::handle_order(res_data, ct_val)
+            }
             // ExchangeEnum::KucoinSpot => {
             //     kucoin_spot_handle::handle_order(res_data, ct_val)
             // }
@@ -240,12 +240,12 @@ pub fn format_depth(exchange: ExchangeEnum, res_data: &ResponseData) -> DepthPar
             t = Decimal::from_str(&res_data.data["t"].to_string()).unwrap();
             create_at = res_data.data["t"].as_i64().unwrap() * 1000;
         }
-        // ExchangeEnum::KucoinSwap => {
-        //     depth_asks = kucoin_handle::format_depth_items(res_data_json["asks"].clone());
-        //     depth_bids = kucoin_handle::format_depth_items(res_data_json["bids"].clone());
-        //     t = Decimal::from_str(&res_data_json["sequence"].to_string()).unwrap();
-        //     create_at = res_data_json["ts"].as_i64().unwrap() * 1000;
-        // }
+        ExchangeEnum::KucoinSwap => {
+            depth_asks = kucoin_handle::format_depth_items(res_data.data["asks"].clone());
+            depth_bids = kucoin_handle::format_depth_items(res_data.data["bids"].clone());
+            t = Decimal::from_str(&res_data.data["sequence"].to_string()).unwrap();
+            create_at = res_data.data["ts"].as_i64().unwrap() * 1000;
+        }
         // ExchangeEnum::KucoinSpot => {
         //     depth_asks = kucoin_spot_handle::format_depth_items(res_data_json["asks"].clone());
         //     depth_bids = kucoin_spot_handle::format_depth_items(res_data_json["bids"].clone());

+ 155 - 161
standard/src/kucoin_handle.rs

@@ -1,161 +1,155 @@
-// use std::str::FromStr;
-// use rust_decimal::Decimal;
-// use rust_decimal::prelude::FromPrimitive;
-// use rust_decimal_macros::dec;
-// use tokio::time::Instant;
-// use exchanges::response_base::ResponseData;
-// use global::trace_stack::TraceStack;
-// use crate::{Account, MarketOrder, Order, Position, PositionModeEnum, SpecialDepth, SpecialOrder, SpecialTicker, utils};
-// use crate::exchange::ExchangeEnum;
-// use crate::handle_info::HandleSwapInfo;
-//
-// // 处理账号信息
-// pub fn handle_account_info(res_data: ResponseData, symbol: String) -> Account {
-//     let res_data_str = res_data.data;
-//     let res_data_json: serde_json::Value = serde_json::from_str(&res_data_str).unwrap();
-//     format_account_info(res_data_json, symbol)
-// }
-//
-// pub fn format_account_info(data: serde_json::Value, symbol: String) -> Account {
-//     let symbol_upper = symbol.to_uppercase();
-//     let symbol_array: Vec<&str> = symbol_upper.split("_").collect();
-//     let available_balance = Decimal::from_str(data["availableBalance"].as_str().unwrap()).unwrap();
-//     let frozen_balance = Decimal::from_str(data["holdBalance"].as_str().unwrap()).unwrap();
-//     let balance = available_balance + frozen_balance;
-//     Account {
-//         coin: symbol_array[1].to_string(),
-//         balance,
-//         available_balance,
-//         frozen_balance,
-//         stocks: Decimal::ZERO,
-//         available_stocks: Decimal::ZERO,
-//         frozen_stocks: Decimal::ZERO,
-//     }
-// }
-//
-// // 处理特殊Ticket信息
-// 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)
-// }
-//
-// pub fn format_special_ticker(data: serde_json::Value, label: String) -> SpecialDepth {
-//     let bp = Decimal::from_str(&data["bestBidPrice"].as_str().unwrap()).unwrap();
-//     let bq = Decimal::from_f64(data["bestBidSize"].as_f64().unwrap()).unwrap();
-//     let ap = Decimal::from_str(&data["bestAskPrice"].as_str().unwrap()).unwrap();
-//     let aq = Decimal::from_f64(data["bestAskSize"].as_f64().unwrap()).unwrap();
-//     let mp = (bp + ap) * dec!(0.5);
-//     let t = Decimal::from_str(&data["sequence"].to_string()).unwrap();
-//     let create_at = (data["ts"].as_f64().unwrap() / 1000.0).floor() as i64;
-//
-//     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,
-//     }
-// }
-//
-// // 处理position信息
-// pub fn handle_position(res_data: ResponseData, ct_val: Decimal) -> Vec<Position> {
-//     let res_data_str = res_data.data;
-//     let res_data_json: serde_json::Value = serde_json::from_str(&res_data_str).unwrap();
-//     let result = format_position_item(&res_data_json, ct_val);
-//     return vec![result];
-// }
-//
-// pub fn format_position_item(position: &serde_json::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,
-//     }
-// }
-//
-// // 处理order信息
-// pub fn handle_order(res_data: ResponseData, ct_val: Decimal) -> SpecialOrder {
-//     let res_data_str = res_data.data;
-//     let res_data_json: Vec<serde_json::Value> = vec![serde_json::from_str(&*res_data_str).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,
-//     }
-// }
-//
-// // ws处理
-// pub fn format_order_item(order: serde_json::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(),
-//         trace_stack: TraceStack::new(0, Instant::now()).on_special("136 kucoin_handle".to_string()),
-//     }
-// }
-//
-// // 处理特殊深度数据
-// pub fn handle_special_depth(res_data: ResponseData) -> SpecialDepth {
-//     HandleSwapInfo::handle_special_depth(ExchangeEnum::KucoinSwap, res_data)
-// }
-//
-// 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_str(value[0].as_str().unwrap()).unwrap(),
-//             amount: Decimal::from_f64(value[1].as_f64().unwrap()).unwrap(),
-//         })
-//     }
-//     return depth_items;
-// }
+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 exchanges::response_base::ResponseData;
+use global::trace_stack::TraceStack;
+use crate::{Account, MarketOrder, Order, Position, PositionModeEnum, SpecialDepth, SpecialOrder, SpecialTicker, utils};
+use crate::exchange::ExchangeEnum;
+use crate::handle_info::HandleSwapInfo;
+
+// 处理账号信息
+pub fn handle_account_info(res_data: &ResponseData, symbol: &String) -> Account {
+    format_account_info(&res_data.data, symbol)
+}
+
+pub fn format_account_info(data: &Value, symbol: &String) -> Account {
+    let symbol_upper = symbol.to_uppercase();
+    let symbol_array: Vec<&str> = symbol_upper.split("_").collect();
+    let available_balance = Decimal::from_str(data["availableBalance"].as_str().unwrap()).unwrap();
+    let frozen_balance = Decimal::from_str(data["holdBalance"].as_str().unwrap()).unwrap();
+    let balance = available_balance + frozen_balance;
+    Account {
+        coin: symbol_array[1].to_string(),
+        balance,
+        available_balance,
+        frozen_balance,
+        stocks: Decimal::ZERO,
+        available_stocks: Decimal::ZERO,
+        frozen_stocks: Decimal::ZERO,
+    }
+}
+
+// 处理特殊Ticket信息
+pub fn handle_book_ticker(res_data: &ResponseData) -> SpecialDepth {
+    format_special_ticker(&res_data.data, &res_data.label)
+}
+
+pub fn format_special_ticker(data: &Value, label: &String) -> SpecialDepth {
+    let bp = Decimal::from_str(&data["bestBidPrice"].as_str().unwrap()).unwrap();
+    let bq = Decimal::from_f64(data["bestBidSize"].as_f64().unwrap()).unwrap();
+    let ap = Decimal::from_str(&data["bestAskPrice"].as_str().unwrap()).unwrap();
+    let aq = Decimal::from_f64(data["bestAskSize"].as_f64().unwrap()).unwrap();
+    let mp = (bp + ap) * dec!(0.5);
+    let t = Decimal::from_str(&data["sequence"].to_string()).unwrap();
+    let create_at = (data["ts"].as_f64().unwrap() / 1000.0).floor() as i64;
+
+    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.clone(),
+        depth: depth_info,
+        ticker: ticker_info,
+        t,
+        create_at,
+    }
+}
+
+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 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, 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(),
+        trace_stack: TraceStack::new(0, Instant::now()).on_special("136 kucoin_handle".to_string()),
+    }
+}
+
+// 处理特殊深度数据
+pub fn handle_special_depth(res_data: ResponseData) -> SpecialDepth {
+    HandleSwapInfo::handle_special_depth(ExchangeEnum::KucoinSwap, &res_data)
+}
+
+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_str(value[0].as_str().unwrap()).unwrap(),
+            amount: Decimal::from_f64(value[1].as_f64().unwrap()).unwrap(),
+        })
+    }
+    return depth_items;
+}

+ 668 - 685
standard/src/kucoin_swap.rs

@@ -1,685 +1,668 @@
-// use std::collections::{BTreeMap, HashMap};
-// 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;
-// 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" {
-//             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 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_str = &res_data.data;
-//             let res_data_json: serde_json::Value = serde_json::from_str(res_data_str).unwrap();
-//
-//             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 res_data_str = &res_data.data;
-//             let res_data_json: serde_json::Value = serde_json::from_str(res_data_str).unwrap();
-//             let result = kucoin_handle::format_position_item(&res_data_json, 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" {
-//             let res_data_str = &res_data.data;
-//             let res_data_json: Vec<serde_json::Value> = serde_json::from_str(res_data_str).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_str = &res_data.data;
-//             let res_data_json: serde_json::Value = serde_json::from_str(res_data_str).unwrap();
-//             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_str = &res_data.data;
-//             let res_data_json: serde_json::Value = serde_json::from_str(res_data_str).unwrap();
-//             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_str = &res_data.data;
-//             let res_data_json: Vec<serde_json::Value> = serde_json::from_str(res_data_str).unwrap();
-//
-//             let market_info = res_data_json.iter().find(|item| item["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_str = &res_data.data;
-//             let res_data_json: Vec<serde_json::Value> = serde_json::from_str(res_data_str).unwrap();
-//             let market_info = res_data_json.iter().find(|item| item["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_str = &res_data.data;
-//             let res_data_json: serde_json::Value = serde_json::from_str(res_data_str).unwrap();
-//             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_str = &res_data.data;
-//             let res_data_json: serde_json::Value = serde_json::from_str(res_data_str).unwrap();
-//             let order_list: Vec<serde_json::Value> = res_data_json["items"].as_array().unwrap().clone();
-//             let order_info: Vec<&serde_json::Value> = 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_str = &res_data.data;
-//             let res_data_json: serde_json::Value = serde_json::from_str(res_data_str).unwrap();
-//             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_str = &res_data.data;
-//             let res_data_json: serde_json::Value = serde_json::from_str(res_data_str).unwrap();
-//             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_str = &res_data.data;
-//             let res_data_json: serde_json::Value = serde_json::from_str(res_data_str).unwrap();
-//             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" {
-//             let res_data_str = &res_data.data;
-//             let res_data_json: serde_json::Value = serde_json::from_str(res_data_str).unwrap();
-//             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" {
-//             let res_data_str = &res_data.data;
-//             let res_data_json: serde_json::Value = serde_json::from_str(res_data_str).unwrap();
-//             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 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" {
-//             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 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: OrderCommand, trace_stack: TraceStack) {
-//         let mut handles = vec![];
-//         // 撤销订单
-//         let cancel = order_command.cancel;
-//         for item in cancel.keys() {
-//             let mut self_clone = self.clone();
-//             let cancel_clone = cancel.clone();
-//             let item_clone = item.clone();
-//             let order_id = cancel_clone[&item_clone].get(1).unwrap_or(&"".to_string()).clone();
-//             let custom_id = cancel_clone[&item_clone].get(0).unwrap_or(&"".to_string()).clone();
-//             let result_sd = self.order_sender.clone();
-//             let err_sd = self.error_sender.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) => {
-//                                     result_sd.send(order).await.unwrap();
-//                                 }
-//                                 Err(_query_err) => {
-//                                     // error!(?_query_err);
-//                                     // error!("撤单失败,而且查单也失败了,kucoin_swap,oid={}, cid={}。", order_id.clone(), custom_id.clone());
-//                                 }
-//                             }
-//                             err_sd.send(error).await.unwrap();
-//                         }
-//                     }
-//                 }
-//             });
-//             handles.push(handle)
-//         }
-//         // 下单指令
-//         let mut limits = HashMap::new();
-//         limits.extend(order_command.limits_open);
-//         limits.extend(order_command.limits_close);
-//         for item in limits.keys() {
-//             let mut self_clone = self.clone();
-//             let limits_clone = limits.clone();
-//             let item_clone = item.clone();
-//             let result_sd = self.order_sender.clone();
-//             let err_sd = self.error_sender.clone();
-//             let ts = trace_stack.clone();
-//
-//             let handle = tokio::spawn(async move {
-//                 let value = limits_clone[&item_clone].clone();
-//                 // info!(?value);
-//                 // info!("{}", ts.to_string());
-//                 let amount = Decimal::from_str(value.get(0).unwrap_or(&"0".to_string())).unwrap();
-//                 let side = value.get(1).unwrap();
-//                 let price = Decimal::from_str(value.get(2).unwrap_or(&"0".to_string())).unwrap();
-//                 let cid = value.get(3).unwrap();
-//
-//                 //  order_name: [数量,方向,价格,c_id]
-//                 let result = self_clone.take_order(cid, side, price, amount).await;
-//                 match result {
-//                     Ok(mut result) => {
-//                         // ts.on_after_send();
-//                         result.trace_stack = ts.clone();
-//
-//                         result_sd.send(result).await.unwrap();
-//                     }
-//                     Err(error) => {
-//                         let mut err_order = Order::new();
-//                         err_order.custom_id = cid.clone();
-//                         err_order.status = "REMOVE".to_string();
-//
-//                         result_sd.send(err_order).await.unwrap();
-//                         err_sd.send(error).await.unwrap();
-//                     }
-//                 }
-//             });
-//             handles.push(handle)
-//         }
-//         // if limits.len() > 0 {
-//         //     info!("");
-//         // }
-//         // 检查订单指令
-//         let check = order_command.check;
-//         for item in check.keys() {
-//             let mut self_clone = self.clone();
-//             let check_clone = check.clone();
-//             let item_clone = item.clone();
-//             let order_id = check_clone[&item_clone].get(1).unwrap_or(&"".to_string()).clone();
-//             let custom_id = check_clone[&item_clone].get(0).unwrap_or(&"".to_string()).clone();
-//             let result_sd = self.order_sender.clone();
-//             let err_sd = self.error_sender.clone();
-//             let handle = tokio::spawn(async move {
-//                 let result = self_clone.get_order_detail(&order_id, &custom_id).await;
-//                 match result {
-//                     Ok(result) => {
-//                         result_sd.send(result).await.unwrap();
-//                     }
-//                     Err(error) => {
-//                         err_sd.send(error).await.unwrap();
-//                     }
-//                 }
-//             });
-//             handles.push(handle)
-//         }
-//
-//         let futures = FuturesUnordered::from_iter(handles);
-//         let _: Result<Vec<_>, _> = futures.try_collect().await;
-//     }
-// }
-//
-// pub fn format_order_item(order: serde_json::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" {
+            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" {
+            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" {
+            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()),
+    }
+}

+ 32 - 31
standard/src/utils.rs

@@ -1,5 +1,6 @@
 use tracing::trace;
 use exchanges::proxy;
+use crate::exchange::ExchangeEnum;
 
 /// 修改交易对连接符号
 /// - `symbol(str)`: 交易对, "BTC_USDT", 默认以下划线传递
@@ -15,34 +16,34 @@ pub fn proxy_handle() {
     }
 }
 
-// /// 币种映射器
-// #[allow(dead_code)]
-// 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() }
-//         }
-//         _ => {
-//             symbol_upper.to_string()
-//         }
-//     }
-// }
-//
-// /// 币种映射器
-// #[allow(dead_code)]
-// 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() }
-//         }
-//         _ => {
-//             symbol_upper.to_string()
-//         }
-//     }
-// }
+/// 币种映射器
+#[allow(dead_code)]
+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() }
+        }
+        _ => {
+            symbol_upper.to_string()
+        }
+    }
+}
+
+/// 币种映射器
+#[allow(dead_code)]
+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() }
+        }
+        _ => {
+            symbol_upper.to_string()
+        }
+    }
+}

+ 4 - 4
strategy/src/core.rs

@@ -22,7 +22,7 @@ use global::public_params::{ASK_PRICE_INDEX, BID_PRICE_INDEX, LENGTH};
 use global::trace_stack::TraceStack;
 use standard::{Account, Market, Order, OrderCommand, Platform, Position, PositionModeEnum, SpecialTicker, Ticker};
 use standard::exchange::{Exchange};
-use standard::exchange::ExchangeEnum::{BinanceSwap, BybitSwap, GateSwap};
+use standard::exchange::ExchangeEnum::{BinanceSwap, BybitSwap, GateSwap, KucoinSwap};
 
 use crate::model::{LocalPosition, OrderInfo, TokenParam};
 use crate::predictor::Predictor;
@@ -203,9 +203,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
                 }

+ 7 - 7
strategy/src/exchange_disguise.rs

@@ -12,7 +12,7 @@ use crate::gate_swap::gate_swap_run;
 // use crate::bitget_spot::bitget_spot_run;
 use crate::bybit_usdt_swap::bybit_swap_run;
 // use crate::kucoin_spot::kucoin_spot_run;
-// use crate::kucoin_swap::kucoin_swap_run;
+use crate::kucoin_swap::kucoin_swap_run;
 // use crate::okx_usdt_swap::okex_swap_run;
 use crate::core::Core;
 
@@ -28,9 +28,9 @@ 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;
         // },
@@ -68,9 +68,9 @@ 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;
         // },

+ 165 - 206
strategy/src/kucoin_swap.rs

@@ -1,206 +1,165 @@
-// use std::collections::{BTreeMap};
-// use std::sync::Arc;
-// use std::sync::atomic::{AtomicBool};
-// use std::time::Duration;
-// use futures_util::StreamExt;
-//
-// use rust_decimal::Decimal;
-// use tokio_tungstenite::tungstenite::Message;
-// use tokio::spawn;
-// use tokio::sync::Mutex;
-// use tokio::time::sleep;
-//
-// 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, OriginalTradeGa};
-// 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 symbols_clone = symbols.clone();
-//     let mut symbol_arr = Vec::new();
-//     for symbol in symbols_clone {
-//         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;
-//             }
-//         }
-//     });
-//
-//     spawn(async move {
-//         //创建读写通道
-//         let (write_tx, write_rx) = futures_channel::mpsc::unbounded::<Message>();
-//         let (read_tx, mut read_rx) = futures_channel::mpsc::unbounded();
-//
-//         spawn( async move {
-//             let mut kucoin_exc;
-//             //模拟业务场景 开启链接
-//             let is_shutdown_arc_clone = Arc::clone(&is_shutdown_arc);
-//             let write_tx_am = Arc::new(Mutex::new(write_tx));
-//
-//             // 交易
-//             if is_trade {
-//                 let login_params = parse_btree_map_to_kucoin_swap_login(exchange_params);
-//                 kucoin_exc = KucoinSwapWs::new_label(name.clone(), is_colo, Option::from(login_params), KucoinSwapWsType::Private).await;
-//                 kucoin_exc.set_subscribe(vec![
-//                     KucoinSwapSubscribeType::PuContractMarketLevel2Depth50,
-//                     // KucoinSwapSubscribeType::PuContractMarkettickerV2,
-//                     // KucoinSwapSubscribeType::PrContractAccountWallet,
-//                     KucoinSwapSubscribeType::PrContractPosition,
-//                     KucoinSwapSubscribeType::PrContractMarketTradeOrders
-//                 ]);
-//             } else { // 参考
-//                 kucoin_exc = KucoinSwapWs::new_label(name.clone(), is_colo, None, KucoinSwapWsType::Public).await;
-//                 kucoin_exc.set_subscribe(vec![
-//                     KucoinSwapSubscribeType::PuContractMarketLevel2Depth50,
-//                     // python注释掉了
-//                     // KucoinSwapSubscribeType::PuContractMarkettickerV2,
-//                     KucoinSwapSubscribeType::PuContractMarketExecution
-//                 ]);
-//             }
-//
-//             kucoin_exc.set_symbols(symbol_arr);
-//             kucoin_exc.ws_connect_async(is_shutdown_arc_clone, &write_tx_am, write_rx, read_tx).await.unwrap();
-//         });
-//
-//         // 数据处理协程
-//         spawn(async move {
-//             let core_arc_clone = Arc::clone(&core_arc);
-//
-//             // ticker
-//             let mut update_flag_u = Decimal::ZERO;
-//             let mut max_buy = Decimal::ZERO;
-//             let mut min_sell = Decimal::ZERO;
-//             let multiplier = core_arc_clone.lock().await.platform_rest.get_self_market().ct_val;
-//
-//             loop {
-//                 if let Some(data) = read_rx.next().await {
-//                     on_data(core_arc_clone.clone(),
-//                             &mut update_flag_u,
-//                             multiplier,
-//                             &mut max_buy,
-//                             &mut min_sell,
-//                             data).await;
-//                 }
-//             }
-//         });
-//     });
-// }
-//
-// 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,
-//                  data: ResponseData) {
-//     let mut trace_stack = TraceStack::new(0, Instant::now());
-//     trace_stack.on_after_network(data.time);
-//     trace_stack.on_before_unlock_core();
-//
-//     if data.code != "200".to_string() {
-//         return;
-//     }
-//     if data.channel == "level2" {
-//         trace_stack.on_before_format();
-//         let special_depth = standard::handle_info::HandleSwapInfo::handle_special_depth(KucoinSwap,data.clone());
-//         trace_stack.on_before_network(special_depth.create_at.clone());
-//         trace_stack.on_after_format();
-//
-//         on_special_depth(core_arc_clone, update_flag_u, data.label, trace_stack, special_depth).await
-//     } else if data.channel == "tickerV2" {
-//         let special_depth = standard::handle_info::HandleSwapInfo::handle_special_ticker(KucoinSwap, data.clone());
-//         trace_stack.on_before_network(special_depth.create_at.clone());
-//
-//         on_special_depth(core_arc_clone, update_flag_u, data.label, trace_stack, special_depth).await
-//     } else if data.channel == "availableBalance.change" {
-//         // 取消原有推送解析,因为推送的信息不准确
-//         // let account = standard::handle_info::HandleSwapInfo::handle_account_info(KucoinSwap, data, run_symbol.clone());
-//         // {
-//         //     let mut core = core_arc_clone.lock().await;
-//         //     core.update_equity(account);
-//         // }
-//     } else if data.channel == "symbolOrderChange" {
-//         trace_stack.on_before_format();
-//         let orders = standard::handle_info::HandleSwapInfo::handle_order(KucoinSwap, data.clone(), multiplier);
-//         trace_stack.on_after_format();
-//         let mut order_infos:Vec<OrderInfo> = Vec::new();
-//         for order in orders.order {
-//             if order.status == "NULL" {
-//                 continue;
-//             }
-//             let order_info = OrderInfo {
-//                 symbol: "".to_string(),
-//                 amount: order.amount.abs(),
-//                 side: "".to_string(),
-//                 price: order.price,
-//                 client_id: order.custom_id,
-//                 filled_price: order.avg_price,
-//                 filled: order.deal_amount.abs(),
-//                 order_id: order.id,
-//                 local_time: 0,
-//                 create_time: 0,
-//                 status: order.status,
-//                 fee: Default::default(),
-//                 trace_stack: Default::default(),
-//             };
-//             order_infos.push(order_info);
-//         }
-//
-//         {
-//             let mut core = core_arc_clone.lock().await;
-//             core.update_order(order_infos, trace_stack);
-//         }
-//     } else if data.channel == "position.change" {
-//         let positions = standard::handle_info::HandleSwapInfo::handle_position(KucoinSwap,data, multiplier);
-//         {
-//             let mut core = core_arc_clone.lock().await;
-//             core.update_position(positions).await;
-//         }
-//     } else if data.channel == "match" {
-//         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 trade: OriginalTradeGa = serde_json::from_str(data.data.as_str()).unwrap();
-//         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]);
-//     }
-// }
-//
-// 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(),
+    }
+}