瀏覽代碼

币安交易接入,修复开亏损单

1. binance接入
2. 以参考交易所的最小价格步长计算最大最小价差参数
JiahengHe 1 年之前
父節點
當前提交
948cba7830

+ 302 - 25
standard/src/binance_swap.rs

@@ -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;
 }

+ 10 - 10
standard/src/bitget_spot.rs

@@ -24,12 +24,12 @@ pub struct BitgetSpot {
     params: BTreeMap<String, String>,
     request: BitgetSpotRest,
     market: Market,
-    order_sender: Sender<Order>,
-    error_sender: Sender<Error>,
+    order_sender: Option<Sender<Order>>,
+    error_sender: Option<Sender<Error>>,
 }
 
 impl BitgetSpot {
-    pub async fn new(symbol: String, is_colo: bool, params: BTreeMap<String, String>, order_sender: Sender<Order>, error_sender: Sender<Error>) -> BitgetSpot {
+    pub async fn new(symbol: String, is_colo: bool, params: BTreeMap<String, String>, order_sender: Option<Sender<Order>>, error_sender: Option<Sender<Error>>) -> BitgetSpot {
         let market = Market::new();
         let mut bitget_spot = BitgetSpot {
             exchange: ExchangeEnum::BitgetSpot,
@@ -493,14 +493,14 @@ impl Platform for BitgetSpot {
                         let query_rst = self_clone.get_order_detail(&order_id, &custom_id).await;
                         match query_rst {
                             Ok(order) => {
-                                result_sd.send(order).await.unwrap();
+                                result_sd.unwrap().send(order).await.unwrap();
                             }
                             Err(_query_err) => {
                                 // error!(?_query_err);
                                 // error!("撤单失败,而且查单也失败了,bitget_spot,oid={}, cid={}。", order_id.clone(), custom_id.clone());
                             }
                         }
-                        err_sd.send(error).await.unwrap();
+                        err_sd.unwrap().send(error).await.unwrap();
                     }
                 }
             });
@@ -533,15 +533,15 @@ impl Platform for BitgetSpot {
                         ts.on_after_send();
                         result.trace_stack = ts;
 
-                        result_sd.send(result).await.unwrap();
+                        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.send(err_order).await.unwrap();
-                        err_sd.send(error).await.unwrap();
+                        result_sd.unwrap().send(err_order).await.unwrap();
+                        err_sd.unwrap().send(error).await.unwrap();
                     }
                 }
             });
@@ -561,10 +561,10 @@ impl Platform for BitgetSpot {
                 let result = self_clone.get_order_detail(&order_id, &custom_id).await;
                 match result {
                     Ok(result) => {
-                        result_sd.send(result).await.unwrap();
+                        result_sd.unwrap().send(result).await.unwrap();
                     }
                     Err(error) => {
-                        err_sd.send(error).await.unwrap();
+                        err_sd.unwrap().send(error).await.unwrap();
                     }
                 }
             });

+ 13 - 13
standard/src/bybit_swap.rs

