|
|
@@ -1,124 +1,133 @@
|
|
|
-use std::collections::{BTreeMap, HashMap};
|
|
|
-use std::sync::{Arc};
|
|
|
-use std::sync::atomic::AtomicBool;
|
|
|
-use lazy_static::lazy_static;
|
|
|
-use serde_json::json;
|
|
|
-use tokio::sync::{Mutex};
|
|
|
-use tracing::info;
|
|
|
-use exchanges::htx_swap_rest::HtxSwapRest;
|
|
|
-use exchanges::htx_swap_ws::{HtxSwapSubscribeType, HtxSwapWs, HtxSwapWsType};
|
|
|
-use exchanges::response_base::ResponseData;
|
|
|
-use standard::exchange::ExchangeEnum;
|
|
|
-use standard::exchange_struct_handler::ExchangeStructHandler;
|
|
|
-use crate::listener_tools::{RecordMap, TradeMap, update_record, update_trade};
|
|
|
-
|
|
|
-const EXCHANGE_NAME: &str = "htx_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());
|
|
|
-}
|
|
|
-
|
|
|
-pub async fn run_listener(is_shutdown_arc: Arc<AtomicBool>) {
|
|
|
- let name = "htx_usdt_swap_listener";
|
|
|
- // 订阅所有币种
|
|
|
- let login = BTreeMap::new();
|
|
|
- let mut htx_rest = HtxSwapRest::new(false, login);
|
|
|
- let params = json!({
|
|
|
- "contract_type": "swap"
|
|
|
- });
|
|
|
- let response = htx_rest.get_market(params).await;
|
|
|
- let mut symbols = vec![];
|
|
|
- if response.code == 200 {
|
|
|
- let data = response.data.as_array().unwrap();
|
|
|
- for info in data {
|
|
|
- symbols.push(info["contract_code"].as_str().unwrap().to_string().replace("-", "_"))
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- info!(?symbols);
|
|
|
-
|
|
|
- // 将 symbols 分成每份20个元素的小块
|
|
|
- for chunk in symbols.chunks(20) {
|
|
|
- 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 ws_name = name.to_string();
|
|
|
- let write_tx_clone = Arc::clone(&write_tx_am);
|
|
|
- let is_shutdown_clone = Arc::clone(&is_shutdown_arc);
|
|
|
-
|
|
|
- tokio::spawn(async move {
|
|
|
- let mut ws = HtxSwapWs::new_with_tag(ws_name, None, HtxSwapWsType::Public);
|
|
|
- ws.set_subscribe(vec![
|
|
|
- HtxSwapSubscribeType::PuFuturesRecords,
|
|
|
- HtxSwapSubscribeType::PuFuturesTrades
|
|
|
- ]);
|
|
|
-
|
|
|
- // 建立链接
|
|
|
- ws.set_symbols(symbols_chunk);
|
|
|
- ws.ws_connect_async(is_shutdown_clone, data_listener, &write_tx_clone, write_rx).await.unwrap();
|
|
|
- });
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-// 读取数据
|
|
|
-pub async fn data_listener(response: ResponseData) {
|
|
|
- if response.code != 200 {
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
- let (origin_symbol, simple_channel) = extract_parts(response.channel.as_str());
|
|
|
- let mut r = response.clone();
|
|
|
- r.data["symbol"] = json!(origin_symbol);
|
|
|
-
|
|
|
- match simple_channel.as_str() {
|
|
|
- // 深度数据
|
|
|
- "深度" => {
|
|
|
- // let depth = ExchangeStructHandler::order_book_handle(ExchangeEnum::HtxSwap, &r);
|
|
|
- //
|
|
|
- // update_depth(&depth).await;
|
|
|
- },
|
|
|
- // 订单流数据
|
|
|
- "trade.detail" => {
|
|
|
- let trades = ExchangeStructHandler::trades_handle(ExchangeEnum::HtxSwap, &r);
|
|
|
-
|
|
|
- for trade in trades.iter() {
|
|
|
- let trades_map = TRADES_MAP.lock().await;
|
|
|
-
|
|
|
- update_trade(&trade, trades_map, EXCHANGE_NAME).await
|
|
|
- }
|
|
|
- },
|
|
|
- // k线数据
|
|
|
- "kline.1min" => {
|
|
|
- let records = ExchangeStructHandler::records_handle(ExchangeEnum::HtxSwap, &r);
|
|
|
-
|
|
|
- if records.is_empty() {
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
- let record_map= RECORD_MAP.lock().await;
|
|
|
- update_record(&records[records.len() - 1], record_map, EXCHANGE_NAME).await;
|
|
|
- },
|
|
|
- _ => {
|
|
|
- info!("98 未知的数据类型: {:?}", response)
|
|
|
- }
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-fn extract_parts(input: &str) -> (String, String) {
|
|
|
- // 使用 `split` 方法以点号分割字符串,并收集到 Vec 中
|
|
|
- let parts: Vec<&str> = input.split('.').collect();
|
|
|
-
|
|
|
- // 从分割后的数组中获取交易对和详情部分
|
|
|
- // `parts[1]` 应该是 "BTC-USDT",`parts[2]` 是 "trade" 或 "kline",`parts[3]` 是 "detail" 或 "1min"
|
|
|
- let pair = parts.get(1).unwrap_or(&"").to_string().replace("-", "_");
|
|
|
- let detail = if parts.len() > 3 {
|
|
|
- format!("{}.{}", parts[2], parts[3])
|
|
|
- } else {
|
|
|
- input.to_string()
|
|
|
- };
|
|
|
-
|
|
|
- (pair, detail)
|
|
|
-}
|
|
|
+// use std::collections::{BTreeMap, HashMap};
|
|
|
+// use std::sync::{Arc};
|
|
|
+// use std::sync::atomic::AtomicBool;
|
|
|
+// use std::time::Duration;
|
|
|
+// use lazy_static::lazy_static;
|
|
|
+// use serde_json::json;
|
|
|
+// use tokio::sync::{Mutex};
|
|
|
+// use tracing::info;
|
|
|
+// use exchanges::htx_swap_rest::HtxSwapRest;
|
|
|
+// use exchanges::htx_swap_ws::{HtxSwapSubscribeType, HtxSwapWs, HtxSwapWsType};
|
|
|
+// use exchanges::response_base::ResponseData;
|
|
|
+// use standard::exchange::ExchangeEnum;
|
|
|
+// use standard::exchange_struct_handler::ExchangeStructHandler;
|
|
|
+// use crate::json_db_utils::delete_db_by_exchange;
|
|
|
+// use crate::listener_tools::{RecordMap, TradeMap, update_record, update_trade};
|
|
|
+//
|
|
|
+// const EXCHANGE_NAME: &str = "htx_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());
|
|
|
+// }
|
|
|
+//
|
|
|
+// pub async fn run_listener(is_shutdown_arc: Arc<AtomicBool>) {
|
|
|
+// let name = "htx_usdt_swap_listener";
|
|
|
+// // 订阅所有币种
|
|
|
+// let login = BTreeMap::new();
|
|
|
+// let mut htx_rest = HtxSwapRest::new(false, login);
|
|
|
+// let params = json!({
|
|
|
+// "contract_type": "swap"
|
|
|
+// });
|
|
|
+// let response = htx_rest.get_market(params).await;
|
|
|
+// let mut symbols = vec![];
|
|
|
+// if response.code == 200 {
|
|
|
+// let data = response.data.as_array().unwrap();
|
|
|
+// for info in data {
|
|
|
+// symbols.push(info["contract_code"].as_str().unwrap().to_string().replace("-", "_"))
|
|
|
+// }
|
|
|
+// }
|
|
|
+//
|
|
|
+// info!(?symbols);
|
|
|
+//
|
|
|
+// // 将 symbols 分成每份20个元素的小块
|
|
|
+// for chunk in symbols.chunks(20) {
|
|
|
+// 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 ws_name = name.to_string();
|
|
|
+// let write_tx_clone = Arc::clone(&write_tx_am);
|
|
|
+// let is_shutdown_clone = Arc::clone(&is_shutdown_arc);
|
|
|
+//
|
|
|
+// tokio::spawn(async move {
|
|
|
+// let mut ws = HtxSwapWs::new_with_tag(ws_name, None, HtxSwapWsType::Public);
|
|
|
+// ws.set_subscribe(vec![
|
|
|
+// HtxSwapSubscribeType::PuFuturesRecords,
|
|
|
+// HtxSwapSubscribeType::PuFuturesTrades,
|
|
|
+// ]);
|
|
|
+//
|
|
|
+// // 建立链接
|
|
|
+// ws.set_symbols(symbols_chunk);
|
|
|
+// ws.ws_connect_async(is_shutdown_clone, data_listener, &write_tx_clone, write_rx).await.unwrap();
|
|
|
+// });
|
|
|
+// }
|
|
|
+// // 定时删除数据
|
|
|
+// tokio::spawn(async move {
|
|
|
+// loop {
|
|
|
+// delete_db_by_exchange(EXCHANGE_NAME, vec!["trades", "record"], 2880).await;
|
|
|
+// tokio::time::sleep(Duration::from_secs(60 * 60 * 4)).await;
|
|
|
+// }
|
|
|
+// });
|
|
|
+// }
|
|
|
+//
|
|
|
+// // 读取数据
|
|
|
+// pub async fn data_listener(response: ResponseData) {
|
|
|
+// if response.code != 200 {
|
|
|
+// return;
|
|
|
+// }
|
|
|
+//
|
|
|
+// let (origin_symbol, simple_channel) = extract_parts(response.channel.as_str());
|
|
|
+// let mut r = response.clone();
|
|
|
+// r.data["symbol"] = json!(origin_symbol);
|
|
|
+//
|
|
|
+// match simple_channel.as_str() {
|
|
|
+// // 深度数据
|
|
|
+// "深度" => {
|
|
|
+// // let depth = ExchangeStructHandler::order_book_handle(ExchangeEnum::HtxSwap, &r);
|
|
|
+// //
|
|
|
+// // update_depth(&depth).await;
|
|
|
+// }
|
|
|
+// // 订单流数据
|
|
|
+// "trade.detail" => {
|
|
|
+// let trades = ExchangeStructHandler::trades_handle(ExchangeEnum::HtxSwap, &r);
|
|
|
+//
|
|
|
+// for trade in trades.iter() {
|
|
|
+// let trades_map = TRADES_MAP.lock().await;
|
|
|
+//
|
|
|
+// update_trade(&trade, trades_map, EXCHANGE_NAME).await
|
|
|
+// }
|
|
|
+// }
|
|
|
+// // k线数据
|
|
|
+// "kline.1min" => {
|
|
|
+// let records = ExchangeStructHandler::records_handle(ExchangeEnum::HtxSwap, &r);
|
|
|
+//
|
|
|
+// if records.is_empty() {
|
|
|
+// return;
|
|
|
+// }
|
|
|
+//
|
|
|
+// let record_map = RECORD_MAP.lock().await;
|
|
|
+// update_record(&records[records.len() - 1], record_map, EXCHANGE_NAME).await;
|
|
|
+// }
|
|
|
+// _ => {
|
|
|
+// info!("98 未知的数据类型: {:?}", response)
|
|
|
+// }
|
|
|
+// }
|
|
|
+// }
|
|
|
+//
|
|
|
+// fn extract_parts(input: &str) -> (String, String) {
|
|
|
+// // 使用 `split` 方法以点号分割字符串,并收集到 Vec 中
|
|
|
+// let parts: Vec<&str> = input.split('.').collect();
|
|
|
+//
|
|
|
+// // 从分割后的数组中获取交易对和详情部分
|
|
|
+// // `parts[1]` 应该是 "BTC-USDT",`parts[2]` 是 "trade" 或 "kline",`parts[3]` 是 "detail" 或 "1min"
|
|
|
+// let pair = parts.get(1).unwrap_or(&"").to_string().replace("-", "_");
|
|
|
+// let detail = if parts.len() > 3 {
|
|
|
+// format!("{}.{}", parts[2], parts[3])
|
|
|
+// } else {
|
|
|
+// input.to_string()
|
|
|
+// };
|
|
|
+//
|
|
|
+// (pair, detail)
|
|
|
+// }
|