use std::collections::{BTreeMap}; use std::io::{Error, ErrorKind}; use std::str::FromStr; use tokio::sync::mpsc::Sender; use async_trait::async_trait; use futures::stream::FuturesUnordered; use futures::TryStreamExt; use rust_decimal::Decimal; use rust_decimal::prelude::{FromPrimitive, ToPrimitive}; use serde_json::{json, Value}; use tokio::spawn; use tokio::time::Instant; use tracing::{error, info}; use crate::{Platform, ExchangeEnum, Account, Position, Ticker, Market, Order, OrderCommand, PositionModeEnum}; use exchanges::gate_swap_rest::GateSwapRest; use global::trace_stack::TraceStack; #[allow(dead_code)] #[derive(Clone)] pub struct GateSwap { exchange: ExchangeEnum, symbol: String, is_colo: bool, params: BTreeMap, request: GateSwapRest, market: Market, order_sender: Sender, error_sender: Sender, } impl GateSwap { pub async fn new(symbol: String, is_colo: bool, params: BTreeMap, order_sender: Sender, error_sender: Sender) -> GateSwap { let market = Market::new(); let mut gate_swap = GateSwap { exchange: ExchangeEnum::GateSwap, symbol: symbol.to_uppercase(), is_colo, params: params.clone(), request: GateSwapRest::new(is_colo, params.clone()), market, order_sender, error_sender, }; // 修改持仓模式 let symbol_array: Vec<&str> = symbol.split("_").collect(); let mode_result = gate_swap.set_dual_mode(symbol_array[1], true).await; match mode_result { Ok(ok) => { info!("Gate:设置持仓模式成功!{:?}", ok); } Err(error) => { error!("Gate:设置持仓模式失败!mode_result={}", error) } } // 获取市场信息 gate_swap.market = GateSwap::get_market(&mut gate_swap).await.unwrap_or(gate_swap.market); return gate_swap; } } #[async_trait] impl Platform for GateSwap { // 克隆方法 fn clone_box(&self) -> Box { Box::new(self.clone()) } // 获取交易所模式 fn get_self_exchange(&self) -> ExchangeEnum { ExchangeEnum::GateSwap } // 获取交易对 fn get_self_symbol(&self) -> String { self.symbol.clone() } // 获取是否使用高速通道 fn get_self_is_colo(&self) -> bool { self.is_colo } // 获取params信息 fn get_self_params(&self) -> BTreeMap { self.params.clone() } // 获取market信息 fn get_self_market(&self) -> Market { self.market.clone() } // 获取请求时间 fn get_request_delays(&self) -> Vec { self.request.get_delays() } // 获取请求平均时间 fn get_request_avg_delay(&self) -> Decimal { self.request.get_avg_delay() } // 获取请求最大时间 fn get_request_max_delay(&self) -> i64 { self.request.get_max_delay() } // 获取服务器时间 async fn get_server_time(&mut self) -> Result { let res_data = self.request.get_server_time().await; if res_data.code == 200 { let res_data_json: serde_json::Value = res_data.data; let result = res_data_json["server_time"].to_string(); Ok(result) } else { Err(Error::new(ErrorKind::Other, res_data.to_string())) } } // 获取账号信息 async fn get_account(&mut self) -> Result { let symbol_array: Vec<&str> = self.symbol.split("_").collect(); let res_data = self.request.get_account(symbol_array[1].to_string().to_lowercase()).await; if res_data.code == 200 { let res_data_json: serde_json::Value = res_data.data; let balance = Decimal::from_str(res_data_json["total"].as_str().unwrap()).unwrap(); let available_balance = Decimal::from_str(res_data_json["available"].as_str().unwrap()).unwrap(); let frozen_balance = balance - available_balance; let result = Account { coin: symbol_array[1].to_string(), balance, available_balance, frozen_balance, stocks: Decimal::ZERO, available_stocks: Decimal::ZERO, frozen_stocks: Decimal::ZERO, }; Ok(result) } else { Err(Error::new(ErrorKind::Other, res_data.to_string())) } } async fn get_spot_account(&mut self) -> Result, Error> { Err(Error::new(ErrorKind::NotFound, "gate_swap:该交易所方法未实现".to_string())) } // 获取持仓信息 async fn get_position(&mut self) -> Result, Error> { let symbol_array: Vec<&str> = self.symbol.split("_").collect(); let ct_val = self.market.ct_val; let res_data = self.request.get_position(symbol_array[1].to_string().to_lowercase(), self.symbol.clone()).await; if res_data.code == 200 { let res_data_json = res_data.data.as_array().unwrap(); let result = res_data_json.iter().map(|item| { format_position_item(item, ct_val) }).collect(); Ok(result) } else { Err(Error::new(ErrorKind::Other, res_data.to_string())) } } // 获取所有持仓 async fn get_positions(&mut self) -> Result, Error> { let symbol_array: Vec<&str> = self.symbol.split("_").collect(); let res_data = self.request.get_user_position(symbol_array[1].to_string().to_lowercase()).await; if res_data.code == 200 { let res_data_json = res_data.data.as_array().unwrap(); let result = res_data_json.iter().map(|item| { format_position_item(item, Decimal::ONE) }).collect(); Ok(result) } else { Err(Error::new(ErrorKind::Other, res_data.to_string())) } } // 获取市场行情 async fn get_ticker(&mut self) -> Result { let symbol_array: Vec<&str> = self.symbol.split("_").collect(); let res_data = self.request.get_ticker(symbol_array[1].to_string().to_lowercase()).await; if res_data.code == 200 { let res_data_json = res_data.data.as_array().unwrap(); let ticker_info = res_data_json.iter().find(|item| item["contract"].as_str().unwrap() == self.symbol); match ticker_info { None => { error!("gate_swap:获取Ticker信息错误!\nget_ticker:res_data={:?}", res_data); Err(Error::new(ErrorKind::Other, res_data.to_string())) } Some(value) => { let result = Ticker { time: chrono::Utc::now().timestamp_millis(), high: Decimal::from_str(value["high_24h"].as_str().unwrap()).unwrap(), low: Decimal::from_str(value["low_24h"].as_str().unwrap()).unwrap(), sell: Decimal::from_str(value["lowest_ask"].as_str().unwrap()).unwrap(), buy: Decimal::from_str(value["highest_bid"].as_str().unwrap()).unwrap(), last: Decimal::from_str(value["last"].as_str().unwrap()).unwrap(), volume: Decimal::from_str(value["volume_24h"].as_str().unwrap()).unwrap(), }; Ok(result) } } } else { Err(Error::new(ErrorKind::Other, res_data.to_string())) } } async fn get_ticker_symbol(&mut self, symbol: String) -> Result { let symbol_upper = symbol.to_uppercase(); let symbol_array: Vec<&str> = symbol_upper.split("_").collect(); let res_data = self.request.get_ticker(symbol_array[1].to_string().to_lowercase()).await; if res_data.code == 200 { let res_data_json = res_data.data.as_array().unwrap(); let ticker_info = res_data_json.iter().find(|item| item["contract"].as_str().unwrap() == symbol_upper); match ticker_info { None => { error!("gate_swap:获取Ticker信息错误!\nget_ticker:res_data={:?}", res_data); Err(Error::new(ErrorKind::Other, res_data.to_string())) } Some(value) => { let result = Ticker { time: chrono::Utc::now().timestamp_millis(), high: Decimal::from_str(value["high_24h"].as_str().unwrap()).unwrap(), low: Decimal::from_str(value["low_24h"].as_str().unwrap()).unwrap(), sell: Decimal::from_str(value["lowest_ask"].as_str().unwrap()).unwrap(), buy: Decimal::from_str(value["highest_bid"].as_str().unwrap()).unwrap(), last: Decimal::from_str(value["last"].as_str().unwrap()).unwrap(), volume: Decimal::from_str(value["volume_24h"].as_str().unwrap()).unwrap(), }; Ok(result) } } } else { Err(Error::new(ErrorKind::Other, res_data.to_string())) } } async fn get_market(&mut self) -> Result { let symbol_array: Vec<&str> = self.symbol.split("_").collect(); let res_data = self.request.get_market_details(symbol_array[1].to_string().to_lowercase()).await; if res_data.code == 200 { let res_data_json = res_data.data.as_array().unwrap(); let market_info = res_data_json.iter().find(|item| item["name"].as_str().unwrap() == self.symbol); match market_info { None => { error!("gate_swap:获取Market信息错误!\nget_market:res_data={:?}", res_data); Err(Error::new(ErrorKind::Other, res_data.to_string())) } Some(value) => { let name = value["name"].as_str().unwrap(); let name_array: Vec<&str> = name.split("_").collect(); let tick_size = Decimal::from_str(value["order_price_round"].as_str().unwrap()).unwrap(); let min_qty = Decimal::from_str(&value["order_size_min"].to_string()).unwrap(); let max_qty = Decimal::from_str(&value["order_size_max"].to_string()).unwrap(); let ct_val = Decimal::from_str(value["quanto_multiplier"].as_str().unwrap()).unwrap(); let amount_size = min_qty * ct_val; let price_precision = Decimal::from_u32(tick_size.scale()).unwrap(); let amount_precision = Decimal::from_u32(amount_size.scale()).unwrap(); let min_notional = min_qty * ct_val; let max_notional = max_qty * ct_val; let result = Market { symbol: name.to_string(), base_asset: name_array[0].to_string(), quote_asset: name_array[1].to_string(), tick_size, amount_size, price_precision, amount_precision, min_qty, max_qty, min_notional, max_notional, ct_val, }; Ok(result) } } } else { Err(Error::new(ErrorKind::Other, res_data.to_string())) } } async fn get_market_symbol(&mut self, symbol: String) -> Result { let symbol_upper = symbol.to_uppercase(); let symbol_array: Vec<&str> = symbol_upper.split("_").collect(); let res_data = self.request.get_market_details(symbol_array[1].to_string().to_lowercase()).await; if res_data.code == 200 { let res_data_json = res_data.data.as_array().unwrap(); let market_info = res_data_json.iter().find(|item| item["name"].as_str().unwrap() == symbol_upper); match market_info { None => { error!("gate_swap:获取Market信息错误!\nget_market:res_data={:?}", res_data); Err(Error::new(ErrorKind::Other, res_data.to_string())) } Some(value) => { let name = value["name"].as_str().unwrap(); let name_array: Vec<&str> = name.split("_").collect(); let tick_size = Decimal::from_str(value["order_price_round"].as_str().unwrap()).unwrap(); let min_qty = Decimal::from_str(&value["order_size_min"].to_string()).unwrap(); let max_qty = Decimal::from_str(&value["order_size_max"].to_string()).unwrap(); let ct_val = Decimal::from_str(value["quanto_multiplier"].as_str().unwrap()).unwrap(); let amount_size = min_qty * ct_val; let price_precision = Decimal::from_u32(tick_size.scale()).unwrap(); let amount_precision = Decimal::from_u32(amount_size.scale()).unwrap(); let min_notional = min_qty * ct_val; let max_notional = max_qty * ct_val; let result = Market { symbol: name.to_string(), base_asset: name_array[0].to_string(), quote_asset: name_array[1].to_string(), tick_size, amount_size, price_precision, amount_precision, min_qty, max_qty, min_notional, max_notional, ct_val, }; Ok(result) } } } else { Err(Error::new(ErrorKind::Other, res_data.to_string())) } } // 获取订单详情 async fn get_order_detail(&mut self, order_id: &str, custom_id: &str) -> Result { let symbol_array: Vec<&str> = self.symbol.split("_").collect(); let ct_val = self.market.ct_val; let id = if order_id.eq("") { format!("t-{}", custom_id) } else { order_id.to_string() }; let res_data = self.request.get_order_details(symbol_array[1].to_string().to_lowercase(), id).await; if res_data.code == 200 { let res_data_json: serde_json::Value = res_data.data; let result = format_order_item(res_data_json, ct_val); Ok(result) } else { Err(Error::new(ErrorKind::Other, res_data.to_string())) } } // 获取订单列表 async fn get_orders_list(&mut self, status: &str) -> Result, Error> { let symbol_array: Vec<&str> = self.symbol.split("_").collect(); let ct_val = self.market.ct_val; let res_data = self.request.get_orders(symbol_array[1].to_string().to_lowercase(), status.to_string()).await; if res_data.code == 200 { let res_data_json = res_data.data.as_array().unwrap(); let order_info: Vec<_> = res_data_json.iter().filter(|item| item["contract"].as_str().unwrap_or("") == self.symbol).collect(); let result = order_info.iter().map(|&item| format_order_item(item.clone(), ct_val)).collect(); Ok(result) } else { Err(Error::new(ErrorKind::Other, res_data.to_string())) } } // 下单接口 async fn take_order(&mut self, custom_id: &str, origin_side: &str, price: Decimal, amount: Decimal) -> Result { let symbol_array: Vec<&str> = self.symbol.split("_").collect(); let ct_val = self.market.ct_val; let mut params = json!({ "text": format!("t-{}", custom_id), "contract": self.symbol.to_string(), "price": price.to_string(), }); let size = (amount / ct_val).floor(); if price.eq(&Decimal::ZERO) { params["tif"] = json!("ioc".to_string()); } match origin_side { "kd" => { params["reduce_only"] = json!(false); params["size"] = json!(size.to_i64()); } "pd" => { params["reduce_only"] = json!(true); params["size"] = serde_json::Value::from((-size).to_i64()); } "kk" => { params["reduce_only"] = json!(false); params["size"] = serde_json::Value::from((-size).to_i64()); } "pk" => { params["reduce_only"] = json!(true); params["size"] = json!(size.to_i64()); } _ => { error!("下单参数错误"); } }; let res_data = self.request.swap_order(symbol_array[1].to_string().to_lowercase(), params).await; if res_data.code == 200 { let res_data_json: serde_json::Value = res_data.data; let result = format_order_item(res_data_json, ct_val); Ok(result) } else { Err(Error::new(ErrorKind::Other, res_data.to_string())) } } async fn take_order_symbol(&mut self, symbol: String, ct_val: Decimal, custom_id: &str, origin_side: &str, price: Decimal, amount: Decimal) -> Result { let symbol_upper = symbol.to_uppercase(); let symbol_array: Vec<&str> = symbol_upper.split("_").collect(); let mut params = json!({ "text": format!("t-{}", custom_id), "contract": symbol_upper.to_string(), "price": price.to_string(), }); let size = (amount / ct_val).floor(); if price.eq(&Decimal::ZERO) { params["tif"] = json!("ioc".to_string()); } match origin_side { "kd" => { params["reduce_only"] = json!(false); params["size"] = json!(size.to_i64()); } "pd" => { params["reduce_only"] = json!(true); params["size"] = serde_json::Value::from((-size).to_i64()); } "kk" => { params["reduce_only"] = json!(false); params["size"] = serde_json::Value::from((-size).to_i64()); } "pk" => { params["reduce_only"] = json!(true); params["size"] = json!(size.to_i64()); } _ => { error!("下单参数错误"); } }; let res_data = self.request.swap_order(symbol_array[1].to_string().to_lowercase(), params).await; if res_data.code == 200 { let res_data_json: serde_json::Value = res_data.data; let result = format_order_item(res_data_json, ct_val); Ok(result) } else { Err(Error::new(ErrorKind::Other, res_data.to_string())) } } // 撤销订单 async fn cancel_order(&mut self, order_id: &str, custom_id: &str) -> Result { let symbol_array: Vec<&str> = self.symbol.split("_").collect(); let ct_val = self.market.ct_val; let settle = symbol_array[1].to_string().to_lowercase(); let id = if order_id.eq("") { format!("t-{}", custom_id) } else { order_id.to_string() }; let res_data = self.request.cancel_order(settle, id.to_string()).await; if res_data.code == 200 { let res_data_json: serde_json::Value = res_data.data; let result = format_order_item(res_data_json, ct_val); Ok(result) } else { Err(Error::new(ErrorKind::Other, res_data.to_string())) } } // 批量撤销订单 async fn cancel_orders(&mut self) -> Result, Error> { let symbol_array: Vec<&str> = self.symbol.split("_").collect(); let ct_val = self.market.ct_val; let res_data = self.request.cancel_orders(symbol_array[1].to_string().to_lowercase(), self.symbol.to_string()).await; if res_data.code == 200 { let res_data_json = res_data.data.as_array().unwrap(); let result = res_data_json.iter().map(|item| format_order_item(item.clone(), ct_val)).collect(); Ok(result) } else { Err(Error::new(ErrorKind::Other, res_data.to_string())) } } async fn cancel_orders_all(&mut self) -> Result, Error> { let symbol_array: Vec<&str> = self.symbol.split("_").collect(); let ct_val = self.market.ct_val; let orders_res_data = self.request.get_orders(symbol_array[1].to_string().to_lowercase(), "open".to_string()).await; if orders_res_data.code == 200 { let mut result = vec![]; let orders_res_data_json = orders_res_data.data.as_array().unwrap(); for order in orders_res_data_json { let cancel_res_data = self.request.cancel_orders(symbol_array[1].to_string().to_lowercase(), order["contract"].as_str().unwrap().to_string()).await; if cancel_res_data.code == 200 { let cancel_res_data_json = cancel_res_data.data.as_array().unwrap(); for cancel in cancel_res_data_json { result.push(format_order_item(cancel.clone(), ct_val)) }; } else { return Err(Error::new(ErrorKind::Other, cancel_res_data.to_string())); } } Ok(result) } else { Err(Error::new(ErrorKind::Other, orders_res_data.to_string())) } } async fn take_stop_loss_order(&mut self, stop_price: Decimal, price: Decimal, side: &str) -> Result { let mut params = json!({}); let mut initial = json!({ "contract": "XRP_USDT", "price": price.to_string(), "tif": "ioc", // 是否只减仓 "reduce_only": true, // [平多:close_long, 平空:close_short] // "auto_size": "close_long" }); let mut trigger = json!({ // [平多:close-long-position, 平空:close-short-position] // "order_type": "close-long-position", // 一般都默认用0 "strategy_type": 0, // [0 - 最新成交价,1 - 标记价格,2 - 指数价格] "price_type": 0, // [1: 引用价格大于等于我们传的价格,2:引用价格小于等于我们传的价格] // 在止损的情况下: // 1 可以理解为向上突破触发价(一般是给空单用) // 2 可以理解为向下突破触发价(一般是给多单用) // "rule": 2, // 订单触发价格 "price": stop_price.to_string(), }); match side { "kd" => { initial["auto_size"] = json!("close_long"); trigger["order_type"] = json!("close-long-position"); trigger["rule"] = json!(2); }, "kk" => { initial["auto_size"] = json!("close_short"); trigger["order_type"] = json!("close-short-position"); trigger["rule"] = json!(1); }, _ => { error!("gate swap 止损单side错误: {}", side); } } params["initial"] = initial; params["trigger"] = trigger; let binding = self.symbol.clone().to_lowercase(); let symbol_split: Vec<&str> = binding.split("_").collect(); let base_coin = symbol_split[1].to_string(); let response_data = self.request.place_price_order(base_coin, params).await; if response_data.code == 200 { Ok(response_data.data) } else { Err(Error::new(ErrorKind::Other, response_data.to_string())) } } async fn cancel_stop_loss_order(&mut self, order_id: &str) -> Result { let binding = self.symbol.clone().to_lowercase(); let symbol_split: Vec<&str> = binding.split("_").collect(); let base_coin = symbol_split[1].to_string(); let response_data = self.request.cancel_price_order(base_coin, order_id.to_string()).await; if response_data.code == 200 { Ok(response_data.data) } else { Err(Error::new(ErrorKind::Other, response_data.to_string())) } } // 设置持仓模式 async fn set_dual_mode(&mut self, coin: &str, is_dual_mode: bool) -> Result { 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.to_string()) } else { Err(Error::new(ErrorKind::Other, res_data.to_string())) } } // 更新双持仓模式下杠杆 async fn set_dual_leverage(&mut self, leverage: &str) -> Result { let symbol_array: Vec<&str> = self.symbol.split("_").collect(); let res_data = self.request.setting_dual_leverage(symbol_array[1].to_string().to_lowercase(), self.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.to_string()) } else { Err(Error::new(ErrorKind::Other, res_data.to_string())) } } async fn set_auto_deposit_status(&mut self, _status: bool) -> Result { Err(Error::new(ErrorKind::NotFound, "gate:该交易所方法未实现".to_string())) } // 交易账户互转 async fn wallet_transfers(&mut self, coin: &str, from: &str, to: &str, amount: Decimal) -> Result { 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.to_string()) } else { Err(Error::new(ErrorKind::Other, res_data.to_string())) } } // 指令下单 async fn command_order(&mut self, order_command: &mut OrderCommand, trace_stack: &TraceStack) { let mut handles = vec![]; // 下单指令,limits_open里已经包含了limits_close for item in order_command.limits_open.keys() { let mut ts = trace_stack.clone(); let amount = Decimal::from_str(&*order_command.limits_open[item].get(0).unwrap().clone()).unwrap(); let side = order_command.limits_open[item].get(1).unwrap().clone(); let price = Decimal::from_str(&*order_command.limits_open[item].get(2).unwrap().clone()).unwrap(); let cid = order_command.limits_open[item].get(3).unwrap().clone(); // order_name: [数量,方向,价格,c_id] let mut self_clone = self.clone(); let handle = spawn(async move { // TraceStack::show_delay(&ts.ins); ts.on_before_send(); let result = self_clone.take_order(&cid, &side, price, amount).await; ts.on_after_send(); match result { Ok(mut result) => { result.trace_stack = ts; self_clone.order_sender.send(result).await.unwrap(); } Err(error) => { let mut err_order = Order::new(); err_order.custom_id = cid.clone(); err_order.status = "REMOVE".to_string(); self_clone.order_sender.send(err_order).await.unwrap(); self_clone.error_sender.send(error).await.unwrap(); } } }); handles.push(handle) } let futures = FuturesUnordered::from_iter(handles); // 等待所有任务完成 let _: Result, _> = futures.try_collect().await; // 撤销订单 let mut cancel_handlers = vec![]; for item in order_command.cancel.keys() { let order_id = order_command.cancel[item].get(1).unwrap().clone(); let custom_id = order_command.cancel[item].get(0).unwrap().clone(); let mut self_clone = self.clone(); let handle = spawn(async move { let result = self_clone.cancel_order(&order_id, &custom_id).await; match result { Ok(_) => { // result_sd.send(result).await.unwrap(); } Err(error) => { // 取消失败去查订单。 let query_rst = self_clone.get_order_detail(&order_id, &custom_id).await; match query_rst { Ok(order) => { self_clone.order_sender.send(order).await.unwrap(); } Err(_err) => { // error!("撤单失败,而且查单也失败了,gate_io_swap,oid={}, cid={}。", order_id.clone(), custom_id.clone()); // panic!("撤单失败,而且查单也失败了,gate_io_swap,oid={}, cid={}。", order_id.clone(), custom_id.clone()); } } self_clone.error_sender.send(error).await.unwrap(); } } }); cancel_handlers.push(handle) } let futures = FuturesUnordered::from_iter(cancel_handlers); // 等待所有任务完成 let _: Result, _> = futures.try_collect().await; // 检查订单指令 let mut check_handlers = vec![]; for item in order_command.check.keys() { let order_id = order_command.check[item].get(1).unwrap().clone(); let custom_id = order_command.check[item].get(0).unwrap().clone(); let mut self_clone = self.clone(); let handle = spawn(async move { let result = self_clone.get_order_detail(&order_id, &custom_id).await; match result { Ok(result) => { self_clone.order_sender.send(result).await.unwrap(); } Err(error) => { self_clone.error_sender.send(error).await.unwrap(); } } }); check_handlers.push(handle) } let futures = FuturesUnordered::from_iter(check_handlers); // 等待所有任务完成 let _: Result, _> = futures.try_collect().await; } } pub fn format_position_item(position: &serde_json::Value, ct_val: Decimal) -> Position { let mut position_mode = match position["mode"].as_str().unwrap_or("") { "single" => PositionModeEnum::Both, "dual_long" => PositionModeEnum::Long, "dual_short" => PositionModeEnum::Short, _ => { error!("gate_swap:格式化持仓模式错误!\nformat_position_item:position={:?}", position); panic!("gate_swap:格式化持仓模式错误!\nformat_position_item:position={:?}", position) } }; let size = Decimal::from_str(&position["size"].to_string()).unwrap(); let amount = size * ct_val; match position_mode { PositionModeEnum::Both => { position_mode = match amount { amount if amount > Decimal::ZERO => PositionModeEnum::Long, amount if amount < Decimal::ZERO => PositionModeEnum::Short, _ => { PositionModeEnum::Both } } } _ => {} } Position { symbol: position["contract"].as_str().unwrap_or("").parse().unwrap(), margin_level: Decimal::from_str(position["leverage"].as_str().unwrap()).unwrap(), amount, frozen_amount: Decimal::ZERO, price: Decimal::from_str(position["entry_price"].as_str().unwrap()).unwrap(), profit: Decimal::from_str(position["unrealised_pnl"].as_str().unwrap()).unwrap(), position_mode, margin: Decimal::from_str(position["margin"].as_str().unwrap()).unwrap(), } } pub fn format_order_item(order: serde_json::Value, ct_val: Decimal) -> Order { let status = order["status"].as_str().unwrap_or(""); let text = order["text"].as_str().unwrap_or(""); let size = Decimal::from_str(&order["size"].to_string()).unwrap(); let left = Decimal::from_str(&order["left"].to_string()).unwrap(); let amount = size * ct_val; let deal_amount = (size - left) * ct_val; let custom_status = if status == "finished" { "REMOVE".to_string() } else if status == "open" { "NEW".to_string() } else { error!("gate_swap:格式化订单状态错误!\nformat_order_item:order={:?}", order); panic!("gate_swap:格式化订单状态错误!\nformat_order_item:order={:?}", order) }; let rst_order = Order { id: order["id"].to_string(), custom_id: text.replace("t-my-custom-id_", "").replace("t-", ""), price: Decimal::from_str(order["price"].as_str().unwrap()).unwrap(), amount, deal_amount, avg_price: Decimal::from_str(&order["fill_price"].as_str().unwrap()).unwrap(), status: custom_status, order_type: "limit".to_string(), trace_stack: TraceStack::new(0, Instant::now()).on_special("688 trace_stack".to_string()), }; return rst_order; }