Bläddra i källkod

加入bingx,注释kucoin

DESKTOP-NE65RNK\Citrus_limon 1 år sedan
förälder
incheckning
b47feaaf5a

+ 3 - 3
exchanges/src/coinsph_swap_rest.rs

@@ -1,5 +1,5 @@
 use std::collections::BTreeMap;
-use chrono::Utc;
+// use chrono::Utc;
 use reqwest::header::HeaderMap;
 use reqwest::{Client};
 use rust_decimal::Decimal;
@@ -120,7 +120,7 @@ impl CoinsphSwapRest {
                          prefix_url: String,
                          request_url: String,
                          is_login: bool,
-                         mut params: Value) -> ResponseData
+                         params: Value) -> ResponseData
     {
         trace!("login_param:{:?}", self.login_param);
         //解析账号信息
@@ -142,7 +142,7 @@ impl CoinsphSwapRest {
         }
 
         //每个接口都有的参数
-        let timestamp = Utc::now().timestamp_millis();
+        // let timestamp = Utc::now().timestamp_millis();
 
         //请求类型不同,可能请求头body 不同
         let mut body = "{}".to_string();

+ 2 - 3
exchanges/src/coinsph_swap_ws.rs

@@ -1,5 +1,4 @@
 use std::io::Read;
-use std::ptr::null;
 use std::str::from_utf8;
 use std::sync::Arc;
 use std::sync::atomic::AtomicBool;
@@ -340,13 +339,13 @@ impl CoinsphSwapWs {
     //数据解析
     pub async fn ok_text(text: String) -> ResponseData
     {
-        info!("原始数据:{}", text);
+        // info!("原始数据:{}", text);
         let mut res_data = ResponseData::new("".to_string(), 200, "success".to_string(), Value::Null);
         let json_value: Value = serde_json::from_str(&text).unwrap();
 
         let id = json_value["id"].as_str();
         match id {
-            Some(v) => {
+            Some(_v) => {
                 res_data.code = -201;
                 res_data.message = format!("订阅成功:{}", json_value["request"].clone().to_string());
                 return res_data;

+ 121 - 121
src/bingx_usdt_swap_data_listener.rs

@@ -1,121 +1,121 @@
-// use std::collections::{BTreeMap, HashMap};
-// use std::sync::{Arc};
-// use std::sync::atomic::AtomicBool;
-// use lazy_static::lazy_static;
-// use rust_decimal::Decimal;
-// use rust_decimal_macros::dec;
-// use tokio::sync::{Mutex};
-// use tracing::info;
-// use exchanges::bingx_swap_rest::BingxSwapRest;
-// use exchanges::bingx_swap_ws::{BingxSwapSubscribeType, BingxSwapWs, BingxSwapWsType};
-// use exchanges::response_base::ResponseData;
-// use serde_json::json;
-// use standard::exchange::ExchangeEnum;
-// use standard::exchange_struct_handler::ExchangeStructHandler;
-// use crate::listener_tools::{RecordMap, TradeMap, update_record, update_trade};
-//
-// const EXCHANGE_NAME: &str = "bingx_usdt_swap";
-//
-// lazy_static! {
-//     // static ref DEPTH_MAP: Mutex<DepthMap> = Mutex::new(HashMap::new());
-//     static ref TRADES_MAP: Mutex<TradeMap> = Mutex::new(HashMap::new());
-//     static ref RECORD_MAP: Mutex<RecordMap> = Mutex::new(HashMap::new());
-//     static ref MUL_MAP: Mutex<HashMap<String, Decimal>> = Mutex::new(HashMap::new());
-// }
-//
-// pub async fn run_listener(is_shutdown_arc: Arc<AtomicBool>) {
-//     let name = "bingx_usdt_swap_listener";
-//     // 订阅所有币种
-//     let login = BTreeMap::new();
-//     let mut bingx_rest = BingxSwapRest::new(false, login);
-//     let params = json!({});
-//     let response = bingx_rest.get_market(params).await;
-//     let mut symbols = vec![];
-//     if response.code == 200 {
-//         let symbol_infos = response.data.as_array().unwrap();
-//         let mut mul_map = MUL_MAP.lock().await;
-//         for symbol_info in symbol_infos {
-//             // quanto_multiplier是ct_val
-//             let symbol = symbol_info["symbol"].as_str().unwrap().replace("-", "_");
-//             let mul = Decimal::ONE;
-//             mul_map.insert(symbol.clone(), mul);
-//
-//             symbols.push(symbol)
-//         }
-//     }
-//
-//     for chunk in symbols.chunks(20) {
-//         let ws_name = name.to_string();
-//         let (write_tx, write_rx) = futures_channel::mpsc::unbounded();
-//         let write_tx_am = Arc::new(Mutex::new(write_tx));
-//         let symbols_chunk = chunk.iter().cloned().collect::<Vec<String>>();
-//         let is_shutdown_clone = Arc::clone(&is_shutdown_arc);
-//
-//         tokio::spawn(async move {
-//             let mut ws = BingxSwapWs::new_with_tag(ws_name, false, None, BingxSwapWsType::PublicAndPrivate);
-//             ws.set_subscribe(vec![
-//                 BingxSwapSubscribeType::PuFuturesTrades,
-//                 BingxSwapSubscribeType::PuFuturesRecords,
-//                 // BingxSwapSubscribeType::PuFuturesOrderBook
-//             ]);
-//
-//             // 建立链接
-//             ws.set_symbols(symbols_chunk);
-//             ws.ws_connect_async(is_shutdown_clone, data_listener, &write_tx_am, write_rx).await.expect("链接失败(内部一个心跳线程应该已经关闭了)");
-//         });
-//     }
-// }
-//
-// // 读取数据
-// pub async fn data_listener(response: ResponseData) {
-//     if response.code != 200 {
-//         return;
-//     }
-//
-//     match response.channel.as_str() {
-//         // 深度数据
-//         "futures.order_book" => {
-//             // let depth = ExchangeStructHandler::order_book_handle(ExchangeEnum::BingxSwap, &response);
-//             //
-//             // update_depth(&depth).await;
-//         }
-//         // 订单流数据
-//         "futures.trades" => {
-//             let mut trades = ExchangeStructHandler::trades_handle(ExchangeEnum::BingxSwap, &response);
-//             let mul_map = MUL_MAP.lock().await;
-//
-//             for trade in trades.iter_mut() {
-//                 // 真实交易量处理,因为bingx的量都是张数
-//                 let mul = mul_map[trade.symbol.as_str()];
-//                 let mut real_size = trade.size * mul * trade.price;
-//                 real_size.rescale(2);
-//                 trade.size = real_size;
-//
-//                 // 更新到本地数据库
-//                 let trades_map = TRADES_MAP.lock().await;
-//                 update_trade(trade, trades_map, EXCHANGE_NAME).await;
-//             }
-//         }
-//         // k线数据
-//         "futures.candlesticks" => {
-//             let mut records = ExchangeStructHandler::records_handle(ExchangeEnum::BingxSwap, &response);
-//
-//             let mul_map = MUL_MAP.lock().await;
-//             for record in records.iter_mut() {
-//                 // 真实交易量处理,因为bingx的量都是张数
-//                 let mul = mul_map[record.symbol.as_str()];
-//                 let mid_price = (record.high + record.low) * dec!(0.5);
-//                 let mut real_volume = record.volume * mul * mid_price;
-//                 real_volume.rescale(2);
-//                 record.volume = real_volume;
-//
-//                 // 更新到本地数据库
-//                 let record_map = RECORD_MAP.lock().await;
-//                 update_record(record, record_map, EXCHANGE_NAME).await;
-//             }
-//         }
-//         _ => {
-//             info!("48 未知的数据类型: {:?}", response)
-//         }
-//     }
-// }
+use std::collections::{BTreeMap, HashMap};
+use std::sync::{Arc};
+use std::sync::atomic::AtomicBool;
+use lazy_static::lazy_static;
+use rust_decimal::Decimal;
+use rust_decimal_macros::dec;
+use tokio::sync::{Mutex};
+use tracing::info;
+use exchanges::bingx_swap_rest::BingxSwapRest;
+use exchanges::bingx_swap_ws::{BingxSwapSubscribeType, BingxSwapWs, BingxSwapWsType};
+use exchanges::response_base::ResponseData;
+use serde_json::json;
+use standard::exchange::ExchangeEnum;
+use standard::exchange_struct_handler::ExchangeStructHandler;
+use crate::listener_tools::{RecordMap, TradeMap, update_record, update_trade};
+
+const EXCHANGE_NAME: &str = "bingx_usdt_swap";
+
+lazy_static! {
+    // static ref DEPTH_MAP: Mutex<DepthMap> = Mutex::new(HashMap::new());
+    static ref TRADES_MAP: Mutex<TradeMap> = Mutex::new(HashMap::new());
+    static ref RECORD_MAP: Mutex<RecordMap> = Mutex::new(HashMap::new());
+    static ref MUL_MAP: Mutex<HashMap<String, Decimal>> = Mutex::new(HashMap::new());
+}
+
+pub async fn run_listener(is_shutdown_arc: Arc<AtomicBool>) {
+    let name = "bingx_usdt_swap_listener";
+    // 订阅所有币种
+    let login = BTreeMap::new();
+    let mut bingx_rest = BingxSwapRest::new(false, login);
+    let params = json!({});
+    let response = bingx_rest.get_market(params).await;
+    let mut symbols = vec![];
+    if response.code == 200 {
+        let symbol_infos = response.data.as_array().unwrap();
+        let mut mul_map = MUL_MAP.lock().await;
+        for symbol_info in symbol_infos {
+            // quanto_multiplier是ct_val
+            let symbol = symbol_info["symbol"].as_str().unwrap().replace("-", "_");
+            let mul = Decimal::ONE;
+            mul_map.insert(symbol.clone(), mul);
+
+            symbols.push(symbol)
+        }
+    }
+
+    for chunk in symbols.chunks(20) {
+        let ws_name = name.to_string();
+        let (write_tx, write_rx) = futures_channel::mpsc::unbounded();
+        let write_tx_am = Arc::new(Mutex::new(write_tx));
+        let symbols_chunk = chunk.iter().cloned().collect::<Vec<String>>();
+        let is_shutdown_clone = Arc::clone(&is_shutdown_arc);
+
+        tokio::spawn(async move {
+            let mut ws = BingxSwapWs::new_with_tag(ws_name, false, None, BingxSwapWsType::PublicAndPrivate);
+            ws.set_subscribe(vec![
+                BingxSwapSubscribeType::PuFuturesTrades,
+                BingxSwapSubscribeType::PuFuturesRecords,
+                // BingxSwapSubscribeType::PuFuturesOrderBook
+            ]);
+
+            // 建立链接
+            ws.set_symbols(symbols_chunk);
+            ws.ws_connect_async(is_shutdown_clone, data_listener, &write_tx_am, write_rx).await.expect("链接失败(内部一个心跳线程应该已经关闭了)");
+        });
+    }
+}
+
+// 读取数据
+pub async fn data_listener(response: ResponseData) {
+    if response.code != 200 {
+        return;
+    }
+
+    match response.channel.as_str() {
+        // 深度数据
+        "futures.order_book" => {
+            // let depth = ExchangeStructHandler::order_book_handle(ExchangeEnum::BingxSwap, &response);
+            //
+            // update_depth(&depth).await;
+        }
+        // 订单流数据
+        "futures.trades" => {
+            let mut trades = ExchangeStructHandler::trades_handle(ExchangeEnum::BingxSwap, &response);
+            let mul_map = MUL_MAP.lock().await;
+
+            for trade in trades.iter_mut() {
+                // 真实交易量处理,因为bingx的量都是张数
+                let mul = mul_map[trade.symbol.as_str()];
+                let mut real_size = trade.size * mul * trade.price;
+                real_size.rescale(2);
+                trade.size = real_size;
+
+                // 更新到本地数据库
+                let trades_map = TRADES_MAP.lock().await;
+                update_trade(trade, trades_map, EXCHANGE_NAME).await;
+            }
+        }
+        // k线数据
+        "futures.candlesticks" => {
+            let mut records = ExchangeStructHandler::records_handle(ExchangeEnum::BingxSwap, &response);
+
+            let mul_map = MUL_MAP.lock().await;
+            for record in records.iter_mut() {
+                // 真实交易量处理,因为bingx的量都是张数
+                let mul = mul_map[record.symbol.as_str()];
+                let mid_price = (record.high + record.low) * dec!(0.5);
+                let mut real_volume = record.volume * mul * mid_price;
+                real_volume.rescale(2);
+                record.volume = real_volume;
+
+                // 更新到本地数据库
+                let record_map = RECORD_MAP.lock().await;
+                update_record(record, record_map, EXCHANGE_NAME).await;
+            }
+        }
+        _ => {
+            info!("48 未知的数据类型: {:?}", response)
+        }
+    }
+}

+ 122 - 122
src/bitmart_usdt_swap_data_listener.rs

@@ -1,122 +1,122 @@
-use std::collections::{BTreeMap, HashMap};
-use std::str::FromStr;
-use std::sync::{Arc};
-use std::sync::atomic::AtomicBool;
-use lazy_static::lazy_static;
-use rust_decimal::Decimal;
-use rust_decimal_macros::dec;
-use tokio::sync::{Mutex};
-use exchanges::bitmart_swap_rest::BitMartSwapRest;
-use exchanges::bitmart_swap_ws::{BitMartSwapSubscribeType, BitMartSwapWs, BitMartSwapWsType};
-use exchanges::response_base::ResponseData;
-use serde_json::json;
-use standard::exchange::ExchangeEnum;
-use standard::exchange_struct_handler::ExchangeStructHandler;
-use crate::listener_tools::{RecordMap, TradeMap, update_record, update_trade};
-
-const EXCHANGE_NAME: &str = "bitmart_usdt_swap";
-
-lazy_static! {
-    // static ref DEPTH_MAP: Mutex<DepthMap> = Mutex::new(HashMap::new());
-    static ref TRADES_MAP: Mutex<TradeMap> = Mutex::new(HashMap::new());
-    static ref RECORD_MAP: Mutex<RecordMap> = Mutex::new(HashMap::new());
-    static ref MUL_MAP: Mutex<HashMap<String, Decimal>> = Mutex::new(HashMap::new());
-}
-
-pub async fn run_listener(is_shutdown_arc: Arc<AtomicBool>) {
-    let name = "bitmart_usdt_swap_listener";
-    // 订阅所有币种
-    let login = BTreeMap::new();
-    let mut bitmart_rest = BitMartSwapRest::new(false, login);
-    let params = json!({});
-    let response = bitmart_rest.get_market(params).await;
-    let mut symbols = vec![];
-    if response.code == 200 {
-        let symbol_infos = response.data["symbols"].as_array().unwrap();
-
-        let mut mul_map = MUL_MAP.lock().await;
-        for symbol_info in symbol_infos {
-            // quanto_multiplier是ct_val
-            let symbol = format!("{}_{}", symbol_info["base_currency"].as_str().unwrap(), symbol_info["quote_currency"].as_str().unwrap());
-            let mul = Decimal::from_str(symbol_info["contract_size"].as_str().unwrap()).unwrap();
-            mul_map.insert(symbol.clone(), mul);
-
-            symbols.push(symbol)
-        }
-    }
-
-    for chunk in symbols.chunks(10) {
-        let ws_name = name.to_string();
-        let (write_tx, write_rx) = futures_channel::mpsc::unbounded();
-        let write_tx_am = Arc::new(Mutex::new(write_tx));
-        let symbols_chunk = chunk.iter().cloned().collect::<Vec<String>>();
-        let is_shutdown_clone = Arc::clone(&is_shutdown_arc);
-
-        tokio::spawn(async move {
-            let mut ws = BitMartSwapWs::new_with_tag(ws_name, false, None, BitMartSwapWsType::Public);
-            ws.set_subscribe(vec![
-                BitMartSwapSubscribeType::PuFuturesTrades,
-                BitMartSwapSubscribeType::PuFuturesRecords
-                // BitMartSwapSubscribeType::PuFuturesDepth,
-
-            ]);
-            // 建立链接
-            ws.set_symbols(symbols_chunk);
-            ws.ws_connect_async(is_shutdown_clone, data_listener, &write_tx_am, write_rx).await.expect("链接失败(内部一个心跳线程应该已经关闭了)");
-        });
-    }
-}
-
-// 读取数据
-pub async fn data_listener(response: ResponseData) {
-    if response.code != 200 {
-        return;
-    }
-
-    match response.channel.as_str() {
-        // 深度数据
-        "futures.order_book" => {
-            // let depth = ExchangeStructHandler::order_book_handle(ExchangeEnum::BitMartSwap, &response);
-            //
-            // update_depth(&depth).await;
-        }
-        // 订单流数据
-        "futures.trades" => {
-            let mut trades = ExchangeStructHandler::trades_handle(ExchangeEnum::BitMartSwap, &response);
-            let mul_map = MUL_MAP.lock().await;
-
-            for trade in trades.iter_mut() {
-                // 真实交易量处理,因为bitmart的量都是张数
-                let mul = mul_map[trade.symbol.as_str()];
-                let mut real_size = trade.size * mul * trade.price;
-                real_size.rescale(2);
-                trade.size = real_size;
-
-                // 更新到本地数据库
-                let trades_map = TRADES_MAP.lock().await;
-                update_trade(trade, trades_map, EXCHANGE_NAME).await;
-            }
-        }
-        // k线数据
-        "futures.candlesticks" => {
-            let mut records = ExchangeStructHandler::records_handle(ExchangeEnum::BitMartSwap, &response);
-
-            let mul_map = MUL_MAP.lock().await;
-            for record in records.iter_mut() {
-                // 真实交易量处理,因为bitmart的量都是张数
-                let mul = mul_map[record.symbol.as_str()];
-                let mid_price = (record.high + record.low) * dec!(0.5);
-                let mut real_volume = record.volume * mul * mid_price;
-                real_volume.rescale(2);
-                record.volume = real_volume;
-
-                // 更新到本地数据库
-                let record_map = RECORD_MAP.lock().await;
-                update_record(record, record_map, EXCHANGE_NAME).await;
-            }
-        }
-        _ => {
-            // info!("48 未知的数据类型: {:?}", response)
-        }
-    }
-}
+// use std::collections::{BTreeMap, HashMap};
+// use std::str::FromStr;
+// use std::sync::{Arc};
+// use std::sync::atomic::AtomicBool;
+// use lazy_static::lazy_static;
+// use rust_decimal::Decimal;
+// use rust_decimal_macros::dec;
+// use tokio::sync::{Mutex};
+// use exchanges::bitmart_swap_rest::BitMartSwapRest;
+// use exchanges::bitmart_swap_ws::{BitMartSwapSubscribeType, BitMartSwapWs, BitMartSwapWsType};
+// use exchanges::response_base::ResponseData;
+// use serde_json::json;
+// use standard::exchange::ExchangeEnum;
+// use standard::exchange_struct_handler::ExchangeStructHandler;
+// use crate::listener_tools::{RecordMap, TradeMap, update_record, update_trade};
+//
+// const EXCHANGE_NAME: &str = "bitmart_usdt_swap";
+//
+// lazy_static! {
+//     // static ref DEPTH_MAP: Mutex<DepthMap> = Mutex::new(HashMap::new());
+//     static ref TRADES_MAP: Mutex<TradeMap> = Mutex::new(HashMap::new());
+//     static ref RECORD_MAP: Mutex<RecordMap> = Mutex::new(HashMap::new());
+//     static ref MUL_MAP: Mutex<HashMap<String, Decimal>> = Mutex::new(HashMap::new());
+// }
+//
+// pub async fn run_listener(is_shutdown_arc: Arc<AtomicBool>) {
+//     let name = "bitmart_usdt_swap_listener";
+//     // 订阅所有币种
+//     let login = BTreeMap::new();
+//     let mut bitmart_rest = BitMartSwapRest::new(false, login);
+//     let params = json!({});
+//     let response = bitmart_rest.get_market(params).await;
+//     let mut symbols = vec![];
+//     if response.code == 200 {
+//         let symbol_infos = response.data["symbols"].as_array().unwrap();
+//
+//         let mut mul_map = MUL_MAP.lock().await;
+//         for symbol_info in symbol_infos {
+//             // quanto_multiplier是ct_val
+//             let symbol = format!("{}_{}", symbol_info["base_currency"].as_str().unwrap(), symbol_info["quote_currency"].as_str().unwrap());
+//             let mul = Decimal::from_str(symbol_info["contract_size"].as_str().unwrap()).unwrap();
+//             mul_map.insert(symbol.clone(), mul);
+//
+//             symbols.push(symbol)
+//         }
+//     }
+//
+//     for chunk in symbols.chunks(10) {
+//         let ws_name = name.to_string();
+//         let (write_tx, write_rx) = futures_channel::mpsc::unbounded();
+//         let write_tx_am = Arc::new(Mutex::new(write_tx));
+//         let symbols_chunk = chunk.iter().cloned().collect::<Vec<String>>();
+//         let is_shutdown_clone = Arc::clone(&is_shutdown_arc);
+//
+//         tokio::spawn(async move {
+//             let mut ws = BitMartSwapWs::new_with_tag(ws_name, false, None, BitMartSwapWsType::Public);
+//             ws.set_subscribe(vec![
+//                 BitMartSwapSubscribeType::PuFuturesTrades,
+//                 BitMartSwapSubscribeType::PuFuturesRecords
+//                 // BitMartSwapSubscribeType::PuFuturesDepth,
+//
+//             ]);
+//             // 建立链接
+//             ws.set_symbols(symbols_chunk);
+//             ws.ws_connect_async(is_shutdown_clone, data_listener, &write_tx_am, write_rx).await.expect("链接失败(内部一个心跳线程应该已经关闭了)");
+//         });
+//     }
+// }
+//
+// // 读取数据
+// pub async fn data_listener(response: ResponseData) {
+//     if response.code != 200 {
+//         return;
+//     }
+//
+//     match response.channel.as_str() {
+//         // 深度数据
+//         "futures.order_book" => {
+//             // let depth = ExchangeStructHandler::order_book_handle(ExchangeEnum::BitMartSwap, &response);
+//             //
+//             // update_depth(&depth).await;
+//         }
+//         // 订单流数据
+//         "futures.trades" => {
+//             let mut trades = ExchangeStructHandler::trades_handle(ExchangeEnum::BitMartSwap, &response);
+//             let mul_map = MUL_MAP.lock().await;
+//
+//             for trade in trades.iter_mut() {
+//                 // 真实交易量处理,因为bitmart的量都是张数
+//                 let mul = mul_map[trade.symbol.as_str()];
+//                 let mut real_size = trade.size * mul * trade.price;
+//                 real_size.rescale(2);
+//                 trade.size = real_size;
+//
+//                 // 更新到本地数据库
+//                 let trades_map = TRADES_MAP.lock().await;
+//                 update_trade(trade, trades_map, EXCHANGE_NAME).await;
+//             }
+//         }
+//         // k线数据
+//         "futures.candlesticks" => {
+//             let mut records = ExchangeStructHandler::records_handle(ExchangeEnum::BitMartSwap, &response);
+//
+//             let mul_map = MUL_MAP.lock().await;
+//             for record in records.iter_mut() {
+//                 // 真实交易量处理,因为bitmart的量都是张数
+//                 let mul = mul_map[record.symbol.as_str()];
+//                 let mid_price = (record.high + record.low) * dec!(0.5);
+//                 let mut real_volume = record.volume * mul * mid_price;
+//                 real_volume.rescale(2);
+//                 record.volume = real_volume;
+//
+//                 // 更新到本地数据库
+//                 let record_map = RECORD_MAP.lock().await;
+//                 update_record(record, record_map, EXCHANGE_NAME).await;
+//             }
+//         }
+//         _ => {
+//             // info!("48 未知的数据类型: {:?}", response)
+//         }
+//     }
+// }

+ 122 - 0
src/coinsph_usdt_swap_data_listener.rs

@@ -0,0 +1,122 @@
+// use std::collections::{BTreeMap, HashMap};
+// use std::sync::{Arc};
+// use std::sync::atomic::AtomicBool;
+// use lazy_static::lazy_static;
+// use rust_decimal::Decimal;
+// use rust_decimal_macros::dec;
+// use tokio::sync::{Mutex};
+// use tracing::info;
+// use exchanges::coinsph_swap_rest::CoinsphSwapRest;
+// use exchanges::coinsph_swap_ws::{CoinsphSwapSubscribeType, CoinsphSwapWs, CoinsphSwapWsType};
+// use exchanges::response_base::ResponseData;
+// use rust_decimal::prelude::FromPrimitive;
+// use serde_json::json;
+// use standard::exchange::ExchangeEnum;
+// use standard::exchange_struct_handler::ExchangeStructHandler;
+// use crate::listener_tools::{RecordMap, TradeMap, update_record, update_trade};
+//
+// const EXCHANGE_NAME: &str = "coinsph_usdt_swap";
+//
+// lazy_static! {
+//     // static ref DEPTH_MAP: Mutex<DepthMap> = Mutex::new(HashMap::new());
+//     static ref TRADES_MAP: Mutex<TradeMap> = Mutex::new(HashMap::new());
+//     static ref RECORD_MAP: Mutex<RecordMap> = Mutex::new(HashMap::new());
+//     static ref MUL_MAP: Mutex<HashMap<String, Decimal>> = Mutex::new(HashMap::new());
+// }
+//
+// pub async fn run_listener(is_shutdown_arc: Arc<AtomicBool>) {
+//     let name = "coinsph_usdt_swap_listener";
+//     // 订阅所有币种
+//     let login = BTreeMap::new();
+//     let mut coinsph_rest = CoinsphSwapRest::new(false, login);
+//     let params = json!({});
+//     let response = coinsph_rest.get_market(params).await;
+//     let mut symbols = vec![];
+//     if response.code == 200 {
+//         let symbol_infos = response.data["symbols"].as_array().unwrap();
+//         let mut mul_map = MUL_MAP.lock().await;
+//         for symbol_info in symbol_infos {
+//             if !symbol_info["symbol"].as_str().unwrap().ends_with("PHP") { continue; }
+//             // quanto_multiplier是ct_val
+//             let symbol = format!("{}_{}", symbol_info["baseAsset"].as_str().unwrap(), symbol_info["quoteAsset"].as_str().unwrap());
+//             let mul = Decimal::ONE;
+//             mul_map.insert(symbol.clone(), mul);
+//
+//             symbols.push(symbol)
+//         }
+//     }
+//     for chunk in symbols.chunks(20) {
+//         let ws_name = name.to_string();
+//         let (write_tx, write_rx) = futures_channel::mpsc::unbounded();
+//         let write_tx_am = Arc::new(Mutex::new(write_tx));
+//         let symbols_chunk = chunk.iter().cloned().collect::<Vec<String>>();
+//         let is_shutdown_clone = Arc::clone(&is_shutdown_arc);
+//
+//         tokio::spawn(async move {
+//             let mut ws = CoinsphSwapWs::new_with_tag(ws_name, false, None, CoinsphSwapWsType::Public);
+//             ws.set_subscribe(vec![
+//                 CoinsphSwapSubscribeType::PuFuturesTrades,
+//                 CoinsphSwapSubscribeType::PuFuturesRecords,
+//                 // CoinsphSwapSubscribeType::PuFuturesOrderBook
+//             ]);
+//
+//             // 建立链接
+//             ws.set_symbols(symbols_chunk);
+//             ws.ws_connect_async(is_shutdown_clone, data_listener, &write_tx_am, write_rx).await.expect("链接失败(内部一个心跳线程应该已经关闭了)");
+//         });
+//     }
+// }
+//
+// // 读取数据
+// pub async fn data_listener(response: ResponseData) {
+//     if response.code != 200 {
+//         return;
+//     }
+//
+//     match response.channel.as_str() {
+//         // 深度数据
+//         "futures.order_book" => {
+//             // let depth = ExchangeStructHandler::order_book_handle(ExchangeEnum::CoinsphSwap, &response);
+//             //
+//             // update_depth(&depth).await;
+//         }
+//         // 订单流数据
+//         "futures.trades" => {
+//             let mut trades = ExchangeStructHandler::trades_handle(ExchangeEnum::CoinsphSwap, &response);
+//             let mul_map = MUL_MAP.lock().await;
+//
+//             for trade in trades.iter_mut() {
+//                 // 真实交易量处理,因为coinsph的量都是张数
+//                 let mul = mul_map[trade.symbol.as_str()];
+//                 let mut real_size = trade.size * mul * trade.price;
+//                 real_size.rescale(2);
+//                 trade.size = real_size;
+//
+//                 // 更新到本地数据库
+//                 let trades_map = TRADES_MAP.lock().await;
+//                 update_trade(trade, trades_map, EXCHANGE_NAME).await;
+//             }
+//         }
+//         // k线数据
+//         "futures.candlesticks" => {
+//             let mut records = ExchangeStructHandler::records_handle(ExchangeEnum::CoinsphSwap, &response);
+//
+//             let mul_map = MUL_MAP.lock().await;
+//             for record in records.iter_mut() {
+//                 // 真实交易量处理,因为coinsph的量都是张数
+//                 let mul = mul_map[record.symbol.as_str()];
+//                 let mid_price = (record.high + record.low) * dec!(0.5);
+//                 let mut real_volume = record.volume * mul * mid_price;
+//                 real_volume.rescale(2);
+//                 record.volume = real_volume;
+//
+//                 // 更新到本地数据库
+//                 let record_map = RECORD_MAP.lock().await;
+//                 update_record(record, record_map, EXCHANGE_NAME).await;
+//             }
+//         }
+//         _ => {
+//             info!("48 未知的数据类型: {:?}", response)
+//         }
+//     }
+// }

+ 122 - 122
src/kucoin_usdt_swap_data_listener.rs

@@ -1,122 +1,122 @@
-use std::collections::{BTreeMap, HashMap};
-use std::sync::{Arc};
-use std::sync::atomic::AtomicBool;
-use lazy_static::lazy_static;
-use rust_decimal::Decimal;
-use rust_decimal_macros::dec;
-use tokio::sync::{Mutex};
-use exchanges::kucoin_swap_rest::KucoinSwapRest;
-use exchanges::kucoin_swap_ws::{KucoinSwapSubscribeType, KucoinSwapWs, KucoinSwapWsType};
-use exchanges::response_base::ResponseData;
-use rust_decimal::prelude::FromPrimitive;
-use standard::exchange::ExchangeEnum;
-use standard::exchange_struct_handler::ExchangeStructHandler;
-use standard::utils::symbol_out_mapper;
-use crate::listener_tools::{RecordMap, TradeMap, update_record, update_trade};
-
-const EXCHANGE_NAME: &str = "kucoin_usdt_swap";
-
-lazy_static! {
-    // static ref DEPTH_MAP: Mutex<DepthMap> = Mutex::new(HashMap::new());
-    static ref TRADES_MAP: Mutex<TradeMap> = Mutex::new(HashMap::new());
-    static ref RECORD_MAP: Mutex<RecordMap> = Mutex::new(HashMap::new());
-    static ref MUL_MAP: Mutex<HashMap<String, Decimal>> = Mutex::new(HashMap::new());
-}
-
-pub async fn run_listener(is_shutdown_arc: Arc<AtomicBool>) {
-    let name = "kucoin_usdt_swap_listener";
-    // 订阅所有币种
-    let login = BTreeMap::new();
-    let mut kucoin_rest = KucoinSwapRest::new(false, login);
-    let response = kucoin_rest.get_market_details().await;
-    let mut symbols = vec![];
-    if response.code == 200 {
-        let symbol_infos = response.data.as_array().unwrap();
-        let mut mul_map = MUL_MAP.lock().await;
-        for symbol_info in symbol_infos {
-            if symbol_info["quoteCurrency"] != "USDT" { continue; }
-            // quanto_multiplier是ct_val
-            let symbol = format!("{}{}M", symbol_info["baseCurrency"].as_str().unwrap(), symbol_info["quoteCurrency"].as_str().unwrap());
-            let loc_symbol = format!("{}_{}", symbol_info["baseCurrency"].as_str().unwrap(), symbol_info["quoteCurrency"].as_str().unwrap());
-            let mul = Decimal::from_f64(symbol_info["multiplier"].as_f64().unwrap()).unwrap();
-            mul_map.insert(symbol_out_mapper(ExchangeEnum::KucoinSwap, &loc_symbol), mul);
-
-            symbols.push(symbol)
-        }
-    }
-
-    for chunk in symbols.chunks(20) {
-        let ws_name = name.to_string();
-        let (write_tx, write_rx) = futures_channel::mpsc::unbounded();
-        let write_tx_am = Arc::new(Mutex::new(write_tx));
-        let symbols_chunk = chunk.iter().cloned().collect::<Vec<String>>();
-        let is_shutdown_clone = Arc::clone(&is_shutdown_arc);
-
-        tokio::spawn(async move {
-            let mut ws = KucoinSwapWs::new_with_tag(ws_name, false, None, KucoinSwapWsType::Public).await.clone();
-            ws.set_subscribe(vec![
-                KucoinSwapSubscribeType::PuFuturesTrades,
-                KucoinSwapSubscribeType::PuFuturesRecords,
-                // KucoinSwapSubscribeType::PuFuturesOrderBook
-            ]);
-
-            // 建立链接
-            ws.set_symbols(symbols_chunk);
-            ws.ws_connect_async(is_shutdown_clone, data_listener, &write_tx_am, write_rx).await.expect("链接失败(内部一个心跳线程应该已经关闭了)");
-        });
-    }
-}
-
-// 读取数据
-pub async fn data_listener(response: ResponseData) {
-    if response.code != 200 {
-        return;
-    }
-
-    match response.channel.as_str() {
-        // 深度数据
-        "futures.order_book" => {
-            // let depth = ExchangeStructHandler::order_book_handle(ExchangeEnum::KucoinSwap, &response);
-            //
-            // update_depth(&depth).await;
-        }
-        // 订单流数据
-        "futures.trades" => {
-            let mut trades = ExchangeStructHandler::trades_handle(ExchangeEnum::KucoinSwap, &response);
-            let mul_map = MUL_MAP.lock().await;
-
-            for trade in trades.iter_mut() {
-                // 真实交易量处理,因为kucoin的量都是张数
-                let mul = mul_map[trade.symbol.as_str()];
-                let mut real_size = trade.size * mul * trade.price;
-                real_size.rescale(2);
-                trade.size = real_size;
-
-                // 更新到本地数据库
-                let trades_map = TRADES_MAP.lock().await;
-                update_trade(trade, trades_map, EXCHANGE_NAME).await;
-            }
-        }
-        // k线数据
-        "futures.candlesticks" => {
-            let mut records = ExchangeStructHandler::records_handle(ExchangeEnum::KucoinSwap, &response);
-
-            let mul_map = MUL_MAP.lock().await;
-            for record in records.iter_mut() {
-                // 真实交易量处理,因为kucoin的量都是张数
-                let mul = mul_map[record.symbol.as_str()];
-                let mid_price = (record.high + record.low) * dec!(0.5);
-                let mut real_volume = record.volume * mul * mid_price;
-                real_volume.rescale(2);
-                record.volume = real_volume;
-
-                // 更新到本地数据库
-                let record_map = RECORD_MAP.lock().await;
-                update_record(record, record_map, EXCHANGE_NAME).await;
-            }
-        }
-        _ => {
-            // info!("48 未知的数据类型: {:?}", response)
-        }
-    }
-}
+// use std::collections::{BTreeMap, HashMap};
+// use std::sync::{Arc};
+// use std::sync::atomic::AtomicBool;
+// use lazy_static::lazy_static;
+// use rust_decimal::Decimal;
+// use rust_decimal_macros::dec;
+// use tokio::sync::{Mutex};
+// use exchanges::kucoin_swap_rest::KucoinSwapRest;
+// use exchanges::kucoin_swap_ws::{KucoinSwapSubscribeType, KucoinSwapWs, KucoinSwapWsType};
+// use exchanges::response_base::ResponseData;
+// use rust_decimal::prelude::FromPrimitive;
+// use standard::exchange::ExchangeEnum;
+// use standard::exchange_struct_handler::ExchangeStructHandler;
+// use standard::utils::symbol_out_mapper;
+// use crate::listener_tools::{RecordMap, TradeMap, update_record, update_trade};
+//
+// const EXCHANGE_NAME: &str = "kucoin_usdt_swap";
+//
+// lazy_static! {
+//     // static ref DEPTH_MAP: Mutex<DepthMap> = Mutex::new(HashMap::new());
+//     static ref TRADES_MAP: Mutex<TradeMap> = Mutex::new(HashMap::new());
+//     static ref RECORD_MAP: Mutex<RecordMap> = Mutex::new(HashMap::new());
+//     static ref MUL_MAP: Mutex<HashMap<String, Decimal>> = Mutex::new(HashMap::new());
+// }
+//
+// pub async fn run_listener(is_shutdown_arc: Arc<AtomicBool>) {
+//     let name = "kucoin_usdt_swap_listener";
+//     // 订阅所有币种
+//     let login = BTreeMap::new();
+//     let mut kucoin_rest = KucoinSwapRest::new(false, login);
+//     let response = kucoin_rest.get_market_details().await;
+//     let mut symbols = vec![];
+//     if response.code == 200 {
+//         let symbol_infos = response.data.as_array().unwrap();
+//         let mut mul_map = MUL_MAP.lock().await;
+//         for symbol_info in symbol_infos {
+//             if symbol_info["quoteCurrency"] != "USDT" { continue; }
+//             // quanto_multiplier是ct_val
+//             let symbol = format!("{}{}M", symbol_info["baseCurrency"].as_str().unwrap(), symbol_info["quoteCurrency"].as_str().unwrap());
+//             let loc_symbol = format!("{}_{}", symbol_info["baseCurrency"].as_str().unwrap(), symbol_info["quoteCurrency"].as_str().unwrap());
+//             let mul = Decimal::from_f64(symbol_info["multiplier"].as_f64().unwrap()).unwrap();
+//             mul_map.insert(symbol_out_mapper(ExchangeEnum::KucoinSwap, &loc_symbol), mul);
+//
+//             symbols.push(symbol)
+//         }
+//     }
+//
+//     for chunk in symbols.chunks(20) {
+//         let ws_name = name.to_string();
+//         let (write_tx, write_rx) = futures_channel::mpsc::unbounded();
+//         let write_tx_am = Arc::new(Mutex::new(write_tx));
+//         let symbols_chunk = chunk.iter().cloned().collect::<Vec<String>>();
+//         let is_shutdown_clone = Arc::clone(&is_shutdown_arc);
+//
+//         tokio::spawn(async move {
+//             let mut ws = KucoinSwapWs::new_with_tag(ws_name, false, None, KucoinSwapWsType::Public).await.clone();
+//             ws.set_subscribe(vec![
+//                 KucoinSwapSubscribeType::PuFuturesTrades,
+//                 KucoinSwapSubscribeType::PuFuturesRecords,
+//                 // KucoinSwapSubscribeType::PuFuturesOrderBook
+//             ]);
+//
+//             // 建立链接
+//             ws.set_symbols(symbols_chunk);
+//             ws.ws_connect_async(is_shutdown_clone, data_listener, &write_tx_am, write_rx).await.expect("链接失败(内部一个心跳线程应该已经关闭了)");
+//         });
+//     }
+// }
+//
+// // 读取数据
+// pub async fn data_listener(response: ResponseData) {
+//     if response.code != 200 {
+//         return;
+//     }
+//
+//     match response.channel.as_str() {
+//         // 深度数据
+//         "futures.order_book" => {
+//             // let depth = ExchangeStructHandler::order_book_handle(ExchangeEnum::KucoinSwap, &response);
+//             //
+//             // update_depth(&depth).await;
+//         }
+//         // 订单流数据
+//         "futures.trades" => {
+//             let mut trades = ExchangeStructHandler::trades_handle(ExchangeEnum::KucoinSwap, &response);
+//             let mul_map = MUL_MAP.lock().await;
+//
+//             for trade in trades.iter_mut() {
+//                 // 真实交易量处理,因为kucoin的量都是张数
+//                 let mul = mul_map[trade.symbol.as_str()];
+//                 let mut real_size = trade.size * mul * trade.price;
+//                 real_size.rescale(2);
+//                 trade.size = real_size;
+//
+//                 // 更新到本地数据库
+//                 let trades_map = TRADES_MAP.lock().await;
+//                 update_trade(trade, trades_map, EXCHANGE_NAME).await;
+//             }
+//         }
+//         // k线数据
+//         "futures.candlesticks" => {
+//             let mut records = ExchangeStructHandler::records_handle(ExchangeEnum::KucoinSwap, &response);
+//
+//             let mul_map = MUL_MAP.lock().await;
+//             for record in records.iter_mut() {
+//                 // 真实交易量处理,因为kucoin的量都是张数
+//                 let mul = mul_map[record.symbol.as_str()];
+//                 let mid_price = (record.high + record.low) * dec!(0.5);
+//                 let mut real_volume = record.volume * mul * mid_price;
+//                 real_volume.rescale(2);
+//                 record.volume = real_volume;
+//
+//                 // 更新到本地数据库
+//                 let record_map = RECORD_MAP.lock().await;
+//                 update_record(record, record_map, EXCHANGE_NAME).await;
+//             }
+//         }
+//         _ => {
+//             // info!("48 未知的数据类型: {:?}", response)
+//         }
+//     }
+// }

+ 5 - 3
src/main.rs

@@ -12,6 +12,7 @@ mod mexc_usdt_swap_data_listener;
 mod okx_usdt_swap_data_listener;
 mod bitmart_usdt_swap_data_listener;
 mod kucoin_usdt_swap_data_listener;
+mod coinsph_usdt_swap_data_listener;
 
 
 use std::sync::Arc;
@@ -39,15 +40,16 @@ async fn main() {
     // 启动各交易所的数据监听器
     // bitget_usdt_swap_data_listener::run_listener(running.clone()).await;
     // okx_usdt_swap_data_listener::run_listener(running.clone()).await;
-    // bingx_usdt_swap_data_listener::run_listener(running.clone()).await;
     // mexc_usdt_swap_data_listener::run_listener(running.clone()).await;
+    // kucoin_usdt_swap_data_listener::run_listener(running.clone()).await;
+    // bitmart_usdt_swap_data_listener::run_listener(running.clone()).await;
 
     binance_usdt_swap_data_listener::run_listener(running.clone()).await;
     gate_usdt_swap_data_listener::run_listener(running.clone()).await;
     coinex_usdt_swap_data_listener::run_listener(running.clone()).await;
     htx_usdt_swap_data_listener::run_listener(running.clone()).await;
-    bitmart_usdt_swap_data_listener::run_listener(running.clone()).await;
-    kucoin_usdt_swap_data_listener::run_listener(running.clone()).await;
+    bingx_usdt_swap_data_listener::run_listener(running.clone()).await;
+    // coinsph_usdt_swap_data_listener::run_listener(running.clone()).await;
     // panic错误捕获,panic级别的错误直接退出
     // let panic_running = running.clone();
     std::panic::set_hook(Box::new(move |panic_info| {

+ 1 - 0
src/server.rs

@@ -178,6 +178,7 @@ async fn get_exchanges() -> impl Responder {
         "htx_usdt_swap",
         "bitmart_usdt_swap",
         "kucoin_usdt_swap",
+        "coinsph_usdt_swap"
     ];
     let response_data = json!(exchanges);
 

+ 252 - 0
standard/src/coinsph_swap.rs

@@ -0,0 +1,252 @@
+use std::collections::{BTreeMap};
+use std::io::{Error, ErrorKind};
+use std::str::FromStr;
+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::coinsph_swap_rest::CoinsphSwapRest;
+use rust_decimal::prelude::FromPrimitive;
+
+#[allow(dead_code)]
+#[derive(Clone)]
+pub struct CoinsphSwap {
+    exchange: ExchangeEnum,
+    symbol: String,
+    is_colo: bool,
+    params: BTreeMap<String, String>,
+    request: CoinsphSwapRest,
+    market: Market,
+    order_sender: Sender<Order>,
+    error_sender: Sender<Error>,
+}
+
+impl CoinsphSwap {
+    pub async fn new(symbol: String, is_colo: bool, params: BTreeMap<String, String>, order_sender: Sender<Order>, error_sender: Sender<Error>) -> CoinsphSwap {
+        let market = Market::new();
+        let mut coinsph_swap = CoinsphSwap {
+            exchange: ExchangeEnum::CoinsphSwap,
+            symbol: symbol.to_uppercase(),
+            is_colo,
+            params: params.clone(),
+            request: CoinsphSwapRest::new(is_colo, params.clone()),
+            market,
+            order_sender,
+            error_sender,
+        };
+
+        // 修改持仓模式
+        let symbol_array: Vec<&str> = symbol.split("_").collect();
+        let mode_result = coinsph_swap.set_dual_mode(symbol_array[1], true).await;
+        match mode_result {
+            Ok(ok) => {
+                info!("Coinsph:设置持仓模式成功!{:?}", ok);
+            }
+            Err(error) => {
+                error!("Coinsph:设置持仓模式失败!mode_result={}", error)
+            }
+        }
+        // 获取市场信息
+        coinsph_swap.market = CoinsphSwap::get_market(&mut coinsph_swap).await.unwrap_or(coinsph_swap.market);
+        return coinsph_swap;
+    }
+}
+
+#[async_trait]
+impl Platform for CoinsphSwap {
+    // 克隆方法
+    fn clone_box(&self) -> Box<dyn Platform + Send + Sync> { Box::new(self.clone()) }
+    // 获取交易所模式
+    fn get_self_exchange(&self) -> ExchangeEnum {
+        ExchangeEnum::CoinsphSwap
+    }
+    // 获取交易对
+    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, "coinsph_swap:该交易所方法未实现".to_string()))
+    }
+    // 获取账号信息
+    async fn get_account(&mut self) -> Result<Account, Error> {
+        Err(Error::new(ErrorKind::NotFound, "coinsph_swap:该交易所方法未实现".to_string()))
+    }
+
+    async fn get_spot_account(&mut self) -> Result<Vec<Account>, Error> {
+        Err(Error::new(ErrorKind::NotFound, "coinsph_swap:该交易所方法未实现".to_string()))
+    }
+
+    // 获取持仓信息
+    async fn get_position(&mut self) -> Result<Vec<Position>, Error> {
+        Err(Error::new(ErrorKind::NotFound, "coinsph_swap:该交易所方法未实现".to_string()))
+    }
+    // 获取所有持仓
+    async fn get_positions(&mut self) -> Result<Vec<Position>, Error> {
+        Err(Error::new(ErrorKind::NotFound, "coinsph_swap:该交易所方法未实现".to_string()))
+    }
+    // 获取市场行情
+    async fn get_ticker(&mut self) -> Result<Ticker, Error> {
+        Err(Error::new(ErrorKind::NotFound, "coinsph_swap:该交易所方法未实现".to_string()))
+    }
+
+    async fn get_ticker_symbol(&mut self, _symbol: String) -> Result<Ticker, Error> {
+        Err(Error::new(ErrorKind::NotFound, "coinsph_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 symbols = res_data.data["symbols"].as_array().unwrap();
+            let market_info = symbols.iter().find(|&item| item["symbol"].as_str().unwrap() == symbol_format);
+            match market_info {
+                None => {
+                    error!("coinsph_swap:获取Market信息错误!\nget_market:res_data={:?}", res_data);
+                    Err(Error::new(ErrorKind::Other, res_data.to_string()))
+                }
+                Some(value) => {
+                    let base_asset = value["baseAsset"].as_str().unwrap().to_string();
+                    let quote_asset = value["quoteAsset"].as_str().unwrap().to_string();
+
+                    let filter_array = value["filters"].as_array().unwrap().clone();
+                    let price_filter = filter_array.iter().find(|&item| item["filterType"].as_str().unwrap() == "PRICE_FILTER").unwrap();
+                    let lot_size_filter = filter_array.iter().find(|&item| item["filterType"].as_str().unwrap() == "LOT_SIZE").unwrap();
+
+                    let result = Market {
+                        symbol: format!("{}_{}", base_asset, quote_asset),
+                        base_asset,
+                        quote_asset,
+                        tick_size: Decimal::from_str(&price_filter["tickSize"].as_str().unwrap()).unwrap(),
+                        amount_size: Decimal::from_str(lot_size_filter["stepSize"].as_str().unwrap()).unwrap(),
+                        price_precision: Decimal::from_f64(value["pricePrecision"].as_f64().unwrap()).unwrap(),
+                        amount_precision: Decimal::from_f64(value["quantityPrecision"].as_f64().unwrap()).unwrap(),
+                        min_qty: Decimal::from_str(lot_size_filter["minQty"].as_str().unwrap()).unwrap(),
+                        max_qty: Decimal::from_str(lot_size_filter["maxQty"].as_str().unwrap()).unwrap(),
+                        min_notional: Decimal::from_str(price_filter["minPrice"].as_str().unwrap()).unwrap(),
+                        max_notional: Decimal::from_str(price_filter["maxPrice"].as_str().unwrap()).unwrap(),
+                        ct_val: Decimal::ONE,
+                    };
+                    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!({});
+        let res_data = self.request.get_market(params).await;
+        if res_data.code == 200 {
+            let symbols = res_data.data["symbols"].as_array().unwrap();
+            let market_info = symbols.iter().find(|&item| item["symbol"].as_str().unwrap() == symbol_format);
+            match market_info {
+                None => {
+                    error!("coinsph_swap:获取Market信息错误!\nget_market:res_data={:?}", res_data);
+                    Err(Error::new(ErrorKind::Other, res_data.to_string()))
+                }
+                Some(value) => {
+                    let base_asset = value["baseAsset"].as_str().unwrap().to_string();
+                    let quote_asset = value["quoteAsset"].as_str().unwrap().to_string();
+
+                    let filter_array = value["filters"].as_array().unwrap().clone();
+                    let price_filter = filter_array.iter().find(|&item| item["filterType"].as_str().unwrap() == "PRICE_FILTER").unwrap();
+                    let lot_size_filter = filter_array.iter().find(|&item| item["filterType"].as_str().unwrap() == "LOT_SIZE").unwrap();
+
+                    let result = Market {
+                        symbol: format!("{}_{}", base_asset, quote_asset),
+                        base_asset,
+                        quote_asset,
+                        tick_size: Decimal::from_str(&price_filter["tickSize"].as_str().unwrap()).unwrap(),
+                        amount_size: Decimal::from_str(lot_size_filter["stepSize"].as_str().unwrap()).unwrap(),
+                        price_precision: Decimal::from_f64(value["pricePrecision"].as_f64().unwrap()).unwrap(),
+                        amount_precision: Decimal::from_f64(value["quantityPrecision"].as_f64().unwrap()).unwrap(),
+                        min_qty: Decimal::from_str(lot_size_filter["minQty"].as_str().unwrap()).unwrap(),
+                        max_qty: Decimal::from_str(lot_size_filter["maxQty"].as_str().unwrap()).unwrap(),
+                        min_notional: Decimal::from_str(price_filter["minPrice"].as_str().unwrap()).unwrap(),
+                        max_notional: Decimal::from_str(price_filter["maxPrice"].as_str().unwrap()).unwrap(),
+                        ct_val: Decimal::ONE,
+                    };
+                    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, "coinsph_swap:该交易所方法未实现".to_string()))
+    }
+    // 获取订单列表
+    async fn get_orders_list(&mut self, _status: &str) -> Result<Vec<Order>, Error> {
+        Err(Error::new(ErrorKind::NotFound, "coinsph_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, "coinsph_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, "coinsph_swap:该交易所方法未实现".to_string()))
+    }
+
+    // 撤销订单
+    async fn cancel_order(&mut self, _order_id: &str, _custom_id: &str) -> Result<Order, Error> {
+        Err(Error::new(ErrorKind::NotFound, "coinsph_swap:该交易所方法未实现".to_string()))
+    }
+    // 批量撤销订单
+    async fn cancel_orders(&mut self) -> Result<Vec<Order>, Error> {
+        Err(Error::new(ErrorKind::NotFound, "coinsph_swap:该交易所方法未实现".to_string()))
+    }
+
+    async fn cancel_orders_all(&mut self) -> Result<Vec<Order>, Error> {
+        Err(Error::new(ErrorKind::NotFound, "coinsph_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, "coinsph_swap:该交易所方法未实现".to_string()))
+    }
+
+    async fn cancel_stop_loss_order(&mut self, _order_id: &str) -> Result<Value, Error> {
+        Err(Error::new(ErrorKind::NotFound, "coinsph_swap:该交易所方法未实现".to_string()))
+    }
+
+    // 设置持仓模式
+    async fn set_dual_mode(&mut self, _coin: &str, _is_dual_mode: bool) -> Result<String, Error> {
+        Err(Error::new(ErrorKind::NotFound, "coinsph_swap:该交易所方法未实现".to_string()))
+    }
+
+    // 更新双持仓模式下杠杆
+    async fn set_dual_leverage(&mut self, _leverage: &str) -> Result<String, Error> {
+        Err(Error::new(ErrorKind::NotFound, "coinsph_swap:该交易所方法未实现".to_string()))
+    }
+
+    async fn set_auto_deposit_status(&mut self, _status: bool) -> Result<String, Error> { Err(Error::new(ErrorKind::NotFound, "coinsph:该交易所方法未实现".to_string())) }
+
+    // 交易账户互转
+    async fn wallet_transfers(&mut self, _coin: &str, _from: &str, _to: &str, _amount: Decimal) -> Result<String, Error> {
+        Err(Error::new(ErrorKind::NotFound, "coinsph_swap:该交易所方法未实现".to_string()))
+    }
+}

+ 94 - 0
standard/src/coinsph_swap_handle.rs

@@ -0,0 +1,94 @@
+use std::str::FromStr;
+use rust_decimal::Decimal;
+use rust_decimal::prelude::FromPrimitive;
+use serde_json::Value;
+use exchanges::response_base::ResponseData;
+use crate::{Trade, Record};
+// use crate::{OrderBook, Trade, Record};
+// use crate::{Account, OrderBook, Order, Position, SpecialOrder, Trade, Record};
+
+// 处理账号信息
+// pub fn handle_account_info(res_data: &ResponseData, symbol: &String) -> Account {
+//     Account::new()
+// }
+//
+// pub fn format_account_info(_data: &Vec<Value>, _symbol: &String) -> Account {
+//     Account::new()
+// }
+//
+// // 处理position信息
+// pub fn handle_position(_res_data: &ResponseData, _ct_val: &Decimal) -> Vec<Position> {
+//     vec![Position::new()]
+// }
+//
+// pub fn format_position_item(_position: &Value, _ct_val: &Decimal) -> Position {
+//     Position::new()
+// }
+//
+// // 处理order信息
+// pub fn handle_order(_res_data: &ResponseData, _ct_val: Decimal) -> SpecialOrder {
+//     SpecialOrder::new()
+// }
+//
+// pub fn format_order_item(_order: Value, _ct_val: Decimal) -> Order {
+//     Order::new()
+// }
+// 处理特殊Ticket信息
+// pub fn handle_book_ticker(res_data: &ResponseData) -> SpecialDepth {
+//     let bp = Decimal::from_str((*res_data).data["b"].as_str().unwrap()).unwrap();
+//     let bq = Decimal::from_f64((*res_data).data["B"].as_f64().unwrap()).unwrap();
+//     let ap = Decimal::from_str((*res_data).data["a"].as_str().unwrap()).unwrap();
+//     let aq = Decimal::from_f64((*res_data).data["A"].as_f64().unwrap()).unwrap();
+//     let mp = (bp + ap) * dec!(0.5);
+//     let t = Decimal::from_u64((*res_data).data["u"].as_u64().unwrap()).unwrap();
+//     let create_at = (*res_data).data["t"].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,
+//     }
+// }
+
+pub fn handle_records(value: &Value) -> Vec<Record> {
+    let data = value["k"].clone();
+    return vec![Record {
+        time: Decimal::from_i64(data["t"].as_i64().unwrap()).unwrap(),
+        open: Decimal::from_str(data["o"].as_str().unwrap()).unwrap(),
+        high: Decimal::from_str(data["h"].as_str().unwrap()).unwrap(),
+        low: Decimal::from_str(data["l"].as_str().unwrap()).unwrap(),
+        close: Decimal::from_str(data["c"].as_str().unwrap()).unwrap(),
+        volume: Decimal::from_str(data["q"].as_str().unwrap()).unwrap(),
+        symbol: data["s"].as_str().unwrap().replace("USDT","_USDT"),
+    }];
+}
+
+// pub fn format_depth_items(value: &Value) -> Vec<OrderBook> {
+//     let mut depth_items: Vec<OrderBook> = vec![];
+//     for value in value.as_array().unwrap() {
+//         depth_items.push(OrderBook {
+//             price: Decimal::from_f64(value[0].as_f64().unwrap()).unwrap(),
+//             amount: Decimal::from_f64(value[1].as_f64().unwrap()).unwrap(),
+//         })
+//     }
+//     return depth_items;
+// }
+
+pub fn format_trade_items(res_data: &ResponseData) -> Vec<Trade> {
+    let result = res_data.data.clone();
+
+    let side = result["m"] == true;
+    let size = Decimal::from_str(result["q"].as_str().unwrap()).unwrap();
+    return vec![Trade {
+        id: result["a"].to_string(),
+        time: Decimal::from_i64(result["T"].as_i64().unwrap()).unwrap(),
+        size: if side { -size } else { size },
+        price: Decimal::from_str(result["p"].as_str().unwrap()).unwrap(),
+        symbol: result["s"].as_str().unwrap().replace("USDT","_USDT"),
+    }];
+}

+ 6 - 1
standard/src/exchange.rs

@@ -13,6 +13,7 @@ use crate::htx_swap::HtxSwap;
 use crate::bingx_swap::BingxSwap;
 use crate::mexc_swap::MexcSwap;
 use crate::bitmart_swap::BitMartSwap;
+use crate::coinsph_swap::CoinsphSwap;
 
 
 /// 交易所交易模式枚举
@@ -37,7 +38,8 @@ pub enum ExchangeEnum {
     HtxSwap,
     BingxSwap,
     MexcSwap,
-    BitMartSwap
+    BitMartSwap,
+    CoinsphSwap
 }
 
 /// Exchange结构体
@@ -124,6 +126,9 @@ impl Exchange {
             ExchangeEnum::BitMartSwap => {
                 Box::new(BitMartSwap::new(symbol, is_colo, params, order_sender, error_sender).await)
             }
+            ExchangeEnum::CoinsphSwap => {
+                Box::new(CoinsphSwap::new(symbol, is_colo, params, order_sender, error_sender).await)
+            }
         }
     }
 }

+ 11 - 5
standard/src/exchange_struct_handler.rs

@@ -4,7 +4,7 @@ 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, bybit_swap_handle, bitget_swap_handle, coinex_swap_handle, kucoin_handle, htx_swap_handle, bingx_swap_handle, mexc_swap_handle, okx_swap_handle, bitmart_swap_handle, kucoin_swap_handle};
+use crate::{binance_swap_handle, gate_swap_handle, bybit_swap_handle, bitget_swap_handle, coinex_swap_handle, htx_swap_handle, bingx_swap_handle, mexc_swap_handle, okx_swap_handle, bitmart_swap_handle, kucoin_swap_handle, coinsph_swap_handle};
 use crate::{Record, Ticker, Trade, Depth};
 use crate::{Account, OrderBook, Position, SpecialOrder};
 
@@ -34,8 +34,8 @@ impl ExchangeStructHandler {
                 symbol = res_data.data["contract"].as_str().unwrap().to_string()
             }
             ExchangeEnum::KucoinSwap => {
-                depth_asks = kucoin_handle::format_depth_items(res_data.data["asks"].clone());
-                depth_bids = kucoin_handle::format_depth_items(res_data.data["bids"].clone());
+                depth_asks = kucoin_swap_handle::format_depth_items(res_data.data["asks"].clone());
+                depth_bids = kucoin_swap_handle::format_depth_items(res_data.data["bids"].clone());
                 t = Decimal::from_str(&res_data.data["ts"].to_string()).unwrap();
             }
             ExchangeEnum::BitgetSwap => {
@@ -104,6 +104,9 @@ impl ExchangeStructHandler {
             ExchangeEnum::KucoinSwap => {
                 kucoin_swap_handle::format_trade_items(&res_data)
             }
+            ExchangeEnum::CoinsphSwap => {
+                coinsph_swap_handle::format_trade_items(&res_data)
+            }
             _ => {
                 error!("未找到该交易所!trades_handle: {:?}", exchange);
                 panic!("未找到该交易所!trades_handle: {:?}", exchange);
@@ -149,6 +152,9 @@ impl ExchangeStructHandler {
             ExchangeEnum::KucoinSwap => {
                 kucoin_swap_handle::handle_records(&res_data.data)
             }
+            ExchangeEnum::CoinsphSwap => {
+                coinsph_swap_handle::handle_records(&res_data.data)
+            }
             _ => {
                 error!("未找到该交易所!records_handle: {:?}", exchange);
                 panic!("未找到该交易所!records_handle: {:?}", exchange);
@@ -180,7 +186,7 @@ impl ExchangeStructHandler {
                 gate_swap_handle::handle_position(res_data, ct_val)
             }
             ExchangeEnum::KucoinSwap => {
-                kucoin_handle::handle_position(res_data, ct_val)
+                kucoin_swap_handle::handle_position(res_data, ct_val)
             }
             ExchangeEnum::BitgetSwap => {
                 bitget_swap_handle::handle_position(res_data, ct_val)
@@ -201,7 +207,7 @@ impl ExchangeStructHandler {
                 gate_swap_handle::handle_order(res_data, ct_val)
             }
             ExchangeEnum::KucoinSwap => {
-                kucoin_handle::handle_order(res_data, ct_val)
+                kucoin_swap_handle::handle_order(res_data, ct_val)
             }
             ExchangeEnum::BitgetSwap => {
                 bitget_swap_handle::handle_order(res_data, ct_val)

+ 0 - 142
standard/src/kucoin_handle.rs

@@ -1,142 +0,0 @@
-use std::str::FromStr;
-use rust_decimal::Decimal;
-use rust_decimal::prelude::FromPrimitive;
-use serde_json::Value;
-use exchanges::response_base::ResponseData;
-use crate::{Account, OrderBook, Order, Position, PositionModeEnum, SpecialOrder, utils};
-use crate::exchange::ExchangeEnum;
-
-// 处理账号信息
-pub fn handle_account_info(res_data: &ResponseData, symbol: &String) -> Account {
-    format_account_info(&res_data.data, symbol)
-}
-
-pub fn format_account_info(data: &Value, symbol: &String) -> Account {
-    let symbol_upper = symbol.to_uppercase();
-    let symbol_array: Vec<&str> = symbol_upper.split("_").collect();
-    let available_balance = Decimal::from_str(data["availableBalance"].as_str().unwrap()).unwrap();
-    let frozen_balance = Decimal::from_str(data["holdBalance"].as_str().unwrap()).unwrap();
-    let balance = available_balance + frozen_balance;
-    Account {
-        coin: symbol_array[1].to_string(),
-        balance,
-        available_balance,
-        frozen_balance,
-        stocks: Decimal::ZERO,
-        available_stocks: Decimal::ZERO,
-        frozen_stocks: Decimal::ZERO,
-    }
-}
-
-// 处理特殊Ticket信息
-// pub fn handle_book_ticker(res_data: &ResponseData) -> SpecialDepth {
-//     format_special_ticker(&res_data.data, &res_data.tag)
-// }
-//
-// pub fn format_special_ticker(data: &Value, tag: &String) -> SpecialDepth {
-//     let bp = Decimal::from_str(&data["bestBidPrice"].as_str().unwrap()).unwrap();
-//     let bq = Decimal::from_f64(data["bestBidSize"].as_f64().unwrap()).unwrap();
-//     let ap = Decimal::from_str(&data["bestAskPrice"].as_str().unwrap()).unwrap();
-//     let aq = Decimal::from_f64(data["bestAskSize"].as_f64().unwrap()).unwrap();
-//     let mp = (bp + ap) * dec!(0.5);
-//     let t = Decimal::from_str(&data["sequence"].to_string()).unwrap();
-//     let create_at = (data["ts"].as_f64().unwrap() / 1000.0).floor() as i64;
-//
-//     let ticker_info = SpecialTicker { sell: ap, buy: bp, mid_price: mp, t, create_at };
-//     let depth_info = vec![bp, bq, ap, aq];
-//     SpecialDepth {
-//         name: tag.clone(),
-//         depth: depth_info,
-//         ticker: ticker_info,
-//         t,
-//         create_at,
-//     }
-// }
-
-pub fn format_position_item(position: &Value, ct_val: &Decimal) -> Position {
-    let symbol = position["symbol"].as_str().unwrap_or("");
-    let symbol_mapper = utils::symbol_out_mapper(ExchangeEnum::KucoinSwap, symbol);
-    let real_leverage = Decimal::from_f64(position["realLeverage"].as_f64().unwrap()).unwrap();
-    let currency = position["settleCurrency"].as_str().unwrap_or("");
-    let coin = &symbol_mapper[..symbol_mapper.find(currency).unwrap_or(0)];
-    let avg_entry_price = Decimal::from_f64(position["avgEntryPrice"].as_f64().unwrap()).unwrap();
-    let unrealised_pnl = Decimal::from_f64(position["unrealisedPnl"].as_f64().unwrap()).unwrap();
-    let pos_margin = Decimal::from_f64(position["posMargin"].as_f64().unwrap()).unwrap();
-
-    let current_qty = Decimal::from_f64(position["currentQty"].as_f64().unwrap()).unwrap();
-    let amount = current_qty * ct_val;
-    let 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: real_leverage,
-        amount,
-        frozen_amount: Decimal::ZERO,
-        price: avg_entry_price,
-        profit: unrealised_pnl,
-        position_mode,
-        margin: pos_margin,
-    }
-}
-
-// 处理position信息
-pub fn handle_position(res_data: &ResponseData, ct_val: &Decimal) -> Vec<Position> {
-    let result = format_position_item(&res_data.data, ct_val);
-    return vec![result];
-}
-
-// 处理order信息
-pub fn handle_order(res_data: &ResponseData, ct_val: Decimal) -> SpecialOrder {
-    let order_info = vec![format_order_item(&res_data.data, ct_val)];
-
-    SpecialOrder {
-        name: res_data.tag.clone(),
-        order: order_info,
-    }
-}
-
-// ws处理
-pub fn format_order_item(order: &Value, ct_val: Decimal) -> Order {
-    let price = Decimal::from_str(order["price"].as_str().unwrap()).unwrap();
-    let size = Decimal::from_str(order["size"].as_str().unwrap()).unwrap();
-    let status = order["status"].as_str().unwrap_or("");
-    let type_ = order["type"].as_str().unwrap_or("");
-    let filled_size = Decimal::from_str(order["filledSize"].as_str().unwrap()).unwrap();
-
-    let avg_price = price;
-
-    let amount = size * ct_val;
-    let deal_amount = filled_size * ct_val;
-    let custom_status;
-    if ["filled", "canceled"].contains(&type_) {
-        custom_status = "REMOVE".to_string();
-    } else if ["open"].contains(&status) {
-        custom_status = "NEW".to_string();
-    } else {
-        custom_status = "NULL".to_string();
-    }
-    Order {
-        id: order["orderId"].as_str().unwrap().to_string(),
-        custom_id: order["clientOid"].as_str().unwrap_or("").to_string(),
-        price,
-        amount,
-        deal_amount,
-        avg_price,
-        status: custom_status,
-        order_type: order["type"].as_str().unwrap().to_string()
-    }
-}
-
-pub fn format_depth_items(value: serde_json::Value) -> Vec<OrderBook> {
-    let mut depth_items: Vec<OrderBook> = vec![];
-    for value in value.as_array().unwrap() {
-        depth_items.push(OrderBook {
-            price: Decimal::from_str(value[0].as_str().unwrap()).unwrap(),
-            amount: Decimal::from_f64(value[1].as_f64().unwrap()).unwrap(),
-        })
-    }
-    return depth_items;
-}

+ 3 - 3
standard/src/kucoin_swap.rs

@@ -10,7 +10,7 @@ use serde_json::{json, Value};
 use tracing::{error, info};
 use exchanges::kucoin_swap_rest::KucoinSwapRest;
 use crate::exchange::ExchangeEnum;
-use crate::{Account, kucoin_handle, Market, Order, Platform, Position, Ticker, utils};
+use crate::{Account, kucoin_swap_handle, Market, Order, Platform, Position, Ticker, utils};
 
 #[allow(dead_code)]
 #[derive(Clone)]
@@ -119,7 +119,7 @@ impl Platform for KucoinSwap {
         let ct_val = self.market.ct_val;
         let res_data = self.request.get_position(symbol_format).await;
         if res_data.code == 200 {
-            let result = kucoin_handle::format_position_item(&res_data.data, &ct_val);
+            let result = kucoin_swap_handle::format_position_item(&res_data.data, &ct_val);
             Ok(vec![result])
         } else {
             Err(Error::new(ErrorKind::Other, res_data.to_string()))
@@ -134,7 +134,7 @@ impl Platform for KucoinSwap {
             let res_data_json = res_data.data.as_array().unwrap();
             let mut result = Vec::new();
             for item in res_data_json.iter() {
-                result.push(kucoin_handle::format_position_item(item, &Decimal::ONE))
+                result.push(kucoin_swap_handle::format_position_item(item, &Decimal::ONE))
             }
             Ok(result)
         } else {

+ 90 - 1
standard/src/kucoin_swap_handle.rs

@@ -1,8 +1,9 @@
+use std::str::FromStr;
 use rust_decimal::Decimal;
 use rust_decimal::prelude::FromPrimitive;
 use serde_json::Value;
 use exchanges::response_base::ResponseData;
-use crate::{Record, Trade};
+use crate::{Order, OrderBook, Position, PositionModeEnum, Record, SpecialOrder, Trade, utils};
 use crate::exchange::ExchangeEnum;
 use crate::utils::symbol_out_mapper;
 
@@ -44,4 +45,92 @@ pub fn handle_records(value: &Value) -> Vec<Record> {
         volume,
         symbol,
     }]
+}
+
+pub fn format_depth_items(value: serde_json::Value) -> Vec<OrderBook> {
+    let mut depth_items: Vec<OrderBook> = vec![];
+    for value in value.as_array().unwrap() {
+        depth_items.push(OrderBook {
+            price: Decimal::from_str(value[0].as_str().unwrap()).unwrap(),
+            amount: Decimal::from_f64(value[1].as_f64().unwrap()).unwrap(),
+        })
+    }
+    return depth_items;
+}
+
+pub fn format_position_item(position: &Value, ct_val: &Decimal) -> Position {
+    let symbol = position["symbol"].as_str().unwrap_or("");
+    let symbol_mapper = utils::symbol_out_mapper(ExchangeEnum::KucoinSwap, symbol);
+    let real_leverage = Decimal::from_f64(position["realLeverage"].as_f64().unwrap()).unwrap();
+    let currency = position["settleCurrency"].as_str().unwrap_or("");
+    let coin = &symbol_mapper[..symbol_mapper.find(currency).unwrap_or(0)];
+    let avg_entry_price = Decimal::from_f64(position["avgEntryPrice"].as_f64().unwrap()).unwrap();
+    let unrealised_pnl = Decimal::from_f64(position["unrealisedPnl"].as_f64().unwrap()).unwrap();
+    let pos_margin = Decimal::from_f64(position["posMargin"].as_f64().unwrap()).unwrap();
+
+    let current_qty = Decimal::from_f64(position["currentQty"].as_f64().unwrap()).unwrap();
+    let amount = current_qty * ct_val;
+    let 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: real_leverage,
+        amount,
+        frozen_amount: Decimal::ZERO,
+        price: avg_entry_price,
+        profit: unrealised_pnl,
+        position_mode,
+        margin: pos_margin,
+    }
+}
+
+// 处理position信息
+pub fn handle_position(res_data: &ResponseData, ct_val: &Decimal) -> Vec<Position> {
+    let result = format_position_item(&res_data.data, ct_val);
+    return vec![result];
+}
+
+// 处理order信息
+pub fn handle_order(res_data: &ResponseData, ct_val: Decimal) -> SpecialOrder {
+    let order_info = vec![format_order_item(&res_data.data, ct_val)];
+
+    SpecialOrder {
+        name: res_data.tag.clone(),
+        order: order_info,
+    }
+}
+
+// ws处理
+pub fn format_order_item(order: &Value, ct_val: Decimal) -> Order {
+    let price = Decimal::from_str(order["price"].as_str().unwrap()).unwrap();
+    let size = Decimal::from_str(order["size"].as_str().unwrap()).unwrap();
+    let status = order["status"].as_str().unwrap_or("");
+    let type_ = order["type"].as_str().unwrap_or("");
+    let filled_size = Decimal::from_str(order["filledSize"].as_str().unwrap()).unwrap();
+
+    let avg_price = price;
+
+    let amount = size * ct_val;
+    let deal_amount = filled_size * ct_val;
+    let custom_status;
+    if ["filled", "canceled"].contains(&type_) {
+        custom_status = "REMOVE".to_string();
+    } else if ["open"].contains(&status) {
+        custom_status = "NEW".to_string();
+    } else {
+        custom_status = "NULL".to_string();
+    }
+    Order {
+        id: order["orderId"].as_str().unwrap().to_string(),
+        custom_id: order["clientOid"].as_str().unwrap_or("").to_string(),
+        price,
+        amount,
+        deal_amount,
+        avg_price,
+        status: custom_status,
+        order_type: order["type"].as_str().unwrap().to_string()
+    }
 }

+ 3 - 2
standard/src/lib.rs

@@ -22,7 +22,7 @@ mod gate_swap;
 mod gate_spot;
 pub mod gate_swap_handle;
 mod kucoin_swap;
-pub mod kucoin_handle;
+mod kucoin_swap_handle;
 mod okx_swap;
 pub mod okx_swap_handle;
 mod bitget_spot;
@@ -43,7 +43,8 @@ mod mexc_swap;
 mod mexc_swap_handle;
 mod bitmart_swap;
 mod bitmart_swap_handle;
-mod kucoin_swap_handle;
+mod coinsph_swap;
+mod coinsph_swap_handle;
 
 /// 持仓模式枚举
 /// - `Both`:单持仓方向