Explorar o código

ok 接口提交

875428575@qq.com %!s(int64=2) %!d(string=hai) anos
pai
achega
fe09a18187
Modificáronse 3 ficheiros con 250 adicións e 43 borrados
  1. 36 1
      Cargo.lock
  2. 5 5
      Cargo.toml
  3. 209 37
      src/exchange_libs.rs

+ 36 - 1
Cargo.lock

@@ -64,9 +64,12 @@ checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711"
 name = "as-market-binance-okx-spot"
 name = "as-market-binance-okx-spot"
 version = "0.1.0"
 version = "0.1.0"
 dependencies = [
 dependencies = [
+ "base64 0.13.1",
  "chrono",
  "chrono",
+ "hex",
  "ndarray",
  "ndarray",
  "reqwest",
  "reqwest",
+ "ring",
  "rust_decimal",
  "rust_decimal",
  "rust_decimal_macros",
  "rust_decimal_macros",
  "serde",
  "serde",
@@ -75,7 +78,6 @@ dependencies = [
  "time 0.2.27",
  "time 0.2.27",
  "tokio",
  "tokio",
  "tungstenite",
  "tungstenite",
- "url",
 ]
 ]
 
 
 [[package]]
 [[package]]
@@ -492,6 +494,12 @@ version = "0.3.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "443144c8cdadd93ebf52ddb4056d257f5b52c04d3c804e657d19eb73fc33668b"
 checksum = "443144c8cdadd93ebf52ddb4056d257f5b52c04d3c804e657d19eb73fc33668b"
 
 
+[[package]]
+name = "hex"
+version = "0.4.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70"
+
 [[package]]
 [[package]]
 name = "http"
 name = "http"
 version = "0.2.9"
 version = "0.2.9"
@@ -1049,6 +1057,21 @@ dependencies = [
  "winreg",
  "winreg",
 ]
 ]
 
 
+[[package]]
+name = "ring"
+version = "0.17.0-alpha.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4575a179070909595bea5f999d67934737c2e0757a1eb9839af555917817b257"
+dependencies = [
+ "cc",
+ "libc",
+ "once_cell",
+ "spin",
+ "untrusted",
+ "web-sys",
+ "winapi",
+]
+
 [[package]]
 [[package]]
 name = "rkyv"
 name = "rkyv"
 version = "0.7.42"
 version = "0.7.42"
@@ -1326,6 +1349,12 @@ dependencies = [
  "winapi",
  "winapi",
 ]
 ]
 
 
+[[package]]
+name = "spin"
+version = "0.5.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d"
+
 [[package]]
 [[package]]
 name = "standback"
 name = "standback"
 version = "0.2.17"
 version = "0.2.17"
@@ -1652,6 +1681,12 @@ dependencies = [
  "tinyvec",
  "tinyvec",
 ]
 ]
 
 
+[[package]]
+name = "untrusted"
+version = "0.7.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a"
+
 [[package]]
 [[package]]
 name = "url"
 name = "url"
 version = "2.4.0"
 version = "2.4.0"

+ 5 - 5
Cargo.toml

@@ -8,7 +8,7 @@ edition = "2021"
 [dependencies]
 [dependencies]
 rust_decimal = "1.31.0"
 rust_decimal = "1.31.0"
 rust_decimal_macros = "1.31.0"
 rust_decimal_macros = "1.31.0"
-reqwest = "0.11"
+reqwest = { version = "0.11.14", features = ["json"] }
 chrono = "0.4.26"
 chrono = "0.4.26"
 serde = "1.0.183"
 serde = "1.0.183"
 serde_derive = "1.0.183"
 serde_derive = "1.0.183"
@@ -18,11 +18,11 @@ time = "0.2"
 tokio = { version = "1.31.0", features = ["full"] }
 tokio = { version = "1.31.0", features = ["full"] }
 
 
 tungstenite = { git = "https://github.com/PrivateRookie/tungstenite-rs.git", rev = "1d9289276518e5ab7e5194126d40b441d8938375" }
 tungstenite = { git = "https://github.com/PrivateRookie/tungstenite-rs.git", rev = "1d9289276518e5ab7e5194126d40b441d8938375" }
-url = "2.4.0"
+#url = "2.4.0"
 base64 = "0.13"
 base64 = "0.13"
