|
|
@@ -1,26 +1,31 @@
|
|
|
use std::collections::BTreeMap;
|
|
|
use std::io::{Error, ErrorKind};
|
|
|
+use std::str::FromStr;
|
|
|
+use std::thread;
|
|
|
use async_trait::async_trait;
|
|
|
use rust_decimal::Decimal;
|
|
|
use rust_decimal::prelude::{FromPrimitive, ToPrimitive};
|
|
|
use rust_decimal_macros::dec;
|
|
|
use serde_json::{json};
|
|
|
-use crate::{Platform, ExchangeEnum, Account, Position, PositionModeEnum, Ticker, Market, Order, utils};
|
|
|
+use tokio::runtime;
|
|
|
+use crate::{Platform, ExchangeEnum, Account, Position, PositionModeEnum, Ticker, Market, Order, utils, OrderCommand};
|
|
|
use exchanges::gate_swap_rest::GateSwapRest;
|
|
|
-use crate::PositionModeEnum::{Both, Long};
|
|
|
|
|
|
#[allow(dead_code)]
|
|
|
+#[derive(Clone)]
|
|
|
pub struct GateSwap {
|
|
|
exchange: ExchangeEnum,
|
|
|
+ symbol: String,
|
|
|
is_colo: bool,
|
|
|
params: BTreeMap<String, String>,
|
|
|
request: GateSwapRest,
|
|
|
}
|
|
|
|
|
|
impl GateSwap {
|
|
|
- pub fn new(is_colo: bool, params: BTreeMap<String, String>) -> GateSwap {
|
|
|
+ pub fn new(symbol: String, is_colo: bool, params: BTreeMap<String, String>) -> GateSwap {
|
|
|
GateSwap {
|
|
|
exchange: ExchangeEnum::GateSwap,
|
|
|
+ symbol,
|
|
|
is_colo,
|
|
|
params: params.clone(),
|
|
|
request: GateSwapRest::new(is_colo, params.clone()),
|
|
|
@@ -34,6 +39,8 @@ impl Platform for GateSwap {
|
|
|
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
|
|
|
@@ -54,8 +61,8 @@ impl Platform for GateSwap {
|
|
|
}
|
|
|
}
|
|
|
// 获取账号信息
|
|
|
- async fn get_account(&self, symbol: &str) -> Result<Account, Error> {
|
|
|
- let symbol_array: Vec<&str> = symbol.split("_").collect();
|
|
|
+ async fn get_account(&self) -> Result<Account, Error> {
|
|
|
+ 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_str = &res_data.data;
|
|
|
@@ -77,21 +84,22 @@ impl Platform for GateSwap {
|
|
|
}
|
|
|
}
|
|
|
// 获取持仓信息
|
|
|
- async fn get_position(&self, symbol: &str, _mode: PositionModeEnum) -> Result<Position, Error> {
|
|
|
- let symbol_array: Vec<&str> = symbol.split("_").collect();
|
|
|
- let res_data = self.request.get_position(symbol_array[1].to_string().to_lowercase(), symbol.to_string()).await;
|
|
|
+ async fn get_position(&self, _mode: PositionModeEnum) -> Result<Position, Error> {
|
|
|
+ let symbol_array: Vec<&str> = self.symbol.split("_").collect();
|
|
|
+ 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_str = &res_data.data;
|
|
|
let res_data_json: Vec<serde_json::Value> = serde_json::from_str(res_data_str).unwrap();
|
|
|
- let position_info = &res_data_json[0];
|
|
|
+ let position_info = res_data_json.iter().find(|item| item["contract"].as_str().unwrap() == self.symbol).unwrap();
|
|
|
let position_mode = match position_info["mode"].as_str().unwrap_or("") {
|
|
|
- "single" => Both,
|
|
|
- "dual_long" => Long,
|
|
|
- "dual_short" => Both,
|
|
|
- _ => Both
|
|
|
+ "single" => PositionModeEnum::Both,
|
|
|
+ "dual_long" => PositionModeEnum::Long,
|
|
|
+ "dual_short" => PositionModeEnum::Short,
|
|
|
+ _ => PositionModeEnum::Both
|
|
|
};
|
|
|
+ println!("{}", position_info);
|
|
|
let result = Position {
|
|
|
- margin_level: position_info["size"].as_str().unwrap_or("1").parse().unwrap_or(dec!(1)),
|
|
|
+ margin_level: position_info["leverage"].as_str().unwrap_or("1").parse().unwrap_or(dec!(0)),
|
|
|
amount: position_info["size"].as_str().unwrap_or("0").parse().unwrap_or(dec!(0)),
|
|
|
frozen_amount: dec!(0),
|
|
|
price: position_info["price"].as_str().unwrap_or("0").parse().unwrap_or(dec!(0)),
|
|
|
@@ -105,16 +113,16 @@ impl Platform for GateSwap {
|
|
|
}
|
|
|
}
|
|
|
// 获取市场行情
|
|
|
- async fn get_ticker(&self, symbol: &str) -> Result<Ticker, Error> {
|
|
|
- let symbol_array: Vec<&str> = symbol.split("_").collect();
|
|
|
+ async fn get_ticker(&self) -> Result<Ticker, Error> {
|
|
|
+ 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_str = &res_data.data;
|
|
|
let res_data_json: Vec<serde_json::Value> = serde_json::from_str(res_data_str).unwrap();
|
|
|
let default_info = json!({"high_24h": "0","low_24h": "0","lowest_ask": "0","highest_bid": "0","last": "0","volume_24h": "0"});
|
|
|
- let ticker_info = res_data_json.iter().find(|item| item["contract"].as_str().unwrap() == symbol).unwrap_or(&default_info);
|
|
|
+ let ticker_info = res_data_json.iter().find(|item| item["contract"].as_str().unwrap() == self.symbol).unwrap_or(&default_info);
|
|
|
let result = Ticker {
|
|
|
- time: 0,
|
|
|
+ time: chrono::Utc::now().timestamp_millis(),
|
|
|
high: ticker_info["high_24h"].as_str().unwrap_or("0").parse().unwrap_or(dec!(0)),
|
|
|
low: ticker_info["low_24h"].as_str().unwrap_or("0").parse().unwrap_or(dec!(0)),
|
|
|
sell: ticker_info["lowest_ask"].as_str().unwrap_or("0").parse().unwrap_or(dec!(0)),
|
|
|
@@ -128,21 +136,21 @@ impl Platform for GateSwap {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- async fn get_market(&self, symbol: &str) -> Result<Market, Error> {
|
|
|
- let symbol_array: Vec<&str> = symbol.split("_").collect();
|
|
|
+ async fn get_market(&self) -> Result<Market, Error> {
|
|
|
+ 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_str = &res_data.data;
|
|
|
let res_data_json: Vec<serde_json::Value> = serde_json::from_str(res_data_str).unwrap();
|
|
|
let default_info = json!({});
|
|
|
- let market_info = res_data_json.iter().find(|item| item["name"].as_str().unwrap() == symbol).unwrap_or(&default_info);
|
|
|
+ let market_info = res_data_json.iter().find(|item| item["name"].as_str().unwrap() == self.symbol).unwrap_or(&default_info);
|
|
|
let tick_size = market_info["order_price_round"].as_str().unwrap_or("0").parse().unwrap_or(dec!(0));
|
|
|
let amount_size = market_info["quanto_multiplier"].as_str().unwrap_or("0").parse().unwrap_or(dec!(0));
|
|
|
let price_precision = Decimal::from_u32(tick_size.scale()).unwrap();
|
|
|
let amount_precision = Decimal::from_u32(amount_size.scale()).unwrap();
|
|
|
|
|
|
let result = Market {
|
|
|
- symbol: symbol.to_string(),
|
|
|
+ symbol: self.symbol.to_string(),
|
|
|
base_asset: symbol_array[0].to_string(),
|
|
|
quote_asset: symbol_array[1].to_string(),
|
|
|
tick_size,
|
|
|
@@ -161,8 +169,8 @@ impl Platform for GateSwap {
|
|
|
}
|
|
|
}
|
|
|
// 获取订单详情
|
|
|
- async fn get_order_detail(&self, symbol: &str, id: &str) -> Result<Order, Error> {
|
|
|
- let symbol_array: Vec<&str> = symbol.split("_").collect();
|
|
|
+ async fn get_order_detail(&self, id: &str) -> Result<Order, Error> {
|
|
|
+ let symbol_array: Vec<&str> = self.symbol.split("_").collect();
|
|
|
let res_data = self.request.get_order_details(symbol_array[1].to_string().to_lowercase(), id.to_string()).await;
|
|
|
if res_data.code == "200" {
|
|
|
let res_data_str = &res_data.data;
|
|
|
@@ -174,13 +182,13 @@ impl Platform for GateSwap {
|
|
|
}
|
|
|
}
|
|
|
// 获取订单列表
|
|
|
- async fn get_orders_list(&self, symbol: &str, status: &str) -> Result<Vec<Order>, Error> {
|
|
|
- let symbol_array: Vec<&str> = symbol.split("_").collect();
|
|
|
+ async fn get_orders_list(&self, status: &str) -> Result<Vec<Order>, Error> {
|
|
|
+ let symbol_array: Vec<&str> = self.symbol.split("_").collect();
|
|
|
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_str = &res_data.data;
|
|
|
let res_data_json: Vec<serde_json::Value> = serde_json::from_str(res_data_str).unwrap();
|
|
|
- let order_info: Vec<_> = res_data_json.iter().filter(|item| item["contract"].as_str().unwrap_or("") == symbol).collect();
|
|
|
+ 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| parse_order_item(item)).collect();
|
|
|
Ok(result)
|
|
|
} else {
|
|
|
@@ -200,9 +208,9 @@ impl Platform for GateSwap {
|
|
|
}
|
|
|
}
|
|
|
// 更新双持仓模式下杠杆
|
|
|
- async fn set_dual_leverage(&self, symbol: &str, leverage: &str) -> Result<String, Error> {
|
|
|
- let symbol_array: Vec<&str> = symbol.split("_").collect();
|
|
|
- let res_data = self.request.setting_dual_leverage(symbol_array[1].to_string().to_lowercase(), symbol.to_string(), leverage.to_string()).await;
|
|
|
+ async fn set_dual_leverage(&self, leverage: &str) -> Result<String, Error> {
|
|
|
+ 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();
|
|
|
@@ -224,8 +232,8 @@ impl Platform for GateSwap {
|
|
|
}
|
|
|
}
|
|
|
// 下单接口
|
|
|
- async fn take_order(&self, custom_id: &str, origin_side: &str, coin: &str, symbol: &str, amount: Decimal) -> Result<Order, Error> {
|
|
|
- let symbol_format = utils::format_symbol(symbol.clone(), "_");
|
|
|
+ async fn take_order(&self, custom_id: &str, origin_side: &str, coin: &str, amount: Decimal) -> Result<Order, Error> {
|
|
|
+ let symbol_format = utils::format_symbol(self.symbol.clone(), "_");
|
|
|
let coin_format = coin.to_string().to_lowercase();
|
|
|
let res_data = self.request.swap_bazaar_order(custom_id.to_string(), origin_side.to_string(), coin_format.clone(), symbol_format, amount.to_i64().unwrap()).await;
|
|
|
if res_data.code == "200" {
|
|
|
@@ -238,9 +246,11 @@ impl Platform for GateSwap {
|
|
|
}
|
|
|
}
|
|
|
// 撤销订单
|
|
|
- async fn cancel_order(&self, symbol: &str, order_id: &str) -> Result<Order, Error> {
|
|
|
- let symbol_array: Vec<&str> = symbol.split("_").collect();
|
|
|
- let res_data = self.request.cancel_order(symbol_array[1].to_string().to_lowercase(), order_id.to_string()).await;
|
|
|
+ async fn cancel_order(&self, order_id: &str, is_custom_id: Option<bool>) -> Result<Order, Error> {
|
|
|
+ let symbol_array: Vec<&str> = self.symbol.split("_").collect();
|
|
|
+ let settle = symbol_array[1].to_string().to_lowercase();
|
|
|
+ let id = if is_custom_id.unwrap_or(false) { order_id } else { order_id };
|
|
|
+ let res_data = self.request.cancel_order(settle, 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();
|
|
|
@@ -251,9 +261,9 @@ impl Platform for GateSwap {
|
|
|
}
|
|
|
}
|
|
|
// 批量撤销订单
|
|
|
- async fn cancel_orders(&self, symbol: &str) -> Result<Vec<Order>, Error> {
|
|
|
- let symbol_array: Vec<&str> = symbol.split("_").collect();
|
|
|
- let res_data = self.request.cancel_orders(symbol_array[1].to_string().to_lowercase(), symbol.to_string()).await;
|
|
|
+ async fn cancel_orders(&self) -> Result<Vec<Order>, Error> {
|
|
|
+ let symbol_array: Vec<&str> = self.symbol.split("_").collect();
|
|
|
+ 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_str = &res_data.data;
|
|
|
let res_data_json: Vec<serde_json::Value> = serde_json::from_str(res_data_str).unwrap();
|
|
|
@@ -263,6 +273,104 @@ impl Platform for GateSwap {
|
|
|
Err(Error::new(ErrorKind::Other, res_data.message))
|
|
|
}
|
|
|
}
|
|
|
+ // 指令下单
|
|
|
+ async fn command_order(&self, order_command: OrderCommand) {
|
|
|
+ let mut handles = vec![];
|
|
|
+ // 撤销订单
|
|
|
+ let cancel = order_command.cancel;
|
|
|
+ for item in cancel.keys() {
|
|
|
+ let cancel_clone = cancel.clone();
|
|
|
+ let item_clone = item.clone();
|
|
|
+ if cancel_clone[&item_clone].get(0).unwrap() != "" {
|
|
|
+ let self_clone = self.clone();
|
|
|
+ let order_id = cancel_clone[&item_clone].get(0).unwrap().clone();
|
|
|
+ let handle = thread::spawn(move || {
|
|
|
+ runtime::Runtime::new().unwrap().block_on(async {
|
|
|
+ let result = self_clone.cancel_order(&order_id, None).await;
|
|
|
+ match result {
|
|
|
+ Ok(result) => {
|
|
|
+ println!("{:?}", result);
|
|
|
+ }
|
|
|
+ Err(error) => {
|
|
|
+ println!("{}", error);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ });
|
|
|
+ });
|
|
|
+ handles.push(handle)
|
|
|
+ } else if cancel_clone[&item_clone].get(1).unwrap() != "" {
|
|
|
+ let self_clone = self.clone();
|
|
|
+ let order_id = cancel_clone[&item_clone].get(1).unwrap().clone();
|
|
|
+ let handle = thread::spawn(move || {
|
|
|
+ runtime::Runtime::new().unwrap().block_on(async {
|
|
|
+ let result = self_clone.cancel_order(&order_id, Option::from(true)).await;
|
|
|
+ match result {
|
|
|
+ Ok(result) => {
|
|
|
+ println!("{:?}", result);
|
|
|
+ }
|
|
|
+ Err(error) => {
|
|
|
+ println!("{}", error);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ });
|
|
|
+ });
|
|
|
+ handles.push(handle)
|
|
|
+ }
|
|
|
+ }
|
|
|
+ // 下单指令
|
|
|
+ let limits = order_command.limits;
|
|
|
+ for item in limits.keys() {
|
|
|
+ let self_clone = self.clone();
|
|
|
+ let limits_clone = limits.clone();
|
|
|
+ let item_clone = item.clone();
|
|
|
+ let handle = thread::spawn(move || {
|
|
|
+ runtime::Runtime::new().unwrap().block_on(async {
|
|
|
+ let value = limits_clone[&item_clone].clone();
|
|
|
+ let cid = value.get(3).unwrap();
|
|
|
+ let side = value.get(1).unwrap();
|
|
|
+ let symbol = &item_clone;
|
|
|
+ let amount = Decimal::from_str(value.get(0).unwrap()).unwrap();
|
|
|
+ // order_name: [数量,方向,价格,c_id]
|
|
|
+ let result = self_clone.take_order(cid, side, "usdt", amount).await;
|
|
|
+ match result {
|
|
|
+ Ok(result) => {
|
|
|
+ println!("{:?}", result);
|
|
|
+ }
|
|
|
+ Err(error) => {
|
|
|
+ println!("{}", error);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ });
|
|
|
+ });
|
|
|
+ handles.push(handle)
|
|
|
+ }
|
|
|
+ // 检查订单指令
|
|
|
+ let check = order_command.check;
|
|
|
+ for item in check.keys() {
|
|
|
+ let self_clone = self.clone();
|
|
|
+ let check_clone = check.clone();
|
|
|
+ let item_clone = item.clone();
|
|
|
+ let handle = thread::spawn(move || {
|
|
|
+ runtime::Runtime::new().unwrap().block_on(async {
|
|
|
+ let value = check_clone[&item_clone].clone();
|
|
|
+ let cid = value.get(0).unwrap();
|
|
|
+ let result = self_clone.get_order_detail(cid).await;
|
|
|
+ match result {
|
|
|
+ Ok(result) => {
|
|
|
+ println!("{:?}", result);
|
|
|
+ }
|
|
|
+ Err(error) => {
|
|
|
+ println!("{}", error);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ });
|
|
|
+ });
|
|
|
+ handles.push(handle)
|
|
|
+ }
|
|
|
+ for handle in handles {
|
|
|
+ handle.join().unwrap();
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
fn parse_order_item(order: &serde_json::Value) -> Order {
|