@@ -36,12 +36,12 @@ pub struct BybitSwap {
     params: BTreeMap<String, String>,
     request: BybitSwapRest,
     market: Market,
-    order_sender: Sender<Order>,
-    error_sender: Sender<Error>,
+    order_sender: Option<Sender<Order>>,
+    error_sender: Option<Sender<Error>>,
 }
 
 impl BybitSwap {
-    pub async fn new(symbol: String, is_colo: bool, params: BTreeMap<String, String>, order_sender: Sender<Order>, error_sender: Sender<Error>) -> BybitSwap {
+    pub async fn new(symbol: String, is_colo: bool, params: BTreeMap<String, String>, order_sender: Option<Sender<Order>>, error_sender: Option<Sender<Error>>) -> BybitSwap {
         let market = Market::new();
         let mut bybit_swap = BybitSwap {
             exchange: ExchangeEnum::BybitSwap,
@@ -78,7 +78,7 @@ impl Platform for BybitSwap {
     fn clone_box(&self) -> Box<dyn Platform + Send + Sync> { Box::new(self.clone()) }
     // 获取交易所模式
     fn get_self_exchange(&self) -> ExchangeEnum {
-        ExchangeEnum::GateSwap
+        ExchangeEnum::BybitSwap
     }
     // 获取交易对
     fn get_self_symbol(&self) -> String { self.symbol.clone() }
@@ -574,14 +574,14 @@ impl Platform for BybitSwap {
                         let query_rst = self_clone.get_order_detail(&order_id, &custom_id).await;
                         match query_rst {
                             Ok(order) => {
-                                result_sd.send(order).await.unwrap();
+                                result_sd.unwrap().send(order).await.unwrap();
                             }
                             Err(_err) => {
-                                // error!("撤单失败,而且查单也失败了,gate_io_swap,oid={}, cid={}。", order_id.clone(), custom_id.clone());
-                                // panic!("撤单失败,而且查单也失败了,gate_io_swap,oid={}, cid={}。", order_id.clone(), custom_id.clone());
+                                // error!("撤单失败,而且查单也失败了,bybit_io_swap,oid={}, cid={}。", order_id.clone(), custom_id.clone());
+                                // panic!("撤单失败,而且查单也失败了,bybit_io_swap,oid={}, cid={}。", order_id.clone(), custom_id.clone());
                             }
                         }
-                        err_sd.send(error).await.unwrap();
+                        err_sd.unwrap().send(error).await.unwrap();
                     }
                 }
             });
@@ -614,15 +614,15 @@ impl Platform for BybitSwap {
                         ts.on_after_send();
                         result.trace_stack = ts;
 
-                        result_sd.send(result).await.unwrap();
+                        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.send(err_order).await.unwrap();
-                        err_sd.send(error).await.unwrap();
+                        result_sd.unwrap().send(err_order).await.unwrap();
+                        err_sd.unwrap().send(error).await.unwrap();
                     }
                 }
             });
@@ -642,10 +642,10 @@ impl Platform for BybitSwap {
                 let result = self_clone.get_order_detail(&order_id, &custom_id).await;
                 match result {
                     Ok(result) => {
-                        result_sd.send(result).await.unwrap();
+                        result_sd.unwrap().send(result).await.unwrap();
                     }
                     Err(error) => {
-                        err_sd.send(error).await.unwrap();
+                        err_sd.unwrap().send(error).await.unwrap();
                     }
                 }
             });

+ 2 - 2
standard/src/exchange.rs

