|
|
@@ -1,13 +1,16 @@
|
|
|
-use std::collections::BTreeMap;
|
|
|
+use std::collections::{BTreeMap, HashMap};
|
|
|
use std::io::{Error, ErrorKind};
|
|
|
use std::result::Result;
|
|
|
use std::str::FromStr;
|
|
|
use async_trait::async_trait;
|
|
|
+use futures::stream::FuturesUnordered;
|
|
|
+use futures::TryStreamExt;
|
|
|
use rust_decimal::Decimal;
|
|
|
use rust_decimal::prelude::FromPrimitive;
|
|
|
use rust_decimal_macros::dec;
|
|
|
+use serde_json::{from_str, json, Value};
|
|
|
use tokio::sync::mpsc::Sender;
|
|
|
-use tracing::{error, warn};
|
|
|
+use tracing::{debug, error, info};
|
|
|
use crate::{Platform, ExchangeEnum, Account, Position, Ticker, Market, Order, OrderCommand, utils, PositionModeEnum};
|
|
|
use exchanges::binance_swap_rest::BinanceSwapRest;
|
|
|
use global::trace_stack::TraceStack;
|
|
|
@@ -17,20 +20,22 @@ use global::trace_stack::TraceStack;
|
|
|
pub struct BinanceSwap {
|
|
|
exchange: ExchangeEnum,
|
|
|
symbol: String,
|
|
|
+ symbol_uppercase: String,
|
|
|
is_colo: bool,
|
|
|
params: BTreeMap<String, String>,
|
|
|
request: BinanceSwapRest,
|
|
|
market: Market,
|
|
|
- order_sender: Sender<Order>,
|
|
|
- error_sender: Sender<Error>,
|
|
|
+ order_sender: Option<Sender<Order>>,
|
|
|
+ error_sender: Option<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 {
|
|
|
+ pub async fn new(symbol: String, is_colo: bool, params: BTreeMap<String, String>, order_sender: Option<Sender<Order>>, error_sender: Option<Sender<Error>>) -> BinanceSwap {
|
|
|
let market = Market::new();
|
|
|
let mut binance_swap = BinanceSwap {
|
|
|
exchange: ExchangeEnum::BinanceSwap,
|
|
|
symbol: symbol.to_uppercase(),
|
|
|
+ symbol_uppercase: symbol.replace("_", "").to_uppercase(),
|
|
|
is_colo,
|
|
|
params: params.clone(),
|
|
|
request: BinanceSwapRest::new(is_colo, params.clone()),
|
|
|
@@ -75,7 +80,7 @@ impl Platform for BinanceSwap {
|
|
|
let res_data = self.request.get_server_time().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 res_data_json: Value = from_str(res_data_str).unwrap();
|
|
|
let result = res_data_json["serverTime"].to_string();
|
|
|
Ok(result)
|
|
|
} else {
|
|
|
@@ -88,7 +93,7 @@ impl Platform for BinanceSwap {
|
|
|
let res_data = self.request.get_account().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 res_data_json: Vec<Value> = from_str(res_data_str).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 => {
|
|
|
@@ -127,7 +132,7 @@ impl Platform for BinanceSwap {
|
|
|
let res_data = self.request.get_position_risk(symbol_format).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 res_data_json: Vec<Value> = from_str(res_data_str).unwrap();
|
|
|
let result = res_data_json.iter().map(|item| { format_position_item(item, ct_val) }).collect();
|
|
|
Ok(result)
|
|
|
} else {
|
|
|
@@ -139,7 +144,7 @@ impl Platform for BinanceSwap {
|
|
|
let res_data = self.request.get_position_risk("".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 res_data_json: Vec<Value> = from_str(res_data_str).unwrap();
|
|
|
let result = res_data_json.iter().map(|item| { format_position_item(item, Decimal::ONE) }).collect();
|
|
|
Ok(result)
|
|
|
} else {
|
|
|
@@ -153,7 +158,7 @@ impl Platform for BinanceSwap {
|
|
|
let res_data = self.request.get_book_ticker(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 res_data_json: Value = from_str(res_data_str).unwrap();
|
|
|
let result = Ticker {
|
|
|
time: res_data_json["time"].as_i64().unwrap(),
|
|
|
high: Decimal::from_str(res_data_json["askPrice"].as_str().unwrap()).unwrap(),
|
|
|
@@ -174,7 +179,7 @@ impl Platform for BinanceSwap {
|
|
|
let res_data = self.request.get_book_ticker(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 res_data_json: Value = from_str(res_data_str).unwrap();
|
|
|
let result = Ticker {
|
|
|
time: res_data_json["time"].as_i64().unwrap(),
|
|
|
high: Decimal::from_str(res_data_json["askPrice"].as_str().unwrap()).unwrap(),
|
|
|
@@ -195,8 +200,8 @@ impl Platform for BinanceSwap {
|
|
|
let res_data = self.request.get_exchange_info().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 symbols: Vec<serde_json::Value> = res_data_json["symbols"].as_array().unwrap().clone();
|
|
|
+ let res_data_json: Value = from_str(res_data_str).unwrap();
|
|
|
+ let symbols: Vec<Value> = res_data_json["symbols"].as_array().unwrap().clone();
|
|
|
let market_info = symbols.iter().find(|&item| item["symbol"].as_str().unwrap() == symbol_format);
|
|
|
match market_info {
|
|
|
None => {
|
|
|
@@ -238,8 +243,8 @@ impl Platform for BinanceSwap {
|
|
|
let res_data = self.request.get_exchange_info().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 symbols: Vec<serde_json::Value> = res_data_json["symbols"].as_array().unwrap().clone();
|
|
|
+ let res_data_json: Value = from_str(res_data_str).unwrap();
|
|
|
+ let symbols: Vec<Value> = res_data_json["symbols"].as_array().unwrap().clone();
|
|
|
let market_info = symbols.iter().find(|&item| item["symbol"].as_str().unwrap() == symbol_format);
|
|
|
match market_info {
|
|
|
None => {
|
|
|
@@ -281,7 +286,7 @@ impl Platform for BinanceSwap {
|
|
|
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_str = &res_data.data;
|
|
|
- let res_data_json: serde_json::Value = serde_json::from_str(res_data_str).unwrap();
|
|
|
+ let res_data_json: Value = from_str(res_data_str).unwrap();
|
|
|
|
|
|
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 {
|
|
|
@@ -310,7 +315,7 @@ impl Platform for BinanceSwap {
|
|
|
let res_data = self.request.get_open_orders(symbol_format).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 res_data_json: Vec<Value> = from_str(res_data_str).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();
|
|
|
@@ -336,17 +341,142 @@ impl Platform for BinanceSwap {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- 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(&mut self, custom_id: &str, origin_side: &str, price: Decimal, amount: Decimal) -> Result<Order, Error> {
|
|
|
+ let symbol = self.symbol_uppercase.clone();
|
|
|
+ let ct_val = self.market.ct_val;
|
|
|
+ let size = (amount / ct_val).floor();
|
|
|
+ let mut params = json!({
|
|
|
+ "symbol": symbol,
|
|
|
+ "newClientOrderId": format!("t-{}", custom_id),
|
|
|
+ "price": price.to_string(),
|
|
|
+ "quantity": json!(size)
|
|
|
+ });
|
|
|
|
|
|
- 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())) }
|
|
|
+ if price.eq(&Decimal::ZERO) {
|
|
|
+ params["type"] = json!("MARKET".to_string());
|
|
|
+ } else {
|
|
|
+ params["type"] = json!("LIMIT".to_string());
|
|
|
+ }
|
|
|
+ match origin_side {
|
|
|
+ "kd" => {
|
|
|
+ params["reduce_only"] = json!(false);
|
|
|
+ params["positionSide"] = json!("LONG".to_string());
|
|
|
+ }
|
|
|
+ "pd" => {
|
|
|
+ params["reduce_only"] = json!(true);
|
|
|
+ params["positionSide"] = json!("LONG".to_string());
|
|
|
+ }
|
|
|
+ "kk" => {
|
|
|
+ params["reduce_only"] = json!(false);
|
|
|
+ params["positionSide"] = json!("SHORT".to_string());
|
|
|
+ }
|
|
|
+ "pk" => {
|
|
|
+ params["reduce_only"] = json!(true);
|
|
|
+ params["positionSide"] = json!("SHORT".to_string());
|
|
|
+ }
|
|
|
+ _ => { error!("下单参数错误"); }
|
|
|
+ };
|
|
|
+ let res_data = self.request.swap_order(params).await;
|
|
|
+ if res_data.code == "200" {
|
|
|
+ let res_data_str = &res_data.data;
|
|
|
+ let res_data_json: Value = from_str(res_data_str).unwrap();
|
|
|
+ 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<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> {
|
|
|
+ let symbol_upper = symbol.replace("_", "").trim().to_uppercase();
|
|
|
+ let size = (amount / ct_val).floor();
|
|
|
+ let mut params = json!({
|
|
|
+ "symbol": symbol_upper,
|
|
|
+ "newClientOrderId": format!("t-{}", custom_id),
|
|
|
+ "price": price.to_string(),
|
|
|
+ "quantity": json!(size)
|
|
|
+ });
|
|
|
|
|
|
- async fn cancel_orders(&mut self) -> Result<Vec<Order>, Error> { Err(Error::new(ErrorKind::NotFound, "binance_swap:该交易所方法未实现".to_string())) }
|
|
|
+ if price.eq(&Decimal::ZERO) {
|
|
|
+ params["type"] = json!("MARKET".to_string());
|
|
|
+ } else {
|
|
|
+ params["type"] = json!("LIMIT".to_string());
|
|
|
+ }
|
|
|
+ match origin_side {
|
|
|
+ "kd" => {
|
|
|
+ params["reduce_only"] = json!(false);
|
|
|
+ params["positionSide"] = json!("LONG".to_string());
|
|
|
+ }
|
|
|
+ "pd" => {
|
|
|
+ params["reduce_only"] = json!(true);
|
|
|
+ params["positionSide"] = json!("LONG".to_string());
|
|
|
+ }
|
|
|
+ "kk" => {
|
|
|
+ params["reduce_only"] = json!(false);
|
|
|
+ params["positionSide"] = json!("SHORT".to_string());
|
|
|
+ }
|
|
|
+ "pk" => {
|
|
|
+ params["reduce_only"] = json!(true);
|
|
|
+ params["positionSide"] = json!("SHORT".to_string());
|
|
|
+ }
|
|
|
+ _ => { error!("下单参数错误"); }
|
|
|
+ };
|
|
|
+ let res_data = self.request.swap_order(params).await;
|
|
|
+ if res_data.code == "200" {
|
|
|
+ let res_data_str = &res_data.data;
|
|
|
+ let res_data_json: Value = from_str(res_data_str).unwrap();
|
|
|
+ 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_all(&mut self) -> Result<Vec<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> {
|
|
|
+ let symbol = self.symbol_uppercase.clone();
|
|
|
+ let id = format!("t-{}", custom_id);
|
|
|
+ let res_data = self.request.cancel_order(symbol, order_id.parse::<i64>().unwrap(), id.clone()).await;
|
|
|
+ if res_data.code == "200" {
|
|
|
+ let res_data_str = &res_data.data;
|
|
|
+ let res_data_json: Value = from_str(res_data_str).unwrap();
|
|
|
+ let result = format_cancel_order_item(res_data_json);
|
|
|
+ Ok(result)
|
|
|
+ } else {
|
|
|
+ Err(Error::new(ErrorKind::Other, res_data.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 cancel_orders(&mut self) -> Result<Vec<Order>, Error> {
|
|
|
+ let symbol = self.symbol_uppercase.clone();
|
|
|
+ let res_data = self.request.cancel_order_all(symbol).await;
|
|
|
+ if res_data.code == "200" {
|
|
|
+ Ok(vec![])
|
|
|
+ } else {
|
|
|
+ Err(Error::new(ErrorKind::Other, res_data.to_string()))
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ async fn cancel_orders_all(&mut self) -> Result<Vec<Order>, Error> {
|
|
|
+ // 币安没有以结算币查询订单的功能,所以只能撤销当前币种的挂单
|
|
|
+ let symbol = self.symbol_uppercase.clone();
|
|
|
+ let res_data = self.request.cancel_order_all(symbol).await;
|
|
|
+ if res_data.code == "200" {
|
|
|
+ info!("币安没有以结算币查询订单的功能,只能撤销当前币种的挂单, 请人工检查其他币种遗留订单!");
|
|
|
+ Ok(vec![])
|
|
|
+ } else {
|
|
|
+ Err(Error::new(ErrorKind::Other, res_data.to_string()))
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ async fn set_dual_mode(&mut self, _coin: &str, is_dual_mode: bool) -> Result<String, Error> {
|
|
|
+ let res_data = self.request.change_pos_side(is_dual_mode).await;
|
|
|
+ if res_data.code == "200" {
|
|
|
+ let res_data_str = res_data.data;
|
|
|
+ Ok(res_data_str)
|
|
|
+ } else {
|
|
|
+ Err(Error::new(ErrorKind::Other, res_data.to_string()))
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
async fn set_dual_leverage(&mut self, _leverage: &str) -> Result<String, Error> { Err(Error::new(ErrorKind::NotFound, "binance_swap:该交易所方法未实现".to_string())) }
|
|
|
|
|
|
@@ -354,10 +484,113 @@ impl Platform for BinanceSwap {
|
|
|
|
|
|
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())) }
|
|
|
|
|
|
- async fn command_order(&mut self, _order_command: OrderCommand, _trace_stack: TraceStack) { warn!("binance_swap:该交易所方法未实现"); }
|
|
|
+ async fn command_order(&mut self, order_command: 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.get(&item_clone).unwrap().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.unwrap().send(order).await.unwrap();
|
|
|
+ }
|
|
|
+ Err(_err) => {
|
|
|
+ // error!("撤单失败,而且查单也失败了,binance_io_swap,oid={}, cid={}。", order_id.clone(), custom_id.clone());
|
|
|
+ // panic!("撤单失败,而且查单也失败了,binance_io_swap,oid={}, cid={}。", order_id.clone(), custom_id.clone());
|
|
|
+ }
|
|
|
+ }
|
|
|
+ err_sd.unwrap().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 mut 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.unwrap().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.unwrap().send(err_order).await.unwrap();
|
|
|
+ err_sd.unwrap().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.unwrap().send(result).await.unwrap();
|
|
|
+ }
|
|
|
+ Err(error) => {
|
|
|
+ err_sd.unwrap().send(error).await.unwrap();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ });
|
|
|
+ handles.push(handle)
|
|
|
+ }
|
|
|
+
|
|
|
+ let futures = FuturesUnordered::from_iter(handles);
|
|
|
+ let _: Result<Vec<_>, _> = futures.try_collect().await;
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
-pub fn format_position_item(position: &serde_json::Value, ct_val: Decimal) -> Position {
|
|
|
+pub fn format_position_item(position: &Value, ct_val: Decimal) -> Position {
|
|
|
let mut position_mode = match position["positionSide"].as_str().unwrap_or("") {
|
|
|
"BOTH" => PositionModeEnum::Both,
|
|
|
"LONG" => PositionModeEnum::Long,
|
|
|
@@ -389,4 +622,48 @@ pub fn format_position_item(position: &serde_json::Value, ct_val: Decimal) -> Po
|
|
|
position_mode,
|
|
|
margin: Decimal::from_str(position["isolatedMargin"].as_str().unwrap()).unwrap(),
|
|
|
}
|
|
|
+}
|
|
|
+
|
|
|
+fn format_cancel_order_item(order: Value) -> Order {
|
|
|
+ Order {
|
|
|
+ id: format!("{}", order["orderId"].as_str().unwrap()),
|
|
|
+ custom_id: order["clientOrderId"].as_str().unwrap().replace("t-my-custom-id_", "").replace("t-", ""),
|
|
|
+ price: Decimal::ZERO,
|
|
|
+ amount: Decimal::ZERO,
|
|
|
+ deal_amount: Decimal::ZERO,
|
|
|
+ avg_price: Decimal::ZERO,
|
|
|
+ status: "REMOVE".to_string(),
|
|
|
+ order_type: "limit".to_string(),
|
|
|
+ trace_stack: TraceStack::default().on_special("688 trace_stack".to_string())
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+fn format_order_item(order: Value, ct_val: Decimal)-> Order {
|
|
|
+ debug!("format-order-start, binance_swap");
|
|
|
+ debug!(?order);
|
|
|
+ let status = order["status"].as_str().unwrap_or("");
|
|
|
+ let text = order["clientOrderId"].as_str().unwrap_or("");
|
|
|
+ let size = Decimal::from_str(&order["origQty"].to_string()).unwrap();
|
|
|
+ let right = Decimal::from_str(&order["executedQty"].to_string()).unwrap();
|
|
|
+
|
|
|
+ let amount = size * ct_val;
|
|
|
+ let deal_amount = right * ct_val;
|
|
|
+ let custom_status = if ["CANCELED", "FILLED", "EXPIRED"].contains(&status) { "REMOVE".to_string() } else if status == "NEW" { "NEW".to_string() } else {
|
|
|
+ error!("binance_swap:格式化订单状态错误!\nformat_order_item:order={:?}", order);
|
|
|
+ panic!("binance_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["avgPrice"].as_str().unwrap()).unwrap(),
|
|
|
+ status: custom_status,
|
|
|
+ order_type: "limit".to_string(),
|
|
|
+ trace_stack: TraceStack::default().on_special("688 trace_stack".to_string()),
|
|
|
+ };
|
|
|
+ debug!(?rst_order);
|
|
|
+ debug!("format-order-end, gate_swap");
|
|
|
+ return rst_order;
|
|
|
}
|