Browse Source

这个版本是特殊定制的,只有币安有深度数据的版本。

skyffire 1 year ago
parent
commit
8dad07f45d

+ 40 - 0
README.MD

@@ -0,0 +1,40 @@
+## /order_book 获取订单簿信息
+## GET类型
+
+##### request
+``` json
+{
+    "exchange": "binance_usdt_swap",        // 交易所,当前支持[binance_usdt_swap]
+    "symbol": "ETH_USDT",                   // 符号,当前仅支持ETH_USDT
+    "start_time": "1715071080000",          // 查询开始时间戳
+    "end_time": "1715071081000"             // 查询结束时间戳
+}
+```
+
+##### response
+``` json
+{
+    "msg": "查询成功",                      // 后台提醒
+    "query": {                             // 后台收到的查询参数,可用于debug
+        "end_time": 1715071081000,
+        "exchange": "binance_usdt_swap",
+        "start_time": 1715071080000,
+        "symbol": "ETH_USDT"
+    },
+    "data": [                               // 返回的数据结构
+        {
+            "a": [                          // 卖盘,卖一在前
+                ["3118.56", "68.022"],      // 卖一价,卖一量     
+                ["3118.57", "8.748"],       // 卖二价,卖二量   
+                ...
+            ],
+            "b": [                          // 买盘,买一在前
+                ["3118.55", "68.023"],      // 买一价,买一量
+                ["3118.54", "28.022"],      // 买二价,买二量
+                ... 
+            ],
+            "t": "1715071080082"            // 此深度对应的时间戳,是交易所的数据生成时间
+        }
+    ]
+}
+```

+ 45 - 31
exchanges/src/binance_swap_rest.rs

@@ -1,10 +1,9 @@
 use std::collections::BTreeMap;
-use std::str::FromStr;
 use reqwest::header::HeaderMap;
 use hex;
 use reqwest::Client;
 use rust_decimal::Decimal;
-use rust_decimal::prelude::FromPrimitive;
+use rust_decimal::prelude::{FromPrimitive, ToPrimitive};
 use rust_decimal_macros::dec;
 use crate::http_tool::RestTool;
 use crate::response_base::ResponseData;