@@ -66,12 +66,12 @@ pub enum ExchangeEnum {
 /// let (order_sender, _order_receiver): (mpsc::Sender<Order>, mpsc::Receiver<Order>) = mpsc::channel(1024);
 /// let (error_sender, _error_receiver): (mpsc::Sender<Error>, mpsc::Receiver<Error>) = mpsc::channel(1024);
 ///
-/// let exchange = Exchange::new(ExchangeEnum::BinanceSwap, "BTC_USDT".to_string(), false, params, order_sender, error_sender);
+/// let exchange = Exchange::new(ExchangeEnum::BinanceSwap, "BTC_USDT".to_string(), false, params, Some(order_sender), Some(error_sender));
 #[derive(Debug, Clone)]
 pub struct Exchange;
 
 impl Exchange {
-    pub async fn new(exchange: ExchangeEnum, symbol: String, is_colo: bool, params: BTreeMap<String, String>, order_sender: Sender<Order>, error_sender: Sender<Error>) -> Box<dyn Platform + Send + Sync> {
+    pub async fn new(exchange: ExchangeEnum, symbol: String, is_colo: bool, params: BTreeMap<String, String>, order_sender: Option<Sender<Order>>, error_sender: Option<Sender<Error>>) -> Box<dyn Platform + Send + Sync> {
         match exchange {
             ExchangeEnum::BinanceSwap => {
                 Box::new(BinanceSwap::new(symbol, is_colo, params, order_sender, error_sender).await)

+ 10 - 10
standard/src/gate_swap.rs

@@ -22,12 +22,12 @@ pub struct GateSwap {
     params: BTreeMap<String, String>,
     request: GateSwapRest,
     market: Market,
-    order_sender: Sender<Order>,
-    error_sender: Sender<Error>,
+    order_sender: Option<Sender<Order>>,
+    error_sender: Option<Sender<Error>>,
 }
 
 impl GateSwap {
-    pub async fn new(symbol: String, is_colo: bool, params: BTreeMap<String, String>, order_sender: Sender<Order>, error_sender: Sender<Error>) -> GateSwap {
+    pub async fn new(symbol: String, is_colo: bool, params: BTreeMap<String, String>, order_sender: Option<Sender<Order>>, error_sender: Option<Sender<Error>>) -> GateSwap {
         let market = Market::new();
         let mut gate_swap = GateSwap {
             exchange: ExchangeEnum::GateSwap,
@@ -548,14 +548,14 @@ impl Platform for GateSwap {
                         let query_rst = self_clone.get_order_detail(&order_id, &custom_id).await;
                         match query_rst {
                             Ok(order) => {
-                                result_sd.send(order).await.unwrap();
+                                result_sd.unwrap().send(order).await.unwrap();
                             }
                             Err(_err) => {
                                 // error!("撤单失败,而且查单也失败了,gate_io_swap,oid={}, cid={}。", order_id.clone(), custom_id.clone());
                                 // panic!("撤单失败,而且查单也失败了,gate_io_swap,oid={}, cid={}。", order_id.clone(), custom_id.clone());
                             }
                         }
-                        err_sd.send(error).await.unwrap();
+                        err_sd.unwrap().send(error).await.unwrap();
                     }
                 }
             });
@@ -588,15 +588,15 @@ impl Platform for GateSwap {
                         ts.on_after_send();
                         result.trace_stack = ts;
 
-                        result_sd.send(result).await.unwrap();
+                        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.send(err_order).await.unwrap();
-                        err_sd.send(error).await.unwrap();
+                        result_sd.unwrap().send(err_order).await.unwrap();
+                        err_sd.unwrap().send(error).await.unwrap();
                     }
                 }
             });
@@ -616,10 +616,10 @@ impl Platform for GateSwap {
                 let result = self_clone.get_order_detail(&order_id, &custom_id).await;
                 match result {
                     Ok(result) => {
-                        result_sd.send(result).await.unwrap();
+                        result_sd.unwrap().send(result).await.unwrap();
                     }
                     Err(error) => {
-                        err_sd.send(error).await.unwrap();
+                        err_sd.unwrap().send(error).await.unwrap();
                     }
                 }
             });

+ 10 - 10
standard/src/kucoin_spot.rs

@@ -196,12 +196,12 @@ pub struct KucoinSpot {
     params: BTreeMap<String, String>,
     request: KucoinSpotRest,
     market: Market,
-    order_sender: Sender<Order>,
-    error_sender: Sender<Error>,
+    order_sender: Option<Sender<Order>>,
+    error_sender: Option<Sender<Error>>,
 }
 
 impl KucoinSpot {
-    pub async fn new(symbol: String, is_colo: bool, params: BTreeMap<String, String>, order_sender: Sender<Order>, error_sender: Sender<Error>) -> KucoinSpot {
+    pub async fn new(symbol: String, is_colo: bool, params: BTreeMap<String, String>, order_sender: Option<Sender<Order>>, error_sender: Option<Sender<Error>>) -> KucoinSpot {
         let market = Market::new();
         let mut kucoin_spot = KucoinSpot {
             exchange: ExchangeEnum::KucoinSpot,
@@ -638,14 +638,14 @@ impl Platform for KucoinSpot {
                         let query_rst = self_clone.get_order_detail(&order_id, &custom_id).await;
                         match query_rst {
                             Ok(order) => {
-                                result_sd.send(order).await.unwrap();
+                                result_sd.unwrap().send(order).await.unwrap();
                             }
                             Err(_query_err) => {
                                 // error!(?_query_err);
                                 // error!("撤单失败,而且查单也失败了,bitget_spot,oid={}, cid={}。", order_id.clone(), custom_id.clone());
                             }
                         }
-                        err_sd.send(error).await.unwrap();
+                        err_sd.unwrap().send(error).await.unwrap();
                     }
                 }
             });
@@ -678,15 +678,15 @@ impl Platform for KucoinSpot {
                         ts.on_after_send();
                         result.trace_stack = ts;
 
-                        result_sd.send(result).await.unwrap();
+                        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.send(err_order).await.unwrap();
-                        err_sd.send(error).await.unwrap();
+                        result_sd.unwrap().send(err_order).await.unwrap();
+                        err_sd.unwrap().send(error).await.unwrap();
                     }
                 }
             });
@@ -706,10 +706,10 @@ impl Platform for KucoinSpot {
                 let result = self_clone.get_order_detail(&order_id, &custom_id).await;
                 match result {
                     Ok(result) => {
-                        result_sd.send(result).await.unwrap();
+                        result_sd.unwrap().send(result).await.unwrap();
                     }
                     Err(error) => {
-                        err_sd.send(error).await.unwrap();
+                        err_sd.unwrap().send(error).await.unwrap();
                     }
                 }
             });

