skyffire 1 anno fa
parent
commit
a95a6d2f86

+ 201 - 0
derive/src/bybit_swap_export.rs

@@ -0,0 +1,201 @@
+use std::collections::{BTreeMap};
+use async_trait::async_trait;
+use chrono::{FixedOffset, NaiveDateTime, TimeZone};
+use rust_decimal::prelude::ToPrimitive;
+use serde::{Deserialize, Serialize};
+use tracing::{warn};
+use exchanges::bybit_swap_rest::BybitSwapRest;
+use standard::utils;
+use crate::ExportConnector;
+
+pub struct BybitSwapExport {
+    request: BybitSwapRest,
+}
+
+impl BybitSwapExport {
+    pub async fn new(is_colo: bool, params: BTreeMap<String, String>) -> BybitSwapExport {
+        BybitSwapExport {
+            request: BybitSwapRest::new(is_colo, params.clone())
+        }
+    }
+}
+
+#[async_trait]
+impl ExportConnector for BybitSwapExport {
+    async fn export_trades(&mut self, prefix_name: &str, symbol: String, start_time: i64, end_time: i64, limit: i64) -> String {
+        let pnl_array = get_position_pnl(self.request.clone(), symbol.clone(), start_time.clone(), end_time.clone(), limit.clone()).await;
+        let trades_array = get_trades(self.request.clone(), symbol.clone(), start_time.clone(), end_time.clone(), limit.clone()).await;
+        let pnl_header_array = vec!["订单编号", "交易币对", "买卖方向", "入场价格", "出场价格", "交易类型", "成交数量", "交易盈亏", "创建时间", "更新时间"];
+        let trades_header_array = vec!["交易编号", "订单编号", "交易币对", "买卖方向", "成交价格", "成交数量", "交易类型", "成交价值", "交易费用", "交易费率", "交易时间"];
+        global::export_utils::export_excel_sheets(vec![pnl_header_array, trades_header_array], vec![pnl_array, trades_array], vec!["pnl", "trades"], prefix_name)
+    }
+}
+
+/// TradesSwap
+/// - `symbol`: String,
+/// - `order_id`: String,
+/// - `order_link_id`: String,
+/// - `side`: String,
+/// - `order_price`: String,
+/// - `order_qty`: String,
+/// - `leaves_qty`: String,
+/// - `create_type`: String,
+/// - `order_type`: String,
+/// - `stop_order_type`: String,
+/// - `exec_fee`: String,
+/// - `exec_id`: String,
+/// - `exec_price`: String,
+/// - `exec_qty`: String,
+/// - `exec_type`: String,
+/// - `exec_value`: String,
+/// - `exec_time`: String,
+/// - `fee_currency`: String,
+/// - `is_maker`: bool,
+/// - `fee_rate`: String,
+/// - `trade_iv`: String,
+/// - `mark_iv`: String,
+/// - `mark_price`: String,
+/// - `index_price`: String,
+/// - `underlying_price`: String,
+/// - `block_trade_id`: String,
+/// - `closed_size`: String,
+/// - `seq`: i64,
+#[derive(Debug, Deserialize, Serialize)]
+#[serde(rename_all = "camelCase")]
+struct TradesSwap {
+    symbol: String,
+    order_id: String,
+    order_link_id: String,
+    side: String,
+    order_price: String,
+    order_qty: String,
+    leaves_qty: String,
+    create_type: String,
+    order_type: String,
+    stop_order_type: String,
+    exec_fee: String,
+    exec_id: String,
+    exec_price: String,
+    exec_qty: String,
+    exec_type: String,
+    exec_value: String,
+    exec_time: String,
+    fee_currency: String,
+    is_maker: bool,
+    fee_rate: String,
+    trade_iv: String,
+    mark_iv: String,
+    mark_price: String,
+    index_price: String,
+    underlying_price: String,
+    block_trade_id: String,
+    closed_size: String,
+    seq: i64,
+}
+
+async fn get_trades(mut request: BybitSwapRest, symbol: String, start_time: i64, end_time: i64, limit: i64) -> Vec<Vec<String>> {
+    let symbol_format = utils::format_symbol(symbol.clone(), "");
+    let limit_params = if limit > 100 {
+        warn!("查询条数最大为1000条,已修改为100条!");
+        100
+    } else { limit };
+    let mut cursor = "".to_string();
+    let mut data_array = vec![];
+
+    loop {
+        let res_data = request.get_user_trades(symbol_format.clone(), start_time, end_time, limit_params, cursor.clone()).await;
+        if res_data.code == 200 {
+            let data_clone = res_data.data.clone();
+            let trades_info: Vec<TradesSwap> = serde_json::from_str(&*data_clone["list"].to_string()).unwrap();
+            cursor = data_clone["nextPageCursor"].as_str().unwrap_or("").to_string();
+            for value in trades_info.iter() {
+                let time = FixedOffset::east_opt(8 * 3600).unwrap().from_utc_datetime(&NaiveDateTime::from_timestamp_millis(value.exec_time.parse::<i64>().unwrap()).unwrap()).format("%Y-%m-%d %H:%M:%S%.3f").to_string();
+                let order_type = value.order_type.clone();
+
+                data_array.push(vec![
+                    value.exec_id.clone(),
+                    value.order_id.clone(),
+                    value.symbol.clone(),
+                    value.side.clone(),
+                    value.exec_price.clone(),
+                    value.exec_qty.clone(),
+                    order_type.to_string(),
+                    value.exec_value.clone(),
+                    value.exec_fee.clone(),
+                    value.fee_rate.clone(),
+                    time,
+                ]);
+            }
+
+            if trades_info.len().to_i64().unwrap() < limit_params {
+                break;
+            }
+        }
+    }
+    data_array.reverse();
+    data_array
+}
+
+#[derive(Debug, Deserialize, Serialize)]
+#[serde(rename_all = "camelCase")]
+struct PositionPnlSwap {
+    symbol: String,
+    order_id: String,
+    side: String,
+    qty: String,
+    order_price: String,
+    order_type: String,
+    exec_type: String,
+    closed_size: String,
+    cum_entry_value: String,
+    avg_entry_price: String,
+    cum_exit_value: String,
+    avg_exit_price: String,
+    closed_pnl: String,
+    fill_count: String,
+    leverage: String,
+    created_time: String,
+    updated_time: String,
+}
+async fn get_position_pnl(mut request: BybitSwapRest, symbol: String, start_time: i64, end_time: i64, limit: i64) -> Vec<Vec<String>> {
+    let symbol_format = utils::format_symbol(symbol.clone(), "");
+    let limit_params = if limit > 100 {
+        warn!("查询条数最大为1000条,已修改为100条!");
+        100
+    } else { limit };
+    let mut cursor = "".to_string();
+    let mut data_array = vec![];
+
+    loop {
+        let res_data = request.get_position_closed_pnl(symbol_format.clone(), start_time, end_time, limit_params, cursor.clone()).await;
+        if res_data.code == 200 {
+            let data_clone = res_data.data.clone();
+            let trades_info: Vec<PositionPnlSwap> = serde_json::from_str(&*data_clone["list"].to_string()).unwrap();
+            cursor = data_clone["nextPageCursor"].as_str().unwrap_or("").to_string();
+            for value in trades_info.iter() {
+                let create_time = FixedOffset::east_opt(8 * 3600).unwrap().from_utc_datetime(&NaiveDateTime::from_timestamp_millis(value.created_time.parse::<i64>().unwrap()).unwrap()).format("%Y-%m-%d %H:%M:%S%.3f").to_string();
+                let update_time = FixedOffset::east_opt(8 * 3600).unwrap().from_utc_datetime(&NaiveDateTime::from_timestamp_millis(value.updated_time.parse::<i64>().unwrap()).unwrap()).format("%Y-%m-%d %H:%M:%S%.3f").to_string();
+
+                data_array.push(vec![
+                    value.order_id.clone(),
+                    value.symbol.clone(),
+                    value.side.clone(),
+                    value.avg_entry_price.clone(),
+                    value.avg_exit_price.clone(),
+                    value.order_type.clone(),
+                    value.closed_size.clone(),
+                    value.closed_pnl.clone(),
+                    create_time,
+                    update_time,
+                ]);
+            }
+
+            if trades_info.len().to_i64().unwrap() < limit_params {
+                break;
+            }
+        }
+    }
+
+    data_array.reverse();
+    data_array
+}

+ 5 - 0
derive/src/export_excel.rs

@@ -1,5 +1,6 @@
 use std::collections::BTreeMap;
 use crate::binance_swap_export::BinanceSwapExport;
+use crate::bybit_swap_export::BybitSwapExport;
 // use crate::bitget_spot_export::BitgetSpotExport;
 use crate::ExportConnector;
 use crate::gate_swap_export::GateSwapExport;
@@ -13,6 +14,7 @@ pub enum ExportEnum {
     // KucoinSwap,
     // KucoinSpot,
     GateSwap,
+    BybitSwap,
     // BitgetSpot,
     // OkxSwap,
 }
@@ -35,6 +37,9 @@ impl ExportExcel {
             ExportEnum::GateSwap => {
                 Box::new(GateSwapExport::new(is_colo, params).await)
             }
+            ExportEnum::BybitSwap => {
+                Box::new(BybitSwapExport::new(is_colo, params).await)
+            }
             // ExportEnum::BitgetSpot => {
             //     Box::new(BitgetSpotExport::new(is_colo, params).await)
             // }

+ 1 - 0
derive/src/lib.rs

@@ -7,6 +7,7 @@ pub mod export_excel;
 mod gate_swap_export;
 mod bitget_spot_export;
 mod okx_swap_export;
+mod bybit_swap_export;
 
 #[async_trait]
 pub trait ExportConnector {

+ 19 - 0
derive/tests/bybit_swap_export_test.rs

@@ -0,0 +1,19 @@
+mod export_excel_test;
+
+use tracing::{instrument, trace};
+use derive::export_excel::ExportEnum;
+use crate::export_excel_test::test_new_export;
+
+
+const SYMBOL: &str = "1000PEPE_USDT";
+
+// 测试获取Exchange实体
+#[tokio::test]
+#[instrument(level = "TRACE")]
+async fn test_get_self_exchange() {
+    global::log_utils::init_log_with_trace();
+
+    let mut export = test_new_export(ExportEnum::BybitSwap).await;
+    let export_trades = export.export_trades("bybit_swap", SYMBOL.to_string(), 1726131600000, 1726192800000, 100).await;
+    trace!(?export_trades);
+}

+ 8 - 0
derive/tests/export_excel_test.rs

@@ -53,6 +53,14 @@ pub async fn test_new_export(export_enum: ExportEnum) -> Box<dyn ExportConnector
             params.insert("secret_key".to_string(), secret_key);
             ExportExcel::new(ExportEnum::GateSwap, false, params).await
         }
+        ExportEnum::BybitSwap => {
+            let mut params: BTreeMap<String, String> = BTreeMap::new();
+            let access_key = account_info.bybit_access_key;
+            let secret_key = account_info.bybit_secret_key;
+            params.insert("access_key".to_string(), access_key);
+            params.insert("secret_key".to_string(), secret_key);
+            ExportExcel::new(ExportEnum::BybitSwap, false, params).await
+        }
         // ExportEnum::BitgetSpot => {
         //     let mut params: BTreeMap<String, String> = BTreeMap::new();
         //     let access_key = account_info.bitget_access_key;

+ 39 - 11
exchanges/src/bybit_swap_rest.rs

@@ -130,7 +130,6 @@ impl BybitSwapRest {
         ).await;
         data
     }
