|
|
@@ -0,0 +1,121 @@
|
|
|
+use std::collections::HashMap;
|
|
|
+use rust_decimal::Decimal;
|
|
|
+use rust_decimal_macros::dec;
|
|
|
+use serde::{Deserialize, Serialize};
|
|
|
+use serde_json::Value;
|
|
|
+use tokio::sync::MutexGuard;
|
|
|
+use crate::msv::Indicators;
|
|
|
+
|
|
|
+#[derive(Serialize, Deserialize, Clone)]
|
|
|
+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,
|
|
|
+}
|
|
|
+
|
|
|
+const TWENTY: Decimal = dec!(20);
|
|
|
+const SIXTY: Decimal = dec!(60);
|
|
|
+const TWO_HUNDRED: Decimal = dec!(200);
|
|
|
+const TEN_THOUSAND: Decimal = dec!(10000);
|
|
|
+
|
|
|
+// 根据最终的msv计算排行榜
|
|
|
+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();
|
|
|
+
|
|
|
+ // ============== msv相关数据的计算 =================
|
|
|
+ let mut msv_abs_total = Decimal::ZERO;
|
|
|
+ let mut msv_abs_max = Decimal::ZERO;
|
|
|
+ let mut effective_count = Decimal::ZERO;
|
|
|
+ for value in indicators.msv.iter() {
|
|
|
+ let msv_abs_value = value[1].abs();
|
|
|
+
|
|
|
+ if msv_abs_value <= Decimal::ZERO {
|
|
|
+ continue
|
|
|
+ }
|
|
|
+
|
|
|
+ effective_count += Decimal::ONE;
|
|
|
+ msv_abs_total += msv_abs_value;
|
|
|
+
|
|
|
+ if msv_abs_value > msv_abs_max {
|
|
|
+ msv_abs_max = msv_abs_value
|
|
|
+ }
|
|
|
+ }
|
|
|
+ let mut msv_abs_avg = if effective_count == Decimal::ZERO {
|
|
|
+ Decimal::ZERO
|
|
|
+ } else {
|
|
|
+ msv_abs_total / effective_count
|
|
|
+ };
|
|
|
+ msv_abs_avg.rescale(6);
|
|
|
+ let mut coverted_open_base = (msv_abs_max + msv_abs_avg) / TWO_HUNDRED;
|
|
|
+ coverted_open_base.rescale(8);
|
|
|
+
|
|
|
+ // ============== epr相关数据的计算 =================
|
|
|
+ let mut epr_total = Decimal::ZERO;
|
|
|
+ for value in indicators.eprs.iter() {
|
|
|
+ epr_total += value[1];
|
|
|
+ }
|
|
|
+
|
|
|
+ // ============== liq相关数据的计算 =================
|
|
|
+ let mut liquidity_total = Decimal::ZERO;
|
|
|
+ for value in indicators.liqs.iter() {
|
|
|
+ liquidity_total += value[1] * Decimal::ONE_THOUSAND;
|
|
|
+ }
|
|
|
+ let mut liquidity_avg = if effective_count == Decimal::ZERO {
|
|
|
+ Decimal::ZERO
|
|
|
+ } else {
|
|
|
+ liquidity_total / effective_count
|
|
|
+ };
|
|
|
+ liquidity_avg.rescale(0);
|
|
|
+
|
|
|
+ // msv_score计算规则
|
|
|
+ let mut msv_score = if msv_abs_total > Decimal::ZERO {
|
|
|
+ effective_count * (epr_total / msv_abs_total) * SIXTY
|
|
|
+ } else {
|
|
|
+ Decimal::ZERO
|
|
|
+ };
|
|
|
+ msv_score.rescale(2);
|
|
|
+
|
|
|
+ // liquidity_score
|
|
|
+ let mut liquidity_score = (liquidity_avg / TEN_THOUSAND) * TWENTY;
|
|
|
+ liquidity_score.rescale(2);
|
|
|
+
|
|
|
+ // frequency_score计算规则
|
|
|
+ let mut frequency_score = (effective_count / Decimal::ONE_HUNDRED) * TWENTY;
|
|
|
+ frequency_score.rescale(2);
|
|
|
+
|
|
|
+ let score = msv_score + liquidity_score + frequency_score;
|
|
|
+ let rank = Rank {
|
|
|
+ symbol,
|
|
|
+ score,
|
|
|
+ msv_score,
|
|
|
+ liquidity_score,
|
|
|
+ frequency_score,
|
|
|
+ msv_abs_total,
|
|
|
+ msv_abs_max,
|
|
|
+ msv_abs_avg,
|
|
|
+ coverted_open_base,
|
|
|
+ epr_total,
|
|
|
+ effective_count,
|
|
|
+ liquidity_avg,
|
|
|
+ };
|
|
|
+
|
|
|
+ rank_list.push(rank);
|
|
|
+ }
|
|
|
+
|
|
|
+ // 按 score 倒序排序
|
|
|
+ rank_list.sort_by(|a, b| b.score.cmp(&a.score));
|
|
|
+
|
|
|
+ return serde_json::to_value(&rank_list).unwrap();
|
|
|
+}
|