+ 10 - 10
standard/src/kucoin_swap.rs

@@ -24,12 +24,12 @@ pub struct KucoinSwap {
     params: BTreeMap<String, String>,
     request: KucoinSwapRest,
     market: Market,
-    order_sender: Sender<Order>,
-    error_sender: Sender<Error>,
+    order_sender: Option<Sender<Order>>,
+    error_sender: Option<Sender<Error>>,
 }
 
 impl KucoinSwap {
-    pub async fn new(symbol: String, is_colo: bool, params: BTreeMap<String, String>, order_sender: Sender<Order>, error_sender: Sender<Error>) -> KucoinSwap {
+    pub async fn new(symbol: String, is_colo: bool, params: BTreeMap<String, String>, order_sender: Option<Sender<Order>>, error_sender: Option<Sender<Error>>) -> KucoinSwap {
         let market = Market::new();
         let mut kucoin_swap = KucoinSwap {
             exchange: ExchangeEnum::KucoinSwap,
@@ -569,14 +569,14 @@ impl Platform for KucoinSwap {
                             let query_rst = self_clone.get_order_detail(&order_id, &custom_id).await;
                             match query_rst {
                                 Ok(order) => {
-                                    result_sd.send(order).await.unwrap();
+                                    result_sd.unwrap().send(order).await.unwrap();
                                 }
                                 Err(_query_err) => {
                                     // error!(?_query_err);
                                     // error!("撤单失败,而且查单也失败了,kucoin_swap,oid={}, cid={}。", order_id.clone(), custom_id.clone());
                                 }
                             }
-                            err_sd.send(error).await.unwrap();
+                            err_sd.unwrap().send(error).await.unwrap();
                         }
                     }
                 }
@@ -614,15 +614,15 @@ impl Platform for KucoinSwap {
                         ts.on_after_send();
                         result.trace_stack = ts.clone();
 
-                        result_sd.send(result).await.unwrap();
+                        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.send(err_order).await.unwrap();
-                        err_sd.send(error).await.unwrap();
+                        result_sd.unwrap().send(err_order).await.unwrap();
+                        err_sd.unwrap().send(error).await.unwrap();
                     }
                 }
             });
@@ -645,10 +645,10 @@ impl Platform for KucoinSwap {
                 let result = self_clone.get_order_detail(&order_id, &custom_id).await;
                 match result {
                     Ok(result) => {
-                        result_sd.send(result).await.unwrap();
+                        result_sd.unwrap().send(result).await.unwrap();
                     }
                     Err(error) => {
-                        err_sd.send(error).await.unwrap();
+                        err_sd.unwrap().send(error).await.unwrap();
                     }
                 }
             });

+ 10 - 10
standard/src/okx_swap.rs

