Browse Source

修改exchange结构
添加下单指令

gepangpang 2 năm trước cách đây
mục cha
commit
39d324833d

+ 2 - 1
standard/Cargo.toml

@@ -12,4 +12,5 @@ tokio = { version = "1.31.0", features = ["full"] }
 async-trait = "0.1.73"
 serde_json = "1.0.105"
 rust_decimal = "1.32.0"
-rust_decimal_macros = "1.32.0"
+rust_decimal_macros = "1.32.0"
+chrono = "0.4.30"

+ 1 - 1
standard/src/binance_handle.rs

@@ -9,7 +9,7 @@ use global::public_params;
 use crate::{Account, MarketOrder, SpecialDepth, SpecialTicker};
 
 // 处理账号信息
-pub fn handle_account_info(res_data: ResponseData, symbol: &str) -> Result<Account, Error> {
+pub fn handle_account_info(res_data: ResponseData, symbol: String) -> Result<Account, Error> {
     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();

+ 21 - 15
standard/src/binance_spot.rs

@@ -3,25 +3,25 @@ use std::io::{Error};
 use std::result::Result;
 use async_trait::async_trait;
 use rust_decimal::Decimal;
-use crate::{Platform, ExchangeEnum, Account, binance_handle, Position, PositionModeEnum, Ticker, Market, Order};
+use crate::{Platform, ExchangeEnum, Account, binance_handle, Position, PositionModeEnum, Ticker, Market, Order, OrderCommand};
 use exchanges::binance_spot_rest::BinanceSpotRest;
 use exchanges::response_base::ResponseData;
 
 #[allow(dead_code)]
 pub struct BinanceSpot {
     exchange: ExchangeEnum,
+    symbol: String,
     is_colo: bool,
-    is_login: bool,
     params: BTreeMap<String, String>,
     request: BinanceSpotRest,
 }
 
 impl BinanceSpot {
-    pub fn new(is_colo: bool, is_login: bool, params: BTreeMap<String, String>) -> BinanceSpot {
+    pub fn new(symbol: String, is_colo: bool, params: BTreeMap<String, String>) -> BinanceSpot {
         BinanceSpot {
             exchange: ExchangeEnum::BinanceSpot,
+            symbol,
             is_colo,
-            is_login,
             params: params.clone(),
             request: BinanceSpotRest::new(is_colo, params.clone()),
         }
@@ -34,6 +34,8 @@ impl Platform for BinanceSpot {
     fn get_self_exchange(&self) -> ExchangeEnum {
         ExchangeEnum::BinanceSpot
     }
+    // 获取交易对
+    fn get_self_symbol(&self) -> String { self.symbol.clone() }
     // 获取是否使用高速通道
     fn get_self_is_colo(&self) -> bool {
         self.is_colo
@@ -48,33 +50,33 @@ impl Platform for BinanceSpot {
     }
 
     // 获取账号信息
-    async fn get_account(&self, symbol: &str) -> Result<Account, Error> {
+    async fn get_account(&self) -> Result<Account, Error> {
         let res_data = ResponseData {
             code: "200".to_string(),
             message: "你猜猜这是什么错误".to_string(),
             data: "[]".to_string(),
             channel: "".to_string(),
         };
-        binance_handle::handle_account_info(res_data, symbol)
+        binance_handle::handle_account_info(res_data, self.symbol.clone())
     }
     // 获取仓位信息
-    async fn get_position(&self, _symbol: &str, _mode: PositionModeEnum) -> Result<Position, Error> {
+    async fn get_position(&self, _mode: PositionModeEnum) -> Result<Position, Error> {
         todo!()
     }
     // 获取市场行情
-    async fn get_ticker(&self, _symbol: &str) -> Result<Ticker, Error> {
+    async fn get_ticker(&self) -> Result<Ticker, Error> {
         todo!()
     }
 
-    async fn get_market(&self, _symbol: &str) -> Result<Market, Error> {
+    async fn get_market(&self) -> Result<Market, Error> {
         todo!()
     }
 
-    async fn get_order_detail(&self, _symbol: &str, _id: &str) -> Result<Order, Error> {
+    async fn get_order_detail(&self, _id: &str) -> Result<Order, Error> {
         todo!()
     }
 
-    async fn get_orders_list(&self, _symbol: &str, _status: &str) -> Result<Vec<Order>, Error> {
+    async fn get_orders_list(&self, _status: &str) -> Result<Vec<Order>, Error> {
         todo!()
     }
 
@@ -82,7 +84,7 @@ impl Platform for BinanceSpot {
         todo!()
     }
 
-    async fn set_dual_leverage(&self, _symbol: &str, _leverage: &str) -> Result<String, Error> {
+    async fn set_dual_leverage(&self, _leverage: &str) -> Result<String, Error> {
         todo!()
     }
 
@@ -90,15 +92,19 @@ impl Platform for BinanceSpot {
         todo!()
     }
 
-    async fn take_order(&self, _custom_id: &str, _origin_side: &str, _coin: &str, _symbol: &str, _amount: Decimal) -> Result<Order, Error> {
+    async fn take_order(&self, _custom_id: &str, _origin_side: &str, _coin: &str, _amount: Decimal) -> Result<Order, Error> {
         todo!()
     }
 
-    async fn cancel_order(&self, _symbol: &str, _order_id: &str) -> Result<Order, Error> {
+    async fn cancel_order(&self, _order_id: &str, _is_custom_id: Option<bool>) -> Result<Order, Error> {
         todo!()
     }
 
-    async fn cancel_orders(&self, _symbol: &str) -> Result<Vec<Order>, Error> {
+    async fn cancel_orders(&self) -> Result<Vec<Order>, Error> {
+        todo!()
+    }
+
+    async fn command_order(&self, order_command: OrderCommand) {
         todo!()
     }
 }

+ 23 - 16
standard/src/binance_swap.rs

@@ -5,21 +5,23 @@ use async_trait::async_trait;
 use rust_decimal::Decimal;
 use rust_decimal_macros::dec;
 use serde_json::json;
-use crate::{Platform, ExchangeEnum, Account, Position, PositionModeEnum, Ticker, Market, Order};
+use crate::{Platform, ExchangeEnum, Account, Position, PositionModeEnum, Ticker, Market, Order, OrderCommand};
 use exchanges::binance_usdt_swap_rest::BinanceUsdtSwapRest;
 
 #[allow(dead_code)]
 pub struct BinanceSwap {
     exchange: ExchangeEnum,
+    symbol: String,
     is_colo: bool,
     params: BTreeMap<String, String>,
     request: BinanceUsdtSwapRest,
 }
 
 impl BinanceSwap {
-    pub fn new(is_colo: bool, params: BTreeMap<String, String>) -> BinanceSwap {
+    pub fn new(symbol: String, is_colo: bool, params: BTreeMap<String, String>) -> BinanceSwap {
         BinanceSwap {
             exchange: ExchangeEnum::BinanceSwap,
+            symbol,
             is_colo,
             params: params.clone(),
             request: BinanceUsdtSwapRest::new(is_colo, params.clone()),
@@ -33,6 +35,8 @@ impl Platform for BinanceSwap {
     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
@@ -42,20 +46,19 @@ impl Platform for BinanceSwap {
         self.params.clone()
     }
     // 获取服务器时间
-    async fn get_server_time(&self) -> Result<String, Error>{
+    async fn get_server_time(&self) -> Result<String, Error> {
         todo!()
     }
-
     // 获取账号信息
-    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().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 details = res_data_json;
             let default_info = json!({"balance":"0","availableBalance":"0"});
-            let balance_info = details.iter().find(|item| item["asset"].as_str().unwrap() == symbol_array[1].to_string()).unwrap_or(&default_info);
+            let balance_info = details.iter().find(|item| item["asset"].as_str().unwrap().to_string() == symbol_array[1].to_string()).unwrap_or(&default_info);
             let balance = balance_info["balance"].as_str().unwrap().parse().unwrap_or(dec!(0.0));
             let available_balance = balance_info["availableBalance"].as_str().unwrap().parse().unwrap_or(dec!(0.0));
             let frozen_balance = balance - available_balance;
@@ -73,23 +76,23 @@ impl Platform for BinanceSwap {
         }
     }
     // 获取仓位信息
-    async fn get_position(&self, _symbol: &str, _mode: PositionModeEnum) -> Result<Position, Error> {
+    async fn get_position(&self, _mode: PositionModeEnum) -> Result<Position, Error> {
         todo!()
     }
     // 获取市场行情
-    async fn get_ticker(&self, _symbol: &str) -> Result<Ticker, Error> {
+    async fn get_ticker(&self) -> Result<Ticker, Error> {
         todo!()
     }
 
-    async fn get_market(&self, _symbol: &str) -> Result<Market, Error> {
+    async fn get_market(&self) -> Result<Market, Error> {
         todo!()
     }
 
-    async fn get_order_detail(&self, _symbol: &str, _id: &str) -> Result<Order, Error> {
+    async fn get_order_detail(&self, _id: &str) -> Result<Order, Error> {
         todo!()
     }
 
-    async fn get_orders_list(&self, _symbol: &str, _status: &str) -> Result<Vec<Order>, Error> {
+    async fn get_orders_list(&self, _status: &str) -> Result<Vec<Order>, Error> {
         todo!()
     }
 
@@ -97,7 +100,7 @@ impl Platform for BinanceSwap {
         todo!()
     }
 
-    async fn set_dual_leverage(&self, _symbol: &str, _leverage: &str) -> Result<String, Error> {
+    async fn set_dual_leverage(&self, _leverage: &str) -> Result<String, Error> {
         todo!()
     }
 
@@ -105,15 +108,19 @@ impl Platform for BinanceSwap {
         todo!()
     }
 
-    async fn take_order(&self, _custom_id: &str, _origin_side: &str, _coin: &str, _symbol: &str, _amount: Decimal) -> Result<Order, Error> {
+    async fn take_order(&self, _custom_id: &str, _origin_side: &str, _coin: &str, _amount: Decimal) -> Result<Order, Error> {
+        todo!()
+    }
+
+    async fn cancel_order(&self, _order_id: &str, _is_custom_id: Option<bool>,) -> Result<Order, Error> {
         todo!()
     }
 
-    async fn cancel_order(&self, _symbol: &str, _order_id: &str) -> Result<Order, Error> {
+    async fn cancel_orders(&self) -> Result<Vec<Order>, Error> {
         todo!()
     }
 
-    async fn cancel_orders(&self, _symbol: &str) -> Result<Vec<Order>, Error> {
+    async fn command_order(&self, _order_command: OrderCommand) {
         todo!()
     }
 

+ 9 - 9
standard/src/exchange.rs

@@ -12,7 +12,7 @@ use crate::Platform;
 /// - `GateSwap`: Gate交易所期货;
 /// - `GateSpot`: Gate交易所现货;
 /// - `KucoinSwap`: kucoin交易所期货;
-#[derive(Debug)]
+#[derive(Debug, Clone)]
 pub enum ExchangeEnum {
     BinanceSwap,
     BinanceSpot,
@@ -28,8 +28,8 @@ pub enum ExchangeEnum {
 ///
 /// new(platform: [ExchangeEnum], is_colo: bool, is_login:bool, params: BTreeMap<String, String>) -> Box\<dyn Platform\>
 /// - `platform(`[ExchangeEnum]`)`: 交易所平台枚举
+/// - `symbol(String)`: 币对
 /// - `is_colo(bool)`: 是否开始告诉模式
-/// - `is_login(bool)`: 是否需要登录
 /// - `params(BTreeMap<String, String>)`: 登录所需参数
 ///
 /// 示例参数值:
@@ -47,26 +47,26 @@ pub enum ExchangeEnum {
 /// let mut params:BTreeMap<String,String> = BTreeMap::new();
 /// params.insert("access_key".to_string(), "your_access_key".to_string());
 /// params.insert("access_key".to_string(), "your_secret_key".to_string());
-/// let exchange = Exchange::new(ExchangeEnum::BinanceSwap, true, true, params);
+/// let exchange = Exchange::new(ExchangeEnum::BinanceSwap, "BTC_USDT".to_string(), false, params);
 pub struct Exchange;
 
 impl Exchange {
-    pub fn new(exchange: ExchangeEnum, is_colo: bool, params: BTreeMap<String, String>) -> Box<dyn Platform> {
+    pub fn new(exchange: ExchangeEnum, symbol: String, is_colo: bool, params: BTreeMap<String, String>) -> Box<dyn Platform> {
         match exchange {
             ExchangeEnum::BinanceSwap => {
-                Box::new(BinanceSwap::new(is_colo, params))
+                Box::new(BinanceSwap::new(symbol, is_colo, params))
             }
             ExchangeEnum::BinanceSpot => {
-                Box::new(BinanceSpot::new(is_colo, true, params))
+                Box::new(BinanceSpot::new(symbol, is_colo, params))
             }
             ExchangeEnum::GateSwap => {
-                Box::new(GateSwap::new(is_colo, params))
+                Box::new(GateSwap::new(symbol, is_colo, params))
             }
             ExchangeEnum::GateSpot => {
-                Box::new(GateSpot::new(is_colo, true, params))
+                Box::new(GateSpot::new(symbol, is_colo, params))
             }
             ExchangeEnum::KucoinSwap => {
-                Box::new(KucoinSwap::new(is_colo, params))
+                Box::new(KucoinSwap::new(symbol, is_colo, params))
             }
         }
     }

+ 1 - 1
standard/src/gate_handle.rs

@@ -4,7 +4,7 @@ use serde_json::json;
 use exchanges::response_base::ResponseData;
 use crate::Account;
 
-pub fn handle_account_info(res_data: ResponseData, symbol: &str) -> Result<Account, Error> {
+pub fn handle_account_info(res_data: ResponseData, symbol: String) -> Result<Account, Error> {
     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();

+ 21 - 23
standard/src/gate_spot.rs

@@ -2,25 +2,25 @@ use std::collections::BTreeMap;
 use std::io::{Error};
 use async_trait::async_trait;
 use rust_decimal::Decimal;
-use crate::{Platform, ExchangeEnum, Account, gate_handle, Position, PositionModeEnum, Ticker, Market, Order};
+use crate::{Platform, ExchangeEnum, Account, gate_handle, Position, PositionModeEnum, Ticker, Market, Order, OrderCommand};
 use exchanges::gate_spot_rest::GateSpotRest;
 use exchanges::response_base::ResponseData;
 
 #[allow(dead_code)]
 pub struct GateSpot {
     exchange: ExchangeEnum,
+    symbol: String,
     is_colo: bool,
-    is_login: bool,
     params: BTreeMap<String, String>,
     request: GateSpotRest,
 }
 
 impl GateSpot {
-    pub fn new(is_colo: bool, is_login: bool, params: BTreeMap<String, String>) -> GateSpot {
+    pub fn new(symbol: String, is_colo: bool, params: BTreeMap<String, String>) -> GateSpot {
         GateSpot {
             exchange: ExchangeEnum::GateSpot,
+            symbol,
             is_colo,
-            is_login,
             params: params.clone(),
             request: GateSpotRest::new(is_colo, params.clone()),
         }
@@ -33,6 +33,8 @@ impl Platform for GateSpot {
     fn get_self_exchange(&self) -> ExchangeEnum {
         ExchangeEnum::GateSpot
     }
+    // 获取交易对
+    fn get_self_symbol(&self) -> String { self.symbol.clone() }
     // 获取是否使用高速通道
     fn get_self_is_colo(&self) -> bool {
         self.is_colo
@@ -47,35 +49,27 @@ impl Platform for GateSpot {
     }
 
     // 获取账号信息
-    async fn get_account(&self, symbol: &str) -> Result<Account, Error> {
-        let symbol_array: Vec<&str> = symbol.split("_").collect();
-        // let res_data = self.request.get_account(&symbol_array[1]).await;
-        let res_data = ResponseData {
-            code: "200".to_string(),
-            message: "gate现货获取账号".to_string() + symbol_array[0] + "信息错误",
-            data: "[]".to_string(),
-            channel: "".to_string(),
-        };
-        gate_handle::handle_account_info(res_data, symbol)
+    async fn get_account(&self) -> Result<Account, Error> {
+        todo!()
     }
     // 获取仓位信息
-    async fn get_position(&self, _symbol: &str, _mode: PositionModeEnum) -> Result<Position, Error> {
+    async fn get_position(&self, _mode: PositionModeEnum) -> Result<Position, Error> {
         todo!()
     }
     // 获取市场行情
-    async fn get_ticker(&self, _symbol: &str) -> Result<Ticker, Error> {
+    async fn get_ticker(&self) -> Result<Ticker, Error> {
         todo!()
     }
 
-    async fn get_market(&self, _symbol: &str) -> Result<Market, Error> {
+    async fn get_market(&self) -> Result<Market, Error> {
         todo!()
     }
 
-    async fn get_order_detail(&self, _symbol: &str, _id: &str) -> Result<Order, Error> {
+    async fn get_order_detail(&self, _id: &str) -> Result<Order, Error> {
         todo!()
     }
 
-    async fn get_orders_list(&self, _symbol: &str, _status: &str) -> Result<Vec<Order>, Error> {
+    async fn get_orders_list(&self, _status: &str) -> Result<Vec<Order>, Error> {
         todo!()
     }
 
@@ -83,7 +77,7 @@ impl Platform for GateSpot {
         todo!()
     }
 
-    async fn set_dual_leverage(&self, _symbol: &str, _leverage: &str) -> Result<String, Error> {
+    async fn set_dual_leverage(&self, _leverage: &str) -> Result<String, Error> {
         todo!()
     }
 
@@ -91,15 +85,19 @@ impl Platform for GateSpot {
         todo!()
     }
 
-    async fn take_order(&self, _custom_id: &str, _origin_side: &str, _coin: &str, _symbol: &str, _amount: Decimal) -> Result<Order, Error> {
+    async fn take_order(&self, _custom_id: &str, _origin_side: &str, _coin: &str, _amount: Decimal) -> Result<Order, Error> {
+        todo!()
+    }
+
+    async fn cancel_order(&self, _order_id: &str, _is_custom_id: Option<bool>) -> Result<Order, Error> {
         todo!()
     }
 
-    async fn cancel_order(&self, _symbol: &str, _order_id: &str) -> Result<Order, Error> {
+    async fn cancel_orders(&self) -> Result<Vec<Order>, Error> {
         todo!()
     }
 
-    async fn cancel_orders(&self, _symbol: &str) -> Result<Vec<Order>, Error> {
+    async fn command_order(&self, _order_command: OrderCommand) {
         todo!()
     }
 }

+ 146 - 38
standard/src/gate_swap.rs

@@ -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 {

+ 144 - 19
standard/src/kucoin_swap.rs

@@ -1,24 +1,29 @@
 use std::collections::BTreeMap;
 use std::io::{Error, ErrorKind};
+use std::str::FromStr;
 use async_trait::async_trait;
 use rust_decimal::Decimal;
+use rust_decimal::prelude::ToPrimitive;
 use rust_decimal_macros::dec;
+use serde_json::{json};
 use exchanges::kucoin_swap_rest::KucoinSwapRest;
 use crate::exchange::ExchangeEnum;
-use crate::{Account, Market, Order, Platform, Position, PositionModeEnum, Ticker};
+use crate::{Account, Market, Order, OrderCommand, Platform, Position, PositionModeEnum, Ticker, utils};
 
 #[allow(dead_code)]
 pub struct KucoinSwap {
     exchange: ExchangeEnum,
+    symbol: String,
     is_colo: bool,
     params: BTreeMap<String, String>,
     request: KucoinSwapRest,
 }
 
 impl KucoinSwap {
-    pub fn new(is_colo: bool, params: BTreeMap<String, String>) -> KucoinSwap {
+    pub fn new(symbol: String, is_colo: bool, params: BTreeMap<String, String>) -> KucoinSwap {
         KucoinSwap {
             exchange: ExchangeEnum::KucoinSwap,
+            symbol,
             is_colo,
             params: params.clone(),
             request: KucoinSwapRest::new(is_colo, params.clone()),
@@ -31,6 +36,8 @@ impl Platform for KucoinSwap {
     fn get_self_exchange(&self) -> ExchangeEnum {
         ExchangeEnum::KucoinSwap
     }
+    // 获取交易对
+    fn get_self_symbol(&self) -> String { self.symbol.clone() }
     // 获取是否使用高速通道
     fn get_self_is_colo(&self) -> bool {
         self.is_colo
@@ -52,15 +59,15 @@ impl Platform for KucoinSwap {
         }
     }
     // 获取账号信息
-    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()).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 balance = res_data_json["accountEquity"].to_string().parse().unwrap_or(dec!(0));
             let available_balance = res_data_json["availableBalance"].to_string().parse().unwrap_or(dec!(0));
-            let frozen_balance = res_data_json["frozenFunds"].to_string().parse().unwrap_or(dec!(0));
+            let frozen_balance = balance - available_balance;
             let result = Account {
                 balance,
                 available_balance,
@@ -75,31 +82,112 @@ impl Platform for KucoinSwap {
         }
     }
 
-    async fn get_position(&self, _symbol: &str, _mode: PositionModeEnum) -> Result<Position, Error> {
-        todo!()
+    async fn get_position(&self, _mode: PositionModeEnum) -> Result<Position, Error> {
+        let symbol_array: Vec<&str> = self.symbol.split("_").collect();
+        let symbol_format = format!("{}M", utils::format_symbol(self.symbol.clone(), ""));
+        let res_data = self.request.get_positions(symbol_array[1].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 default_info = json!({"high_24h": "0","low_24h": "0","lowest_ask": "0","highest_bid": "0","last": "0","volume_24h": "0"});
+            let position_info = res_data_json.iter().find(|item| item["symbol"].as_str().unwrap() == format!("{}M", symbol_format)).unwrap_or(&default_info);
+            let position_mode = match position_info["mode"].as_str().unwrap_or("") {
+                "dual_long" => PositionModeEnum::Long,
+                "dual_short" => PositionModeEnum::Both,
+                _ => PositionModeEnum::Long,
+            };
+            let result = Position {
+                margin_level: position_info["size"].as_str().unwrap_or("1").parse().unwrap_or(dec!(1)),
+                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)),
+                profit: position_info["unrealised_pnl"].as_str().unwrap_or("0").parse().unwrap_or(dec!(0)),
+                position_mode,
+                margin: position_info["margin"].as_str().unwrap_or("0").parse().unwrap_or(dec!(0)),
+            };
+            Ok(result)
+        } else {
+            Err(Error::new(ErrorKind::Other, res_data.message))
+        }
     }
 
-    async fn get_ticker(&self, _symbol: &str) -> Result<Ticker, Error> {
-        todo!()
+    async fn get_ticker(&self) -> Result<Ticker, Error> {
+        let symbol_format = format!("{}M", utils::format_symbol(self.symbol.clone(), ""));
+        let res_data = self.request.get_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 ticker_info = res_data_json;
+            let time = (Decimal::from_str(&*ticker_info["ts"].to_string()).unwrap() / dec!(1000000)).floor().to_i64().unwrap();
+            let result = Ticker {
+                time,
+                high: ticker_info["bestAskPrice"].as_str().unwrap_or("0").parse().unwrap_or(dec!(0)),
+                low: ticker_info["bestBidPrice"].as_str().unwrap_or("0").parse().unwrap_or(dec!(0)),
+                sell: ticker_info["bestAskPrice"].as_str().unwrap_or("0").parse().unwrap_or(dec!(0)),
+                buy: ticker_info["bestBidPrice"].as_str().unwrap_or("0").parse().unwrap_or(dec!(0)),
+                last: ticker_info["price"].as_str().unwrap_or("0").parse().unwrap_or(dec!(0)),
+                volume: ticker_info["size"].to_string().parse().unwrap_or(dec!(0)),
+            };
+            Ok(result)
+        } else {
+            Err(Error::new(ErrorKind::Other, res_data.message))
+        }
     }
 
-    async fn get_market(&self, _symbol: &str) -> Result<Market, Error> {
-        todo!()
+    async fn get_market(&self) -> Result<Market, Error> {
+        let symbol_format = format!("{}M", utils::format_symbol(self.symbol.clone(), ""));
+        let res_data = self.request.get_market_details().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["symbol"].as_str().unwrap() == symbol_format).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 result = Market {
+                symbol: self.symbol.clone(),
+                base_asset: market_info["baseCurrency"].as_str().unwrap_or("").to_string(),
+                quote_asset: market_info["quoteCurrency"].as_str().unwrap_or("").to_string(),
+                tick_size,
+                amount_size,
+                price_precision: dec!(0),
+                amount_precision: dec!(0),
+                min_qty: market_info["order_size_min"].as_str().unwrap_or("0").parse().unwrap_or(dec!(0)),
+                max_qty: market_info["order_size_max"].as_str().unwrap_or("0").parse().unwrap_or(dec!(0)),
+                min_notional: Default::default(),
+                max_notional: Default::default(),
+                ct_val: Default::default(),
+            };
+            Ok(result)
+        } else {
+            Err(Error::new(ErrorKind::Other, res_data.message))
+        }
     }
 
-    async fn get_order_detail(&self, _symbol: &str, _id: &str) -> Result<Order, Error> {
+    async fn get_order_detail(&self, _id: &str) -> Result<Order, Error> {
         todo!()
     }
 
-    async fn get_orders_list(&self, _symbol: &str, _status: &str) -> Result<Vec<Order>, Error> {
-        todo!()
+    async fn get_orders_list(&self, status: &str) -> Result<Vec<Order>, Error> {
+        let symbol_format = format!("{}M", utils::format_symbol(self.symbol.clone(), ""));
+        let res_data = self.request.get_orders(status.to_string(), 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 order_info: Vec<_> = res_data_json.iter().filter(|item| item["contract"].as_str().unwrap_or("") == self.symbol.clone()).collect();
+            let result = order_info.iter().map(|item| parse_order_item(item)).collect();
+            Ok(result)
+        } else {
+            Err(Error::new(ErrorKind::Other, res_data.message))
+        }
     }
 
     async fn set_dual_mode(&self, _coin: &str, _is_dual_mode: bool) -> Result<String, Error> {
         todo!()
     }
 
-    async fn set_dual_leverage(&self, _symbol: &str, _leverage: &str) -> Result<String, Error> {
+    async fn set_dual_leverage(&self, _leverage: &str) -> Result<String, Error> {
         todo!()
     }
 
@@ -107,15 +195,52 @@ impl Platform for KucoinSwap {
         todo!()
     }
 
-    async fn take_order(&self, _custom_id: &str, _origin_side: &str, _coin: &str, _symbol: &str, _amount: Decimal) -> Result<Order, Error> {
-        todo!()
+    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(), symbol_format, origin_side.to_string(), amount.to_u64().unwrap(), "10".to_string(), "".to_string(), "".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 = parse_order_item(&res_data_json);
+            Ok(result)
+        } else {
+            Err(Error::new(ErrorKind::Other, res_data.message))
+        }
     }
 
-    async fn cancel_order(&self, _symbol: &str, _order_id: &str) -> Result<Order, Error> {
+    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 res_data = self.request.cancel_order(symbol_array[1].to_string().to_lowercase(), order_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 = parse_order_item(&res_data_json);
+            Ok(result)
+        } else {
+            Err(Error::new(ErrorKind::Other, res_data.message))
+        }
+    }
+
+    async fn cancel_orders(&self) -> Result<Vec<Order>, Error> {
         todo!()
     }
 
-    async fn cancel_orders(&self, _symbol: &str) -> Result<Vec<Order>, Error> {
+    // 指令下单
+    async fn command_order(&self, order_command: OrderCommand) {
         todo!()
     }
 }
+
+fn parse_order_item(order: &serde_json::Value) -> Order {
+    Order {
+        id: order["id"].to_string(),
+        custom_id: order["text"].to_string(),
+        price: order["price"].as_str().unwrap_or("0").parse().unwrap_or(dec!(0)),
+        amount: order["size"].to_string().parse().unwrap_or(dec!(0)),
+        deal_amount: Default::default(),
+        avg_price: Default::default(),
+        status: "".to_string(),
+        order_type: "".to_string(),
+    }
+}

+ 56 - 19
standard/src/lib.rs

@@ -1,4 +1,4 @@
-use std::collections::BTreeMap;
+use std::collections::{BTreeMap, HashMap};
 use std::io::{Error};
 use async_trait::async_trait;
 use rust_decimal::Decimal;
@@ -26,6 +26,39 @@ pub enum PositionModeEnum {
     Short,
 }
 
+#[derive(Debug)]
+pub enum OrderCommandEnum {
+    Cancel,
+    Limits,
+    Check,
+    LimitsOpen,
+    LimitsClose,
+}
+
+/// OrderCommand结构体(下单指令)
+/// - `cancel(Vec<String>)`: 取消订单指令;
+/// - `limits(HashMap<String, Vec<String>>)`: 限价单指令;
+/// - `check(HashMap<String, Vec<String>>)`: balance挂单的冻结数量
+/// - `limits_open(HashMap<String, Vec<String>>)`: 总计交易币数量
+/// - `limits_close(HashMap<String, Vec<String>>)`: 可用交易币数量
+#[derive(Debug, Clone)]
+pub struct OrderCommand {
+    // 取消订单指令,数据结构例子:
+    //  [c_id, o_id]
+    pub cancel: HashMap<String, Vec<String>>,
+    // 限价单指令,数据结构例子:
+    // {
+    //  order_name: [数量,方向,价格,c_id]
+    // }
+    pub limits: HashMap<String, Vec<String>>,
+    // 检验指令,数据结构例子:(暂没找到例子)
+    pub check: HashMap<String, Vec<String>>,
+    // 限开指令,数据结构例子:(暂没找到例子)
+    // pub limits_open: HashMap<String, Vec<String>>,
+    // 限收指令,数据结构例子:(暂没找到例子)
+    // pub limits_close: HashMap<String, Vec<String>>
+}
+
 /// Account结构体(账户信息)
 /// - `balance(Decimal)`: 总计计价币数量;
 /// - `available_balance(Decimal)`: 可用计价币数量;
@@ -199,7 +232,7 @@ pub struct Position {
 /// let mut params:BTreeMap<String,String> = BTreeMap::new();
 /// params.insert("access_key".to_string(), "your_access_key".to_string());
 /// params.insert("access_key".to_string(), "your_secret_key".to_string());
-/// let exchange = Exchange::new(ExchangeEnum::BinanceSwap, true, params);
+/// let exchange = Exchange::new(ExchangeEnum::BinanceSwap, "BTC_USDT".to_string(), true, params);
 /// ```
 /// 获取当前交易所交易模式
 /// - fn get_self_exchange(&self) -> ExchangeEnum;
@@ -209,7 +242,7 @@ pub struct Position {
 /// # let mut params:BTreeMap<String,String> = BTreeMap::new();
 /// # params.insert("access_key".to_string(), "your_access_key".to_string());
 /// # params.insert("access_key".to_string(), "your_secret_key".to_string());
-/// # let exchange = Exchange::new(ExchangeEnum::BinanceSwap, true, params);
+/// # let exchange = Exchange::new(ExchangeEnum::BinanceSwap, "BTC_USDT".to_string(), true, params);
 ///
 /// exchange.get_self_exchange();
 /// ```
@@ -221,7 +254,7 @@ pub struct Position {
 /// # let mut params:BTreeMap<String,String> = BTreeMap::new();
 /// # params.insert("access_key".to_string(), "your_access_key".to_string());
 /// # params.insert("access_key".to_string(), "your_secret_key".to_string());
-/// # let exchange = Exchange::new(ExchangeEnum::BinanceSwap, true, params);
+/// # let exchange = Exchange::new(ExchangeEnum::BinanceSwap, "BTC_USDT".to_string(), true, params);
 ///
 /// exchange.get_self_is_colo();
 /// ```
@@ -233,7 +266,7 @@ pub struct Position {
 /// # let mut params:BTreeMap<String,String> = BTreeMap::new();
 /// # params.insert("access_key".to_string(), "your_access_key".to_string());
 /// # params.insert("access_key".to_string(), "your_secret_key".to_string());
-/// # let exchange = Exchange::new(ExchangeEnum::BinanceSwap, true, params);
+/// # let exchange = Exchange::new(ExchangeEnum::BinanceSwap, "BTC_USDT".to_string(), true, params);
 ///
 /// exchange.get_self_is_login();
 /// ```
@@ -245,7 +278,7 @@ pub struct Position {
 /// # let mut params:BTreeMap<String,String> = BTreeMap::new();
 /// # params.insert("access_key".to_string(), "your_access_key".to_string());
 /// # params.insert("access_key".to_string(), "your_secret_key".to_string());
-/// # let exchange = Exchange::new(ExchangeEnum::BinanceSwap, true, params);
+/// # let exchange = Exchange::new(ExchangeEnum::BinanceSwap, "BTC_USDT".to_string(), true, params);
 ///
 /// exchange.get_self_params();
 /// ```
@@ -257,9 +290,9 @@ pub struct Position {
 /// # let mut params:BTreeMap<String,String> = BTreeMap::new();
 /// # params.insert("access_key".to_string(), "your_access_key".to_string());
 /// # params.insert("access_key".to_string(), "your_secret_key".to_string());
-/// # let exchange = Exchange::new(ExchangeEnum::BinanceSwap, true, params);
+/// # let exchange = Exchange::new(ExchangeEnum::BinanceSwap, "BTC_USDT".to_string(), true, params);
 ///
-/// exchange.get_account("BTC_USDT")
+/// exchange.get_account()
 /// ```
 /// 订阅账号信息
 /// ```rust
@@ -268,7 +301,7 @@ pub struct Position {
 /// # let mut params:BTreeMap<String,String> = BTreeMap::new();
 /// # params.insert("access_key".to_string(), "your_access_key".to_string());
 /// # params.insert("access_key".to_string(), "your_secret_key".to_string());
-/// # let exchange = Exchange::new(ExchangeEnum::BinanceSwap, true, params);
+/// # let exchange = Exchange::new(ExchangeEnum::BinanceSwap, "BTC_USDT".to_string(), true, params);
 ///
 /// exchange.subscribe_account();
 /// ```
@@ -276,6 +309,8 @@ pub struct Position {
 pub trait Platform {
     // 获取当前交易所交易模式
     fn get_self_exchange(&self) -> ExchangeEnum;
+    // 获取交易对
+    fn get_self_symbol(&self) -> String;
     // 获取当前是否使用高速模式
     fn get_self_is_colo(&self) -> bool;
     // 获取登录params信息
@@ -283,28 +318,30 @@ pub trait Platform {
     // 获取服务器时间
     async fn get_server_time(&self) -> Result<String, Error>;
     // 获取账号信息
-    async fn get_account(&self, symbol: &str) -> Result<Account, Error>;
+    async fn get_account(&self) -> Result<Account, Error>;
     // 获取持仓信息
-    async fn get_position(&self, symbol: &str, mode: PositionModeEnum) -> Result<Position, Error>;
+    async fn get_position(&self, mode: PositionModeEnum) -> Result<Position, Error>;
     // 获取市场行情
-    async fn get_ticker(&self, symbol: &str) -> Result<Ticker, Error>;
+    async fn get_ticker(&self) -> Result<Ticker, Error>;
     // 查询所有的合约信息
-    async fn get_market(&self, symbol: &str) -> Result<Market, Error>;
+    async fn get_market(&self) -> Result<Market, Error>;
     // 查询订单详情
-    async fn get_order_detail(&self, symbol: &str, id: &str) -> Result<Order, Error>;
+    async fn get_order_detail(&self, id: &str) -> Result<Order, Error>;
     // 获取订单列表
-    async fn get_orders_list(&self, symbol: &str, status: &str) -> Result<Vec<Order>, Error>;
+    async fn get_orders_list(&self, status: &str) -> Result<Vec<Order>, Error>;
     // 设置持仓模式
     async fn set_dual_mode(&self, coin: &str, is_dual_mode: bool) -> Result<String, Error>;
     // 更新双持仓模式下杠杆
-    async fn set_dual_leverage(&self, symbol: &str, leverage: &str) -> Result<String, Error>;
+    async fn set_dual_leverage(&self, leverage: &str) -> Result<String, Error>;
     // 交易账户互转
     async fn wallet_transfers(&self, coin: &str, from: &str, to: &str, amount: Decimal) -> Result<String, Error>;
     // 下单接口
-    async fn take_order(&self, custom_id: &str, origin_side: &str, coin: &str, symbol: &str, amount: Decimal) -> Result<Order, Error>;
+    async fn take_order(&self, custom_id: &str, origin_side: &str, coin: &str, amount: Decimal) -> Result<Order, Error>;
     // 撤销订单
-    async fn cancel_order(&self, symbol: &str, order_id: &str) -> Result<Order,Error>;
+    async fn cancel_order(&self, order_id: &str, is_custom_id: Option<bool>) -> Result<Order, Error>;
     // 批量撤销订单
-    async fn cancel_orders(&self, symbol: &str) -> Result<Vec<Order>, Error>;
+    async fn cancel_orders(&self) -> Result<Vec<Order>, Error>;
+    // 指令下单
+    async fn command_order(&self, order_command: OrderCommand);
 }
 

+ 1 - 1
standard/src/utils.rs

@@ -1,6 +1,6 @@
 /// 修改交易对连接符号
 /// - `symbol(str)`: 交易对, "BTC_USDT", 默认以下划线传递
 /// - `pat(str)`: 替换字符, "-", 把 “_” 替换为 "-"
-pub fn format_symbol(symbol: &str, pat: &str) -> String {
+pub fn format_symbol(symbol: String, pat: &str) -> String {
     return symbol.to_uppercase().replace("_", pat);
 }

+ 46 - 20
standard/tests/libs_test.rs

@@ -17,7 +17,7 @@ fn test_new_exchange(exchange: ExchangeEnum) -> Box<dyn Platform> {
             let secret_key = env::var("binance_secret_key").unwrap_or("".to_string());
             params.insert("access_key".to_string(), access_key);
             params.insert("secret_key".to_string(), secret_key);
-            Exchange::new(exchange, false, params)
+            Exchange::new(exchange, "ROSE_USDT".to_string(), false, params)
         }
         ExchangeEnum::BinanceSpot => {
             let mut params: BTreeMap<String, String> = BTreeMap::new();
@@ -25,7 +25,7 @@ fn test_new_exchange(exchange: ExchangeEnum) -> Box<dyn Platform> {
             let secret_key = env::var("binance_secret_key").unwrap_or("".to_string());
             params.insert("access_key".to_string(), access_key);
             params.insert("secret_key".to_string(), secret_key);
-            Exchange::new(exchange, false, params)
+            Exchange::new(exchange, "ROSE_USDT".to_string(), false, params)
         }
         ExchangeEnum::GateSwap => {
             let mut params: BTreeMap<String, String> = BTreeMap::new();
@@ -33,7 +33,7 @@ fn test_new_exchange(exchange: ExchangeEnum) -> Box<dyn Platform> {
             let secret_key = env::var("gate_secret_key").unwrap_or("".to_string());
             params.insert("access_key".to_string(), access_key);
             params.insert("secret_key".to_string(), secret_key);
-            Exchange::new(exchange, false, params)
+            Exchange::new(exchange, "ROSE_USDT".to_string(), false, params)
         }
         ExchangeEnum::GateSpot => {
             let mut params: BTreeMap<String, String> = BTreeMap::new();
@@ -41,7 +41,7 @@ fn test_new_exchange(exchange: ExchangeEnum) -> Box<dyn Platform> {
             let secret_key = env::var("gate_secret_key").unwrap_or("".to_string());
             params.insert("access_key".to_string(), access_key);
             params.insert("secret_key".to_string(), secret_key);
-            Exchange::new(exchange, false, params)
+            Exchange::new(exchange, "ROSE_USDT".to_string(), false, params)
         }
         ExchangeEnum::KucoinSwap => {
             let mut params: BTreeMap<String, String> = BTreeMap::new();
@@ -51,7 +51,7 @@ fn test_new_exchange(exchange: ExchangeEnum) -> Box<dyn Platform> {
             params.insert("access_key".to_string(), access_key);
             params.insert("secret_key".to_string(), secret_key);
             params.insert("pass_key".to_string(), pass_key);
-            Exchange::new(exchange, false, params)
+            Exchange::new(exchange, "ROSE_USDT".to_string(), false, params)
         }
     }
 }
@@ -104,62 +104,88 @@ async fn test_kucoin_swap_account() {
 // 测试币对连接符号替换
 #[tokio::test]
 async fn test_replace_symbol() {
-    println!("test_replace_symbol: {}", utils::format_symbol("BTC_USDT", "-"))
+    println!("test_replace_symbol: {}", utils::format_symbol("BTC_USDT".to_string(), "-"))
 }
 
 // 测试Binance期货K线推送
 #[tokio::test]
 async fn test_get_account() {
     let binance_swap_exchange: Box<dyn Platform> = test_new_exchange(ExchangeEnum::BinanceSwap);
-    println!("binance_swap account:{:?}", binance_swap_exchange.get_account("BTC_USDT").await);
+    println!("binance_swap account:{:?}", binance_swap_exchange.get_account().await);
     let binance_spot_exchange: Box<dyn Platform> = test_new_exchange(ExchangeEnum::BinanceSpot);
-    println!("binance_spot account:{:?}", binance_spot_exchange.get_account("BTC_USDT").await);
+    println!("binance_spot account:{:?}", binance_spot_exchange.get_account().await);
     let gate_swap_exchange: Box<dyn Platform> = test_new_exchange(ExchangeEnum::GateSwap);
-    println!("gate_swap account:{:?}", gate_swap_exchange.get_account("BTC_USDT").await);
-    let gate_spot_exchange: Box<dyn Platform> = test_new_exchange(ExchangeEnum::GateSpot);
-    println!("gate_spot account:{:?}", gate_spot_exchange.get_account("BTC_USDT").await);
+    println!("gate_swap account:{:?}", gate_swap_exchange.get_account().await);
     let kucoin_swap_exchange: Box<dyn Platform> = test_new_exchange(ExchangeEnum::KucoinSwap);
-    println!("kucoin_swap account:{:?}", kucoin_swap_exchange.get_account("BTC_USDT").await);
+    println!("kucoin_swap account:{:?}", kucoin_swap_exchange.get_account().await);
 }
 
 // 测试Gate 获取持仓信息
 #[tokio::test]
 async fn test_gate_swap_get_position() {
     let gate_swap_exchange: Box<dyn Platform> = test_new_exchange(ExchangeEnum::GateSwap);
-    println!("gate_swap position:{:?}", gate_swap_exchange.get_position("CYBER_USDT", PositionModeEnum::Both).await);
+    println!("gate_swap get_position:{:?}", gate_swap_exchange.get_position(PositionModeEnum::Both).await);
 }
 
 // 测试Gate获取Ticker信息
 #[tokio::test]
 async fn test_gate_swap_get_ticker() {
     let gate_swap_exchange: Box<dyn Platform> = test_new_exchange(ExchangeEnum::GateSwap);
-    println!("gate_swap ticker:{:?}", gate_swap_exchange.get_ticker("CYBER_USDT").await);
+    println!("gate_swap get_ticker:{:?}", gate_swap_exchange.get_ticker().await);
 }
 
-// 测试Gate获取Maket信息
+// 测试Gate获取Market信息
 #[tokio::test]
 async fn test_gate_swap_get_market() {
     let gate_swap_exchange: Box<dyn Platform> = test_new_exchange(ExchangeEnum::GateSwap);
-    println!("gate_swap market:{:?}", gate_swap_exchange.get_market("CYBER_USDT").await);
+    println!("gate_swap get_market:{:?}", gate_swap_exchange.get_market().await);
 }
 
 // 测试Gate获取Order详情信息
 #[tokio::test]
 async fn test_gate_swap_get_order_detail() {
     let gate_swap_exchange: Box<dyn Platform> = test_new_exchange(ExchangeEnum::GateSwap);
-    println!("gate_swap order_detail:{:?}", gate_swap_exchange.get_order_detail("CYBER_USDT", "336321097375").await);
+    println!("gate_swap get_order_detail:{:?}", gate_swap_exchange.get_order_detail("336321097375").await);
 }
 
 // 测试Gate获取Order列表信息
 #[tokio::test]
 async fn test_gate_swap_get_orders_list() {
     let gate_swap_exchange: Box<dyn Platform> = test_new_exchange(ExchangeEnum::GateSwap);
-    println!("gate_swap orders_list:{:?}", gate_swap_exchange.get_orders_list("CYBER_USDT", "finished").await);
+    println!("gate_swap get_orders_list:{:?}", gate_swap_exchange.get_orders_list("finished").await);
 }
 
-// 设置持仓模式
+// 测试Gate 设置持仓模式
 #[tokio::test]
 async fn test_set_dual_mode() {
     let gate_swap_exchange: Box<dyn Platform> = test_new_exchange(ExchangeEnum::GateSwap);
-    println!("gate_swap orders_list:{:?}", gate_swap_exchange.set_dual_mode("usdt", true).await);
+    println!("gate_swap set_dual_mode:{:?}", gate_swap_exchange.set_dual_mode("usdt", true).await);
+}
+
+// 测试Gate 设置持仓模式
+#[tokio::test]
+async fn test_set_dual_leverage() {
+    let gate_swap_exchange: Box<dyn Platform> = test_new_exchange(ExchangeEnum::GateSwap);
+    println!("gate_swap set_dual_leverage:{:?}", gate_swap_exchange.set_dual_leverage("10").await);
+}
+
+// 测试kucoin 获取持仓信息
+#[tokio::test]
+async fn test_kucoin_swap_get_position() {
+    let kucoin_swap_exchange: Box<dyn Platform> = test_new_exchange(ExchangeEnum::KucoinSwap);
+    println!("kucoin_swap get_position:{:?}", kucoin_swap_exchange.get_position(PositionModeEnum::Both).await);
+}
+
+// 测试kucoin 获取Ticker信息
+#[tokio::test]
+async fn test_kucoin_swap_get_ticker() {
+    let kucoin_swap_exchange: Box<dyn Platform> = test_new_exchange(ExchangeEnum::KucoinSwap);
+    println!("kucoin_swap get_ticker:{:?}", kucoin_swap_exchange.get_ticker().await);
+}
+
+// 测试kucoin 获取Market信息
+#[tokio::test]
+async fn test_kucoin_swap_get_market() {
+    let kucoin_swap_exchange: Box<dyn Platform> = test_new_exchange(ExchangeEnum::KucoinSwap);
+    println!("kucoin_swap get_market:{:?}", kucoin_swap_exchange.get_market().await);
 }