use std::collections::BTreeMap; use reqwest::header::HeaderMap; use ring::{digest}; use hex; use hmac::{Hmac, Mac, NewMac}; use reqwest::Client; use rust_decimal::Decimal; use rust_decimal::prelude::FromPrimitive; use rust_decimal_macros::dec; use serde_json::Value; use crate::http_tool::RestTool; use crate::response_base::ResponseData; use sha2::Sha512; use tracing::{error, info}; #[derive(Clone)] pub struct GateSwapRest { label: String, base_url: String, client: reqwest::Client, /*******参数*/ //登录所需参数 login_param: BTreeMap, delays: Vec, max_delay: i64, avg_delay: Decimal, } impl GateSwapRest { /*******************************************************************************************************/ /*****************************************获取一个对象****************************************************/ /*******************************************************************************************************/ pub fn new(is_colo: bool, login_param: BTreeMap) -> GateSwapRest { return GateSwapRest::new_label("default-GateSwapRest".to_string(), is_colo, login_param); } pub fn new_label(label: String, is_colo: bool, login_param: BTreeMap) -> GateSwapRest { let base_url = if is_colo { let url = "https://apiv4-private.gateapi.io".to_string(); info!("开启高速通道:{:?}",url); url } else { let url = "https://api.gateio.ws".to_string(); info!("走普通通道:{}",url); url }; if is_colo {} else {} /*****返回结构体*******/ GateSwapRest { 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(), "/api/v4".to_string(), format!("/spot/time"), true, params.to_string(), ).await; data } //查询个人交易费率 pub async fn wallet_fee(&mut self) -> ResponseData { let params = serde_json::json!({ }); let data = self.request("GET".to_string(), "/api/v4".to_string(), format!("/wallet/fee"), true, params.to_string(), ).await; data } //查询合约账户 pub async fn get_account(&mut self, settle: String) -> ResponseData { let params = serde_json::json!({ }); let data = self.request("GET".to_string(), "/api/v4".to_string(), format!("/futures/{}/accounts", settle), true, params.to_string(), ).await; data } //用户仓位列表 pub async fn get_user_position(&mut self, settle: String) -> ResponseData { let params = serde_json::json!({ }); let data = self.request("GET".to_string(), "/api/v4".to_string(), format!("/futures/{}/positions", settle), true, params.to_string(), ).await; data } //双仓模式下的持仓信息 pub async fn get_position(&mut self, settle: String, contract: String) -> ResponseData { let params = serde_json::json!({ }); let data = self.request("GET".to_string(), "/api/v4".to_string(), format!("/futures/{}/dual_comp/positions/{}", settle, contract), true, params.to_string(), ).await; data } //获取所有合约交易行情统计 pub async fn get_ticker(&mut self, settle: String) -> ResponseData { let params = serde_json::json!({ }); let data = self.request("GET".to_string(), "/api/v4".to_string(), format!("/futures/{}/tickers", settle), true, params.to_string(), ).await; data } //查询所有的合约信息 pub async fn get_market_details(&mut self, settle: String) -> ResponseData { let params = serde_json::json!({ }); let data = self.request("GET".to_string(), "/api/v4".to_string(), format!("/futures/{}/contracts", settle), true, params.to_string(), ).await; data } //查询单个订单详情 pub async fn get_order_details(&mut self, settle: String, order_id: String) -> ResponseData { let params = serde_json::json!({ }); let data = self.request("GET".to_string(), "/api/v4".to_string(), format!("/futures/{}/orders/{}", settle, order_id), true, params.to_string(), ).await; data } //查询合约订单列表 pub async fn get_orders(&mut self, settle: String, status: String) -> ResponseData { let params = serde_json::json!({ "status":status }); let data = self.request("GET".to_string(), "/api/v4".to_string(), format!("/futures/{}/orders", settle), true, params.to_string(), ).await; data } //下单:side-下单方向,pos_side-持仓方向 pub async fn order(&mut self, settle: String, pos_side: String, side: String, contract: String, size: i64, price: String, text: String, ) -> ResponseData { if side != "buy" && side != "sell" { ResponseData::error(self.label.clone(), format!("未知下单方向!{}", side)); } if pos_side != "long" && pos_side != "short" { ResponseData::error(self.label.clone(), format!("未知持仓方向!{}", side)); } let mut param = serde_json::json!({ "contract":contract, //合约标识 "size":size, "price":price, "text":text, }); if price == "0" { param.as_object_mut().unwrap().insert("tif".to_string(), serde_json::json!("ioc")); } if size == 0 { //数量为0则平仓 param.as_object_mut().unwrap().insert("close".to_string(), serde_json::json!(true)); } match format!("{}_{}", pos_side, side).as_str() { "long_buy" => {//开多 param.as_object_mut().unwrap().insert("reduce_only".to_string(), serde_json::json!(false)); } "long_sell" => {//平多 param.as_object_mut().unwrap().insert("reduce_only".to_string(), serde_json::json!(true)); } "short_buy" => {//平空 param.as_object_mut().unwrap().insert("reduce_only".to_string(), serde_json::json!(true)); } "short_sell" => {//开空 param.as_object_mut().unwrap().insert("reduce_only".to_string(), serde_json::json!(false)); } _ => {} // 处理未知请求类型 }; // trace!("----param{}", param.to_string()); let data = self.swap_order(settle, param).await; data } //合约交易下单 pub async fn swap_order(&mut self, settle: String, params: serde_json::Value) -> ResponseData { let data = self.request("POST".to_string(), "/api/v4".to_string(), format!("/futures/{}/orders", settle), true, params.to_string(), ).await; data } // 提交一个自动订单 pub async fn place_price_order(&mut self, settle: String, params: Value) -> ResponseData { self.request("POST".to_string(), "/api/v4".to_string(), format!("/futures/{}/price_orders", settle), true, params.to_string()).await } // 撤销自动订单 pub async fn cancel_price_order(&mut self, settle: String, order_id: String) -> ResponseData { self.request("DELETE".to_string(), "/api/v4".to_string(), format!("/futures/{}/price_orders/{}", settle, order_id), true, "{}".to_string(), ).await } //设置持仓模式 pub async fn setting_dual_mode(&mut self, settle: String, dual_mode: bool) -> ResponseData { let params = serde_json::json!({ "dual_mode":dual_mode, }); let data = self.request("POST".to_string(), "/api/v4".to_string(), format!("/futures/{}/dual_mode", settle), true, params.to_string(), ).await; data } //更新双仓模式下的杠杆 pub async fn setting_dual_leverage(&mut self, settle: String, symbol: String, leverage: String) -> ResponseData { let params = serde_json::json!({ "leverage":leverage, }); let data = self.request("POST".to_string(), "/api/v4".to_string(), format!("/futures/{}/dual_comp/positions/{}/leverage", settle, symbol), true, params.to_string(), ).await; data } //交易账户互转 pub async fn wallet_transfers(&mut self, currency: String, from: String, to: String, amount: String, settle: String) -> ResponseData { let params = serde_json::json!({ "currency":currency, "from":from, "to":to, "amount":amount, "settle":settle, }); let data = self.request("POST".to_string(), "/api/v4".to_string(), format!("/wallet/transfers"), true, params.to_string(), ).await; data } //撤销单个订单 pub async fn cancel_order(&mut self, settle: String, order_id: String) -> ResponseData { let params = serde_json::json!({ }); let data = self.request("DELETE".to_string(), "/api/v4".to_string(), format!("/futures/{}/orders/{}", settle, order_id), true, params.to_string(), ).await; data } //撤销所有挂单 pub async fn cancel_order_all(&mut self) -> ResponseData { let params = serde_json::json!({ }); let data = self.request("POST".to_string(), "/api/v5".to_string(), format!("/sprd/mass-cancel"), true, params.to_string(), ).await; data } //弃用 pub async fn swap_bazaar_order(&mut 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, "contract":contract, "price":"0", "size":size, }); let req = match origin_side.as_str() { "kd" => { reduce_only = false; true } "pd" => { reduce_only = true; true } "kk" => { reduce_only = false; true } "pk" => { reduce_only = true; true } _ => { false } // 处理未知请求类型 }; if req { param.as_object_mut().unwrap().insert("reduce_only".to_string(), serde_json::json!(reduce_only)); } let data = self.swap_order(settle, param).await; data } //批量取消状态为 open 的订单 pub async fn cancel_orders(&mut self, settle: String, contract: String) -> ResponseData { let params = serde_json::json!({ "contract":contract }); let data = self.request("DELETE".to_string(), "/api/v4".to_string(), format!("/futures/{}/orders", settle), true, params.to_string(), ).await; data } //查询个人成交记录 pub async fn my_trades(&mut self, settle: String, contract: String, limit: i64, last_id: String) -> ResponseData { let mut params = serde_json::json!({ "contract":contract, "last_id": last_id, "limit":1000 }); if limit > 0 { params["limit"] = serde_json::json!(limit); } let data = self.request("GET".to_string(), "/api/v4".to_string(), format!("/futures/{}/my_trades", settle), true, params.to_string(), ).await; data } //查询合约账户变更历史 pub async fn account_book(&mut self, settle: String) -> ResponseData { let params = serde_json::json!({ "limit":200 }); let data = self.request("GET".to_string(), "/api/v4".to_string(), format!("/futures/{}/account_book", settle), 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, requesst_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 body = "".to_string(); let timestamp = chrono::Utc::now().timestamp().to_string(); let mut headers = HeaderMap::new(); if requesst_type == "GET" { headers.insert("Content-type", "application/x-www-form-urlencoded".parse().unwrap()); headers.insert("User-Agent", "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) ".parse().unwrap()); } else { headers.insert("Accept", "application/json".parse().unwrap()); headers.insert("Content-Type", "application/json".parse().unwrap()); } if requesst_type == "POST" { body = params.clone(); } //是否需要登录-- 组装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(), requesst_type.clone(), prefix_url.clone(), request_url.clone(), params.clone(), body.clone(), timestamp.clone(), ); // trace!("sing:{}", sing); //组装header headers.extend(Self::headers(access_key, timestamp, sing)); } } // trace!("headers:{:?}", headers); let base_url = format!("{}{}", prefix_url.clone(), request_url.clone()); let start_time = chrono::Utc::now().timestamp_millis(); let response = self.http_tool( base_url.clone(), requesst_type.to_string(), params.clone(), headers, ).await; let time_array = chrono::Utc::now().timestamp_millis() - start_time; self.delays.push(time_array); self.get_delay_info(); response } pub fn headers(access_key: String, timestamp: String, sign: String) -> HeaderMap { let mut headers = HeaderMap::new(); headers.insert("KEY", access_key.clone().parse().unwrap()); headers.insert("Timestamp", timestamp.clone().parse().unwrap()); headers.insert("SIGN", sign.clone().parse().unwrap()); headers } pub fn sign(secret_key: String, requesst_type: 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); let body = Some(body_data); let hashed_payload = if let Some(body) = body { let mut m = digest::Context::new(&digest::SHA512); m.update(body.as_bytes()); hex::encode(m.finish().as_ref()) } else { String::new() }; // trace!("hashed_payload:{}", hashed_payload); let message = format!("{}\n{}\n{}\n{}\n{}", requesst_type, url, params_str, hashed_payload, timestamp); // trace!("**********", ); // trace!("组装数据:{}", message); // trace!("**********", ); let mut mac = Hmac::::new_varkey(secret_key.as_bytes()).expect("Failed to create HMAC"); mac.update(message.as_bytes()); let result = mac.finalize().into_bytes(); let sign = hex::encode(result); 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 addrs_url = format!("{}?{}", url.clone(), RestTool::parse_params_to_str(params.clone())); let request_builder = match request_type.as_str() { "GET" => self.client.get(addrs_url.clone()).headers(headers), "POST" => self.client.post(addrs_url.clone()).body(params.clone()).headers(headers), "DELETE" => self.client.delete(addrs_url.clone()).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, ¶ms) } } 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; if !data["message"].is_null() { message = format!("{}:{}", data["label"].as_str().unwrap(), data["message"].as_str().unwrap()); } else { message = data["label"].to_string(); } let mut error = ResponseData::error(self.label.clone(), message); error.message = format!("请求地址:{}, 请求参数:{}, 报错内容:{}。", base_url, params, error.message); error } Err(e) => { error!("解析错误:{:?}", e); let error = ResponseData::error("".to_string(), format!("json 解析失败:{},相关参数:{}", e, text)); error } } } }