@@ -471,12 +471,12 @@ pub struct OkxSwap {
     params: BTreeMap<String, String>,
     request: OkxSwapRest,
     market: Market,
-    order_sender: Sender<Order>,
-    error_sender: Sender<Error>,
+    order_sender: Option<Sender<Order>>,
+    error_sender: Option<Sender<Error>>,
 }
 
 impl OkxSwap {
-    pub async fn new(symbol: String, is_colo: bool, params: BTreeMap<String, String>, order_sender: Sender<Order>, error_sender: Sender<Error>) -> OkxSwap {
+    pub async fn new(symbol: String, is_colo: bool, params: BTreeMap<String, String>, order_sender: Option<Sender<Order>>, error_sender: Option<Sender<Error>>) -> OkxSwap {
         let market = Market::new();
         let mut okx_swap = OkxSwap {
             exchange: ExchangeEnum::OkxSwap,
@@ -942,14 +942,14 @@ impl Platform for OkxSwap {
                             let query_rst = self_clone.get_order_detail(&order_id, &custom_id).await;
                             match query_rst {
                                 Ok(order) => {
-                                    result_sd.send(order).await.unwrap();
+                                    result_sd.unwrap().send(order).await.unwrap();
                                 }
                                 Err(query_err) => {
                                     error!(?query_err);
                                     error!("撤单失败,而且查单也失败了,okx_swap,oid={}, cid={}。", order_id.clone(), custom_id.clone());
                                 }
                             }
-                            err_sd.send(error).await.unwrap();
+                            err_sd.unwrap().send(error).await.unwrap();
                         }
                     }
                 }
@@ -982,15 +982,15 @@ impl Platform for OkxSwap {
                         ts.on_after_send();
                         result.trace_stack = ts.clone();
 
-                        result_sd.send(result).await.unwrap();
+                        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.send(err_order).await.unwrap();
-                        err_sd.send(error).await.unwrap();
+                        result_sd.unwrap().send(err_order).await.unwrap();
+                        err_sd.unwrap().send(error).await.unwrap();
                     }
                 }
             });
@@ -1010,10 +1010,10 @@ impl Platform for OkxSwap {
                 let result = self_clone.get_order_detail(&order_id, &custom_id).await;
                 match result {
                     Ok(result) => {
-                        result_sd.send(result).await.unwrap();
+                        result_sd.unwrap().send(result).await.unwrap();
                     }
                     Err(error) => {
-                        err_sd.send(error).await.unwrap();
+                        err_sd.unwrap().send(error).await.unwrap();
                     }
                 }
             });

+ 5 - 5
strategy/src/bybit_usdt_swap.rs

