use std::collections::BTreeMap; use std::io::{Error, ErrorKind}; use std::result::Result; use std::str::FromStr; use async_trait::async_trait; use rust_decimal::Decimal; use rust_decimal::prelude::FromPrimitive; use rust_decimal_macros::dec; use serde_json::Value; use tokio::sync::mpsc::Sender; use tracing::{error}; use crate::{Platform, ExchangeEnum, Account, Position, Ticker, Market, Order, utils, PositionModeEnum}; use exchanges::binance_swap_rest::BinanceSwapRest; #[allow(dead_code)] #[derive(Clone)] pub struct BinanceSwap { exchange: ExchangeEnum, symbol: String, is_colo: bool, params: BTreeMap, request: BinanceSwapRest, market: Market, order_sender: Sender, error_sender: Sender, } impl BinanceSwap { pub async fn new(symbol: String, is_colo: bool, params: BTreeMap, order_sender: Sender, error_sender: Sender) -> BinanceSwap { let market = Market::new(); let mut binance_swap = BinanceSwap { exchange: ExchangeEnum::BinanceSwap, symbol: symbol.to_uppercase(), is_colo, params: params.clone(), request: BinanceSwapRest::new(is_colo, params.clone()), market, order_sender, error_sender, }; binance_swap.market = BinanceSwap::get_market(&mut binance_swap).await.unwrap_or(binance_swap.market); return binance_swap; } } #[async_trait] impl Platform for BinanceSwap { // 克隆方法 fn clone_box(&self) -> Box { Box::new(self.clone()) } // 获取交易所模式 fn get_self_exchange(&self) -> ExchangeEnum { ExchangeEnum::BinanceSwap } // 获取交易对 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 = res_data.data; let result = res_data_json["serverTime"].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().await; if res_data.code == 200 { let res_data_json = res_data.data.as_array().unwrap(); let balance_info = res_data_json.iter().find(|item| item["asset"].as_str().unwrap().to_string() == symbol_array[1].to_string()); match balance_info { None => { error!("binance_swap:格式化账号信息错误!\nget_account: res_data={:?}", res_data); Err(Error::new(ErrorKind::Other, res_data.to_string())) } Some(value) => { let balance = Decimal::from_str(value["balance"].as_str().unwrap()).unwrap(); let available_balance = Decimal::from_str(value["availableBalance"].as_str().unwrap()).unwrap(); let frozen_balance = balance - available_balance; let result = Account { coin: value["asset"].as_str().unwrap().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, "binance_swap:该交易所方法未实现".to_string())) } // 获取仓位信息 async fn get_position(&mut self) -> Result, Error> { let symbol_format = utils::format_symbol(self.symbol.clone(), ""); let ct_val = self.market.ct_val; let res_data = self.request.get_position_risk(symbol_format).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 res_data = self.request.get_position_risk("".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_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_format = utils::format_symbol(self.symbol.clone(), ""); let res_data = self.request.get_book_ticker(symbol_format).await; if res_data.code == 200 { let res_data_json: serde_json::Value = res_data.data; let result = Ticker { time: res_data_json["time"].as_i64().unwrap(), high: Decimal::from_str(res_data_json["askPrice"].as_str().unwrap()).unwrap(), low: Decimal::from_str(res_data_json["bidPrice"].as_str().unwrap()).unwrap(), sell: Decimal::from_str(res_data_json["askPrice"].as_str().unwrap()).unwrap(), buy: Decimal::from_str(res_data_json["bidPrice"].as_str().unwrap()).unwrap(), last: dec!(-1), volume: dec!(-1), }; Ok(result) } else { Err(Error::new(ErrorKind::Other, res_data.to_string())) } } async fn get_ticker_symbol(&mut self, symbol: String) -> Result { let symbol_format = utils::format_symbol(symbol.clone(), ""); let res_data = self.request.get_book_ticker(symbol_format).await; if res_data.code == 200 { let res_data_json: serde_json::Value = res_data.data; let result = Ticker { time: res_data_json["time"].as_i64().unwrap(), high: Decimal::from_str(res_data_json["askPrice"].as_str().unwrap()).unwrap(), low: Decimal::from_str(res_data_json["bidPrice"].as_str().unwrap()).unwrap(), sell: Decimal::from_str(res_data_json["askPrice"].as_str().unwrap()).unwrap(), buy: Decimal::from_str(res_data_json["bidPrice"].as_str().unwrap()).unwrap(), last: dec!(-1), volume: dec!(-1), }; Ok(result) } else { Err(Error::new(ErrorKind::Other, res_data.to_string())) } } async fn get_market(&mut self) -> Result { let symbol_format = utils::format_symbol(self.symbol.clone(), ""); let res_data = self.request.get_exchange_info().await; if res_data.code == 200 { let res_data_json = res_data.data; let symbols = res_data_json["symbols"].as_array().unwrap(); let market_info = symbols.iter().find(|&item| item["symbol"].as_str().unwrap() == symbol_format); match market_info { None => { error!("binance_swap:获取Market信息错误!\nget_market:res_data={:?}", res_data_json); Err(Error::new(ErrorKind::Other, res_data_json.to_string())) } Some(value) => { let base_asset = value["baseAsset"].as_str().unwrap_or("").to_string(); let quote_asset = value["quoteAsset"].as_str().unwrap_or("").to_string(); let filter_array = value["filters"].as_array().unwrap().clone(); let price_filter = filter_array.iter().find(|&item| item["filterType"].as_str().unwrap() == "PRICE_FILTER").unwrap(); let lot_size_filter = filter_array.iter().find(|&item| item["filterType"].as_str().unwrap() == "LOT_SIZE").unwrap(); let result = Market { symbol: format!("{}_{}", base_asset, quote_asset), base_asset, quote_asset, tick_size: Decimal::from_str(&price_filter["tickSize"].as_str().unwrap()).unwrap(), amount_size: Decimal::from_str(lot_size_filter["stepSize"].as_str().unwrap()).unwrap(), price_precision: Decimal::from_f64(value["pricePrecision"].as_f64().unwrap()).unwrap(), amount_precision: Decimal::from_f64(value["quantityPrecision"].as_f64().unwrap()).unwrap(), min_qty: Decimal::from_str(lot_size_filter["minQty"].as_str().unwrap()).unwrap(), max_qty: Decimal::from_str(lot_size_filter["maxQty"].as_str().unwrap()).unwrap(), min_notional: Decimal::from_str(price_filter["minPrice"].as_str().unwrap()).unwrap(), max_notional: Decimal::from_str(price_filter["maxPrice"].as_str().unwrap()).unwrap(), ct_val: Decimal::ONE, }; Ok(result) } } } else { Err(Error::new(ErrorKind::Other, res_data.to_string())) } } async fn get_market_symbol(&mut self, symbol: String) -> Result { let symbol_format = utils::format_symbol(symbol.clone(), ""); let res_data = self.request.get_exchange_info().await; if res_data.code == 200 { let res_data_json: serde_json::Value = res_data.data; let symbols = res_data_json["symbols"].as_array().unwrap(); let market_info = symbols.iter().find(|&item| item["symbol"].as_str().unwrap() == symbol_format); match market_info { None => { error!("binance_swap:获取Market信息错误!\nget_market:res_data={:?}", res_data_json); Err(Error::new(ErrorKind::Other, res_data_json.to_string())) } Some(value) => { let base_asset = value["baseAsset"].as_str().unwrap_or("").to_string(); let quote_asset = value["quoteAsset"].as_str().unwrap_or("").to_string(); let filter_array = value["filters"].as_array().unwrap().clone(); let price_filter = filter_array.iter().find(|&item| item["filterType"].as_str().unwrap() == "PRICE_FILTER").unwrap(); let lot_size_filter = filter_array.iter().find(|&item| item["filterType"].as_str().unwrap() == "LOT_SIZE").unwrap(); let result = Market { symbol: format!("{}_{}", base_asset, quote_asset), base_asset, quote_asset, tick_size: Decimal::from_str(&price_filter["tickSize"].as_str().unwrap()).unwrap(), amount_size: Decimal::from_str(lot_size_filter["stepSize"].as_str().unwrap()).unwrap(), price_precision: Decimal::from_f64(value["pricePrecision"].as_f64().unwrap()).unwrap(), amount_precision: Decimal::from_f64(value["quantityPrecision"].as_f64().unwrap()).unwrap(), min_qty: Decimal::from_str(lot_size_filter["minQty"].as_str().unwrap()).unwrap(), max_qty: Decimal::from_str(lot_size_filter["maxQty"].as_str().unwrap()).unwrap(), min_notional: Decimal::from_str(price_filter["minPrice"].as_str().unwrap()).unwrap(), max_notional: Decimal::from_str(price_filter["maxPrice"].as_str().unwrap()).unwrap(), ct_val: Decimal::ONE, }; 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_format = utils::format_symbol(self.symbol.clone(), ""); let res_data = self.request.get_order(symbol_format, order_id.parse().unwrap_or(-1), custom_id.to_string()).await; if res_data.code == 200 { let res_data_json: serde_json::Value = res_data.data; let status = res_data_json["status"].as_str().unwrap(); let custom_status = if ["CANCELED", "EXPIRED", "FILLED"].contains(&status) { "REMOVE".to_string() } else if status == "NEW" { "NEW".to_string() } else { error!("binance_swap:格式化订单状态错误!\nget_order_detail:res_data={:?}", res_data_json); panic!("binance_swap:格式化订单状态错误!\nget_order_detail:res_data={:?}", res_data_json) }; let result = Order { id: res_data_json["orderId"].to_string(), custom_id: res_data_json["clientOrderId"].as_str().unwrap().parse().unwrap(), price: Decimal::from_str(res_data_json["price"].as_str().unwrap()).unwrap(), amount: Decimal::from_str(res_data_json["origQty"].as_str().unwrap()).unwrap(), deal_amount: Decimal::from_str(res_data_json["executedQty"].as_str().unwrap()).unwrap(), avg_price: Decimal::from_str(res_data_json["avgPrice"].as_str().unwrap()).unwrap(), status: custom_status, order_type: res_data_json["type"].as_str().unwrap().parse().unwrap() }; 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_format = utils::format_symbol(self.symbol.clone(), ""); let res_data = self.request.get_open_orders(symbol_format).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| { let status = item["status"].as_str().unwrap(); let custom_status = if ["CANCELED", "EXPIRED", "FILLED"].contains(&status) { "REMOVE".to_string() } else if status == "NEW" { "NEW".to_string() } else { error!("binance_swap:格式化订单状态错误!\nget_order_detail:res_data={:?}", res_data); panic!("binance_swap:格式化订单状态错误!\nget_order_detail:res_data={:?}", res_data) }; Order { id: item["orderId"].to_string(), custom_id: item["clientOrderId"].as_str().unwrap().parse().unwrap(), price: Decimal::from_str(item["price"].as_str().unwrap()).unwrap(), amount: Decimal::from_str(item["origQty"].as_str().unwrap()).unwrap(), deal_amount: Decimal::from_str(item["executedQty"].as_str().unwrap()).unwrap(), avg_price: Decimal::from_str(item["avgPrice"].as_str().unwrap()).unwrap(), status: custom_status, order_type: item["type"].as_str().unwrap().parse().unwrap() } }).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 { Err(Error::new(ErrorKind::NotFound, "binance_swap:该交易所方法未实现".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 { Err(Error::new(ErrorKind::NotFound, "binance_swap:该交易所方法未实现".to_string())) } async fn cancel_order(&mut self, _order_id: &str, _custom_id: &str) -> Result { Err(Error::new(ErrorKind::NotFound, "binance_swap:该交易所方法未实现".to_string())) } async fn cancel_orders(&mut self) -> Result, Error> { Err(Error::new(ErrorKind::NotFound, "binance_swap:该交易所方法未实现".to_string())) } async fn cancel_orders_all(&mut self) -> Result, Error> { Err(Error::new(ErrorKind::NotFound, "binance_swap:该交易所方法未实现".to_string())) } async fn take_stop_loss_order(&mut self, _stop_price: Decimal, _price: Decimal, _side: &str) -> Result { Err(Error::new(ErrorKind::NotFound, "binance_swap:该交易所方法未实现".to_string())) } async fn cancel_stop_loss_order(&mut self, _order_id: &str) -> Result { Err(Error::new(ErrorKind::NotFound, "binance_swap:该交易所方法未实现".to_string())) } async fn set_dual_mode(&mut self, _coin: &str, _is_dual_mode: bool) -> Result { Err(Error::new(ErrorKind::NotFound, "binance_swap:该交易所方法未实现".to_string())) } async fn set_dual_leverage(&mut self, _leverage: &str) -> Result { Err(Error::new(ErrorKind::NotFound, "binance_swap:该交易所方法未实现".to_string())) } async fn set_auto_deposit_status(&mut self, _status: bool) -> Result { Err(Error::new(ErrorKind::NotFound, "binance_swap:该交易所方法未实现".to_string())) } async fn wallet_transfers(&mut self, _coin: &str, _from: &str, _to: &str, _amount: Decimal) -> Result { Err(Error::new(ErrorKind::NotFound, "binance_swap:该交易所方法未实现".to_string())) } } pub fn format_position_item(position: &serde_json::Value, ct_val: Decimal) -> Position { let mut position_mode = match position["positionSide"].as_str().unwrap_or("") { "BOTH" => PositionModeEnum::Both, "LONG" => PositionModeEnum::Long, "SHORT" => PositionModeEnum::Short, _ => { error!("binance_swap:格式化持仓模式错误!\nformat_position_item:position={:?}", position); panic!("binance_swap:格式化持仓模式错误!\nformat_position_item:position={:?}", position) } }; let size = Decimal::from_str(position["positionAmt"].as_str().unwrap()).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["symbol"].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["entryPrice"].as_str().unwrap()).unwrap(), profit: Decimal::from_str(position["unRealizedProfit"].as_str().unwrap()).unwrap(), position_mode, margin: Decimal::from_str(position["isolatedMargin"].as_str().unwrap()).unwrap(), } }