-rust-crypto = "0.2.36"
+#rust-crypto = "0.2.36"
 
 
-hmac = "0.8.0"
-sha2 = "0.9"
+#hmac = "0.8.0"
+#sha2 = "0.9"
 hex = "0.4"
 hex = "0.4"
 ring = "0.17.0-alpha.11"
 ring = "0.17.0-alpha.11"

+ 209 - 37
src/exchange_libs.rs

@@ -22,33 +22,6 @@ pub async fn binan_k(symbol: &str, interval: &str, limit: &i32) -> String {
     }
     }
 }
 }
 
 
-fn okx_create_header(api_key: &str, passphrase: &str, sign: &str, timestamp: &str) -> HeaderMap {
-    // 处理请求头 headers
-
-    let mut header_map = HeaderMap::new();
-
-    header_map.insert(
-        "OK-ACCESS-KEY",
-        HeaderValue::from_str(&api_key).unwrap(),
-    );
-    header_map.insert(
-        "OK-ACCESS-SIGN",
-        HeaderValue::from_str(&sign).unwrap());
-    header_map.insert(
-        "OK-ACCESS-TIMESTAMP",
-        HeaderValue::from_str(&timestamp).unwrap(),
-    );
-    header_map.insert(
-        "OK-ACCESS-PASSPHRASE",
-        HeaderValue::from_str(&passphrase).unwrap(),
-    );
-    header_map.insert(
-        "CONTENT_TYPE",
-        HeaderValue::from_static("application/json; charset=UTF-8"),
-    );
-    header_map
-}
-
 
 
 /*普通 Get 请求*/
 /*普通 Get 请求*/
 pub async fn get(url: String) -> Result<(String), reqwest::Error> {
 pub async fn get(url: String) -> Result<(String), reqwest::Error> {
@@ -108,6 +81,7 @@ pub fn is_proxy() -> bool {
     }
     }
 }
 }
 
 
