|
@@ -54,7 +54,7 @@ fn calc_rise_percentage(records: Value) -> Decimal {
|
|
|
return rst
|
|
return rst
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-pub async fn get_symbols(_mode: &str, exchanges: &Vec<String>, minute_time_range: i64, _filters: &Vec<Value>) -> HttpResponse {
|
|
|
|
|
|
|
+pub async fn get_final_symbols(mode: &str, exchanges: &Vec<String>, minute_time_range: i64, filters: &Vec<Value>) -> HttpResponse {
|
|
|
// 1. 获取所选交易所的所有交易对
|
|
// 1. 获取所选交易所的所有交易对
|
|
|
let mut symbols_map = json!({});
|
|
let mut symbols_map = json!({});
|
|
|
for exchange in exchanges {
|
|
for exchange in exchanges {
|
|
@@ -71,17 +71,17 @@ pub async fn get_symbols(_mode: &str, exchanges: &Vec<String>, minute_time_range
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
// 2. 如果是多交易所,则获取所有交易所的交集
|
|
// 2. 如果是多交易所,则获取所有交易所的交集
|
|
|
- let mut symbols: Vec<String> = get_public_symbols(&symbols_map);
|
|
|
|
|
|
|
+ let symbols: Vec<String> = get_public_symbols(&symbols_map);
|
|
|
// 确保有足够的元素
|
|
// 确保有足够的元素
|
|
|
- let n = 10;
|
|
|
|
|
- // 获取前20个元素,如果不足20个,则获取全部
|
|
|
|
|
- let top_symbols = if symbols.len() > n {
|
|
|
|
|
- &symbols[0..n]
|
|
|
|
|
- } else {
|
|
|
|
|
- &symbols[..]
|
|
|
|
|
- };
|
|
|
|
|
- // 如果你需要将这些元素放在新的 Vec 中
|
|
|
|
|
- symbols = top_symbols.to_vec();
|
|
|
|
|
|
|
+ // let n = 10;
|
|
|
|
|
+ // // 获取前20个元素,如果不足20个,则获取全部
|
|
|
|
|
+ // let top_symbols = if symbols.len() > n {
|
|
|
|
|
+ // &symbols[0..n]
|
|
|
|
|
+ // } else {
|
|
|
|
|
+ // &symbols[..]
|
|
|
|
|
+ // };
|
|
|
|
|
+ // // 如果你需要将这些元素放在新的 Vec 中
|
|
|
|
|
+ // symbols = top_symbols.to_vec();
|
|
|
|
|
|
|
|
// 3. 获取它们的k线数据,注意时间范围以及保存形式。
|
|
// 3. 获取它们的k线数据,注意时间范围以及保存形式。
|
|
|
// {
|
|
// {
|
|
@@ -141,7 +141,7 @@ pub async fn get_symbols(_mode: &str, exchanges: &Vec<String>, minute_time_range
|
|
|
// },
|
|
// },
|
|
|
// }
|
|
// }
|
|
|
// ]
|
|
// ]
|
|
|
- let mut response_value = json!([]);
|
|
|
|
|
|
|
+ let mut temp_value = json!([]);
|
|
|
for symbol in &symbols {
|
|
for symbol in &symbols {
|
|
|
let mut rise = json!({});
|
|
let mut rise = json!({});
|
|
|
let mut volume = json!({});
|
|
let mut volume = json!({});
|
|
@@ -161,7 +161,7 @@ pub async fn get_symbols(_mode: &str, exchanges: &Vec<String>, minute_time_range
|
|
|
"volume": volume
|
|
"volume": volume
|
|
|
});
|
|
});
|
|
|
|
|
|
|
|
- response_value.as_array_mut().unwrap().push(value);
|
|
|
|
|
|
|
+ temp_value.as_array_mut().unwrap().push(value);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// 5. 整理完之后,获取指标数据,进行逻辑判断,注意与/或只是指过滤器,如果选择了多交易所,交易所的逻辑部分都是与
|
|
// 5. 整理完之后,获取指标数据,进行逻辑判断,注意与/或只是指过滤器,如果选择了多交易所,交易所的逻辑部分都是与
|
|
@@ -169,6 +169,7 @@ pub async fn get_symbols(_mode: &str, exchanges: &Vec<String>, minute_time_range
|
|
|
// 选择了gate_usdt_swap与bitget_usdt_swap两个交易所,并且对交易量进行了0.5M的过滤
|
|
// 选择了gate_usdt_swap与bitget_usdt_swap两个交易所,并且对交易量进行了0.5M的过滤
|
|
|
// 两个交易所都有xrp,如果gate与bitget的xrp交易量都大于0.5M,则会显示在最终列表中
|
|
// 两个交易所都有xrp,如果gate与bitget的xrp交易量都大于0.5M,则会显示在最终列表中
|
|
|
// 最终过滤
|
|
// 最终过滤
|
|
|
|
|
+ let response_value = symbols_filter(temp_value.as_array().unwrap(), filters, mode, exchanges);
|
|
|
let response = Response {
|
|
let response = Response {
|
|
|
query: Value::Null,
|
|
query: Value::Null,
|
|
|
msg: Some("排行榜生成完毕".to_string()),
|
|
msg: Some("排行榜生成完毕".to_string()),
|
|
@@ -180,6 +181,122 @@ pub async fn get_symbols(_mode: &str, exchanges: &Vec<String>, minute_time_range
|
|
|
HttpResponse::Ok().content_type("application/json").body(json_string)
|
|
HttpResponse::Ok().content_type("application/json").body(json_string)
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+fn symbols_filter(symbols: &Vec<Value>, filters: &Vec<Value>, mode: &str, exchanges: &Vec<String>) -> Value {
|
|
|
|
|
+ let mut rst = json!([]);
|
|
|
|
|
+
|
|
|
|
|
+ // 进行symbols的过滤
|
|
|
|
|
+ for symbol in symbols {
|
|
|
|
|
+ let mut is_valid = match mode {
|
|
|
|
|
+ "and" => {
|
|
|
|
|
+ true
|
|
|
|
|
+ },
|
|
|
|
|
+ "or" => {
|
|
|
|
|
+ false
|
|
|
|
|
+ }
|
|
|
|
|
+ _ => {
|
|
|
|
|
+ panic!("{}", format!("无法识别的模式: {}", mode))
|
|
|
|
|
+ }
|
|
|
|
|
+ };
|
|
|
|
|
+
|
|
|
|
|
+ // 过滤器功能启动
|
|
|
|
|
+ for filter in filters {
|
|
|
|
|
+ let filter_rst = match filter["target"].as_str().unwrap() {
|
|
|
|
|
+ "R" => {
|
|
|
|
|
+ rise_filter(symbol, filter, exchanges)
|
|
|
|
|
+ },
|
|
|
|
|
+ "V" => {
|
|
|
|
|
+ volume_filter(symbol, filter, exchanges)
|
|
|
|
|
+ },
|
|
|
|
|
+ "ROA" => {
|
|
|
|
|
+ rise_of_abs_filter(symbol, filter, exchanges)
|
|
|
|
|
+ },
|
|
|
|
|
+ _ => {
|
|
|
|
|
+ panic!("{}", format!("无法识别的过滤器: {}", filter["target"].as_str().unwrap()))
|
|
|
|
|
+ }
|
|
|
|
|
+ };
|
|
|
|
|
+
|
|
|
|
|
+ // 结果识别器
|
|
|
|
|
+ is_valid = match mode {
|
|
|
|
|
+ "and" => {
|
|
|
|
|
+ is_valid && filter_rst
|
|
|
|
|
+ },
|
|
|
|
|
+ "or" => {
|
|
|
|
|
+ is_valid || filter_rst
|
|
|
|
|
+ }
|
|
|
|
|
+ _ => {
|
|
|
|
|
+ panic!("{}", format!("无法识别的模式: {}", mode))
|
|
|
|
|
+ }
|
|
|
|
|
+ };
|
|
|
|
|
+
|
|
|
|
|
+ if !is_valid {
|
|
|
|
|
+ break
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 如果是有效的币,就塞到结果里
|
|
|
|
|
+ if is_valid {
|
|
|
|
|
+ rst.as_array_mut().unwrap().push(symbol.clone())
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ return rst
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// 涨跌幅过滤器
|
|
|
|
|
+fn rise_filter(symbol: &Value, filter: &Value, exchanges: &Vec<String>) -> bool {
|
|
|
|
|
+ let rise_limit = Decimal::from_str(filter["value"].as_str().unwrap().to_string().as_str()).unwrap();
|
|
|
|
|
+ let mut rst = true;
|
|
|
|
|
+
|
|
|
|
|
+ for exchange in exchanges {
|
|
|
|
|
+ let rise_map = symbol["rise"].clone();
|
|
|
|
|
+ let rise = Decimal::from_str(rise_map[exchange].as_str().unwrap().to_string().as_str()).unwrap();
|
|
|
|
|
+
|
|
|
|
|
+ rst = rst && rise > rise_limit;
|
|
|
|
|
+ if !rst {
|
|
|
|
|
+ break
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ return rst
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// 交易量过滤器
|
|
|
|
|
+fn volume_filter(symbol: &Value, filter: &Value, exchanges: &Vec<String>) -> bool {
|
|
|
|
|
+ let volume_limit = Decimal::from_str(filter["value"].as_str().unwrap().to_string().as_str()).unwrap();
|
|
|
|
|
+ let mut rst = true;
|
|
|
|
|
+
|
|
|
|
|
+ for exchange in exchanges {
|
|
|
|
|
+ let volume_map = symbol["volume"].clone();
|
|
|
|
|
+ let volume = Decimal::from_str(volume_map[exchange].as_str().unwrap().to_string().as_str()).unwrap();
|
|
|
|
|
+
|
|
|
|
|
+ rst = rst && volume > volume_limit;
|
|
|
|
|
+ if !rst {
|
|
|
|
|
+ break
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ return rst
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// 涨跌幅绝对值过滤器
|
|
|
|
|
+fn rise_of_abs_filter(symbol: &Value, filter: &Value, exchanges: &Vec<String>) -> bool {
|
|
|
|
|
+ let rise_limit = Decimal::from_str(filter["value"].as_str().unwrap().to_string().as_str()).unwrap();
|
|
|
|
|
+ let mut rst = true;
|
|
|
|
|
+
|
|
|
|
|
+ for exchange in exchanges {
|
|
|
|
|
+ let rise_map = symbol["rise"].clone();
|
|
|
|
|
+ let rise = Decimal::from_str(rise_map[exchange].as_str().unwrap().to_string().as_str()).unwrap().abs();
|
|
|
|
|
+
|
|
|
|
|
+ rst = rst && rise > rise_limit;
|
|
|
|
|
+ if !rst {
|
|
|
|
|
+ break
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ return rst
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
#[tokio::test]
|
|
#[tokio::test]
|
|
|
async fn get_public_symbols_test() {
|
|
async fn get_public_symbols_test() {
|
|
|
use global::log_utils::init_log_with_info;
|
|
use global::log_utils::init_log_with_info;
|