Эх сурвалжийг харах

测试完了,先上去看看第一版。

skyffire 7 сар өмнө
parent
commit
7b43411922

+ 3 - 22
README.MD

@@ -14,17 +14,8 @@
     "data": [                               // 排行榜结果
         {
             "symbol": "BTC_USDT",           // 币对
-            "score": "205",                 // 总评分
-            "msv_score": "157",             // 波动分数
-            "liquidity_score": "33",        // 交易量分数
-            "frequency_score": "15",        // 交易频次分数
-            "msv_abs_total": "17.2",        // Sum(Abs(波动率))
-            "msv_abs_max": "1.2",           // 最大Abs(波动率)
-            "msv_abs_avg": "0.2",           // 平均Abs(波动率)
-            "coverted_open_base": "0.007",  // 转换后的基础开仓值(0.007代表0.7%)
-            "epr_total": "7.2",             // Sum(预期利润)
-            "effective_count": "10",        // 有效波动次数
-            "liquidity_avg": "3000",        // 平均行情推动量
+            "score": "0.1573",              // 总评分
+            "trend_strength": "0.1573",     // 趋势强度 
         },
         ...
     ],
@@ -32,17 +23,7 @@
 ```
 ```
 评分规则
-score = msv_score + liquity_score + frequency_score
-
-1. msv_score计算规则
-当msv_abs_total > 0时, msv_score = effective_count * (epr_total / msv_abs_total) * 60 * msv_abs_avg
-当msv_abs_total = 0时, msv_score = 0
-   
-2. liquity_score计算规则
-liquidity_score = (liquidity_avg / 1000) * 20
-
-3. frequency_score计算规则
-frequency_score = (effective_count / 100) * 20
+score = trend_strength
 ```
 
 

+ 27 - 25
src/bybit_usdt_swap_data_listener.rs

@@ -1,6 +1,8 @@
 use std::collections::{BTreeMap, HashMap};
 use std::sync::{Arc};
 use std::sync::atomic::{AtomicBool};
+use std::time::Duration;
+use chrono::Utc;
 use lazy_static::lazy_static;
 use rust_decimal::Decimal;
 use tokio::sync::{Mutex};
@@ -11,8 +13,9 @@ use exchanges::response_base::ResponseData;
 use serde_json::Value;
 use standard::exchange::ExchangeEnum;
 use standard::exchange_struct_handler::ExchangeStructHandler;
+use crate::json_db_utils::{collect_records, delete_db_by_exchange};
 use crate::listener_tools::{update_record, RecordMap};
-use crate::trend14400::Indicators;
+use crate::trend14400::{generate_14400trend_by_records, Indicators};
 
 const EXCHANGE_NAME: &str = "bybit_usdt_swap";
 
@@ -60,28 +63,29 @@ pub async fn run_listener(is_shutdown_arc: Arc<AtomicBool>) {
             ws.ws_connect_async(is_shutdown_clone, data_listener, &write_tx_am, write_rx).await.expect("链接失败(内部一个心跳线程应该已经关闭了)");
         });
     }
-    // // 每分钟计算msv
-    // tokio::spawn(async move {
-    //     loop {
-    //         let end_timestamp = Utc::now().timestamp_millis();
-    //         let start_timestamp = end_timestamp - 60 * 1000 * 60 * 2;
-    //         for symbol in symbols.clone() {
-    //             let trades_value = collect_special_trades_json(start_timestamp, end_timestamp, EXCHANGE_NAME, &symbol).await;
-    //             let trades = parse_json_to_trades(trades_value);
-    //             let msv = generate_msv_by_trades(trades, dec!(50), vec![], start_timestamp, end_timestamp);
-    //             let mut indicator_map = INDICATOR_MAP.lock().await;
-    //             indicator_map.insert(symbol, msv);
-    //         }
-    //         tokio::time::sleep(Duration::from_secs(65)).await;
-    //     }
-    // });
-    // // 定时删除数据
-    // tokio::spawn(async move {
-    //     loop {
-    //         tokio::time::sleep(Duration::from_secs(1800)).await;
-    //         delete_db_by_exchange(EXCHANGE_NAME, "trades", 5 * 60).await;
-    //     }
-    // });
+    // 每分钟计算trend
+    tokio::spawn(async move {
+        loop {
+            let end_timestamp = Utc::now().timestamp_millis();
+            let start_timestamp = end_timestamp - 60 * 1000 * 60 * 2;
+            for symbol in symbols.clone() {
+                let mut records = collect_records(start_timestamp, end_timestamp, EXCHANGE_NAME, &symbol).await;
+                records.sort_by(|a, b| a.time.cmp(&b.time));
+
+                let indicators = generate_14400trend_by_records(&records);
+                let mut indicator_map = INDICATOR_MAP.lock().await;
+                indicator_map.insert(symbol, indicators);
+            }
+            tokio::time::sleep(Duration::from_secs(65)).await;
+        }
+    });
+    // 定时删除数据
+    tokio::spawn(async move {
+        loop {
+            tokio::time::sleep(Duration::from_secs(1800)).await;
+            delete_db_by_exchange(EXCHANGE_NAME, "record", 5 * 60).await;
+        }
+    });
 }
 
 // 读取数据
@@ -98,8 +102,6 @@ pub async fn data_listener(response: ResponseData) {
                 return;
             }
 
-            info!(?records);
-
             let record_map= RECORD_MAP.lock().await;
             update_record(&records[records.len() - 1], record_map, EXCHANGE_NAME).await;
         },

+ 11 - 18
src/json_db_utils.rs

@@ -9,7 +9,7 @@ use tokio::io::AsyncWriteExt;
 use tokio::{fs};
 // use tracing::{error, info};
 use tracing::{error, info};
-use standard::{SpecialTrade};
+use standard::{Record};
 
 pub async fn write_to_file(json_data: String, file_path: String) {
     // 尝试创建文件路径
@@ -76,33 +76,26 @@ pub fn minute_to_date(minute: i64) -> String {
     datetime_east_eight.format("%Y%m%d").to_string()
 }
 
-// 将一个时间段范围内的所有SpecialTrade返回(以json形式)
-pub async fn collect_special_trades_json(start_timestamp: i64, end_timestamp: i64, exchange: &str, symbol: &str) -> Value {
-    let mut all_trades = Vec::new();
-    let filenames = generate_filenames(start_timestamp, end_timestamp, exchange, symbol, "trades");
+// 将一个时间段范围内的所有Record返回(以json形式)
+pub async fn collect_records(start_timestamp: i64, end_timestamp: i64, exchange: &str, symbol: &str) -> Vec<Record> {
+    let mut records = Vec::new();
+    let filenames = generate_filenames(start_timestamp, end_timestamp, exchange, symbol, "record");
 
     for filename in filenames {
         let file_path = PathBuf::from(filename.as_str());
         let file_content = fs::read_to_string(file_path).await;
 
         // 检查文件内容是否成功读取
-        let mut trades = if let Ok(content) = file_content {
+        if let Ok(content) = file_content {
             // 尝试反序列化文件内容
-            if let Ok(trades) = serde_json::from_str::<Vec<SpecialTrade>>(&content) {
-                trades // 成功反序列化,返回结果
-            } else {
-                vec![] // 反序列化失败,返回空 Vec
+            if let Ok(record) = serde_json::from_str::<Record>(&content) {
+                // info!("{} 找到 1 条", filename);
+                records.push(record.clone());
             }
-        } else {
-            vec![] // 读取文件失败,返回空 Vec
-        };
-
-        trades.reverse();
-        // info!("{} 找到 {} 条", filename, trades.len());
-        all_trades.append(&mut trades);
+        }
     }
 
-    serde_json::to_value(&all_trades).unwrap()
+    records
 }
 
 // 清除指定时间前db文件

+ 20 - 13
src/rank.rs

@@ -9,20 +9,27 @@ use crate::trend14400::Indicators;
 pub struct Rank {
     symbol: String,
     score: Decimal,
-    msv_score: Decimal,
-    liquidity_score: Decimal,
-    frequency_score: Decimal,
-    msv_abs_total: Decimal,
-    msv_abs_max: Decimal,
-    msv_abs_avg: Decimal,
-    coverted_open_base: Decimal,
-    epr_total: Decimal,
-    effective_count: Decimal,
-    liquidity_avg: Decimal,
-    is_binance: bool,
+    trend_strength: Decimal,
 }
 
 // 根据最终的msv计算排行榜
-pub fn generate_rank_by_indicator_map(_indicator_map: &MutexGuard<HashMap<String, Indicators>>) -> Value {
-    Value::Null
+pub fn generate_rank_by_indicator_map(indicator_map: &MutexGuard<HashMap<String, Indicators>>) -> Value {
+    let mut rank_list: Vec<Rank> = vec![];
+
+    for (key, indicators) in indicator_map.iter() {
+        let symbol = key.clone();
+        let trend_strength = indicators.trend_strength.clone();
+        let score = trend_strength;
+
+        rank_list.push(Rank {
+            symbol,
+            score,
+            trend_strength,
+        });
+    }
+
+    // 按 score 倒序排序
+    rank_list.sort_by(|a, b| b.score.cmp(&a.score));
+
+    return serde_json::to_value(&rank_list).unwrap();
 }

+ 21 - 2
src/trend14400.rs

@@ -11,8 +11,27 @@ pub struct Indicators {
 }
 
 // 将records转为1440trend
-pub fn generate_14400trend_by_records(_records: &Vec<Record>) -> Indicators {
-    Indicators {
+pub fn generate_14400trend_by_records(records: &Vec<Record>) -> Indicators {
+    let mut indicators = Indicators {
         trend_strength: Decimal::ZERO,
+    };
+    // 如果没有记录,返回零
+    if records.is_empty() {
+        indicators.trend_strength = Decimal::ZERO;
+    } else {
+        // 计算close的总和
+        let sum = records.iter()
+            .fold(Decimal::new(0, 0), |acc, record| acc + record.close);
+
+        // 计算均值
+        let mean = sum / Decimal::new(records.len() as i64, 0);
+
+        // 计算比率
+        let trend = records.last().unwrap().close / mean;
+
+        indicators.trend_strength = (trend - Decimal::ONE).abs();
+        indicators.trend_strength.rescale(6);
     }
+
+    indicators
 }