Browse Source

mexc合约加入,基础语法通过了,明天慢慢查吧。

skyfffire 3 months ago
parent
commit
7601e9efb0

+ 20 - 50
exchanges/src/mexc_swap_ws.rs

@@ -35,6 +35,8 @@ pub struct MexcSwapWsParam {
 pub enum MexcSwapSubscribeType {
     // 深度
     PuFuturesDepth,
+    // 深度
+    PuFuturesDepthFull(i64),
     // 公开成交
     PuFuturesTrades,
     // K线数据
@@ -131,9 +133,10 @@ impl MexcSwapWs {
     fn contains_pr(&self) -> bool {
         for t in self.subscribe_types.clone() {
             if match t {
+                MexcSwapSubscribeType::PuFuturesDepth => false,
+                MexcSwapSubscribeType::PuFuturesDepthFull(_) => false,
                 MexcSwapSubscribeType::PuFuturesTrades => false,
                 MexcSwapSubscribeType::PuFuturesRecords => false,
-                MexcSwapSubscribeType::PuFuturesDepth => false,
             } {
                 return true;
             }
@@ -146,12 +149,21 @@ impl MexcSwapWs {
     //订阅枚举解析
     pub fn enum_to_string(symbol: String, subscribe_type: MexcSwapSubscribeType) -> Value {
         match subscribe_type {
-            MexcSwapSubscribeType::PuFuturesDepth => {//深度
+            MexcSwapSubscribeType::PuFuturesDepth => {//增量深度
                 json!({
                    "method":"sub.depth",
                    "param":{ "symbol":symbol }
                 })
             }
+            MexcSwapSubscribeType::PuFuturesDepthFull(limit) => {//全量深度
+                json!({
+                   "method":"sub.depth.full",
+                   "param":{
+                        "symbol":symbol,
+                        "limit":limit,
+                    }
+                })
+            }
             MexcSwapSubscribeType::PuFuturesRecords => {//k线
                 json!({
                     "method":"sub.kline",
@@ -197,16 +209,6 @@ impl MexcSwapWs {
         let subscription = self.get_subscription();
         let address_url = self.address_url.clone();
         let tag = self.tag.clone();
-        // let heartbeat_time = self.ws_param.ws_ping_interval.clone();
-
-        //心跳-- 方法内部线程启动
-        // let write_tx_clone1 = write_tx_am.clone();
-        // tokio::spawn(async move {
-        //     trace!("线程-异步心跳-开始");
-        //     AbstractWsMode::ping_or_pong(write_tx_clone1, HeartbeatType::Ping, heartbeat_time as u64).await;
-        //     trace!("线程-异步心跳-结束");
-        // });
-
 
         //设置订阅
         let subscribe_array = subscription.clone();
@@ -244,11 +246,11 @@ impl MexcSwapWs {
     }
     //数据解析-ping
     pub fn message_ping(_pi: Vec<u8>) -> Option<ResponseData> {
-        return Option::from(ResponseData::new("".to_string(), -300, "success".to_string(), Value::Null));
+        Option::from(ResponseData::new("".to_string(), -300, "success".to_string(), Value::Null))
     }
     //数据解析-pong
     pub fn message_pong(_po: Vec<u8>) -> Option<ResponseData> {
-        return Option::from(ResponseData::new("".to_string(), -301, "success".to_string(), Value::Null));
+        Option::from(ResponseData::new("".to_string(), -301, "success".to_string(), Value::Null))
     }
     //数据解析-二进制
     pub fn message_binary(po: Vec<u8>) -> Option<ResponseData> {
@@ -267,14 +269,14 @@ impl MexcSwapWs {
             match String::from_utf8(decompressed_data) {
                 Ok(text) => {
                     let response_data = Self::ok_text(text);
-                    return Option::from(response_data);
+                    Option::from(response_data)
                 }
                 Err(_) => {
-                    return Option::from(ResponseData::new("".to_string(), 400, "二进制数据转化出错".to_string(), Value::Null));
+                    Option::from(ResponseData::new("".to_string(), 400, "二进制数据转化出错".to_string(), Value::Null))
                 }
             }
         } else {
-            return Option::from(ResponseData::new("".to_string(), 400, "二进制数据转化出错".to_string(), Value::Null));
+            Option::from(ResponseData::new("".to_string(), 400, "二进制数据转化出错".to_string(), Value::Null))
         }
     }
     //数据解析
@@ -282,7 +284,7 @@ impl MexcSwapWs {
     {
         // trace!("原始数据:{:?}",text);
         let mut res_data = ResponseData::new("".to_string(), 200, "success".to_string(), Value::Null);
-        let json_value: serde_json::Value = serde_json::from_str(&text).unwrap();
+        let json_value: Value = serde_json::from_str(&text).unwrap();
 
         match json_value["channel"].as_str() {
             Some(method) => {
@@ -330,38 +332,6 @@ impl MexcSwapWs {
                 res_data.message = "未知解析".to_string();
             }
         }
-        //
-        // if json_value["method"].as_str() == Option::from("id1") {}
-        //
-        // // { "id": "id1", "code": 0, "msg": "" }
-        // if json_value["id"].as_str() == Option::from("id1") {
-        //     //订阅
-        //     if json_value["code"].as_i64() == Option::from(0) {
-        //         res_data.code = -201;
-        //         res_data.message = "订阅成功".to_string();
-        //     } else {
-        //         res_data.code = 400;
-        //         res_data.message = "订阅失败".to_string();
-        //     }
-        // } else if json_value["code"].as_i64() == Option::from(0) {
-        //     res_data.code = 200;
-        //     res_data.data = json_value.clone();
-        //
-        //     //订阅数据 甄别
-        //     let dataType = json_value["dataType"].as_str().unwrap();
-        //     if dataType.contains("@depth") {
-        //         res_data.channel = "futures.order_book".to_string();
-        //     } else if dataType.contains("@trade") {
-        //         res_data.channel = "futures.trades".to_string();
-        //     } else if dataType.contains("@kline_1m") {
-        //         res_data.channel = "futures.candlesticks".to_string();
-        //     } else {
-        //         res_data.channel = "未知推送数据".to_string();
-        //     }
-        // } else {
-        //     res_data.code = -1;
-        //     res_data.message = "未知解析".to_string();
-        // }
 
         res_data
     }

+ 6 - 4
standard/src/exchange.rs

@@ -7,6 +7,7 @@ use crate::bitget_swap::BitgetSwap;
 use crate::bybit_swap::BybitSwap;
 use crate::coinex_swap::CoinexSwap;
 use crate::gate_swap::GateSwap;
+use crate::mexc_swap::MexcSwap;
 
 /// 交易所交易模式枚举
 /// - `BinanceSwap`: Binance交易所期货;
@@ -34,7 +35,8 @@ pub enum ExchangeEnum {
     // CoinsphSwap,
     // PhemexSwap,
     // WooSwap,
-    // CointrSwap
+    // CointrSwap,
+    MexcSwap,
 }
 
 /// Exchange结构体
@@ -115,9 +117,9 @@ impl Exchange {
             // ExchangeEnum::BingxSwap => {
             //     Box::new(BingxSwap::new(symbol, is_colo, params, order_sender, error_sender).await)
             // }
-            // ExchangeEnum::MexcSwap => {
-            //     Box::new(MexcSwap::new(symbol, is_colo, params, order_sender, error_sender).await)
-            // }
+            ExchangeEnum::MexcSwap => {
+                Box::new(MexcSwap::new(symbol, is_colo, params, order_sender, error_sender).await)
+            }
             // ExchangeEnum::BitMartSwap => {
             //     Box::new(BitMartSwap::new(symbol, is_colo, params, order_sender, error_sender).await)
             // }

+ 4 - 4
standard/src/exchange_struct_handler.rs

@@ -151,10 +151,10 @@ impl ExchangeStructHandler {
             // ExchangeEnum::CointrSwap => {
             //     cointr_swap_handle::format_trade_items(&res_data)
             // }
-            // _ => {
-            //     error!("未找到该交易所!trades_handle: {:?}", exchange);
-            //     panic!("未找到该交易所!trades_handle: {:?}", exchange);
-            // }
+            _ => {
+                error!("未找到该交易所!trades_handle: {:?}", exchange);
+                panic!("未找到该交易所!trades_handle: {:?}", exchange);
+            }
         }
     }
     // 处理BookTicker信息

+ 270 - 261
standard/src/mexc_swap.rs

@@ -1,261 +1,270 @@
-// use std::collections::{BTreeMap};
-// use std::io::{Error, ErrorKind};
-// use tokio::sync::mpsc::Sender;
-// use async_trait::async_trait;
-// use rust_decimal::{Decimal};
-// use serde_json::{json, Value};
-// use tracing::{error, info};
-// use crate::{Platform, ExchangeEnum, Account, Position, Ticker, Market, Order, utils};
-// use exchanges::mexc_swap_rest::MexcSwapRest;
-// use rust_decimal::prelude::FromPrimitive;
-//
-// #[allow(dead_code)]
-// #[derive(Clone)]
-// pub struct MexcSwap {
-//     exchange: ExchangeEnum,
-//     symbol: String,
-//     is_colo: bool,
-//     params: BTreeMap<String, String>,
-//     request: MexcSwapRest,
-//     market: Market,
-//     order_sender: Sender<Order>,
-//     error_sender: Sender<Error>,
-// }
-//
-// impl MexcSwap {
-//     pub async fn new(symbol: String, is_colo: bool, params: BTreeMap<String, String>, order_sender: Sender<Order>, error_sender: Sender<Error>) -> MexcSwap {
-//         let market = Market::new();
-//         let mut mexc_swap = MexcSwap {
-//             exchange: ExchangeEnum::MexcSwap,
-//             symbol: symbol.to_uppercase(),
-//             is_colo,
-//             params: params.clone(),
-//             request: MexcSwapRest::new(is_colo, params.clone()),
-//             market,
-//             order_sender,
-//             error_sender,
-//         };
-//
-//         // 修改持仓模式
-//         let symbol_array: Vec<&str> = symbol.split("_").collect();
-//         let mode_result = mexc_swap.set_dual_mode(symbol_array[1], true).await;
-//         match mode_result {
-//             Ok(ok) => {
-//                 info!("Mexc:设置持仓模式成功!{:?}", ok);
-//             }
-//             Err(error) => {
-//                 error!("Mexc:设置持仓模式失败!mode_result={}", error)
-//             }
-//         }
-//         // 获取市场信息
-//         mexc_swap.market = MexcSwap::get_market(&mut mexc_swap).await.unwrap_or(mexc_swap.market);
-//         return mexc_swap;
-//     }
-// }
-//
-// #[async_trait]
-// impl Platform for MexcSwap {
-//     // 克隆方法
-//     fn clone_box(&self) -> Box<dyn Platform + Send + Sync> { Box::new(self.clone()) }
-//     // 获取交易所模式
-//     fn get_self_exchange(&self) -> ExchangeEnum {
-//         ExchangeEnum::MexcSwap
-//     }
-//     // 获取交易对
-//     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> {
-//         Err(Error::new(ErrorKind::NotFound, "mexc_swap:该交易所方法未实现".to_string()))
-//     }
-//     // 获取账号信息
-//     async fn get_account(&mut self) -> Result<Account, Error> {
-//         Err(Error::new(ErrorKind::NotFound, "mexc_swap:该交易所方法未实现".to_string()))
-//     }
-//
-//     async fn get_spot_account(&mut self) -> Result<Vec<Account>, Error> {
-//         Err(Error::new(ErrorKind::NotFound, "mexc_swap:该交易所方法未实现".to_string()))
-//     }
-//
-//     // 获取持仓信息
-//     async fn get_position(&mut self) -> Result<Vec<Position>, Error> {
-//         Err(Error::new(ErrorKind::NotFound, "mexc_swap:该交易所方法未实现".to_string()))
-//     }
-//     // 获取所有持仓
-//     async fn get_positions(&mut self) -> Result<Vec<Position>, Error> {
-//         Err(Error::new(ErrorKind::NotFound, "mexc_swap:该交易所方法未实现".to_string()))
-//     }
-//     // 获取市场行情
-//     async fn get_ticker(&mut self) -> Result<Ticker, Error> {
-//         Err(Error::new(ErrorKind::NotFound, "mexc_swap:该交易所方法未实现".to_string()))
-//     }
-//
-//     async fn get_ticker_symbol(&mut self, _symbol: String) -> Result<Ticker, Error> {
-//         Err(Error::new(ErrorKind::NotFound, "mexc_swap:该交易所方法未实现".to_string()))
-//     }
-//
-//     async fn get_market(&mut self) -> Result<Market, Error> {
-//         let symbol_format = utils::format_symbol(self.symbol.clone(), "_");
-//         let params = json!({});
-//         let res_data = self.request.get_market(params).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["symbol"].as_str().unwrap() == symbol_format);
-//             match market_info {
-//                 None => {
-//                     error!("mexc_swap:获取Market信息错误!\nget_market:res_data={:?}", res_data);
-//                     Err(Error::new(ErrorKind::Other, res_data.to_string()))
-//                 }
-//                 Some(value) => {
-//                     let symbol = value["symbol"].as_str().unwrap().to_string();
-//                     let base_asset = value["baseCoin"].as_str().unwrap().to_string();
-//                     let quote_asset = value["quoteCoin"].as_str().unwrap().to_string();
-//                     let tick_size = Decimal::from_i64(value["priceUnit"].as_i64().unwrap()).unwrap();
-//                     let amount_size = Decimal::from_i64(value["volUnit"].as_i64().unwrap()).unwrap();
-//                     let price_precision = Decimal::from_i64(value["priceScale"].as_i64().unwrap()).unwrap();
-//                     let amount_precision = Decimal::from_i64(value["volScale"].as_i64().unwrap()).unwrap();
-//                     let min_qty = Decimal::from_i64(value["minVol"].as_i64().unwrap()).unwrap();
-//                     let max_qty = Decimal::from_i64(value["maxVol"].as_i64().unwrap()).unwrap();
-//                     let ct_val = Decimal::from_i64(value["contractSize"].as_i64().unwrap()).unwrap();
-//
-//                     let result = Market {
-//                         symbol,
-//                         base_asset,
-//                         quote_asset,
-//                         tick_size,
-//                         amount_size,
-//                         price_precision,
-//                         amount_precision,
-//                         min_qty,
-//                         max_qty,
-//                         min_notional: min_qty,
-//                         max_notional: max_qty,
-//                         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_format = utils::format_symbol(symbol.clone(), "-");
-//         let params = json!({
-//             "symbol": symbol_format.clone()
-//         });
-//         let res_data = self.request.get_market(params).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["symbol"].as_str().unwrap() == symbol_format);
-//             match market_info {
-//                 None => {
-//                     error!("mexc_swap:获取Market信息错误!\nget_market:res_data={:?}", res_data);
-//                     Err(Error::new(ErrorKind::Other, res_data.to_string()))
-//                 }
-//                 Some(value) => {
-//                     let symbol = value["symbol"].as_str().unwrap().to_string();
-//                     let base_asset = value["baseCoin"].as_str().unwrap().to_string();
-//                     let quote_asset = value["quoteCoin"].as_str().unwrap().to_string();
-//                     let tick_size = Decimal::from_i64(value["priceUnit"].as_i64().unwrap()).unwrap();
-//                     let amount_size = Decimal::from_i64(value["volUnit"].as_i64().unwrap()).unwrap();
-//                     let price_precision = Decimal::from_i64(value["priceScale"].as_i64().unwrap()).unwrap();
-//                     let amount_precision = Decimal::from_i64(value["volScale"].as_i64().unwrap()).unwrap();
-//                     let min_qty = Decimal::from_i64(value["minVol"].as_i64().unwrap()).unwrap();
-//                     let max_qty = Decimal::from_i64(value["maxVol"].as_i64().unwrap()).unwrap();
-//                     let ct_val = Decimal::from_i64(value["contractSize"].as_i64().unwrap()).unwrap();
-//
-//                     let result = Market {
-//                         symbol,
-//                         base_asset,
-//                         quote_asset,
-//                         tick_size,
-//                         amount_size,
-//                         price_precision,
-//                         amount_precision,
-//                         min_qty,
-//                         max_qty,
-//                         min_notional: min_qty,
-//                         max_notional: max_qty,
-//                         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> {
-//         Err(Error::new(ErrorKind::NotFound, "mexc_swap:该交易所方法未实现".to_string()))
-//     }
-//     // 获取订单列表
-//     async fn get_orders_list(&mut self, _status: &str) -> Result<Vec<Order>, Error> {
-//         Err(Error::new(ErrorKind::NotFound, "mexc_swap:该交易所方法未实现".to_string()))
-//     }
-//     // 下单接口
-//     async fn take_order(&mut self, _custom_id: &str, _origin_side: &str, _price: Decimal, _amount: Decimal) -> Result<Order, Error> {
-//         Err(Error::new(ErrorKind::NotFound, "mexc_swap:该交易所方法未实现".to_string()))
-//     }
-//
-//     async fn take_order_symbol(&mut self, _symbol: String, _ct_val: Decimal, _custom_id: &str, _origin_side: &str, _price: Decimal, _amount: Decimal) -> Result<Order, Error> {
-//         Err(Error::new(ErrorKind::NotFound, "mexc_swap:该交易所方法未实现".to_string()))
-//     }
-//
-//     // 撤销订单
-//     async fn cancel_order(&mut self, _order_id: &str, _custom_id: &str) -> Result<Order, Error> {
-//         Err(Error::new(ErrorKind::NotFound, "mexc_swap:该交易所方法未实现".to_string()))
-//     }
-//     // 批量撤销订单
-//     async fn cancel_orders(&mut self) -> Result<Vec<Order>, Error> {
-//         Err(Error::new(ErrorKind::NotFound, "mexc_swap:该交易所方法未实现".to_string()))
-//     }
-//
-//     async fn cancel_orders_all(&mut self) -> Result<Vec<Order>, Error> {
-//         Err(Error::new(ErrorKind::NotFound, "mexc_swap:该交易所方法未实现".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, "mexc_swap:该交易所方法未实现".to_string()))
-//     }
-//
-//     async fn cancel_stop_loss_order(&mut self, _order_id: &str) -> Result<Value, Error> {
-//         Err(Error::new(ErrorKind::NotFound, "mexc_swap:该交易所方法未实现".to_string()))
-//     }
-//
-//     // 设置持仓模式
-//     async fn set_dual_mode(&mut self, _coin: &str, _is_dual_mode: bool) -> Result<String, Error> {
-//         Err(Error::new(ErrorKind::NotFound, "mexc_swap:该交易所方法未实现".to_string()))
-//     }
-//
-//     // 更新双持仓模式下杠杆
-//     async fn set_dual_leverage(&mut self, _leverage: &str) -> Result<String, Error> {
-//         Err(Error::new(ErrorKind::NotFound, "mexc_swap:该交易所方法未实现".to_string()))
-//     }
-//
-//     async fn set_auto_deposit_status(&mut self, _status: bool) -> Result<String, Error> { Err(Error::new(ErrorKind::NotFound, "mexc:该交易所方法未实现".to_string())) }
-//
-//     // 交易账户互转
-//     async fn wallet_transfers(&mut self, _coin: &str, _from: &str, _to: &str, _amount: Decimal) -> Result<String, Error> {
-//         Err(Error::new(ErrorKind::NotFound, "mexc_swap:该交易所方法未实现".to_string()))
-//     }
-// }
+use std::collections::{BTreeMap};
+use std::io::{Error, ErrorKind};
+use tokio::sync::mpsc::Sender;
+use async_trait::async_trait;
+use rust_decimal::{Decimal};
+use serde_json::{json, Value};
+use tracing::{error, info};
+use crate::{Platform, ExchangeEnum, Account, Position, Ticker, Market, Order, utils, Record, OrderCommand};
+use exchanges::mexc_swap_rest::MexcSwapRest;
+use rust_decimal::prelude::FromPrimitive;
+use global::trace_stack::TraceStack;
+
+#[allow(dead_code)]
+#[derive(Clone)]
+pub struct MexcSwap {
+    exchange: ExchangeEnum,
+    symbol: String,
+    is_colo: bool,
+    params: BTreeMap<String, String>,
+    request: MexcSwapRest,
+    market: Market,
+    order_sender: Sender<Order>,
+    error_sender: Sender<Error>,
+}
+
+impl MexcSwap {
+    pub async fn new(symbol: String, is_colo: bool, params: BTreeMap<String, String>, order_sender: Sender<Order>, error_sender: Sender<Error>) -> MexcSwap {
+        let market = Market::new();
+        let mut mexc_swap = MexcSwap {
+            exchange: ExchangeEnum::MexcSwap,
+            symbol: symbol.to_uppercase(),
+            is_colo,
+            params: params.clone(),
+            request: MexcSwapRest::new(is_colo, params.clone()),
+            market,
+            order_sender,
+            error_sender,
+        };
+
+        // 修改持仓模式
+        let symbol_array: Vec<&str> = symbol.split("_").collect();
+        let mode_result = mexc_swap.set_dual_mode(symbol_array[1], true).await;
+        match mode_result {
+            Ok(ok) => {
+                info!("Mexc:设置持仓模式成功!{:?}", ok);
+            }
+            Err(error) => {
+                error!("Mexc:设置持仓模式失败!mode_result={}", error)
+            }
+        }
+        // 获取市场信息
+        mexc_swap.market = MexcSwap::get_market(&mut mexc_swap).await.unwrap_or(mexc_swap.market);
+        return mexc_swap;
+    }
+}
+
+#[async_trait]
+impl Platform for MexcSwap {
+    // 克隆方法
+    fn clone_box(&self) -> Box<dyn Platform + Send + Sync> { Box::new(self.clone()) }
+    // 获取交易所模式
+    fn get_self_exchange(&self) -> ExchangeEnum {
+        ExchangeEnum::MexcSwap
+    }
+    // 获取交易对
+    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> {
+        Err(Error::new(ErrorKind::NotFound, "mexc_swap:该交易所方法未实现".to_string()))
+    }
+    // 获取账号信息
+    async fn get_account(&mut self) -> Result<Account, Error> {
+        Err(Error::new(ErrorKind::NotFound, "mexc_swap:该交易所方法未实现".to_string()))
+    }
+
+    async fn get_spot_account(&mut self) -> Result<Vec<Account>, Error> {
+        Err(Error::new(ErrorKind::NotFound, "mexc_swap:该交易所方法未实现".to_string()))
+    }
+
+    // 获取持仓信息
+    async fn get_position(&mut self) -> Result<Vec<Position>, Error> {
+        Err(Error::new(ErrorKind::NotFound, "mexc_swap:该交易所方法未实现".to_string()))
+    }
+    // 获取所有持仓
+    async fn get_positions(&mut self) -> Result<Vec<Position>, Error> {
+        Err(Error::new(ErrorKind::NotFound, "mexc_swap:该交易所方法未实现".to_string()))
+    }
+    // 获取市场行情
+    async fn get_ticker(&mut self) -> Result<Ticker, Error> {
+        Err(Error::new(ErrorKind::NotFound, "mexc_swap:该交易所方法未实现".to_string()))
+    }
+
+    async fn get_record(&mut self, _interval: String) -> Result<Vec<Record>, Error> {
+        todo!("还没做呢")
+    }
+
+    async fn get_ticker_symbol(&mut self, _symbol: String) -> Result<Ticker, Error> {
+        Err(Error::new(ErrorKind::NotFound, "mexc_swap:该交易所方法未实现".to_string()))
+    }
+
+    async fn get_market(&mut self) -> Result<Market, Error> {
+        let symbol_format = utils::format_symbol(self.symbol.clone(), "_");
+        let params = json!({});
+        let res_data = self.request.get_market(params).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["symbol"].as_str().unwrap() == symbol_format);
+            match market_info {
+                None => {
+                    error!("mexc_swap:获取Market信息错误!\nget_market:res_data={:?}", res_data);
+                    Err(Error::new(ErrorKind::Other, res_data.to_string()))
+                }
+                Some(value) => {
+                    let symbol = value["symbol"].as_str().unwrap().to_string();
+                    let base_asset = value["baseCoin"].as_str().unwrap().to_string();
+                    let quote_asset = value["quoteCoin"].as_str().unwrap().to_string();
+                    let tick_size = Decimal::from_i64(value["priceUnit"].as_i64().unwrap()).unwrap();
+                    let amount_size = Decimal::from_i64(value["volUnit"].as_i64().unwrap()).unwrap();
+                    let price_precision = Decimal::from_i64(value["priceScale"].as_i64().unwrap()).unwrap();
+                    let amount_precision = Decimal::from_i64(value["volScale"].as_i64().unwrap()).unwrap();
+                    let min_qty = Decimal::from_i64(value["minVol"].as_i64().unwrap()).unwrap();
+                    let max_qty = Decimal::from_i64(value["maxVol"].as_i64().unwrap()).unwrap();
+                    let multiplier = Decimal::from_i64(value["contractSize"].as_i64().unwrap()).unwrap();
+
+                    let result = Market {
+                        symbol,
+                        base_asset,
+                        quote_asset,
+                        tick_size,
+                        amount_size,
+                        price_precision,
+                        amount_precision,
+                        min_qty,
+                        max_qty,
+                        min_notional: min_qty,
+                        max_notional: max_qty,
+                        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_format = utils::format_symbol(symbol.clone(), "-");
+        let params = json!({
+            "symbol": symbol_format.clone()
+        });
+        let res_data = self.request.get_market(params).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["symbol"].as_str().unwrap() == symbol_format);
+            match market_info {
+                None => {
+                    error!("mexc_swap:获取Market信息错误!\nget_market:res_data={:?}", res_data);
+                    Err(Error::new(ErrorKind::Other, res_data.to_string()))
+                }
+                Some(value) => {
+                    let symbol = value["symbol"].as_str().unwrap().to_string();
+                    let base_asset = value["baseCoin"].as_str().unwrap().to_string();
+                    let quote_asset = value["quoteCoin"].as_str().unwrap().to_string();
+                    let tick_size = Decimal::from_i64(value["priceUnit"].as_i64().unwrap()).unwrap();
+                    let amount_size = Decimal::from_i64(value["volUnit"].as_i64().unwrap()).unwrap();
+                    let price_precision = Decimal::from_i64(value["priceScale"].as_i64().unwrap()).unwrap();
+                    let amount_precision = Decimal::from_i64(value["volScale"].as_i64().unwrap()).unwrap();
+                    let min_qty = Decimal::from_i64(value["minVol"].as_i64().unwrap()).unwrap();
+                    let max_qty = Decimal::from_i64(value["maxVol"].as_i64().unwrap()).unwrap();
+                    let multiplier = Decimal::from_i64(value["contractSize"].as_i64().unwrap()).unwrap();
+
+                    let result = Market {
+                        symbol,
+                        base_asset,
+                        quote_asset,
+                        tick_size,
+                        amount_size,
+                        price_precision,
+                        amount_precision,
+                        min_qty,
+                        max_qty,
+                        min_notional: min_qty,
+                        max_notional: max_qty,
+                        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> {
+        Err(Error::new(ErrorKind::NotFound, "mexc_swap:该交易所方法未实现".to_string()))
+    }
+    // 获取订单列表
+    async fn get_orders_list(&mut self, _status: &str) -> Result<Vec<Order>, Error> {
+        Err(Error::new(ErrorKind::NotFound, "mexc_swap:该交易所方法未实现".to_string()))
+    }
+    // 下单接口
+    async fn take_order(&mut self, _custom_id: &str, _origin_side: &str, _price: Decimal, _amount: Decimal) -> Result<Order, Error> {
+        Err(Error::new(ErrorKind::NotFound, "mexc_swap:该交易所方法未实现".to_string()))
+    }
+
+    async fn take_order_symbol(&mut self, _symbol: String, _ct_val: Decimal, _custom_id: &str, _origin_side: &str, _price: Decimal, _amount: Decimal) -> Result<Order, Error> {
+        Err(Error::new(ErrorKind::NotFound, "mexc_swap:该交易所方法未实现".to_string()))
+    }
+
+    // 撤销订单
+    async fn cancel_order(&mut self, _order_id: &str, _custom_id: &str) -> Result<Order, Error> {
+        Err(Error::new(ErrorKind::NotFound, "mexc_swap:该交易所方法未实现".to_string()))
+    }
+    // 批量撤销订单
+    async fn cancel_orders(&mut self) -> Result<Vec<Order>, Error> {
+        Err(Error::new(ErrorKind::NotFound, "mexc_swap:该交易所方法未实现".to_string()))
+    }
+
+    async fn cancel_orders_all(&mut self) -> Result<Vec<Order>, Error> {
+        Err(Error::new(ErrorKind::NotFound, "mexc_swap:该交易所方法未实现".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, "mexc_swap:该交易所方法未实现".to_string()))
+    }
+
+    async fn cancel_stop_loss_order(&mut self, _order_id: &str) -> Result<Value, Error> {
+        Err(Error::new(ErrorKind::NotFound, "mexc_swap:该交易所方法未实现".to_string()))
+    }
+
+    // 设置持仓模式
+    async fn set_dual_mode(&mut self, _coin: &str, _is_dual_mode: bool) -> Result<String, Error> {
+        Err(Error::new(ErrorKind::NotFound, "mexc_swap:该交易所方法未实现".to_string()))
+    }
+
+    // 更新双持仓模式下杠杆
+    async fn set_dual_leverage(&mut self, _leverage: &str) -> Result<String, Error> {
+        Err(Error::new(ErrorKind::NotFound, "mexc_swap:该交易所方法未实现".to_string()))
+    }
+
+    async fn set_auto_deposit_status(&mut self, _status: bool) -> Result<String, Error> { Err(Error::new(ErrorKind::NotFound, "mexc:该交易所方法未实现".to_string())) }
+
+    // 交易账户互转
+    async fn wallet_transfers(&mut self, _coin: &str, _from: &str, _to: &str, _amount: Decimal) -> Result<String, Error> {
+        Err(Error::new(ErrorKind::NotFound, "mexc_swap:该交易所方法未实现".to_string()))
+    }
+
+    async fn command_order(&mut self, _order_command: &mut OrderCommand, _trace_stack: &TraceStack) {
+        todo!("还没做呢")
+    }
+}

+ 3 - 0
strategy/src/exchange_disguise.rs

@@ -25,6 +25,9 @@ pub async fn run_transactional_exchange(is_shutdown_arc :Arc<AtomicBool>,
         },
         "gate_usdt_swap" => {
             gate_swap_run(is_shutdown_arc, true, core_arc, name, symbols, is_colo, exchange_params).await;
+        }
+        "mexc_usdt_swap" => {
+            
         }
         // "kucoin_usdt_swap" => {
         //     kucoin_swap_run(is_shutdown_arc, true, core_arc, name, symbols, is_colo, exchange_params).await;

+ 1 - 0
strategy/src/lib.rs

@@ -14,5 +14,6 @@ mod okx_usdt_swap;
 mod bybit_usdt_swap;
 mod bitget_usdt_swap;
 mod coinex_usdt_swap;
+mod mexc_usdt_swap;
 mod htx_usdt_swap;
 pub mod clear_core;

+ 260 - 0
strategy/src/mexc_usdt_swap.rs

@@ -0,0 +1,260 @@
+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};
+use tokio_tungstenite::tungstenite::Message;
+use exchanges::mexc_swap_ws::{MexcSwapLogin, MexcSwapSubscribeType, MexcSwapWs, MexcSwapWsType};
+use exchanges::response_base::ResponseData;
+use global::trace_stack::TraceStack;
+use standard::exchange::ExchangeEnum::MexcSwap;
+use standard::exchange_struct_handler::ExchangeStructHandler;
+use standard::{Depth, OrderBook, Position, PositionModeEnum};
+use crate::core::Core;
+use crate::exchange_disguise::{on_depth, on_record, on_ticker, on_trade};
+use crate::model::OrderInfo;
+
+pub async fn reference_mexc_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 = MexcSwapWs::new_with_tag(name, is_colo, None, MexcSwapWsType::PublicAndPrivate);
+        ws.set_subscribe(vec![
+            MexcSwapSubscribeType::PuFuturesDepthFull(5),
+        ]);
+
+        // 读取数据
+        let core_arc_clone = Arc::clone(&core_arc);
+        let mut rest = core_arc_clone.lock().await.platform_rest.clone_box();
+        let multiplier = rest.get_self_market().multiplier;
+        let mut records = rest.get_record("1".to_string()).await.unwrap();
+        for record in records.iter_mut() {
+            let core_arc_clone = core_arc.clone();
+
+            on_record(core_arc_clone, record).await
+        }
+
+        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("mexc_usdt_swap 链接有异常");
+    });
+}
+
+// 交易 mexc 合约 启动
+pub(crate) async fn mexc_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>) {
+    reference_mexc_swap_run(is_shutdown_arc.clone(), core_arc.clone(), name.clone(), symbols.clone(), is_colo).await;
+
+    spawn(async move {
+        let (write_tx, write_rx) = futures_channel::mpsc::unbounded();
+        let auth = Some(parse_btree_map_to_mexc_swap_login(exchange_params));
+        let mut ws = MexcSwapWs::new_with_tag(name.clone(), is_colo, auth, MexcSwapWsType::PublicAndPrivate);
+        ws.set_subscribe(vec![
+            // mexcSwapSubscribeType::PrOrders,
+            // mexcSwapSubscribeType::PrAccount,
+            // mexcSwapSubscribeType::PrPosition
+        ]);
+
+        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("mexc_usdt_swap 链接有异常");
+    });
+}
+
+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(MexcSwap, response, run_symbol);
+            let mut core = core_arc_clone.lock().await;
+            core.update_equity(account).await;
+        }
+        "order" => {
+            let orders = ExchangeStructHandler::order_handle(MexcSwap, 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!("mexc_usdt_swap 未识别的订单状态:{:?}", response);
+                    continue;
+                }
+
+                // if order.deal_amount != Decimal::ZERO {
+                //     info!("mexc 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 mut positions = ExchangeStructHandler::position_handle(MexcSwap, response, ct_val);
+            let mut core = core_arc_clone.lock().await;
+
+            if positions.is_empty() {
+                positions.push(Position {
+                    symbol: run_symbol.to_string(),
+                    margin_level: Default::default(),
+                    amount: Default::default(),
+                    frozen_amount: Default::default(),
+                    price: Default::default(),
+                    profit: Default::default(),
+                    position_mode: PositionModeEnum::Both,
+                    margin: Default::default(),
+                });
+            }
+
+            core.update_position(positions).await;
+        }
+        _ => {
+            error!("未知推送类型");
+            error!(?response);
+        }
+    }
+}
+
+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("mexc_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(MexcSwap, &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, 0).await;
+            }
+            // 全量
+            else {
+                trace_stack.on_after_format();
+                on_depth(core_arc, &response.label, &mut trace_stack, &depth, 0).await;
+
+                depth_asks.clear();
+                depth_asks.append(&mut depth.asks);
+                depth_bids.clear();
+                depth_bids.append(&mut depth.bids);
+            }
+        }
+        "trade" => {
+            trace_stack.set_source("mexc_usdt_swap.trade".to_string());
+
+            let mut trades = ExchangeStructHandler::trades_handle(MexcSwap, 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, 0).await;
+            }
+        }
+        "tickers" => {
+            trace_stack.set_source("mexc_usdt_swap.tickers".to_string());
+            let ticker = ExchangeStructHandler::ticker_handle(MexcSwap, response).await;
+            trace_stack.on_after_format();
+
+            on_ticker(core_arc, &mut trace_stack, &ticker).await;
+        }
+        // k线数据
+        "kline" => {
+            let mut records = ExchangeStructHandler::records_handle(MexcSwap, &response);
+
+            if records.is_empty() {
+                return;
+            }
+
+            for record in records.iter_mut() {
+                let core_arc_clone = core_arc.clone();
+
+                on_record(core_arc_clone, record).await
+            }
+        }
+        _ => {
+            error!("未知推送类型");
+            error!(?response);
+        }
+    }
+}
+
+fn parse_btree_map_to_mexc_swap_login(exchange_params: BTreeMap<String, String>) -> MexcSwapLogin {
+    MexcSwapLogin {
+        access_key: exchange_params.get("access_key").unwrap().clone(),
+        secret_key: exchange_params.get("secret_key").unwrap().clone(),
+        pass_key: "".to_string(),
+    }
+}