-
     //查看持仓信息
     pub async fn get_positions(&mut self, symbol: String, settle_coin: String) -> ResponseData {
         let mut params = serde_json::json!({
@@ -165,10 +164,8 @@ impl BybitSwapRest {
         ).await;
         data
     }
-
     //設置槓桿
-    pub async fn set_leverage(&mut self, symbol: String,
-                              lever: String) -> ResponseData {
+    pub async fn set_leverage(&mut self, symbol: String, lever: String) -> ResponseData {
         let params = serde_json::json!({
              "category": "linear",
              "symbol": symbol,
@@ -183,8 +180,6 @@ impl BybitSwapRest {
         ).await;
         data
     }
-
-
     //查詢錢包餘額
     pub async fn get_account_balance(&mut self, symbol: String) -> ResponseData {
         let params = serde_json::json!({
@@ -199,7 +194,6 @@ impl BybitSwapRest {
         ).await;
         data
     }
-
     //創建委託單
     pub async fn swap_order(&mut self, params: serde_json::Value) -> ResponseData {
         let data = self.request("POST".to_string(),
@@ -230,7 +224,6 @@ impl BybitSwapRest {
         ).await;
         data
     }
-
     //撤单
     pub async fn cancel_order(&mut self, symbol: String, order_id: String, order_link_id: String) -> ResponseData {
         let mut params = serde_json::json!({
@@ -251,7 +244,6 @@ impl BybitSwapRest {
         ).await;
         data
     }
-
     //撤銷所有訂單
     pub async fn cancel_orders(&mut self, symbol: String) -> ResponseData {
         let params = serde_json::json!({
@@ -266,8 +258,44 @@ impl BybitSwapRest {
         ).await;
         data
     }
-
-
+    //账户成交历史
+    pub async fn get_user_trades(&mut self, symbol: String, start_time: i64, end_time: i64, limit: i64, cursor: String) -> ResponseData {
+        let mut params = serde_json::json!({
+            "category": "linear",
+            "limit": 100
+         });
+        if symbol != "" { params["symbol"] = serde_json::json!(symbol); }
+        if start_time > 0 { params["startTime"] = serde_json::json!(start_time); }
+        if end_time > 0 { params["endTime"] = serde_json::json!(end_time); }
+        if limit > 0 { params["limit"] = serde_json::json!(limit); }
+        if cursor != "" { params["cursor"] = serde_json::json!(cursor); }
+        let data = self.request("GET".to_string(),
+                                "/v5".to_string(),
+                                "/execution/list".to_string(),
+                                true,
+                                params.to_string(),
+        ).await;
+        data
+    }
+    //账户成交历史
+    pub async fn get_position_closed_pnl(&mut self, symbol: String, start_time: i64, end_time: i64, limit: i64, cursor: String) -> ResponseData {
+        let mut params = serde_json::json!({
+            "category": "linear",
+            "limit": 100
+         });
+        if symbol != "" { params["symbol"] = serde_json::json!(symbol); }
+        if start_time > 0 { params["startTime"] = serde_json::json!(start_time); }
+        if end_time > 0 { params["endTime"] = serde_json::json!(end_time); }
+        if limit > 0 { params["limit"] = serde_json::json!(limit); }
+        if cursor != "" { params["cursor"] = serde_json::json!(cursor); }
+        let data = self.request("GET".to_string(),
+                                "/v5".to_string(),
+                                "/position/closed-pnl".to_string(),
+                                true,
+                                params.to_string(),
+        ).await;
+        data
+    }
     /*******************************************************************************************************/
     /*****************************************工具函数********************************************************/
     /*******************************************************************************************************/

+ 5 - 5
exchanges/src/bybit_swap_ws.rs

@@ -25,7 +25,7 @@ pub enum BybitSwapWsType {
 pub enum BybitSwapSubscribeType {
     PuOrderBook1,
     PuOrderBook50,
-    PuBlicTrade,
+    PuTrade,
     PuTickers,
     PuKline(String),
 
@@ -71,10 +71,10 @@ impl BybitSwapWs {
         /*******公共频道-私有频道数据组装*/
         let address_url = match ws_type {
             BybitSwapWsType::Public => {
-                "wss://stream.bybit.com/v5/public/linear?max_alive_time=1m".to_string()
+                "wss://stream.bybit.com/v5/public/linear?max_alive_time=10m".to_string()
             }
             BybitSwapWsType::Private => {
-                "wss://stream.bybit.com/v5/private?max_alive_time=1m".to_string()
+                "wss://stream.bybit.com/v5/private?max_alive_time=10m".to_string()
             }
         };
 
@@ -118,7 +118,7 @@ impl BybitSwapWs {
             if match t {
                 BybitSwapSubscribeType::PuOrderBook1 => false,
                 BybitSwapSubscribeType::PuOrderBook50 => false,
-                BybitSwapSubscribeType::PuBlicTrade => false,
+                BybitSwapSubscribeType::PuTrade => false,
                 BybitSwapSubscribeType::PuTickers => false,
                 BybitSwapSubscribeType::PuKline(_) => false,
 
@@ -144,7 +144,7 @@ impl BybitSwapWs {
             BybitSwapSubscribeType::PuOrderBook50 => {
                 format!("orderbook.50.{}", symbol)
             }
-            BybitSwapSubscribeType::PuBlicTrade => {
+            BybitSwapSubscribeType::PuTrade => {
                 format!("publicTrade.{}", symbol)
             }
             BybitSwapSubscribeType::PuTickers => {

+ 7 - 5
exchanges/src/socket_tool.rs

@@ -64,7 +64,7 @@ impl AbstractWsMode {
         };
         // 如果不需要事先登录,则直接订阅消息
         if !is_first_login {
-            info!("不需要登录,订阅内容:{:?}", subscribe_array.clone());
+            info!("不需要登录,订阅内容:{:?}", subscribe_array.clone());
             for s in &subscribe_array {
                 let mut write_lock = ws_write_arc.lock().await;
                 write_lock.send(Message::Text(s.parse().unwrap())).await.expect("订阅消息失败");
@@ -114,11 +114,13 @@ impl AbstractWsMode {
                             //登录成功
                             info!("ws登录成功:{:?}", data);
                             info!("订阅内容:{:?}", subscribe_array.clone());
-                            for s in &subscribe_array {
-                                let mut write_lock = ws_write_arc.lock().await;
-                                write_lock.send(Message::Text(s.parse().unwrap())).await.expect("订阅消息失败");
+                            if is_first_login {
+                                for s in &subscribe_array {
+                                    let mut write_lock = ws_write_arc.lock().await;
+                                    write_lock.send(Message::Text(s.parse().unwrap())).await.expect("订阅消息失败");
+                                }
+                                info!("订阅完成!");
                             }
-                            info!("订阅完成!");
                         }
                         -201 => {
                             //订阅成功

+ 4 - 0
global/src/account_info.rs

@@ -19,6 +19,8 @@ pub struct AccountInfo {
     pub bitget_access_key: String,
     pub bitget_secret_key: String,
     pub bitget_pass: String,
+    pub bybit_access_key: String,
+    pub bybit_secret_key: String,
     pub htx_access_key: String,
     pub htx_secret_key: String,
     pub htx_pass: String,
@@ -40,6 +42,8 @@ impl AccountInfo {
             bitget_access_key: "".to_string(),
             bitget_secret_key: "".to_string(),
             bitget_pass: "".to_string(),
+            bybit_access_key: "".to_string(),
+            bybit_secret_key: "".to_string(),
             htx_access_key: "".to_string(),
             htx_secret_key: "".to_string(),
             htx_pass: "".to_string(),

+ 38 - 0
global/src/export_utils.rs

@@ -35,4 +35,42 @@ pub fn export_excel(header_array: Vec<&str>, data: Vec<Vec<String>>, prefix_name
     }).expect("写入excel错误!");
     wb.close().expect("关闭excel错误!");
     file_name
+}
+
+pub fn export_excel_sheets(header_array: Vec<Vec<&str>>, data: Vec<Vec<Vec<String>>>, sheet_name: Vec<&str>, prefix_name: &str) -> String {
+    //本地存储路径
+    let save_path = "C:/Users/Public/Documents/";
+    let _ = std::fs::create_dir(format!("{}rust_export/", save_path));
+    // 当前时间
+    let date = Local::now().format("%Y-%m-%d").to_string();
+    let uid = Uuid::new_v4().to_string()[0..8].to_string();
+    let name = if prefix_name == "" { "".to_string() } else { format!("{}_", prefix_name) };
+    let file_name = format!("{}rust_export/{}{}_{}.xlsx", save_path, name, date, uid);
+    let mut wb = Workbook::create(&file_name);
+    if header_array.len() != data.len() { return "表头和数据数量有误,请检查后再试!".to_string(); }
+    for (index, headers) in header_array.iter().enumerate() {
+        let mut sheet = wb.create_sheet(sheet_name[index]);
+        // 设置行宽
+        for _ in 0..headers.len() {
+            sheet.add_column(Column { width: 20.0 });
+        }
+        wb.write_sheet(&mut sheet, |sheet_writer| {
+            let sw = sheet_writer;
+            let mut header_row = Row::new();
+            for value in headers.clone() {
+                header_row.add_cell(value);
+            }
+            sw.append_row(header_row).expect(format!("创建excel标题错误!header:{:?}", header_array).as_str());
+            for cell in data[index].clone() {
+                let mut data_row = Row::new();
+                for value in cell.clone() {
+                    data_row.add_cell(value);
+                }
+                sw.append_row(data_row).expect(format!("添加excel数据错误!cell:{:?}", cell).as_str());
+            }
+            sw.append_row(Default::default())
+        }).expect("写入excel错误!");
+    }
+    wb.close().expect("关闭excel错误!");
+    file_name
 }

+ 760 - 748
standard/src/bybit_swap.rs

@@ -1,748 +1,760 @@
-// use std::collections::{BTreeMap};
-// use std::io::{Error, ErrorKind};
-// use std::str::FromStr;
-// use tokio::sync::mpsc::Sender;
-// use async_trait::async_trait;
-// use futures::stream::FuturesUnordered;
-// use futures::TryStreamExt;
-// use rust_decimal::Decimal;
-// use serde_json::{from_value, json, Value};
-// use rust_decimal::prelude::FromPrimitive;
-// use serde::{Deserialize, Serialize};
-// use tokio::time::Instant;
-// use tracing::{error, info, trace};
-// use exchanges::bybit_swap_rest::BybitSwapRest;
-// use crate::{Platform, ExchangeEnum, Account, Position, Ticker, Market, Order, OrderCommand, PositionModeEnum};
-// use global::trace_stack::TraceStack;
-//
-// #[derive(Debug, Clone, Deserialize, Serialize)]
-// #[serde(rename_all = "camelCase")]
-// struct SwapTicker {
-//     symbol: String,
-//     high_price24h: Decimal,
-//     low_price24h: Decimal,
-//     bid1_price: Decimal,
-//     ask1_price: Decimal,
-//     last_price: Decimal,
-//     volume24h: Decimal
-// }
-//
-// #[allow(dead_code)]
-// #[derive(Clone)]
-// pub struct BybitSwap {
-//     exchange: ExchangeEnum,
-//     symbol: String,
-//     symbol_uppercase: String,
-//     is_colo: bool,
-//     params: BTreeMap<String, String>,
-//     request: BybitSwapRest,
-//     market: Market,
-//     order_sender: Sender<Order>,
-//     error_sender: 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 {
-//         let market = Market::new();
-//         let mut bybit_swap = BybitSwap {
-//             exchange: ExchangeEnum::BybitSwap,
-//             symbol: symbol.to_uppercase(),
-//             symbol_uppercase: symbol.replace("_", "").to_uppercase(),
-//             is_colo,
-//             params: params.clone(),
-//             request: BybitSwapRest::new(is_colo, params.clone()),
-//             market,
-//             order_sender,
-//             error_sender,
-//         };
-//
-//         // 修改持仓模式
-//         let symbol_array: Vec<&str> = symbol.split("_").collect();
-//         let mode_result = bybit_swap.set_dual_mode(symbol_array[1], true).await;
-//         match mode_result {
-//             Ok(_) => {
-//                 trace!("Bybit:设置持仓模式成功!")
-//             }
-//             Err(error) => {
-//                 error!("Bybit:设置持仓模式失败!mode_result={}", error)
-//             }
-//         }
-//         // 获取市场信息
-//         bybit_swap.market = BybitSwap::get_market(&mut bybit_swap).await.unwrap_or(bybit_swap.market);
-//         return bybit_swap;
-//     }
-// }
-//
-// #[async_trait]
-// 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
-//     }
-//     // 获取交易对
-//     fn get_self_symbol(&self) -> String { self.symbol.clone() }
-//     // 获取是否使用高速通道
-//     fn get_self_is_colo(&self) -> bool {
-//         self.is_colo
-//     }
-//     // 获取params信息
-//     fn get_self_params(&self) -> BTreeMap<String, String> {
-//         self.params.clone()
-//     }
-//     // 获取market信息
-//     fn get_self_market(&self) -> Market { self.market.clone() }
-//     // 获取请求时间
-//     fn get_request_delays(&self) -> Vec<i64> { self.request.get_delays() }
-//     // 获取请求平均时间
-//     fn get_request_avg_delay(&self) -> Decimal { self.request.get_avg_delay() }
-//     // 获取请求最大时间
-//     fn get_request_max_delay(&self) -> i64 { self.request.get_max_delay() }
-//
-//     // 获取服务器时间
-//     async fn get_server_time(&mut self) -> Result<String, Error> {
-//         let res_data = self.request.get_server_time().await;
-//         if res_data.code == 200 {
-//             let result = res_data.data["server_time"].to_string();
-//             Ok(result)
-//         } else {
-//             Err(Error::new(ErrorKind::Other, res_data.to_string()))
-//         }
-//     }
-//     // 获取账号信息
-//     async fn get_account(&mut self) -> Result<Account, Error> {
-//         let symbol_array: Vec<&str> = self.symbol.split("_").collect();
-//         let res_data = self.request.get_account_balance(symbol_array[1].parse().unwrap()).await;
-//         if res_data.code == 200 {
-//             let arr_infos: Vec<Value> = from_value(res_data.data["list"].clone()).unwrap();
-//             if arr_infos.len() < 1usize{
-//                 return Err(Error::new(ErrorKind::NotFound, format!("{} 无账户信息", symbol_array[1])));
-//             }
-//             let coin_infos: Vec<Value> = from_value(arr_infos[0]["coin"].clone()).unwrap();
-//             if coin_infos.len() < 1usize{
-//                return Err(Error::new(ErrorKind::NotFound, format!("{} 无账户信息", symbol_array[1])));
-//             }
-//             let balance = Decimal::from_str(coin_infos[0]["equity"].as_str().unwrap()).unwrap();
-//             let available_balance = Decimal::from_str(coin_infos[0]["walletBalance"].as_str().unwrap()).unwrap();
-//             let frozen_balance = balance - available_balance;
-//             let result = Account {
-//                 coin: symbol_array[1].to_string(),
-//                 balance,
-//                 available_balance,
-//                 frozen_balance,
-//                 stocks: Decimal::ZERO,
-//                 available_stocks: Decimal::ZERO,
-//                 frozen_stocks: Decimal::ZERO,
-//             };
-//             Ok(result)
-//         } else {
-//             Err(Error::new(ErrorKind::Other, res_data.to_string()))
-//         }
-//     }
-//
-//     async fn get_spot_account(&mut self) -> Result<Vec<Account>, Error> {
-//         Err(Error::new(ErrorKind::NotFound, "bybit_swap:该交易所方法未实现".to_string()))
-//     }
-//
-//     // 获取持仓信息
-//     async fn get_position(&mut self) -> Result<Vec<Position>, Error> {
-//         let symbol = self.symbol_uppercase.clone();
-//         let ct_val = self.market.ct_val;
-//         let res_data = self.request.get_positions(symbol, "".to_string()).await;
-//         if res_data.code == 200 {
-//             let result = res_data.data["list"].as_array().unwrap().iter().map(|item| { format_position_item(item, ct_val) }).collect();
-//             Ok(result)
-//         } else {
-//             Err(Error::new(ErrorKind::Other, res_data.to_string()))
-//         }
-//     }
-//     // 获取所有持仓
-//     async fn get_positions(&mut self) -> Result<Vec<Position>, Error> {
-//         let symbol_array: Vec<&str> = self.symbol.split("_").collect();
-//         let ct_val = self.market.ct_val;
-//         let res_data = self.request.get_positions("".to_string(), symbol_array[1].to_string().to_uppercase()).await;
-//         if res_data.code == 200 {
-//             info!("{}", res_data.data.to_string());
-//             let result = res_data.data["list"].as_array().unwrap().iter().map(|item| { format_position_item(item, ct_val) }).collect();
-//             Ok(result)
-//         } else {
-//             Err(Error::new(ErrorKind::Other, res_data.to_string()))
-//         }
-//     }
-//     // 获取市场行情
-//     async fn get_ticker(&mut self) -> Result<Ticker, Error> {
-//         let symbol = self.symbol_uppercase.clone();
-//         let res_data = self.request.get_tickers(symbol).await;
-//         if res_data.code == 200 {
-//             let list :Vec<SwapTicker> = from_value(res_data.data["list"].clone()).unwrap_or(Vec::new());
-//
-//             if list.len() < 1usize {
-//                 error!("bybit_swap:获取Ticker信息错误!\nget_ticker:res_data={:?}", res_data);
-//                 return Err(Error::new(ErrorKind::Other, res_data.to_string()));
-//             }
-//             let value = list[0].clone();
-//             Ok(Ticker{
-//                 time: chrono::Utc::now().timestamp_millis(),
-//                 high: value.high_price24h,
-//                 low: value.low_price24h,
-//                 sell: value.ask1_price,
-//                 buy: value.bid1_price,
-//                 last: value.last_price,
-//                 volume: value.volume24h
-//             })
-//         } else {
-//             Err(Error::new(ErrorKind::Other, res_data.to_string()))
-//         }
-//     }
-//
-//     async fn get_ticker_symbol(&mut self, symbol: String) -> Result<Ticker, Error> {
-//         let symbol_upper = symbol.replace("_", "").to_uppercase();
-//         let res_data = self.request.get_tickers(symbol_upper.clone()).await;
-//         if res_data.code == 200 {
-//             let list: Vec<SwapTicker> = from_value(res_data.data["list"].clone()).unwrap();
-//             let ticker_info = list.iter().find(|&item| item.symbol == symbol_upper);
-//
-//             match ticker_info {
-//                 None => {
-//                     error!("bybit_swap:获取Ticker信息错误!\nget_ticker:res_data={:?}", res_data);
-//                     Err(Error::new(ErrorKind::Other, res_data.to_string()))
-//                 }
-//                 Some(value) => {
-//                     let result = Ticker {
-//                         time: chrono::Utc::now().timestamp_millis(),
-//                         high: value.high_price24h,
-//                         low: value.low_price24h,
-//                         sell: value.ask1_price,
-//                         buy: value.bid1_price,
-//                         last: value.last_price,
-//                         volume: value.volume24h
-//                     };
-//                     Ok(result)
-//                 }
-//             }
-//         } else {
-//             Err(Error::new(ErrorKind::Other, res_data.to_string()))
-//         }
-//     }
-//
-//     async fn get_market(&mut self) -> Result<Market, Error> {
-//         let symbol = self.symbol_uppercase.clone();
-//         let res_data = self.request.get_instruments_info(symbol.clone()).await;
-//         if res_data.code == 200 {
-//             let arr_data: Vec<Value> = from_value(res_data.data["list"].clone()).unwrap();
-//             let market_info = arr_data.iter().find(|&item| item["symbol"].as_str().unwrap() == symbol);
-//             match market_info {
-//                 None => {
-//                     error!("bybit_swap:获取Market信息错误!\nget_market:res_data={:?}", res_data);
-//                     Err(Error::new(ErrorKind::Other, res_data.to_string()))
-//                 }
-//                 Some(value) => {
-//                     let base_coin = value["baseCoin"].as_str().unwrap();
-//                     let quote_coin = value["quoteCoin"].as_str().unwrap();
-//                     let name = format!("{}_{}",base_coin, quote_coin);
-//                     let tick_size = Decimal::from_str(value["priceFilter"]["minPrice"].as_str().unwrap().trim()).unwrap();
-//                     let min_qty = Decimal::from_str(value["lotSizeFilter"]["minOrderQty"].as_str().unwrap().trim()).unwrap();
-//                     let max_qty = Decimal::from_str(value["lotSizeFilter"]["maxOrderQty"].as_str().unwrap().trim()).unwrap();
-//                     let ct_val = Decimal::ONE;
-//
-//                     let amount_size = min_qty * ct_val;
-//                     let price_precision = Decimal::from_u32(tick_size.scale()).unwrap();
-//                     let amount_precision = Decimal::from_u32(amount_size.scale()).unwrap();
-//                     let min_notional = min_qty * ct_val;
-//                     let max_notional = max_qty * ct_val;
-//
-//                     let result = Market {
-//                         symbol: name,
-//                         base_asset: base_coin.to_string(),
-//                         quote_asset: quote_coin.to_string(),
-//                         tick_size,
-//                         amount_size,
-//                         price_precision,
-//                         amount_precision,
-//                         min_qty,
-//                         max_qty,
-//                         min_notional,
-//                         max_notional,
-//                         ct_val,
-//                     };
-//                     Ok(result)
-//                 }
-//             }
-//         } else {
-//             Err(Error::new(ErrorKind::Other, res_data.to_string()))
-//         }
-//     }
-//
-//     async fn get_market_symbol(&mut self, symbol: String) -> Result<Market, Error> {
-//         let symbol = symbol.replace("_", "").to_uppercase();
-//         let res_data = self.request.get_instruments_info(symbol.clone()).await;
-//         if res_data.code == 200 {
-//             let arr_data: Vec<Value> = from_value(res_data.data["list"].clone()).unwrap();
-//             let market_info = arr_data.iter().find(|item| item["symbol"].as_str().unwrap() == symbol);
-//             match market_info {
-//                 None => {
-//                     error!("bybit_swap:获取Market信息错误!\nget_market:res_data={:?}", res_data);
-//                     Err(Error::new(ErrorKind::Other, res_data.to_string()))
-//                 }
-//                 Some(value) => {
-//                     let base_coin = value["baseCoin"].as_str().unwrap();
-//                     let quote_coin = value["quoteCoin"].as_str().unwrap();
-//                     let name = format!("{}_{}",base_coin, quote_coin);
-//                     let tick_size = Decimal::from_str(value["priceFilter"]["minPrice"].as_str().unwrap().trim()).unwrap();
-//                     let min_qty = Decimal::from_str(value["lotSizeFilter"]["minOrderQty"].as_str().unwrap().trim()).unwrap();
-//                     let max_qty = Decimal::from_str(value["lotSizeFilter"]["maxOrderQty"].as_str().unwrap().trim()).unwrap();
-//                     let ct_val = Decimal::ONE;
-//
-//                     let amount_size = min_qty * ct_val;
-//                     let price_precision = Decimal::from_u32(tick_size.scale()).unwrap();
-//                     let amount_precision = Decimal::from_u32(amount_size.scale()).unwrap();
-//                     let min_notional = min_qty * ct_val;
-//                     let max_notional = max_qty * ct_val;
-//
-//                     let result = Market {
-//                         symbol: name,
-//                         base_asset: base_coin.to_string(),
-//                         quote_asset: quote_coin.to_string(),
-//                         tick_size,
-//                         amount_size,
-//                         price_precision,
-//                         amount_precision,
-//                         min_qty,
-//                         max_qty,
-//                         min_notional,
-//                         max_notional,
-//                         ct_val,
-//                     };
-//                     Ok(result)
-//                 }
-//             }
-//         } else {
-//             Err(Error::new(ErrorKind::Other, res_data.to_string()))
-//         }
-//     }
-//
-//     // 获取订单详情
-//     async fn get_order_detail(&mut self, order_id: &str, custom_id: &str) -> Result<Order, Error> {
-//         let symbol = self.symbol_uppercase.clone();
-//         let ct_val = self.market.ct_val;
-//         let id = if !custom_id.trim().eq("") { format!("t-{}", custom_id) } else { String::new() };
-//         let res_data = self.request.get_order(symbol, order_id.parse().unwrap(), id).await;
-//         if res_data.code == 200 {
-//             let res_data_json: Value = res_data.data["list"].clone();
-//             if res_data_json.is_array() && res_data_json.as_array().unwrap().len() == 0 {
-//                 return Err(Error::new(ErrorKind::Other, "没有该订单!"));
-//             }
-//             let result = format_order_item(res_data_json.as_array().unwrap()[0].clone(), ct_val);
-//             Ok(result)
-//         } else {
-//             Err(Error::new(ErrorKind::Other, res_data.to_string()))
-//         }
-//     }
-//     // 获取订单列表
-//     async fn get_orders_list(&mut self, _status: &str) -> Result<Vec<Order>, Error> {
-//        Err(Error::new(ErrorKind::Other, "bybit获取订单列表暂未实现".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;
-//         let mut params = json!({
-//             "orderLinkId": format!("t-{}", custom_id),
-//             "symbol": symbol.to_string(),
-//             "price": price.to_string(),
-//             "category": "linear",
-//             "orderType":"Limit",
-//             "qty": json!(size),
-//             // 0.單向持倉 1.買側雙向持倉 2.賣側雙向持倉
-//             "positionIdx": json!(1),
-//             "reduceOnly": json!(false)
-//         });
-//
-//         if price.eq(&Decimal::ZERO) {
-//             params["timeInForce"] = json!("IOC".to_string());
-//         }
-//         match origin_side {
-//             "kd" => {
-//                 params["side"] = json!("Buy");
-//             }
-//             "pd" => {
-//                 params["side"] = json!("Sell");
-//                 // 减仓
-//                 params["reduceOnly"] = json!(true);
-//             }
-//             "kk" => {
-//                 params["side"] = json!("Sell");
-//                 params["positionIdx"] = json!(2);
-//             }
-//             "pk" => {
-//                 params["side"] = json!("Buy");
-//                 // 减仓
-//                 params["reduceOnly"] = json!(true);
-//                 params["positionIdx"] = json!(2);
-//             }
-//             _ => { error!("下单参数错误"); }
-//         };
-//         let res_data = self.request.swap_order(params).await;
-//         if res_data.code == 200 {
-//             let result = format_new_order_item(res_data.data, price, size);
-//             Ok(result)
-//         } else {
-//             Err(Error::new(ErrorKind::Other, res_data.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 order_type = if price == Decimal::ZERO {
-//             "Market"
-//         } else {
-//             "Limit"
-//         };
-//         let mut params = json!({
-//             "orderLinkId": format!("t-{}", custom_id),
-//             "symbol": symbol_upper,
-//             "price": price.to_string(),
-//             "category": "linear",
-//             "orderType": order_type,
-//             "qty": json!(size),
-//             // 0.單向持倉 1.買側雙向持倉 2.賣側雙向持倉
-//             "positionIdx": json!(1),
-//             "reduceOnly": json!(false)
-//         });
-//
-//         if price.eq(&Decimal::ZERO) {
-//             params["timeInForce"] = json!("IOC".to_string());
-//         }
-//         match origin_side {
-//             "kd" => {
-//                 params["side"] = json!("Buy");
-//             }
-//             "pd" => {
-//                 params["side"] = json!("Sell");
-//                 params["positionIdx"] = json!(1);
-//                 // 减仓
-//                 params["reduceOnly"] = json!(true);
-//             }
-//             "kk" => {
-//                 params["side"] = json!("Sell");
-//                 params["positionIdx"] = json!(2);
-//             }
-//             "pk" => {
-//                 params["side"] = json!("Buy");
-//                 params["positionIdx"] = json!(2);
-//                 // 减仓
-//                 params["reduceOnly"] = json!(true);
-//             }
-//             _ => { error!("下单参数错误"); }
-//         };
-//         let res_data = self.request.swap_order(params.clone()).await;
-//         if res_data.code == 200 {
-//             let result = format_new_order_item(res_data.data, price, size);
-//             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> {
-//         let symbol = self.symbol_uppercase.clone();
-//         let id = format!("t-{}", custom_id);
-//         let res_data = self.request.cancel_order(symbol, String::from(order_id), id.clone()).await;
-//         if res_data.code == 200 {
-//             let result = format_cancel_order_item(res_data.data);
-//             Ok(result)
-//         } else {
-//             Err(Error::new(ErrorKind::Other, res_data.to_string()))
-//         }
-//     }
-//     // 批量撤销订单
-//     async fn cancel_orders(&mut self) -> Result<Vec<Order>, Error> {
-//         let symbol = self.symbol_uppercase.clone();
-//         let res_data = self.request.cancel_orders(symbol).await;
-//         if res_data.code == 200 {
-//             info!("{}", res_data.data.to_string());
-//             let res_arr: Vec<Value> = from_value(res_data.data).unwrap();
-//             let result = res_arr.iter().map(|item| format_cancel_order_item(item.clone())).collect();
-//             Ok(result)
-//         } 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_orders(symbol).await;
-//         if res_data.code == 200 {
-//             info!("{}", res_data.data.to_string());
-//             let res_arr: Vec<Value> = from_value(res_data.data["list"].clone()).unwrap();
-//             let result = res_arr.iter().map(|item| format_cancel_order_item(item.clone())).collect();
-//             Ok(result)
-//         } else {
-//             Err(Error::new(ErrorKind::Other, res_data.to_string()))
-//         }
-//     }
-//
-//     async fn take_stop_loss_order(&mut self, _stop_price: Decimal, _price: Decimal, _side: &str) -> Result<Value, Error> {
-//         Err(Error::new(ErrorKind::NotFound, "bybit_swap:该交易所方法未实现".to_string()))
-//     }
-//
-//     async fn cancel_stop_loss_order(&mut self, _order_id: &str) -> Result<Value, Error> {
-//         Err(Error::new(ErrorKind::NotFound, "bybit_swap:该交易所方法未实现".to_string()))
-//     }
-//
-//     // 设置持仓模式
-//     async fn set_dual_mode(&mut self, _coin: &str, is_dual_mode: bool) -> Result<String, Error> {
-//         let coin_format = self.symbol_uppercase.clone();
-//         let mut mod_num = 0;
-//         if is_dual_mode {
-//             mod_num = 3;
-//         }
-//         let res_data = self.request.set_position_mode(coin_format, mod_num).await;
-//         if res_data.code == 200 {
-//             Ok(res_data.data.to_string())
-//         } else {
-//             Err(Error::new(ErrorKind::Other, res_data.to_string()))
-//         }
-//     }
-//
-//     // 更新双持仓模式下杠杆
-//     async fn set_dual_leverage(&mut self, leverage: &str) -> Result<String, Error> {
-//         let symbol = self.symbol_uppercase.clone();
-//         let res_data = self.request.set_leverage(symbol, leverage.to_string()).await;
-//         if res_data.code == 200 {
-//             Ok(res_data.data.to_string())
-//         } else {
-//             Err(Error::new(ErrorKind::Other, res_data.to_string()))
-//         }
-//     }
-//
-//     async fn set_auto_deposit_status(&mut self, _status: bool) -> Result<String, Error> { Err(Error::new(ErrorKind::NotFound, "gate:该交易所方法未实现".to_string())) }
-//
-//     // 交易账户互转
-//     async fn wallet_transfers(&mut self, _coin: &str, _from: &str, _to: &str, _amount: Decimal) -> Result<String, Error> {
-//         // let coin_format = coin.to_string().to_lowercase();
-//         // let res_data = self.request.wallet_transfers(coin_format.clone(), from.to_string(), to.to_string(), amount.to_string(), coin_format.clone()).await;
-//         // if res_data.code == 200 {
-//         //     let res_data_str = &res_data.data;
-//         //     let result = res_data_str.clone();
-//         //     Ok(result)
-//         // } else {
-//         //     Err(Error::new(ErrorKind::Other, res_data.to_string()))
-//         // }
-//         Err(Error::new(ErrorKind::Other, "暂未实现!"))
-//     }
-//
-//     // 指令下单
-//     async fn command_order(&mut self, order_command: &mut OrderCommand, trace_stack: &TraceStack) {
-//         // 下单指令
-//         let mut handles = vec![];
-//         for item in order_command.limits_open.keys() {
-//             let mut self_clone = self.clone();
-//
-//             let amount = Decimal::from_str(order_command.limits_open[item].get(0).unwrap_or(&"0".to_string())).unwrap();
-//             let side = order_command.limits_open[item].get(1).unwrap().clone();
-//             let price = Decimal::from_str(order_command.limits_open[item].get(2).unwrap_or(&"0".to_string())).unwrap();
-//             let cid = order_command.limits_open[item].get(3).unwrap().clone();
-//
-//             let mut ts = trace_stack.clone();
-//
-//             let handle = tokio::spawn(async move {
-//                 ts.on_before_send();
-//                 // TraceStack::show_delay(&ts.ins);
-//                 let result = self_clone.take_order(cid.as_str(), side.as_str(), price, amount).await;
-//                 ts.on_after_send();
-//                 match result {
-//                     Ok(mut result) => {
-//                         // 记录此订单完成时间
-//                         result.trace_stack = ts;
-//
-//                         self_clone.order_sender.send(result).await.unwrap();
-//                     }
-//                     Err(error) => {
-//                         error!("bybit:下单失败:{:?}", error);
-//
-//                         let mut err_order = Order::new();
-//                         err_order.custom_id = cid.clone();
-//                         err_order.status = "REMOVE".to_string();
-//
-//                         self_clone.order_sender.send(err_order).await.unwrap();
-//                         self_clone.error_sender.send(error).await.unwrap();
-//                     }
-//                 }
-//             });
-//             handles.push(handle)
-//         }
-//         let futures = FuturesUnordered::from_iter(handles);
-//         let _: Result<Vec<_>, _> = futures.try_collect().await;
-//
-//         // 撤销订单
-//         let mut cancel_handles = vec![];
-//         for item in order_command.cancel.keys() {
-//             let mut self_clone = self.clone();
-//
-//             let order_id = order_command.cancel[item].get(1).unwrap().clone();
-//             let custom_id = order_command.cancel[item].get(0).unwrap().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) => {
-//                                 self_clone.order_sender.send(order).await.unwrap();
-//                             }
-//                             Err(_err) => {
-//                                 error!("bybit:撤单失败,而且查单也失败了,oid={}, cid={}。", order_id.clone(), custom_id.clone());
-//                             }
-//                         }
-//                         self_clone.error_sender.send(error).await.unwrap();
-//                     }
-//                 }
-//             });
-//             cancel_handles.push(handle)
-//         }
-//         let futures = FuturesUnordered::from_iter(cancel_handles);
-//         let _: Result<Vec<_>, _> = futures.try_collect().await;
-//
-//         // 检查订单指令
-//         let mut check_handles = vec![];
-//         for item in order_command.check.keys() {
-//             let mut self_clone = self.clone();
-//
-//             let order_id = order_command.check[item].get(1).unwrap().clone();
-//             let custom_id = order_command.check[item].get(0).unwrap().clone();
-//
-//             let handle = tokio::spawn(async move {
-//                 let result = self_clone.get_order_detail(&order_id, &custom_id).await;
-//                 match result {
-//                     Ok(result) => {
-//                         self_clone.order_sender.send(result).await.unwrap();
-//                     }
-//                     Err(error) => {
-//                         self_clone.error_sender.send(error).await.unwrap();
-//                     }
-//                 }
-//             });
-//             check_handles.push(handle)
-//         }
-//         let futures = FuturesUnordered::from_iter(check_handles);
-//         let _: Result<Vec<_>, _> = futures.try_collect().await;
-//     }
-// }
-//
-// pub fn format_position_item(position: &Value, ct_val: Decimal) -> Position {
-//     let position_idx = position["positionIdx"].to_string();
-//     let mut position_mode = match position_idx.as_str() {
-//         "0" => PositionModeEnum::Both,
-//         "1" => PositionModeEnum::Long,
-//         "2" => PositionModeEnum::Short,
-//         _ => {
-//             error!("bybit_swap:格式化持仓模式错误!\nformat_position_item:position={:?}", position);
-//             panic!("bybit_swap:格式化持仓模式错误!\nformat_position_item:position={:?}", position)
-//         }
-//     };
-//     let size_str: String = from_value(position["size"].clone()).unwrap();
-//     let size = Decimal::from_str(size_str.as_str()).unwrap();
-//     let amount = size * ct_val;
-//     let mut profit = Decimal::ZERO;
-//     let profit_str = position["unrealisedPnl"].as_str().unwrap_or("0");
-//     if profit_str != "" {
-//         profit = Decimal::from_str(profit_str).unwrap();
-//     }
-//
-//     match position_mode {
-//         PositionModeEnum::Both => {
-//             position_mode = match amount {
-//                 amount if amount > Decimal::ZERO => PositionModeEnum::Long,
-//                 amount if amount < Decimal::ZERO => PositionModeEnum::Short,
-//                 _ => { PositionModeEnum::Both }
-//             }
-//         }
-//         _ => {}
-//     }
-//     Position {
-//         symbol: position["symbol"].as_str().unwrap_or("").parse().unwrap(),
-//         margin_level: Decimal::from_str(position["leverage"].as_str().unwrap()).unwrap(),
-//         amount,
-//         frozen_amount: Decimal::ZERO,
-//         price: Decimal::from_str(position["avgPrice"].as_str().unwrap()).unwrap(),
-//         profit,
-//         position_mode,
-//         margin: Decimal::from_str(position["positionBalance"].as_str().unwrap()).unwrap(),
-//     }
-// }
-//
-// fn format_cancel_order_item(order: Value) -> Order {
-//      Order {
-//         id: format!("{}", order["orderId"].as_str().unwrap()),
-//         custom_id: order["orderLinkId"].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::new(0, Instant::now()).on_special("688 trace_stack".to_string())
-//     }
-// }
-//
-// fn format_new_order_item(order: Value, price: Decimal, amount: Decimal) -> Order {
-//     Order {
-//         id: format!("{}", order["orderId"].as_str().unwrap()),
-//         custom_id: order["orderLinkId"].as_str().unwrap().replace("t-my-custom-id_", "").replace("t-", ""),
-//         price,
-//         amount,
-//         deal_amount: Decimal::ZERO,
-//         avg_price: price,
-//         status: "NEW".to_string(),
-//         order_type: "limit".to_string(),
-//         trace_stack: TraceStack::new(0, Instant::now()).on_special("688 trace_stack".to_string())
-//     }
-// }
-//
-// pub fn format_order_item(order: Value, ct_val: Decimal) -> Order {
-//     let status = order["orderStatus"].as_str().unwrap_or("");
-//     let text = order["orderLinkId"].as_str().unwrap_or("");
-//     let mut size = Decimal::ZERO;
-//     let mut deal_amount = Decimal::ZERO;
-//     let mut avg_price = Decimal::ZERO;
-//
-//     let right_str = order["cumExecQty"].to_string();
-//     let size_str = order["qty"].to_string();
-//
-//     if !order.get("qty").is_some() {
-//         size = Decimal::from_str(size_str.as_str()).unwrap();
-//         let right_val = Decimal::from_str(order["cumExecValue"].as_str().unwrap()).unwrap();
-//         let right = Decimal::from_str(right_str.as_str()).unwrap();
-//         if right != Decimal::ZERO {
-//             avg_price = right_val / right;
-//         }
-//         deal_amount = right * ct_val;
-//     }
-//
-//     let amount = size * ct_val;
-//     let custom_status = if status == "Filled" || status == "Cancelled" { "REMOVE".to_string() } else if status == "New" { "NEW".to_string() } else {
-//         "NULL".to_string()
-//     };
-//     let rst_order = Order {
-//         id: format!("{}", order["orderId"].as_str().unwrap()),
-//         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,
-//         status: custom_status,
-//         order_type: "limit".to_string(),
-//         trace_stack: TraceStack::new(0, Instant::now()).on_special("688 trace_stack".to_string()),
-//     };
-//     return rst_order;
-// }
+use std::collections::{BTreeMap};
+use std::io::{Error, ErrorKind};
+use std::str::FromStr;
+use tokio::sync::mpsc::Sender;
+use async_trait::async_trait;
+use futures::stream::FuturesUnordered;
+use futures::TryStreamExt;
+use rust_decimal::Decimal;
+use serde_json::{from_value, json, Value};
+use rust_decimal::prelude::FromPrimitive;
+use serde::{Deserialize, Serialize};
+use tokio::time::Instant;
+use tracing::{error, info, trace};
+use exchanges::bybit_swap_rest::BybitSwapRest;
+use crate::{Platform, ExchangeEnum, Account, Position, Ticker, Market, Order, OrderCommand, PositionModeEnum};
+use global::trace_stack::TraceStack;
+
+#[derive(Debug, Clone, Deserialize, Serialize)]
+#[serde(rename_all = "camelCase")]
+struct SwapTicker {
+    symbol: String,
+    high_price24h: Decimal,
+    low_price24h: Decimal,
+    bid1_price: Decimal,
+    ask1_price: Decimal,
+    last_price: Decimal,
+    volume24h: Decimal
+}
+
+#[allow(dead_code)]
+#[derive(Clone)]
+pub struct BybitSwap {
+    exchange: ExchangeEnum,
+    symbol: String,
+    symbol_uppercase: String,
+    is_colo: bool,
+    params: BTreeMap<String, String>,
+    request: BybitSwapRest,
+    market: Market,
+    order_sender: Sender<Order>,
+    error_sender: 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 {
+        let market = Market::new();
+        let mut bybit_swap = BybitSwap {
+            exchange: ExchangeEnum::BybitSwap,
+            symbol: symbol.to_uppercase(),
+            symbol_uppercase: symbol.replace("_", "").to_uppercase(),
+            is_colo,
+            params: params.clone(),
+            request: BybitSwapRest::new(is_colo, params.clone()),
+            market,
+            order_sender,
+            error_sender,
+        };
+
+        // 修改持仓模式
+        let symbol_array: Vec<&str> = symbol.split("_").collect();
+        let mode_result = bybit_swap.set_dual_mode(symbol_array[1], false).await;
+        match mode_result {
+            Ok(_) => {
+                trace!("Bybit:设置持仓模式成功!")
+            }
+            Err(error) => {
+                error!("Bybit:设置持仓模式失败!mode_result={}", error)
+            }
+        }
+        // 设置持仓杠杆
+        let lever_rate_result = bybit_swap.set_dual_leverage("1").await;
+        match lever_rate_result {
+            Ok(ok) => {
+                info!("Bybit:设置持仓杠杆成功!{:?}", ok);
+            }
+            Err(error) => {
+                error!("Bybit:设置持仓杠杆失败!{:?}", error)
+            }
+        }
+        // 获取市场信息
+        bybit_swap.market = BybitSwap::get_market(&mut bybit_swap).await.unwrap_or(bybit_swap.market);
+        bybit_swap
+    }
+}
+
+#[async_trait]
+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
+    }
+    // 获取交易对
+    fn get_self_symbol(&self) -> String { self.symbol.clone() }
+    // 获取是否使用高速通道
+    fn get_self_is_colo(&self) -> bool {
+        self.is_colo
+    }
+    // 获取params信息
+    fn get_self_params(&self) -> BTreeMap<String, String> {
+        self.params.clone()
+    }
+    // 获取market信息
+    fn get_self_market(&self) -> Market { self.market.clone() }
+    // 获取请求时间
+    fn get_request_delays(&self) -> Vec<i64> { self.request.get_delays() }
+    // 获取请求平均时间
+    fn get_request_avg_delay(&self) -> Decimal { self.request.get_avg_delay() }
+    // 获取请求最大时间
+    fn get_request_max_delay(&self) -> i64 { self.request.get_max_delay() }
+
+    // 获取服务器时间
+    async fn get_server_time(&mut self) -> Result<String, Error> {
+        let res_data = self.request.get_server_time().await;
+        if res_data.code == 200 {
+            let result = res_data.data["server_time"].to_string();
+            Ok(result)
+        } else {
+            Err(Error::new(ErrorKind::Other, res_data.to_string()))
+        }
+    }
+    // 获取账号信息
+    async fn get_account(&mut self) -> Result<Account, Error> {
+        let symbol_array: Vec<&str> = self.symbol.split("_").collect();
+        let res_data = self.request.get_account_balance(symbol_array[1].parse().unwrap()).await;
+        if res_data.code == 200 {
+            let arr_infos: Vec<Value> = from_value(res_data.data["list"].clone()).unwrap();
+            if arr_infos.len() < 1usize{
+                return Err(Error::new(ErrorKind::NotFound, format!("{} 无账户信息", symbol_array[1])));
+            }
+            let coin_infos: Vec<Value> = from_value(arr_infos[0]["coin"].clone()).unwrap();
+            if coin_infos.len() < 1usize{
+               return Err(Error::new(ErrorKind::NotFound, format!("{} 无账户信息", symbol_array[1])));
+            }
+            let balance = Decimal::from_str(coin_infos[0]["equity"].as_str().unwrap()).unwrap();
+            let available_balance = Decimal::from_str(coin_infos[0]["walletBalance"].as_str().unwrap()).unwrap();
+            let frozen_balance = balance - available_balance;
+            let result = Account {
+                coin: symbol_array[1].to_string(),
+                balance,
+                available_balance,
+                frozen_balance,
+                stocks: Decimal::ZERO,
+                available_stocks: Decimal::ZERO,
+                frozen_stocks: Decimal::ZERO,
+            };
+            Ok(result)
+        } else {
+            Err(Error::new(ErrorKind::Other, res_data.to_string()))
+        }
+    }
+
+    async fn get_spot_account(&mut self) -> Result<Vec<Account>, Error> {
+        Err(Error::new(ErrorKind::NotFound, "bybit_swap:该交易所方法未实现".to_string()))
+    }
+
+    // 获取持仓信息
+    async fn get_position(&mut self) -> Result<Vec<Position>, Error> {
+        let symbol = self.symbol_uppercase.clone();
+        let ct_val = self.market.multiplier;
+        let res_data = self.request.get_positions(symbol, "".to_string()).await;
+        if res_data.code == 200 {
+            let result = res_data.data["list"].as_array().unwrap().iter().map(|item| { format_position_item(item, ct_val) }).collect();
+            Ok(result)
+        } else {
+            Err(Error::new(ErrorKind::Other, res_data.to_string()))
+        }
+    }
+    // 获取所有持仓
+    async fn get_positions(&mut self) -> Result<Vec<Position>, Error> {
+        let symbol_array: Vec<&str> = self.symbol.split("_").collect();
+        let ct_val = self.market.multiplier;
+        let res_data = self.request.get_positions("".to_string(), symbol_array[1].to_string().to_uppercase()).await;
+        if res_data.code == 200 {
+            info!("{}", res_data.data.to_string());
+            let result = res_data.data["list"].as_array().unwrap().iter().map(|item| { format_position_item(item, ct_val) }).collect();
+            Ok(result)
+        } else {
+            Err(Error::new(ErrorKind::Other, res_data.to_string()))
+        }
+    }
+    // 获取市场行情
+    async fn get_ticker(&mut self) -> Result<Ticker, Error> {
+        let symbol = self.symbol_uppercase.clone();
+        let res_data = self.request.get_tickers(symbol).await;
+        if res_data.code == 200 {
+            let list :Vec<SwapTicker> = from_value(res_data.data["list"].clone()).unwrap_or(Vec::new());
+
+            if list.len() < 1usize {
+                error!("bybit_swap:获取Ticker信息错误!\nget_ticker:res_data={:?}", res_data);
+                return Err(Error::new(ErrorKind::Other, res_data.to_string()));
+            }
+            let value = list[0].clone();
+            Ok(Ticker{
+                time: chrono::Utc::now().timestamp_millis(),
+                high: value.high_price24h,
+                low: value.low_price24h,
+                sell: value.ask1_price,
+                buy: value.bid1_price,
+                last: value.last_price,
+                volume: value.volume24h
+            })
+        } else {
+            Err(Error::new(ErrorKind::Other, res_data.to_string()))
+        }
+    }
+
+    async fn get_ticker_symbol(&mut self, symbol: String) -> Result<Ticker, Error> {
+        let symbol_upper = symbol.replace("_", "").to_uppercase();
+        let res_data = self.request.get_tickers(symbol_upper.clone()).await;
+        if res_data.code == 200 {
+            let list: Vec<SwapTicker> = from_value(res_data.data["list"].clone()).unwrap();
+            let ticker_info = list.iter().find(|&item| item.symbol == symbol_upper);
+
+            match ticker_info {
+                None => {
+                    error!("bybit_swap:获取Ticker信息错误!\nget_ticker:res_data={:?}", res_data);
+                    Err(Error::new(ErrorKind::Other, res_data.to_string()))
+                }
+                Some(value) => {
+                    let result = Ticker {
+                        time: chrono::Utc::now().timestamp_millis(),
+                        high: value.high_price24h,
+                        low: value.low_price24h,
+                        sell: value.ask1_price,
+                        buy: value.bid1_price,
+                        last: value.last_price,
+                        volume: value.volume24h
+                    };
+                    Ok(result)
+                }
+            }
+        } else {
+            Err(Error::new(ErrorKind::Other, res_data.to_string()))
+        }
+    }
+
+    async fn get_market(&mut self) -> Result<Market, Error> {
+        let symbol = self.symbol_uppercase.clone();
+        let res_data = self.request.get_instruments_info(symbol.clone()).await;
+        if res_data.code == 200 {
+            let arr_data: Vec<Value> = from_value(res_data.data["list"].clone()).unwrap();
+            let market_info = arr_data.iter().find(|&item| item["symbol"].as_str().unwrap() == symbol);
+            match market_info {
+                None => {
+                    error!("bybit_swap:获取Market信息错误!\nget_market:res_data={:?}", res_data);
+                    Err(Error::new(ErrorKind::Other, res_data.to_string()))
+                }
+                Some(value) => {
+                    let base_coin = value["baseCoin"].as_str().unwrap();
+                    let quote_coin = value["quoteCoin"].as_str().unwrap();
+                    let name = format!("{}_{}",base_coin, quote_coin);
+                    let tick_size = Decimal::from_str(value["priceFilter"]["minPrice"].as_str().unwrap().trim()).unwrap();
+                    let min_qty = Decimal::from_str(value["lotSizeFilter"]["minOrderQty"].as_str().unwrap().trim()).unwrap();
+                    let max_qty = Decimal::from_str(value["lotSizeFilter"]["maxOrderQty"].as_str().unwrap().trim()).unwrap();
+                    let ct_val = Decimal::ONE;
+
+                    let amount_size = min_qty * ct_val;
+                    let price_precision = Decimal::from_u32(tick_size.scale()).unwrap();
+                    let amount_precision = Decimal::from_u32(amount_size.scale()).unwrap();
+                    let min_notional = Decimal::from_str(value["lotSizeFilter"]["minNotionalValue"].as_str().unwrap().trim()).unwrap();
+                    let max_notional = max_qty * ct_val;
+
+                    let result = Market {
+                        symbol: name,
+                        base_asset: base_coin.to_string(),
+                        quote_asset: quote_coin.to_string(),
+                        tick_size,
+                        amount_size,
+                        price_precision,
+                        amount_precision,
+                        min_qty,
+                        max_qty,
+                        min_notional,
+                        max_notional,
+                        multiplier: ct_val,
+                    };
+                    Ok(result)
+                }
+            }
+        } else {
+            Err(Error::new(ErrorKind::Other, res_data.to_string()))
+        }
+    }
+
+    async fn get_market_symbol(&mut self, symbol: String) -> Result<Market, Error> {
+        let symbol = symbol.replace("_", "").to_uppercase();
+        let res_data = self.request.get_instruments_info(symbol.clone()).await;
+        if res_data.code == 200 {
+            let arr_data: Vec<Value> = from_value(res_data.data["list"].clone()).unwrap();
+            let market_info = arr_data.iter().find(|item| item["symbol"].as_str().unwrap() == symbol);
+            match market_info {
+                None => {
+                    error!("bybit_swap:获取Market信息错误!\nget_market:res_data={:?}", res_data);
+                    Err(Error::new(ErrorKind::Other, res_data.to_string()))
+                }
+                Some(value) => {
+                    let base_coin = value["baseCoin"].as_str().unwrap();
+                    let quote_coin = value["quoteCoin"].as_str().unwrap();
+                    let name = format!("{}_{}",base_coin, quote_coin);
+                    let tick_size = Decimal::from_str(value["priceFilter"]["minPrice"].as_str().unwrap().trim()).unwrap();
+                    let min_qty = Decimal::from_str(value["lotSizeFilter"]["minOrderQty"].as_str().unwrap().trim()).unwrap();
+                    let max_qty = Decimal::from_str(value["lotSizeFilter"]["maxOrderQty"].as_str().unwrap().trim()).unwrap();
+                    let ct_val = Decimal::ONE;
+
+                    let amount_size = min_qty * ct_val;
+                    let price_precision = Decimal::from_u32(tick_size.scale()).unwrap();
+                    let amount_precision = Decimal::from_u32(amount_size.scale()).unwrap();
+                    let min_notional = Decimal::from_str(value["lotSizeFilter"]["minNotionalValue"].as_str().unwrap().trim()).unwrap();
+                    let max_notional = max_qty * ct_val;
+
+                    let result = Market {
+                        symbol: name,
+                        base_asset: base_coin.to_string(),
+                        quote_asset: quote_coin.to_string(),
+                        tick_size,
+                        amount_size,
+                        price_precision,
+                        amount_precision,
+                        min_qty,
+                        max_qty,
+                        min_notional,
+                        max_notional,
+                        multiplier: ct_val,
+                    };
+                    Ok(result)
+                }
+            }
+        } else {
+            Err(Error::new(ErrorKind::Other, res_data.to_string()))
+        }
+    }
+
+    // 获取订单详情
+    async fn get_order_detail(&mut self, order_id: &str, custom_id: &str) -> Result<Order, Error> {
+        let symbol = self.symbol_uppercase.clone();
+        let ct_val = self.market.multiplier;
+        let id = if !custom_id.trim().eq("") { format!("t-{}", custom_id) } else { String::new() };
+        let res_data = self.request.get_order(symbol, order_id.parse().unwrap(), id).await;
+        if res_data.code == 200 {
+            let res_data_json: Value = res_data.data["list"].clone();
+            if res_data_json.is_array() && res_data_json.as_array().unwrap().len() == 0 {
+                return Err(Error::new(ErrorKind::Other, "没有该订单!"));
+            }
+            let result = format_order_item(res_data_json.as_array().unwrap()[0].clone(), ct_val);
+            Ok(result)
+        } else {
+            Err(Error::new(ErrorKind::Other, res_data.to_string()))
+        }
+    }
+    // 获取订单列表
+    async fn get_orders_list(&mut self, _status: &str) -> Result<Vec<Order>, Error> {
+       Err(Error::new(ErrorKind::Other, "bybit获取订单列表暂未实现".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.multiplier;
+        let size = amount / ct_val;
+        let mut params = json!({
+            "orderLinkId": format!("t-{}", custom_id),
+            "symbol": symbol.to_string(),
+            "price": price.to_string(),
+            "category": "linear",
+            "orderType":"Limit",
+            "qty": json!(size),
+            // 0.單向持倉 1.買側雙向持倉 2.賣側雙向持倉
+            // "positionIdx": json!(1),
+            "positionIdx": json!(0),
+            "reduceOnly": json!(false)
+        });
+
+        if price.eq(&Decimal::ZERO) {
+            params["timeInForce"] = json!("IOC".to_string());
+        }
+        match origin_side {
+            "kd" => {
+                params["side"] = json!("Buy");
+            }
+            "pd" => {
+                params["side"] = json!("Sell");
+                // 减仓
+                params["reduceOnly"] = json!(true);
+            }
+            "kk" => {
+                params["side"] = json!("Sell");
+                // params["positionIdx"] = json!(2);
+            }
+            "pk" => {
+                params["side"] = json!("Buy");
+                // 减仓
+                params["reduceOnly"] = json!(true);
+                // params["positionIdx"] = json!(2);
+            }
+            _ => { error!("下单参数错误"); }
+        };
+        let res_data = self.request.swap_order(params).await;
+        if res_data.code == 200 {
+            let result = format_new_order_item(res_data.data, price, size);
+            Ok(result)
+        } else {
+            Err(Error::new(ErrorKind::Other, res_data.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 order_type = if price == Decimal::ZERO {
+            "Market"
+        } else {
+            "Limit"
+        };
+        let mut params = json!({
+            "orderLinkId": format!("t-{}", custom_id),
+            "symbol": symbol_upper,
+            "price": price.to_string(),
+            "category": "linear",
+            "orderType": order_type,
+            "qty": json!(size),
+            // 0.單向持倉 1.買側雙向持倉 2.賣側雙向持倉
+            "positionIdx": json!(0),
+            "reduceOnly": json!(false)
+        });
+
+        if price.eq(&Decimal::ZERO) {
+            params["timeInForce"] = json!("IOC".to_string());
+        }
+        match origin_side {
+            "kd" => {
+                params["side"] = json!("Buy");
+            }
+            "pd" => {
+                params["side"] = json!("Sell");
+                // params["positionIdx"] = json!(1);
+                // 减仓
+                params["reduceOnly"] = json!(true);
+            }
+            "kk" => {
+                params["side"] = json!("Sell");
+                // params["positionIdx"] = json!(2);
+            }
+            "pk" => {
+                params["side"] = json!("Buy");
+                // params["positionIdx"] = json!(2);
+                // 减仓
+                params["reduceOnly"] = json!(true);
+            }
+            _ => { error!("下单参数错误"); }
+        };
+        let res_data = self.request.swap_order(params.clone()).await;
+        if res_data.code == 200 {
+            let result = format_new_order_item(res_data.data, price, size);
+            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> {
+        let symbol = self.symbol_uppercase.clone();
+        let id = format!("t-{}", custom_id);
+        let res_data = self.request.cancel_order(symbol, String::from(order_id), id.clone()).await;
+        if res_data.code == 200 {
+            let result = format_cancel_order_item(res_data.data);
+            Ok(result)
+        } else {
+            Err(Error::new(ErrorKind::Other, res_data.to_string()))
+        }
+    }
+    // 批量撤销订单
+    async fn cancel_orders(&mut self) -> Result<Vec<Order>, Error> {
+        let symbol = self.symbol_uppercase.clone();
+        let res_data = self.request.cancel_orders(symbol).await;
+        if res_data.code == 200 {
+            info!("{}", res_data.data.to_string());
+            let res_arr: Vec<Value> = from_value(res_data.data).unwrap();
+            let result = res_arr.iter().map(|item| format_cancel_order_item(item.clone())).collect();
+            Ok(result)
+        } 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_orders(symbol).await;
+        if res_data.code == 200 {
+            info!("{}", res_data.data.to_string());
+            let res_arr: Vec<Value> = from_value(res_data.data["list"].clone()).unwrap();
+            let result = res_arr.iter().map(|item| format_cancel_order_item(item.clone())).collect();
+            Ok(result)
+        } else {
+            Err(Error::new(ErrorKind::Other, res_data.to_string()))
+        }
+    }
+
+    async fn take_stop_loss_order(&mut self, _stop_price: Decimal, _price: Decimal, _side: &str) -> Result<Value, Error> {
+        Err(Error::new(ErrorKind::NotFound, "bybit_swap:该交易所方法未实现".to_string()))
+    }
+
+    async fn cancel_stop_loss_order(&mut self, _order_id: &str) -> Result<Value, Error> {
+        Err(Error::new(ErrorKind::NotFound, "bybit_swap:该交易所方法未实现".to_string()))
+    }
+
+    // 设置持仓模式
+    async fn set_dual_mode(&mut self, _coin: &str, is_dual_mode: bool) -> Result<String, Error> {
+        let coin_format = self.symbol_uppercase.clone();
+        let mut mod_num = 0;
+        if is_dual_mode {
+            mod_num = 3;
+        }
+        let res_data = self.request.set_position_mode(coin_format, mod_num).await;
+        if res_data.code == 200 {
+            Ok(res_data.data.to_string())
+        } else {
+            Err(Error::new(ErrorKind::Other, res_data.to_string()))
+        }
+    }
+
+    // 更新双持仓模式下杠杆
+    async fn set_dual_leverage(&mut self, leverage: &str) -> Result<String, Error> {
+        let symbol = self.symbol_uppercase.clone();
+        let res_data = self.request.set_leverage(symbol, leverage.to_string()).await;
+        if res_data.code == 200 {
+            Ok(res_data.data.to_string())
+        } else {
+            Err(Error::new(ErrorKind::Other, res_data.to_string()))
+        }
+    }
+
+    async fn set_auto_deposit_status(&mut self, _status: bool) -> Result<String, Error> { Err(Error::new(ErrorKind::NotFound, "gate:该交易所方法未实现".to_string())) }
+
+    // 交易账户互转
+    async fn wallet_transfers(&mut self, _coin: &str, _from: &str, _to: &str, _amount: Decimal) -> Result<String, Error> {
+        // let coin_format = coin.to_string().to_lowercase();
+        // let res_data = self.request.wallet_transfers(coin_format.clone(), from.to_string(), to.to_string(), amount.to_string(), coin_format.clone()).await;
+        // if res_data.code == 200 {
+        //     let res_data_str = &res_data.data;
+        //     let result = res_data_str.clone();
+        //     Ok(result)
+        // } else {
+        //     Err(Error::new(ErrorKind::Other, res_data.to_string()))
+        // }
+        Err(Error::new(ErrorKind::Other, "暂未实现!"))
+    }
+
+    // 指令下单
+    async fn command_order(&mut self, order_command: &mut OrderCommand, trace_stack: &TraceStack) {
+        // 下单指令
+        let mut handles = vec![];
+        for item in order_command.limits_open.keys() {
+            let mut self_clone = self.clone();
+
+            let amount = Decimal::from_str(order_command.limits_open[item].get(0).unwrap_or(&"0".to_string())).unwrap();
+            let side = order_command.limits_open[item].get(1).unwrap().clone();
+            let price = Decimal::from_str(order_command.limits_open[item].get(2).unwrap_or(&"0".to_string())).unwrap();
+            let cid = order_command.limits_open[item].get(3).unwrap().clone();
+
+            let mut ts = trace_stack.clone();
+
+            let handle = tokio::spawn(async move {
+                ts.on_before_send();
+                // TraceStack::show_delay(&ts.ins);
+                let result = self_clone.take_order(cid.as_str(), side.as_str(), price, amount).await;
+                ts.on_after_send();
+                match result {
+                    Ok(mut result) => {
+                        // 记录此订单完成时间
+                        result.trace_stack = ts;
+
+                        self_clone.order_sender.send(result).await.unwrap();
+                    }
+                    Err(error) => {
+                        error!("bybit:下单失败:{:?}", error);
+
+                        let mut err_order = Order::new();
+                        err_order.custom_id = cid.clone();
+                        err_order.status = "REMOVE".to_string();
+
+                        self_clone.order_sender.send(err_order).await.unwrap();
+                        self_clone.error_sender.send(error).await.unwrap();
+                    }
+                }
+            });
+            handles.push(handle)
+        }
+        let futures = FuturesUnordered::from_iter(handles);
+        let _: Result<Vec<_>, _> = futures.try_collect().await;
+
+        // 撤销订单
+        let mut cancel_handles = vec![];
+        for item in order_command.cancel.keys() {
+            let mut self_clone = self.clone();
+
+            let order_id = order_command.cancel[item].get(1).unwrap().clone();
+            let custom_id = order_command.cancel[item].get(0).unwrap().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) => {
+                                self_clone.order_sender.send(order).await.unwrap();
+                            }
+                            Err(_err) => {
+                                error!("bybit:撤单失败,而且查单也失败了,oid={}, cid={}。", order_id.clone(), custom_id.clone());
+                            }
+                        }
+                        self_clone.error_sender.send(error).await.unwrap();
+                    }
+                }
+            });
+            cancel_handles.push(handle)
+        }
+        let futures = FuturesUnordered::from_iter(cancel_handles);
+        let _: Result<Vec<_>, _> = futures.try_collect().await;
+
+        // 检查订单指令
+        let mut check_handles = vec![];
+        for item in order_command.check.keys() {
+            let mut self_clone = self.clone();
+
+            let order_id = order_command.check[item].get(1).unwrap().clone();
+            let custom_id = order_command.check[item].get(0).unwrap().clone();
+
+            let handle = tokio::spawn(async move {
+                let result = self_clone.get_order_detail(&order_id, &custom_id).await;
+                match result {
+                    Ok(result) => {
+                        self_clone.order_sender.send(result).await.unwrap();
+                    }
+                    Err(error) => {
+                        self_clone.error_sender.send(error).await.unwrap();
+                    }
+                }
+            });
+            check_handles.push(handle)
+        }
+        let futures = FuturesUnordered::from_iter(check_handles);
+        let _: Result<Vec<_>, _> = futures.try_collect().await;
+    }
+}
+
+pub fn format_position_item(position: &Value, ct_val: Decimal) -> Position {
+    let position_idx = position["positionIdx"].to_string();
+    let mut position_mode = match position_idx.as_str() {
+        "0" => PositionModeEnum::Both,
+        "1" => PositionModeEnum::Long,
+        "2" => PositionModeEnum::Short,
+        _ => {
+            error!("bybit_swap:格式化持仓模式错误!\nformat_position_item:position={:?}", position);
+            panic!("bybit_swap:格式化持仓模式错误!\nformat_position_item:position={:?}", position)
+        }
+    };
+    let size_str: String = from_value(position["size"].clone()).unwrap();
+    let size = Decimal::from_str(size_str.as_str()).unwrap();
+    let side = position["side"].as_str().unwrap().to_string();
+    let amount = size * ct_val;
+    let mut profit = Decimal::ZERO;
+    let profit_str = position["unrealisedPnl"].as_str().unwrap_or("0");
+    if profit_str != "" {
+        profit = Decimal::from_str(profit_str).unwrap();
+    }
+
+    match position_mode {
+        PositionModeEnum::Both => {
+            position_mode = match side.as_str() {
+                "Buy" => PositionModeEnum::Long,
+                "Sell" => PositionModeEnum::Short,
+                _ => { PositionModeEnum::Both }
+            }
+        }
+        _ => {}
+    }
+    Position {
+        symbol: position["symbol"].as_str().unwrap_or("").parse().unwrap(),
+        margin_level: Decimal::from_str(position["leverage"].as_str().unwrap()).unwrap(),
+        amount,
+        frozen_amount: Decimal::ZERO,
+        price: Decimal::from_str(position["avgPrice"].as_str().unwrap()).unwrap(),
+        profit,
+        position_mode,
+        margin: Decimal::from_str(position["positionBalance"].as_str().unwrap()).unwrap(),
+    }
+}
+
+fn format_cancel_order_item(order: Value) -> Order {
+     Order {
+        id: format!("{}", order["orderId"].as_str().unwrap()),
+        custom_id: order["orderLinkId"].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::new(0, Instant::now()).on_special("688 trace_stack".to_string())
+    }
+}
+
+fn format_new_order_item(order: Value, price: Decimal, amount: Decimal) -> Order {
+    Order {
+        id: format!("{}", order["orderId"].as_str().unwrap()),
+        custom_id: order["orderLinkId"].as_str().unwrap().replace("t-my-custom-id_", "").replace("t-", ""),
+        price,
+        amount,
+        deal_amount: Decimal::ZERO,
+        avg_price: price,
+        status: "NEW".to_string(),
+        order_type: "limit".to_string(),
+        trace_stack: TraceStack::new(0, Instant::now()).on_special("688 trace_stack".to_string())
+    }
+}
+
+pub fn format_order_item(order: Value, ct_val: Decimal) -> Order {
+    let status = order["orderStatus"].as_str().unwrap_or("");
+    let text = order["orderLinkId"].as_str().unwrap_or("");
+    let mut size = Decimal::ZERO;
+    let mut deal_amount = Decimal::ZERO;
+    let mut avg_price = Decimal::ZERO;
+
+    let right_str = order["cumExecQty"].to_string();
+    let size_str = order["qty"].to_string();
+
+    if !order.get("qty").is_some() {
+        size = Decimal::from_str(size_str.as_str()).unwrap();
+        let right_val = Decimal::from_str(order["cumExecValue"].as_str().unwrap()).unwrap();
+        let right = Decimal::from_str(right_str.as_str()).unwrap();
+        if right != Decimal::ZERO {
+            avg_price = right_val / right;
+        }
+        deal_amount = right * ct_val;
+    }
+
+    let amount = size * ct_val;
+    let custom_status = if status == "Filled" || status == "Cancelled" { "REMOVE".to_string() } else if status == "New" { "NEW".to_string() } else {
+        "NULL".to_string()
+    };
+    let rst_order = Order {
+        id: format!("{}", order["orderId"].as_str().unwrap()),
+        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,
+        status: custom_status,
+        order_type: "limit".to_string(),
+        trace_stack: TraceStack::new(0, Instant::now()).on_special("688 trace_stack".to_string()),
+    };
+    return rst_order;
+}

+ 209 - 167
standard/src/bybit_swap_handle.rs

@@ -1,167 +1,209 @@
-// use std::str::FromStr;
-// use rust_decimal::Decimal;
-// use serde_json::{from_value, Value};
-// use tracing::{error};
-// use exchanges::response_base::ResponseData;
-// use crate::{Account, OrderBook, Order, Position, PositionModeEnum, SpecialOrder};
-//
-// // 处理账号信息
-// pub fn handle_account_info(res_data: &ResponseData, symbol: &String) -> Account {
-//     format_account_info(res_data.data.as_array().unwrap().clone(), symbol)
-// }
-//
-// pub fn format_account_info(data: Vec<Value>, symbol: &String) -> Account {
-//     let account = data.iter().find(| &item | item["accountType"] == "UNIFIED");
-//     match account {
-//         None => {
-//             error!("Bybit:格式化统一账户信息错误!\nformat_account_info: data={:?}", data);
-//             panic!("Bybit:格式化统一账户信息错误!\nformat_account_info: data={:?}", data)
-//         }
-//         Some(val) =>{
-//             let arr: Vec<Value> = from_value(val["coin"].clone()).unwrap();
-//             let upper_str = symbol.to_uppercase();
-//             let symbol_array: Vec<&str> = upper_str.split("_").collect();
-//             let balance_info = arr.iter().find(|&item| item["coin"].as_str().unwrap() == symbol_array[1]);
-//             match balance_info {
-//                 None => {
-//                     error!("Bybit:格式化usdt余额信息错误!\nformat_account_info: data={:?}", balance_info);
-//                     panic!("Bybit:格式化usdt余额信息错误!\nformat_account_info: data={:?}", balance_info)
-//                 }
-//                 Some(value) => {
-//                     let balance = Decimal::from_str(&value["walletBalance"].as_str().unwrap().to_string()).unwrap();
-//                     Account {
-//                         coin: symbol_array[1].to_string(),
-//                         balance,
-//                         available_balance: Decimal::ZERO,
-//                         frozen_balance: Decimal::ZERO,
-//                         stocks: Decimal::ZERO,
-//                         available_stocks: Decimal::ZERO,
-//                         frozen_stocks: Decimal::ZERO,
-//                     }
-//                 }
-//             }
-//         }
-//     }
-// }
-//
-// // 处理position信息
-// pub fn handle_position(res_data: &ResponseData, ct_val: &Decimal) -> Vec<Position> {
-//     res_data.data.as_array().unwrap().iter().map(|item| { format_position_item(item, ct_val) }).collect()
-// }
-//
-// pub fn format_position_item(position: &Value, ct_val: &Decimal) -> Position {
-//     let position_idx: String = position["positionIdx"].to_string();
-//     let mut position_mode = match position_idx.as_str() {
-//         "0" => PositionModeEnum::Both,
-//         "1" => PositionModeEnum::Long,
-//         "2" => PositionModeEnum::Short,
-//         _ => {
-//             error!("bybit_swap:格式化持仓模式错误!\nformat_position_item:position={:?}", position);
-//             panic!("bybit_swap:格式化持仓模式错误!\nformat_position_item:position={:?}", position)
-//         }
-//     };
-//     let symbol_mapper =  position["symbol"].as_str().unwrap().to_string();
-//     let currency = "USDT";
-//     let coin = &symbol_mapper[..symbol_mapper.find(currency).unwrap_or(0)];
-//     let size_str: String = from_value(position["size"].clone()).unwrap();
-//     let size = Decimal::from_str(size_str.as_str()).unwrap();
-//     let amount = size * ct_val;
-//     match position_mode {
-//         PositionModeEnum::Both => {
-//             position_mode = match amount {
-//                 amount if amount > Decimal::ZERO => PositionModeEnum::Long,
-//                 amount if amount < Decimal::ZERO => PositionModeEnum::Short,
-//                 _ => { PositionModeEnum::Both }
-//             }
-//         }
-//         _ => {}
-//     }
-//     Position {
-//         symbol: format!{"{}_{}", coin, currency},
-//         margin_level: Decimal::from_str(position["leverage"].as_str().unwrap()).unwrap(),
-//         amount,
-//         frozen_amount: Decimal::ZERO,
-//         price: Decimal::from_str(position["entryPrice"].as_str().unwrap()).unwrap(),
-//         profit: Decimal::from_str(position["unrealisedPnl"].as_str().unwrap()).unwrap(),
-//         position_mode,
-//         margin: Decimal::from_str(position["positionBalance"].as_str().unwrap()).unwrap(),
-//     }
-// }
-//
-// // 处理order信息
-// pub fn handle_order(res_data: &ResponseData, ct_val: Decimal) -> SpecialOrder {
-//     let res_data_json: Vec<Value> = res_data.data.as_array().unwrap().clone();
-//     let mut order_info = Vec::new();
-//     for item in res_data_json.iter() {
-//         order_info.push(format_order_item(item.clone(), ct_val));
-//     };
-//
-//     SpecialOrder {
-//         name: res_data.label.clone(),
-//         order: order_info,
-//     }
-// }
-//
-// pub fn format_order_item(order: Value, ct_val: Decimal) -> Order {
-//     let status = order["orderStatus"].as_str().unwrap_or("");
-//     let text = order["orderLinkId"].as_str().unwrap_or("");
-//     let size = Decimal::from_str(order["qty"].as_str().unwrap()).unwrap();
-//     let right = Decimal::from_str(order["cumExecQty"].as_str().unwrap()).unwrap();
-//     let right_val = Decimal::from_str(order["cumExecValue"].as_str().unwrap()).unwrap();
-//     let price = Decimal::from_str(order["price"].as_str().unwrap()).unwrap();
-//     let amount = size * ct_val;
-//     let mut avg_price = Decimal::ZERO;
-//     if right != Decimal::ZERO {
-//         avg_price = right_val / right;
-//     }
-//     let deal_amount = right * ct_val;
-//     let custom_status = if status == "Filled" || status == "Cancelled" { "REMOVE".to_string() } else if status == "New" { "NEW".to_string() } else {
-//         "NULL".to_string()
-//     };
-//     let rst_order = Order {
-//         id: format!("{}", order["orderId"].as_str().unwrap()),
-//         custom_id: text.replace("t-my-custom-id_", "").replace("t-", ""),
-//         price,
-//         amount,
-//         deal_amount,
-//         avg_price,
-//         status: custom_status,
-//         order_type: "limit".to_string()
-//     };
-//
-//     return rst_order;
-// }
-//
-// // 处理特殊Ticket信息
-// // pub fn handle_ticker(res_data: &ResponseData) -> SpecialDepth {
-// //     let ap = Decimal::from_str(res_data.data["ask1Price"].as_str().unwrap()).unwrap();
-// //     let bp = Decimal::from_str(res_data.data["bid1Price"].as_str().unwrap()).unwrap();
-// //     let aq = Decimal::from_str(res_data.data["ask1Size"].as_str().unwrap()).unwrap();
-// //     let bq = Decimal::from_str(res_data.data["bid1Size"].as_str().unwrap()).unwrap();
-// //     let mp = (bp + ap) * dec!(0.5);
-// //
-// //     let t = Decimal::from_i64(res_data.data["ts"].as_i64().unwrap()).unwrap();
-// //     let create_at = t.to_i64().unwrap();
-// //
-// //     let ticker_info = SpecialTicker { sell: ap, buy: bp, mid_price: mp, t, create_at: 0 };
-// //     let depth_info = vec![bp, bq, ap, aq];
-// //     SpecialDepth {
-// //         name: res_data.tag.clone(),
-// //         depth: depth_info,
-// //         ticker: ticker_info,
-// //         t,
-// //         create_at,
-// //     }
-// // }
-//
-// pub fn format_depth_items(value: serde_json::Value) -> Vec<OrderBook> {
-//     let mut depth_items: Vec<OrderBook> = vec![];
-//     for val in value.as_array().unwrap() {
-//         let arr = val.as_array().unwrap();
-//         depth_items.push(OrderBook {
-//             price: Decimal::from_str(arr[0].as_str().unwrap()).unwrap(),
-//             amount: Decimal::from_str(arr[1].as_str().unwrap()).unwrap(),
-//         })
-//     }
-//     return depth_items;
-// }
+use std::str::FromStr;
+use rust_decimal::Decimal;
+use rust_decimal::prelude::FromPrimitive;
+use serde_json::{from_value, Value};
+use tokio::time::Instant;
+use tracing::{error};
+use exchanges::response_base::ResponseData;
+use global::trace_stack::TraceStack;
+use crate::{Account, OrderBook, Order, Position, PositionModeEnum, SpecialOrder, Depth, Trade};
+
+// 处理账号信息
+pub fn handle_account_info(res_data: &ResponseData, symbol: &String) -> Account {
+    format_account_info(res_data.data.as_array().unwrap().clone(), symbol)
+}
+
+pub fn format_account_info(data: Vec<Value>, symbol: &String) -> Account {
+    let account = data.iter().find(| &item | item["accountType"] == "UNIFIED");
+    match account {
+        None => {
+            error!("Bybit:格式化统一账户信息错误!\nformat_account_info: data={:?}", data);
+            panic!("Bybit:格式化统一账户信息错误!\nformat_account_info: data={:?}", data)
+        }
+        Some(val) =>{
+            let arr: Vec<Value> = from_value(val["coin"].clone()).unwrap();
+            let upper_str = symbol.to_uppercase();
+            let symbol_array: Vec<&str> = upper_str.split("_").collect();
+            let balance_info = arr.iter().find(|&item| item["coin"].as_str().unwrap() == symbol_array[1]);
+            match balance_info {
+                None => {
+                    error!("Bybit:格式化usdt余额信息错误!\nformat_account_info: data={:?}", balance_info);
+                    panic!("Bybit:格式化usdt余额信息错误!\nformat_account_info: data={:?}", balance_info)
+                }
+                Some(value) => {
+                    let balance = Decimal::from_str(&value["walletBalance"].as_str().unwrap().to_string()).unwrap();
+                    Account {
+                        coin: symbol_array[1].to_string(),
+                        balance,
+                        available_balance: Decimal::ZERO,
+                        frozen_balance: Decimal::ZERO,
+                        stocks: Decimal::ZERO,
+                        available_stocks: Decimal::ZERO,
+                        frozen_stocks: Decimal::ZERO,
+                    }
+                }
+            }
+        }
+    }
+}
+
+// 处理position信息
+pub fn handle_position(res_data: &ResponseData, ct_val: &Decimal) -> Vec<Position> {
+    res_data.data.as_array().unwrap().iter().map(|item| { format_position_item(item, ct_val) }).collect()
+}
+
+pub fn format_position_item(position: &Value, ct_val: &Decimal) -> Position {
+    let position_idx: String = position["positionIdx"].to_string();
+    let mut position_mode = match position_idx.as_str() {
+        "0" => PositionModeEnum::Both,
+        "1" => PositionModeEnum::Long,
+        "2" => PositionModeEnum::Short,
+        _ => {
+            error!("bybit_swap:格式化持仓模式错误!\nformat_position_item:position={:?}", position);
+            panic!("bybit_swap:格式化持仓模式错误!\nformat_position_item:position={:?}", position)
+        }
+    };
+    let symbol_mapper =  position["symbol"].as_str().unwrap().to_string();
+    let currency = "USDT";
+    let coin = &symbol_mapper[..symbol_mapper.find(currency).unwrap_or(0)];
+    let size_str: String = from_value(position["size"].clone()).unwrap();
+    let size = Decimal::from_str(size_str.as_str()).unwrap();
+    let amount = size * ct_val;
+    let side = position["side"].as_str().unwrap().to_string();
+    let mut profit = Decimal::ZERO;
+    let profit_str = position["unrealisedPnl"].as_str().unwrap_or("0");
+    if profit_str != "" {
+        profit = Decimal::from_str(profit_str).unwrap();
+    }
+
+    match position_mode {
+        PositionModeEnum::Both => {
+            position_mode = match side.as_str() {
+                "Buy" => PositionModeEnum::Long,
+                "Sell" => PositionModeEnum::Short,
+                _ => { PositionModeEnum::Both }
+            }
+        }
+        _ => {}
+    }
+    Position {
+        symbol: format!{"{}_{}", coin, currency},
+        margin_level: Decimal::from_str(position["leverage"].as_str().unwrap()).unwrap(),
+        amount,
+        frozen_amount: Decimal::ZERO,
+        price: Decimal::from_str(position["entryPrice"].as_str().unwrap()).unwrap(),
+        profit,
+        position_mode,
+        margin: Decimal::from_str(position["positionBalance"].as_str().unwrap()).unwrap(),
+    }
+}
+
+// 处理order信息
+pub fn handle_order(res_data: &ResponseData, ct_val: &Decimal) -> SpecialOrder {
+    let res_data_json: Vec<Value> = res_data.data.as_array().unwrap().clone();
+    let mut order_info = Vec::new();
+    for item in res_data_json.iter() {
+        order_info.push(format_order_item(item.clone(), ct_val));
+    };
+
+    SpecialOrder {
+        name: res_data.label.clone(),
+        order: order_info,
+    }
+}
+
+pub fn format_order_item(order: Value, ct_val: &Decimal) -> Order {
+    let status = order["orderStatus"].as_str().unwrap_or("");
+    let text = order["orderLinkId"].as_str().unwrap_or("");
+    let size = Decimal::from_str(order["qty"].as_str().unwrap()).unwrap();
+    let right = Decimal::from_str(order["cumExecQty"].as_str().unwrap()).unwrap();
+    let right_val = Decimal::from_str(order["cumExecValue"].as_str().unwrap()).unwrap();
+    let price = Decimal::from_str(order["price"].as_str().unwrap()).unwrap();
+    let amount = size * ct_val;
+    let mut avg_price = Decimal::ZERO;
+    if right != Decimal::ZERO {
+        avg_price = right_val / right;
+    }
+    let deal_amount = right * ct_val;
+    let custom_status = if status == "Filled" || status == "Cancelled" { "REMOVE".to_string() } else if status == "New" { "NEW".to_string() } else {
+        "NULL".to_string()
+    };
+    let rst_order = Order {
+        id: format!("{}", order["orderId"].as_str().unwrap()),
+        custom_id: text.replace("t-my-custom-id_", "").replace("t-", ""),
+        price,
+        amount,
+        deal_amount,
+        avg_price,
+        status: custom_status,
+        order_type: "limit".to_string(),
+        trace_stack: TraceStack::new(0, Instant::now()).on_special("132 bybit_swap_handle".to_string()),
+    };
+
+    rst_order
+}
+
+pub fn format_trade_items(response: &ResponseData) -> Vec<Trade> {
+    let result = response.data.as_array().unwrap();
+    let mut trades = vec![];
+
+    for item in result {
+        // 因为gate的量都是张数,所以要进行真实交易量处理
+        let mut size = Decimal::from_str(item["v"].as_str().unwrap()).unwrap();
+        let price = Decimal::from_str(item["p"].as_str().unwrap().to_string().as_str()).unwrap();
+        let side = item["S"].as_str().unwrap().to_string();
+        size = match side.as_str() {
+            "Buy" => {
+                size
+            }
+            "Sell" => {
+                -size
+            }
+            _ => {
+                error!("{}", item.to_string());
+                panic!("Bybit trade error side(bybit_swap_handle_156)")
+            }
+        };
+        let value = (size * price).abs();
+
+        trades.push(Trade {
+            id: item["i"].as_str().unwrap().to_string(),
+            time: Decimal::from_i64(item["T"].as_i64().unwrap()).unwrap(),
+            size,
+            price,
+            value,
+            symbol: item["s"].as_str().unwrap().to_string(),
+        })
+    }
+
+    return trades
+}
+
+pub fn handle_book_ticker(res_data: &ResponseData, mul: &Decimal) -> Depth {
+    let asks = format_depth_items(res_data.data["a"].clone(), mul);
+    let bids = format_depth_items(res_data.data["b"].clone(), mul);
+    let t = Decimal::from_i64(res_data.reach_time).unwrap();
+    let s = res_data.data["s"].as_str().unwrap().replace("USDT", "_USDT");
+
+    Depth {
+        time: t,
+        symbol: s.to_string(),
+        asks,
+        bids,
+    }
+}
+
+pub fn format_depth_items(value: Value, mul: &Decimal) -> Vec<OrderBook> {
+    let mut depth_items: Vec<OrderBook> = vec![];
+    for val in value.as_array().unwrap() {
+        let arr = val.as_array().unwrap();
+        let price = Decimal::from_str(arr[0].as_str().unwrap()).unwrap();
+        let size = Decimal::from_str(arr[1].as_str().unwrap()).unwrap();
+        depth_items.push(OrderBook {
+            price,
+            size,
+            value: price * size * mul,
+        })
+    }
+    depth_items
+}

+ 771 - 771
standard/src/coinex_swap.rs

@@ -1,771 +1,771 @@
-// use std::collections::{BTreeMap};
-// use std::io::{Error, ErrorKind};
-// use std::str::FromStr;
-// use tokio::sync::mpsc::Sender;
-// use async_trait::async_trait;
-// use futures::stream::FuturesUnordered;
-// use futures::TryStreamExt;
-// use rust_decimal::Decimal;
-// use rust_decimal::prelude::{FromPrimitive, ToPrimitive};
-// use serde_json::{Value};
-// use tokio::spawn;
-// use tokio::time::Instant;
-// use tracing::{error, info, trace};
-// use exchanges::coinex_swap_rest::CoinexSwapRest;
-// use crate::{Platform, ExchangeEnum, Account, Position, Ticker, Market, Order, OrderCommand, PositionModeEnum, utils};
-// use global::trace_stack::TraceStack;
-// use crate::utils::get_tick_size;
-//
-// #[allow(dead_code)]
-// #[derive(Clone)]
-// pub struct CoinexSwap {
-//     exchange: ExchangeEnum,
-//     symbol: String,
-//     is_colo: bool,
-//     params: BTreeMap<String, String>,
-//     request: CoinexSwapRest,
-//     market: Market,
-//     order_sender: Sender<Order>,
-//     error_sender: Sender<Error>,
-// }
-//
-// impl CoinexSwap {
-//     pub async fn new(symbol: String, is_colo: bool, params: BTreeMap<String, String>, order_sender: Sender<Order>, error_sender: Sender<Error>) -> CoinexSwap {
-//         let market = Market::new();
-//         let mut coinex_swap = CoinexSwap {
-//             exchange: ExchangeEnum::CoinexSwap,
-//             symbol: symbol.to_uppercase(),
-//             is_colo,
-//             params: params.clone(),
-//             request: CoinexSwapRest::new(params.clone()),
-//             market,
-//             order_sender,
-//             error_sender,
-//         };
-//
-//         // 修改持仓模式
-//         let symbol_array: Vec<&str> = symbol.split("_").collect();
-//         let mode_result = coinex_swap.set_dual_mode(symbol_array[1], true).await;
-//         match mode_result {
-//             Ok(_) => {
-//                 trace!("Coinex:设置持仓模式成功!")
-//             }
-//             Err(error) => {
-//                 error!("Coinex:设置持仓模式失败!mode_result={}", error)
-//             }
-//         }
-//         // 获取市场信息
-//         coinex_swap.market = CoinexSwap::get_market(&mut coinex_swap).await.unwrap_or(coinex_swap.market);
-//         // 设置持仓杠杆
-//         let lever_rate_result = coinex_swap.set_dual_leverage("10").await;
-//         match lever_rate_result {
-//             Ok(ok) => {
-//                 info!("Coinex:设置持仓杠杆成功!{:?}", ok);
-//             }
-//             Err(error) => {
-//                 error!("Coinex:设置持仓杠杆失败!{:?}", error)
-//             }
-//         }
-//         return coinex_swap;
-//     }
-// }
-//
-// #[async_trait]
-// impl Platform for CoinexSwap {
-//     // 克隆方法
-//     fn clone_box(&self) -> Box<dyn Platform + Send + Sync> { Box::new(self.clone()) }
-//     // 获取交易所模式
-//     fn get_self_exchange(&self) -> ExchangeEnum {
-//         ExchangeEnum::CoinexSwap
-//     }
-//     // 获取交易对
-//     fn get_self_symbol(&self) -> String { self.symbol.clone() }
-//     // 获取是否使用高速通道
-//     fn get_self_is_colo(&self) -> bool {
-//         self.is_colo
-//     }
-//     // 获取params信息
-//     fn get_self_params(&self) -> BTreeMap<String, String> {
-//         self.params.clone()
-//     }
-//     // 获取market信息
-//     fn get_self_market(&self) -> Market { self.market.clone() }
-//     // 获取请求时间
-//     fn get_request_delays(&self) -> Vec<i64> { self.request.get_delays() }
-//     // 获取请求平均时间
-//     fn get_request_avg_delay(&self) -> Decimal { self.request.get_avg_delay() }
-//     // 获取请求最大时间
-//     fn get_request_max_delay(&self) -> i64 { self.request.get_max_delay() }
-//
-//     // 获取服务器时间
-//     async fn get_server_time(&mut self) -> Result<String, Error> {
-//         let res_data = self.request.get_server_time().await;
-//         if res_data.code == 200 {
-//             let res_data_json: Value = res_data.data;
-//             let result = res_data_json["timestamp"].to_string();
-//             Ok(result)
-//         } else {
-//             Err(Error::new(ErrorKind::Other, res_data.to_string()))
-//         }
-//     }
-//     // 获取账号信息
-//     async fn get_account(&mut self) -> Result<Account, Error> {
-//         let symbol_array: Vec<&str> = self.symbol.split("_").collect();
-//         let coin = symbol_array[1].to_string().to_uppercase();
-//         let res_data = self.request.get_account().await;
-//         if res_data.code == 200 {
-//             if res_data.data.is_array() {
-//                 let res_data_array = res_data.data.as_array().unwrap();
-//                 for res_data_json in res_data_array.iter() {
-//                     if res_data_json["ccy"].as_str().unwrap() == coin {
-//                         let frozen_balance= Decimal::from_str(res_data_json["frozen"].as_str().unwrap()).unwrap();
-//                         let available_balance = Decimal::from_str(res_data_json["available"].as_str().unwrap()).unwrap();
-//                         let balance = frozen_balance + available_balance;
-//                         let result = Account {
-//                             coin: symbol_array[1].to_string(),
-//                             balance,
-//                             available_balance,
-//                             frozen_balance,
-//                             stocks: Decimal::ZERO,
-//                             available_stocks: Decimal::ZERO,
-//                             frozen_stocks: Decimal::ZERO,
-//                         };
-//                         return Ok(result);
-//                     }
-//                 }
-//             }
-//         }
-//         Err(Error::new(ErrorKind::Other, res_data.to_string()))
-//     }
-//
-//     async fn get_spot_account(&mut self) -> Result<Vec<Account>, Error> {
-//         Err(Error::new(ErrorKind::NotFound, "coinex_swap:该方法暂未实现".to_string()))
-//     }
-//
-//     // 获取持仓信息
-//     async fn get_position(&mut self) -> Result<Vec<Position>, Error> {
-//         let symbol: String = self.symbol.replace("_", "").to_uppercase();
-//         let ct_val = self.market.ct_val;
-//         let res_data = self.request.get_position(symbol).await;
-//         if res_data.code == 200 {
-//             let res_data_json = res_data.data.as_array().unwrap();
-//             let result = res_data_json.iter().map(|item| { format_position_item(item, ct_val) }).collect();
-//             Ok(result)
-//         } else {
-//             Err(Error::new(ErrorKind::Other, res_data.to_string()))
-//         }
-//     }
-//
-//     // 获取所有持仓
-//     async fn get_positions(&mut self) -> Result<Vec<Position>, Error> {
-//         let res_data = self.request.get_user_position().await;
-//         if res_data.code == 200 {
-//             info!("{}", res_data.data.to_string());
-//             let res_data_json = res_data.data.as_array().unwrap();
-//             let result = res_data_json.iter().map(|item| { format_position_item(item, Decimal::ONE) }).collect();
-//             Ok(result)
-//         } else {
-//             Err(Error::new(ErrorKind::Other, res_data.to_string()))
-//         }
-//     }
-//     // 获取市场行情
-//     async fn get_ticker(&mut self) -> Result<Ticker, Error> {
-//         let symbol: String = self.symbol.replace("_", "");
-//         let res_data = self.request.get_ticker(symbol.clone()).await;
-//         if res_data.code == 200 {
-//             let res_data_json = res_data.data.as_array().unwrap();
-//             let ticker_info = res_data_json.iter().find(|item| item["market"].as_str().unwrap() == symbol);
-//             match ticker_info {
-//                 None => {
-//                     error!("coinex_swap:获取Ticker信息错误!\nget_ticker:res_data={:?}", res_data);
-//                     Err(Error::new(ErrorKind::Other, res_data.to_string()))
-//                 }
-//                 Some(value) => {
-//                     let result = Ticker {
-//                         time: chrono::Utc::now().timestamp_millis(),
-//                         high: Decimal::from_str(value["high"].as_str().unwrap()).unwrap(),
-//                         low: Decimal::from_str(value["low"].as_str().unwrap()).unwrap(),
-//                         sell: Decimal::from_str(value["last"].as_str().unwrap()).unwrap(),
-//                         buy: Decimal::from_str(value["last"].as_str().unwrap()).unwrap(),
-//                         last: Decimal::from_str(value["last"].as_str().unwrap()).unwrap(),
-//                         volume: Decimal::from_str(value["volume"].as_str().unwrap()).unwrap(),
-//                     };
-//                     Ok(result)
-//                 }
-//             }
-//         } else {
-//             Err(Error::new(ErrorKind::Other, res_data.to_string()))
-//         }
-//     }
-//
-//     async fn get_ticker_symbol(&mut self, symbol_param: String) -> Result<Ticker, Error> {
-//         let symbol: String = symbol_param.replace("_", "").to_uppercase();
-//         let res_data = self.request.get_ticker(symbol.clone()).await;
-//         if res_data.code == 200 {
-//             let res_data_json = res_data.data.as_array().unwrap();
-//             let ticker_info = res_data_json.iter().find(|item| item["contract"].as_str().unwrap() == symbol);
-//             match ticker_info {
-//                 None => {
-//                     error!("coinex_swap:获取Ticker信息错误!\nget_ticker:res_data={:?}", res_data);
-//                     Err(Error::new(ErrorKind::Other, res_data.to_string()))
-//                 }
-//                 Some(value) => {
-//                     let result = Ticker {
-//                         time: chrono::Utc::now().timestamp_millis(),
-//                         high: Decimal::from_str(value["high"].as_str().unwrap()).unwrap(),
-//                         low: Decimal::from_str(value["low"].as_str().unwrap()).unwrap(),
-//                         sell: Decimal::from_str(value["last"].as_str().unwrap()).unwrap(),
-//                         buy: Decimal::from_str(value["last"].as_str().unwrap()).unwrap(),
-//                         last: Decimal::from_str(value["last"].as_str().unwrap()).unwrap(),
-//                         volume: Decimal::from_str(value["volume"].as_str().unwrap()).unwrap(),
-//                     };
-//                     Ok(result)
-//                 }
-//             }
-//         } else {
-//             Err(Error::new(ErrorKind::Other, res_data.to_string()))
-//         }
-//     }
-//
-//     async fn get_market(&mut self) -> Result<Market, Error> {
-//         let symbol_array: Vec<&str> = self.symbol.split("_").collect();
-//         let symbol = format!("{}{}", symbol_array[0], symbol_array[1]);
-//         let res_data = self.request.get_market_details(symbol.clone()).await;
-//         if res_data.code == 200 {
-//             let res_data_json = res_data.data.as_array().unwrap();
-//             let market_info = res_data_json.iter().find(|item| item["market"].as_str().unwrap() == symbol);
-//             match market_info {
-//                 None => {
-//                     error!("coinex_swap:获取Market信息错误!\nget_market:res_data={:?}", res_data);
-//                     Err(Error::new(ErrorKind::Other, res_data.to_string()))
-//                 }
-//                 Some(value) => {
-//                     // 报价精度字符串
-//                     let price_precision_i64 = value["quote_ccy_precision"].as_i64().unwrap();
-//                     // 价格最小变动数值
-//                     let tick_size = get_tick_size(price_precision_i64.to_u32().unwrap());
-//                     // 报价精度
-//                     let price_precision = Decimal::from_i64(price_precision_i64).unwrap();
-//                     // 最小数量
-//                     let min_qty = Decimal::from_str(value["min_amount"].as_str().unwrap()).unwrap();
-//                     // 数量没有最大值
-//                     let max_qty = Decimal::MAX;
-//                     // 没有张数
-//                     let ct_val = Decimal::ONE;
-//
-//                     let amount_size = min_qty * ct_val;
-//                     let amount_precision = Decimal::from_u32(amount_size.scale()).unwrap();
-//                     let min_notional = min_qty * ct_val;
-//                     let max_notional = max_qty * ct_val;
-//
-//                     let result = Market {
-//                         symbol: self.symbol.clone(),
-//                         base_asset: symbol_array[0].to_string(),
-//                         quote_asset: symbol_array[1].to_string(),
-//                         tick_size,
-//                         amount_size,
-//                         price_precision,
-//                         amount_precision,
-//                         min_qty,
-//                         max_qty,
-//                         min_notional,
-//                         max_notional,
-//                         ct_val,
-//                     };
-//                     Ok(result)
-//                 }
-//             }
-//         } else {
-//             Err(Error::new(ErrorKind::Other, res_data.to_string()))
-//         }
-//     }
-//
-//     async fn get_market_symbol(&mut self, symbol: String) -> Result<Market, Error> {
-//         let symbol_upper = symbol.to_uppercase();
-//         let symbol_array: Vec<&str> = symbol_upper.split("_").collect();
-//         let symbol = format!("{}{}", symbol_array[0], symbol_array[1]);
-//         let res_data = self.request.get_market_details(symbol.clone()).await;
-//         if res_data.code == 200 {
-//             let res_data_json = res_data.data.as_array().unwrap();
-//             let market_info = res_data_json.iter().find(|item| item["name"].as_str().unwrap() == symbol.clone());
-//             match market_info {
-//                 None => {
-//                     error!("coinex_swap:获取Market信息错误!\nget_market:res_data={:?}", res_data);
-//                     Err(Error::new(ErrorKind::Other, res_data.to_string()))
-//                 }
-//                 Some(value) => {
-//                     let tick_size = Decimal::from_str(value["quote_ccy_precision"].as_str().unwrap()).unwrap();
-//                     let min_qty = Decimal::from_str(&value["min_amount"].to_string()).unwrap();
-//                     // 数量没有最大值
-//                     let max_qty = Decimal::MAX;
-//                     // 没有张数
-//                     let ct_val = Decimal::ONE;
-//
-//                     let amount_size = min_qty * ct_val;
-//                     let price_precision = Decimal::from_u32(tick_size.scale()).unwrap();
-//                     let amount_precision = Decimal::from_u32(amount_size.scale()).unwrap();
-//                     let min_notional = min_qty * ct_val;
-//                     let max_notional = max_qty * ct_val;
-//
-//                     let result = Market {
-//                         symbol: self.symbol.clone(),
-//                         base_asset: symbol_array[0].to_string(),
-//                         quote_asset: symbol_array[1].to_string(),
-//                         tick_size,
-//                         amount_size,
-//                         price_precision,
-//                         amount_precision,
-//                         min_qty,
-//                         max_qty,
-//                         min_notional,
-//                         max_notional,
-//                         ct_val,
-//                     };
-//                     Ok(result)
-//                 }
-//             }
-//         } else {
-//             Err(Error::new(ErrorKind::Other, res_data.to_string()))
-//         }
-//     }
-//
-//     // 获取订单详情
-//     async fn get_order_detail(&mut self, order_id: &str, custom_id: &str) -> Result<Order, Error> {
-//         let symbol = self.symbol.replace("_", "").to_uppercase();
-//         let ct_val = self.market.ct_val;
-//         let res_data;
-//         let status ;
-//         if order_id != "" {
-//             status = "";
-//             res_data = self.request.get_order_details(order_id.to_string(), symbol).await;
-//         } else if custom_id != "" {
-//             // 通过客户端id查询  只有未完成的订单才能查询出来
-//             res_data = self.request.get_pending_order(custom_id.to_string()).await;
-//             status = "open";
-//         } else {
-//             return Err(Error::new(ErrorKind::Other, format!("订单id和客户端id都为空,查询失败!order_id :{}, custom_id: {}", order_id, custom_id)));
-//         }
-//
-//         if res_data.code == 200 {
-//             // info!("order_detail {}", res_data.data);
-//             if res_data.data.is_array() {
-//                 let res_data_json = res_data.data.as_array().unwrap();
-//                 if res_data_json.len() == 0 { // 已取消或已成交
-//                     return Ok(Order{
-//                         id: order_id.to_string(),
-//                         custom_id: custom_id.to_string(),
-//                         price: Default::default(),
-//                         amount: Default::default(),
-//                         deal_amount: Default::default(),
-//                         avg_price: Default::default(),
-//                         status: "NULL".to_string(),
-//                         order_type: "".to_string(),
-//                         trace_stack: TraceStack::new(0, Instant::now()).on_special("358 coinex_swap".to_string()),
-//                     })
-//                 } else { // 待成交
-//                     let mut result = format_order_item(res_data_json[0].clone(), ct_val, status);
-//                     result.custom_id = custom_id.to_string();
-//                     result.id = order_id.to_string();
-//                     Ok(result)
-//                 }
-//             } else {
-//                 let mut result = format_order_item(res_data.data, ct_val, status);
-//                 result.custom_id = custom_id.to_string();
-//                 result.id = order_id.to_string();
-//                 Ok(result)
-//             }
-//         } else {
-//             Err(Error::new(ErrorKind::Other, res_data.to_string()))
-//         }
-//     }
-//
-//     // 获取未完成订单列表
-//     async fn get_orders_list(&mut self, status: &str) -> Result<Vec<Order>, Error> {
-//         let symbol = self.symbol.replace("_", "").to_uppercase();
-//         let ct_val = self.market.ct_val;
-//         let status_order;
-//         let res_data;
-//         if status == "pending" {
-//             res_data = self.request.get_pending_orders().await;
-//             status_order = "open";
-//         } else if status == "finish" {
-//             res_data = self.request.get_finished_orders().await;
-//             status_order = "filled";
-//         }else{
-//             return Err(Error::new(ErrorKind::Other, status));
-//         }
-//         if res_data.code == 200 {
-//             let res_data_json = res_data.data.as_array().unwrap();
-//             if res_data_json.len() ==0 {
-//                return Ok(vec![])
-//             }
-//             let order_info: Vec<_> = res_data_json.iter().filter(|item| item["market"].as_str().unwrap_or("") == symbol).collect();
-//             let result = order_info.iter().map(|&item| format_order_item(item.clone(), ct_val, status_order)).collect();
-//             Ok(result)
-//         } else {
-//             Err(Error::new(ErrorKind::Other, res_data.to_string()))
-//         }
-//     }
-//
-//     // 下单接口
-//     async fn take_order(&mut self, custom_id: &str, origin_side: &str, price: Decimal, amount: Decimal) -> Result<Order, Error> {
-//         let symbol = self.symbol.replace("_", "").to_uppercase();
-//         let ct_val = self.market.ct_val;
-//         let order_side;
-//         let position_side;
-//         let size = utils::truncate_decimal(amount, self.market.amount_precision.to_u32().unwrap());
-//         if size <= Decimal::ZERO {
-//             error!("下单数量异常 amount {} amount_precision {} size {}", amount, self.market.amount_precision.to_u32().unwrap(), size);
-//             return Err(Error::new(ErrorKind::Other, format!("下单数量错误 amount:{}", amount)));
-//         }
-//         match origin_side {
-//             "kd" => {
-//                 position_side = "long";
-//                 order_side = "buy";
-//             }
-//             "pd" => {
-//                 position_side = "long";
-//                 order_side = "sell";
-//             }
-//             "kk" => {
-//                 position_side = "short";
-//                 order_side = "sell";
-//             }
-//             "pk" => {
-//                 position_side = "short";
-//                 order_side = "buy";
-//             }
-//             _ => {
-//                 error!("下单参数错误");
-//                 position_side = "error";
-//                 order_side = "error";
-//             }
-//         };
-//         let res_data = self.request.order(symbol, position_side.to_string(), order_side.to_string(), size, price, custom_id.to_string()).await;
-//         if res_data.code == 200 {
-//             let res_data_json: Value = res_data.data;
-//             // info!("take_order {}", res_data_json);
-//             let result = format_order_item(res_data_json, ct_val, "open");
-//             Ok(result)
-//         } else {
-//             // error!("take_order error {}", res_data.data);
-//             Err(Error::new(ErrorKind::Other, res_data.to_string()))
-//         }
-//     }
-//
-//     async fn take_order_symbol(&mut self, symbol_y: String, ct_val: Decimal, custom_id: &str, origin_side: &str, price: Decimal, amount: Decimal) -> Result<Order, Error> {
-//         let symbol = symbol_y.replace("_", "").to_uppercase();
-//         let order_side;
-//         let position_side;
-//         let size = (amount / ct_val).floor();
-//         match origin_side {
-//             "kd" => {
-//                 position_side = "long";
-//                 order_side = "buy";
-//             }
-//             "pd" => {
-//                 position_side = "long";
-//                 order_side = "sell";
-//             }
-//             "kk" => {
-//                 position_side = "short";
-//                 order_side = "sell";
-//             }
-//             "pk" => {
-//                 position_side = "short";
-//                 order_side = "buy";
-//             }
-//             _ => {
-//                 error!("下单参数错误");
-//                 position_side = "error";
-//                 order_side = "error";
-//             }
-//         };
-//         let res_data = self.request.order(symbol, position_side.to_string(), order_side.to_string(), size, price, custom_id.to_string()).await;
-//         if res_data.code == 200 {
-//             let res_data_json: Value = res_data.data;
-//             let result = format_order_item(res_data_json, ct_val, "open");
-//             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> {
-//         let symbol = self.symbol.replace("_", "").to_uppercase();
-//
-//         let ct_val = self.market.ct_val;
-//         let res_data = self.request.cancel_order(symbol, order_id, custom_id).await;
-//         if res_data.code == 200 {
-//             let res_data_json: Value = res_data.data;
-//             let mut result;
-//             if res_data_json.is_null(){
-//                 result = Order{
-//                     id: custom_id.to_string(),
-//                     custom_id: order_id.to_string(),
-//                     price: Default::default(),
-//                     amount: Default::default(),
-//                     deal_amount: Default::default(),
-//                     avg_price: Default::default(),
-//                     status: "NULL".to_string(),
-//                     order_type: "".to_string(),
-//                     trace_stack:  TraceStack::new(0, Instant::now()).on_special("513 coinex_swap".to_string())
-//                 };
-//             } else {
-//                 result = format_order_item(res_data_json, ct_val, "canceled");
-//                 result.custom_id = custom_id.to_string();
-//                 result.id = order_id.to_string();
-//             }
-//             Ok(result)
-//         } else {
-//             let message = format!("撤单HTTP请求失败  order_id: {}, custom_id: {}, res_data: {:?}", order_id, custom_id, res_data);
-//             Err(Error::new(ErrorKind::Other, message))
-//         }
-//     }
-//     // 批量撤销订单
-//     async fn cancel_orders(&mut self) -> Result<Vec<Order>, Error> {
-//         let symbol = self.symbol.replace("_", "").to_uppercase();
-//         let res_data = self.request.cancel_order_all(symbol).await;
-//         if res_data.code == 200 {
-//             info!("{}", res_data.data.to_string());
-//             let result = vec![];
-//             Ok(result)
-//         } else {
-//             Err(Error::new(ErrorKind::Other, res_data.to_string()))
-//         }
-//     }
-//
-//     async fn cancel_orders_all(&mut self) -> Result<Vec<Order>, Error> {
-//         let orders_res_data = self.request.get_pending_orders().await;
-//         if orders_res_data.code == 200 {
-//             let result = vec![];
-//             let orders_res_data_json = orders_res_data.data.as_array().unwrap();
-//             for order in orders_res_data_json {
-//                 let cancel_res_data = self.request.cancel_order_all( order["market"].as_str().unwrap().to_string()).await;
-//                 if cancel_res_data.code != 200 {
-//                     return Err(Error::new(ErrorKind::Other, cancel_res_data.to_string()));
-//                 }
-//             }
-//             Ok(result)
-//         } else {
-//             Err(Error::new(ErrorKind::Other, orders_res_data.to_string()))
-//         }
-//     }
-//
-//     async fn take_stop_loss_order(&mut self, _stop_price: Decimal, _price: Decimal, _side: &str) -> Result<Value, Error> {
-//         Err(Error::new(ErrorKind::NotFound, "coin_ex:该交易所暂未实现自动订单下单".to_string()))
-//     }
-//
-//     async fn cancel_stop_loss_order(&mut self, _order_id: &str) -> Result<Value, Error> {
-//         Err(Error::new(ErrorKind::NotFound, "coin_ex:该交易所暂未实现取消自动订单".to_string()))
-//     }
-//
-//     // 设置持仓模式
-//     async fn set_dual_mode(&mut self, _coin: &str, _is_dual_mode: bool) -> Result<String, Error> {
-//         Err(Error::new(ErrorKind::NotFound, "coin_ex:该交易所只允许单向持仓,无法设置持仓模式".to_string()))
-//     }
-//
-//     // 更新杠杆
-//     async fn set_dual_leverage(&mut self, leverage: &str) -> Result<String, Error> {
-//         let leverage_int = leverage.parse::<i32>().unwrap();
-//         let symbol = self.symbol.replace("_", "").to_uppercase();
-//         let res_data = self.request.setting_dual_leverage(symbol, leverage_int).await;
-//         if res_data.code == 200 {
-//             let res_data_str = &res_data.data;
-//             let result = res_data_str.clone();
-//             Ok(result.to_string())
-//         } else {
-//             Err(Error::new(ErrorKind::Other, res_data.to_string()))
-//         }
-//     }
-//
-//     async fn set_auto_deposit_status(&mut self, _status: bool) -> Result<String, Error> { Err(Error::new(ErrorKind::NotFound, "Coinex:该交易所方法未实现".to_string())) }
-//
-//     async fn wallet_transfers(&mut self, _coin: &str, _from: &str, _to: &str, _amount: Decimal) -> Result<String, Error> {
-//         Err(Error::new(ErrorKind::NotFound, "Coinex wallet_transfers:该交易所方法未实现".to_string()))
-//     }
-//
-//     // 指令下单
-//     async fn command_order(&mut self, order_command: &mut OrderCommand, trace_stack: &TraceStack) {
-//         let mut handles = vec![];
-//
-//         // 下单指令
-//         for item in order_command.limits_open.keys() {
-//             let mut ts = trace_stack.clone();
-//
-//             let amount = Decimal::from_str(&*order_command.limits_open[item].get(0).unwrap().clone()).unwrap();
-//             let side = order_command.limits_open[item].get(1).unwrap().clone();
-//             let price = Decimal::from_str(&*order_command.limits_open[item].get(2).unwrap().clone()).unwrap();
-//             let cid = order_command.limits_open[item].get(3).unwrap().clone();
-//
-//             //  order_name: [数量,方向,价格,c_id]
-//             let mut self_clone = self.clone();
-//             let handle = spawn(async move {
-//                 // info!("数量 {},方向 {},价格 {},c_id {}", amount, side, price, cid);
-//                 ts.on_before_send();
-//                 let result = self_clone.take_order(&cid, &side, price, amount).await;
-//                 ts.on_after_send();
-//
-//                 match result {
-//                     Ok(mut result) => {
-//                         result.trace_stack = ts;
-//                         // info!("数量 {},方向 {},价格 {},c_id {}", amount, side, price, cid);
-//                         self_clone.order_sender.send(result).await.unwrap();
-//                     }
-//                     Err(error) => {
-//                         let mut err_order = Order::new();
-//                         err_order.custom_id = cid.clone();
-//                         err_order.status = "REMOVE".to_string();
-//                         // info!("coinex下单error 数量: {},方向: {},价格: {},c_id: {}, err: {}", amount, side, price, cid, error);
-//                         self_clone.order_sender.send(err_order).await.unwrap();
-//                         self_clone.error_sender.send(error).await.unwrap();
-//                         // 触发限频
-//                         // if error_info.to_string().contains("213:Please don't try too frequently") {
-//                         //     Err(Error::new(ErrorKind::Other, "触发限频, 请调整下单频率"))
-//                         // }
-//                     }
-//                 }
-//             });
-//             handles.push(handle)
-//         }
-//         let futures = FuturesUnordered::from_iter(handles);
-//         // 等待所有任务完成
-//         let _: Result<Vec<_>, _> = futures.try_collect().await;
-//
-//         // 撤销订单
-//         let mut cancel_handlers = vec![];
-//         for item in order_command.cancel.keys() {
-//             let order_id = order_command.cancel[item].get(1).unwrap().clone();
-//             let custom_id = order_command.cancel[item].get(0).unwrap().clone();
-//
-//             let mut self_clone = self.clone();
-//             let handle = spawn(async move {
-//                 let result = self_clone.cancel_order(&order_id, &custom_id).await;
-//                 match result {
-//                     Ok(order) => {
-//                         if order.status == "REMOVE" {
-//                             // 由于有时撤单成功ws不推送,所以加入rest
-//                             self_clone.order_sender.send(order).await.unwrap();
-//                         }
-//                     }
-//                     Err(error) => {
-//                         // info!("撤单失败:{:?}", error.to_string());
-//                         // 取消失败去查订单。
-//                         let query_rst = self_clone.get_order_detail(&order_id, &custom_id).await;
-//                         match query_rst {
-//                             Ok(order) => {
-//                                 // info!("查单 订单详情:{:?}", order);
-//                                 self_clone.order_sender.send(order).await.unwrap();
-//                             }
-//                             Err(_err) => {
-//                                 // warn!("撤单失败,而且查单也失败了,Coinex_io_swap,oid={}, cid={} err={:?}", order_id.clone(), custom_id.clone(), err);
-//                                 // panic!("撤单失败,而且查单也失败了,Coinex_io_swap,oid={}, cid={}。", order_id.clone(), custom_id.clone());
-//                             }
-//                         }
-//                         self_clone.error_sender.send(error).await.unwrap();
-//                     }
-//                 }
-//             });
-//             cancel_handlers.push(handle)
-//         }
-//         let futures = FuturesUnordered::from_iter(cancel_handlers);
-//         // 等待所有任务完成
-//         let _: Result<Vec<_>, _> = futures.try_collect().await;
-//
-//         // 检查订单指令
-//         let mut check_handlers = vec![];
-//         for item in order_command.check.keys() {
-//             let order_id = order_command.check[item].get(1).unwrap().clone();
-//             let custom_id = order_command.check[item].get(0).unwrap().clone();
-//
-//             let mut self_clone = self.clone();
-//             let handle = spawn(async move {
-//                 let result = self_clone.get_order_detail(&order_id, &custom_id).await;
-//                 match result {
-//                     Ok(result) => {
-//                         self_clone.order_sender.send(result).await.unwrap();
-//                     }
-//                     Err(error) => {
-//                         self_clone.error_sender.send(error).await.unwrap();
-//                     }
-//                 }
-//             });
-//             check_handlers.push(handle)
-//         }
-//
-//         let futures = FuturesUnordered::from_iter(check_handlers);
-//         // 等待所有任务完成
-//         let _: Result<Vec<_>, _> = futures.try_collect().await;
-//     }
-// }
-//
-// pub fn format_position_item(position: &Value, ct_val: Decimal) -> Position {
-//     let position_mode = match position["side"].as_str().unwrap_or("") {
-//         "long" => PositionModeEnum::Long,
-//         "short" => PositionModeEnum::Short,
-//         _ => {
-//             error!("coinex_swap:格式化持仓模式错误!\nformat_position_item:position={:?}", position);
-//             panic!("coinex_swap:格式化持仓模式错误!\nformat_position_item:position={:?}", position)
-//         }
-//     };
-//     let size = Decimal::from_str(&position["open_interest"].as_str().unwrap()).unwrap();
-//     let amount = size * ct_val;
-//     Position {
-//         symbol: position["market"].as_str().unwrap_or("").parse().unwrap(),
-//         margin_level: Decimal::from_str(position["leverage"].as_str().unwrap()).unwrap(),
-//         amount,
-//         frozen_amount: Decimal::ZERO,
-//         price: Decimal::from_str(position["avg_entry_price"].as_str().unwrap()).unwrap(),
-//         profit: Decimal::from_str(position["unrealized_pnl"].as_str().unwrap()).unwrap(),
-//         position_mode,
-//         margin: Decimal::from_str(position["ath_margin_size"].as_str().unwrap()).unwrap(),
-//     }
-// }
-//
-// pub fn format_order_item(order: Value, ct_val: Decimal, status: &str) -> Order {
-//     // info!("order_format {}", order);
-//     let size;
-//     match order["amount"].as_str() {
-//         Some(val) => {
-//             size = Decimal::from_str(val).unwrap()
-//         },
-//         None => {
-//             error!("coinex_swap:格式化订单大小错误!\nformat_order_item:order={:?} status={}", order, status);
-//             panic!("coinex_swap:格式化订单大小失败,退出程序!");
-//         }
-//     }
-//     // info!("order {}", order);
-//     // 通过客户端id查询订单 只能查出未完成订单(没有状态字段)
-//     let status = order["status"].as_str().unwrap_or(status);
-//     let text = order["client_id"].as_str().unwrap_or("");
-//
-//     let deal_amount = Decimal::from_str(&order["filled_amount"].as_str().unwrap()).unwrap();
-//     let filled_value = Decimal::from_str(&order["filled_value"].as_str().unwrap()).unwrap();
-//
-//     let amount = size * ct_val;
-//     let mut avg_price = Decimal::ZERO;
-//     if deal_amount != Decimal::ZERO{
-//         avg_price = filled_value/deal_amount;
-//     }
-//     let custom_status = if status == "filled" || status == "canceled" {
-//         "REMOVE".to_string()
-//     } else if status == "open" || status == "part_filled" || status == "part_canceled" {
-//         "NEW".to_string()
-//     } else {
-//         error!("coinex_swap:格式化订单状态错误!\nformat_order_item:order={:?}", order);
-//         "NULL".to_string()
-//     };
-//     let rst_order = Order {
-//         id: order["order_id"].to_string(),
-//         custom_id: text.to_string(),
-//         price: Decimal::from_str(order["price"].as_str().unwrap()).unwrap(),
-//         amount,
-//         deal_amount,
-//         avg_price,
-//         status: custom_status,
-//         order_type: "limit".to_string(),
-//         trace_stack: TraceStack::new(0, Instant::now()).on_special("765 trace_stack".to_string()),
-//     };
-//     return rst_order;
-// }
+use std::collections::{BTreeMap};
+use std::io::{Error, ErrorKind};
+use std::str::FromStr;
+use tokio::sync::mpsc::Sender;
+use async_trait::async_trait;
+use futures::stream::FuturesUnordered;
+use futures::TryStreamExt;
+use rust_decimal::Decimal;
+use rust_decimal::prelude::{FromPrimitive, ToPrimitive};
+use serde_json::{Value};
+use tokio::spawn;
+use tokio::time::Instant;
+use tracing::{error, info, trace};
+use exchanges::coinex_swap_rest::CoinexSwapRest;
+use crate::{Platform, ExchangeEnum, Account, Position, Ticker, Market, Order, OrderCommand, PositionModeEnum, utils};
+use global::trace_stack::TraceStack;
+use crate::utils::get_tick_size;
+
+#[allow(dead_code)]
+#[derive(Clone)]
+pub struct CoinexSwap {
+    exchange: ExchangeEnum,
+    symbol: String,
+    is_colo: bool,
+    params: BTreeMap<String, String>,
+    request: CoinexSwapRest,
+    market: Market,
+    order_sender: Sender<Order>,
+    error_sender: Sender<Error>,
+}
+
+impl CoinexSwap {
+    pub async fn new(symbol: String, is_colo: bool, params: BTreeMap<String, String>, order_sender: Sender<Order>, error_sender: Sender<Error>) -> CoinexSwap {
+        let market = Market::new();
+        let mut coinex_swap = CoinexSwap {
+            exchange: ExchangeEnum::CoinexSwap,
+            symbol: symbol.to_uppercase(),
+            is_colo,
+            params: params.clone(),
+            request: CoinexSwapRest::new(params.clone()),
+            market,
+            order_sender,
+            error_sender,
+        };
+
+        // 修改持仓模式
+        let symbol_array: Vec<&str> = symbol.split("_").collect();
+        let mode_result = coinex_swap.set_dual_mode(symbol_array[1], true).await;
+        match mode_result {
+            Ok(_) => {
+                trace!("Coinex:设置持仓模式成功!")
+            }
+            Err(error) => {
+                error!("Coinex:设置持仓模式失败!mode_result={}", error)
+            }
+        }
+        // 获取市场信息
+        coinex_swap.market = CoinexSwap::get_market(&mut coinex_swap).await.unwrap_or(coinex_swap.market);
+        // 设置持仓杠杆
+        let lever_rate_result = coinex_swap.set_dual_leverage("10").await;
+        match lever_rate_result {
+            Ok(ok) => {
+                info!("Coinex:设置持仓杠杆成功!{:?}", ok);
+            }
+            Err(error) => {
+                error!("Coinex:设置持仓杠杆失败!{:?}", error)
+            }
+        }
+        return coinex_swap;
+    }
+}
+
+#[async_trait]
+impl Platform for CoinexSwap {
+    // 克隆方法
+    fn clone_box(&self) -> Box<dyn Platform + Send + Sync> { Box::new(self.clone()) }
+    // 获取交易所模式
+    fn get_self_exchange(&self) -> ExchangeEnum {
+        ExchangeEnum::CoinexSwap
+    }
+    // 获取交易对
+    fn get_self_symbol(&self) -> String { self.symbol.clone() }
+    // 获取是否使用高速通道
+    fn get_self_is_colo(&self) -> bool {
+        self.is_colo
+    }
+    // 获取params信息
+    fn get_self_params(&self) -> BTreeMap<String, String> {
+        self.params.clone()
+    }
+    // 获取market信息
+    fn get_self_market(&self) -> Market { self.market.clone() }
+    // 获取请求时间
+    fn get_request_delays(&self) -> Vec<i64> { self.request.get_delays() }
+    // 获取请求平均时间
+    fn get_request_avg_delay(&self) -> Decimal { self.request.get_avg_delay() }
+    // 获取请求最大时间
+    fn get_request_max_delay(&self) -> i64 { self.request.get_max_delay() }
+
+    // 获取服务器时间
+    async fn get_server_time(&mut self) -> Result<String, Error> {
+        let res_data = self.request.get_server_time().await;
+        if res_data.code == 200 {
+            let res_data_json: Value = res_data.data;
+            let result = res_data_json["timestamp"].to_string();
+            Ok(result)
+        } else {
+            Err(Error::new(ErrorKind::Other, res_data.to_string()))
+        }
+    }
+    // 获取账号信息
+    async fn get_account(&mut self) -> Result<Account, Error> {
+        let symbol_array: Vec<&str> = self.symbol.split("_").collect();
+        let coin = symbol_array[1].to_string().to_uppercase();
+        let res_data = self.request.get_account().await;
+        if res_data.code == 200 {
+            if res_data.data.is_array() {
+                let res_data_array = res_data.data.as_array().unwrap();
+                for res_data_json in res_data_array.iter() {
+                    if res_data_json["ccy"].as_str().unwrap() == coin {
+                        let frozen_balance= Decimal::from_str(res_data_json["frozen"].as_str().unwrap()).unwrap();
+                        let available_balance = Decimal::from_str(res_data_json["available"].as_str().unwrap()).unwrap();
+                        let balance = frozen_balance + available_balance;
+                        let result = Account {
+                            coin: symbol_array[1].to_string(),
+                            balance,
+                            available_balance,
+                            frozen_balance,
+                            stocks: Decimal::ZERO,
+                            available_stocks: Decimal::ZERO,
+                            frozen_stocks: Decimal::ZERO,
+                        };
+                        return Ok(result);
+                    }
+                }
+            }
+        }
+        Err(Error::new(ErrorKind::Other, res_data.to_string()))
+    }
+
+    async fn get_spot_account(&mut self) -> Result<Vec<Account>, Error> {
+        Err(Error::new(ErrorKind::NotFound, "coinex_swap:该方法暂未实现".to_string()))
+    }
+
+    // 获取持仓信息
+    async fn get_position(&mut self) -> Result<Vec<Position>, Error> {
+        let symbol: String = self.symbol.replace("_", "").to_uppercase();
+        let ct_val = self.market.multiplier;
+        let res_data = self.request.get_position(symbol).await;
+        if res_data.code == 200 {
+            let res_data_json = res_data.data.as_array().unwrap();
+            let result = res_data_json.iter().map(|item| { format_position_item(item, ct_val) }).collect();
+            Ok(result)
+        } else {
+            Err(Error::new(ErrorKind::Other, res_data.to_string()))
+        }
+    }
+
+    // 获取所有持仓
+    async fn get_positions(&mut self) -> Result<Vec<Position>, Error> {
+        let res_data = self.request.get_user_position().await;
+        if res_data.code == 200 {
+            info!("{}", res_data.data.to_string());
+            let res_data_json = res_data.data.as_array().unwrap();
+            let result = res_data_json.iter().map(|item| { format_position_item(item, Decimal::ONE) }).collect();
+            Ok(result)
+        } else {
+            Err(Error::new(ErrorKind::Other, res_data.to_string()))
+        }
+    }
+    // 获取市场行情
+    async fn get_ticker(&mut self) -> Result<Ticker, Error> {
+        let symbol: String = self.symbol.replace("_", "");
+        let res_data = self.request.get_ticker(symbol.clone()).await;
+        if res_data.code == 200 {
+            let res_data_json = res_data.data.as_array().unwrap();
+            let ticker_info = res_data_json.iter().find(|item| item["market"].as_str().unwrap() == symbol);
+            match ticker_info {
+                None => {
+                    error!("coinex_swap:获取Ticker信息错误!\nget_ticker:res_data={:?}", res_data);
+                    Err(Error::new(ErrorKind::Other, res_data.to_string()))
+                }
+                Some(value) => {
+                    let result = Ticker {
+                        time: chrono::Utc::now().timestamp_millis(),
+                        high: Decimal::from_str(value["high"].as_str().unwrap()).unwrap(),
+                        low: Decimal::from_str(value["low"].as_str().unwrap()).unwrap(),
+                        sell: Decimal::from_str(value["last"].as_str().unwrap()).unwrap(),
+                        buy: Decimal::from_str(value["last"].as_str().unwrap()).unwrap(),
+                        last: Decimal::from_str(value["last"].as_str().unwrap()).unwrap(),
+                        volume: Decimal::from_str(value["volume"].as_str().unwrap()).unwrap(),
+                    };
+                    Ok(result)
+                }
+            }
+        } else {
+            Err(Error::new(ErrorKind::Other, res_data.to_string()))
+        }
+    }
+
+    async fn get_ticker_symbol(&mut self, symbol_param: String) -> Result<Ticker, Error> {
+        let symbol: String = symbol_param.replace("_", "").to_uppercase();
+        let res_data = self.request.get_ticker(symbol.clone()).await;
+        if res_data.code == 200 {
+            let res_data_json = res_data.data.as_array().unwrap();
+            let ticker_info = res_data_json.iter().find(|item| item["contract"].as_str().unwrap() == symbol);
+            match ticker_info {
+                None => {
+                    error!("coinex_swap:获取Ticker信息错误!\nget_ticker:res_data={:?}", res_data);
+                    Err(Error::new(ErrorKind::Other, res_data.to_string()))
+                }
+                Some(value) => {
+                    let result = Ticker {
+                        time: chrono::Utc::now().timestamp_millis(),
+                        high: Decimal::from_str(value["high"].as_str().unwrap()).unwrap(),
+                        low: Decimal::from_str(value["low"].as_str().unwrap()).unwrap(),
+                        sell: Decimal::from_str(value["last"].as_str().unwrap()).unwrap(),
+                        buy: Decimal::from_str(value["last"].as_str().unwrap()).unwrap(),
+                        last: Decimal::from_str(value["last"].as_str().unwrap()).unwrap(),
+                        volume: Decimal::from_str(value["volume"].as_str().unwrap()).unwrap(),
+                    };
+                    Ok(result)
+                }
+            }
+        } else {
+            Err(Error::new(ErrorKind::Other, res_data.to_string()))
+        }
+    }
+
+    async fn get_market(&mut self) -> Result<Market, Error> {
+        let symbol_array: Vec<&str> = self.symbol.split("_").collect();
+        let symbol = format!("{}{}", symbol_array[0], symbol_array[1]);
+        let res_data = self.request.get_market_details(symbol.clone()).await;
+        if res_data.code == 200 {
+            let res_data_json = res_data.data.as_array().unwrap();
+            let market_info = res_data_json.iter().find(|item| item["market"].as_str().unwrap() == symbol);
+            match market_info {
+                None => {
+                    error!("coinex_swap:获取Market信息错误!\nget_market:res_data={:?}", res_data);
+                    Err(Error::new(ErrorKind::Other, res_data.to_string()))
+                }
+                Some(value) => {
+                    // 报价精度字符串
+                    let price_precision_i64 = value["quote_ccy_precision"].as_i64().unwrap();
+                    // 价格最小变动数值
+                    let tick_size = get_tick_size(price_precision_i64.to_u32().unwrap());
+                    // 报价精度
+                    let price_precision = Decimal::from_i64(price_precision_i64).unwrap();
+                    // 最小数量
+                    let min_qty = Decimal::from_str(value["min_amount"].as_str().unwrap()).unwrap();
+                    // 数量没有最大值
+                    let max_qty = Decimal::MAX;
+                    // 没有张数
+                    let multiplier = Decimal::ONE;
+
+                    let amount_size = min_qty * multiplier;
+                    let amount_precision = Decimal::from_u32(amount_size.scale()).unwrap();
+                    let min_notional = min_qty * multiplier;
+                    let max_notional = max_qty * multiplier;
+
+                    let result = Market {
+                        symbol: self.symbol.clone(),
+                        base_asset: symbol_array[0].to_string(),
+                        quote_asset: symbol_array[1].to_string(),
+                        tick_size,
+                        amount_size,
+                        price_precision,
+                        amount_precision,
+                        min_qty,
+                        max_qty,
+                        min_notional,
+                        max_notional,
+                        multiplier,
+                    };
+                    Ok(result)
+                }
+            }
+        } else {
+            Err(Error::new(ErrorKind::Other, res_data.to_string()))
+        }
+    }
+
+    async fn get_market_symbol(&mut self, symbol: String) -> Result<Market, Error> {
+        let symbol_upper = symbol.to_uppercase();
+        let symbol_array: Vec<&str> = symbol_upper.split("_").collect();
+        let symbol = format!("{}{}", symbol_array[0], symbol_array[1]);
+        let res_data = self.request.get_market_details(symbol.clone()).await;
+        if res_data.code == 200 {
+            let res_data_json = res_data.data.as_array().unwrap();
+            let market_info = res_data_json.iter().find(|item| item["name"].as_str().unwrap() == symbol.clone());
+            match market_info {
+                None => {
+                    error!("coinex_swap:获取Market信息错误!\nget_market:res_data={:?}", res_data);
+                    Err(Error::new(ErrorKind::Other, res_data.to_string()))
+                }
+                Some(value) => {
+                    let tick_size = Decimal::from_str(value["quote_ccy_precision"].as_str().unwrap()).unwrap();
+                    let min_qty = Decimal::from_str(&value["min_amount"].to_string()).unwrap();
+                    // 数量没有最大值
+                    let max_qty = Decimal::MAX;
+                    // 没有张数
+                    let multiplier = Decimal::ONE;
+
+                    let amount_size = min_qty * multiplier;
+                    let price_precision = Decimal::from_u32(tick_size.scale()).unwrap();
+                    let amount_precision = Decimal::from_u32(amount_size.scale()).unwrap();
+                    let min_notional = min_qty * multiplier;
+                    let max_notional = max_qty * multiplier;
+
+                    let result = Market {
+                        symbol: self.symbol.clone(),
+                        base_asset: symbol_array[0].to_string(),
+                        quote_asset: symbol_array[1].to_string(),
+                        tick_size,
+                        amount_size,
+                        price_precision,
+                        amount_precision,
+                        min_qty,
+                        max_qty,
+                        min_notional,
+                        max_notional,
+                        multiplier,
+                    };
+                    Ok(result)
+                }
+            }
+        } else {
+            Err(Error::new(ErrorKind::Other, res_data.to_string()))
+        }
+    }
+
+    // 获取订单详情
+    async fn get_order_detail(&mut self, order_id: &str, custom_id: &str) -> Result<Order, Error> {
+        let symbol = self.symbol.replace("_", "").to_uppercase();
+        let multiplier = self.market.multiplier;
+        let res_data;
+        let status ;
+        if order_id != "" {
+            status = "";
+            res_data = self.request.get_order_details(order_id.to_string(), symbol).await;
+        } else if custom_id != "" {
+            // 通过客户端id查询  只有未完成的订单才能查询出来
+            res_data = self.request.get_pending_order(custom_id.to_string()).await;
+            status = "open";
+        } else {
+            return Err(Error::new(ErrorKind::Other, format!("订单id和客户端id都为空,查询失败!order_id :{}, custom_id: {}", order_id, custom_id)));
+        }
+
+        if res_data.code == 200 {
+            // info!("order_detail {}", res_data.data);
+            if res_data.data.is_array() {
+                let res_data_json = res_data.data.as_array().unwrap();
+                if res_data_json.len() == 0 { // 已取消或已成交
+                    return Ok(Order{
+                        id: order_id.to_string(),
+                        custom_id: custom_id.to_string(),
+                        price: Default::default(),
+                        amount: Default::default(),
+                        deal_amount: Default::default(),
+                        avg_price: Default::default(),
+                        status: "NULL".to_string(),
+                        order_type: "".to_string(),
+                        trace_stack: TraceStack::new(0, Instant::now()).on_special("358 coinex_swap".to_string()),
+                    })
+                } else { // 待成交
+                    let mut result = format_order_item(res_data_json[0].clone(), multiplier, status);
+                    result.custom_id = custom_id.to_string();
+                    result.id = order_id.to_string();
+                    Ok(result)
+                }
+            } else {
+                let mut result = format_order_item(res_data.data, multiplier, status);
+                result.custom_id = custom_id.to_string();
+                result.id = order_id.to_string();
+                Ok(result)
+            }
+        } else {
+            Err(Error::new(ErrorKind::Other, res_data.to_string()))
+        }
+    }
+
+    // 获取未完成订单列表
+    async fn get_orders_list(&mut self, status: &str) -> Result<Vec<Order>, Error> {
+        let symbol = self.symbol.replace("_", "").to_uppercase();
+        let multiplier = self.market.multiplier;
+        let status_order;
+        let res_data;
+        if status == "pending" {
+            res_data = self.request.get_pending_orders().await;
+            status_order = "open";
+        } else if status == "finish" {
+            res_data = self.request.get_finished_orders().await;
+            status_order = "filled";
+        }else{
+            return Err(Error::new(ErrorKind::Other, status));
+        }
+        if res_data.code == 200 {
+            let res_data_json = res_data.data.as_array().unwrap();
+            if res_data_json.len() ==0 {
+               return Ok(vec![])
+            }
+            let order_info: Vec<_> = res_data_json.iter().filter(|item| item["market"].as_str().unwrap_or("") == symbol).collect();
+            let result = order_info.iter().map(|&item| format_order_item(item.clone(), multiplier, status_order)).collect();
+            Ok(result)
+        } else {
+            Err(Error::new(ErrorKind::Other, res_data.to_string()))
+        }
+    }
+
+    // 下单接口
+    async fn take_order(&mut self, custom_id: &str, origin_side: &str, price: Decimal, amount: Decimal) -> Result<Order, Error> {
+        let symbol = self.symbol.replace("_", "").to_uppercase();
+        let multiplier = self.market.multiplier;
+        let order_side;
+        let position_side;
+        let size = utils::truncate_decimal(amount, self.market.amount_precision.to_u32().unwrap());
+        if size <= Decimal::ZERO {
+            error!("下单数量异常 amount {} amount_precision {} size {}", amount, self.market.amount_precision.to_u32().unwrap(), size);
+            return Err(Error::new(ErrorKind::Other, format!("下单数量错误 amount:{}", amount)));
+        }
+        match origin_side {
+            "kd" => {
+                position_side = "long";
+                order_side = "buy";
+            }
+            "pd" => {
+                position_side = "long";
+                order_side = "sell";
+            }
+            "kk" => {
+                position_side = "short";
+                order_side = "sell";
+            }
+            "pk" => {
+                position_side = "short";
+                order_side = "buy";
+            }
+            _ => {
+                error!("下单参数错误");
+                position_side = "error";
+                order_side = "error";
+            }
+        };
+        let res_data = self.request.order(symbol, position_side.to_string(), order_side.to_string(), size, price, custom_id.to_string()).await;
+        if res_data.code == 200 {
+            let res_data_json: Value = res_data.data;
+            // info!("take_order {}", res_data_json);
+            let result = format_order_item(res_data_json, multiplier, "open");
+            Ok(result)
+        } else {
+            // error!("take_order error {}", res_data.data);
+            Err(Error::new(ErrorKind::Other, res_data.to_string()))
+        }
+    }
+
+    async fn take_order_symbol(&mut self, symbol_y: String, ct_val: Decimal, custom_id: &str, origin_side: &str, price: Decimal, amount: Decimal) -> Result<Order, Error> {
+        let symbol = symbol_y.replace("_", "").to_uppercase();
+        let order_side;
+        let position_side;
+        let size = (amount / ct_val).floor();
+        match origin_side {
+            "kd" => {
+                position_side = "long";
+                order_side = "buy";
+            }
+            "pd" => {
+                position_side = "long";
+                order_side = "sell";
+            }
+            "kk" => {
+                position_side = "short";
+                order_side = "sell";
+            }
+            "pk" => {
+                position_side = "short";
+                order_side = "buy";
+            }
+            _ => {
+                error!("下单参数错误");
+                position_side = "error";
+                order_side = "error";
+            }
+        };
+        let res_data = self.request.order(symbol, position_side.to_string(), order_side.to_string(), size, price, custom_id.to_string()).await;
+        if res_data.code == 200 {
+            let res_data_json: Value = res_data.data;
+            let result = format_order_item(res_data_json, ct_val, "open");
+            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> {
+        let symbol = self.symbol.replace("_", "").to_uppercase();
+
+        let multiplier = self.market.multiplier;
+        let res_data = self.request.cancel_order(symbol, order_id, custom_id).await;
+        if res_data.code == 200 {
+            let res_data_json: Value = res_data.data;
+            let mut result;
+            if res_data_json.is_null(){
+                result = Order{
+                    id: custom_id.to_string(),
+                    custom_id: order_id.to_string(),
+                    price: Default::default(),
+                    amount: Default::default(),
+                    deal_amount: Default::default(),
+                    avg_price: Default::default(),
+                    status: "NULL".to_string(),
+                    order_type: "".to_string(),
+                    trace_stack:  TraceStack::new(0, Instant::now()).on_special("513 coinex_swap".to_string())
+                };
+            } else {
+                result = format_order_item(res_data_json, multiplier, "canceled");
+                result.custom_id = custom_id.to_string();
+                result.id = order_id.to_string();
+            }
+            Ok(result)
+        } else {
+            let message = format!("撤单HTTP请求失败  order_id: {}, custom_id: {}, res_data: {:?}", order_id, custom_id, res_data);
+            Err(Error::new(ErrorKind::Other, message))
+        }
+    }
+    // 批量撤销订单
+    async fn cancel_orders(&mut self) -> Result<Vec<Order>, Error> {
+        let symbol = self.symbol.replace("_", "").to_uppercase();
+        let res_data = self.request.cancel_order_all(symbol).await;
+        if res_data.code == 200 {
+            info!("{}", res_data.data.to_string());
+            let result = vec![];
+            Ok(result)
+        } else {
+            Err(Error::new(ErrorKind::Other, res_data.to_string()))
+        }
+    }
+
+    async fn cancel_orders_all(&mut self) -> Result<Vec<Order>, Error> {
+        let orders_res_data = self.request.get_pending_orders().await;
+        if orders_res_data.code == 200 {
+            let result = vec![];
+            let orders_res_data_json = orders_res_data.data.as_array().unwrap();
+            for order in orders_res_data_json {
+                let cancel_res_data = self.request.cancel_order_all( order["market"].as_str().unwrap().to_string()).await;
+                if cancel_res_data.code != 200 {
+                    return Err(Error::new(ErrorKind::Other, cancel_res_data.to_string()));
+                }
+            }
+            Ok(result)
+        } else {
+            Err(Error::new(ErrorKind::Other, orders_res_data.to_string()))
+        }
+    }
+
+    async fn take_stop_loss_order(&mut self, _stop_price: Decimal, _price: Decimal, _side: &str) -> Result<Value, Error> {
+        Err(Error::new(ErrorKind::NotFound, "coin_ex:该交易所暂未实现自动订单下单".to_string()))
+    }
+
+    async fn cancel_stop_loss_order(&mut self, _order_id: &str) -> Result<Value, Error> {
+        Err(Error::new(ErrorKind::NotFound, "coin_ex:该交易所暂未实现取消自动订单".to_string()))
+    }
+
+    // 设置持仓模式
+    async fn set_dual_mode(&mut self, _coin: &str, _is_dual_mode: bool) -> Result<String, Error> {
+        Err(Error::new(ErrorKind::NotFound, "coin_ex:该交易所只允许单向持仓,无法设置持仓模式".to_string()))
+    }
+
+    // 更新杠杆
+    async fn set_dual_leverage(&mut self, leverage: &str) -> Result<String, Error> {
+        let leverage_int = leverage.parse::<i32>().unwrap();
+        let symbol = self.symbol.replace("_", "").to_uppercase();
+        let res_data = self.request.setting_dual_leverage(symbol, leverage_int).await;
+        if res_data.code == 200 {
+            let res_data_str = &res_data.data;
+            let result = res_data_str.clone();
+            Ok(result.to_string())
+        } else {
+            Err(Error::new(ErrorKind::Other, res_data.to_string()))
+        }
+    }
+
+    async fn set_auto_deposit_status(&mut self, _status: bool) -> Result<String, Error> { Err(Error::new(ErrorKind::NotFound, "Coinex:该交易所方法未实现".to_string())) }
+
+    async fn wallet_transfers(&mut self, _coin: &str, _from: &str, _to: &str, _amount: Decimal) -> Result<String, Error> {
+        Err(Error::new(ErrorKind::NotFound, "Coinex wallet_transfers:该交易所方法未实现".to_string()))
+    }
+
+    // 指令下单
+    async fn command_order(&mut self, order_command: &mut OrderCommand, trace_stack: &TraceStack) {
+        let mut handles = vec![];
+
+        // 下单指令
+        for item in order_command.limits_open.keys() {
+            let mut ts = trace_stack.clone();
+
+            let amount = Decimal::from_str(&*order_command.limits_open[item].get(0).unwrap().clone()).unwrap();
+            let side = order_command.limits_open[item].get(1).unwrap().clone();
+            let price = Decimal::from_str(&*order_command.limits_open[item].get(2).unwrap().clone()).unwrap();
+            let cid = order_command.limits_open[item].get(3).unwrap().clone();
+
+            //  order_name: [数量,方向,价格,c_id]
+            let mut self_clone = self.clone();
+            let handle = spawn(async move {
+                // info!("数量 {},方向 {},价格 {},c_id {}", amount, side, price, cid);
+                ts.on_before_send();
+                let result = self_clone.take_order(&cid, &side, price, amount).await;
+                ts.on_after_send();
+
+                match result {
+                    Ok(mut result) => {
+                        result.trace_stack = ts;
+                        // info!("数量 {},方向 {},价格 {},c_id {}", amount, side, price, cid);
+                        self_clone.order_sender.send(result).await.unwrap();
+                    }
+                    Err(error) => {
+                        let mut err_order = Order::new();
+                        err_order.custom_id = cid.clone();
+                        err_order.status = "REMOVE".to_string();
+                        // info!("coinex下单error 数量: {},方向: {},价格: {},c_id: {}, err: {}", amount, side, price, cid, error);
+                        self_clone.order_sender.send(err_order).await.unwrap();
+                        self_clone.error_sender.send(error).await.unwrap();
+                        // 触发限频
+                        // if error_info.to_string().contains("213:Please don't try too frequently") {
+                        //     Err(Error::new(ErrorKind::Other, "触发限频, 请调整下单频率"))
+                        // }
+                    }
+                }
+            });
+            handles.push(handle)
+        }
+        let futures = FuturesUnordered::from_iter(handles);
+        // 等待所有任务完成
+        let _: Result<Vec<_>, _> = futures.try_collect().await;
+
+        // 撤销订单
+        let mut cancel_handlers = vec![];
+        for item in order_command.cancel.keys() {
+            let order_id = order_command.cancel[item].get(1).unwrap().clone();
+            let custom_id = order_command.cancel[item].get(0).unwrap().clone();
+
+            let mut self_clone = self.clone();
+            let handle = spawn(async move {
+                let result = self_clone.cancel_order(&order_id, &custom_id).await;
+                match result {
+                    Ok(order) => {
+                        if order.status == "REMOVE" {
+                            // 由于有时撤单成功ws不推送,所以加入rest
+                            self_clone.order_sender.send(order).await.unwrap();
+                        }
+                    }
+                    Err(error) => {
+                        // info!("撤单失败:{:?}", error.to_string());
+                        // 取消失败去查订单。
+                        let query_rst = self_clone.get_order_detail(&order_id, &custom_id).await;
+                        match query_rst {
+                            Ok(order) => {
+                                // info!("查单 订单详情:{:?}", order);
+                                self_clone.order_sender.send(order).await.unwrap();
+                            }
+                            Err(_err) => {
+                                // warn!("撤单失败,而且查单也失败了,Coinex_io_swap,oid={}, cid={} err={:?}", order_id.clone(), custom_id.clone(), err);
+                                // panic!("撤单失败,而且查单也失败了,Coinex_io_swap,oid={}, cid={}。", order_id.clone(), custom_id.clone());
+                            }
+                        }
+                        self_clone.error_sender.send(error).await.unwrap();
+                    }
+                }
+            });
+            cancel_handlers.push(handle)
+        }
+        let futures = FuturesUnordered::from_iter(cancel_handlers);
+        // 等待所有任务完成
+        let _: Result<Vec<_>, _> = futures.try_collect().await;
+
+        // 检查订单指令
+        let mut check_handlers = vec![];
+        for item in order_command.check.keys() {
+            let order_id = order_command.check[item].get(1).unwrap().clone();
+            let custom_id = order_command.check[item].get(0).unwrap().clone();
+
+            let mut self_clone = self.clone();
+            let handle = spawn(async move {
+                let result = self_clone.get_order_detail(&order_id, &custom_id).await;
+                match result {
+                    Ok(result) => {
+                        self_clone.order_sender.send(result).await.unwrap();
+                    }
+                    Err(error) => {
+                        self_clone.error_sender.send(error).await.unwrap();
+                    }
+                }
+            });
+            check_handlers.push(handle)
+        }
+
+        let futures = FuturesUnordered::from_iter(check_handlers);
+        // 等待所有任务完成
+        let _: Result<Vec<_>, _> = futures.try_collect().await;
+    }
+}
+
+pub fn format_position_item(position: &Value, ct_val: Decimal) -> Position {
+    let position_mode = match position["side"].as_str().unwrap_or("") {
+        "long" => PositionModeEnum::Long,
+        "short" => PositionModeEnum::Short,
+        _ => {
+            error!("coinex_swap:格式化持仓模式错误!\nformat_position_item:position={:?}", position);
+            panic!("coinex_swap:格式化持仓模式错误!\nformat_position_item:position={:?}", position)
+        }
+    };
+    let size = Decimal::from_str(&position["open_interest"].as_str().unwrap()).unwrap();
+    let amount = size * ct_val;
+    Position {
+        symbol: position["market"].as_str().unwrap_or("").parse().unwrap(),
+        margin_level: Decimal::from_str(position["leverage"].as_str().unwrap()).unwrap(),
+        amount,
+        frozen_amount: Decimal::ZERO,
+        price: Decimal::from_str(position["avg_entry_price"].as_str().unwrap()).unwrap(),
+        profit: Decimal::from_str(position["unrealized_pnl"].as_str().unwrap()).unwrap(),
+        position_mode,
+        margin: Decimal::from_str(position["ath_margin_size"].as_str().unwrap()).unwrap(),
+    }
+}
+
+pub fn format_order_item(order: Value, ct_val: Decimal, status: &str) -> Order {
+    // info!("order_format {}", order);
+    let size;
+    match order["amount"].as_str() {
+        Some(val) => {
+            size = Decimal::from_str(val).unwrap()
+        },
+        None => {
+            error!("coinex_swap:格式化订单大小错误!\nformat_order_item:order={:?} status={}", order, status);
+            panic!("coinex_swap:格式化订单大小失败,退出程序!");
+        }
+    }
+    // info!("order {}", order);
+    // 通过客户端id查询订单 只能查出未完成订单(没有状态字段)
+    let status = order["status"].as_str().unwrap_or(status);
+    let text = order["client_id"].as_str().unwrap_or("");
+
+    let deal_amount = Decimal::from_str(&order["filled_amount"].as_str().unwrap()).unwrap();
+    let filled_value = Decimal::from_str(&order["filled_value"].as_str().unwrap()).unwrap();
+
+    let amount = size * ct_val;
+    let mut avg_price = Decimal::ZERO;
+    if deal_amount != Decimal::ZERO{
+        avg_price = filled_value/deal_amount;
+    }
+    let custom_status = if status == "filled" || status == "canceled" {
+        "REMOVE".to_string()
+    } else if status == "open" || status == "part_filled" || status == "part_canceled" {
+        "NEW".to_string()
+    } else {
+        error!("coinex_swap:格式化订单状态错误!\nformat_order_item:order={:?}", order);
+        "NULL".to_string()
+    };
+    let rst_order = Order {
+        id: order["order_id"].to_string(),
+        custom_id: text.to_string(),
+        price: Decimal::from_str(order["price"].as_str().unwrap()).unwrap(),
+        amount,
+        deal_amount,
+        avg_price,
+        status: custom_status,
+        order_type: "limit".to_string(),
+        trace_stack: TraceStack::new(0, Instant::now()).on_special("765 trace_stack".to_string()),
+    };
+    return rst_order;
+}

+ 175 - 173
standard/src/coinex_swap_handle.rs

@@ -1,180 +1,182 @@
-// use std::str::FromStr;
-// use rust_decimal::Decimal;
-// use rust_decimal::prelude::FromPrimitive;
-// use exchanges::response_base::ResponseData;
-// use crate::{Trade};
-//
-// // 处理账号信息
-// // pub fn handle_account_info(res_data: &ResponseData, symbol: &String) -> Account {
-// //     let res_data_json = res_data.data["balance_list"].as_array().unwrap();
-// //     format_account_info(res_data_json, symbol)
-// // }
-//
-// // pub fn format_account_info(data: &Vec<Value>, symbol: &String) -> Account {
-// //     let symbol_upper = symbol.to_uppercase();
-// //     let symbol_array: Vec<&str> = symbol_upper.split("_").collect();
-// //     let balance_info = data.iter().find(|&item| item["ccy"].as_str().unwrap().contains(symbol_array[1]));
-// //
-// //     match balance_info {
-// //         None => {
-// //             error!("Coinex:格式化账号信息错误!\nformat_account_info: data={:?}", data);
-// //             panic!("Coinex:格式化账号信息错误!\nformat_account_info: data={:?}", data)
-// //         }
-// //         Some(value) => {
-// //             let frozen_balance= Decimal::from_str(&value["frozen"].as_str().unwrap()).unwrap();
-// //             let available_balance = Decimal::from_str(&value["available"].as_str().unwrap()).unwrap();
-// //             let margin = Decimal::from_str(&value["margin"].as_str().unwrap()).unwrap();
-// //             let profit_unreal = Decimal::from_str(&value["unrealized_pnl"].as_str().unwrap()).unwrap();
-// //             let balance = frozen_balance + available_balance + margin + profit_unreal;
-// //             Account {
-// //                 coin: symbol_array[1].to_string(),
-// //                 balance,
-// //                 available_balance: Decimal::ZERO,
-// //                 frozen_balance: Decimal::ZERO,
-// //                 stocks: Decimal::ZERO,
-// //                 available_stocks: Decimal::ZERO,
-// //                 frozen_stocks: Decimal::ZERO,
-// //             }
-// //         }
-// //     }
-// // }
-//
-// // 处理position信息
-// // pub fn handle_position(res_data: &ResponseData, ct_val: &Decimal) -> Vec<Position> {
-// //     let res_data_json = &res_data.data["position"];
-// //     let position =  format_position_item(res_data_json, ct_val);
-// //     vec![position]
-// // }
-//
-// // pub fn format_position_item(position: &Value, ct_val: &Decimal) -> Position {
-// //     let position_mode = match position["side"].as_str().unwrap_or("") {
-// //         "long" => PositionModeEnum::Long,
-// //         "short" => PositionModeEnum::Short,
-// //         _ => {
-// //             error!("Coinex:格式化持仓模式错误!\nformat_position_item:position={:?}", position);
-// //             panic!("Coinex:格式化持仓模式错误!\nformat_position_item:position={:?}", position)
-// //         }
-// //     };
-// //     let size = Decimal::from_str(&position["open_interest"].as_str().unwrap()).unwrap();
-// //     let amount = size * ct_val;
-// //     Position {
-// //         symbol: position["market"].as_str().unwrap().to_string(),
-// //         margin_level: Decimal::from_str(&position["leverage"].as_str().unwrap()).unwrap(),
-// //         amount,
-// //         frozen_amount: Decimal::ZERO,
-// //         price: Decimal::from_str(&position["avg_entry_price"].as_str().unwrap()).unwrap(),
-// //         profit: Decimal::from_str(&position["unrealized_pnl"].as_str().unwrap()).unwrap(),
-// //         position_mode,
-// //         margin: Decimal::from_str(&position["ath_margin_size"].as_str().unwrap()).unwrap(),
-// //     }
-// // }
-//
-// // 处理order信息
-// // pub fn handle_order(res_data: ResponseData, ct_val: Decimal) -> SpecialOrder {
-// //     let status = res_data.data["event"].as_str().unwrap();
-// //     let res_data_json = &res_data.data["order"];
-// //     let order_info = format_order_item(res_data_json, ct_val, status);
-// //
-// //     SpecialOrder {
-// //         name: res_data.tag,
-// //         order: vec![order_info],
-// //     }
-// // }
-//
-// // pub fn format_order_item(order: &Value, ct_val: Decimal, status: &str) -> Order {
-// //     let text = order["client_id"].as_str().unwrap_or("");
-// //     let size = Decimal::from_str(order["amount"].as_str().unwrap()).unwrap();
-// //     let left = Decimal::from_str(order["unfilled_amount"].as_str().unwrap()).unwrap();
-// //     // 已成交量
-// //     let filled_amount = size - left;
-// //     // 成交额
-// //     let filled_value = Decimal::from_str(order["filled_value"].as_str().unwrap()).unwrap();
-// //     // 成交均价
-// //     let mut avg_price = Decimal::ZERO;
-// //     if filled_amount > Decimal::ZERO{
-// //         avg_price = filled_value/filled_amount;
-// //     }
-// //     let amount = size * ct_val;
-// //     let deal_amount = filled_amount * ct_val;
-// //     let custom_status = if status == "finish" { "REMOVE".to_string() } else if status == "put" || status == "update" { "NEW".to_string() } else {
-// //         "NULL".to_string()
-// //     };
-// //     let rst_order = Order {
-// //         id: order["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,
-// //         status: custom_status,
-// //         order_type: "limit".to_string(),
-// //     };
-// //     return rst_order;
-// // }
-//
-// pub fn format_trade_items(response: &ResponseData) -> Vec<Trade> {
-//     let symbol = response.data["market"].as_str().unwrap().to_string().replace("USDT", "_USDT");
-//     let result = response.data["deal_list"].as_array().unwrap();
-//     let mut trades = vec![];
+use std::str::FromStr;
+use rust_decimal::Decimal;
+use rust_decimal::prelude::FromPrimitive;
+use exchanges::response_base::ResponseData;
+use crate::{Trade};
+
+// 处理账号信息
+// pub fn handle_account_info(res_data: &ResponseData, symbol: &String) -> Account {
+//     let res_data_json = res_data.data["balance_list"].as_array().unwrap();
+//     format_account_info(res_data_json, symbol)
+// }
+
+// pub fn format_account_info(data: &Vec<Value>, symbol: &String) -> Account {
+//     let symbol_upper = symbol.to_uppercase();
+//     let symbol_array: Vec<&str> = symbol_upper.split("_").collect();
+//     let balance_info = data.iter().find(|&item| item["ccy"].as_str().unwrap().contains(symbol_array[1]));
 //
-//     for item in result {
-//         let id = format!("{}", item["deal_id"].as_i64().unwrap());
-//         let time = Decimal::from_i64(item["created_at"].as_i64().unwrap()).unwrap();
-//         let mut size = Decimal::from_str(item["amount"].as_str().unwrap()).unwrap();
-//         if item["side"].as_str().unwrap().eq("sell") {
-//             size = size * Decimal::NEGATIVE_ONE;
+//     match balance_info {
+//         None => {
+//             error!("Coinex:格式化账号信息错误!\nformat_account_info: data={:?}", data);
+//             panic!("Coinex:格式化账号信息错误!\nformat_account_info: data={:?}", data)
 //         }
-//         let price = Decimal::from_str(item["price"].as_str().unwrap().to_string().as_str()).unwrap();
-//
-//         let trade = Trade {
-//             id,
-//             time,
-//             size,
-//             price,
-//             symbol: symbol.clone(),
-//         };
-//
-//         trades.push(trade)
+//         Some(value) => {
+//             let frozen_balance= Decimal::from_str(&value["frozen"].as_str().unwrap()).unwrap();
+//             let available_balance = Decimal::from_str(&value["available"].as_str().unwrap()).unwrap();
+//             let margin = Decimal::from_str(&value["margin"].as_str().unwrap()).unwrap();
+//             let profit_unreal = Decimal::from_str(&value["unrealized_pnl"].as_str().unwrap()).unwrap();
+//             let balance = frozen_balance + available_balance + margin + profit_unreal;
+//             Account {
+//                 coin: symbol_array[1].to_string(),
+//                 balance,
+//                 available_balance: Decimal::ZERO,
+//                 frozen_balance: Decimal::ZERO,
+//                 stocks: Decimal::ZERO,
+//                 available_stocks: Decimal::ZERO,
+//                 frozen_stocks: Decimal::ZERO,
+//             }
+//         }
+//     }
+// }
+
+// 处理position信息
+// pub fn handle_position(res_data: &ResponseData, ct_val: &Decimal) -> Vec<Position> {
+//     let res_data_json = &res_data.data["position"];
+//     let position =  format_position_item(res_data_json, ct_val);
+//     vec![position]
+// }
+
+// pub fn format_position_item(position: &Value, ct_val: &Decimal) -> Position {
+//     let position_mode = match position["side"].as_str().unwrap_or("") {
+//         "long" => PositionModeEnum::Long,
+//         "short" => PositionModeEnum::Short,
+//         _ => {
+//             error!("Coinex:格式化持仓模式错误!\nformat_position_item:position={:?}", position);
+//             panic!("Coinex:格式化持仓模式错误!\nformat_position_item:position={:?}", position)
+//         }
+//     };
+//     let size = Decimal::from_str(&position["open_interest"].as_str().unwrap()).unwrap();
+//     let amount = size * ct_val;
+//     Position {
+//         symbol: position["market"].as_str().unwrap().to_string(),
+//         margin_level: Decimal::from_str(&position["leverage"].as_str().unwrap()).unwrap(),
+//         amount,
+//         frozen_amount: Decimal::ZERO,
+//         price: Decimal::from_str(&position["avg_entry_price"].as_str().unwrap()).unwrap(),
+//         profit: Decimal::from_str(&position["unrealized_pnl"].as_str().unwrap()).unwrap(),
+//         position_mode,
+//         margin: Decimal::from_str(&position["ath_margin_size"].as_str().unwrap()).unwrap(),
 //     }
+// }
+
+// 处理order信息
+// pub fn handle_order(res_data: ResponseData, ct_val: Decimal) -> SpecialOrder {
+//     let status = res_data.data["event"].as_str().unwrap();
+//     let res_data_json = &res_data.data["order"];
+//     let order_info = format_order_item(res_data_json, ct_val, status);
 //
-//     return trades
+//     SpecialOrder {
+//         name: res_data.tag,
+//         order: vec![order_info],
+//     }
+// }
+
+// pub fn format_order_item(order: &Value, ct_val: Decimal, status: &str) -> Order {
+//     let text = order["client_id"].as_str().unwrap_or("");
+//     let size = Decimal::from_str(order["amount"].as_str().unwrap()).unwrap();
+//     let left = Decimal::from_str(order["unfilled_amount"].as_str().unwrap()).unwrap();
+//     // 已成交量
+//     let filled_amount = size - left;
+//     // 成交额
+//     let filled_value = Decimal::from_str(order["filled_value"].as_str().unwrap()).unwrap();
+//     // 成交均价
+//     let mut avg_price = Decimal::ZERO;
+//     if filled_amount > Decimal::ZERO{
+//         avg_price = filled_value/filled_amount;
+//     }
+//     let amount = size * ct_val;
+//     let deal_amount = filled_amount * ct_val;
+//     let custom_status = if status == "finish" { "REMOVE".to_string() } else if status == "put" || status == "update" { "NEW".to_string() } else {
+//         "NULL".to_string()
+//     };
+//     let rst_order = Order {
+//         id: order["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,
+//         status: custom_status,
+//         order_type: "limit".to_string(),
+//     };
+//     return rst_order;
 // }
+
+pub fn format_trade_items(response: &ResponseData) -> Vec<Trade> {
+    let symbol = response.data["market"].as_str().unwrap().to_string().replace("USDT", "_USDT");
+    let result = response.data["deal_list"].as_array().unwrap();
+    let mut trades = vec![];
+
+    for item in result {
+        let id = format!("{}", item["deal_id"].as_i64().unwrap());
+        let time = Decimal::from_i64(item["created_at"].as_i64().unwrap()).unwrap();
+        let mut size = Decimal::from_str(item["amount"].as_str().unwrap()).unwrap();
+        if item["side"].as_str().unwrap().eq("sell") {
+            size = size * Decimal::NEGATIVE_ONE;
+        }
+        let price = Decimal::from_str(item["price"].as_str().unwrap().to_string().as_str()).unwrap();
+        let value = (price * size).abs();
+
+        let trade = Trade {
+            id,
+            time,
+            size,
+            price,
+            value,
+            symbol: symbol.clone(),
+        };
+
+        trades.push(trade)
+    }
+
+    return trades
+}
+
+// 处理特殊Ticket信息
+// pub fn handle_ticker(res_data: &ResponseData) -> SpecialDepth {
+//     let depth = &res_data.data["depth"];
+//
+//     let bp = Decimal::from_str(depth["bids"][0][0].as_str().unwrap()).unwrap();
+//     let bq = Decimal::from_str(depth["bids"][0][1].as_str().unwrap()).unwrap();
+//     let ap = Decimal::from_str(depth["asks"][0][0].as_str().unwrap()).unwrap();
+//     let aq = Decimal::from_str(depth["asks"][0][1].as_str().unwrap()).unwrap();
+//     let mp = (bp + ap) * dec!(0.5);
+//     let t = Decimal::from_i64(depth.get("checksum").unwrap().as_i64().unwrap_or(0i64)).unwrap();
+//     let create_at = depth.get("updated_at").unwrap().as_i64().unwrap() * 1000;
 //
-// // 处理特殊Ticket信息
-// // pub fn handle_ticker(res_data: &ResponseData) -> SpecialDepth {
-// //     let depth = &res_data.data["depth"];
-// //
-// //     let bp = Decimal::from_str(depth["bids"][0][0].as_str().unwrap()).unwrap();
-// //     let bq = Decimal::from_str(depth["bids"][0][1].as_str().unwrap()).unwrap();
-// //     let ap = Decimal::from_str(depth["asks"][0][0].as_str().unwrap()).unwrap();
-// //     let aq = Decimal::from_str(depth["asks"][0][1].as_str().unwrap()).unwrap();
-// //     let mp = (bp + ap) * dec!(0.5);
-// //     let t = Decimal::from_i64(depth.get("checksum").unwrap().as_i64().unwrap_or(0i64)).unwrap();
-// //     let create_at = depth.get("updated_at").unwrap().as_i64().unwrap() * 1000;
-// //
-// //     let ticker_info = SpecialTicker { sell: ap, buy: bp, mid_price: mp, t, create_at };
-// //     let depth_info = vec![bp, bq, ap, aq];
-// //
-// //     SpecialDepth {
-// //         name: (*res_data).tag.clone(),
-// //         depth: depth_info,
-// //         ticker: ticker_info,
-// //         t,
-// //         create_at,
-// //     }
-// // }
+//     let ticker_info = SpecialTicker { sell: ap, buy: bp, mid_price: mp, t, create_at };
+//     let depth_info = vec![bp, bq, ap, aq];
 //
-// // pub fn format_depth_items(value: &Value) -> Vec<MarketOrder> {
-// //     if value.is_null() {
-// //         return vec![];
-// //     }
-// //     let mut depth_items: Vec<MarketOrder> = vec![];
-// //     for value in value.as_array().unwrap() {
-// //         let values = value.as_array().unwrap();
-// //         depth_items.push(MarketOrder {
-// //             price: Decimal::from_str(values[0].as_str().unwrap()).unwrap(),
-// //             amount: Decimal::from_str(values[1].as_str().unwrap()).unwrap(),
-// //         })
-// //     }
-// //     return depth_items;
-// // }
+//     SpecialDepth {
+//         name: (*res_data).tag.clone(),
+//         depth: depth_info,
+//         ticker: ticker_info,
+//         t,
+//         create_at,
+//     }
+// }
+
+// pub fn format_depth_items(value: &Value) -> Vec<MarketOrder> {
+//     if value.is_null() {
+//         return vec![];
+//     }
+//     let mut depth_items: Vec<MarketOrder> = vec![];
+//     for value in value.as_array().unwrap() {
+//         let values = value.as_array().unwrap();
+//         depth_items.push(MarketOrder {
+//             price: Decimal::from_str(values[0].as_str().unwrap()).unwrap(),
+//             amount: Decimal::from_str(values[1].as_str().unwrap()).unwrap(),
+//         })
+//     }
+//     return depth_items;
+// }

+ 10 - 8
standard/src/exchange.rs

@@ -3,6 +3,8 @@ use std::io::Error;
 use tokio::sync::mpsc::Sender;
 use crate::{Order, Platform};
 use crate::binance_swap::BinanceSwap;
+use crate::bybit_swap::BybitSwap;
+use crate::coinex_swap::CoinexSwap;
 use crate::gate_swap::GateSwap;
 
 /// 交易所交易模式枚举
@@ -14,7 +16,7 @@ use crate::gate_swap::GateSwap;
 #[derive(Debug, Clone, PartialEq, Eq)]
 pub enum ExchangeEnum {
     BinanceSwap,
-    // CoinexSwap,
+    CoinexSwap,
     // BinanceSpot,
     GateSwap,
     // GateSpot,
@@ -23,7 +25,7 @@ pub enum ExchangeEnum {
     // OkxSwap,
     // BitgetSpot,
     // BitgetSwap,
-    // BybitSwap,
+    BybitSwap,
     // HtxSwap,
     // BingxSwap,
     // MexcSwap,
@@ -100,12 +102,12 @@ impl Exchange {
             // ExchangeEnum::BitgetSwap => {
             //     Box::new(BitgetSwap::new(symbol, is_colo, params, order_sender, error_sender).await)
             // }
-            // ExchangeEnum::BybitSwap => {
-            //     Box::new(BybitSwap::new(symbol, is_colo, params, order_sender, error_sender).await)
-            // }
-            // ExchangeEnum::CoinexSwap => {
-            //     Box::new(CoinexSwap::new(symbol, is_colo, params, order_sender, error_sender).await)
-            // }
+            ExchangeEnum::BybitSwap => {
+                Box::new(BybitSwap::new(symbol, is_colo, params, order_sender, error_sender).await)
+            }
+            ExchangeEnum::CoinexSwap => {
+                Box::new(CoinexSwap::new(symbol, is_colo, params, order_sender, error_sender).await)
+            }
             // ExchangeEnum::HtxSwap => {
             //     Box::new(HtxSwap::new(symbol, is_colo, params, order_sender, error_sender).await)
             // }

+ 55 - 42
standard/src/exchange_struct_handler.rs

@@ -1,8 +1,10 @@
 use std::str::FromStr;
 use rust_decimal::{Decimal};
+use rust_decimal::prelude::FromPrimitive;
+use tracing::error;
 use exchanges::response_base::ResponseData;
 use crate::exchange::ExchangeEnum;
-use crate::{binance_swap_handle, gate_swap_handle};
+use crate::{binance_swap_handle, bybit_swap_handle, coinex_swap_handle, gate_swap_handle};
 use crate::{Record, Trade, Depth};
 use crate::{Account, OrderBook, Position, SpecialOrder};
 
@@ -49,11 +51,13 @@ impl ExchangeStructHandler {
             //     depth_bids = bitget_swap_handle::format_depth_items(res_data.data[0]["bids"].clone());
             //     t = Decimal::from_str(res_data.data[0]["ts"].as_str().unwrap()).unwrap();
             // }
-            // ExchangeEnum::BybitSwap => {
-            //     depth_asks = bybit_swap_handle::format_depth_items(res_data.data["a"].clone());
-            //     depth_bids = bybit_swap_handle::format_depth_items(res_data.data["b"].clone());
-            //     t = Decimal::from_i64(res_data.reach_time).unwrap();
-            // }
+            ExchangeEnum::BybitSwap => {
+                depth_asks = bybit_swap_handle::format_depth_items(res_data.data["a"].clone(), mul);
+                depth_bids = bybit_swap_handle::format_depth_items(res_data.data["b"].clone(), mul);
+                t = Decimal::from_i64(res_data.reach_time).unwrap();
+
+                res_data.data["s"].as_str().unwrap().to_string().replace("USDT", "_USDT")
+            }
             // ExchangeEnum::BingxSwap => {
             //     depth_asks = bingx_swap_handle::format_depth_items(&res_data.data["data"]["asks"].clone());
             //     depth_bids = bingx_swap_handle::format_depth_items(&res_data.data["data"]["bids"].clone());
@@ -81,10 +85,10 @@ impl ExchangeStructHandler {
             //     t = Decimal::from_i64(res_data.data["pTime"].as_i64().unwrap()).unwrap();
             //     symbol = res_data.data["instId"].as_str().unwrap().replace("USDT", "_USDT")
             // }
-            // _ => {
-            //     error!("未找到该交易所!order_book_handle: {:?}", exchange);
-            //     panic!("未找到该交易所!order_book_handle: {:?}", exchange);
-            // }
+            _ => {
+                error!("未找到该交易所!order_book_handle: {:?}", exchange);
+                panic!("未找到该交易所!order_book_handle: {:?}", exchange);
+            }
         };
 
         Depth {
@@ -112,9 +116,12 @@ impl ExchangeStructHandler {
             ExchangeEnum::BinanceSwap => {
                 binance_swap_handle::format_trade_items(&res_data)
             }
-            // ExchangeEnum::CoinexSwap => {
-            //     coinex_swap_handle::format_trade_items(&res_data)
-            // }
+            ExchangeEnum::BybitSwap => {
+                bybit_swap_handle::format_trade_items(&res_data)
+            }
+            ExchangeEnum::CoinexSwap => {
+                coinex_swap_handle::format_trade_items(&res_data)
+            }
             // ExchangeEnum::HtxSwap => {
             //     htx_swap_handle::format_trade_items(&res_data)
             // }
@@ -161,10 +168,13 @@ impl ExchangeStructHandler {
             ExchangeEnum::BinanceSwap => {
                 binance_swap_handle::handle_book_ticker(&res_data, mul)
             }
-            // _ => {
-            //     error!("未找到该交易所!book_ticker_handle: {:?}", exchange);
-            //     panic!("未找到该交易所!book_ticker_handle: {:?}", exchange);
-            // }
+            ExchangeEnum::BybitSwap => {
+                bybit_swap_handle::handle_book_ticker(&res_data, mul)
+            }
+            _ => {
+                error!("未找到该交易所!book_ticker_handle: {:?}", exchange);
+                panic!("未找到该交易所!book_ticker_handle: {:?}", exchange);
+            }
         }
     }
     // 处理蜡烛信息
@@ -182,6 +192,9 @@ impl ExchangeStructHandler {
             ExchangeEnum::BinanceSwap => {
                 binance_swap_handle::handle_records(&res_data.data)
             }
+            ExchangeEnum::BybitSwap => { // 未使用暂不实现
+                vec![]
+            }
             // ExchangeEnum::HtxSwap => {
             //     htx_swap_handle::handle_records(&res_data.data)
             // }
@@ -212,10 +225,10 @@ impl ExchangeStructHandler {
             // ExchangeEnum::CointrSwap => {
             //     cointr_swap_handle::handle_records(&res_data.data)
             // }
-            // _ => {
-            //     error!("未找到该交易所!records_handle: {:?}", exchange);
-            //     panic!("未找到该交易所!records_handle: {:?}", exchange);
-            // }
+            _ => {
+                error!("未找到该交易所!records_handle: {:?}", exchange);
+                panic!("未找到该交易所!records_handle: {:?}", exchange);
+            }
         }
     }
     // 处理账号信息
@@ -230,13 +243,13 @@ impl ExchangeStructHandler {
             // ExchangeEnum::BitgetSwap => {
             //     bitget_swap_handle::handle_account_info(res_data, symbol)
             // }
-            // ExchangeEnum::BybitSwap => {
-            //     bybit_swap_handle::handle_account_info(res_data, symbol)
-            // }
-            // _ => {
-            //     error!("未找到该交易所!handle_account_info: {:?}", exchange);
-            //     panic!("未找到该交易所!handle_account_info: {:?}", exchange);
-            // }
+            ExchangeEnum::BybitSwap => {
+                bybit_swap_handle::handle_account_info(res_data, symbol)
+            }
+            _ => {
+                error!("未找到该交易所!handle_account_info: {:?}", exchange);
+                panic!("未找到该交易所!handle_account_info: {:?}", exchange);
+            }
         }
     }
     // 处理position信息
@@ -254,13 +267,13 @@ impl ExchangeStructHandler {
             // ExchangeEnum::BitgetSwap => {
             //     bitget_swap_handle::handle_position(res_data, ct_val)
             // }
-            // ExchangeEnum::BybitSwap => {
-            //     bybit_swap_handle::handle_position(res_data, ct_val)
-            // }
-            // _ => {
-            //     error!("暂未提供此交易所方法!handle_position:{:?}", exchange);
-            //     panic!("暂未提供此交易所方法!handle_position:{:?}", exchange);
-            // }
+            ExchangeEnum::BybitSwap => {
+                bybit_swap_handle::handle_position(res_data, mul)
+            }
+            _ => {
+                error!("暂未提供此交易所方法!handle_position:{:?}", exchange);
+                panic!("暂未提供此交易所方法!handle_position:{:?}", exchange);
+            }
         }
     }
     // 处理订单信息
@@ -278,13 +291,13 @@ impl ExchangeStructHandler {
             // ExchangeEnum::BitgetSwap => {
             //     bitget_swap_handle::handle_order(res_data, ct_val)
             // }
-            // ExchangeEnum::BybitSwap => {
-            //     bybit_swap_handle::handle_order(res_data, ct_val)
-            // }
-            // _ => {
-            //     error!("暂未提供此交易所方法!order_handle:{:?}", exchange);
-            //     panic!("暂未提供此交易所方法!order_handle:{:?}", exchange);
-            // }
+            ExchangeEnum::BybitSwap => {
+                bybit_swap_handle::handle_order(res_data, ct_val)
+            }
+            _ => {
+                error!("暂未提供此交易所方法!order_handle:{:?}", exchange);
+                panic!("暂未提供此交易所方法!order_handle:{:?}", exchange);
+            }
         }
     }
 }

+ 5 - 5
standard/src/gate_swap.rs

@@ -276,13 +276,13 @@ impl Platform for GateSwap {
                     let tick_size = Decimal::from_str(value["order_price_round"].as_str().unwrap()).unwrap();
                     let min_qty = Decimal::from_str(&value["order_size_min"].to_string()).unwrap();
                     let max_qty = Decimal::from_str(&value["order_size_max"].to_string()).unwrap();
-                    let multiplier = Decimal::from_str(value["quanto_multiplier"].as_str().unwrap()).unwrap();
+                    let ct_val = Decimal::from_str(value["quanto_multiplier"].as_str().unwrap()).unwrap();
 
-                    let amount_size = min_qty * multiplier;
+                    let amount_size = min_qty * ct_val;
                     let price_precision = Decimal::from_u32(tick_size.scale()).unwrap();
                     let amount_precision = Decimal::from_u32(amount_size.scale()).unwrap();
-                    let min_notional = min_qty * multiplier;
-                    let max_notional = max_qty * multiplier;
+                    let min_notional = min_qty * ct_val;
+                    let max_notional = max_qty * ct_val;
 
                     let result = Market {
                         symbol: name.to_string(),
@@ -296,7 +296,7 @@ impl Platform for GateSwap {
                         max_qty,
                         min_notional,
                         max_notional,
-                        multiplier,
+                        multiplier: ct_val,
                     };
                     Ok(result)
                 }

+ 218 - 253
strategy/src/bybit_usdt_swap.rs

@@ -1,253 +1,218 @@
-// use std::collections::BTreeMap;
-// use std::sync::Arc;
-// use std::sync::atomic::{AtomicBool};
-// use rust_decimal::Decimal;
-// use tokio::{spawn};
-// use tokio::sync::Mutex;
-// use tracing::{error, info};
-// use tokio_tungstenite::tungstenite::Message;
-// use exchanges::bybit_swap_ws::{BybitSwapLogin, BybitSwapSubscribeType, BybitSwapWs, BybitSwapWsType};
-// use exchanges::response_base::ResponseData;
-// use global::trace_stack::TraceStack;
-// use standard::exchange::ExchangeEnum::BybitSwap;
-// use crate::core::Core;
-// use crate::exchange_disguise::on_special_depth;
-// use crate::model::OrderInfo;
-//
-// // 1交易、0参考 bybit 合约 启动
-// pub async fn bybit_swap_run(is_shutdown_arc: Arc<AtomicBool>,
-//                             is_trade: bool,
-//                             core_arc: Arc<Mutex<Core>>,
-//                             name: String,
-//                             symbols: Vec<String>,
-//                             is_colo: bool,
-//                             exchange_params: BTreeMap<String, String>) {
-//     // 启动公共频道
-//     let (write_tx_public, write_rx_public) = futures_channel::mpsc::unbounded::<Message>();
-//
-//     let mut ws_public = BybitSwapWs::new_label(name.clone(), is_colo, None, BybitSwapWsType::Public);
-//     ws_public.set_symbols(symbols.clone());
-//     ws_public.set_subscribe(vec![
-//         BybitSwapSubscribeType::PuTickers
-//     ]);
-//     // if is_trade {
-//     //     ws_public.set_subscribe(vec![
-//     //         BybitSwapSubscribeType::PuBlicTrade
-//     //     ]);
-//     // }
-//     // 挂起公共ws
-//     let write_tx_am_public = Arc::new(Mutex::new(write_tx_public));
-//     let is_shutdown_clone_public = Arc::clone(&is_shutdown_arc);
-//     let core_arc_clone_public = core_arc.clone();
-//     spawn(async move {
-//         // 消费数据
-//         let mut update_flag_u = Decimal::ZERO;
-//
-//         let fun = move |data: ResponseData| {
-//             let core_arc = core_arc_clone_public.clone();
-//
-//             async move {
-//                 on_public_data(core_arc,
-//                                &mut update_flag_u,
-//                                data).await;
-//             }
-//         };
-//
-//         // ws_public.ws_connect_async(is_shutdown_clone_public,
-//         //                            fun,
-//         //                            &write_tx_am_public,
-//         //                            write_rx_public).await.expect("链接失败(内部一个心跳线程应该已经关闭了)");
-//     });
-//     let trade_symbols = symbols.clone();
-//     // 交易交易所需要启动私有ws
-//     if is_trade {
-//         let (write_tx_private, write_rx_private) = futures_channel::mpsc::unbounded();
-//         let auth = Some(parse_btree_map_to_bybit_swap_login(exchange_params));
-//
-//         let mut ws_private = BybitSwapWs::new_label(name.clone(), is_colo, auth, BybitSwapWsType::Private);
-//         ws_private.set_symbols(trade_symbols);
-//         ws_private.set_subscribe(vec![
-//             BybitSwapSubscribeType::PrPosition,
-//             BybitSwapSubscribeType::PrOrder,
-//             BybitSwapSubscribeType::PrWallet
-//         ]);
-//
-//         // 挂起私有ws
-//         let write_tx_am_private = Arc::new(Mutex::new(write_tx_private));
-//         let is_shutdown_clone_private = Arc::clone(&is_shutdown_arc);
-//         let core_arc_clone_private = core_arc.clone();
-//         spawn(async move {
-//             let ct_val = core_arc_clone_private.lock().await.platform_rest.get_self_market().ct_val;
-//             let run_symbol = symbols.clone()[0].clone();
-//
-//             let fun = move |data: ResponseData| {
-//                 let core_arc_clone = core_arc_clone_private.clone();
-//                 let run_symbol_clone = run_symbol.clone();
-//
-//                 async move {
-//                     on_private_data(core_arc_clone.clone(), &ct_val, &run_symbol_clone, data).await;
-//                 }
-//             };
-//
-//             ws_private.ws_connect_async(is_shutdown_clone_private,
-//                                         fun,
-//                                         &write_tx_am_private,
-//                                         write_rx_private).await.expect("链接失败(内部一个心跳线程应该已经关闭了)");
-//         });
-//     }
-// }
-//
-// async fn on_private_data(core_arc_clone: Arc<Mutex<Core>>, ct_val: &Decimal, run_symbol: &String, response: ResponseData) {
-//     let mut trace_stack = TraceStack::new(response.time, response.ins);
-//     trace_stack.on_after_span_line();
-//
-//     match response.channel.as_str() {
-//         // "wallet" => {
-//         //     let account = standard::handle_info::HandleSwapInfo::handle_account_info(BybitSwap, &response, run_symbol);
-//         //     let mut core = core_arc_clone.lock().await;
-//         //     core.update_equity(account).await;
-//         // }
-//         // "order" => {
-//         //     let orders = standard::handle_info::HandleSwapInfo::handle_order(BybitSwap, response.clone(), ct_val.clone());
-//         //     trace_stack.on_after_format();
-//         //
-//         //     let mut order_infos:Vec<OrderInfo> = Vec::new();
-//         //     for mut order in orders.order {
-//         //         if order.status == "NULL" {
-//         //             error!("bybit_usdt_swap 未识别的订单状态:{:?}", response);
-//         //
-//         //             continue;
-//         //         }
-//         //
-//         //         if order.deal_amount != Decimal::ZERO {
-//         //             info!("bybit order 消息原文:{:?}", response);
-//         //         }
-//         //
-//         //         let order_info = OrderInfo::parse_order_to_order_info(&mut order);
-//         //         order_infos.push(order_info);
-//         //     }
-//         //
-//         //     let mut core = core_arc_clone.lock().await;
-//         //     core.update_order(order_infos, trace_stack).await;
-//         // }
-//         // "position" => {
-//         //     let positions = standard::handle_info::HandleSwapInfo::handle_position(BybitSwap, &response, ct_val);
-//         //     let mut core = core_arc_clone.lock().await;
-//         //     core.update_position(positions).await;
-//         // }
-//         _ => {
-//             error!("未知推送类型");
-//             error!(?response);
-//         }
-//     }
-// }
-//
-// async fn on_public_data(core_arc_clone: Arc<Mutex<Core>>, update_flag_u: &mut Decimal, response: ResponseData) {
-//     if response.code != 200 {
-//         return;
-//     }
-//
-//     let mut trace_stack = TraceStack::new(response.time, response.ins);
-//     trace_stack.on_after_span_line();
-//
-//     match response.channel.as_str() {
-//         "tickers" => {
-//             // trace_stack.set_source("bybit_usdt_swap.tickers".to_string());
-//             //
-//             // // 处理ticker信息
-//             // let special_depth = standard::handle_info::HandleSwapInfo::handle_book_ticker(BybitSwap, &response);
-//             // trace_stack.on_after_format();
-//             //
-//             // on_special_depth(core_arc_clone, update_flag_u, &response.label, &mut trace_stack, &special_depth).await;
-//         }
-//         "orderbook" => {
-//             // let mut is_update = false;
-//             // let data_type = data.data_type.clone();
-//             // let label = data.label.clone();
-//             // if data_type == "delta"  {
-//             //     is_update = true;
-//             // }
-//             // let mut depth_format: DepthParam = format_depth(BybitSwap, &data);
-//             // // 是增量更新
-//             // if is_update {
-//             //     update_order_book(depth_asks, depth_bids, depth_format.depth_asks, depth_format.depth_bids);
-//             // } else { // 全量
-//             //     depth_asks.clear();
-//             //     depth_asks.append(&mut depth_format.depth_asks);
-//             //     depth_bids.clear();
-//             //     depth_bids.append(&mut depth_format.depth_bids);
-//             // }
-//             // let depth = make_special_depth(label.clone(), depth_asks, depth_bids, depth_format.t, depth_format.create_at);
-//             // trace_stack.on_before_network(depth_format.create_at.clone());
-//             // trace_stack.on_after_format();
-//             //
-//             // on_special_depth(core_arc_clone, update_flag_u, &label, &mut trace_stack, &depth).await;
-//         }
-//         "trade" => {
-//             // let mut core = core_arc_clone.lock().await;
-//             // let str = data.label.clone();
-//             // if core.is_update.contains_key(&data.label) && *core.is_update.get(str.as_str()).unwrap(){
-//             //     *max_buy = Decimal::ZERO;
-//             //     *min_sell = Decimal::ZERO;
-//             //     core.is_update.remove(str.as_str());
-//             // }
-//             // let trades: Vec<OriginalTradeBy> = serde_json::from_str(data.data.as_str()).unwrap();
-//             // for trade in trades {
-//             //     if trade.p > *max_buy || *max_buy == Decimal::ZERO{
-//             //         *max_buy = trade.p
-//             //     }
-//             //     if trade.p < *min_sell || *min_sell == Decimal::ZERO{
-//             //         *min_sell = trade.p
-//             //     }
-//             // }
-//             // core.max_buy_min_sell_cache.insert(data.label, vec![*max_buy, *min_sell]);
-//         }
-//         _ => {}
-//     }
-// }
-//
-// fn parse_btree_map_to_bybit_swap_login(exchange_params: BTreeMap<String, String>) -> BybitSwapLogin {
-//     BybitSwapLogin {
-//         api_key: exchange_params.get("access_key").unwrap().clone(),
-//         secret_key: exchange_params.get("secret_key").unwrap().clone(),
-//     }
-// }
-//
-// // fn update_order_book(depth_asks: &mut Vec<MarketOrder>, depth_bids: &mut Vec<MarketOrder>, asks : Vec<MarketOrder>, bids: Vec<MarketOrder>) {
-// //     for i in asks {
-// //         let index_of_value = depth_asks.iter().position(|x| x.price == i.price);
-// //         match index_of_value {
-// //             Some(index) => {
-// //                 if i.amount == Decimal::ZERO {
-// //                     depth_asks.remove(index);
-// //                 } else {
-// //                     depth_asks[index].amount = i.amount.clone();
-// //                 }
-// //             },
-// //             None => {
-// //                 depth_asks.push(i.clone());
-// //             },
-// //         }
-// //     }
-// //     for i in bids {
-// //         let index_of_value = depth_bids.iter().position(|x| x.price == i.price);
-// //         match index_of_value {
-// //             Some(index) => {
-// //                 if i.amount == Decimal::ZERO {
-// //                     depth_bids.remove(index);
-// //                 } else {
-// //                     depth_bids[index].amount = i.amount.clone();
-// //                 }
-// //             },
-// //             None => {
-// //                 depth_bids.push(i.clone());
-// //             },
-// //         }
-// //     }
-// //     depth_asks.sort_by(|a, b| a.price.partial_cmp(&b.price).unwrap_or(Ordering::Equal));
-// //     depth_bids.sort_by(|a, b| b.price.partial_cmp(&a.price).unwrap_or(Ordering::Equal));
-// //
-// //     // 限制总长度100
-// //     depth_asks.truncate(100);
-// //     depth_bids.truncate(100);
-// // }
+use std::collections::BTreeMap;
+use std::sync::Arc;
+use std::sync::atomic::{AtomicBool};
+use rust_decimal::Decimal;
+use tokio::{spawn};
+use tokio::sync::Mutex;
+use tracing::{error, info};
+use tokio_tungstenite::tungstenite::Message;
+use exchanges::bybit_swap_ws::{BybitSwapLogin, BybitSwapSubscribeType, BybitSwapWs, BybitSwapWsType};
+use exchanges::response_base::ResponseData;
+use global::trace_stack::TraceStack;
+use standard::exchange::ExchangeEnum::BybitSwap;
+use standard::exchange_struct_handler::ExchangeStructHandler;
+use standard::{Depth, OrderBook};
+use crate::core::Core;
+use crate::exchange_disguise::{on_depth, on_trade};
+use crate::model::OrderInfo;
+
+// 参考 Bybit 合约 启动
+pub(crate) async fn reference_bybit_swap_run(is_shutdown_arc: Arc<AtomicBool>,
+                                             core_arc: Arc<Mutex<Core>>,
+                                             name: String,
+                                             symbols: Vec<String>,
+                                             is_colo: bool) {
+    spawn(async move {
+        //创建读写通道
+        let (write_tx, write_rx) = futures_channel::mpsc::unbounded::<Message>();
+        let mut ws = BybitSwapWs::new_label(name, is_colo, None, BybitSwapWsType::Public);
+        ws.set_subscribe(vec![
+            BybitSwapSubscribeType::PuOrderBook1,
+            BybitSwapSubscribeType::PuTrade
+        ]);
+
+        // 读取数据
+        let core_arc_clone = Arc::clone(&core_arc);
+        let multiplier = core_arc_clone.lock().await.platform_rest.get_self_market().multiplier;
+        let depth_asks = Arc::new(Mutex::new(Vec::new()));
+        let depth_bids = Arc::new(Mutex::new(Vec::new()));
+
+        let fun = move |data: ResponseData| {
+            // 在 async 块之前克隆 Arc
+            let core_arc_cc = core_arc_clone.clone();
+            let mul = multiplier.clone();
+
+            let depth_asks = Arc::clone(&depth_asks);
+            let depth_bids = Arc::clone(&depth_bids);
+
+            async move {
+                let mut depth_asks = depth_asks.lock().await;
+                let mut depth_bids = depth_bids.lock().await;
+                // 使用克隆后的 Arc,避免 move 语义
+                on_public_data(core_arc_cc, &mul, &data, &mut depth_asks, &mut depth_bids).await
+            }
+        };
+
+        // 链接
+        let write_tx_am = Arc::new(Mutex::new(write_tx));
+        ws.set_symbols(symbols);
+        ws.ws_connect_async(is_shutdown_arc, fun, &write_tx_am, write_rx).await.expect("链接失败");
+    });
+}
+
+// 交易 bybit 合约 启动
+pub(crate) async fn bybit_swap_run(is_shutdown_arc: Arc<AtomicBool>,
+                                   core_arc: Arc<Mutex<Core>>,
+                                   name: String,
+                                   symbols: Vec<String>,
+                                   is_colo: bool,
+                                   exchange_params: BTreeMap<String, String>) {
+    spawn(async move {
+        // 交易交易所需要启动私有ws
+        let (write_tx, write_rx) = futures_channel::mpsc::unbounded();
+        let auth = Some(parse_btree_map_to_bybit_swap_login(exchange_params));
+        let mut ws = BybitSwapWs::new_label(name.clone(), is_colo, auth, BybitSwapWsType::Private);
+        ws.set_subscribe(vec![
+            BybitSwapSubscribeType::PrPosition,
+            BybitSwapSubscribeType::PrOrder,
+            BybitSwapSubscribeType::PrWallet
+        ]);
+
+        let core_arc_clone_private = core_arc.clone();
+        let multiplier = core_arc_clone_private.lock().await.platform_rest.get_self_market().multiplier;
+        let run_symbol = symbols.clone()[0].clone();
+
+        // 挂起私有ws
+        let fun = move |data: ResponseData| {
+            // 在 async 块之前克隆 Arc
+            let core_arc_cc = core_arc_clone_private.clone();
+            let mul = multiplier.clone();
+            let rs = run_symbol.clone();
+
+            async move {
+                // 使用克隆后的 Arc,避免 move 语义
+                on_private_data(core_arc_cc, &mul, &rs, &data).await;
+            }
+        };
+
+        // 链接
+        let write_tx_am = Arc::new(Mutex::new(write_tx));
+        ws.set_symbols(symbols);
+        ws.ws_connect_async(is_shutdown_arc, fun, &write_tx_am, write_rx).await.expect("链接失败");
+    });
+}
+
+async fn on_public_data(core_arc: Arc<Mutex<Core>>, mul: &Decimal, response: &ResponseData, depth_asks: &mut Vec<OrderBook>, depth_bids: &mut Vec<OrderBook>) {
+    let mut trace_stack = TraceStack::new(response.time, response.ins);
+    trace_stack.on_after_span_line();
+
+    match response.channel.as_str() {
+        "orderbook" => {
+            trace_stack.set_source("bybit_usdt_swap.bookTicker".to_string());
+
+            let mut is_update = false;
+            if response.data_type == "delta"  {
+                is_update = true;
+            }
+            let mut depth = ExchangeStructHandler::book_ticker_handle(BybitSwap, &response, mul);
+            // 是增量更新
+            if is_update {
+                if depth.asks.len() != 0 {
+                    depth_asks.clear();
+                    depth_asks.append(&mut depth.asks);
+                } else if depth.bids.len() != 0 {
+                    depth_bids.clear();
+                    depth_bids.append(&mut depth.bids);
+                }
+
+                let result_depth = Depth {
+                    time: depth.time,
+                    symbol: depth.symbol,
+                    asks: depth_asks.clone(),
+                    bids: depth_bids.clone(),
+                };
+
+                trace_stack.on_after_format();
+                on_depth(core_arc, &response.label, &mut trace_stack, &result_depth).await;
+            }
+            // 全量
+            else {
+                trace_stack.on_after_format();
+                on_depth(core_arc, &response.label, &mut trace_stack, &depth).await;
+
+                depth_asks.clear();
+                depth_asks.append(&mut depth.asks);
+                depth_bids.clear();
+                depth_bids.append(&mut depth.bids);
+            }
+        }
+        "trade" => {
+            trace_stack.set_source("bybit_usdt_swap.trade".to_string());
+
+            let mut trades = ExchangeStructHandler::trades_handle(BybitSwap, response, mul);
+            trace_stack.on_after_format();
+
+            for trade in trades.iter_mut() {
+                let core_arc_clone = core_arc.clone();
+
+                on_trade(core_arc_clone, &response.label, &mut trace_stack, &trade).await;
+            }
+        }
+        _ => {
+            error!("未知推送类型");
+            error!(?response);
+        }
+    }
+}
+
+async fn on_private_data(core_arc_clone: Arc<Mutex<Core>>, ct_val: &Decimal, run_symbol: &String, response: &ResponseData) {
+    let mut trace_stack = TraceStack::new(response.time, response.ins);
+    trace_stack.on_after_span_line();
+
+    match response.channel.as_str() {
+        "wallet" => {
+            let account = ExchangeStructHandler::account_info_handle(BybitSwap, response, run_symbol);
+            let mut core = core_arc_clone.lock().await;
+            core.update_equity(account).await;
+        }
+        "order" => {
+            let orders = ExchangeStructHandler::order_handle(BybitSwap, response, ct_val);
+            trace_stack.on_after_format();
+
+            let mut order_infos:Vec<OrderInfo> = Vec::new();
+            for mut order in orders.order {
+                if order.status == "NULL" {
+                    error!("bybit_usdt_swap 未识别的订单状态:{:?}", response);
+
+                    continue;
+                }
+
+                if order.deal_amount != Decimal::ZERO {
+                    info!("bybit order 消息原文:{:?}", response);
+                }
+
+                let order_info = OrderInfo::parse_order_to_order_info(&mut order);
+                order_infos.push(order_info);
+            }
+
+            let mut core = core_arc_clone.lock().await;
+            core.update_order(order_infos, trace_stack).await;
+        }
+        "position" => {
+            let positions = ExchangeStructHandler::position_handle(BybitSwap, response, ct_val);
+            let mut core = core_arc_clone.lock().await;
+            core.update_position(positions).await;
+        }
+        _ => {
+            error!("未知推送类型");
+            error!(?response);
+        }
+    }
+}
+
+fn parse_btree_map_to_bybit_swap_login(exchange_params: BTreeMap<String, String>) -> BybitSwapLogin {
+    BybitSwapLogin {
+        api_key: exchange_params.get("access_key").unwrap().clone(),
+        secret_key: exchange_params.get("secret_key").unwrap().clone(),
+    }
+}

+ 267 - 268
strategy/src/coinex_usdt_swap.rs

@@ -1,270 +1,269 @@
-// use tracing::{error};
-// use std::collections::BTreeMap;
-// use std::sync::Arc;
-// use std::sync::atomic::AtomicBool;
-// use rust_decimal::Decimal;
-// use tokio::spawn;
-// use tokio::sync::Mutex;
-// use exchanges::coinex_swap_ws::{CoinexSwapLogin, CoinexSwapSubscribeType, CoinexSwapWs};
-// use exchanges::response_base::ResponseData;
-// use global::trace_stack::{TraceStack};
+use tracing::{error};
+use std::collections::BTreeMap;
+use std::sync::Arc;
+use std::sync::atomic::AtomicBool;
+use rust_decimal::Decimal;
+use tokio::spawn;
+use tokio::sync::Mutex;
+use exchanges::coinex_swap_ws::{CoinexSwapLogin, CoinexSwapSubscribeType, CoinexSwapWs};
+use exchanges::response_base::ResponseData;
+use global::trace_stack::{TraceStack};
 // use standard::exchange::ExchangeEnum::{CoinexSwap};
 // use crate::model::{OrderInfo};
-// use crate::core::Core;
-// use crate::exchange_disguise::on_special_depth;
-//
-// // 1交易、0参考 coinex 合约 启动
-// pub async fn coinex_swap_run(is_shutdown_arc: Arc<AtomicBool>,
-//                            is_trade: bool,
-//                            core_arc: Arc<Mutex<Core>>,
-//                            name: String,
-//                            symbols: Vec<String>,
-//                            _is_colo: bool,
-//                            exchange_params: BTreeMap<String, String>) {
-//     let (write_tx, write_rx) = futures_channel::mpsc::unbounded();
-//
-//     let write_tx_am = Arc::new(Mutex::new(write_tx));
-//     let symbols_clone = symbols.clone();
-//     spawn(async move {
-//         let mut ws;
-//         // 交易
-//         if is_trade {
-//             let login_param = parse_btree_map_to_coinex_swap_login(exchange_params);
-//             ws = CoinexSwapWs::new_label(name.clone(), Some(login_param));
-//             ws.set_subscribe(vec![
-//                 // CoinexSwapSubscribeType::PuFuturesDeals,
-//                 CoinexSwapSubscribeType::PuFuturesDepth,
-//
-//                 CoinexSwapSubscribeType::PrFuturesOrders,
-//                 CoinexSwapSubscribeType::PrFuturesPositions,
-//                 CoinexSwapSubscribeType::PrFuturesBalances,
-//             ]);
-//         } else { // 参考
-//             ws = CoinexSwapWs::new_label(name.clone(), None);
-//             ws.set_subscribe(vec![
-//                 // CoinexSwapSubscribeType::PuFuturesDeals,
-//                 CoinexSwapSubscribeType::PuFuturesDepth
-//             ]);
-//         }
-//
-//         // 读取数据
-//         let mut update_flag_u = Decimal::ZERO;
-//         let core_arc_clone = Arc::clone(&core_arc);
-//         let multiplier = core_arc_clone.lock().await.platform_rest.get_self_market().ct_val;
-//         let run_symbol = symbols.clone()[0].clone();
-//
-//         let fun = move |data: ResponseData| {
-//             let core_arc_cc = core_arc_clone.clone();
-//             // 在 async 块之前克隆 Arc
-//             let mul = multiplier.clone();
-//             let rs = run_symbol.clone();
-//
-//             async move {
-//                 on_data(core_arc_cc,
-//                         &mut update_flag_u,
-//                         &mul,
-//                         &rs,
-//                         data,
-//                 ).await
-//             }
-//         };
-//
-//         // 建立链接
-//         ws.set_symbols(symbols_clone);
-//         ws.ws_connect_async(is_shutdown_arc, fun, &write_tx_am, write_rx).await.expect("链接失败(内部一个心跳线程应该已经关闭了)");
-//     });
-// }
-//
-// async fn on_data(core_arc_clone: Arc<Mutex<Core>>,
-//                  update_flag_u: &mut Decimal,
-//                  multiplier: &Decimal,
-//                  run_symbol: &String,
-//                  response: ResponseData) {
-//     let mut trace_stack = TraceStack::new(response.time, response.ins);
-//     trace_stack.on_after_span_line();
-//
-//     match response.channel.as_str() {
-//         // "depth.update" => {
-//         //     trace_stack.set_source("coinex_usdt_swap.order_book".to_string());
-//         //     let special_depth = standard::handle_info::HandleSwapInfo::handle_special_depth(CoinexSwap, &response);
-//         //     trace_stack.on_after_format();
-//         //
-//         //     on_special_depth(core_arc_clone, update_flag_u, &response.label, &mut trace_stack, &special_depth).await;
-//         // }
-//         // "balance.update" => {
-//         //     let account = standard::handle_info::HandleSwapInfo::handle_account_info(CoinexSwap, &response, run_symbol);
-//         //     let mut core = core_arc_clone.lock().await;
-//         //     core.update_equity(account).await;
-//         // }
-//         // "order.update" => {
-//         //     trace_stack.set_source("coinex_swap.orders".to_string());
-//         //     let orders = standard::handle_info::HandleSwapInfo::handle_order(CoinexSwap, response.clone(), multiplier.clone());
-//         //     let mut order_infos:Vec<OrderInfo> = Vec::new();
-//         //     for mut order in orders.order {
-//         //         if order.status == "NULL" {
-//         //             error!("coinex_usdt_swap 未识别的订单状态:{:?}", response);
-//         //             continue;
-//         //         }
-//         //
-//         //         let order_info = OrderInfo::parse_order_to_order_info(&mut order);
-//         //         order_infos.push(order_info);
-//         //     }
-//         //
-//         //     if order_infos.is_empty() {
-//         //         error!("coinex_usdt_swap 未识别的订单 格式化失败:{:?}", response);
-//         //         return
-//         //     }
-//         //     let mut new_order = order_infos[0].clone();
-//         //     let mut core = core_arc_clone.lock().await;
-//         //     // 本地订单缓存判断
-//         //     if !core.local_orders_backup.contains_key(&new_order.client_id) {
-//         //         return
-//         //     }
-//         //
-//         //     // 获取订单目的
-//         //     let mut rst = vec![];
-//         //     let side = core.local_orders_backup.get(&new_order.client_id).unwrap().side.as_str();
-//         //     let local_position_by_orders = &core.local_position_by_orders;
-//         //     let long_pos = local_position_by_orders.long_pos;
-//         //     let short_pos = local_position_by_orders.short_pos;
-//         //
-//         //     // 部分成交和新订单的处理,不用走下面的逻辑
-//         //     if new_order.status != "REMOVE" || new_order.filled == Decimal::ZERO {
-//         //         core.update_order(order_infos, trace_stack).await;
-//         //         return
-//         //     }
-//         //
-//         //     // 单向持仓的处理
-//         //     match side {
-//         //         "kd" => {
-//         //             if short_pos != Decimal::ZERO {
-//         //                 let vir_order_filled;
-//         //                 if short_pos >= new_order.amount {
-//         //                     vir_order_filled = new_order.amount;
-//         //                 } else {
-//         //                     vir_order_filled = short_pos
-//         //                 }
-//         //                 // 构造虚拟订单
-//         //                 let vir_client_id = format!("{}vir", new_order.client_id.clone());
-//         //                 let vir_order = OrderInfo {
-//         //                     symbol: "".to_string(),
-//         //                     amount: vir_order_filled,
-//         //                     side: "pk".to_string(),
-//         //                     price: new_order.price,
-//         //                     client_id: vir_client_id.clone(),
-//         //                     filled_price: new_order.price,
-//         //                     filled: vir_order_filled,
-//         //                     order_id: "".to_string(),
-//         //                     local_time: 0,
-//         //                     create_time: 0,
-//         //                     status: new_order.status.clone(),
-//         //                     fee: Default::default(),
-//         //                     trace_stack: trace_stack.clone(),
-//         //                 };
-//         //                 core.local_orders_backup.insert(vir_client_id.clone(), vir_order.clone());
-//         //
-//         //                 // 原始订单处理
-//         //                 new_order.amount -= vir_order_filled;
-//         //                 new_order.filled -= vir_order_filled;
-//         //
-//         //                 rst.push(vir_order.clone());
-//         //                 if new_order.amount > Decimal::ZERO {
-//         //                     rst.push(new_order.clone());
-//         //                 } else {
-//         //                     core.local_cancel_log.remove(&new_order.client_id);
-//         //                     core.local_orders_backup.remove(&new_order.client_id);
-//         //                     core.local_orders.remove(&new_order.client_id);
-//         //                 }
-//         //             } else {
-//         //                 rst.push(new_order.clone());
-//         //             }
-//         //         }
-//         //         "kk" => {
-//         //             if long_pos != Decimal::ZERO {
-//         //                 let vir_order_filled;
-//         //                 if long_pos >= new_order.amount {
-//         //                     vir_order_filled = new_order.amount;
-//         //                 } else {
-//         //                     vir_order_filled = long_pos
-//         //                 }
-//         //                 // 构造虚拟订单
-//         //                 let vir_client_id = format!("{}vir", new_order.client_id.clone());
-//         //                 let vir_order = OrderInfo {
-//         //                     symbol: "".to_string(),
-//         //                     amount: vir_order_filled,
-//         //                     side: "pd".to_string(),
-//         //                     price: new_order.price,
-//         //                     client_id: vir_client_id.clone(),
-//         //                     filled_price: new_order.price,
-//         //                     filled: vir_order_filled,
-//         //                     order_id: "".to_string(),
-//         //                     local_time: 0,
-//         //                     create_time: 0,
-//         //                     status: new_order.status.clone(),
-//         //                     fee: Default::default(),
-//         //                     trace_stack: trace_stack.clone(),
-//         //                 };
-//         //                 core.local_orders_backup.insert(vir_client_id.clone(), vir_order.clone());
-//         //
-//         //                 // 原始订单处理
-//         //                 new_order.amount -= vir_order_filled;
-//         //                 new_order.filled -= vir_order_filled;
-//         //
-//         //                 rst.push(vir_order.clone());
-//         //                 if new_order.amount > Decimal::ZERO {
-//         //                     rst.push(new_order.clone());
-//         //                 } else {
-//         //                     core.local_cancel_log.remove(&new_order.client_id);
-//         //                     core.local_orders_backup.remove(&new_order.client_id);
-//         //                     core.local_orders.remove(&new_order.client_id);
-//         //                 }
-//         //             } else {
-//         //                 rst.push(new_order.clone());
-//         //             }
-//         //         }
-//         //         _ => {
-//         //             rst = order_infos;
-//         //         }
-//         //     }
-//         //
-//         //     core.update_order(rst, trace_stack).await;
-//         // }
-//         // "position.update" => {
-//         //     // info!("coinex_usdt_swap 仓位推送:{:?}", response.data);
-//         //     let positions = standard::handle_info::HandleSwapInfo::handle_position(CoinexSwap, &response, multiplier);
-//         //     let mut core = core_arc_clone.lock().await;
-//         //
-//         //     core.update_position(positions).await;
-//         // }
-//         // "deals.update" => {
-//         //     // let mut core = core_arc_clone.lock().await;
-//         //     // let str = data.label.clone();
-//         //     // if core.is_update.contains_key(&data.label) && *core.is_update.get(str.as_str()).unwrap(){
-//         //     //     *max_buy = Decimal::ZERO;
-//         //     //     *min_sell = Decimal::ZERO;
-//         //     //     core.is_update.remove(str.as_str());
-//         //     // }
-//         //     // let trades: Vec<OriginalTradeGa> = serde_json::from_str(data.data.as_str()).unwrap();
-//         //     // for trade in trades {
-//         //     //     if trade.price > *max_buy || *max_buy == Decimal::ZERO{
-//         //     //         *max_buy = trade.price
-//         //     //     }
-//         //     //     if trade.price < *min_sell || *min_sell == Decimal::ZERO{
-//         //     //         *min_sell = trade.price
-//         //     //     }
-//         //     // }
-//         //     // core.max_buy_min_sell_cache.insert(data.label, vec![*max_buy, *min_sell]);
-//         // }
-//         _ => {
-//             error!("未知推送类型");
-//             error!(?response);
-//         }
-//     }
-// }
-//
-// fn parse_btree_map_to_coinex_swap_login(exchange_params: BTreeMap<String, String>) -> CoinexSwapLogin {
-//     CoinexSwapLogin {
-//         api_key: exchange_params.get("access_key").unwrap().clone(),
-//         secret: exchange_params.get("secret_key").unwrap().clone()
-//     }
-// }
+use crate::core::Core;
+
+// 1交易、0参考 coinex 合约 启动
+pub async fn coinex_swap_run(is_shutdown_arc: Arc<AtomicBool>,
+                           is_trade: bool,
+                           core_arc: Arc<Mutex<Core>>,
+                           name: String,
+                           symbols: Vec<String>,
+                           _is_colo: bool,
+                           exchange_params: BTreeMap<String, String>) {
+    let (write_tx, write_rx) = futures_channel::mpsc::unbounded();
+
+    let write_tx_am = Arc::new(Mutex::new(write_tx));
+    let symbols_clone = symbols.clone();
+    spawn(async move {
+        let mut ws;
+        // 交易
+        if is_trade {
+            let login_param = parse_btree_map_to_coinex_swap_login(exchange_params);
+            ws = CoinexSwapWs::new_label(name.clone(), Some(login_param));
+            ws.set_subscribe(vec![
+                // CoinexSwapSubscribeType::PuFuturesDeals,
+                CoinexSwapSubscribeType::PuFuturesDepth,
+
+                CoinexSwapSubscribeType::PrFuturesOrders,
+                CoinexSwapSubscribeType::PrFuturesPositions,
+                CoinexSwapSubscribeType::PrFuturesBalances,
+            ]);
+        } else { // 参考
+            ws = CoinexSwapWs::new_label(name.clone(), None);
+            ws.set_subscribe(vec![
+                // CoinexSwapSubscribeType::PuFuturesDeals,
+                CoinexSwapSubscribeType::PuFuturesDepth
+            ]);
+        }
+
+        // 读取数据
+        let mut update_flag_u = Decimal::ZERO;
+        let core_arc_clone = Arc::clone(&core_arc);
+        let multiplier = core_arc_clone.lock().await.platform_rest.get_self_market().multiplier;
+        let run_symbol = symbols.clone()[0].clone();
+
+        let fun = move |data: ResponseData| {
+            let core_arc_cc = core_arc_clone.clone();
+            // 在 async 块之前克隆 Arc
+            let mul = multiplier.clone();
+            let rs = run_symbol.clone();
+
+            async move {
+                on_data(core_arc_cc,
+                        &mut update_flag_u,
+                        &mul,
+                        &rs,
+                        data,
+                ).await
+            }
+        };
+
+        // 建立链接
+        ws.set_symbols(symbols_clone);
+        ws.ws_connect_async(is_shutdown_arc, fun, &write_tx_am, write_rx).await.expect("链接失败(内部一个心跳线程应该已经关闭了)");
+    });
+}
+
+async fn on_data(_core_arc_clone: Arc<Mutex<Core>>,
+                 _update_flag_u: &mut Decimal,
+                 _multiplier: &Decimal,
+                 _run_symbol: &String,
+                 response: ResponseData) {
+    let mut trace_stack = TraceStack::new(response.time, response.ins);
+    trace_stack.on_after_span_line();
+
+    match response.channel.as_str() {
+        // "depth.update" => {
+        //     trace_stack.set_source("coinex_usdt_swap.order_book".to_string());
+        //     let special_depth = standard::handle_info::HandleSwapInfo::handle_special_depth(CoinexSwap, &response);
+        //     trace_stack.on_after_format();
+        //
+        //     on_special_depth(core_arc_clone, update_flag_u, &response.label, &mut trace_stack, &special_depth).await;
+        // }
+        // "balance.update" => {
+        //     let account = standard::handle_info::HandleSwapInfo::handle_account_info(CoinexSwap, &response, run_symbol);
+        //     let mut core = core_arc_clone.lock().await;
+        //     core.update_equity(account).await;
+        // }
+        // "order.update" => {
+        //     trace_stack.set_source("coinex_swap.orders".to_string());
+        //     let orders = standard::handle_info::HandleSwapInfo::handle_order(CoinexSwap, response.clone(), multiplier.clone());
+        //     let mut order_infos:Vec<OrderInfo> = Vec::new();
+        //     for mut order in orders.order {
+        //         if order.status == "NULL" {
+        //             error!("coinex_usdt_swap 未识别的订单状态:{:?}", response);
+        //             continue;
+        //         }
+        //
+        //         let order_info = OrderInfo::parse_order_to_order_info(&mut order);
+        //         order_infos.push(order_info);
+        //     }
+        //
+        //     if order_infos.is_empty() {
+        //         error!("coinex_usdt_swap 未识别的订单 格式化失败:{:?}", response);
+        //         return
+        //     }
+        //     let mut new_order = order_infos[0].clone();
+        //     let mut core = core_arc_clone.lock().await;
+        //     // 本地订单缓存判断
+        //     if !core.local_orders_backup.contains_key(&new_order.client_id) {
+        //         return
+        //     }
+        //
+        //     // 获取订单目的
+        //     let mut rst = vec![];
+        //     let side = core.local_orders_backup.get(&new_order.client_id).unwrap().side.as_str();
+        //     let local_position_by_orders = &core.local_position_by_orders;
+        //     let long_pos = local_position_by_orders.long_pos;
+        //     let short_pos = local_position_by_orders.short_pos;
+        //
+        //     // 部分成交和新订单的处理,不用走下面的逻辑
+        //     if new_order.status != "REMOVE" || new_order.filled == Decimal::ZERO {
+        //         core.update_order(order_infos, trace_stack).await;
+        //         return
+        //     }
+        //
+        //     // 单向持仓的处理
+        //     match side {
+        //         "kd" => {
+        //             if short_pos != Decimal::ZERO {
+        //                 let vir_order_filled;
+        //                 if short_pos >= new_order.amount {
+        //                     vir_order_filled = new_order.amount;
+        //                 } else {
+        //                     vir_order_filled = short_pos
+        //                 }
+        //                 // 构造虚拟订单
+        //                 let vir_client_id = format!("{}vir", new_order.client_id.clone());
+        //                 let vir_order = OrderInfo {
+        //                     symbol: "".to_string(),
+        //                     amount: vir_order_filled,
+        //                     side: "pk".to_string(),
+        //                     price: new_order.price,
+        //                     client_id: vir_client_id.clone(),
+        //                     filled_price: new_order.price,
+        //                     filled: vir_order_filled,
+        //                     order_id: "".to_string(),
+        //                     local_time: 0,
+        //                     create_time: 0,
+        //                     status: new_order.status.clone(),
+        //                     fee: Default::default(),
+        //                     trace_stack: trace_stack.clone(),
+        //                 };
+        //                 core.local_orders_backup.insert(vir_client_id.clone(), vir_order.clone());
+        //
+        //                 // 原始订单处理
+        //                 new_order.amount -= vir_order_filled;
+        //                 new_order.filled -= vir_order_filled;
+        //
+        //                 rst.push(vir_order.clone());
+        //                 if new_order.amount > Decimal::ZERO {
+        //                     rst.push(new_order.clone());
+        //                 } else {
+        //                     core.local_cancel_log.remove(&new_order.client_id);
+        //                     core.local_orders_backup.remove(&new_order.client_id);
+        //                     core.local_orders.remove(&new_order.client_id);
+        //                 }
+        //             } else {
+        //                 rst.push(new_order.clone());
+        //             }
+        //         }
+        //         "kk" => {
+        //             if long_pos != Decimal::ZERO {
+        //                 let vir_order_filled;
+        //                 if long_pos >= new_order.amount {
+        //                     vir_order_filled = new_order.amount;
+        //                 } else {
+        //                     vir_order_filled = long_pos
+        //                 }
+        //                 // 构造虚拟订单
+        //                 let vir_client_id = format!("{}vir", new_order.client_id.clone());
+        //                 let vir_order = OrderInfo {
+        //                     symbol: "".to_string(),
+        //                     amount: vir_order_filled,
+        //                     side: "pd".to_string(),
+        //                     price: new_order.price,
+        //                     client_id: vir_client_id.clone(),
+        //                     filled_price: new_order.price,
+        //                     filled: vir_order_filled,
+        //                     order_id: "".to_string(),
+        //                     local_time: 0,
+        //                     create_time: 0,
+        //                     status: new_order.status.clone(),
+        //                     fee: Default::default(),
+        //                     trace_stack: trace_stack.clone(),
+        //                 };
+        //                 core.local_orders_backup.insert(vir_client_id.clone(), vir_order.clone());
+        //
+        //                 // 原始订单处理
+        //                 new_order.amount -= vir_order_filled;
+        //                 new_order.filled -= vir_order_filled;
+        //
+        //                 rst.push(vir_order.clone());
+        //                 if new_order.amount > Decimal::ZERO {
+        //                     rst.push(new_order.clone());
+        //                 } else {
+        //                     core.local_cancel_log.remove(&new_order.client_id);
+        //                     core.local_orders_backup.remove(&new_order.client_id);
+        //                     core.local_orders.remove(&new_order.client_id);
+        //                 }
+        //             } else {
+        //                 rst.push(new_order.clone());
+        //             }
+        //         }
+        //         _ => {
+        //             rst = order_infos;
+        //         }
+        //     }
+        //
+        //     core.update_order(rst, trace_stack).await;
+        // }
+        // "position.update" => {
+        //     // info!("coinex_usdt_swap 仓位推送:{:?}", response.data);
+        //     let positions = standard::handle_info::HandleSwapInfo::handle_position(CoinexSwap, &response, multiplier);
+        //     let mut core = core_arc_clone.lock().await;
+        //
+        //     core.update_position(positions).await;
+        // }
+        // "deals.update" => {
+        //     // let mut core = core_arc_clone.lock().await;
+        //     // let str = data.label.clone();
+        //     // if core.is_update.contains_key(&data.label) && *core.is_update.get(str.as_str()).unwrap(){
+        //     //     *max_buy = Decimal::ZERO;
+        //     //     *min_sell = Decimal::ZERO;
+        //     //     core.is_update.remove(str.as_str());
+        //     // }
+        //     // let trades: Vec<OriginalTradeGa> = serde_json::from_str(data.data.as_str()).unwrap();
+        //     // for trade in trades {
+        //     //     if trade.price > *max_buy || *max_buy == Decimal::ZERO{
+        //     //         *max_buy = trade.price
+        //     //     }
+        //     //     if trade.price < *min_sell || *min_sell == Decimal::ZERO{
+        //     //         *min_sell = trade.price
+        //     //     }
+        //     // }
+        //     // core.max_buy_min_sell_cache.insert(data.label, vec![*max_buy, *min_sell]);
+        // }
+        _ => {
+            error!("未知推送类型");
+            error!(?response);
+        }
+    }
+}
+
+fn parse_btree_map_to_coinex_swap_login(exchange_params: BTreeMap<String, String>) -> CoinexSwapLogin {
+    CoinexSwapLogin {
+        api_key: exchange_params.get("access_key").unwrap().clone(),
+        secret: exchange_params.get("secret_key").unwrap().clone()
+    }
+}

+ 4 - 4
strategy/src/core.rs

@@ -20,7 +20,7 @@ use global::params::Params;
 use global::trace_stack::TraceStack;
 use standard::{Account, Depth, Market, Order, OrderCommand, Platform, Position, PositionModeEnum, SpecialTicker, Ticker, Trade};
 use standard::exchange::{Exchange};
-use standard::exchange::ExchangeEnum::{BinanceSwap, GateSwap};
+use standard::exchange::ExchangeEnum::{BinanceSwap, BybitSwap, GateSwap};
 
 use crate::model::{LocalPosition, OrderInfo, TokenParam};
 use crate::avellaneda_stoikov::AvellanedaStoikov;
@@ -215,9 +215,9 @@ impl Core {
                 // "okex_usdt_swap" => {
                 //     Exchange::new(OkxSwap, symbol, params.colo != 0i8, exchange_params, order_sender, error_sender).await
                 // }
-                // "bybit_usdt_swap" => {
-                //     Exchange::new(BybitSwap, symbol, params.colo != 0i8, exchange_params, order_sender, error_sender).await
-                // }
+                "bybit_usdt_swap" => {
+                    Exchange::new(BybitSwap, symbol, params.colo != 0i8, exchange_params, order_sender, error_sender).await
+                }
                 // "coinex_usdt_swap" => {
                 //     Exchange::new(CoinexSwap, symbol, params.colo != 0i8, exchange_params, order_sender, error_sender).await
                 // }

+ 14 - 14
strategy/src/exchange_disguise.rs

@@ -5,6 +5,8 @@ use tokio::sync::Mutex;
 use global::trace_stack::TraceStack;
 use standard::{Depth, Trade};
 use crate::binance_usdt_swap::{binance_swap_run, reference_binance_swap_run};
+use crate::bybit_usdt_swap::{bybit_swap_run, reference_bybit_swap_run};
+use crate::coinex_usdt_swap::coinex_swap_run;
 use crate::gate_usdt_swap::gate_swap_run;
 use crate::core::Core;
 
@@ -35,13 +37,12 @@ pub async fn run_transactional_exchange(is_shutdown_arc :Arc<AtomicBool>,
         // "bitget_usdt_swap" => {
         //     bitget_usdt_swap_run(is_shutdown_arc, true, core_arc, name, symbols, is_colo, exchange_params).await;
         // }
-        // "bybit_usdt_swap" => {
-        //     bybit_swap_run(is_shutdown_arc,true, core_arc, name, symbols, is_colo, exchange_params).await;
-        // }
-        // "coinex_usdt_swap" => {
-        //     tokio::time::sleep(Duration::from_secs(1)).await;
-        //     coinex_swap_run(is_shutdown_arc,true, core_arc, name, symbols, is_colo, exchange_params).await;
-        // }
+        "bybit_usdt_swap" => {
+            bybit_swap_run(is_shutdown_arc, core_arc, name, symbols, is_colo, exchange_params).await;
+        }
+        "coinex_usdt_swap" => {
+            coinex_swap_run(is_shutdown_arc,true, core_arc, name, symbols, is_colo, exchange_params).await;
+        }
         // "htx_usdt_swap" =>{
         //     htx_swap_run(is_shutdown_arc,true, core_arc, name, symbols, is_colo, exchange_params).await;
         // }
@@ -85,13 +86,12 @@ pub async fn run_reference_exchange(is_shutdown_arc: Arc<AtomicBool>,
         // "bitget_usdt_swap" => {
         //     bitget_usdt_swap_run(is_shutdown_arc, false, core_arc, name, symbols, is_colo, exchange_params).await;
         // }
-        // "bybit_usdt_swap" => {
-        //     bybit_swap_run(is_shutdown_arc, false, core_arc, name, symbols, is_colo, exchange_params).await;
-        // },
-        // "coinex_usdt_swap" => {
-        //     coinex_swap_run(is_shutdown_arc,false, core_arc, name, symbols, is_colo, exchange_params).await;
-        //
-        // }
+        "bybit_usdt_swap" => {
+            reference_bybit_swap_run(is_shutdown_arc,  core_arc, name, symbols, is_colo).await;
+        },
+        "coinex_usdt_swap" => {
+            coinex_swap_run(is_shutdown_arc,false, core_arc, name, symbols, is_colo, exchange_params).await;
+        }
         // "htx_usdt_swap" =>{
         //     htx_swap_run(is_shutdown_arc, false, core_arc, name, symbols, is_colo, exchange_params).await;
         // }

+ 0 - 2
strategy/src/gate_usdt_swap.rs

@@ -111,8 +111,6 @@ async fn on_data(core_arc: Arc<Mutex<Core>>,
             let depth = ExchangeStructHandler::book_ticker_handle(ExchangeEnum::GateSwap, response, multiplier);
             trace_stack.on_after_format();
 
-            let mp = (depth.asks[0].price + depth.bids[0].price) / Decimal::TWO;
-            core_arc.lock().await.strategy.min_amount_value = multiplier * mp;
             on_depth(core_arc, &response.label, &mut trace_stack, &depth).await;
         }
         "futures.trades" => {

+ 30 - 25
strategy/src/strategy.rs

@@ -826,35 +826,32 @@ impl Strategy {
     pub fn _cancel_open(&self, command: &mut OrderCommand, local_orders: &HashMap<String, OrderInfo>) {
         // debug!(?command);
         // 挂单范围
-        // let long_upper = self.open_dist[0];
-        // let long_lower = self.open_dist[1];
-        // let short_lower = self.open_dist[2];
-        // let short_upper = self.open_dist[3];
+        let long_upper = self.open_dist[0];
+        let long_lower = self.open_dist[1];
+        let short_lower = self.open_dist[2];
+        let short_upper = self.open_dist[3];
 
         for order_client_id in local_orders.keys() {
             let order = local_orders.get(order_client_id).unwrap();
             let key = format!("Cancel{}", *order_client_id);
             let value = vec![order.client_id.clone(), order.order_id.clone()];
 
-            if self.local_time - order.local_time > 100 {
+            // 开多订单处理
+            if order.side == "kd".to_string() {
+                // 在价格范围内时不处理
+                if (order.price <= long_upper && order.price >= long_lower) || self.local_time - order.local_time <= 100 {
+                    continue
+                }
+                // debug!(?key, ?order.price, ?long_upper, ?long_lower);
+                command.cancel.insert(key, value);
+            } else if order.side == "kk".to_string() { // 开空订单处理
+                // 在价格范围内时不处理
+                if (order.price >= short_lower && order.price <= short_upper) || self.local_time - order.local_time <= 100 {
+                    continue
+                }
+                // debug!(?key, ?order.price, ?short_lower, ?short_upper);
                 command.cancel.insert(key, value);
             }
-            // // 开多订单处理
-            // if order.side == "kd".to_string() {
-            //     // 在价格范围内时不处理
-            //     if order.price <= long_upper && order.price >= long_lower {
-            //         continue
-            //     }
-            //     // debug!(?key, ?order.price, ?long_upper, ?long_lower);
-            //     command.cancel.insert(key, value);
-            // } else if order.side == "kk".to_string() { // 开空订单处理
-            //     // 在价格范围内时不处理
-            //     if order.price >= short_lower && order.price <= short_upper {
-            //         continue
-            //     }
-            //     // debug!(?key, ?order.price, ?short_lower, ?short_upper);
-            //     command.cancel.insert(key, value);
-            // }
         }
     }
 
@@ -956,10 +953,14 @@ impl Strategy {
             let mut target_buy_price = predictor.optimal_bid_price;
             // target_buy_price = utils::clip(target_buy_price, self.bp * dec!(0.97), self.ap * dec!(1.0005));
             target_buy_price = utils::fix_price(target_buy_price, self.tick_size);
-            let amount = utils::get_amount_by_min_amount_value(self.min_amount_value, target_buy_price, self.step_size);
+            let amount = if predictor.inventory <= dec!(-3) {
+                utils::get_amount_by_min_amount_value(self.min_amount_value * predictor.inventory.abs(), target_buy_price, self.step_size)
+            } else {
+                utils::get_amount_by_min_amount_value(self.min_amount_value, target_buy_price, self.step_size)
+            };
             // let amount = if predictor.inventory < Decimal::ZERO {
             //     // utils::fix_amount(self.step_size * predictor.inventory.abs(), self.step_size)
-            //     if predictor.level >= dec!(4) {
+            //     if predictor.level >= dec!(3) {
             //         utils::get_amount_by_min_amount_value(self.min_amount_value * predictor.inventory.abs(), target_buy_price, self.step_size)
             //     } else {
             //         utils::get_amount_by_min_amount_value(self.min_amount_value * predictor.level, target_buy_price, self.step_size)
@@ -993,9 +994,13 @@ impl Strategy {
             // target_sell_price = utils::clip(target_sell_price, self.bp * dec!(0.9995), self.ap * dec!(1.03));
             // 取消大小限制
             target_sell_price = utils::fix_price(target_sell_price, self.tick_size);
-            let amount = utils::get_amount_by_min_amount_value(self.min_amount_value, target_sell_price, self.step_size);
+            let amount = if predictor.inventory >= dec!(3) {
+                utils::get_amount_by_min_amount_value(self.min_amount_value * predictor.inventory.abs(), target_sell_price, self.step_size)
+            } else {
+                utils::get_amount_by_min_amount_value(self.min_amount_value, target_sell_price, self.step_size)
+            };
             // let amount = if predictor.inventory > Decimal::ZERO {
-            //     if predictor.level >= dec!(4) {
+            //     if predictor.level >= dec!(3) {
             //         utils::get_amount_by_min_amount_value(self.min_amount_value * predictor.inventory.abs(), target_sell_price, self.step_size)
             //     } else {
             //         utils::get_amount_by_min_amount_value(self.min_amount_value * predictor.level, target_sell_price, self.step_size)