@@ -33,11 +33,11 @@ pub async fn bybit_swap_run(bool_v1: Arc<AtomicBool>,
     ws_public.set_subscribe(vec![
         BybitSwapSubscribeType::PuOrderBook50
     ]);
-    if is_trade {
-        ws_public.set_subscribe(vec![
-            BybitSwapSubscribeType::PuBlicTrade
-        ]);
-    }
+    // if is_trade {
+    //     ws_public.set_subscribe(vec![
+    //         BybitSwapSubscribeType::PuBlicTrade
+    //     ]);
+    // }
     // 挂起公共ws
     let write_tx_am_public = Arc::new(Mutex::new(write_tx_public));
     let bool_clone_public = Arc::clone(&bool_v1);

+ 8 - 7
strategy/src/predictor_new.rs

@@ -34,7 +34,7 @@ pub struct PredictorNew {
     下面的单元测试有使用示例
 */
 impl PredictorNew {
-    pub fn new(ref_exchange_length: usize, max_spread: Decimal, min_spread: Decimal, rl_num: Decimal, max_position_value: Decimal, ira: Decimal) -> Self {
+    pub fn new(ref_exchange_length: usize, rl_num: Decimal, max_position_value: Decimal, ira: Decimal) -> Self {
         Self {
             loop_count: 0,
             market_info_list: vec![],
@@ -46,8 +46,8 @@ impl PredictorNew {
             gamma: Decimal::from_f64(0.999).unwrap(),
             avg_spread_list: vec![dec!(0); ref_exchange_length],
             transaction_prices: Vec::new(),
-            max_spread,
-            min_spread,
+            max_spread: Decimal::ZERO,
+            min_spread: Decimal::ZERO,
             variance: Decimal::ZERO,
             balance_value: Decimal::ZERO,
             rl_num,
@@ -144,6 +144,7 @@ impl PredictorNew {
         let ref_bid_price = last_market_info[public_params::LENGTH+public_params::BID_PRICE_INDEX];
         let ref_ask_price = last_market_info[public_params::LENGTH+public_params::ASK_PRICE_INDEX];
         let ref_mid_price = (ref_bid_price + ref_ask_price) * dec!(0.5);
+        // info!(?ref_mid_price);
         ref_mid_price - self.balance_value * gamma * std * std
     }
 
@@ -298,14 +299,14 @@ mod tests {
     fn predictor_build_test() {
         let mut stdout = io::stdout();
 
-        let predictor1 = PredictorNew::new(2, Default::default(), Default::default(), Default::default(), Default::default(), Decimal::ONE)
+        let predictor1 = PredictorNew::new(2,  Default::default(), Default::default(), Decimal::ONE)
             .alpha(vec![dec!(0.99); 100])
             .gamma(dec!(0.8));
         writeln!(stdout, "predictor1:").unwrap();
         writeln!(stdout, "{:?}", predictor1).unwrap();
         writeln!(stdout, "").unwrap();
 
-        let predictor2 = PredictorNew::new(2, Default::default(), Default::default(), Default::default(), Default::default(), Decimal::ONE);
+        let predictor2 = PredictorNew::new(2,  Default::default(), Default::default(), Decimal::ONE);
         writeln!(stdout, "predictor2:").unwrap();
         writeln!(stdout, "{:?}", predictor2).unwrap();
         writeln!(stdout, "").unwrap();
@@ -313,7 +314,7 @@ mod tests {
 
     #[test]
     fn market_info_handler_test() {
-        let mut predictor = PredictorNew::new(1, Default::default(), Default::default(), Default::default(), Default::default(), Decimal::ONE);
+        let mut predictor = PredictorNew::new(1, Default::default(), Default::default(), Decimal::ONE);
         let market_info_0 = vec![dec!(0.99), dec!(1.0), dec!(0.89), dec!(0.79), dec!(0.99), dec!(1.0), dec!(0.89), dec!(0.79), dec!(0.89), dec!(0.79), dec!(0.99), dec!(1.0), dec!(0.89), dec!(0.79)];
         predictor.market_info_handler(&market_info_0);
         let market_info_1 = vec![dec!(0.98), dec!(0.99), dec!(0.56), dec!(0.49), dec!(0.99), dec!(1.0), dec!(0.89), dec!(0.79), dec!(0.89), dec!(0.79), dec!(0.99), dec!(1.0), dec!(0.89), dec!(0.79)];
@@ -322,7 +323,7 @@ mod tests {
 
     #[test]
     fn get_ref_price_test() {
-        let mut predictor = PredictorNew::new(1, Default::default(), Default::default(), Default::default(), Default::default(), Decimal::ONE)
+        let mut predictor = PredictorNew::new(1, Default::default(), Default::default(), Decimal::ONE)
             .alpha(vec![dec!(0.99); 100])
             .gamma(dec!(0.8));
         predictor.balance_value = Decimal::from_str("0.5").unwrap();

+ 53 - 15
strategy/src/quant.rs

@@ -97,6 +97,7 @@ pub struct Quant {
     pub predictor: PredictorNew,
     pub market: Market,
     pub platform_rest: Box<dyn Platform + Send + Sync>,
+    pub ref_platform_rest: Box<dyn Platform + Send + Sync>,
     // 市场最优买卖价
     pub max_buy_min_sell_cache: HashMap<String, Vec<Decimal>>,
     // 最近一次的depth信息
@@ -210,28 +211,58 @@ impl Quant {
             },
             platform_rest: match exchange.as_str() {
                 "kucoin_usdt_swap" => {
-                    Exchange::new(KucoinSwap, symbol, params.colo != 0i8, exchange_params, order_sender, error_sender).await
+                    Exchange::new(KucoinSwap, symbol.clone(), params.colo != 0i8, exchange_params, Some(order_sender), Some(error_sender)).await
                 }
                 "gate_usdt_swap" => {
-                    Exchange::new(GateSwap, symbol, params.colo != 0i8, exchange_params, order_sender, error_sender).await
+                    Exchange::new(GateSwap, symbol.clone(), params.colo != 0i8, exchange_params, Some(order_sender), Some(error_sender)).await
                 }
                 "gate_usdt_spot" => {
-                    Exchange::new(GateSpot, symbol, params.colo != 0i8, exchange_params, order_sender, error_sender).await
+                    Exchange::new(GateSpot, symbol.clone(), params.colo != 0i8, exchange_params, Some(order_sender), Some(error_sender)).await
                 }
                 "binance_usdt_swap" => {
-                    Exchange::new(BinanceSwap, symbol, params.colo != 0i8, exchange_params, order_sender, error_sender).await
+                    Exchange::new(BinanceSwap, symbol.clone(), params.colo != 0i8, exchange_params, Some(order_sender), Some(error_sender)).await
                 }
                 "binance_spot" => {
-                    Exchange::new(BinanceSpot, symbol, params.colo != 0i8, exchange_params, order_sender, error_sender).await
+                    Exchange::new(BinanceSpot, symbol.clone(), params.colo != 0i8, exchange_params, Some(order_sender), Some(error_sender)).await
                 }
                 "bitget_spot" => {
-                    Exchange::new(BitgetSpot, symbol, params.colo != 0i8, exchange_params, order_sender, error_sender).await
+                    Exchange::new(BitgetSpot, symbol.clone(), params.colo != 0i8, exchange_params, Some(order_sender), Some(error_sender)).await
                 }
                 "okex_usdt_swap" => {
-                    Exchange::new(OkxSwap, symbol, params.colo != 0i8, exchange_params, order_sender, error_sender).await
+                    Exchange::new(OkxSwap, symbol.clone(), params.colo != 0i8, exchange_params, Some(order_sender), Some(error_sender)).await
                 }
                 "bybit_usdt_swap" => {
-                    Exchange::new(BybitSwap, symbol, params.colo != 0i8, exchange_params, order_sender, error_sender).await
+                    Exchange::new(BybitSwap, symbol.clone(), params.colo != 0i8, exchange_params, Some(order_sender), Some(error_sender)).await
+                }
+                _ => {
+                    error!("203未找到对应的交易所rest枚举!");
+                    panic!("203未找到对应的交易所rest枚举!");
+                }
+            },
+            ref_platform_rest:  match params.ref_exchange[0].as_str() {
+                "kucoin_usdt_swap" => {
+                    Exchange::new(KucoinSwap, symbol, false, BTreeMap::new(), None, None).await
+                }
+                "gate_usdt_swap" => {
+                    Exchange::new(GateSwap, symbol, false, BTreeMap::new(), None, None).await
+                }
+                "gate_usdt_spot" => {
+                    Exchange::new(GateSpot, symbol, false, BTreeMap::new(), None, None).await
+                }
+                "binance_usdt_swap" => {
+                    Exchange::new(BinanceSwap, symbol, false, BTreeMap::new(), None, None).await
+                }
+                "binance_spot" => {
+                    Exchange::new(BinanceSpot, symbol, false, BTreeMap::new(), None, None).await
+                }
+                "bitget_spot" => {
+                    Exchange::new(BitgetSpot, symbol, false, BTreeMap::new(), None, None).await
+                }
+                "okex_usdt_swap" => {
+                    Exchange::new(OkxSwap, symbol, false, BTreeMap::new(), None, None).await
+                }
+                "bybit_usdt_swap" => {
+                    Exchange::new(BybitSwap, symbol, false, BTreeMap::new(), None, None).await
                 }
                 _ => {
                     error!("203未找到对应的交易所rest枚举!");
@@ -286,7 +317,7 @@ impl Quant {
             }
         }
         info!("价格系数:{:?}", price_alpha);
-        quant_obj.predictor = PredictorNew::new(quant_obj.ref_name.len(), params.max_spread, params.min_spread, params.rl_num, params.max_position_value, params.ira)
+        quant_obj.predictor = PredictorNew::new(quant_obj.ref_name.len(), params.rl_num, params.max_position_value, params.ira)
             .alpha(price_alpha)
             .gamma(params.gamma);
         // quant_obj.predictor = Predictor::new(quant_obj.ref_name.len())
@@ -588,10 +619,14 @@ impl Quant {
             self.log_ready_status(format!("550聚合行情未准备好: market长度:{}, 检验数: {}", all_market.len(), LENGTH * (1usize + self.ref_num as usize)));
             return;
         } else {
-            // 如果准备就绪,则可以开始交易
-            info!("----------------------------------聚合行情准备就绪,可以开始交易---------------------------------");
             self.trade_msg.market = all_market;
             self.predictor.market_info_handler(&self.trade_msg.market);
+            if self.predictor.min_spread == Decimal::ZERO || self.predictor.max_spread == Decimal::ZERO {
+                self.log_ready_status(format!("560最大最小价差未准备好: max {}  min {}", self.predictor.min_spread, self.predictor.max_spread));
+                return;
+            }
+            // 如果准备就绪,则可以开始交易
+            info!("----------------------------------聚合行情准备就绪,可以开始交易---------------------------------");
             self.ready = 1;
         }
     }
@@ -1526,11 +1561,14 @@ impl Quant {
             info!("数量精度 {}", self.strategy.step_size);
             info!("价格精度 {}", self.strategy.tick_size);
         }
+        let market_ref = self.ref_platform_rest.get_market().await.expect("获取参考交易所价格精度信息异常!");
+
         // 置入最大最小价差
-        self.predictor.min_spread = Decimal::TWO * self.strategy.tick_size;
-        self.predictor.max_spread = Decimal::TEN * self.strategy.tick_size;
-        info!("最小价差 {}", self.predictor.min_spread);
-        info!("最大价差 {}", self.predictor.max_spread);
+        self.predictor.min_spread = Decimal::TWO * market_ref.tick_size;
+        self.predictor.max_spread = Decimal::TEN * market_ref.tick_size;
+        info!("初始化最小价差 {}", self.predictor.min_spread);
+        info!("初始化最大价差 {}", self.predictor.max_spread);
+
         let grid = Decimal::from(self.params.grid.clone());
         // 计算下单数量
         let long_one_hand_value: Decimal = start_cash * self.params.lever_rate / grid;

+ 10 - 0
strategy/src/strategy.rs

@@ -555,6 +555,16 @@ impl Strategy {
         for close_price in &mut close_dist {
             *close_price = utils::fix_price(*close_price, self.tick_size);
         }
+        let kd = utils::fix_price((open_dist[0] + open_dist[1]) / Decimal::TWO, self.tick_size);
+        let kk = utils::fix_price((open_dist[2] + open_dist[3]) / Decimal::TWO, self.tick_size);
+        let pd = utils::fix_price((close_dist[0] + close_dist[1]) / Decimal::TWO, self.tick_size);
+        let pk = utils::fix_price((close_dist[2] + close_dist[3]) / Decimal::TWO, self.tick_size);
+        // 是否亏损开单
+        if pd == kd || pd < kd || kk == pk || kk < pk {
+            error!("亏损开单:open_dist={:?} close_dist={:?}", open_dist, close_dist);
+            panic!("亏损开单:open_dist={:?} close_dist={:?}", open_dist, close_dist);
+        }
+
         self.open_dist = open_dist.clone();
         self.close_dist = close_dist.clone();
         // info!(?open_dist);