Explorar el Código

Merge branch 'master' of http://git.skyfffire.com/skyfffire/as-rust

JiahengHe hace 2 años
padre
commit
14a3db6cce

+ 33 - 100
exchanges/src/binance_usdt_swap_ws.rs

@@ -27,7 +27,7 @@ pub struct BinanceUsdtSwapWs {
     //登陆所需参数
     login_param: BTreeMap<String, String>,
 
-    // sender: mpsc::Sender<ResponseData>,
+    sender: mpsc::Sender<ResponseData>,
 }
 
 impl BinanceUsdtSwapWs {
@@ -37,7 +37,7 @@ impl BinanceUsdtSwapWs {
     pub fn new(is_colo: bool,
                is_login: bool,
                login_param: BTreeMap<String, String>,
-               // sender: mpsc::Sender<ResponseData>,
+               sender: mpsc::Sender<ResponseData>,
     ) -> BinanceUsdtSwapWs
     {
         let mut base_url = String::from("");
@@ -64,7 +64,7 @@ impl BinanceUsdtSwapWs {
             port: port_v,
             is_login,
             login_param,
-            // sender,
+            sender,
         }
     }
 
@@ -73,10 +73,7 @@ impl BinanceUsdtSwapWs {
     /*****************************************订阅函数********************************************************/
     /*******************************************************************************************************/
     //K线-不需要认证
-    pub fn kline<F, Fut>(&self, b_array: Vec<&str>, parse_fn: F)
-        where
-            F: Fn(ResponseData) -> Fut + 'static + Send + Sync,
-            Fut: Future<Output=()> + Send + 'static,
+    pub fn kline(&self, b_array: Vec<&str>)
     {
         //订阅信息拼接
         let mut params = vec![];
@@ -85,14 +82,11 @@ impl BinanceUsdtSwapWs {
             b_name = format!("{}@{}", b_name, "kline_1s");
             params.push(b_name);
         }
-        self.run(b_array, params, parse_fn);
+        self.run(b_array, params);
     }
 
     //自定义-不需要认证
-    pub fn custom_subscribe<F, Fut>(&self, b_array: Vec<&str>, sub_trade: u8, sub_fast: u8, parse_fn: F)
-        where
-            F: Fn(ResponseData) -> Fut + 'static + Send + Sync,
-            Fut: Future<Output=()> + Send + 'static,
+    pub fn custom_subscribe(&self, b_array: Vec<&str>, sub_trade: u8, sub_fast: u8)
     {
         let mut params = vec![];
 
@@ -107,71 +101,17 @@ impl BinanceUsdtSwapWs {
                 params.push(format!("{}@depth20@100ms", b_name));
             }
         }
-        self.run(b_array, params, parse_fn);
+        self.run(b_array, params);
     }
 
     /*******************************************************************************************************/
     /*****************************************工具函数********************************************************/
     /*******************************************************************************************************/
-    fn log_in_to_str(&self) -> String {
-        let mut login_json_str = String::from("");
-
-        //
-        // //解析并且组装 认证信息
-        // let lable = login_param.get("lable");
-        // if let Some(ref_string) = lable {
-        //     if *ref_string == "binance" {
-        //         //println!("----币安 暂不做登陆");
-        //     } else if *ref_string == "okx" {
-        //         let mut access_key: String = "".to_string();
-        //         let mut secret_key: String = "".to_string();
-        //         let mut passphrase: String = "".to_string();
-        //
-        //         for (key, value) in &login_param {
-        //             // //println!("Key: {}, Value: {}", key, value);
-        //             if key == "access_key" {
-        //                 access_key = value.parse().unwrap();
-        //             } else if key == "secret_key" {
-        //                 secret_key = value.parse().unwrap();
-        //             } else if key == "passphrase" {
-        //                 passphrase = value.parse().unwrap();
-        //             }
-        //         }
-        //         let timestamp = Utc::now().timestamp().to_string();
-        //
-        //         // 时间戳 + 请求类型+ 请求参数字符串
-        //         let message = format!("{}GET{}", timestamp, "/users/self/verify");
-        //         // //println!("---message:{:?}", message);
-        //         let hmac_key = ring::hmac::Key::new(hmac::HMAC_SHA256, secret_key.as_bytes());
-        //         let result = ring::hmac::sign(&hmac_key, &message.as_bytes());
-        //         let mut sign = base64::encode(result);
-        //
-        //         let login_json = json!({
-        //                       "op": "login",
-        //                         "args": [{
-        //                         "apiKey": access_key,
-        //                         "passphrase": passphrase,
-        //                         "timestamp": timestamp,
-        //                         "sign": sign  }]
-        //                 });
-        //
-        //         // //println!("---login_json:{0}", login_json.to_string());
-        //         // //println!("--登陆:{:?}", login_json);
-        //         login_json_str = login_json.to_string();
-        //     }
-        // } else {
-        //     //println!("Option is None(lable 为None)");
-        // }
-        login_json_str
-    }
 
     /*******************************************************************************************************/
     /*****************************************socket基本*****************************************************/
     /*******************************************************************************************************/
-    fn run<F, Fut>(&self, b_array: Vec<&str>, params: Vec<String>, parse_fn: F)
-        where
-            F: Fn(ResponseData) -> Fut + 'static + Send + Sync,
-            Fut: Future<Output=()> + Send + 'static,
+    fn run(&self, b_array: Vec<&str>, params: Vec<String>)
     {
         //订阅信息组装
         let subscription = json!({
@@ -179,7 +119,7 @@ impl BinanceUsdtSwapWs {
         "params":params,
                 "id": 1
         });
-        let parse_fn_arc = Arc::new(Mutex::new(parse_fn)); // Wrap the closure in an Arc<Mutex<_>>
+        // let parse_fn_arc = Arc::new(Mutex::new(parse_fn)); // Wrap the closure in an Arc<Mutex<_>>
         loop {
             //币安-登陆流程-rest请求获取k然后拿到 key 拼接地址
             if self.is_login { //暂时没看到有订阅的频道需要登陆 所以暂时不做
@@ -202,29 +142,24 @@ impl BinanceUsdtSwapWs {
                     accept_unmasked_frames: false,
                 });
                 let max_redirects = 5;
-                // let (mut socket, response) =
                 let mut proxy_ws =
                     connect_with_proxy(request_url.clone(), proxy_address, websocket_config, max_redirects)
                         .expect("Can't connect(无法连接)");
-                self.proxy_subscription(proxy_ws.0, &subscription, &parse_fn_arc);
+                self.proxy_subscription(proxy_ws.0, &subscription);
             } else {
-                // let (mut socket, response) =
                 let mut no_proxy_ws =
                     connect(request_url.clone())
                         .expect("Can't connect(无法连接)");
-                self.subscription(no_proxy_ws.0, &subscription, &parse_fn_arc);
+                self.subscription(no_proxy_ws.0, &subscription);
             }
         }
     }
 
     //代理
-    fn proxy_subscription<F, Fut>(&self, mut web_socket: WebSocket<ProxyAutoStream>,
-                                  subscription: &serde_json::Value,
-                                  parse_fn: &Arc<Mutex<F>>,
+    fn proxy_subscription(&self, mut web_socket: WebSocket<ProxyAutoStream>,
+                          subscription: &serde_json::Value,
     )
-        where
-            F: Fn(ResponseData) -> Fut + 'static + Send + Sync,
-            Fut: Future<Output=()> + Send + 'static,
+
 
     {
         /*****消息溜***/
@@ -247,15 +182,15 @@ impl BinanceUsdtSwapWs {
             match msg {
                 Ok(Message::Text(text)) => {
                     let req_data = Self::ok_text(text);
-                    // self.sender.send(req_data).unwrap();
-                    // writeln!(stdout, "Pong-响应--{:?}", req_data).unwrap();
-
-                    let parse_fn_clone = Arc::clone(parse_fn); // Clone the Arc for each iteration
-                    tokio::spawn(async move {
-                        let parse_fn_lock = parse_fn_clone.lock().await;
-                        parse_fn_lock(req_data).await;
-                    });
-                    tokio::spawn(async move {});
+                    self.sender.send(req_data).unwrap();
+                    // // writeln!(stdout, "Pong-响应--{:?}", req_data).unwrap();
+                    //
+                    // let parse_fn_clone = Arc::clone(parse_fn); // Clone the Arc for each iteration
+                    // tokio::spawn(async move {
+                    //     let parse_fn_lock = parse_fn_clone.lock().await;
+                    //     parse_fn_lock(req_data).await;
+                    // });
+                    // tokio::spawn(async move {});
                 }
                 Ok(Message::Ping(s)) => {
                     println!("Ping-响应--{:?}", String::from_utf8(s));
@@ -278,13 +213,10 @@ impl BinanceUsdtSwapWs {
         web_socket.close(None).unwrap();
     }
     //非代理
-    fn subscription<F, Fut>(&self, mut web_socket: WebSocket<AutoStream>,
-                            subscription: &serde_json::Value,
-                            parse_fn: &Arc<Mutex<F>>,
+    fn subscription(&self, mut web_socket: WebSocket<AutoStream>,
+                    subscription: &serde_json::Value,
     )
-        where
-            F: Fn(ResponseData) -> Fut + 'static + Send + Sync,
-            Fut: Future<Output=()> + Send + 'static,
+
     {
         /*****消息溜***/
         let mut stdout = io::stdout();
@@ -309,12 +241,13 @@ impl BinanceUsdtSwapWs {
             match msg {
                 Ok(Message::Text(text)) => {
                     let req_data = Self::ok_text(text);
-                    writeln!(stdout, "Pong-响应--{:?}", req_data).unwrap();
-                    let parse_fn_clone = Arc::clone(parse_fn); // Clone the Arc for each iteration
-                    tokio::spawn(async move {
-                        let parse_fn_lock = parse_fn_clone.lock().await;
-                        parse_fn_lock(req_data).await;
-                    });
+                    self.sender.send(req_data).unwrap();
+                    // writeln!(stdout, "Pong-响应--{:?}", req_data).unwrap();
+                    // let parse_fn_clone = Arc::clone(parse_fn); // Clone the Arc for each iteration
+                    // tokio::spawn(async move {
+                    //     let parse_fn_lock = parse_fn_clone.lock().await;
+                    //     parse_fn_lock(req_data).await;
+                    // });
                 }
                 Ok(Message::Ping(s)) => {
                     println!("Ping-响应--{:?}", String::from_utf8(s));

+ 66 - 55
exchanges/src/gate_swap_rest.rs

@@ -3,17 +3,19 @@ use reqwest::header::HeaderMap;
 use ring::{digest};
 use hex;
 use hmac::{Hmac, Mac, NewMac};
+use reqwest::Client;
 use crate::http_tool::RestTool;
 use crate::response_base::ResponseData;
 use sha2::Sha512;
 
 pub struct GateSwapRest {
+    base_url: String,
+    client: reqwest::Client,
     /*******参数*/
     //是否需要登陆
     is_login: bool,
     //登陆所需参数
     login_param: BTreeMap<String, String>,
-    rest: RestTool,
 }
 
 impl GateSwapRest {
@@ -32,9 +34,10 @@ impl GateSwapRest {
 
         /*****返回结构体*******/
         GateSwapRest {
+            base_url: base_url.to_string(),
+            client: Client::new(),
             is_login,
             login_param,
-            rest: RestTool::new(base_url.to_string()),
         }
     }
 
@@ -138,25 +141,8 @@ impl GateSwapRest {
         ).await;
         data
     }
-
-
-    // » contract	body	string	是	合约标识
-    // » size	body	integer(int64)	是	必选。交易数量,正数为买入,负数为卖出。平仓委托则设置为0。
-    // » iceberg	body	integer(int64)	否	冰山委托显示数量。0为完全不隐藏。注意,隐藏部分成交按照taker收取手续费。
-    // » price	body	string	否	委托价。价格为0并且tif为ioc,代表市价委托。
-    // » close	body	boolean	否	设置为 true 的时候执行平仓操作,并且size应设置为0
-    // » reduce_only	body	boolean	否	设置为 true 的时候,为只减仓委托
-    // » tif	body	string	否	Time in force 策略,市价单当前只支持 ioc 模式
-    // » text	body	string	否	订单自定义信息,用户可以用该字段设置自定义 ID,用户自定义字段必须满足以下条件:
-    // » auto_size	body	string	否	双仓模式下用于设置平仓的方向,close_long 平多头, close_short 平空头,需要同时设置 size 为 0
-    // » stp_act	body	string	否	Self-Trading Prevention Action,用户可以用该字段设置自定义限制自成交策略。
     //合约交易:市价价下单
-    pub async fn swap_bazaar_order(&self,
-                                   text: String,
-                                   origin_side: String,
-                                   settle: String,
-                                   contract: String,
-                                   size: i64) -> ResponseData {
+    pub async fn swap_bazaar_order(&self, text: String, origin_side: String, settle: String, contract: String, size: i64) -> ResponseData {
         let mut reduce_only = false;
         let mut param = serde_json::json!({
             "text":text,
@@ -191,13 +177,8 @@ impl GateSwapRest {
         let data = self.swap_order(settle, param).await;
         data
     }
-
-
     //合约交易下单
-    async fn swap_order(&self,
-                        settle: String,
-                        params: serde_json::Value,
-    ) -> ResponseData {
+    async fn swap_order(&self, settle: String, params: serde_json::Value) -> ResponseData {
         let data = self.request("POST".to_string(),
                                 "/api/v4".to_string(),
                                 format!("/futures/{}/orders", settle),
@@ -206,13 +187,8 @@ impl GateSwapRest {
         ).await;
         data
     }
-
-
     //设置持仓模式
-    pub async fn setting_dual_mode(&self,
-                                   settle: String,
-                                   dual_mode: bool,
-    ) -> ResponseData {
+    pub async fn setting_dual_mode(&self, settle: String, dual_mode: bool) -> ResponseData {
         let params = serde_json::json!({
                 "dual_mode":dual_mode,
              });
@@ -225,11 +201,7 @@ impl GateSwapRest {
         data
     }
     //更新双仓模式下的杠杆
-    pub async fn setting_dual_leverage(&self,
-                                       settle: String,
-                                       symbol: String,
-                                       leverage: String,
-    ) -> ResponseData {
+    pub async fn setting_dual_leverage(&self, settle: String, symbol: String, leverage: String) -> ResponseData {
         let params = serde_json::json!({
                 "leverage":leverage,
              });
@@ -242,13 +214,7 @@ impl GateSwapRest {
         data
     }
     //交易账户互转
-    pub async fn wallet_transfers(&self,
-                                  currency: String,
-                                  from: String,
-                                  to: String,
-                                  amount: String,
-                                  settle: String,
-    ) -> ResponseData {
+    pub async fn wallet_transfers(&self, currency: String, from: String, to: String, amount: String, settle: String) -> ResponseData {
         let params = serde_json::json!({
                 "currency":settle,
                 "from":from,
@@ -264,12 +230,8 @@ impl GateSwapRest {
         ).await;
         data
     }
-
     //撤销单个订单
-    pub async fn cancel_order(&self,
-                              settle: String,
-                              order_id: String,
-    ) -> ResponseData {
+    pub async fn cancel_order(&self, settle: String, order_id: String) -> ResponseData {
         let params = serde_json::json!({
              });
 
@@ -282,10 +244,7 @@ impl GateSwapRest {
         data
     }
     //批量取消状态为 open 的订单
-    pub async fn cancel_orders(&self,
-                               settle: String,
-                               contract: String,
-    ) -> ResponseData {
+    pub async fn cancel_orders(&self, settle: String, contract: String) -> ResponseData {
         let params = serde_json::json!({
             "contract":contract
              });
@@ -366,13 +325,13 @@ impl GateSwapRest {
         }
 
         // println!("headers:{:?}", headers);
-        let mut get_response = self.rest.http_toll(
+        let mut get_response = self.http_toll(
             format!("{}{}", prefix_url.clone(), request_url.clone()),
             requesst_type.to_string(),
             params,
             headers,
         ).await;
-        let mut req_data = RestTool::req_data_analysis(get_response);
+        let mut req_data = Self::req_data_analysis(get_response);
         req_data
     }
 
@@ -415,4 +374,56 @@ impl GateSwapRest {
         let sign = hex::encode(result);
         sign
     }
+
+
+    async fn http_toll(&self, request_path: String, request_type: String, params: String, headers: HeaderMap) -> Result<ResponseData, reqwest::Error> {
+        let req_data: ResponseData;
+        /****请求接口与 地址*/
+        let url = format!("{}{}", self.base_url.to_string(), request_path);
+        let request_type = request_type.clone().to_uppercase();
+        let addrs_url = format!("{}?{}", url.clone(), RestTool::parse_params_to_str(params.clone()));
+        let params_json: serde_json::Value = serde_json::from_str(&params).unwrap();
+        // println!("url:{}",url);
+        // println!("addrs_url:{}",url);
+        // println!("params_json:{}",params_json);
+        // println!("headers:{:?}",headers);
+
+        let req = match request_type.as_str() {
+            "GET" => self.client.get(addrs_url.clone()).headers(headers),
+            "POST" => self.client.post(addrs_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(format!("错误的请求类型:{}", request_type.clone()))), // 处理未知请求类型
+        };
+
+        let response = req.send().await?;
+        if response.status().is_success() {
+            // 读取响应的内容
+            let body = response.text().await?;
+            // println!("ok-----{}", body);
+            req_data = ResponseData::new("200".to_string(), "success".to_string(), body);
+        } else {
+            let body = response.text().await?;
+            // println!("error-----{}", body);
+            req_data = ResponseData::error(body.to_string())
+        }
+        Ok(req_data)
+    }
+
+    //req_data 解析
+    pub fn req_data_analysis(result: Result<ResponseData, reqwest::Error>) -> ResponseData {
+        match result {
+            Ok(req_data) => {
+                if req_data.code != "200" {
+                    req_data
+                } else {
+                    req_data
+                }
+            }
+            Err(err) => {
+                let error = ResponseData::error(format!("json 解析失败:{}", err));
+                error
+            }
+        }
+    }
 }

+ 426 - 0
exchanges/src/kucoin_swap_rest.rs

@@ -0,0 +1,426 @@
+use std::collections::BTreeMap;
+use std::ops::Index;
+use reqwest::header::HeaderMap;
+use ring::{digest};
+use hex;
+use hmac::{Hmac, Mac, NewMac};
+use reqwest::{Client};
+use sha2::Sha256;
+use crate::http_tool::RestTool;
+use crate::response_base::ResponseData;
+
+pub struct KucoinSwapRest {
+    base_url: String,
+    client: reqwest::Client,
+    /*******参数*/
+    //是否需要登陆
+    is_login: bool,
+    //登陆所需参数
+    login_param: BTreeMap<String, String>,
+
+}
+
+impl KucoinSwapRest {
+    /*******************************************************************************************************/
+    /*****************************************获取一个对象****************************************************/
+    /*******************************************************************************************************/
+    pub fn new(is_colo: bool, is_login: bool, login_param: BTreeMap<String, String>) -> KucoinSwapRest
+    {
+        let mut base_url = String::from("");
+        if is_colo {
+            println!("不支持colo高速线路");
+            base_url = "https://api-futures.kucoin.com".to_string()
+        } else {
+            base_url = "https://api-futures.kucoin.com".to_string()
+        }
+
+        /*****返回结构体*******/
+        KucoinSwapRest {
+            base_url: base_url.to_string(),
+            client: Client::new(),
+            is_login,
+            login_param,
+        }
+    }
+
+    /*******************************************************************************************************/
+    /*****************************************rest请求函数********************************************************/
+    /*******************************************************************************************************/
+    pub async fn get_server_time(&self) -> ResponseData {
+        let params = serde_json::json!({
+         });
+        let data = self.request("GET".to_string(),
+                                "/api/v1".to_string(),
+                                "/timestamp".to_string(),
+                                true,
+                                params.to_string(),
+        ).await;
+        data
+    }
+    //查询合约账户
+    pub async fn get_account(&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(&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(&self) -> ResponseData {
+        let mut 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(&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(&self, status: String, trade_type: String) -> ResponseData {
+        let params = serde_json::json!({
+            "status":status,
+            "tradeType":trade_type
+         });
+        let data = self.request("GET".to_string(),
+                                "/api/v1".to_string(),
+                                format!("/orders"),
+                                true,
+                                params.to_string(),
+        ).await;
+        data
+    }
+    //获取用户仓位列表
+    pub async fn get_positions(&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(&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(), client_id.parse().unwrap());
+        }
+
+        let data = self.request("GET".to_string(),
+                                "/api/v1".to_string(),
+                                url,
+                                true,
+                                params.to_string(),
+        ).await;
+        data
+    }
+    async fn swap_order(&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(&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(&self, order_id: String) -> ResponseData {
+    //     let mut params = serde_json::json!({   });
+    //     let data = self.request("DELETE".to_string(),
+    //                             "/api/v1".to_string(),
+    //                             format!("/orders/{}", order_id),
+    //                             true,
+    //                             params.to_string(),
+    //     ).await;
+    //     data
+    // }
+
+    /*******************************************************************************************************/
+    /*****************************************工具函数********************************************************/
+    /*******************************************************************************************************/
+    //调用请求
+    async fn request(&self,
+                     method: String,
+                     prefix_url: String,
+                     request_url: String,
+                     is_login: bool,
+                     params: String) -> ResponseData
+    {
+        println!("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 mut sing = "".to_string();
+        let mut passphrase = "".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("登陆参数错误!".to_string());
+                return e;
+            } else {//需要登陆-且登陆参数齐全
+                println!("param:{}", params);
+                println!("body:{}", body);
+                //组装sing
+                sing = Self::sign(secret_key.clone(),
+                                  method.clone(),
+                                  prefix_url.clone(),
+                                  request_url.clone(),
+                                  params.clone(),
+                                  body.clone(),
+                                  timestamp.clone(),
+                );
+                println!("sing:{}", sing);
+                passphrase = Self::passphrase(secret_key, pass_key);
+                println!("passphrase:{}", passphrase);
+                //组装header
+                headers.extend(Self::headers(sing, timestamp, passphrase, access_key));
+            }
+        }
+
+
+        // println!("headers:{:?}", headers);
+        let mut get_response = self.http_toll(
+            format!("{}{}", prefix_url.clone(), request_url.clone()),
+            method.to_string(),
+            params,
+            headers,
+        ).await;
+
+        let mut req_data = Self::req_data_analysis(get_response);
+        req_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);
+        println!("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()
+        // };
+        // println!("hashed_payload:{}", hashed_payload);
+
+        let mut message = format!("{}{}{}",
+                                  timestamp,
+                                  method,
+                                  url
+        );
+        if method == "GET" || method == "DELETE" {
+            message = format!("{}?{}", message, params_str);
+        } else if method == "POST" || method == "PUT" {
+            message = format!("{}{}", message, body_data);
+        }
+
+        println!("**********", );
+        println!("组装数据:{}", message);
+        println!("**********", );
+
+        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(&self, request_path: String, request_type: String, params: String, headers: HeaderMap) -> Result<ResponseData, reqwest::Error> {
+        let req_data: ResponseData;
+        /****请求接口与 地址*/
+        let url = format!("{}{}", self.base_url.to_string(), request_path);
+        let request_type = request_type.clone().to_uppercase();
+        let addrs_url = format!("{}?{}", url.clone(), RestTool::parse_params_to_str(params.clone()));
+        println!("url:{}", url);
+        println!("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(format!("错误的请求类型:{}", request_type.clone()))), // 处理未知请求类型
+        };
+
+        let response = req.send().await?;
+        if response.status().is_success() {
+            // 读取响应的内容
+            let body = response.text().await?;
+            println!("ok-----{}", body);
+            req_data = ResponseData::new("200".to_string(), "success".to_string(), body);
+        } else {
+            let body = response.text().await?;
+            println!("error-----{}", body);
+            req_data = ResponseData::error(body.to_string())
+        }
+        Ok(req_data)
+    }
+
+
+    //req_data 解析
+    pub fn req_data_analysis(result: Result<ResponseData, reqwest::Error>) -> ResponseData {
+        match result {
+            Ok(req_data) => {
+                if req_data.code != "200" {
+                    req_data
+                } else {
+                    let body: String = req_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(code.to_string(), msg.to_string(), "".parse().unwrap());
+                        error
+                    } else {
+                        let data = serde_json::to_string(&json_value["data"]).unwrap();
+                        let success = ResponseData::new("200".to_string(), "success".to_string(), data.parse().unwrap());
+                        success
+                    }
+                }
+            }
+            Err(err) => {
+                let error = ResponseData::error(format!("json 解析失败:{}", err));
+                error
+            }
+        }
+    }
+}

+ 1 - 0
exchanges/src/lib.rs

@@ -10,5 +10,6 @@ pub mod gate_spot_ws;
 pub mod gate_swap_ws;
 pub mod gate_swap_rest;
 pub mod socket_tool;
+pub mod kucoin_swap_rest;
 
 

+ 17 - 1
global/src/public_params.rs

@@ -14,4 +14,20 @@ pub const MARKET_DELAY_LIMIT: i64 = 30*1000;                                // 
 pub const GRID: i64 = 1;                                                    // 策略资金分成多少份
 pub const STOP_LOSS: Decimal = dec!(0.02);                                  // 风控止损比例,0.02代表2%,是原文的STOPLOSS
 pub const GAMMA: Decimal = dec!(0.999);                                     // gamma默认值
-pub const EFF_RANGE: Decimal = dec!(0.001);                                 // 每1权重需要多少价格距离,0.001代表0.1%,每0.1%代表1权重
+pub const EFF_RANGE: Decimal = dec!(0.001);                                 // 每1权重需要多少价格距离,0.001代表0.1%,每0.1%代表1权重
+
+// 各交易所限频规则汇总
+pub const BASIC_LIMIT:i64 = 100;
+pub const GATE_SPOT_LIMIT:i64 = 10;
+pub const GATE_USDT_SWAP_LIMIT:i64 = 100;
+pub const KUCOIN_SPOT_LIMIT:i64 = 15;
+pub const KUCOIN_USDT_SWAP_LIMIT:i64 = 10;
+pub const BINANCE_USDT_SWAP_LIMIT:i64 = 5;
+pub const BINANCE_SPOT_LIMIT:i64 = 2;
+pub const COINEX_SPOT_LIMIT:i64 = 20;
+pub const COINEX_USDT_SWAP_LIMIT:i64 = 20;
+pub const OKEX_USDT_SWAP_LIMIT:i64 = 30;
+pub const BITGET_USDT_SWAP_LIMIT:i64 = 10;
+pub const BYBIT_USDT_SWAP_LIMIT:i64 = 1;
+pub const MEXC_SPOT_LIMIT:i64 = 333;
+pub const RATIO:i64 = 4;

+ 1 - 0
standard/Cargo.toml

@@ -6,6 +6,7 @@ edition = "2021"
 # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
 
 [dependencies]
+global = { path = "../global" }
 exchanges = { path = "../exchanges" }
 tokio = { version = "1.31.0", features = ["full"] }
 async-trait = "0.1.73"

+ 0 - 0
standard/src/binance_lib.rs → standard/src/binance_handle.rs


+ 7 - 44
standard/src/binance_spot.rs

@@ -2,10 +2,9 @@ use std::collections::BTreeMap;
 use std::io::{Error};
 use std::result::Result;
 use async_trait::async_trait;
-use rust_decimal_macros::dec;
-use crate::{Platform, ExchangeEnum, Account, Depth, MarketOrder, binance_lib, Position, PositionModeEnum, Ticker, Market, Order};
+use rust_decimal::Decimal;
+use crate::{Platform, ExchangeEnum, Account, binance_handle, Position, PositionModeEnum, Ticker, Market, Order};
 use exchanges::binance_spot_rest::BinanceSpotRest;
-use exchanges::binance_spot_ws::BinanceSpotWs;
 use exchanges::response_base::ResponseData;
 
 #[allow(dead_code)]
@@ -15,7 +14,6 @@ pub struct BinanceSpot {
     is_login: bool,
     params: BTreeMap<String, String>,
     request: BinanceSpotRest,
-    wss: BinanceSpotWs,
 }
 
 impl BinanceSpot {
@@ -26,7 +24,6 @@ impl BinanceSpot {
             is_login,
             params: params.clone(),
             request: BinanceSpotRest::new(is_colo, is_login, params.clone()),
-            wss: BinanceSpotWs::new(is_colo, is_login, params.clone()),
         }
     }
 }
@@ -57,7 +54,7 @@ impl Platform for BinanceSpot {
             data: "[]".to_string(),
             channel: "".to_string(),
         };
-        binance_lib::handle_account_info(res_data, symbol)
+        binance_handle::handle_account_info(res_data, symbol)
     }
     // 获取仓位信息
     async fn get_position(&self, _symbol: &str, _mode: PositionModeEnum) -> Result<Position, Error> {
@@ -80,53 +77,19 @@ impl Platform for BinanceSpot {
         todo!()
     }
 
-    // 获取深度信息
-    fn get_depth(&self) -> Depth {
-        let depth_asks = vec![MarketOrder { price: dec!(0.0), amount: dec!(0.0) }];
-        let depth_bids = vec![MarketOrder { price: dec!(0.0), amount: dec!(0.0) }];
-        Depth {
-            time: 0,
-            asks: depth_asks,
-            bids: depth_bids,
-        }
-    }
-
-    fn take_order(&self) {
+    async fn set_dual_mode(&self, _coin: &str, _is_dual_mode: bool) -> Result<String, Error> {
         todo!()
     }
 
-    fn get_order_list(&self) {
+    async fn set_dual_leverage(&self, _symbol: &str, _leverage: &str) -> Result<String, Error> {
         todo!()
     }
 
-    fn cancel_order(&self) {
+    async fn wallet_transfers(&self, _coin: &str, _from: &str, _to: &str, _amount: Decimal) -> Result<String, Error> {
         todo!()
     }
 
-    fn subscribe_account(&self) -> Account {
-        Account {
-            balance: dec!(0.1),
-            available_balance: dec!(0.0),
-            frozen_balance: dec!(0.0),
-            stocks: dec!(0.0),
-            available_stocks: dec!(0.0),
-            frozen_stocks: dec!(0.0),
-        }
-    }
-
-    fn subscribe_depth(&self, _symbol: &str) {
-        let depth_asks = vec![MarketOrder { price: dec!(0.0), amount: dec!(0.0) }];
-        let depth_bids = vec![MarketOrder { price: dec!(0.0), amount: dec!(0.0) }];
-        Depth {
-            time: 0,
-            asks: depth_asks,
-            bids: depth_bids,
-        };
-    }
-
-    fn subscribe_special_depth(&self, symbol: &str) {
+    async fn take_order(&self, _custom_id: &str, _origin_side: &str, _coin: &str, _symbol: &str, _amount: Decimal) -> Result<Order, Error> {
         todo!()
     }
-
-    fn subscribe_kline(&self) {}
 }

+ 112 - 100
standard/src/binance_swap.rs

@@ -1,14 +1,12 @@
-use std::cmp::Ordering;
 use std::collections::BTreeMap;
 use std::io::{Error, ErrorKind};
 use std::result::Result;
 use async_trait::async_trait;
+use rust_decimal::Decimal;
 use rust_decimal_macros::dec;
 use serde_json::json;
-use crate::{Platform, ExchangeEnum, Account, Depth, MarketOrder, Position, PositionModeEnum, utils, Ticker, Market, Order};
+use crate::{Platform, ExchangeEnum, Account, Position, PositionModeEnum, Ticker, Market, Order};
 use exchanges::binance_usdt_swap_rest::BinanceUsdtSwapRest;
-use exchanges::binance_usdt_swap_ws::BinanceUsdtSwapWs;
-use exchanges::response_base::ResponseData;
 
 #[allow(dead_code)]
 pub struct BinanceSwap {
@@ -17,7 +15,6 @@ pub struct BinanceSwap {
     is_login: bool,
     params: BTreeMap<String, String>,
     request: BinanceUsdtSwapRest,
-    wss: BinanceUsdtSwapWs,
 }
 
 impl BinanceSwap {
@@ -28,7 +25,6 @@ impl BinanceSwap {
             is_login,
             params: params.clone(),
             request: BinanceUsdtSwapRest::new(is_colo, is_login, params.clone()),
-            wss: BinanceUsdtSwapWs::new(is_colo, is_login, params.clone()),
         }
     }
 }
@@ -98,113 +94,129 @@ impl Platform for BinanceSwap {
         todo!()
     }
 
-    // 获取深度信息
-    fn get_depth(&self) -> Depth {
-        let depth_asks = vec![MarketOrder { price: dec!(1.0), amount: dec!(0.0) }];
-        let depth_bids = vec![MarketOrder { price: dec!(0.0), amount: dec!(0.0) }];
-
-        Depth {
-            time: 0,
-            asks: depth_asks,
-            bids: depth_bids,
-        }
+    async fn set_dual_mode(&self, _coin: &str, _is_dual_mode: bool) -> Result<String, Error> {
+        todo!()
     }
 
-
-    fn take_order(&self) {
+    async fn set_dual_leverage(&self, _symbol: &str, _leverage: &str) -> Result<String, Error> {
         todo!()
     }
 
-    fn get_order_list(&self) {
+    async fn wallet_transfers(&self, _coin: &str, _from: &str, _to: &str, _amount: Decimal) -> Result<String, Error> {
         todo!()
     }
 
-    fn cancel_order(&self) {
+    async fn take_order(&self, _custom_id: &str, _origin_side: &str, _coin: &str, _symbol: &str, _amount: Decimal) -> Result<Order, Error> {
         todo!()
     }
 
-    fn subscribe_account(&self) -> Account {
-        Account {
-            balance: dec!(1.1),
-            available_balance: dec!(0.0),
-            frozen_balance: dec!(0.0),
-            stocks: dec!(0.0),
-            available_stocks: dec!(0.0),
-            frozen_stocks: dec!(0.0),
-        }
-    }
     // 订阅深度信息
-    fn subscribe_depth(&self, symbol: &str) {
-        ;
-        let symbol_format = &utils::format_symbol(symbol, "");
-        let get_res_data = move |res_data: ResponseData| {
-            async move {
-                if res_data.code == "200" && res_data.channel == "depth" {
-                    let res_data_str = res_data.data;
-                    let res_data_json: serde_json::Value = serde_json::from_str(&*res_data_str).unwrap();
-                    let mut depth_asks: Vec<MarketOrder> = parse_depth_items(&res_data_json["asks"]);
-                    let mut depth_bids: Vec<MarketOrder> = parse_depth_items(&res_data_json["bids"]);
-                    depth_asks.sort_by(|a, b| a.price.partial_cmp(&b.price).unwrap_or(Ordering::Equal));
-                    depth_bids.sort_by(|a, b| b.price.partial_cmp(&a.price).unwrap_or(Ordering::Equal));
-                    let result = Depth {
-                        time: 123456,
-                        asks: depth_asks,
-                        bids: depth_bids,
-                    };
-                    println!("subscribe_depth: {:?}", result);
-                }
-            }
-        };
-        self.wss.custom_subscribe(vec![symbol_format], 0, 0, get_res_data)
-    }
+    // fn subscribe_depth(&self, symbol: &str) {
+    //     let symbol_format = &utils::format_symbol(symbol, "");
+    //     let get_res_data = move |res_data: ResponseData| {
+    //         async move {
+    //             if res_data.code == "200" && res_data.channel == "depth" {
+    //                 let res_data_str = res_data.data;
+    //                 let res_data_json: serde_json::Value = serde_json::from_str(&*res_data_str).unwrap();
+    //                 let mut depth_asks: Vec<MarketOrder> = parse_depth_items(&res_data_json["asks"]);
+    //                 let mut depth_bids: Vec<MarketOrder> = parse_depth_items(&res_data_json["bids"]);
+    //                 depth_asks.sort_by(|a, b| a.price.partial_cmp(&b.price).unwrap_or(Ordering::Equal));
+    //                 depth_bids.sort_by(|a, b| b.price.partial_cmp(&a.price).unwrap_or(Ordering::Equal));
+    //                 let result = Depth {
+    //                     time: 123456,
+    //                     asks: depth_asks,
+    //                     bids: depth_bids,
+    //                 };
+    //                 println!("subscribe_depth: {:?}", result);
+    //             }
+    //         }
+    //     };
+    //     self.wss.custom_subscribe(vec![symbol_format], 0, 0, get_res_data)
+    // }
 
     // 订阅深度信息
-    fn subscribe_special_depth(&self, symbol: &str) {
-        let symbol_format = &utils::format_symbol(symbol, "");
-        let get_res_data = move |res_data: ResponseData| {
-            async move {
-                if res_data.code == "200" && res_data.channel == "depth" {
-                    let res_data_str = res_data.data;
-                    let res_data_json: serde_json::Value = serde_json::from_str(&*res_data_str).unwrap();
-                    let mut depth_asks: Vec<MarketOrder> = parse_depth_items(&res_data_json["asks"]);
-                    let mut depth_bids: Vec<MarketOrder> = parse_depth_items(&res_data_json["bids"]);
-                    depth_asks.sort_by(|a, b| a.price.partial_cmp(&b.price).unwrap_or(Ordering::Equal));
-                    depth_bids.sort_by(|a, b| b.price.partial_cmp(&a.price).unwrap_or(Ordering::Equal));
-                    let mp = (depth_asks[0].price + depth_bids[0].price) * dec!(0.5);
-                    // let step = round(mp * utils::EFF_RANGE / utils::LEVEL, self.decimal);
-                    // TODO  引入有问题
-
-
-                    let result = Depth {
-                        time: 123456,
-                        asks: depth_asks,
-                        bids: depth_bids,
-                    };
-
-                }
-            }
-        };
-        self.wss.custom_subscribe(vec![symbol_format], 0, 0, get_res_data)
-    }
-
-    fn subscribe_kline(&self) {
-        let get_res_data = move |res_data: ResponseData| {
-            async move {
-                println!("?????{:?}", res_data);
-            }
-        };
-
-        self.wss.kline(vec![&"BTCUSDT"], get_res_data);
-    }
+    // fn subscribe_special_depth(&self, symbol: &str) {
+    //     let symbol_format = &utils::format_symbol(symbol, "");
+    //     let get_res_data = move |res_data: ResponseData| {
+    //         async move {
+    //             if res_data.code == "200" && res_data.channel == "depth" {
+    //                 let res_data_str = res_data.data;
+    //                 let res_data_json: serde_json::Value = serde_json::from_str(&*res_data_str).unwrap();
+    //                 let mut depth_asks: Vec<MarketOrder> = parse_depth_items(&res_data_json["asks"]);
+    //                 let mut depth_bids: Vec<MarketOrder> = parse_depth_items(&res_data_json["bids"]);
+    //                 depth_asks.sort_by(|a, b| a.price.partial_cmp(&b.price).unwrap_or(Ordering::Equal));
+    //                 depth_bids.sort_by(|a, b| b.price.partial_cmp(&a.price).unwrap_or(Ordering::Equal));
+    //                 let mp = (depth_asks[0].price + depth_bids[0].price) * dec!(0.5);
+    //                 let step = (public_params::EFF_RANGE * mp / Decimal::from_usize(public_params::LEVEL).unwrap()).round();
+    //                 let mut ap = Vec::new();
+    //                 let mut bp = Vec::new();
+    //                 let mut av: Vec<Decimal> = Vec::new();
+    //                 let mut bv: Vec<Decimal> = Vec::new();
+    //                 for i in 0..public_params::LEVEL {
+    //                     let price = (depth_asks[0].price + step * Decimal::from_f64(i as f64).unwrap()).round();
+    //                     ap.push(price);
+    //                 }
+    //                 for i in 0..public_params::LEVEL {
+    //                     let price = (depth_asks[0].price - step * Decimal::from_f64(i as f64).unwrap()).round();
+    //                     bp.push(price);
+    //                 }
+    //                 let mut ap_price_tag = depth_asks[0].price + step;
+    //                 let mut ap_index = 0;
+    //                 for item in depth_asks.iter() {
+    //                     let price = item.price;
+    //                     let amount = item.amount;
+    //                     println!("{} {}", price, amount);
+    //                     if price > ap_price_tag {
+    //                         av[ap_index] += amount;
+    //                     } else {
+    //                         ap_price_tag += step;
+    //                         ap_index += 1;
+    //                         if ap_index == public_params::LEVEL {
+    //                             break;
+    //                         }
+    //                         av[ap_index] += amount
+    //                     }
+    //                 }
+    //
+    //                 let mut bp_price_tag = depth_bids[0].price - step;
+    //                 let mut bp_index = 0;
+    //                 for item in depth_bids.iter() {
+    //                     let price = item.price;
+    //                     let amount = item.amount;
+    //                     if price > bp_price_tag {
+    //                         bv[bp_index] += amount;
+    //                     } else {
+    //                         bp_price_tag -= step;
+    //                         bp_index += 1;
+    //                         if bp_index == public_params::LEVEL {
+    //                             break;
+    //                         }
+    //                         bv[bp_index] += amount
+    //                     }
+    //                 }
+    //
+    //                 let aa: Vec<&Decimal> = bp.iter().clone().chain(bv.iter().clone()).chain(ap.iter().clone()).chain(av.iter().clone()).collect::<Vec<_>>();
+    //                 println!("{:?}", aa);
+    //                 let result = Depth {
+    //                     time: 123456,
+    //                     asks: depth_asks,
+    //                     bids: depth_bids,
+    //                 };
+    //                 println!("subscribe_special_depth: {:?}", result)
+    //             }
+    //         }
+    //     };
+    //     self.wss.custom_subscribe(vec![symbol_format], 0, 0, get_res_data)
+    // }
 }
 
-fn parse_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: value[0].as_str().unwrap_or("0").parse().unwrap_or(dec!(0)),
-            amount: value[1].as_str().unwrap_or("0").parse().unwrap_or(dec!(0)),
-        })
-    }
-    return depth_items;
-}
+// fn parse_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: value[0].as_str().unwrap_or("0").parse().unwrap_or(dec!(0)),
+//             amount: value[1].as_str().unwrap_or("0").parse().unwrap_or(dec!(0)),
+//         })
+//     }
+//     return depth_items;
+// }

+ 0 - 0
standard/src/gate_lib.rs → standard/src/gate_handle.rs


+ 7 - 47
standard/src/gate_spot.rs

@@ -1,10 +1,9 @@
 use std::collections::BTreeMap;
 use std::io::{Error};
 use async_trait::async_trait;
-use rust_decimal_macros::dec;
-use crate::{Platform, ExchangeEnum, Account, Depth, MarketOrder, gate_lib, Position, PositionModeEnum, Ticker, Market, Order};
+use rust_decimal::Decimal;
+use crate::{Platform, ExchangeEnum, Account, gate_handle, Position, PositionModeEnum, Ticker, Market, Order};
 use exchanges::gate_spot_rest::GateSpotRest;
-use exchanges::gate_spot_ws::GateSpotWs;
 use exchanges::response_base::ResponseData;
 
 #[allow(dead_code)]
@@ -14,7 +13,6 @@ pub struct GateSpot {
     is_login: bool,
     params: BTreeMap<String, String>,
     request: GateSpotRest,
-    wss: GateSpotWs,
 }
 
 impl GateSpot {
@@ -25,7 +23,6 @@ impl GateSpot {
             is_login,
             params: params.clone(),
             request: GateSpotRest::new(is_colo, is_login, params.clone()),
-            wss: GateSpotWs::new(is_colo, is_login, params.clone()),
         }
     }
 }
@@ -58,7 +55,7 @@ impl Platform for GateSpot {
             data: "[]".to_string(),
             channel: "".to_string(),
         };
-        gate_lib::handle_account_info(res_data, symbol)
+        gate_handle::handle_account_info(res_data, symbol)
     }
     // 获取仓位信息
     async fn get_position(&self, _symbol: &str, _mode: PositionModeEnum) -> Result<Position, Error> {
@@ -81,56 +78,19 @@ impl Platform for GateSpot {
         todo!()
     }
 
-    // 获取深度信息
-    fn get_depth(&self) -> Depth {
-        let depth_asks = vec![MarketOrder { price: dec!(2.0), amount: dec!(0.0) }];
-        let depth_bids = vec![MarketOrder { price: dec!(0.0), amount: dec!(0.0) }];
-        Depth {
-            time: 0,
-            asks: depth_asks,
-            bids: depth_bids,
-        }
-    }
-
-
-    fn take_order(&self) {
-        todo!()
-    }
-
-    fn get_order_list(&self) {
+    async fn set_dual_mode(&self, _coin: &str, _is_dual_mode: bool) -> Result<String, Error> {
         todo!()
     }
 
-    fn cancel_order(&self) {
+    async fn set_dual_leverage(&self, _symbol: &str, _leverage: &str) -> Result<String, Error> {
         todo!()
     }
 
-    fn subscribe_account(&self) -> Account {
-        Account {
-            balance: dec!(2.1),
-            available_balance: dec!(0.0),
-            frozen_balance: dec!(0.0),
-            stocks: dec!(0.0),
-            available_stocks: dec!(0.0),
-            frozen_stocks: dec!(0.0),
-        }
-    }
-
-    fn subscribe_depth(&self, _symbol: &str) {
-        let depth_asks = vec![MarketOrder { price: dec!(2.0), amount: dec!(0.0) }];
-        let depth_bids = vec![MarketOrder { price: dec!(0.0), amount: dec!(0.0) }];
-        Depth {
-            time: 0,
-            asks: depth_asks,
-            bids: depth_bids,
-        };
-    }
-
-    fn subscribe_special_depth(&self, symbol: &str) {
+    async fn wallet_transfers(&self, _coin: &str, _from: &str, _to: &str, _amount: Decimal) -> Result<String, Error> {
         todo!()
     }
 
-    fn subscribe_kline(&self) {
+    async fn take_order(&self, _custom_id: &str, _origin_side: &str, _coin: &str, _symbol: &str, _amount: Decimal) -> Result<Order, Error> {
         todo!()
     }
 }

+ 48 - 53
standard/src/gate_swap.rs

@@ -1,14 +1,12 @@
 use std::collections::BTreeMap;
 use std::io::{Error, ErrorKind};
-use std::sync::Arc;
 use async_trait::async_trait;
 use rust_decimal::Decimal;
-use rust_decimal::prelude::FromPrimitive;
+use rust_decimal::prelude::{FromPrimitive, ToPrimitive};
 use rust_decimal_macros::dec;
 use serde_json::{json};
-use crate::{Platform, ExchangeEnum, Account, Depth, MarketOrder, Position, PositionModeEnum, Ticker, Market, Order};
+use crate::{Platform, ExchangeEnum, Account, Position, PositionModeEnum, Ticker, Market, Order, utils};
 use exchanges::gate_swap_rest::GateSwapRest;
-use exchanges::gate_swap_ws::GateSwapWs;
 use crate::PositionModeEnum::{Both, Long};
 
 #[allow(dead_code)]
@@ -18,7 +16,6 @@ pub struct GateSwap {
     is_login: bool,
     params: BTreeMap<String, String>,
     request: GateSwapRest,
-    wss: GateSwapWs,
 }
 
 impl GateSwap {
@@ -29,7 +26,6 @@ impl GateSwap {
             is_login,
             params: params.clone(),
             request: GateSwapRest::new(is_colo, is_login, params.clone()),
-            wss: GateSwapWs::new(is_colo, is_login, params.clone()),
         }
     }
 }
@@ -174,7 +170,7 @@ impl Platform for GateSwap {
             Err(Error::new(ErrorKind::Other, res_data.message))
         }
     }
-
+    // 获取订单列表
     async fn get_orders_list(&self, symbol: &str, status: &str) -> Result<Vec<Order>, Error> {
         let symbol_array: Vec<&str> = symbol.split("_").collect();
         let res_data = self.request.get_orders(symbol_array[1].to_string().to_lowercase(), status.to_string()).await;
@@ -189,65 +185,64 @@ impl Platform for GateSwap {
             Err(Error::new(ErrorKind::Other, res_data.message))
         }
     }
-
-    fn get_depth(&self) -> Depth {
-        let depth_asks = vec![MarketOrder { price: dec!(3.0), amount: dec!(0.0) }];
-        let depth_bids = vec![MarketOrder { price: dec!(0.0), amount: dec!(0.0) }];
-        Depth {
-            time: 0,
-            asks: depth_asks,
-            bids: depth_bids,
+    // 设置持仓模式
+    async fn set_dual_mode(&self, coin: &str, is_dual_mode: bool) -> Result<String, Error> {
+        let coin_format = coin.to_string().to_lowercase();
+        let res_data = self.request.setting_dual_mode(coin_format, is_dual_mode).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.message))
         }
     }
-
-    fn take_order(&self) {
-        todo!()
-    }
-
-    fn get_order_list(&self) {
-        todo!()
-    }
-
-    fn cancel_order(&self) {
-        todo!()
-    }
-
-    fn subscribe_account(&self) -> Account {
-        Account {
-            balance: dec!(3.1),
-            available_balance: dec!(0.0),
-            frozen_balance: dec!(0.0),
-            stocks: dec!(0.0),
-            available_stocks: dec!(0.0),
-            frozen_stocks: dec!(0.0),
+    // 更新双持仓模式下杠杆
+    async fn set_dual_leverage(&self, symbol: &str, leverage: &str) -> Result<String, Error> {
+        let symbol_array: Vec<&str> = symbol.split("_").collect();
+        let res_data = self.request.setting_dual_leverage(symbol_array[1].to_string().to_lowercase(), symbol.to_string(), leverage.to_string()).await;
+        if res_data.code == "200" {
+            let res_data_str = &res_data.data;
+            let result = res_data_str.clone();
+            Ok(result)
+        } else {
+            Err(Error::new(ErrorKind::Other, res_data.message))
         }
     }
-
-    fn subscribe_depth(&self, _symbol: &str) {
-        let depth_asks = vec![MarketOrder { price: dec!(3.0), amount: dec!(0.0) }];
-        let depth_bids = vec![MarketOrder { price: dec!(0.0), amount: dec!(0.0) }];
-        Depth {
-            time: 0,
-            asks: depth_asks,
-            bids: depth_bids,
-        };
+    // 交易账户互转
+    async fn wallet_transfers(&self, coin: &str, from: &str, to: &str, amount: Decimal) -> Result<String, Error> {
+        let coin_format = coin.to_string().to_lowercase();
+        let res_data = self.request.wallet_transfers(coin_format.clone(), from.to_string(), to.to_string(), amount.to_string(), coin_format.clone()).await;
+        if res_data.code == "200" {
+            let res_data_str = &res_data.data;
+            let result = res_data_str.clone();
+            Ok(result)
+        } else {
+            Err(Error::new(ErrorKind::Other, res_data.message))
+        }
     }
-
-    fn subscribe_special_depth(&self, symbol: &str) {
-        todo!()
+    // 下单接口
+    async fn take_order(&self, custom_id: &str, origin_side: &str, coin: &str, symbol: &str, amount: Decimal) -> Result<Order, Error>{
+        let symbol_format = utils::format_symbol(symbol.clone(), "_");
+        let coin_format = coin.to_string().to_lowercase();
+        let res_data = self.request.swap_bazaar_order(custom_id.to_string(), origin_side.to_string(), coin_format.clone(), symbol_format, amount.to_i64().unwrap()).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 = parse_order_item(&res_data_json);
+            Ok(result)
+        } else {
+            Err(Error::new(ErrorKind::Other, res_data.message))
+        }
     }
 
-    fn subscribe_kline(&self) {
-        todo!()
-    }
 }
-
 fn parse_order_item(order: &serde_json::Value) -> Order {
     Order {
         id: order["id"].to_string(),
         custom_id: order["text"].as_str().unwrap_or("0").to_string(),
         price: order["price"].as_str().unwrap_or("0").parse().unwrap_or(dec!(0)),
-        amount: order["size"].as_i64().unwrap(),
+        amount: Decimal::from(order["size"].as_i64().unwrap()),
         deal_amount: Default::default(),
         avg_price: Default::default(),
         status: "".to_string(),

+ 12 - 19
standard/src/lib.rs

@@ -1,5 +1,5 @@
 use std::collections::BTreeMap;
-use std::io::Error;
+use std::io::{Error};
 use async_trait::async_trait;
 use rust_decimal::Decimal;
 use crate::exchange::ExchangeEnum;
@@ -9,11 +9,11 @@ pub mod exchange;
 // 引入binance模块
 mod binance_swap;
 mod binance_spot;
-mod binance_lib;
+mod binance_handle;
 // 引入gate模块
 mod gate_swap;
 mod gate_spot;
-mod gate_lib;
+mod gate_handle;
 // 引入工具模块
 pub mod utils;
 
@@ -83,7 +83,7 @@ pub struct Record {
 /// - `id(String)`: 交易单唯一标识
 /// - `custom_id(String)`: 自定义Id
 /// - `price(Decimal)`: 下单价格
-/// - `amount(i64)`: 下单数量
+/// - `amount(Decimal)`: 下单数量
 /// - `deal_amount(Decimal)`: 成交数量
 /// - `avg_price(Decimal)`: 成交均价
 /// - `status(String)`: 订单状态
@@ -93,7 +93,7 @@ pub struct Order {
     pub id: String,
     pub custom_id: String,
     pub price: Decimal,
-    pub amount: i64,
+    pub amount: Decimal,
     pub deal_amount: Decimal,
     pub avg_price: Decimal,
     pub status: String,
@@ -272,20 +272,13 @@ pub trait Platform {
     async fn get_order_detail(&self, symbol: &str, id: &str) -> Result<Order, Error>;
     // 获取订单列表
     async fn get_orders_list(&self, symbol: &str, status: &str) -> Result<Vec<Order>, Error>;
-    // 获取深度信息
-    fn get_depth(&self) -> Depth;
+    // 设置持仓模式
+    async fn set_dual_mode(&self, coin: &str, is_dual_mode: bool) -> Result<String, Error>;
+    // 更新双持仓模式下杠杆
+    async fn set_dual_leverage(&self, symbol: &str, leverage: &str) -> Result<String, Error>;
+    // 交易账户互转
+    async fn wallet_transfers(&self, coin: &str, from: &str, to: &str, amount: Decimal) -> Result<String, Error>;
     // 下单接口
-    fn take_order(&self);
-    // 获取订单列表
-    fn get_order_list(&self);
-    // 取消订单
-    fn cancel_order(&self);
-    // 订阅账号信息
-    fn subscribe_account(&self) -> Account;
-    // 订阅深度信息
-    fn subscribe_depth(&self, symbol: &str);
-    // 订阅深度信息
-    fn subscribe_special_depth(&self, symbol: &str);
-    fn subscribe_kline(&self);
+    async fn take_order(&self, custom_id: &str, origin_side: &str, coin: &str, symbol: &str, amount: Decimal) -> Result<Order, Error>;
 }
 

+ 6 - 0
standard/tests/libs_test.rs

@@ -134,3 +134,9 @@ async fn test_gate_swap_get_orders_list() {
     let gate_swap_exchange: Box<dyn Platform> = test_new_exchange(ExchangeEnum::GateSwap);
     println!("gate_swap orders_list:{:?}", gate_swap_exchange.get_orders_list("CYBER_USDT", "finished").await);
 }
+// 设置持仓模式
+#[tokio::test]
+async fn test_set_dual_mode() {
+    let gate_swap_exchange: Box<dyn Platform> = test_new_exchange(ExchangeEnum::GateSwap);
+    println!("gate_swap orders_list:{:?}", gate_swap_exchange.set_dual_mode("usdt", true).await);
+}

+ 1 - 1
strategy/src/params.rs

@@ -45,7 +45,7 @@ pub struct Params {
     // 分批建仓功能 小资金建议1 大资金建议3 默认 1
     pub grid: i8,
     // 允许的每秒下单次数
-    pub place_order_limit: i8,
+    pub place_order_limit: i64,
     // 是否启用colocation技术, 1开启,0关闭 默认0
     pub colo: i8
 }

+ 223 - 0
strategy/src/strategy.rs

@@ -0,0 +1,223 @@
+use std::cmp::min;
+use std::collections::HashMap;
+use std::ops::{Div, Mul};
+use chrono::Utc;
+use rust_decimal::Decimal;
+use rust_decimal::prelude::{FromPrimitive, ToPrimitive};
+use rust_decimal_macros::dec;
+use crate::model::Position;
+use crate::params::Params;
+use crate::utils;
+
+struct Strategy {
+    // pub interval: Decimal,                                       // 原文没有使用过这个参数
+
+    // 各类时间戳和时延,我们都改成了毫秒级
+    pub _print_time: i64,                                           // 上次打印时间
+    pub _print_interval: i64,                                       // 打印时延
+    pub _start_time: i64,                                           // 开始时间
+    pub local_time: i64,                                            // 本地时间
+    pub local_start_time: i64,                                      // 本地开始时间
+    pub post_open_time: i64,                                        // 上次提交订单的时间戳
+    pub post_open_interval: i64,                                    // 提交订单时延
+    pub _check_local_orders_time: i64,                              // 上次查单时间
+    pub _check_local_orders_interval: i64,                          // 查单间距,原文是秒级,这里改成毫秒级
+    pub in_cancel: HashMap<String, String>,                         // TODO 撤单队列,类型待补充
+    pub cancel_wait_interval: i64,                                  // 取消等待时延
+    pub in_check: HashMap<String, String>,                          // TODO 检查队列,类型待补充
+    pub check_wait_interval: i64,                                   // 检测时延
+
+    pub request_limit_check_time: i64,                              // 上次检查订单的时间
+    pub request_limit_check_interval: i64,                          // 原文是秒级,这里改成毫秒级
+    pub request_count: i64,                                         // 记录请求次数,原文的request_num
+    pub order_count: i64,                                           // 记录下单次数,原文的request_order_num
+
+    pub limit_requests_num: i64,                                    // 单位(时延)时间内请求次数上限
+    pub limit_order_requests_num: i64,                              // 单位(时延)时间内下单次数上限
+    pub _req_num_per_window: i64,                                   // 单位(时延)时间内请求上限窗口
+
+    pub place_order_limit: i64,                                     // 参数层面传进来的下单数量限制
+    pub params: Params,                                             //
+    pub exchange: String,                                           //
+    pub broker_id: String,                                          //
+    pub trade_name: String,                                         //
+    pub ref_exchange_length: usize,                                 //
+    pub ref_name: Vec<String>,                                      //
+    pub maker_mode: String,                                         //
+    pub local_orders: HashMap<String, String>,                      // TODO 本地订单,类型待补充
+    pub pos: Position,                                              //
+    pub long_hold_value: Decimal,                                   //
+    pub short_hold_value: Decimal,                                  //
+    pub equity: Decimal,                                            //
+    pub coin: Decimal,                                              //
+    pub cash: Decimal,                                              //
+    pub start_equity: Decimal,                                      //
+    pub start_coin: Decimal,                                        //
+    pub start_cash: Decimal,                                        //
+    pub max_equity: Decimal,                                        //
+    pub local_profit: Decimal,                                      //
+    pub total_amount: Decimal,                                      //
+    pub is_ready: bool,                                             // 程序是否已经准备好,ready
+    pub _is_print: bool,                                            //
+    pub _min_amount_value: Decimal,                                 //
+    pub _max_amount_value: Decimal,                                 //
+
+    pub mp_ema: Decimal,                                            // 原文的mp_ewma
+    pub mp: Decimal,                                                //
+    pub bp: Decimal,                                                //
+    pub ap: Decimal,                                                //
+    pub ref_price: Decimal,                                         //
+    pub ref_bp: Decimal,                                            //
+    pub ref_ap: Decimal,                                            //
+    pub step_size: Decimal,                                         // 原文的stepSize
+    pub tick_size: Decimal,                                         // 原文的tickSize
+
+    pub max_pos: Decimal,                                           // 原文的maxPos
+    pub profit: Decimal,                                            //
+    pub daily_return: Decimal,                                      //
+
+    pub adjust_lever_rate: Decimal,                                 // 原文的adjust_leverrate
+    pub lever_rate: Decimal,                                        // 原文的leverrate
+
+    pub long_pos_bias: Decimal,                                     //
+    pub short_pos_bias: Decimal,                                    //
+    pub long_hold_rate: Decimal,                                    //
+    pub short_hold_rate: Decimal,                                   //
+
+    pub open_dist: Vec<Decimal>,                                    // 开仓相关价格
+    pub close_dist: Vec<Decimal>,                                   // 平仓相关价格
+
+    pub trade_close_dist: Decimal,                                  //
+    pub trade_open_dist: Decimal,                                   //
+
+    pub ref_index: usize,                                           //
+    pub predict: Decimal,                                           //
+    pub predict_alpha: Decimal,                                     //
+    pub post_side: i64,                                             // 交易方向
+    pub trade_vol_24h: Decimal,                                     //
+    pub grid: i8,                                                   // 网格数量
+}
+
+impl Strategy {
+    pub fn new(params: Params, is_print: bool) -> Self {
+        if params.ref_exchange.len() != params.ref_pair.len() {
+            panic!("参考盘口数不等于参考品种数,退出,请检查配置!")
+        }
+
+        // strategy的初始化,里面已经有一些参数初始化了
+        let mut strategy = Self {
+            _print_time: 0,
+            _start_time: 0,
+            local_time: 0,
+            local_start_time: 0,
+            request_count: 0,
+            order_count: 0,
+            _print_interval: 5 * 1000,
+            in_cancel: Default::default(),
+            cancel_wait_interval: (0.2 * 1000f64).to_i64().unwrap(),
+            in_check: Default::default(),
+            check_wait_interval: 10 * 1000,
+            _check_local_orders_time: 0,
+            _check_local_orders_interval: 0,
+            place_order_limit: 0,
+            request_limit_check_time: 0,
+            request_limit_check_interval: 0,
+            limit_requests_num: 0,
+            limit_order_requests_num: 0,
+            _req_num_per_window: 0,
+            post_open_time: 0,
+            post_open_interval: 0,
+            params: params.clone(),
+            exchange: params.exchange.clone(),
+            broker_id: params.broker_id.clone(),
+            trade_name: "".to_string(),
+            ref_exchange_length: params.ref_exchange.len(),
+            ref_name: vec![],
+            maker_mode: "free".to_string(),
+            local_orders: Default::default(),
+            pos: Position {
+                long_pos: Default::default(),
+                short_pos: Default::default(),
+                long_avg: Default::default(),
+                short_avg: Default::default(),
+            },
+            long_hold_value: Default::default(),
+            short_hold_value: Default::default(),
+            equity: Default::default(),
+            coin: Default::default(),
+            cash: Default::default(),
+            start_equity: Default::default(),
+            start_coin: Default::default(),
+            start_cash: Default::default(),
+            max_equity: Default::default(),
+            local_profit: Default::default(),
+            total_amount: Default::default(),
+            is_ready: false,
+            _is_print: is_print,
+            _min_amount_value: dec!(30.0),
+            _max_amount_value: dec!(10000.0),
+            mp_ema: Default::default(),
+            mp: Default::default(),
+            bp: Default::default(),
+            ap: Default::default(),
+            ref_price: Default::default(),
+            ref_bp: Default::default(),
+            ref_ap: Default::default(),
+            step_size: dec!(1e-10),
+            tick_size: dec!(1e-10),
+            max_pos: Default::default(),
+            profit: Default::default(),
+            daily_return: Default::default(),
+            adjust_lever_rate: dec!(1),
+            lever_rate: Default::default(),
+            long_pos_bias: Default::default(),
+            short_pos_bias: Default::default(),
+            long_hold_rate: Default::default(),
+            short_hold_rate: Default::default(),
+            open_dist: vec![],
+            close_dist: vec![],
+            trade_close_dist: dec!(0.00001),
+            trade_open_dist: dec!(0.01),
+            ref_index: 0,
+            predict: Default::default(),
+            predict_alpha: Default::default(),
+            post_side: 0,
+            trade_vol_24h: Default::default(),
+            grid: params.grid,
+        };
+
+        // 交易名字
+        strategy.trade_name = format!("{}@{}", params.exchange.clone(), params.pair.clone());
+        // 参考交易所的trade_name
+        for index in 0..strategy.ref_exchange_length {
+            strategy.ref_name.push(format!("{}@{}", params.ref_exchange[index], params.ref_pair[index]));
+        }
+        // 杠杆比例处理
+        if strategy.exchange.contains("spot") {
+            strategy.lever_rate = min(params.lever_rate, dec!(1));
+        }
+        // 各类时间戳
+        let now = Utc::now();
+        strategy.local_time = now.timestamp_millis();
+        strategy.local_start_time = now.timestamp_millis();
+        strategy._print_time = now.timestamp_millis();
+        strategy._start_time = now.timestamp_millis();
+        // 检查订单的时间戳
+        strategy._check_local_orders_time = now.timestamp_millis();
+        strategy._check_local_orders_interval = 10 * 1000;
+        // 下单的相关限制处理
+        strategy.place_order_limit = params.place_order_limit;
+        strategy.request_limit_check_time = now.timestamp_millis();
+        strategy.request_limit_check_interval = 10 * 1000;
+        // 求得正常请求数量和下单请求数量(interval时间内)
+        let request_limit_check_interval_per_second = strategy.request_limit_check_interval / 1000;
+        strategy.limit_requests_num = utils::get_limit_requests_num_per_second(params.exchange.clone(), params.place_order_limit) * (request_limit_check_interval_per_second);
+        strategy.limit_order_requests_num = utils::get_limit_order_requests_num_per_second(params.exchange.clone(), params.place_order_limit) * (request_limit_check_interval_per_second);
+        // 开仓下单间隔 均匀下单机会
+        strategy.post_open_time = now.timestamp_millis();
+        let post_open_interval_per_second = dec!(1).div(Decimal::from_i64(utils::get_limit_order_requests_num_per_second(params.exchange.clone(), 0)).unwrap());
+        strategy.post_open_interval = dec!(1000).mul(post_open_interval_per_second).to_i64().unwrap();
+
+        return strategy;
+    }
+}

+ 60 - 6
strategy/src/utils.rs

@@ -1,18 +1,15 @@
 use std::ops::{Div, Mul};
-use std::time::{SystemTime, UNIX_EPOCH};
+use chrono::Utc;
 use rand::Rng;
 use rust_decimal::Decimal;
+use global::public_params;
 
 // 生成订单的id,可以根据交易所名字来
 pub fn generate_client_id(mut exchange_name_some: Option<&str>) -> String {
     // 交易所名字获取
     let exchange_name = exchange_name_some.unwrap_or("");
     // 随机时间戳,作为订单id的前列
-    let start = SystemTime::now();
-    let since_the_epoch = start
-        .duration_since(UNIX_EPOCH)
-        .expect("Time went backwards");
-    let in_ms = since_the_epoch.as_millis(); // 或者你可以使用 as_secs 获取秒
+    let in_ms = Utc::now().timestamp_millis();
     let time_str = in_ms.to_string();
     let time_slice = &time_str[4..10];
     // 0-1000的随机数
@@ -45,8 +42,55 @@ pub fn fix_price(amount: Decimal, tick_size: Decimal) -> Decimal {
     amount.div(tick_size).round().mul(tick_size)
 }
 
+// 每秒请求频率
+pub fn get_limit_requests_num_per_second(exchange: String, limit: i64) -> i64 {
+    if limit != 0 {
+        return limit * public_params::RATIO;
+    } else if exchange.eq("kucoin_spot") {
+        return public_params::KUCOIN_SPOT_LIMIT * public_params::RATIO;
+    } else if exchange.eq("kucoin_usdt_swap") {
+        return public_params::KUCOIN_USDT_SWAP_LIMIT * public_params::RATIO;
+    } else if exchange.eq("binance_usdt_swap") {
+        return public_params::BINANCE_USDT_SWAP_LIMIT * public_params::RATIO;
+    } else if exchange.eq("binance_spot") {
+        return public_params::BINANCE_SPOT_LIMIT * public_params::RATIO;
+    } else if exchange.eq("gate_spot") {
+        return public_params::GATE_SPOT_LIMIT * public_params::RATIO;
+    } else if exchange.eq("gate_usdt_swap") {
+        return public_params::GATE_USDT_SWAP_LIMIT * public_params::RATIO;
+    } else {
+        panic!("限频规则(ratio)未找到,请检查配置!")
+    }
+
+    return 0
+}
+
+// 每秒下单请求频率
+pub fn get_limit_order_requests_num_per_second(exchange: String, limit: i64) -> i64 {
+    if limit != 0 {
+        return limit
+    } else if exchange.eq("kucoin_spot") {
+        return public_params::KUCOIN_SPOT_LIMIT
+    } else if exchange.eq("kucoin_usdt_swap") {
+        return public_params::KUCOIN_USDT_SWAP_LIMIT
+    } else if exchange.eq("binance_usdt_swap") {
+        return public_params::BINANCE_USDT_SWAP_LIMIT
+    } else if exchange.eq("binance_spot") {
+        return public_params::BINANCE_SPOT_LIMIT
+    } else if exchange.eq("gate_spot") {
+        return public_params::GATE_SPOT_LIMIT
+    } else if exchange.eq("gate_usdt_swap") {
+        return public_params::GATE_USDT_SWAP_LIMIT
+    } else {
+        panic!("限频规则(limit)未找到,请检查配置!")
+    }
+
+    return 0
+}
+
 #[cfg(test)]
 mod tests {
+    use chrono::Utc;
     use rust_decimal_macros::dec;
     use crate::utils::{clip, fix_amount, fix_price, generate_client_id};
 
@@ -85,4 +129,14 @@ mod tests {
         println!("{}", fix_price(dec!(1.2), dec!(0.5)));
         println!("{}", fix_price(dec!(4999.99), dec!(0.5)));
     }
+
+    #[test]
+    fn utc_timestamp_test() {
+        let now = Utc::now();
+
+        println!("timestamp: {}", now.timestamp());
+        println!("timestamp_millis: {}", now.timestamp_millis());
+        println!("timestamp_micros: {}", now.timestamp_micros());
+        println!("timestamp_nanos: {}", now.timestamp_nanos());
+    }
 }

+ 9 - 2
strategy/tests/decimal_test.rs

@@ -1,7 +1,6 @@
-use tokio;
-
 #[cfg(test)]
 mod tests {
+    use std::cmp::{max, min};
     use std::time::{Instant, Duration};
     use rust_decimal::prelude::ToPrimitive;
     use rust_decimal_macros::dec;
@@ -33,4 +32,12 @@ mod tests {
         println!("{} == {} is {}", a, b, a == b);
         println!("{}.eq({}) is {}", a, b, a.eq(&b));
     }
+
+    #[test]
+    fn test_decimal_min_and_max() {
+        let a = dec!(0.123234213);
+        let b = dec!(0.823004213);
+        println!("max({}, {})={}", a, b, max(a, b));
+        println!("min({}, {})={}", a, b, min(a, b));
+    }
 }