use std::collections::BTreeMap; use std::str::FromStr; use reqwest::header::HeaderMap; use hex; use reqwest::Client; use rust_decimal::Decimal; use rust_decimal::prelude::FromPrimitive; use rust_decimal_macros::dec; use crate::http_tool::RestTool; use crate::response_base::ResponseData; use tracing::{error, info, trace}; use ring::hmac; use serde_json::{json, Value}; #[derive(Clone)] pub struct BinanceSwapRest { label: String, base_url: String, client: reqwest::Client, /*******参数*/ //登录所需参数 login_param: BTreeMap, delays: Vec, max_delay: i64, avg_delay: Decimal, } impl BinanceSwapRest { /*******************************************************************************************************/ /*****************************************获取一个对象****************************************************/ /*******************************************************************************************************/ pub fn new(is_colo: bool, login_param: BTreeMap) -> BinanceSwapRest { return BinanceSwapRest::new_label("default-BinanceSwapRest".to_string(), is_colo, login_param); } pub fn new_label(label: String, is_colo: bool, login_param: BTreeMap) -> BinanceSwapRest { let base_url = if is_colo { "https://fapi.binance.com".to_string() } else { "https://fapi.binance.com".to_string() }; if is_colo { info!("开启高速(未配置,走普通:{})通道",base_url); } else { info!("走普通通道:{}",base_url); } /*****返回结构体*******/ BinanceSwapRest { label, base_url: base_url.to_string(), client: Client::new(), login_param, delays: vec![], max_delay: 0, avg_delay: dec!(0.0), } } /*******************************************************************************************************/ /*****************************************rest请求函数********************************************************/ /*******************************************************************************************************/ //获取系统时间 pub async fn get_server_time(&mut self) -> ResponseData { let params = serde_json::json!({ }); let data = self.request("GET".to_string(), "".to_string(), format!("/fapi/v1/time"), true, params.to_string(), ).await; data } //获取交易规则和交易对 pub async fn get_exchange_info(&mut self) -> ResponseData { let params = serde_json::json!({ }); let data = self.request("GET".to_string(), "".to_string(), format!("/fapi/v1/exchangeInfo"), true, params.to_string(), ).await; data } //账户信息 pub async fn get_account(&mut self) -> ResponseData { let params = serde_json::json!({ "recvWindow":"2000" }); let data = self.request("GET".to_string(), "".to_string(), format!("/fapi/v2/balance"), true, params.to_string(), ).await; data } //查询订单 pub async fn get_order(&mut self, symbol: String, order_id: i64, orig_client_order_id: String) -> ResponseData { let mut params = serde_json::json!({ "symbol":symbol, "recvWindow":"2000" }); if order_id > 0 { params["orderId"] = json!(order_id); } if orig_client_order_id.len() > 0 { params["origClientOrderId"] = json!(orig_client_order_id); } let data = self.request("GET".to_string(), "".to_string(), format!("/fapi/v1/order"), true, params.to_string(), ).await; data } //查看当前全部挂单 pub async fn get_open_orders(&mut self, symbol: String) -> ResponseData { let params = serde_json::json!({ "symbol":symbol, "recvWindow":"2000" }); let data = self.request("GET".to_string(), "".to_string(), format!("/fapi/v1/openOrders"), true, params.to_string(), ).await; data } //查询所有订单(包括历史订单) pub async fn get_all_orders(&mut self, symbol: String, limit: u64, start_time: i64, end_time: i64) -> ResponseData { let params = serde_json::json!({ "symbol":symbol, "limit":limit, "startTime":start_time, "endTime":end_time, "recvWindow":"2000" }); let data = self.request("GET".to_string(), "".to_string(), format!("/fapi/v1/allOrders"), true, params.to_string(), ).await; data } //当前最优挂单 pub async fn get_book_ticker(&mut self, symbol: String) -> ResponseData { let params = serde_json::json!({ "symbol":symbol }); let data = self.request("GET".to_string(), "".to_string(), format!("/fapi/v1/ticker/bookTicker"), true, params.to_string(), ).await; data } //用户持仓风险V2 pub async fn get_position_risk(&mut self, symbol: String) -> ResponseData { let params = serde_json::json!({ "symbol":symbol, "recvWindow":"2000" }); let data = self.request("GET".to_string(), "".to_string(), format!("/fapi/v2/positionRisk"), true, params.to_string(), ).await; data } //下单 pub async fn swap_order(&mut self, params: serde_json::Value) -> ResponseData { let data = self.request("POST".to_string(), "".to_string(), format!("/fapi/v1/order"), true, params.to_string(), ).await; data } //更改持仓模式 pub async fn change_pos_side(&mut self, dual_side_position: bool) -> ResponseData { let dual_side_position_str = format!("{}", dual_side_position); let params = serde_json::json!({ "dualSidePosition":dual_side_position_str, "recvWindow":"2000" }); let data = self.request("POST".to_string(), "".to_string(), format!("/fapi/v1/positionSide/dual"), true, params.to_string(), ).await; data } //撤销订单 pub async fn cancel_order(&mut self, symbol: String, order_id: i64, orig_client_order_id: String) -> ResponseData { let mut params = serde_json::json!({ "symbol":symbol, "recvWindow":"2000" }); if order_id > 0 { params["orderId"] = json!(order_id); } if orig_client_order_id.len() > 0 { params["origClientOrderId"] = json!(orig_client_order_id); } let data = self.request("DELETE".to_string(), "".to_string(), format!("/fapi/v1/order"), true, params.to_string(), ).await; data } //根据币对 撤销全部订单 pub async fn cancel_order_all(&mut self, symbol: String) -> ResponseData { let params = serde_json::json!({ "symbol":symbol, "recvWindow":"2000", }); let data = self.request("DELETE".to_string(), "".to_string(), format!("/fapi/v1/allOpenOrders"), true, params.to_string(), ).await; data } //账户成交历史 pub async fn get_user_trades(&mut self, symbol: String, start_time: i64, end_time: i64, limit: i64) -> ResponseData { let mut params = serde_json::json!({ "symbol":symbol, "limit":1000, "recvWindow":"1000", }); if start_time > 0 { params["startTime"] = json!(start_time); } if end_time > 0 { params["endTime"] = json!(end_time); } if limit > 0 { params["limit"] = json!(limit); } let data = self.request("GET".to_string(), "".to_string(), format!("/fapi/v1/userTrades"), true, params.to_string(), ).await; data } /*******************************************************************************************************/ /*****************************************工具函数********************************************************/ /*******************************************************************************************************/ pub fn get_delays(&self) -> Vec { self.delays.clone() } pub fn get_avg_delay(&self) -> Decimal { self.avg_delay.clone() } pub fn get_max_delay(&self) -> i64 { self.max_delay.clone() } fn get_delay_info(&mut self) { let last_100 = if self.delays.len() > 100 { self.delays[self.delays.len() - 100..].to_vec() } else { self.delays.clone() }; let max_value = last_100.iter().max().unwrap(); if max_value.clone().to_owned() > self.max_delay { self.max_delay = max_value.clone().to_owned(); } let sum: i64 = last_100.iter().sum(); let sum_v = Decimal::from_i64(sum).unwrap(); let len_v = Decimal::from_u64(last_100.len() as u64).unwrap(); self.avg_delay = (sum_v / len_v).round_dp(1); self.delays = last_100.clone().into_iter().collect(); } //调用请求 async fn request(&mut self, request_type: String, prefix_url: String, request_url: String, is_login: bool, params: String) -> ResponseData { // trace!("login_param:{:?}", self.login_param); //解析账号信息 let mut access_key = "".to_string(); let mut secret_key = "".to_string(); 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(); } let mut is_login_param = true; if access_key == "" || secret_key == "" { is_login_param = false } //请求头配置-如果需要登录则存在额外配置 let mut params_json: serde_json::Value = serde_json::from_str(params.clone().as_str()).unwrap(); // let mut body = "".to_string(); let timestamp = chrono::Utc::now().timestamp_millis().to_string(); params_json.as_object_mut().unwrap().insert("timestamp".to_string(), serde_json::Value::from(timestamp)); let mut headers = HeaderMap::new(); if request_type == "GET" { headers.insert("Content-Type", "application/json; charset=UTF-8".parse().unwrap()); } else if request_type == "POST" || request_type == "PUT" || request_type == "DELETE" { headers.insert("Content-Type", "application/x-www-form-urlencoded".parse().unwrap()); } //是否需要登录-- 组装sing if is_login { if !is_login_param { let e = ResponseData::error(self.label.clone(), "登录参数错误!".to_string()); return e; } else {//需要登录-且登录参数齐全 //组装sing let sing = Self::sign(secret_key.clone(), params_json.to_string(), ); params_json.as_object_mut().unwrap().insert("signature".to_string(), serde_json::Value::from(sing.clone())); // trace!("sing:{}", sing); //组装header headers.extend(Self::headers(access_key)); } } trace!("headers:{:?}", headers); let start_time = chrono::Utc::now().timestamp_millis(); let response = self.http_tool( format!("{}{}", prefix_url.clone(), request_url.clone()), request_type.to_string(), params_json.to_string(), headers, ).await; let time_array = chrono::Utc::now().timestamp_millis() - start_time; self.delays.push(time_array); self.get_delay_info(); response } pub fn headers(access_key: String) -> HeaderMap { let mut headers = HeaderMap::new(); headers.insert("X-MBX-APIKEY", access_key.parse().unwrap()); headers } pub fn sign(secret_key: String, params_str: String) -> String { /*签名生成*/ let params_str_v = RestTool::parse_params_to_str(params_str.to_string()); let message = format!("{}", params_str_v); // let secret_key2 = "2b5eb11e18796d12d88f13dc27dbbd02c2cc51ff7059765ed9821957d82bb4d9"; // let message2 = "symbol=BTCUSDT&side=BUY&type=LIMIT&quantity=1&price=9000&timeInForce=GTC&recvWindow=5000×tamp=1591702613943"; let signed_key = hmac::Key::new(hmac::HMAC_SHA256, secret_key.as_ref()); let sign = hex::encode(hmac::sign(&signed_key, message.as_bytes()).as_ref()); sign } async fn http_tool(&mut self, request_path: String, request_type: String, params: String, headers: HeaderMap) -> ResponseData { /****请求接口与 地址*/ let url = format!("{}{}", self.base_url.to_string(), request_path); let request_type = request_type.clone().to_uppercase(); let url_param = RestTool::parse_params_to_str(params.clone()); let addrs_url = format!("{}?{}", url.clone(), url_param); let params_json: serde_json::Value = serde_json::from_str(¶ms).unwrap(); trace!("url:{}",url); trace!("addrs_url:{}",addrs_url); trace!("params_json:{}",params_json); trace!("headers:{:?}",headers); trace!("body:{:?}",params); let request_builder = match request_type.as_str() { "GET" => self.client.get(url.clone()).query(¶ms_json).headers(headers), "POST" => self.client.post(url.clone()).query(¶ms_json).headers(headers), "DELETE" => self.client.delete(url.clone()).query(¶ms_json).headers(headers), // "PUT" => self.client.put(url.clone()).json(¶ms), _ => { panic!("{}", format!("错误的请求类型:{}", request_type.clone())) } }; let response = request_builder.send().await.unwrap(); let is_success = response.status().is_success(); // 先检查状态码 let text = response.text().await.unwrap(); return if is_success { self.on_success_data(text) } else { self.on_error_data(text, addrs_url, params) } } pub fn on_success_data(&mut self, text: String) -> ResponseData { let data = serde_json::from_str(text.as_str()).unwrap(); ResponseData::new(self.label.clone(), 200, "success".to_string(), data) } pub fn on_error_data(&mut self, text: String, base_url: String, params: String) -> ResponseData { let json_value = serde_json::from_str::(&text); match json_value { Ok(data) => { let message = data["msg"].as_str().unwrap(); let mut error = ResponseData::error(self.label.clone(), message.to_string()); error.code = i16::from_str(data["code"].as_str().unwrap()).unwrap(); error.message = format!("请求地址:{}, 请求参数:{}", base_url, params); error } Err(e) => { error!("解析错误:{:?}", e); let error = ResponseData::error("".to_string(), format!("json 解析失败:{},相关参数:{}", e, text)); error } } } }