|
@@ -4,7 +4,11 @@ use std::io::BufReader;
|
|
|
use std::str::FromStr;
|
|
use std::str::FromStr;
|
|
|
use chrono::NaiveDateTime;
|
|
use chrono::NaiveDateTime;
|
|
|
use rust_decimal::Decimal;
|
|
use rust_decimal::Decimal;
|
|
|
|
|
+use rust_decimal_macros::dec;
|
|
|
|
|
+use serde_json::json;
|
|
|
use tracing::{error, info};
|
|
use tracing::{error, info};
|
|
|
|
|
+use crate::export_template;
|
|
|
|
|
+use crate::http::request::Response;
|
|
|
use crate::swap_bybit::bybit_swap_rest_utils::BybitSwapRest;
|
|
use crate::swap_bybit::bybit_swap_rest_utils::BybitSwapRest;
|
|
|
use crate::swap_gate::gate_swap_rest_utils::GateSwapRest;
|
|
use crate::swap_gate::gate_swap_rest_utils::GateSwapRest;
|
|
|
use crate::utils::utils;
|
|
use crate::utils::utils;
|
|
@@ -17,6 +21,7 @@ pub async fn export_balance(config_info: BalanceConfigInfo) {
|
|
|
let count_start_time = NaiveDateTime::parse_from_str(&config_info.count_range_time[0].clone(), "%Y-%m-%d %H:%M:%S").unwrap().timestamp() - 8 * 3600;
|
|
let count_start_time = NaiveDateTime::parse_from_str(&config_info.count_range_time[0].clone(), "%Y-%m-%d %H:%M:%S").unwrap().timestamp() - 8 * 3600;
|
|
|
let count_end_time = NaiveDateTime::parse_from_str(&config_info.count_range_time[1].clone(), "%Y-%m-%d %H:%M:%S").unwrap().timestamp() - 8 * 3600;
|
|
let count_end_time = NaiveDateTime::parse_from_str(&config_info.count_range_time[1].clone(), "%Y-%m-%d %H:%M:%S").unwrap().timestamp() - 8 * 3600;
|
|
|
|
|
|
|
|
|
|
+
|
|
|
//获取不同账号的数据
|
|
//获取不同账号的数据
|
|
|
let mut all_account_balance_info: BTreeMap<String, Vec<Vec<String>>> = BTreeMap::new();
|
|
let mut all_account_balance_info: BTreeMap<String, Vec<Vec<String>>> = BTreeMap::new();
|
|
|
let mut account_name_list: Vec<String> = vec![];
|
|
let mut account_name_list: Vec<String> = vec![];
|
|
@@ -25,135 +30,287 @@ pub async fn export_balance(config_info: BalanceConfigInfo) {
|
|
|
return;
|
|
return;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- let mut data: serde_json::Value = utils::get_json_file("./config_history_balance.json");
|
|
|
|
|
-
|
|
|
|
|
- for exchange in config_info.exchanges.clone() {
|
|
|
|
|
- let exchange_up = exchange.to_uppercase();
|
|
|
|
|
- match exchange_up.as_str() {
|
|
|
|
|
- "GATE" => {
|
|
|
|
|
- for account in config_info_clone.account_list.clone() {
|
|
|
|
|
- let mut account_info: BTreeMap<String, String> = BTreeMap::new();
|
|
|
|
|
- account_info.insert("account_name".to_string(), account[0].clone());
|
|
|
|
|
- account_info.insert("access_key".to_string(), account[1].clone());
|
|
|
|
|
- account_info.insert("secret_key".to_string(), account[2].clone());
|
|
|
|
|
-
|
|
|
|
|
- let mut gate_exc = GateSwapRest::new(false, account_info.clone());
|
|
|
|
|
- let data = gate_exc.account_book("usdt".to_string()).await;
|
|
|
|
|
- // info!("请求完成{:?}",data.clone());
|
|
|
|
|
- if data.code.as_str() == "200" {
|
|
|
|
|
- let account_name = account_info.get("account_name").unwrap();
|
|
|
|
|
- account_name_list.push(account_name.clone());
|
|
|
|
|
-
|
|
|
|
|
- //账号
|
|
|
|
|
- let json_value: serde_json::Value = serde_json::from_str(&data.data).unwrap();
|
|
|
|
|
- if let serde_json::Value::Array(array) = json_value {
|
|
|
|
|
- let mut name_data_all: Vec<Vec<String>> = vec![];
|
|
|
|
|
- let mut times = 0;
|
|
|
|
|
-
|
|
|
|
|
- for item in array {
|
|
|
|
|
- // info!("数据{:?}",item.clone().to_string());
|
|
|
|
|
-
|
|
|
|
|
- let time = item["time"].as_i64().unwrap();//秒级
|
|
|
|
|
- if time == times { continue; }
|
|
|
|
|
- times = time;
|
|
|
|
|
-
|
|
|
|
|
- let change = item["change"].as_str().unwrap();
|
|
|
|
|
-
|
|
|
|
|
- let balance = item["balance"].as_str().unwrap();
|
|
|
|
|
- let type_str = match item["type"].as_str().unwrap() {
|
|
|
|
|
- "dnw" => { "transfer" }
|
|
|
|
|
- "pnl" => { "profit" }
|
|
|
|
|
- "fee" => {
|
|
|
|
|
- "交易手续费";
|
|
|
|
|
- continue;
|
|
|
|
|
- }
|
|
|
|
|
- "refr" => {
|
|
|
|
|
- "推荐人返佣";
|
|
|
|
|
- continue;
|
|
|
|
|
- }
|
|
|
|
|
- "fund" => {
|
|
|
|
|
- "资金费用";
|
|
|
|
|
- continue;
|
|
|
|
|
- }
|
|
|
|
|
- "point_dnw" => {
|
|
|
|
|
- "点卡转入转出";
|
|
|
|
|
- continue;
|
|
|
|
|
- }
|
|
|
|
|
- "point_fee" => {
|
|
|
|
|
- "点卡交易手续费";
|
|
|
|
|
- continue;
|
|
|
|
|
- }
|
|
|
|
|
- "point_refr" => {
|
|
|
|
|
- "点卡推荐人返佣";
|
|
|
|
|
- continue;
|
|
|
|
|
- }
|
|
|
|
|
- _ => {
|
|
|
|
|
- "未知-变更类型";
|
|
|
|
|
- continue;
|
|
|
|
|
|
|
+ let mut count_balance_info = vec![];
|
|
|
|
|
+ let mut count_time_list = vec![];
|
|
|
|
|
+ let mut history_balance: serde_json::Value = utils::get_json_file("./config_history_balance.json");
|
|
|
|
|
+ let history_start_time = history_balance["start_time"].as_i64().unwrap_or(0);
|
|
|
|
|
+ let mut history_end_time = history_balance["end_time"].as_i64().unwrap_or(0);
|
|
|
|
|
+ if history_end_time < end_time {
|
|
|
|
|
+ for exchange in config_info.exchanges.clone() {
|
|
|
|
|
+ let exchange_up = exchange.to_uppercase();
|
|
|
|
|
+ match exchange_up.as_str() {
|
|
|
|
|
+ "GATE" => {
|
|
|
|
|
+ for account in &config_info.clone().account_list {
|
|
|
|
|
+ let mut account_info: BTreeMap<String, String> = BTreeMap::new();
|
|
|
|
|
+ account_info.insert("account_name".to_string(), account[0].clone());
|
|
|
|
|
+ account_info.insert("access_key".to_string(), account[1].clone());
|
|
|
|
|
+ account_info.insert("secret_key".to_string(), account[2].clone());
|
|
|
|
|
+
|
|
|
|
|
+ let mut gate_exc = GateSwapRest::new(false, account_info.clone());
|
|
|
|
|
+ let mut data: Response = Response::new();
|
|
|
|
|
+ let form = if start_time > history_end_time { start_time } else { history_end_time };
|
|
|
|
|
+ let mut to = end_time;
|
|
|
|
|
+ loop {
|
|
|
|
|
+ let new_data = gate_exc.account_book("usdt".to_string(), form, to).await;
|
|
|
|
|
+ let new_data_json_value: serde_json::Value = serde_json::from_str(&new_data.data).unwrap_or(json!([]));
|
|
|
|
|
+ let data_json_value: serde_json::Value = serde_json::from_str(&data.data).unwrap_or(json!([]));
|
|
|
|
|
+ if let (serde_json::Value::Array(new_data_json_value), serde_json::Value::Array(mut data_json_value)) = (new_data_json_value, data_json_value) {
|
|
|
|
|
+ data_json_value.extend(new_data_json_value.clone());
|
|
|
|
|
+ // 将拼接后的数组序列化为 JSON 字符串
|
|
|
|
|
+ let result_str = serde_json::to_string(&data_json_value).unwrap();
|
|
|
|
|
+
|
|
|
|
|
+ data.code = new_data.code;
|
|
|
|
|
+ data.data = result_str.clone();
|
|
|
|
|
+ to = if new_data_json_value.len() > 0 { new_data_json_value[new_data_json_value.len() - 1]["time"].as_i64().unwrap() } else { to };
|
|
|
|
|
+ if data_json_value.len() == 0 {
|
|
|
|
|
+ let fill_new_data = gate_exc.fill_account_book("usdt".to_string(), form, to).await;
|
|
|
|
|
+ let fill_new_data_json_value: serde_json::Value = serde_json::from_str(&fill_new_data.data).unwrap_or(json!([]));
|
|
|
|
|
+ if let serde_json::Value::Array(fill_new_data_json_value) = fill_new_data_json_value {
|
|
|
|
|
+ data_json_value.extend(fill_new_data_json_value.clone());
|
|
|
|
|
+ // 将拼接后的数组序列化为 JSON 字符串
|
|
|
|
|
+ let result_str = serde_json::to_string(&data_json_value).unwrap();
|
|
|
|
|
+ data.code = fill_new_data.code;
|
|
|
|
|
+ data.data = result_str.clone();
|
|
|
|
|
+ break;
|
|
|
}
|
|
}
|
|
|
- };
|
|
|
|
|
|
|
+ } else if new_data_json_value.len() < 1000 { break; }
|
|
|
|
|
+ } else {
|
|
|
|
|
+ println!("Input is not valid JSON arrays.");
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ // info!("请求完成{:?}",data.clone());
|
|
|
|
|
+ if data.code.as_str() == "200" {
|
|
|
|
|
+ let account_name = account_info.get("account_name").unwrap();
|
|
|
|
|
+ account_name_list.push(account_name.clone());
|
|
|
|
|
+
|
|
|
|
|
+ //账号
|
|
|
|
|
+ let json_value: serde_json::Value = serde_json::from_str(&data.data).unwrap();
|
|
|
|
|
+ if let serde_json::Value::Array(array) = json_value {
|
|
|
|
|
+ let mut name_data_all: Vec<Vec<String>> = vec![];
|
|
|
|
|
+ let mut times = 0;
|
|
|
|
|
+
|
|
|
|
|
+ for item in array {
|
|
|
|
|
+ // info!("数据{:?}",item.clone().to_string());
|
|
|
|
|
+
|
|
|
|
|
+ let time = item["time"].as_i64().unwrap();//秒级
|
|
|
|
|
+ if time == times { continue; }
|
|
|
|
|
+ times = time;
|
|
|
|
|
|
|
|
|
|
+ let change = item["change"].as_str().unwrap();
|
|
|
|
|
|
|
|
- let text = item["text"].as_str().unwrap();
|
|
|
|
|
- let contract = item["contract"].as_str().unwrap();
|
|
|
|
|
- let trade_id = item["trade_id"].as_str().unwrap();
|
|
|
|
|
|
|
+ let balance = item["balance"].as_str().unwrap();
|
|
|
|
|
+ let type_str = match item["type"].as_str().unwrap() {
|
|
|
|
|
+ "dnw" => { "transfer" }
|
|
|
|
|
+ "pnl" => { "profit" }
|
|
|
|
|
+ "fee" => {
|
|
|
|
|
+ "交易手续费";
|
|
|
|
|
+ continue;
|
|
|
|
|
+ }
|
|
|
|
|
+ "refr" => {
|
|
|
|
|
+ "推荐人返佣";
|
|
|
|
|
+ continue;
|
|
|
|
|
+ }
|
|
|
|
|
+ "fund" => {
|
|
|
|
|
+ "资金费用";
|
|
|
|
|
+ continue;
|
|
|
|
|
+ }
|
|
|
|
|
+ "point_dnw" => {
|
|
|
|
|
+ "点卡转入转出";
|
|
|
|
|
+ continue;
|
|
|
|
|
+ }
|
|
|
|
|
+ "point_fee" => {
|
|
|
|
|
+ "点卡交易手续费";
|
|
|
|
|
+ continue;
|
|
|
|
|
+ }
|
|
|
|
|
+ "point_refr" => {
|
|
|
|
|
+ "点卡推荐人返佣";
|
|
|
|
|
+ continue;
|
|
|
|
|
+ }
|
|
|
|
|
+ _ => {
|
|
|
|
|
+ "未知-变更类型";
|
|
|
|
|
+ continue;
|
|
|
|
|
+ }
|
|
|
|
|
+ };
|
|
|
|
|
|
|
|
- let mut name_data_array: Vec<String> = vec![];
|
|
|
|
|
- name_data_array.push(time.to_string());
|
|
|
|
|
- name_data_array.push(trade_id.to_string());
|
|
|
|
|
- name_data_array.push(change.to_string());
|
|
|
|
|
- name_data_array.push(balance.to_string());
|
|
|
|
|
- name_data_array.push(type_str.to_string());
|
|
|
|
|
- name_data_array.push(contract.to_string());
|
|
|
|
|
- name_data_array.push(text.to_string());
|
|
|
|
|
|
|
|
|
|
- name_data_all.push(name_data_array.clone());
|
|
|
|
|
|
|
+ let text = item["text"].as_str().unwrap();
|
|
|
|
|
+ let contract = item["contract"].as_str().unwrap();
|
|
|
|
|
+ let trade_id = item["trade_id"].as_str().unwrap();
|
|
|
|
|
+ let mut name_data_array: Vec<String> = vec![];
|
|
|
|
|
+ name_data_array.push(time.to_string());
|
|
|
|
|
+ name_data_array.push(trade_id.to_string());
|
|
|
|
|
+ name_data_array.push(change.to_string());
|
|
|
|
|
+ name_data_array.push(balance.to_string());
|
|
|
|
|
+ name_data_array.push(type_str.to_string());
|
|
|
|
|
+ name_data_array.push(contract.to_string());
|
|
|
|
|
+ name_data_array.push(text.to_string());
|
|
|
|
|
+
|
|
|
|
|
+ name_data_all.push(name_data_array.clone());
|
|
|
|
|
+ }
|
|
|
|
|
+ let mut filtered_data: Vec<Vec<String>> = name_data_all.clone();
|
|
|
|
|
+
|
|
|
|
|
+ for ccc in config_info_clone.clone().add_account_list {
|
|
|
|
|
+ let s_t = NaiveDateTime::parse_from_str(&ccc[1], "%Y-%m-%d %H:%M:%S").unwrap().timestamp() - 8 * 3600;
|
|
|
|
|
+ if ccc[0] == account_name.clone() && s_t >= form {
|
|
|
|
|
+ let mut last = name_data_all[name_data_all.len() - 1].clone();
|
|
|
|
|
+ last[0] = s_t.to_string();
|
|
|
|
|
+ last[4] = "transfer".to_string();
|
|
|
|
|
+ filtered_data = name_data_all.iter().filter(|item| item[0].parse::<i64>().unwrap() > s_t).map(|item| item.clone()).collect();
|
|
|
|
|
+ filtered_data.push(last.clone());
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ // println!("{} {:?}", account[0].clone(), filtered_data);
|
|
|
|
|
+ all_account_balance_info.insert(account_name.clone(), filtered_data);
|
|
|
|
|
+ } else {
|
|
|
|
|
+ info!("不是数组 检查数据");
|
|
|
}
|
|
}
|
|
|
- all_account_balance_info.insert(account_name.clone(), name_data_all.clone());
|
|
|
|
|
- } else {
|
|
|
|
|
- info!("不是数组 检查数据");
|
|
|
|
|
}
|
|
}
|
|
|
- }
|
|
|
|
|
- // break;
|
|
|
|
|
- };
|
|
|
|
|
- }
|
|
|
|
|
- _ => {
|
|
|
|
|
- error!("交易所输入错误!");
|
|
|
|
|
- panic!("交易所输入错误!")
|
|
|
|
|
|
|
+ // break;
|
|
|
|
|
+ };
|
|
|
|
|
+ }
|
|
|
|
|
+ _ => {
|
|
|
|
|
+ error!("交易所输入错误!");
|
|
|
|
|
+ panic!("交易所输入错误!")
|
|
|
|
|
+ }
|
|
|
|
|
+ };
|
|
|
|
|
+ }
|
|
|
|
|
+ for (_account_name, balance_info) in all_account_balance_info.clone() {
|
|
|
|
|
+ for value in balance_info {
|
|
|
|
|
+ let time = value[0].clone().parse::<i64>().unwrap();
|
|
|
|
|
+ if !count_time_list.contains(&time) && time > count_start_time && time < count_end_time {
|
|
|
|
|
+ count_time_list.push(time)
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
};
|
|
};
|
|
|
|
|
+ if count_time_list.len() > 0 {
|
|
|
|
|
+ count_time_list.sort_by(|a, b| a.cmp(&b));
|
|
|
|
|
+ count_time_list.insert(0, count_start_time);
|
|
|
|
|
+ count_time_list.push(count_end_time);
|
|
|
|
|
+ count_balance_info = supply_balance(all_account_balance_info.clone(), count_time_list.clone());
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
- // 根据账户变动填充
|
|
|
|
|
- let mut count_time_list = vec![];
|
|
|
|
|
- for (_account_name, balance_info) in all_account_balance_info.clone() {
|
|
|
|
|
- for value in balance_info {
|
|
|
|
|
- let time = value[0].clone().parse::<i64>().unwrap();
|
|
|
|
|
- if !count_time_list.contains(&time) && time > count_start_time && time < count_end_time {
|
|
|
|
|
- count_time_list.push(time)
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ let save_start_time = if history_start_time == 0 { start_time } else { history_start_time };
|
|
|
|
|
+ let save_end_time = if history_end_time > end_time { history_end_time } else { end_time };
|
|
|
|
|
+ let new_data = save_balance(history_balance.clone(), count_balance_info.clone(), save_start_time, save_end_time, history_end_time);
|
|
|
|
|
+ let mut over_balance_info = vec![];
|
|
|
|
|
+ let mut last_count_time_list = vec![];
|
|
|
|
|
+ for (key, value) in new_data.clone() {
|
|
|
|
|
+ last_count_time_list = vec![];
|
|
|
|
|
+ for item in value {
|
|
|
|
|
+ over_balance_info.push(item.clone());
|
|
|
|
|
+ last_count_time_list.push(item[1].clone().parse::<i64>().unwrap());
|
|
|
}
|
|
}
|
|
|
|
|
+ }
|
|
|
|
|
+ let statistic_result = statistic_balance(new_data, count_start_time, count_end_time, config_info.clone());
|
|
|
|
|
+ // 根据小时填充
|
|
|
|
|
+ // let mut last_timestamp: i64 = -1;
|
|
|
|
|
+ // let mut hour_time_list: Vec<i64> = vec![];
|
|
|
|
|
+ // for item in start_time..end_time {
|
|
|
|
|
+ // if item / 3600 != last_timestamp / 3600 {
|
|
|
|
|
+ // last_timestamp = item;
|
|
|
|
|
+ // hour_time_list.push(last_timestamp);
|
|
|
|
|
+ // }
|
|
|
|
|
+ // }
|
|
|
|
|
+ // hour_time_list.push(end_time);
|
|
|
|
|
+ // let all_balance_info: Vec<Vec<String>> = supply_balance(all_account_balance_info.clone(), hour_time_list.clone());
|
|
|
|
|
+
|
|
|
|
|
+ // 打印解析后的数据
|
|
|
|
|
+ account_name_list.push("total_balance".to_string());
|
|
|
|
|
+ match config_info.clone().export_mode {
|
|
|
|
|
+ // 1 => export_template::template_balance::export_html(config_info, &account_name_list, &hour_time_list, &all_balance_info.clone(), statistic_result),
|
|
|
|
|
+ 2 => export_template::template_balance::export_html(config_info, &account_name_list, &last_count_time_list, &over_balance_info.clone(), statistic_result),
|
|
|
|
|
+ _ => error!("导出模式错误,请检查导出模式!")
|
|
|
};
|
|
};
|
|
|
- count_time_list.sort_by(|a, b| a.cmp(&b));
|
|
|
|
|
- count_time_list.insert(0, count_start_time);
|
|
|
|
|
- count_time_list.push(count_end_time);
|
|
|
|
|
- let count_balance_info = supply_balance(all_account_balance_info.clone(), count_time_list.clone());
|
|
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+pub fn save_balance(mut history_balance: serde_json::Value, new_balance: Vec<Vec<String>>, save_start_time: i64, save_end_time: i64, history_end_time: i64) -> BTreeMap<String, Vec<Vec<String>>> {
|
|
|
let mut new_data: BTreeMap<String, Vec<Vec<String>>> = BTreeMap::new();
|
|
let mut new_data: BTreeMap<String, Vec<Vec<String>>> = BTreeMap::new();
|
|
|
|
|
+ let mut history_balance_list: BTreeMap<String, Vec<Vec<String>>> = BTreeMap::new();
|
|
|
|
|
+ history_balance["balance_list"].as_object().map(|item| {
|
|
|
|
|
+ for (key, value) in item {
|
|
|
|
|
+ let dd: Vec<Vec<String>> = value.as_array().unwrap().iter().map(|aa| {
|
|
|
|
|
+ aa.as_array().unwrap().iter().map(|bb| bb.as_str().unwrap().to_string()).collect()
|
|
|
|
|
+ }).collect();
|
|
|
|
|
+ history_balance_list.insert(key.clone(), dd.clone());
|
|
|
|
|
+ }
|
|
|
|
|
+ });
|
|
|
|
|
|
|
|
- for entry in count_balance_info {
|
|
|
|
|
|
|
+ for entry in new_balance.clone() {
|
|
|
let key = entry[0].clone();
|
|
let key = entry[0].clone();
|
|
|
let value = new_data.entry(key).or_insert(Vec::new());
|
|
let value = new_data.entry(key).or_insert(Vec::new());
|
|
|
- value.push(entry.clone());
|
|
|
|
|
|
|
+ if entry[1].clone().parse::<i64>().unwrap() >= history_end_time {
|
|
|
|
|
+ value.push(entry.clone());
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ for (key, value) in new_data.clone() {
|
|
|
|
|
+ let mut value_clone = value.clone();
|
|
|
|
|
+ // if history_balance_list.contains_key(&key.clone()) { value_clone.remove(0); };
|
|
|
|
|
+ history_balance_list.entry(key.clone())
|
|
|
|
|
+ .and_modify(|v| v.extend(value_clone.clone()))
|
|
|
|
|
+ .or_insert_with(|| value_clone.clone());
|
|
|
}
|
|
}
|
|
|
- println!("--------------------");
|
|
|
|
|
- println!("{:?}", new_data);
|
|
|
|
|
- // let statistic_result = statistic_balance(count_balance_info.clone(), count_start_time.clone(), count_end_time.clone(), config_info.clone());
|
|
|
|
|
|
|
+ history_balance["balance_list"] = serde_json::to_string(&history_balance_list).unwrap().parse().unwrap();
|
|
|
|
|
+ history_balance["end_time"] = serde_json::to_string(&save_end_time).unwrap().parse().unwrap();
|
|
|
|
|
+ history_balance["start_time"] = serde_json::to_string(&save_start_time).unwrap().parse().unwrap();
|
|
|
|
|
+ utils::set_json_file("./config_history_balance.json", serde_json::to_string(&history_balance).unwrap());
|
|
|
|
|
+ history_balance_list
|
|
|
|
|
+}
|
|
|
|
|
|
|
|
- data["balance_list"] = serde_json::to_string(&all_account_balance_info).unwrap().parse().unwrap();
|
|
|
|
|
- utils::set_json_file("./config_history_balance.json", serde_json::to_string(&data).unwrap());
|
|
|
|
|
- // 打印解析后的数据
|
|
|
|
|
- // println!("{:?}", data);
|
|
|
|
|
- if data["last_time"] == 0 {}
|
|
|
|
|
|
|
+pub fn statistic_balance(balance_info: BTreeMap<String, Vec<Vec<String>>>, count_start_time: i64, end_start_time: i64, config: BalanceConfigInfo) -> String {
|
|
|
|
|
+ let mut max_withdrawal = dec!(0);
|
|
|
|
|
+ let mut max_total_withdrawal = dec!(0);
|
|
|
|
|
+ let mut total_income = dec!(0);
|
|
|
|
|
+ let mut total_balance = dec!(0);
|
|
|
|
|
+
|
|
|
|
|
+ for (account_name, balance) in balance_info.clone() {
|
|
|
|
|
+ let mut max_price = dec!(0);
|
|
|
|
|
+ let mut min_price = dec!(0);
|
|
|
|
|
+ let mut withdrawal = dec!(0);
|
|
|
|
|
+ for (index, info) in balance.iter().enumerate() {
|
|
|
|
|
+ let present_price = Decimal::from_str(&info[4]).unwrap();
|
|
|
|
|
+ if index == 0 || max_price < present_price {
|
|
|
|
|
+ max_price = present_price;
|
|
|
|
|
+ min_price = present_price;
|
|
|
|
|
+ continue;
|
|
|
|
|
+ }
|
|
|
|
|
+ let mut present_withdrawal = dec!(0);
|
|
|
|
|
+ if max_price != dec!(0) {
|
|
|
|
|
+ present_withdrawal = ((max_price - min_price) / max_price * dec!(100)).round_dp(2);
|
|
|
|
|
+ }
|
|
|
|
|
+ if present_withdrawal > withdrawal { withdrawal = present_withdrawal }
|
|
|
|
|
+
|
|
|
|
|
+ if max_price > present_price && present_price < min_price {
|
|
|
|
|
+ min_price = present_price;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ if account_name != "total_balance" {
|
|
|
|
|
+ if max_withdrawal < withdrawal { max_withdrawal = withdrawal }
|
|
|
|
|
+ } else {
|
|
|
|
|
+ max_total_withdrawal = withdrawal;
|
|
|
|
|
+ let mut present = Decimal::from_str(&balance[0][4]).unwrap();
|
|
|
|
|
+ let mut past = dec!(0);
|
|
|
|
|
+ let mut earnings = dec!(0);
|
|
|
|
|
+ for (index, info) in balance.iter().enumerate() {
|
|
|
|
|
+ if info[5] == "transfer" {
|
|
|
|
|
+ total_income += earnings;
|
|
|
|
|
+ present = Decimal::from_str(&info[4]).unwrap();
|
|
|
|
|
+ }
|
|
|
|
|
+ past = Decimal::from_str(&info[4]).unwrap();
|
|
|
|
|
+ if present != dec!(0) {
|
|
|
|
|
+ earnings = (past - present) / present * dec!(100);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if present != dec!(0) {
|
|
|
|
|
+ total_income = (total_income + (past - present) / present * dec!(100)).round_dp(2);
|
|
|
|
|
+ }
|
|
|
|
|
+ total_balance = past
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ let start_time = NaiveDateTime::from_timestamp_millis((count_start_time + 8 * 3600) * 1000).unwrap().format("%d日%H点").to_string();
|
|
|
|
|
+ let end_time = NaiveDateTime::from_timestamp_millis((end_start_time + 8 * 3600) * 1000).unwrap().format("%d日%H点").to_string();
|
|
|
|
|
+ format!("{}到{},总收益约为{}%,最大回撤约为{}%,其中单个账号最大回撤约为{}%。<br/><br/>余额{}", start_time, end_time, total_income, max_total_withdrawal, max_withdrawal, total_balance)
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
pub fn supply_balance(source_balance_info: BTreeMap<String, Vec<Vec<String>>>, time_slicer: Vec<i64>) -> Vec<Vec<String>> {
|
|
pub fn supply_balance(source_balance_info: BTreeMap<String, Vec<Vec<String>>>, time_slicer: Vec<i64>) -> Vec<Vec<String>> {
|
|
@@ -161,6 +318,7 @@ pub fn supply_balance(source_balance_info: BTreeMap<String, Vec<Vec<String>>>, t
|
|
|
for time in time_slicer.clone() {
|
|
for time in time_slicer.clone() {
|
|
|
// 根据时间片去拿数据 ,如果有添加没有,手动添加
|
|
// 根据时间片去拿数据 ,如果有添加没有,手动添加
|
|
|
let mut total_price = Decimal::ZERO;
|
|
let mut total_price = Decimal::ZERO;
|
|
|
|
|
+ let mut total_status = "profit".to_string();
|
|
|
for (key, value) in source_balance_info.clone() {
|
|
for (key, value) in source_balance_info.clone() {
|
|
|
let mut balance_info = value.clone();
|
|
let mut balance_info = value.clone();
|
|
|
balance_info.sort_by(|a, b| a[0].cmp(&b[0]));
|
|
balance_info.sort_by(|a, b| a[0].cmp(&b[0]));
|
|
@@ -185,29 +343,45 @@ pub fn supply_balance(source_balance_info: BTreeMap<String, Vec<Vec<String>>>, t
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+
|
|
|
match new_info {
|
|
match new_info {
|
|
|
None => {
|
|
None => {
|
|
|
let balance_info_filter: Vec<Vec<String>> = balance_info.iter().filter(|item| {
|
|
let balance_info_filter: Vec<Vec<String>> = balance_info.iter().filter(|item| {
|
|
|
item[0].parse::<i64>().unwrap() < time
|
|
item[0].parse::<i64>().unwrap() < time
|
|
|
}).cloned().collect();
|
|
}).cloned().collect();
|
|
|
-
|
|
|
|
|
- let mut last_balance_info = if balance_info_filter.len() == 0 {
|
|
|
|
|
- balance_info[0].clone()
|
|
|
|
|
|
|
+ let mut last_balance_info;
|
|
|
|
|
+ if balance_info_filter.len() == 0 {
|
|
|
|
|
+ let mut first = balance_info[0].clone();
|
|
|
|
|
+ if first[4] == "transfer" {
|
|
|
|
|
+ let first_change = Decimal::from_str(&first[2]).unwrap();
|
|
|
|
|
+ let first_balance = Decimal::from_str(&first[3]).unwrap();
|
|
|
|
|
+ first[0] = time.to_string();
|
|
|
|
|
+ first[2] = "0".to_string();
|
|
|
|
|
+ first[3] = (first_balance - first_change).to_string();
|
|
|
|
|
+ } else {
|
|
|
|
|
+ first[0] = time.to_string();
|
|
|
|
|
+ }
|
|
|
|
|
+ last_balance_info = first;
|
|
|
} else {
|
|
} else {
|
|
|
- balance_info_filter[balance_info_filter.len() - 1].clone()
|
|
|
|
|
|
|
+ let mut last = balance_info_filter[balance_info_filter.len() - 1].clone();
|
|
|
|
|
+ last[0] = time.to_string();
|
|
|
|
|
+ last_balance_info = last;
|
|
|
};
|
|
};
|
|
|
last_balance_info.insert(0, key.clone());
|
|
last_balance_info.insert(0, key.clone());
|
|
|
|
|
+ last_balance_info[5] = "fill".to_string();
|
|
|
total_price += Decimal::from_str(&last_balance_info[4]).unwrap();
|
|
total_price += Decimal::from_str(&last_balance_info[4]).unwrap();
|
|
|
balance_info_list.push(last_balance_info);
|
|
balance_info_list.push(last_balance_info);
|
|
|
}
|
|
}
|
|
|
Some(ref info) => {
|
|
Some(ref info) => {
|
|
|
|
|
+ if "transfer" == info[5] { total_status = info[5].to_string() };
|
|
|
total_price += Decimal::from_str(&info[4]).unwrap();
|
|
total_price += Decimal::from_str(&info[4]).unwrap();
|
|
|
balance_info_list.push(info.clone());
|
|
balance_info_list.push(info.clone());
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- let sum_row: Vec<String> = vec!["total_balance".to_string(), time.to_string(), "".to_string(), "0".to_string(), total_price.round_dp(2).to_string(), "".to_string(), "".to_string(), "".to_string()];
|
|
|
|
|
|
|
+ let sum_row: Vec<String> = vec!["total_balance".to_string(), time.to_string(), "".to_string(), "0".to_string(), total_price.round_dp(2).to_string(), total_status, "".to_string(), "".to_string()];
|
|
|
|
|
+ // println!("{:?}", sum_row);
|
|
|
balance_info_list.push(sum_row.clone());
|
|
balance_info_list.push(sum_row.clone());
|
|
|
};
|
|
};
|
|
|
balance_info_list
|
|
balance_info_list
|