| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387 |
- 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<String, String>,
- request: BinanceSwapRest,
- market: Market,
- order_sender: Sender<Order>,
- error_sender: Sender<Error>,
- }
- impl BinanceSwap {
- pub async fn new(symbol: String, is_colo: bool, params: BTreeMap<String, String>, order_sender: Sender<Order>, error_sender: Sender<Error>) -> 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<dyn Platform + Send + Sync> { 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<String, String> {
- self.params.clone()
- }
- // 获取market信息
- fn get_self_market(&self) -> Market { self.market.clone() }
- // 获取请求时间
- fn get_request_delays(&self) -> Vec<i64> { 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<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"].to_string();
- Ok(result)
- } else {
- Err(Error::new(ErrorKind::Other, res_data.to_string()))
- }
- }
- // 获取账号信息
- async fn get_account(&mut self) -> Result<Account, Error> {
- 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<Vec<Account>, Error> {
- Err(Error::new(ErrorKind::NotFound, "binance_swap:该交易所方法未实现".to_string()))
- }
- // 获取仓位信息
- async fn get_position(&mut self) -> Result<Vec<Position>, 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<Vec<Position>, 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<Ticker, Error> {
- 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<Ticker, Error> {
- 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<Market, Error> {
- 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<Market, Error> {
- 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<Order, Error> {
- 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<Vec<Order>, 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<Order, Error> { 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<Order, Error> { Err(Error::new(ErrorKind::NotFound, "binance_swap:该交易所方法未实现".to_string())) }
- async fn cancel_order(&mut self, _order_id: &str, _custom_id: &str) -> Result<Order, Error> { Err(Error::new(ErrorKind::NotFound, "binance_swap:该交易所方法未实现".to_string())) }
- async fn cancel_orders(&mut self) -> Result<Vec<Order>, Error> { Err(Error::new(ErrorKind::NotFound, "binance_swap:该交易所方法未实现".to_string())) }
- async fn cancel_orders_all(&mut self) -> Result<Vec<Order>, 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<Value, Error> {
- Err(Error::new(ErrorKind::NotFound, "binance_swap:该交易所方法未实现".to_string()))
- }
- async fn cancel_stop_loss_order(&mut self, _order_id: &str) -> Result<Value, Error> {
- Err(Error::new(ErrorKind::NotFound, "binance_swap:该交易所方法未实现".to_string()))
- }
- async fn set_dual_mode(&mut self, _coin: &str, _is_dual_mode: bool) -> Result<String, Error> { Err(Error::new(ErrorKind::NotFound, "binance_swap:该交易所方法未实现".to_string())) }
- async fn set_dual_leverage(&mut self, _leverage: &str) -> Result<String, Error> { Err(Error::new(ErrorKind::NotFound, "binance_swap:该交易所方法未实现".to_string())) }
- async fn set_auto_deposit_status(&mut self, _status: bool) -> Result<String, Error> { Err(Error::new(ErrorKind::NotFound, "binance_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, "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(),
- }
- }
|