+
 pub struct OkxExc {
 pub struct OkxExc {
     base_url: String,
     base_url: String,
     access_keu: String,
     access_keu: String,
@@ -120,12 +94,121 @@ impl OkxExc {
         OkxExc { base_url: "https://www.okx.com".to_string(), access_keu, secret_key, passphrase }
         OkxExc { base_url: "https://www.okx.com".to_string(), access_keu, secret_key, passphrase }
     }
     }
 
 
+    //获取订单信息
+    pub async fn okx_get_order(&self, inst_id: &str, ord_id: &str) -> ReqData {
+        let mut btree_map: BTreeMap<&str, &str> = BTreeMap::new();
+        btree_map.insert("instId", inst_id);//产品Id
+        btree_map.insert("ordId", ord_id);//顶顶那
+
+        let result = self.get_v(
+            "/api/v5/trade/order".to_string(),
+            btree_map,
+        ).await;
+
+        match result {
+            Ok(reqData) => {
+                if (reqData.code != "0") {
+                    reqData
+                } else {
+                    let body: String = reqData.data;
+                    let json_value: serde_json::Value = serde_json::from_str(&body).unwrap();
+                    let code = json_value["code"].to_string();
+                    let data = json_value["data"].to_string();
+                    let msg = json_value["msg"].to_string();
+
+                    let success = ReqData::new(code.parse().unwrap(),
+                                               msg.parse().unwrap(),
+                                               data.parse().unwrap());
+                    success
+                }
+            }
+            Err(err) => {
+                let error = ReqData::error(format!("json 解析失败:{}", err));
+                error
+            }
+        }
+    }
+
+    //撤单接口
+    pub async fn okx_revocation_order(&self, inst_id: &str, ord_id: &str) -> ReqData {
+        let mut btree_map: BTreeMap<&str, &str> = BTreeMap::new();
+        btree_map.insert("instId", inst_id);//产品Id
+        btree_map.insert("ordId", ord_id);//顶顶那
+
+        let result = self.post_v(
+            "/api/v5/trade/cancel-order".to_string(),
+            btree_map,
+        ).await;
+
+        match result {
+            Ok(reqData) => {
+                if (reqData.code != "0") {
+                    reqData
+                } else {
+                    let body: String = reqData.data;
+                    let json_value: serde_json::Value = serde_json::from_str(&body).unwrap();
+                    let code = json_value["code"].to_string();
+                    let data = json_value["data"].to_string();
+                    let msg = json_value["msg"].to_string();
+
+                    let success = ReqData::new(code.parse().unwrap(),
+                                               msg.parse().unwrap(),
+                                               data.parse().unwrap());
+                    success
+                }
+            }
+            Err(err) => {
+                let error = ReqData::error(format!("json 解析失败:{}", err));
+                error
+            }
+        }
+    }
+
+    //下单接口
+    pub async fn okx_order(&self, inst_id: &str, td_mode: &str, side: &str, ord_type: &str, px: &str, sz: &str) -> ReqData {
+        let mut btree_map: BTreeMap<&str, &str> = BTreeMap::new();
+        btree_map.insert("instId", inst_id);//产品Id
+        btree_map.insert("tdMode", td_mode);//交易模式
+        btree_map.insert("side", side);//订单方向
+        btree_map.insert("ordType", ord_type);//订单类
+        btree_map.insert("px", px);//委托价格
+        btree_map.insert("sz", sz);//委托数量
+
+        let result = self.post_v(
+            "/api/v5/trade/order".to_string(),
+            btree_map,
+        ).await;
+
+        match result {
+            Ok(reqData) => {
+                if (reqData.code != "0") {
+                    reqData
+                } else {
+                    let body: String = reqData.data;
+                    let json_value: serde_json::Value = serde_json::from_str(&body).unwrap();
+                    let code = json_value["code"].to_string();
+                    let data = json_value["data"].to_string();
+                    let msg = json_value["msg"].to_string();
+
+                    let success = ReqData::new(code.parse().unwrap(),
+                                               msg.parse().unwrap(),
+                                               data.parse().unwrap());
+                    success
+                }
+            }
+            Err(err) => {
+                let error = ReqData::error(format!("json 解析失败:{}", err));
+                error
+            }
+        }
+    }
+
     //账户信息
     //账户信息
     pub async fn okx_acc(&self, ccy: &str) -> ReqData {
     pub async fn okx_acc(&self, ccy: &str) -> ReqData {
         let mut btree_map: BTreeMap<&str, &str> = BTreeMap::new();
         let mut btree_map: BTreeMap<&str, &str> = BTreeMap::new();
-        btree_map.insert("ccy", &ccy);
+        btree_map.insert("ccy", ccy);
 
 
-        let result = self.getV(
+        let result = self.get_v(
             "/api/v5/account/balance".to_string(),
             "/api/v5/account/balance".to_string(),
             btree_map,
             btree_map,
         ).await;
         ).await;
@@ -157,8 +240,8 @@ impl OkxExc {
     }
     }
 
 
     //带认证-get
     //带认证-get
-    async fn getV(&self, request_path: String, params: BTreeMap<&str, &str>) -> Result<(ReqData), reqwest::Error> {
-        let mut reqData: ReqData;
+    async fn get_v(&self, request_path: String, params: BTreeMap<&str, &str>) -> Result<(ReqData), reqwest::Error> {
+        let mut req_data: ReqData;
 
 
         /*请求接口与 地址*/
         /*请求接口与 地址*/
         let base_url = self.base_url.to_string();
         let base_url = self.base_url.to_string();
@@ -180,7 +263,7 @@ impl OkxExc {
         let mut sign = self.okx_sign(secret_key, message);
         let mut sign = self.okx_sign(secret_key, message);
 
 
         //添加请求头
         //添加请求头
-        let mut headers = okx_create_header(&access_keu, &passphrase, &sign, &timestamp);
+        let mut headers = self.okx_create_header(&access_keu, &passphrase, &sign, &timestamp);
 
 
         let client = reqwest::Client::new();
         let client = reqwest::Client::new();
         let req = client.get(base_url + &get_url_params)
         let req = client.get(base_url + &get_url_params)
@@ -191,18 +274,77 @@ impl OkxExc {
         let response = req.send()
         let response = req.send()
             .await?;
             .await?;
         // 检查响应是否成功
         // 检查响应是否成功
+        println!("---状态:{:?},{}", response.status(), response.status().is_success());
         if response.status().is_success() {
         if response.status().is_success() {
             // 读取响应的内容
             // 读取响应的内容
             let body = response.text().await?;
             let body = response.text().await?;
             println!("okx_acc-Response body:\n{}", body);
             println!("okx_acc-Response body:\n{}", body);
-            reqData = ReqData::new("0".to_string(), "success".to_string(), body);
+            req_data = ReqData::new("0".to_string(), "success".to_string(), body);
+        } else {
+            let body = response.text().await?;
+            println!("okx_acc-Request failed with status: {}", body);
+            req_data = ReqData::error(body.to_string())
+        }
+        Ok((req_data))
+    }
+
+    //带认证-post
+    async fn post_v(&self, request_path: String, params: BTreeMap<&str, &str>) -> Result<(ReqData), reqwest::Error> {
+        let mut req_data: ReqData;
+
+        /*请求接口与 地址*/
+        let base_url = self.base_url.to_string();
+
+        /*账号 密钥 密码*/
+        let access_keu = self.access_keu.to_string();
+        let secret_key = self.secret_key.to_string();
+        let passphrase = self.passphrase.to_string();
+
+
+        /*签名生成*/
+        let timestamp = get_timestamp();
+        let params_str = serde_json::to_string(&params).unwrap();
+
+        // let params_json = serde_json::to_value(params_str.clone()).unwrap();
+
+        println!("---params:{:?}", params);
+        println!("---params-json_str:{ }", params_str.clone());
+        // println!("---params-json:{:?}", params_json);
+
+        // 时间戳 + 请求类型+ 请求参数字符串
+        let message = format!("{}POST{}{}", timestamp, request_path, &params_str);
+        println!("---message:{:?}", message);
+        let mut sign = self.okx_sign(secret_key, message);
+
+        //添加请求头
+        let mut headers = self.okx_create_header(&access_keu, &passphrase, &sign, &timestamp);
+
+        let client = reqwest::Client::new();
+        let url = format!("{}{}", base_url, request_path);
+        let req = client
+            .post(url)
+            .headers(headers)
+            .json(&params)
+            ;
+
+        let response = req.send()
+            .await?;
+        // 检查响应是否成功
+        println!("---状态:{:?},{}", response.status(), response.status().is_success());
+        if response.status().is_success() {
+            // 读取响应的内容
+            let body = response.text().await?;
+            println!("okx_order-Response body:\n{}", body);
+            req_data = ReqData::new("0".to_string(), "success".to_string(), body);
         } else {
         } else {
-            println!("okx_acc-Request failed with status: {}", response.status());
-            reqData = ReqData::error(response.status().to_string())
+            let body = response.text().await?;
+            println!("okx_order-Request failed with status: {}", body);
+            req_data = ReqData::error(body.to_string())
         }
         }
-        Ok((reqData))
+        Ok((req_data))
     }
     }
 
 
+
     //okx 签名生成
     //okx 签名生成
     fn okx_sign(&self, secret_key: String, message: String) -> String {
     fn okx_sign(&self, secret_key: String, message: String) -> String {
         // 做签名
         // 做签名
@@ -210,6 +352,37 @@ impl OkxExc {
         let result = ring::hmac::sign(&hmac_key, &message.as_bytes());
         let result = ring::hmac::sign(&hmac_key, &message.as_bytes());
         base64::encode(result)
         base64::encode(result)
     }
     }
+
+    fn okx_create_header(&self, api_key: &str, passphrase: &str, sign: &str, timestamp: &str) -> HeaderMap {
+        // 处理请求头 headers
+
+        let mut header_map = HeaderMap::new();
+
+        header_map.insert(
+            "OK-ACCESS-KEY",
+            HeaderValue::from_str(&api_key).unwrap(),
+        );
+        header_map.insert(
+            "OK-ACCESS-SIGN",
+            HeaderValue::from_str(&sign).unwrap());
+        header_map.insert(
+            "OK-ACCESS-TIMESTAMP",
+            HeaderValue::from_str(&timestamp).unwrap(),
+        );
+        header_map.insert(
+            "OK-ACCESS-PASSPHRASE",
+            HeaderValue::from_str(&passphrase).unwrap(),
+        );
+        header_map.insert(
+            "CONTENT-TYPE",
+            HeaderValue::from_static("application/json; charset=UTF-8"),
+        );
+        // header_map.insert(
+        //     reqwest::header::CONTENT_TYPE,
+        //     HeaderValue::from_static("application/json; charset=UTF-8"),
+        // );
+        header_map
+    }
 }
 }
 
 
 
 
@@ -231,4 +404,3 @@ impl ReqData {
     }
     }
 }
 }
 
 
-