|
@@ -0,0 +1,647 @@
|
|
|
|
|
+use std::collections::{BTreeMap};
|
|
|
|
|
+use exchanges::bitget_swap_rest::BitgetSwapRest;
|
|
|
|
|
+use std::io::{Error, ErrorKind};
|
|
|
|
|
+use tokio::sync::mpsc::Sender;
|
|
|
|
|
+use std::str::FromStr;
|
|
|
|
|
+use async_trait::async_trait;
|
|
|
|
|
+use rust_decimal::Decimal;
|
|
|
|
|
+use serde_json::{Value};
|
|
|
|
|
+use tokio::time::Instant;
|
|
|
|
|
+use global::trace_stack::TraceStack;
|
|
|
|
|
+use crate::exchange::ExchangeEnum;
|
|
|
|
|
+use crate::{Account, Market, Order, OrderCommand, Platform, Position, Ticker};
|
|
|
|
|
+
|
|
|
|
|
+#[allow(dead_code)]
|
|
|
|
|
+#[derive(Clone)]
|
|
|
|
|
+pub struct BitgetSwap {
|
|
|
|
|
+ exchange: ExchangeEnum,
|
|
|
|
|
+ symbol: String,
|
|
|
|
|
+ is_colo: bool,
|
|
|
|
|
+ params: BTreeMap<String, String>,
|
|
|
|
|
+ request: BitgetSwapRest,
|
|
|
|
|
+ market: Market,
|
|
|
|
|
+ order_sender: Sender<Order>,
|
|
|
|
|
+ error_sender: Sender<Error>,
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+impl BitgetSwap {
|
|
|
|
|
+ pub async fn new(symbol: String, is_colo: bool, params: BTreeMap<String, String>, order_sender: Sender<Order>, error_sender: Sender<Error>) -> BitgetSwap {
|
|
|
|
|
+ let market = Market::new();
|
|
|
|
|
+ let mut bitget_swap = BitgetSwap {
|
|
|
|
|
+ exchange: ExchangeEnum::BitgetSwap,
|
|
|
|
|
+ symbol: symbol.to_uppercase(),
|
|
|
|
|
+ is_colo,
|
|
|
|
|
+ params: params.clone(),
|
|
|
|
|
+ request: BitgetSwapRest::new(is_colo, params.clone()),
|
|
|
|
|
+ market,
|
|
|
|
|
+ order_sender,
|
|
|
|
|
+ error_sender,
|
|
|
|
|
+ };
|
|
|
|
|
+ bitget_swap.market = BitgetSwap::get_market(&mut bitget_swap).await.unwrap_or(bitget_swap.market);
|
|
|
|
|
+ return bitget_swap;
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+#[async_trait]
|
|
|
|
|
+impl Platform for BitgetSwap {
|
|
|
|
|
+ fn clone_box(&self) -> Box<dyn Platform + Send + Sync> { Box::new(self.clone()) }
|
|
|
|
|
+
|
|
|
|
|
+ fn get_self_exchange(&self) -> ExchangeEnum { ExchangeEnum::BitgetSwap }
|
|
|
|
|
+
|
|
|
|
|
+ fn get_self_symbol(&self) -> String { self.symbol.clone() }
|
|
|
|
|
+
|
|
|
|
|
+ fn get_self_is_colo(&self) -> bool { self.is_colo }
|
|
|
|
|
+
|
|
|
|
|
+ fn get_self_params(&self) -> BTreeMap<String, String> { self.params.clone() }
|
|
|
|
|
+
|
|
|
|
|
+ fn get_self_market(&self) -> Market { self.market.clone() }
|
|
|
|
|
+
|
|
|
|
|
+ fn get_request_delays(&self) -> Vec<i64> {
|
|
|
|
|
+ // self.request.get_delays()
|
|
|
|
|
+ vec![]
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ fn get_request_avg_delay(&self) -> Decimal {
|
|
|
|
|
+ // self.request.get_avg_delay()
|
|
|
|
|
+ Decimal::ZERO
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ fn get_request_max_delay(&self) -> i64 { 0 }
|
|
|
|
|
+
|
|
|
|
|
+ async fn get_server_time(&mut self) -> Result<String, Error> {
|
|
|
|
|
+ let res_data = self.request.get_server_time().await;
|
|
|
|
|
+ if res_data.code == "200" {
|
|
|
|
|
+ let res_data_json = res_data.data;
|
|
|
|
|
+ let result = res_data_json["serverTime"].as_str().unwrap().to_string();
|
|
|
|
|
+ Ok(result)
|
|
|
|
|
+ } else {
|
|
|
|
|
+ Err(Error::new(ErrorKind::Other, res_data.to_string()))
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ async fn get_account(&mut self) -> Result<Account, Error> {
|
|
|
|
|
+ Err(Error::new(ErrorKind::NotFound, "bitget_swap:该交易所方法未实现".to_string()))
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ async fn get_spot_account(&mut self) -> Result<Vec<Account>, Error> {
|
|
|
|
|
+ // let res_data = self.request.get_account_assets().await;
|
|
|
|
|
+ // if res_data.code == "200" {
|
|
|
|
|
+ // let res_data_str = &res_data.data;
|
|
|
|
|
+ // let res_data_json: Vec<serde_json::Value> = serde_json::from_str(res_data_str).unwrap();
|
|
|
|
|
+ // let result = res_data_json.iter().map(|item| format_account_info(item.clone())).collect();
|
|
|
|
|
+ // Ok(result)
|
|
|
|
|
+ // } else {
|
|
|
|
|
+ // Err(Error::new(ErrorKind::Other, res_data.to_string()))
|
|
|
|
|
+ // }
|
|
|
|
|
+ Err(Error::new(ErrorKind::NotFound, "bitget_swap:该交易所方法未实现".to_string()))
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ async fn get_position(&mut self) -> Result<Vec<Position>, Error> { Err(Error::new(ErrorKind::NotFound, "bitget_swap:该交易所方法未实现".to_string())) }
|
|
|
|
|
+
|
|
|
|
|
+ async fn get_positions(&mut self) -> Result<Vec<Position>, Error> { Err(Error::new(ErrorKind::NotFound, "bitget_swap:该交易所方法未实现".to_string())) }
|
|
|
|
|
+
|
|
|
|
|
+ async fn get_ticker(&mut self) -> Result<Ticker, Error> {
|
|
|
|
|
+ // let symbol_format = utils::format_symbol(self.symbol.clone(), "");
|
|
|
|
|
+ // let res_data = self.request.get_tickers(symbol_format).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 ticker_info = res_data_json[0].clone();
|
|
|
|
|
+ // let time = (Decimal::from_str(&*ticker_info["ts"].as_str().unwrap()).unwrap() / dec!(1000)).floor().to_i64().unwrap();
|
|
|
|
|
+ // let result = Ticker {
|
|
|
|
|
+ // time,
|
|
|
|
|
+ // high: Decimal::from_str(ticker_info["high24h"].as_str().unwrap()).unwrap(),
|
|
|
|
|
+ // low: Decimal::from_str(ticker_info["low24h"].as_str().unwrap()).unwrap(),
|
|
|
|
|
+ // sell: Decimal::from_str(ticker_info["askPr"].as_str().unwrap()).unwrap(),
|
|
|
|
|
+ // buy: Decimal::from_str(ticker_info["bidPr"].as_str().unwrap()).unwrap(),
|
|
|
|
|
+ // last: Decimal::from_str(ticker_info["lastPr"].as_str().unwrap()).unwrap(),
|
|
|
|
|
+ // volume: Decimal::from_str(ticker_info["quoteVolume"].as_str().unwrap()).unwrap(),
|
|
|
|
|
+ // };
|
|
|
|
|
+ // Ok(result)
|
|
|
|
|
+ // } else {
|
|
|
|
|
+ // Err(Error::new(ErrorKind::Other, res_data.to_string()))
|
|
|
|
|
+ // }
|
|
|
|
|
+ Err(Error::new(ErrorKind::NotFound, "bitget_swap:该交易所方法未实现".to_string()))
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ async fn get_ticker_symbol(&mut self, symbol: String) -> Result<Ticker, Error> {
|
|
|
|
|
+ // let symbol_format = utils::format_symbol(symbol.clone(), "");
|
|
|
|
|
+ // let res_data = self.request.get_tickers(symbol_format).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 ticker_info = res_data_json[0].clone();
|
|
|
|
|
+ // let time = (Decimal::from_str(&*ticker_info["ts"].as_str().unwrap()).unwrap() / dec!(1000)).floor().to_i64().unwrap();
|
|
|
|
|
+ // let result = Ticker {
|
|
|
|
|
+ // time,
|
|
|
|
|
+ // high: Decimal::from_str(ticker_info["high24h"].as_str().unwrap()).unwrap(),
|
|
|
|
|
+ // low: Decimal::from_str(ticker_info["low24h"].as_str().unwrap()).unwrap(),
|
|
|
|
|
+ // sell: Decimal::from_str(ticker_info["askPr"].as_str().unwrap()).unwrap(),
|
|
|
|
|
+ // buy: Decimal::from_str(ticker_info["bidPr"].as_str().unwrap()).unwrap(),
|
|
|
|
|
+ // last: Decimal::from_str(ticker_info["lastPr"].as_str().unwrap()).unwrap(),
|
|
|
|
|
+ // volume: Decimal::from_str(ticker_info["quoteVolume"].as_str().unwrap()).unwrap(),
|
|
|
|
|
+ // };
|
|
|
|
|
+ // Ok(result)
|
|
|
|
|
+ // } else {
|
|
|
|
|
+ // Err(Error::new(ErrorKind::Other, res_data.to_string()))
|
|
|
|
|
+ // }
|
|
|
|
|
+ Err(Error::new(ErrorKind::NotFound, "bitget_swap:该交易所方法未实现".to_string()))
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ async fn get_market(&mut self) -> Result<Market, Error> {
|
|
|
|
|
+ // let symbol_format = utils::format_symbol(self.symbol.clone(), "");
|
|
|
|
|
+ // let res_data = self.request.get_symbols(symbol_format.clone()).await;
|
|
|
|
|
+ // if res_data.code == "200" {
|
|
|
|
|
+ // let res_data_str = &res_data.data;
|
|
|
|
|
+ // let res_data_json: Vec<serde_json::Value> = serde_json::from_str(res_data_str).unwrap();
|
|
|
|
|
+ // let market_info = res_data_json.iter().find(|&item| item["symbol"].as_str().unwrap() == symbol_format.clone());
|
|
|
|
|
+ // match market_info {
|
|
|
|
|
+ // None => {
|
|
|
|
|
+ // error!("bitget_swap:获取Market信息错误!\nget_market:res_data={:?}", res_data);
|
|
|
|
|
+ // Err(Error::new(ErrorKind::Other, res_data.to_string()))
|
|
|
|
|
+ // }
|
|
|
|
|
+ // Some(value) => {
|
|
|
|
|
+ // let base_asset = value["baseCoin"].as_str().unwrap().to_string();
|
|
|
|
|
+ // let quote_asset = value["quoteCoin"].as_str().unwrap().to_string();
|
|
|
|
|
+ // let price_precision = Decimal::from_str(value["pricePrecision"].as_str().unwrap()).unwrap();
|
|
|
|
|
+ // let amount_precision = Decimal::from_str(value["quantityPrecision"].as_str().unwrap()).unwrap();
|
|
|
|
|
+ // let min_qty = Decimal::from_str(&value["minTradeAmount"].as_str().unwrap()).unwrap();
|
|
|
|
|
+ // let max_qty = Decimal::from_str(&value["maxTradeAmount"].as_str().unwrap()).unwrap();
|
|
|
|
|
+ //
|
|
|
|
|
+ // let tick_size = if price_precision > dec!(0) {
|
|
|
|
|
+ // Decimal::from_str(&format!("0.{}1", "0".repeat(usize::try_from(price_precision - dec!(1)).unwrap()))).unwrap()
|
|
|
|
|
+ // } else {
|
|
|
|
|
+ // Decimal::ONE
|
|
|
|
|
+ // };
|
|
|
|
|
+ // let amount_size = if amount_precision > dec!(0) {
|
|
|
|
|
+ // Decimal::from_str(&format!("0.{}1", "0".repeat(usize::try_from(amount_precision - dec!(1)).unwrap()))).unwrap()
|
|
|
|
|
+ // } else {
|
|
|
|
|
+ // Decimal::ONE
|
|
|
|
|
+ // };
|
|
|
|
|
+ //
|
|
|
|
|
+ // let result = Market {
|
|
|
|
|
+ // symbol: format!("{}_{}", base_asset, quote_asset),
|
|
|
|
|
+ // base_asset,
|
|
|
|
|
+ // quote_asset,
|
|
|
|
|
+ // tick_size,
|
|
|
|
|
+ // amount_size,
|
|
|
|
|
+ // price_precision,
|
|
|
|
|
+ // amount_precision,
|
|
|
|
|
+ // min_qty,
|
|
|
|
|
+ // max_qty,
|
|
|
|
|
+ // min_notional: min_qty,
|
|
|
|
|
+ // max_notional: max_qty,
|
|
|
|
|
+ // ct_val: Decimal::ONE,
|
|
|
|
|
+ // };
|
|
|
|
|
+ // Ok(result)
|
|
|
|
|
+ // }
|
|
|
|
|
+ // }
|
|
|
|
|
+ // } else {
|
|
|
|
|
+ // Err(Error::new(ErrorKind::Other, res_data.to_string()))
|
|
|
|
|
+ // }
|
|
|
|
|
+ Err(Error::new(ErrorKind::NotFound, "bitget_swap:该交易所方法未实现".to_string()))
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ async fn get_market_symbol(&mut self, symbol: String) -> Result<Market, Error> {
|
|
|
|
|
+ // let symbol_format = utils::format_symbol(symbol.clone(), "");
|
|
|
|
|
+ // let res_data = self.request.get_symbols(symbol_format.clone()).await;
|
|
|
|
|
+ // if res_data.code == "200" {
|
|
|
|
|
+ // let res_data_str = &res_data.data;
|
|
|
|
|
+ // let res_data_json: Vec<serde_json::Value> = serde_json::from_str(res_data_str).unwrap();
|
|
|
|
|
+ // let market_info = res_data_json.iter().find(|&item| item["symbol"].as_str().unwrap() == symbol_format.clone());
|
|
|
|
|
+ // match market_info {
|
|
|
|
|
+ // None => {
|
|
|
|
|
+ // error!("bitget_swap:获取Market信息错误!\nget_market:res_data={:?}", res_data);
|
|
|
|
|
+ // Err(Error::new(ErrorKind::Other, res_data.to_string()))
|
|
|
|
|
+ // }
|
|
|
|
|
+ // Some(value) => {
|
|
|
|
|
+ // let base_asset = value["baseCoin"].as_str().unwrap().to_string();
|
|
|
|
|
+ // let quote_asset = value["quoteCoin"].as_str().unwrap().to_string();
|
|
|
|
|
+ // let price_precision = Decimal::from_str(value["pricePrecision"].as_str().unwrap()).unwrap();
|
|
|
|
|
+ // let amount_precision = Decimal::from_str(value["quantityPrecision"].as_str().unwrap()).unwrap();
|
|
|
|
|
+ // let min_qty = Decimal::from_str(&value["minTradeAmount"].as_str().unwrap()).unwrap();
|
|
|
|
|
+ // let max_qty = Decimal::from_str(&value["maxTradeAmount"].as_str().unwrap()).unwrap();
|
|
|
|
|
+ //
|
|
|
|
|
+ // let tick_size = if price_precision > dec!(0) {
|
|
|
|
|
+ // Decimal::from_str(&format!("0.{}1", "0".repeat(usize::try_from(price_precision - dec!(1)).unwrap()))).unwrap()
|
|
|
|
|
+ // } else {
|
|
|
|
|
+ // Decimal::ONE
|
|
|
|
|
+ // };
|
|
|
|
|
+ // let amount_size = if amount_precision > dec!(0) {
|
|
|
|
|
+ // Decimal::from_str(&format!("0.{}1", "0".repeat(usize::try_from(amount_precision - dec!(1)).unwrap()))).unwrap()
|
|
|
|
|
+ // } else {
|
|
|
|
|
+ // Decimal::ONE
|
|
|
|
|
+ // };
|
|
|
|
|
+ //
|
|
|
|
|
+ // let result = Market {
|
|
|
|
|
+ // symbol: format!("{}_{}", base_asset, quote_asset),
|
|
|
|
|
+ // base_asset,
|
|
|
|
|
+ // quote_asset,
|
|
|
|
|
+ // tick_size,
|
|
|
|
|
+ // amount_size,
|
|
|
|
|
+ // price_precision,
|
|
|
|
|
+ // amount_precision,
|
|
|
|
|
+ // min_qty,
|
|
|
|
|
+ // max_qty,
|
|
|
|
|
+ // min_notional: min_qty,
|
|
|
|
|
+ // max_notional: max_qty,
|
|
|
|
|
+ // ct_val: Decimal::ONE,
|
|
|
|
|
+ // };
|
|
|
|
|
+ // Ok(result)
|
|
|
|
|
+ // }
|
|
|
|
|
+ // }
|
|
|
|
|
+ // } else {
|
|
|
|
|
+ // Err(Error::new(ErrorKind::Other, res_data.to_string()))
|
|
|
|
|
+ // }
|
|
|
|
|
+ Err(Error::new(ErrorKind::NotFound, "bitget_swap:该交易所方法未实现".to_string()))
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ async fn get_order_detail(&mut self, order_id: &str, custom_id: &str) -> Result<Order, Error> {
|
|
|
|
|
+ Err(Error::new(ErrorKind::NotFound, "bitget_swap:该交易所方法未实现".to_string()))
|
|
|
|
|
+ // let ct_val = self.market.ct_val;
|
|
|
|
|
+ // let res_data = self.request.get_order(order_id.to_string(), custom_id.to_string()).await;
|
|
|
|
|
+ // if res_data.code == "200" {
|
|
|
|
|
+ // let res_data_str = &res_data.data;
|
|
|
|
|
+ // let res_data_json: Vec<serde_json::Value> = serde_json::from_str(res_data_str).unwrap();
|
|
|
|
|
+ // if res_data_json.len() == 0 {
|
|
|
|
|
+ // Err(Error::new(ErrorKind::Other, res_data.to_string()))
|
|
|
|
|
+ // } else {
|
|
|
|
|
+ // let order_info = res_data_json[0].clone();
|
|
|
|
|
+ // let result = format_order_item(order_info, ct_val);
|
|
|
|
|
+ // Ok(result)
|
|
|
|
|
+ // }
|
|
|
|
|
+ // } else {
|
|
|
|
|
+ // Err(Error::new(ErrorKind::Other, res_data.to_string()))
|
|
|
|
|
+ // }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ async fn get_orders_list(&mut self, _status: &str) -> Result<Vec<Order>, Error> {
|
|
|
|
|
+ Err(Error::new(ErrorKind::NotFound, "bitget_swap:该交易所方法未实现".to_string()))
|
|
|
|
|
+ // let symbol_format = utils::format_symbol(self.symbol.clone(), "");
|
|
|
|
|
+ // let ct_val = self.market.ct_val;
|
|
|
|
|
+ // let res_data = self.request.get_unfilled_orders(symbol_format.to_string(), "".to_string(), "".to_string(), "".to_string(), "100".to_string(), "".to_string()).await;
|
|
|
|
|
+ // if res_data.code == "200" {
|
|
|
|
|
+ // let res_data_str = &res_data.data;
|
|
|
|
|
+ // let res_data_json: Vec<serde_json::Value> = serde_json::from_str(res_data_str).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 take_order(&mut self, custom_id: &str, origin_side: &str, price: Decimal, amount: Decimal) -> Result<Order, Error> {
|
|
|
|
|
+ Err(Error::new(ErrorKind::NotFound, "bitget_swap:该交易所方法未实现".to_string()))
|
|
|
|
|
+ // let symbol_format = utils::format_symbol(self.symbol.clone(), "");
|
|
|
|
|
+ // let mut params = json!({
|
|
|
|
|
+ // "symbol": symbol_format.to_string(),
|
|
|
|
|
+ // "clientOid": custom_id,
|
|
|
|
|
+ // "price": price.to_string(),
|
|
|
|
|
+ // });
|
|
|
|
|
+ // if price.eq(&Decimal::ZERO) {
|
|
|
|
|
+ // params["orderType"] = json!("market");
|
|
|
|
|
+ // params["force"] = json!("post_only");
|
|
|
|
|
+ // } else {
|
|
|
|
|
+ // params["orderType"] = json!("limit");
|
|
|
|
|
+ // params["force"] = json!("gtc");
|
|
|
|
|
+ // };
|
|
|
|
|
+ // params["size"] = json!(amount);
|
|
|
|
|
+ // match origin_side {
|
|
|
|
|
+ // "kd" => {
|
|
|
|
|
+ // params["side"] = json!("buy");
|
|
|
|
|
+ // }
|
|
|
|
|
+ // "pd" => {
|
|
|
|
|
+ // params["side"] = json!("sell");
|
|
|
|
|
+ // }
|
|
|
|
|
+ // "kk" => {
|
|
|
|
|
+ // params["side"] = json!("sell");
|
|
|
|
|
+ // }
|
|
|
|
|
+ // "pk" => {
|
|
|
|
|
+ // params["side"] = json!("buy");
|
|
|
|
|
+ // }
|
|
|
|
|
+ // _ => { error!("下单参数错误"); }
|
|
|
|
|
+ // };
|
|
|
|
|
+ // let res_data = self.request.spot_order(params).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 = Order {
|
|
|
|
|
+ // id: res_data_json["orderId"].as_str().unwrap().to_string(),
|
|
|
|
|
+ // custom_id: res_data_json["clientOid"].as_str().unwrap().to_string(),
|
|
|
|
|
+ // price: Decimal::ZERO,
|
|
|
|
|
+ // amount: Decimal::ZERO,
|
|
|
|
|
+ // deal_amount: Decimal::ZERO,
|
|
|
|
|
+ // avg_price: Decimal::ZERO,
|
|
|
|
|
+ // status: "NEW".to_string(),
|
|
|
|
|
+ // order_type: "".to_string(),
|
|
|
|
|
+ // trace_stack: TraceStack::new(0, Instant::now()).on_special("328 bitget_swap".to_string()),
|
|
|
|
|
+ // };
|
|
|
|
|
+ // 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<Order, Error> {
|
|
|
|
|
+ Err(Error::new(ErrorKind::NotFound, "bitget_swap:该交易所方法未实现".to_string()))
|
|
|
|
|
+ // let symbol_format = utils::format_symbol(symbol.clone(), "");
|
|
|
|
|
+ // let mut params = json!({
|
|
|
|
|
+ // "symbol": symbol_format.to_string(),
|
|
|
|
|
+ // "clientOid": custom_id,
|
|
|
|
|
+ // "price": price.to_string(),
|
|
|
|
|
+ // });
|
|
|
|
|
+ // if price.eq(&Decimal::ZERO) {
|
|
|
|
|
+ // params["orderType"] = json!("market");
|
|
|
|
|
+ // params["force"] = json!("post_only");
|
|
|
|
|
+ // } else {
|
|
|
|
|
+ // params["orderType"] = json!("limit");
|
|
|
|
|
+ // params["force"] = json!("gtc");
|
|
|
|
|
+ // };
|
|
|
|
|
+ // let size = (amount / ct_val).floor();
|
|
|
|
|
+ // params["size"] = json!(size);
|
|
|
|
|
+ // match origin_side {
|
|
|
|
|
+ // "kd" => {
|
|
|
|
|
+ // params["side"] = json!("buy");
|
|
|
|
|
+ // }
|
|
|
|
|
+ // "pd" => {
|
|
|
|
|
+ // params["side"] = json!("sell");
|
|
|
|
|
+ // }
|
|
|
|
|
+ // "kk" => {
|
|
|
|
|
+ // params["side"] = json!("sell");
|
|
|
|
|
+ // }
|
|
|
|
|
+ // "pk" => {
|
|
|
|
|
+ // params["side"] = json!("buy");
|
|
|
|
|
+ // }
|
|
|
|
|
+ // _ => { error!("下单参数错误"); }
|
|
|
|
|
+ // };
|
|
|
|
|
+ // let res_data = self.request.spot_order(params).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 = Order {
|
|
|
|
|
+ // id: res_data_json["orderId"].as_str().unwrap().to_string(),
|
|
|
|
|
+ // custom_id: res_data_json["clientOid"].as_str().unwrap().to_string(),
|
|
|
|
|
+ // price: Decimal::ZERO,
|
|
|
|
|
+ // amount: Decimal::ZERO,
|
|
|
|
|
+ // deal_amount: Decimal::ZERO,
|
|
|
|
|
+ // avg_price: Decimal::ZERO,
|
|
|
|
|
+ // status: "NEW".to_string(),
|
|
|
|
|
+ // order_type: "".to_string(),
|
|
|
|
|
+ // trace_stack: TraceStack::new(0, Instant::now()).on_special("380 bitget_swap".to_string()),
|
|
|
|
|
+ // };
|
|
|
|
|
+ // 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<Order, Error> {
|
|
|
|
|
+ Err(Error::new(ErrorKind::NotFound, "bitget_swap:该交易所方法未实现".to_string()))
|
|
|
|
|
+ // let symbol_format = utils::format_symbol(self.symbol.clone(), "");
|
|
|
|
|
+ // let res_data = self.request.spot_cancel_order(symbol_format.clone(), order_id.to_string(), custom_id.to_string()).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 = Order {
|
|
|
|
|
+ // id: res_data_json["orderId"].as_str().unwrap().to_string(),
|
|
|
|
|
+ // custom_id: res_data_json["clientOid"].as_str().unwrap().to_string(),
|
|
|
|
|
+ // price: Decimal::ZERO,
|
|
|
|
|
+ // amount: Decimal::ZERO,
|
|
|
|
|
+ // deal_amount: Decimal::ZERO,
|
|
|
|
|
+ // avg_price: Decimal::ZERO,
|
|
|
|
|
+ // status: "REMOVE".to_string(),
|
|
|
|
|
+ // order_type: "".to_string(),
|
|
|
|
|
+ // trace_stack: TraceStack::new(0, Instant::now()).on_special("403 bitget_swap".to_string()),
|
|
|
|
|
+ // };
|
|
|
|
|
+ // Ok(result)
|
|
|
|
|
+ // } else {
|
|
|
|
|
+ // Err(Error::new(ErrorKind::Other, res_data.to_string()))
|
|
|
|
|
+ // }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ async fn cancel_orders(&mut self) -> Result<Vec<Order>, Error> {
|
|
|
|
|
+ // let symbol_format = utils::format_symbol(self.symbol.clone(), "");
|
|
|
|
|
+ // let orders_res_data = self.request.get_unfilled_orders(symbol_format.to_string(), "".to_string(), "".to_string(), "".to_string(), "100".to_string(), "".to_string()).await;
|
|
|
|
|
+ // if orders_res_data.code == "200" {
|
|
|
|
|
+ // let mut result = vec![];
|
|
|
|
|
+ // let orders_res_data_str = &orders_res_data.data;
|
|
|
|
|
+ // let orders_res_data_json: Vec<serde_json::Value> = serde_json::from_str(orders_res_data_str).unwrap();
|
|
|
|
|
+ // for order in orders_res_data_json {
|
|
|
|
|
+ // let order_id = order["orderId"].as_str().unwrap().to_string();
|
|
|
|
|
+ // let cancel_res_data = self.request.spot_cancel_order(symbol_format.clone(), order_id, "".to_string()).await;
|
|
|
|
|
+ // if cancel_res_data.code == "200" {
|
|
|
|
|
+ // let cancel_res_data_str = &cancel_res_data.data;
|
|
|
|
|
+ // let cancel_res_data_json: serde_json::Value = serde_json::from_str(cancel_res_data_str).unwrap();
|
|
|
|
|
+ // result.push(Order {
|
|
|
|
|
+ // id: cancel_res_data_json["orderId"].as_str().unwrap().to_string(),
|
|
|
|
|
+ // custom_id: cancel_res_data_json["clientOid"].as_str().unwrap().to_string(),
|
|
|
|
|
+ // price: Decimal::ZERO,
|
|
|
|
|
+ // amount: Decimal::ZERO,
|
|
|
|
|
+ // deal_amount: Decimal::ZERO,
|
|
|
|
|
+ // avg_price: Decimal::ZERO,
|
|
|
|
|
+ // status: "REMOVE".to_string(),
|
|
|
|
|
+ // order_type: "".to_string(),
|
|
|
|
|
+ // trace_stack: TraceStack::new(0, Instant::now()).on_special("434 bitget_swap".to_string()),
|
|
|
|
|
+ // });
|
|
|
|
|
+ // } 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()))
|
|
|
|
|
+ // }
|
|
|
|
|
+ Err(Error::new(ErrorKind::NotFound, "bitget_swap:该交易所方法未实现".to_string()))
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ async fn cancel_orders_all(&mut self) -> Result<Vec<Order>, Error> {
|
|
|
|
|
+ Err(Error::new(ErrorKind::NotFound, "bitget_swap:该交易所方法未实现".to_string()))
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ async fn take_stop_loss_order(&mut self, stop_price: Decimal, price: Decimal, side: &str) -> Result<Value, Error> {
|
|
|
|
|
+ Err(Error::new(ErrorKind::NotFound, "bitget_swap:该交易所方法未实现".to_string()))
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ async fn cancel_stop_loss_order(&mut self, order_id: &str) -> Result<Value, Error> {
|
|
|
|
|
+ Err(Error::new(ErrorKind::NotFound, "bitget_swap:该交易所方法未实现".to_string()))
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ async fn set_dual_mode(&mut self, _coin: &str, _is_dual_mode: bool) -> Result<String, Error> {
|
|
|
|
|
+ Err(Error::new(ErrorKind::NotFound, "bitget_swap:该交易所方法未实现".to_string()))
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ async fn set_dual_leverage(&mut self, _leverage: &str) -> Result<String, Error> {
|
|
|
|
|
+ Err(Error::new(ErrorKind::NotFound, "bitget_swap:该交易所方法未实现".to_string()))
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ async fn set_auto_deposit_status(&mut self, _status: bool) -> Result<String, Error> {
|
|
|
|
|
+ Err(Error::new(ErrorKind::NotFound, "bitget_swap:该交易所方法未实现".to_string()))
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ async fn wallet_transfers(&mut self, coin: &str, from: &str, to: &str, amount: Decimal) -> Result<String, Error> {
|
|
|
|
|
+ Err(Error::new(ErrorKind::NotFound, "bitget_swap:该交易所方法未实现".to_string()))
|
|
|
|
|
+ // let coin_format = coin.to_string().to_uppercase();
|
|
|
|
|
+ // let res_data = self.request.wallet_transfer(from.to_string(), to.to_string(), amount.to_string(), coin_format.clone(), "".to_string(), "".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.to_string()))
|
|
|
|
|
+ // }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ async fn command_order(&mut self, order_command: &mut OrderCommand, trace_stack: &TraceStack) {
|
|
|
|
|
+ // let mut handles = vec![];
|
|
|
|
|
+ // // 撤销订单
|
|
|
|
|
+ // let cancel = order_command.cancel;
|
|
|
|
|
+ // for item in cancel.keys() {
|
|
|
|
|
+ // let mut self_clone = self.clone();
|
|
|
|
|
+ // let cancel_clone = cancel.clone();
|
|
|
|
|
+ // let item_clone = item.clone();
|
|
|
|
|
+ // let order_id = cancel_clone[&item_clone].get(1).unwrap_or(&"".to_string()).clone();
|
|
|
|
|
+ // let custom_id = cancel_clone[&item_clone].get(0).unwrap_or(&"".to_string()).clone();
|
|
|
|
|
+ // let result_sd = self.order_sender.clone();
|
|
|
|
|
+ // let err_sd = self.error_sender.clone();
|
|
|
|
|
+ // let handle = tokio::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) => {
|
|
|
|
|
+ // result_sd.send(order).await.unwrap();
|
|
|
|
|
+ // }
|
|
|
|
|
+ // Err(_query_err) => {
|
|
|
|
|
+ // // error!(?_query_err);
|
|
|
|
|
+ // // error!("撤单失败,而且查单也失败了,bitget_swap,oid={}, cid={}。", order_id.clone(), custom_id.clone());
|
|
|
|
|
+ // }
|
|
|
|
|
+ // }
|
|
|
|
|
+ // err_sd.send(error).await.unwrap();
|
|
|
|
|
+ // }
|
|
|
|
|
+ // }
|
|
|
|
|
+ // });
|
|
|
|
|
+ // handles.push(handle)
|
|
|
|
|
+ // }
|
|
|
|
|
+ // // 下单指令
|
|
|
|
|
+ // let mut limits = HashMap::new();
|
|
|
|
|
+ // limits.extend(order_command.limits_open);
|
|
|
|
|
+ // limits.extend(order_command.limits_close);
|
|
|
|
|
+ // for item in limits.keys() {
|
|
|
|
|
+ // let mut self_clone = self.clone();
|
|
|
|
|
+ // let limits_clone = limits.clone();
|
|
|
|
|
+ // let item_clone = item.clone();
|
|
|
|
|
+ // let result_sd = self.order_sender.clone();
|
|
|
|
|
+ // let err_sd = self.error_sender.clone();
|
|
|
|
|
+ // let ts = trace_stack.clone();
|
|
|
|
|
+ //
|
|
|
|
|
+ // let handle = tokio::spawn(async move {
|
|
|
|
|
+ // let value = limits_clone[&item_clone].clone();
|
|
|
|
|
+ // let amount = Decimal::from_str(value.get(0).unwrap_or(&"0".to_string())).unwrap();
|
|
|
|
|
+ // let side = value.get(1).unwrap();
|
|
|
|
|
+ // let price = Decimal::from_str(value.get(2).unwrap_or(&"0".to_string())).unwrap();
|
|
|
|
|
+ // let cid = value.get(3).unwrap();
|
|
|
|
|
+ //
|
|
|
|
|
+ // // order_name: [数量,方向,价格,c_id]
|
|
|
|
|
+ // let result = self_clone.take_order(cid, side, price, amount).await;
|
|
|
|
|
+ // match result {
|
|
|
|
|
+ // Ok(mut result) => {
|
|
|
|
|
+ // // 记录此订单完成时间
|
|
|
|
|
+ // // ts.on_after_send();
|
|
|
|
|
+ // result.trace_stack = ts;
|
|
|
|
|
+ //
|
|
|
|
|
+ // result_sd.send(result).await.unwrap();
|
|
|
|
|
+ // }
|
|
|
|
|
+ // Err(error) => {
|
|
|
|
|
+ // let mut err_order = Order::new();
|
|
|
|
|
+ // err_order.custom_id = cid.clone();
|
|
|
|
|
+ // err_order.status = "REMOVE".to_string();
|
|
|
|
|
+ //
|
|
|
|
|
+ // result_sd.send(err_order).await.unwrap();
|
|
|
|
|
+ // err_sd.send(error).await.unwrap();
|
|
|
|
|
+ // }
|
|
|
|
|
+ // }
|
|
|
|
|
+ // });
|
|
|
|
|
+ // handles.push(handle)
|
|
|
|
|
+ // }
|
|
|
|
|
+ // // 检查订单指令
|
|
|
|
|
+ // let check = order_command.check;
|
|
|
|
|
+ // for item in check.keys() {
|
|
|
|
|
+ // let mut self_clone = self.clone();
|
|
|
|
|
+ // let check_clone = check.clone();
|
|
|
|
|
+ // let item_clone = item.clone();
|
|
|
|
|
+ // let order_id = check_clone[&item_clone].get(1).unwrap_or(&"".to_string()).clone();
|
|
|
|
|
+ // let custom_id = check_clone[&item_clone].get(0).unwrap_or(&"".to_string()).clone();
|
|
|
|
|
+ // let result_sd = self.order_sender.clone();
|
|
|
|
|
+ // let err_sd = self.error_sender.clone();
|
|
|
|
|
+ // let handle = tokio::spawn(async move {
|
|
|
|
|
+ // let result = self_clone.get_order_detail(&order_id, &custom_id).await;
|
|
|
|
|
+ // match result {
|
|
|
|
|
+ // Ok(result) => {
|
|
|
|
|
+ // result_sd.send(result).await.unwrap();
|
|
|
|
|
+ // }
|
|
|
|
|
+ // Err(error) => {
|
|
|
|
|
+ // err_sd.send(error).await.unwrap();
|
|
|
|
|
+ // }
|
|
|
|
|
+ // }
|
|
|
|
|
+ // });
|
|
|
|
|
+ // handles.push(handle)
|
|
|
|
|
+ // }
|
|
|
|
|
+ //
|
|
|
|
|
+ // let futures = FuturesUnordered::from_iter(handles);
|
|
|
|
|
+ // let _: Result<Vec<_>, _> = futures.try_collect().await;
|
|
|
|
|
+
|
|
|
|
|
+ panic!("bitget_swap:该交易所方法未实现")
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+pub fn format_account_info(balance_data: serde_json::Value) -> Account {
|
|
|
|
|
+ let balance_coin = balance_data["coin"].as_str().unwrap().to_string().to_uppercase();
|
|
|
|
|
+ let available_balance = Decimal::from_str(balance_data["available"].as_str().unwrap()).unwrap();
|
|
|
|
|
+ let frozen_balance = Decimal::from_str(balance_data["frozen"].as_str().unwrap()).unwrap();
|
|
|
|
|
+ let balance = available_balance + frozen_balance;
|
|
|
|
|
+
|
|
|
|
|
+ Account {
|
|
|
|
|
+ coin: balance_coin,
|
|
|
|
|
+ balance,
|
|
|
|
|
+ available_balance,
|
|
|
|
|
+ frozen_balance,
|
|
|
|
|
+ stocks: Decimal::ZERO,
|
|
|
|
|
+ available_stocks: Decimal::ZERO,
|
|
|
|
|
+ frozen_stocks: Decimal::ZERO,
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+pub fn format_order_item(order: serde_json::Value, ct_val: Decimal) -> Order {
|
|
|
|
|
+ let price = Decimal::from_str(order["price"].as_str().unwrap_or(order["priceAvg"].as_str().unwrap())).unwrap();
|
|
|
|
|
+ let size = Decimal::from_str(order["size"].as_str().unwrap()).unwrap();
|
|
|
|
|
+ let status = order["status"].as_str().unwrap_or("");
|
|
|
|
|
+ let base_volume = Decimal::from_str(order["baseVolume"].as_str().unwrap()).unwrap();
|
|
|
|
|
+
|
|
|
|
|
+ let avg_price = Decimal::from_str(order["priceAvg"].as_str().unwrap()).unwrap();
|
|
|
|
|
+
|
|
|
|
|
+ let amount = size * ct_val;
|
|
|
|
|
+ let deal_amount = base_volume * ct_val;
|
|
|
|
|
+ let custom_status = if ["filled", "cancelled"].contains(&status) {
|
|
|
|
|
+ "REMOVE".to_string()
|
|
|
|
|
+ } else if ["init", "live", "new", "partially_filled"].contains(&status) {
|
|
|
|
|
+ "NEW".to_string()
|
|
|
|
|
+ } else {
|
|
|
|
|
+ "NULL".to_string()
|
|
|
|
|
+ };
|
|
|
|
|
+ Order {
|
|
|
|
|
+ id: order["orderId"].as_str().unwrap().to_string(),
|
|
|
|
|
+ custom_id: order["clientOid"].as_str().unwrap().to_string(),
|
|
|
|
|
+ price,
|
|
|
|
|
+ amount,
|
|
|
|
|
+ deal_amount,
|
|
|
|
|
+ avg_price,
|
|
|
|
|
+ status: custom_status,
|
|
|
|
|
+ order_type: order["orderType"].as_str().unwrap().to_string(),
|
|
|
|
|
+ trace_stack: TraceStack::new(0, Instant::now()).on_special("622 bitget_swap".to_string()),
|
|
|
|
|
+ }
|
|
|
|
|
+}
|