@@ -63,12 +62,12 @@ impl BinanceSwapRest {
     /*******************************************************************************************************/
     //获取系统时间
     pub async fn get_server_time(&mut self) -> ResponseData {
-        let params = serde_json::json!({
+        let params = json!({
          });
 
         let data = self.request("GET".to_string(),
                                 "".to_string(),
-                                format!("/fapi/v1/time"),
+                                "/fapi/v1/time".to_string(),
                                 true,
                                 params.to_string(),
         ).await;
@@ -76,11 +75,26 @@ impl BinanceSwapRest {
     }
     //获取交易规则和交易对
     pub async fn get_exchange_info(&mut self) -> ResponseData {
-        let params = serde_json::json!({});
+        let params = json!({});
 
         let data = self.request("GET".to_string(),
                                 "".to_string(),
-                                format!("/fapi/v1/exchangeInfo"),
+                                "/fapi/v1/exchangeInfo".to_string(),
+                                false,
+                                params.to_string(),
+        ).await;
+        data
+    }
+    // 获取深度信息
+    pub async fn get_order_book(&mut self, symbol: &str, limit: i64) -> ResponseData {
+        let params = json!({
+            "symbol": symbol,
+            "limit": limit
+        });
+
+        let data = self.request("GET".to_string(),
+                                "".to_string(),
+                                "/fapi/v1/depth".to_string(),
                                 false,
                                 params.to_string(),
         ).await;
@@ -90,13 +104,13 @@ impl BinanceSwapRest {
 
     //账户信息
     pub async fn get_account(&mut self) -> ResponseData {
-        let params = serde_json::json!({
+        let params = json!({
             "recvWindow":"2000"
          });
 
         let data = self.request("GET".to_string(),
                                 "".to_string(),
-                                format!("/fapi/v2/balance"),
+                                "/fapi/v2/balance".to_string(),
                                 true,
                                 params.to_string(),
         ).await;
@@ -105,7 +119,7 @@ impl BinanceSwapRest {
 
     //查询订单
     pub async fn get_order(&mut self, symbol: String, order_id: i64, orig_client_order_id: String) -> ResponseData {
-        let mut params = serde_json::json!({
+        let mut params = json!({
             "symbol":symbol,
             "recvWindow":"2000"
          });
@@ -118,7 +132,7 @@ impl BinanceSwapRest {
 
         let data = self.request("GET".to_string(),
                                 "".to_string(),
-                                format!("/fapi/v1/order"),
+                                "/fapi/v1/order".to_string(),
                                 true,
                                 params.to_string(),
         ).await;
@@ -126,14 +140,14 @@ impl BinanceSwapRest {
     }
     //查看当前全部挂单
     pub async fn get_open_orders(&mut self, symbol: String) -> ResponseData {
-        let params = serde_json::json!({
+        let params = json!({
             "symbol":symbol,
             "recvWindow":"2000"
          });
 
         let data = self.request("GET".to_string(),
                                 "".to_string(),
-                                format!("/fapi/v1/openOrders"),
+                                "/fapi/v1/openOrders".to_string(),
                                 true,
                                 params.to_string(),
         ).await;
@@ -141,7 +155,7 @@ impl BinanceSwapRest {
     }
     //查询所有订单(包括历史订单)
     pub async fn get_all_orders(&mut self, symbol: String, limit: u64, start_time: i64, end_time: i64) -> ResponseData {
-        let params = serde_json::json!({
+        let params = json!({
             "symbol":symbol,
             "limit":limit,
             "startTime":start_time,
@@ -151,7 +165,7 @@ impl BinanceSwapRest {
 
         let data = self.request("GET".to_string(),
                                 "".to_string(),
-                                format!("/fapi/v1/allOrders"),
+                                "/fapi/v1/allOrders".to_string(),
                                 true,
                                 params.to_string(),
         ).await;
@@ -159,13 +173,13 @@ impl BinanceSwapRest {
     }
     //当前最优挂单
     pub async fn get_book_ticker(&mut self, symbol: String) -> ResponseData {
-        let params = serde_json::json!({
+        let params = json!({
             "symbol":symbol
          });
 
         let data = self.request("GET".to_string(),
                                 "".to_string(),
-                                format!("/fapi/v1/ticker/bookTicker"),
+                                "/fapi/v1/ticker/bookTicker".to_string(),
                                 true,
                                 params.to_string(),
         ).await;
@@ -173,14 +187,14 @@ impl BinanceSwapRest {
     }
     //用户持仓风险V2
     pub async fn get_position_risk(&mut self, symbol: String) -> ResponseData {
-        let params = serde_json::json!({
+        let params = json!({
             "symbol":symbol,
             "recvWindow":"2000"
          });
 
         let data = self.request("GET".to_string(),
                                 "".to_string(),
-                                format!("/fapi/v2/positionRisk"),
+                                "/fapi/v2/positionRisk".to_string(),
                                 true,
                                 params.to_string(),
         ).await;
@@ -191,7 +205,7 @@ impl BinanceSwapRest {
     pub async fn swap_order(&mut self, params: serde_json::Value) -> ResponseData {
         let data = self.request("POST".to_string(),
                                 "".to_string(),
-                                format!("/fapi/v1/order"),
+                                "/fapi/v1/order".to_string(),
                                 true,
                                 params.to_string(),
         ).await;
@@ -200,13 +214,13 @@ impl BinanceSwapRest {
     //更改持仓模式
     pub async fn change_pos_side(&mut self, dual_side_position: bool) -> ResponseData {
         let dual_side_position_str = format!("{}", dual_side_position);
-        let params = serde_json::json!({
+        let params = json!({
             "dualSidePosition":dual_side_position_str,
             "recvWindow":"2000"
          });
         let data = self.request("POST".to_string(),
                                 "".to_string(),
-                                format!("/fapi/v1/positionSide/dual"),
+                                "/fapi/v1/positionSide/dual".to_string(),
                                 true,
                                 params.to_string(),
         ).await;
@@ -214,7 +228,7 @@ impl BinanceSwapRest {
     }
     //撤销订单
     pub async fn cancel_order(&mut self, symbol: String, order_id: i64, orig_client_order_id: String) -> ResponseData {
-        let mut params = serde_json::json!({
+        let mut params = json!({
             "symbol":symbol,
             "recvWindow":"2000"
          });
@@ -226,7 +240,7 @@ impl BinanceSwapRest {
         }
         let data = self.request("DELETE".to_string(),
                                 "".to_string(),
-                                format!("/fapi/v1/order"),
+                                "/fapi/v1/order".to_string(),
                                 true,
                                 params.to_string(),
         ).await;
@@ -234,13 +248,13 @@ impl BinanceSwapRest {
     }
     //根据币对 撤销全部订单
     pub async fn cancel_order_all(&mut self, symbol: String) -> ResponseData {
-        let params = serde_json::json!({
+        let params = json!({
             "symbol":symbol,
             "recvWindow":"2000",
          });
         let data = self.request("DELETE".to_string(),
                                 "".to_string(),
-                                format!("/fapi/v1/allOpenOrders"),
+                                "/fapi/v1/allOpenOrders".to_string(),
                                 true,
                                 params.to_string(),
         ).await;
@@ -248,7 +262,7 @@ impl BinanceSwapRest {
     }
     //账户成交历史
     pub async fn get_user_trades(&mut self, symbol: String, start_time: i64, end_time: i64, limit: i64) -> ResponseData {
-        let mut params = serde_json::json!({
+        let mut params = json!({
             "symbol":symbol,
             "limit":1000,
             "recvWindow":"1000",
@@ -327,10 +341,10 @@ impl BinanceSwapRest {
         }
 
         //请求头配置-如果需要登录则存在额外配置
-        let mut params_json: serde_json::Value = serde_json::from_str(params.clone().as_str()).unwrap();
+        let mut params_json: Value = serde_json::from_str(params.clone().as_str()).unwrap();
         // let mut body = "".to_string();
         let timestamp = chrono::Utc::now().timestamp_millis().to_string();
-        params_json.as_object_mut().unwrap().insert("timestamp".to_string(), serde_json::Value::from(timestamp));
+        params_json.as_object_mut().unwrap().insert("timestamp".to_string(), Value::from(timestamp));
 
 
         let mut headers = HeaderMap::new();
@@ -351,7 +365,7 @@ impl BinanceSwapRest {
                 let sing = Self::sign(secret_key.clone(),
                                       params_json.to_string(),
                 );
-                params_json.as_object_mut().unwrap().insert("signature".to_string(), serde_json::Value::from(sing.clone()));
+                params_json.as_object_mut().unwrap().insert("signature".to_string(), Value::from(sing.clone()));
                 // trace!("sing:{}", sing);
                 //组装header
                 headers.extend(Self::headers(access_key));
@@ -401,7 +415,7 @@ impl BinanceSwapRest {
         let url_param = RestTool::parse_params_to_str(params.clone());
         let addrs_url = format!("{}?{}", url.clone(), url_param);
 
-        let params_json: serde_json::Value = serde_json::from_str(&params).unwrap();
+        let params_json: Value = serde_json::from_str(&params).unwrap();
         trace!("url:{}",url);
         trace!("addrs_url:{}",addrs_url);
         trace!("params_json:{}",params_json);
@@ -443,7 +457,7 @@ impl BinanceSwapRest {
                 let message = data["msg"].as_str().unwrap();
 
                 let mut error = ResponseData::error(self.tag.clone(), message.to_string());
-                error.code = i16::from_str(data["code"].as_str().unwrap()).unwrap();
+                error.code = data["code"].as_i64().unwrap().to_i16().unwrap();
                 error.message = format!("请求地址:{}, 请求参数:{}", base_url, params);
                 error
             }

+ 5 - 0
exchanges/src/binance_swap_ws.rs

@@ -23,6 +23,7 @@ pub enum BinanceSwapSubscribeType {
     PuBookTicker,
     PuAggTrade,
     PuDepth20levels100ms,
+    PuDepthUpdate,
     PuKline,
 }
 
@@ -108,6 +109,7 @@ impl BinanceSwapWs {
                 BinanceSwapSubscribeType::PuBookTicker => false,
                 BinanceSwapSubscribeType::PuAggTrade => false,
                 BinanceSwapSubscribeType::PuDepth20levels100ms => false,
+                BinanceSwapSubscribeType::PuDepthUpdate => false,
                 BinanceSwapSubscribeType::PuKline => false,
             } {
                 return true;
@@ -127,6 +129,9 @@ impl BinanceSwapWs {
             BinanceSwapSubscribeType::PuDepth20levels100ms => {
                 format!("{}@depth20@100ms", symbol)
             }
+            BinanceSwapSubscribeType::PuDepthUpdate => {
+                format!("{}@depth@100ms", symbol)
+            }
             BinanceSwapSubscribeType::PuBookTicker => {
                 format!("{}@bookTicker", symbol)
             }

+ 148 - 53
src/binance_usdt_swap_data_listener.rs

@@ -1,18 +1,25 @@
 use std::collections::{BTreeMap, HashMap};
 use std::sync::{Arc};
 use std::sync::atomic::AtomicBool;
+use std::time::Duration;
 use lazy_static::lazy_static;
-use tokio::sync::{Mutex};
+use rust_decimal::Decimal;
+use rust_decimal_macros::dec;
+use serde_json::{json, Value};
+use tokio::sync::{Mutex, MutexGuard};
 use tracing::info;
 use exchanges::binance_swap_rest::BinanceSwapRest;
 use exchanges::binance_swap_ws::{BinanceSwapSubscribeType, BinanceSwapWs, BinanceSwapWsType};
 use exchanges::response_base::ResponseData;
 use standard::exchange::ExchangeEnum;
 use standard::exchange_struct_handler::ExchangeStructHandler;
+use standard::{Depth, OrderBook, SpecialDepth};
 use crate::listener_tools::{DepthMap, RecordMap, TradeMap, update_depth, update_record, update_trade};
 const EXCHANGE_NAME: &str = "binance_usdt_swap";
 
 lazy_static! {
+    static ref LOCAL_DEPTH: Mutex<HashMap<String, Depth>> = Mutex::new(HashMap::new());             // 本地缓存的订单簿
+
     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());
@@ -23,56 +30,78 @@ pub async fn run_listener(is_shutdown_arc: Arc<AtomicBool>) {
     // 订阅所有币种
     let login = BTreeMap::new();
     let mut binance_rest = BinanceSwapRest::new(false, login);
-    let response = binance_rest.get_exchange_info().await;
-    let mut symbols = vec![];
-    if response.code == 200 {
-        let data = response.data["symbols"].as_array().unwrap();
-        for info in data {
-            let s = info["symbol"].as_str().unwrap().to_string();
-            if !s.ends_with("USDT") {
-                continue
+    // let response = binance_rest.get_exchange_info().await;
+    // let mut symbols = vec![];
+    // if response.code == 200 {
+    //     let data = response.data["symbols"].as_array().unwrap();
+    //     for info in data {
+    //         let s = info["symbol"].as_str().unwrap().to_string();
+    //         if !s.ends_with("USDT") {
+    //             continue
+    //         }
+    //         let symbol = s.replace("USDT", "_USDT");
+    //         symbols.push(symbol)
+    //     }
+    // }
+    // info!(?symbols);
+    //
+    // 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 = BinanceSwapWs::new_with_tag(ws_name, false, None, BinanceSwapWsType::PublicAndPrivate);
+    //         ws.set_subscribe(vec![
+    //             BinanceSwapSubscribeType::PuAggTrade,
+    //             BinanceSwapSubscribeType::PuKline,
+    //         ]);
+    //
+    //         // 建立链接
+    //         ws.set_symbols(symbols_chunk);
+    //         ws.ws_connect_async(is_shutdown_clone, data_listener, &write_tx_am, write_rx).await.expect("链接失败(内部一个心跳线程应该已经关闭了)");
+    //     });
+    // }
+
+    // 2024-5-7任务 单独订阅ETH的全档位深度数据
+    let depth_symbols = vec!["ETH_USDT".to_string()];
+    // 每60s初始化一次深度信息
+    let symbols_clone = depth_symbols.clone();
+    tokio::spawn(async move {
+        loop {
+            for depth_symbol in &symbols_clone {
+                let formated_str = depth_symbol.replace("_", "");
+                let mut response = binance_rest.get_order_book(formated_str.as_str(), 1000).await;
+
+                response.channel = "depthInit".to_string();
+                response.data["a"] = response.data["asks"].clone();
+                response.data["b"] = response.data["bids"].clone();
+                response.data["s"] = json!(formated_str.as_str());
+                response.data["asks"] = Value::Null;
+                response.data["bids"] = Value::Null;
+
+                data_listener(response).await;
             }
-            let symbol = s.replace("USDT", "_USDT");
-            symbols.push(symbol)
+
+            tokio::time::sleep(Duration::from_secs(10)).await;
         }
-    }
-    info!(?symbols);
-
-    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 = BinanceSwapWs::new_with_tag(ws_name, false, None, BinanceSwapWsType::PublicAndPrivate);
-            ws.set_subscribe(vec![
-                BinanceSwapSubscribeType::PuAggTrade,
-                BinanceSwapSubscribeType::PuKline,
-            ]);
-
-            // 建立链接
-            ws.set_symbols(symbols_chunk);
-            ws.ws_connect_async(is_shutdown_clone, data_listener, &write_tx_am, write_rx).await.expect("链接失败(内部一个心跳线程应该已经关闭了)");
-        });
-    }
+    });
+    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 is_shutdown_clone = Arc::clone(&is_shutdown_arc);
+    tokio::spawn(async move {
+        let mut ws = BinanceSwapWs::new_with_tag(ws_name, false, None, BinanceSwapWsType::PublicAndPrivate);
+        ws.set_subscribe(vec![
+            BinanceSwapSubscribeType::PuDepthUpdate
+        ]);
 
-    // // 2024-5-7任务 单独订阅ETH的全档位深度数据
-    // 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 is_shutdown_clone = Arc::clone(&is_shutdown_arc);
-    // tokio::spawn(async move {
-    //     let mut ws = BinanceSwapWs::new_with_tag(ws_name, false, None, BinanceSwapWsType::PublicAndPrivate);
-    //     ws.set_subscribe(vec![
-    //         BinanceSwapSubscribeType::PuDepth20levels100ms
-    //     ]);
-    //
-    //     // 建立链接
-    //     ws.set_symbols(vec!["ETH_USDT".to_string()]);
-    //     ws.ws_connect_async(is_shutdown_clone, data_listener, &write_tx_am, write_rx).await.expect("链接失败(内部一个心跳线程应该已经关闭了)");
-    // });
+        // 建立链接
+        ws.set_symbols(depth_symbols);
+        ws.ws_connect_async(is_shutdown_clone, data_listener, &write_tx_am, write_rx).await.expect("链接失败(内部一个心跳线程应该已经关闭了)");
+    });
 }
 
 // 读取数据
@@ -81,14 +110,39 @@ pub async fn data_listener(response: ResponseData) {
         return;
     }
 
-    match response.channel.as_str() {
-        // 深度数据
-        "深度" => {
-            let depth = ExchangeStructHandler::order_book_handle(ExchangeEnum::GateSwap, &response);
-            let depth_map = DEPTH_MAP.lock().await;
+    // 更新的增量深度数据特殊处理
+    let mut channel = response.channel.clone();
+    if channel.contains("@depth@100ms") {
+        channel = "depthUpdate".to_string();
+    }
+
+    match channel.as_str() {
+        // 初始化的深度数据
+        "depthInit" => {
+            let depth = ExchangeStructHandler::order_book_handle(ExchangeEnum::BinanceSwap, &response);
 
+            // 更新本地队列
+            let mut local_depth_map = LOCAL_DEPTH.lock().await;
+            local_depth_map.insert(depth.symbol.clone(), depth.clone());
+
+            // 标准化后进行深度更新逻辑
+            let depth_map = DEPTH_MAP.lock().await;
             update_depth(&depth, depth_map, EXCHANGE_NAME).await;
         },
+        // 增量深度数据
+        "depthUpdate" => {
+            let update = ExchangeStructHandler::order_book_handle(ExchangeEnum::BinanceSwap, &response);
+            // 更新本地队列
+            let local_depth_map = LOCAL_DEPTH.lock().await;
+            if local_depth_map.contains_key(update.symbol.as_str()) {
+                merge_depths(local_depth_map, &update);
+
+                // 标准化后进行深度更新逻辑
+                let updated_local_depth = LOCAL_DEPTH.lock().await.get(update.symbol.as_str()).unwrap().clone();
+                let depth_map = DEPTH_MAP.lock().await;
+                update_depth(&updated_local_depth, depth_map, EXCHANGE_NAME).await;
+            }
+        },
         // 订单流数据
         "aggTrade" => {
             let trades = ExchangeStructHandler::trades_handle(ExchangeEnum::BinanceSwap, &response);
@@ -114,3 +168,44 @@ pub async fn data_listener(response: ResponseData) {
         }
     }
 }
+
+fn merge_depths(mut local_depth_map: MutexGuard<'_, HashMap<String, Depth>>, update: &Depth) {
+    if let Some(local) = local_depth_map.get_mut(update.symbol.as_str()) {
+        local.time = update.time;
+
+        // Merge asks
+        merge_order_books(&mut local.asks, &update.asks, true);
+
+        // Merge bids
+        merge_order_books(&mut local.bids, &update.bids, false);
+    }
+}
+
+fn merge_order_books(local_books: &mut Vec<OrderBook>, update_books: &Vec<OrderBook>, is_asc: bool) {
+    for update_book in update_books {
+        if update_book.amount.eq(&Decimal::ZERO) {
+            // Remove the order book at this price point if amount is zero
+            local_books.retain(|book| book.price != update_book.price);
+        } else {
+            let mut found = false;
+            for local_book in local_books.iter_mut() {
+                if local_book.price == update_book.price {
+                    // Update the amount for this price
+                    local_book.amount = update_book.amount;
+                    found = true;
+                    break;
+                }
+            }
+            if !found {
+                // Add new order book if not found
+                local_books.push(update_book.clone());
+            }
+        }
+    }
+
+    if is_asc {
+        local_books.sort_by(|a, b| a.price.partial_cmp(&b.price).unwrap());
+    } else {
+        local_books.sort_by(|a, b| b.price.partial_cmp(&a.price).unwrap());
+    }
+}

+ 33 - 1
src/json_db_utils.rs

@@ -1,11 +1,12 @@
 use std::path::{Path, PathBuf};
 use chrono::{FixedOffset, TimeZone, Utc};
+use rust_decimal::prelude::ToPrimitive;
 use serde_json::Value;
 use tokio::fs::File;
 use tokio::io::AsyncWriteExt;
 use tokio::{fs};
 use tracing::{error, info};
-use standard::{Record, SpecialTrade};
+use standard::{Record, SpecialDepth, SpecialTrade};
 
 pub async fn write_to_file(json_data: String, file_path: String) {
     // 尝试创建文件路径
@@ -123,6 +124,37 @@ pub async fn collect_records_json(start_timestamp: i64, end_timestamp: i64, exch
     serde_json::to_value(&records).unwrap()
 }
 
+// 将一个时间段范围内的所有Depth返回(以json形式)
+pub async fn collect_depth_json(start_timestamp: i64, end_timestamp: i64, exchange: &str, symbol: &str) -> Value {
+    let mut depths = Vec::new();
+    let filenames = generate_filenames(start_timestamp, end_timestamp, exchange, symbol, "order_book");
+
+    for filename in filenames {
+        let file_path = PathBuf::from(filename.as_str());
+
+        let file_content = fs::read_to_string(file_path).await;
+
+        // 检查文件内容是否成功读取
+        if let Ok(content) = file_content {
+            // 尝试反序列化文件内容
+            if let Ok(mut depth_list) = serde_json::from_str::<Vec<SpecialDepth>>(&content) {
+                // info!("{} 找到 1 条", filename);
+                for mut depth in depth_list {
+                    // 不在时间范围内的就不要返回了
+                    let t = depth.t.to_i64().unwrap();
+                    if t < start_timestamp || t > end_timestamp {
+                        continue
+                    }
+
+                    depths.push(depth)
+                }
+            }
+        }
+    }
+
+    serde_json::to_value(&depths).unwrap()
+}
+
 fn find_latest_directory(path: &Path) -> std::io::Result<Option<PathBuf>> {
     let mut latest: Option<(PathBuf, std::time::SystemTime)> = None;
 

+ 3 - 3
src/main.rs

@@ -30,10 +30,10 @@ async fn main() {
     // ctrl c退出检查程序
     control_c::exit_handler(running.clone());
     // 启动各交易所的数据监听器
-    gate_usdt_swap_data_listener::run_listener(running.clone()).await;
-    bitget_usdt_swap_data_listener::run_listener(running.clone()).await;
     binance_usdt_swap_data_listener::run_listener(running.clone()).await;
-    coinex_usdt_swap_data_listener::run_listener(running.clone()).await;
+    // gate_usdt_swap_data_listener::run_listener(running.clone()).await;
+    // bitget_usdt_swap_data_listener::run_listener(running.clone()).await;
+    // coinex_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| {

+ 34 - 1
src/server.rs

@@ -4,7 +4,7 @@ use actix_web::{web, App, HttpResponse, HttpServer, Responder, get};
 use serde::{Deserialize, Serialize};
 use serde_json::{json, Value};
 use tracing::{info};
-use crate::json_db_utils::{collect_records_json, collect_special_trades_json, get_symbols_by_exchange};
+use crate::json_db_utils::{collect_depth_json, collect_records_json, collect_special_trades_json, get_symbols_by_exchange};
 
 // 定义用于反序列化查询参数的结构体
 #[derive(Serialize, Deserialize, Clone)]
@@ -295,6 +295,38 @@ async fn get_records(query: web::Query<SimpleQuery>) -> impl Responder {
     }
 }
 
+#[get("/order_book")]
+async fn get_order_book(query: web::Query<SimpleQuery>) -> impl Responder {
+    if query.validate() {
+        let response_data = collect_depth_json(
+            query.start_time.clone().unwrap(),
+            query.end_time.clone().unwrap(),
+            query.exchange.clone().unwrap().as_str(),
+            query.symbol.clone().unwrap().as_str()
+        ).await;
+
+        let response = Response {
+            query: serde_json::to_value(&query.into_inner()).unwrap(),
+            msg: Some("查询成功".to_string()),
+            code: 200,
+            data: response_data,
+        };
+
+        let json_string = serde_json::to_string(&response).unwrap();
+        HttpResponse::Ok().content_type("application/json").body(json_string)
+    } else {
+        let response = Response {
+            query: serde_json::to_value(&query.into_inner()).unwrap(),
+            msg: Some("查询内容有误,必须包含四个参数:[symbol, exchange, start_time, end_time]".to_string()),
+            code: 500,
+            data: Value::Null,
+        };
+
+        let json_string = serde_json::to_string(&response).unwrap();
+        HttpResponse::Ok().content_type("application/json").body(json_string)
+    }
+}
+
 pub fn run_server(port: u32, running: Arc<AtomicBool>) {
     let addr = format!("0.0.0.0:{}", port);
     info!("数据服务绑定地址:{}", addr);
@@ -308,6 +340,7 @@ pub fn run_server(port: u32, running: Arc<AtomicBool>) {
             .service(get_trades_count)
             .service(get_records_map)
             .service(get_exchanges)
+            .service(get_order_book)
     })
     .bind(addr)
     .expect("Bind port error")

+ 3 - 2
standard/src/exchange_struct_handler.rs

@@ -1,7 +1,7 @@
 use std::str::FromStr;
 use rust_decimal::{Decimal};
 use rust_decimal::prelude::FromPrimitive;
-use tracing::{error};
+use tracing::{error, info};
 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};
@@ -31,6 +31,7 @@ impl ExchangeStructHandler {
                 depth_asks = binance_swap_handle::format_depth_items(res_data.data["a"].clone());
                 depth_bids = binance_swap_handle::format_depth_items(res_data.data["b"].clone());
                 t = Decimal::from_str(&res_data.data["E"].to_string()).unwrap();
+                symbol = res_data.data["s"].as_str().unwrap().to_string().replace("USDT", "_USDT");
             }
             ExchangeEnum::GateSwap => {
                 depth_asks = gate_swap_handle::format_depth_items(&res_data.data["asks"]);
@@ -80,7 +81,7 @@ impl ExchangeStructHandler {
             asks: depth_asks,
             bids: depth_bids,
             time: t,
-            symbol: symbol,
+            symbol,
         }
     }
     // 处理成交信息