Bläddra i källkod

修改导出添加本地库

gepangpang 1 år sedan
förälder
incheckning
ef0736be1a

+ 2 - 1
.gitignore

@@ -4,4 +4,5 @@
 ./Cargo.lock
 /logs*
 *.html
-/config_*.toml
+/config_*.toml
+./*.json

+ 44 - 0
config_balance.toml.sample

@@ -10,6 +10,50 @@ exchanges = ["gate"]
 range_time = ["2023-12-20 18:00:00", "2023-12-26 10:00:00"]
 # 配置查询时间(格式:2023-12-6 15:00:00)
 count_range_time = ["2023-12-25 10:00:00", "2023-12-26 10:00:00"]
+# 新增账号记录
+add_account_list = [
+    ["g2022111", "2024-2-25 10:00:00"],
+    ["g2022112", "2024-2-25 10:00:00"],
+    ["g2022113", "2024-2-25 10:00:00"],
+    ["g2022114", "2024-2-25 10:00:00"],
+    ["g2022115", "2024-2-25 10:00:00"],
+    ["g2022116", "2024-2-25 10:00:00"],
+    ["g2022117", "2024-2-25 10:00:00"],
+    ["g2022118", "2024-2-25 10:00:00"],
+    ["g2022119", "2024-2-25 10:00:00"],
+    ["g2022120", "2024-2-25 10:00:00"],
+    ["g2022121", "2024-2-25 10:00:00"],
+    ["g2022122", "2024-2-25 10:00:00"],
+    ["g2022123", "2024-2-25 10:00:00"],
+    ["g2022124", "2024-2-25 10:00:00"],
+    ["g2022125", "2024-2-25 10:00:00"],
+    ["g2022126", "2024-2-25 10:00:00"],
+    ["g2022127", "2024-2-25 10:00:00"],
+    ["g2022128", "2024-2-25 10:00:00"],
+    ["g2022129", "2024-2-25 10:00:00"],
+    ["g2022130", "2024-2-25 10:00:00"],
+
+    ["g2022131", "2024-2-29 10:00:00"],
+    ["g2022132", "2024-2-29 10:00:00"],
+    ["g2022133", "2024-2-29 10:00:00"],
+    ["g2022134", "2024-2-29 10:00:00"],
+    ["g2022135", "2024-2-29 10:00:00"],
+    ["g2022136", "2024-2-29 10:00:00"],
+    ["g2022137", "2024-2-29 10:00:00"],
+    ["g2022138", "2024-2-29 10:00:00"],
+    ["g2022139", "2024-2-29 10:00:00"],
+    ["g2022140", "2024-2-29 10:00:00"],
+    ["g2022141", "2024-2-29 10:00:00"],
+    ["g2022142", "2024-2-29 10:00:00"],
+    ["g2022143", "2024-2-29 10:00:00"],
+    ["g2022144", "2024-2-29 10:00:00"],
+    ["g2022145", "2024-2-29 10:00:00"],
+    ["g2022146", "2024-2-29 10:00:00"],
+    ["g2022147", "2024-2-29 10:00:00"],
+    ["g2022148", "2024-2-29 10:00:00"],
+    ["g2022149", "2024-2-29 10:00:00"],
+    ["g2022150", "2024-2-29 10:00:00"],
+]
 # 是否只导出汇总
 is_total = true
 # 收益率起始值

+ 3 - 5
src/export_balance.rs

@@ -35,7 +35,7 @@ pub async fn export_balance(config_info: BalanceConfigInfo) {
                     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;
+                    let data = gate_exc.account_book("usdt".to_string(), start_time, end_time).await;
                     // info!("请求完成{:?}",data.clone());
                     if data.code.as_str() == "200" {
                         let account_name = account_info.get("account_name").unwrap();
@@ -214,7 +214,6 @@ pub async fn export_balance(config_info: BalanceConfigInfo) {
     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());
     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, statistic_result),
@@ -268,8 +267,6 @@ pub fn statistic_balance(balance_info: Vec<Vec<String>>, count_start_time: i64,
 
 pub fn supply_balance(source_balance_info: BTreeMap<String, Vec<Vec<String>>>, time_slicer: Vec<i64>) -> Vec<Vec<String>> {
     let mut balance_info_list: Vec<Vec<String>> = vec![];
-    println!("{:?}", source_balance_info);
-
     for time in time_slicer.clone() {
         // 根据时间片去拿数据 ,如果有添加没有,手动添加
         let mut total_price = Decimal::ZERO;
@@ -296,7 +293,8 @@ pub fn supply_balance(source_balance_info: BTreeMap<String, Vec<Vec<String>>>, t
                     break;
                 }
             }
-
+            println!("{:?}", new_info);
+            ;
             match new_info {
                 None => {
                     let balance_info_filter: Vec<Vec<String>> = balance_info.iter().filter(|item| {

+ 13 - 8
src/export_template/template_balance.rs

@@ -1,10 +1,12 @@
 use std::collections::BTreeMap;
 use std::fs::File;
 use std::io::Write;
+use std::str::FromStr;
 use chrono::NaiveDateTime;
 use handlebars::Handlebars;
 use rust_decimal::Decimal;
 use rust_decimal::prelude::{FromPrimitive, ToPrimitive};
+use rust_decimal_macros::dec;
 use serde_json::json;
 use tracing::info;
 use crate::utils::utils::{BalanceConfigInfo};
@@ -26,9 +28,9 @@ pub fn export_html(config: BalanceConfigInfo, acc_name_all: &Vec<String>, x_time
     }
     //每个账号的数据
     let mut map: BTreeMap<String, Vec<f64>> = BTreeMap::new();
-    let mut capital_info: BTreeMap<String, f64> = Default::default();
+    let mut capital_info: BTreeMap<String, Decimal> = Default::default();
     for acc_name in acc_name_all.clone() {
-        capital_info.insert(acc_name.parse().unwrap(), 0.0);
+        capital_info.insert(acc_name.parse().unwrap(), dec!(0));
     }
     for acc_name in acc_name_all.clone() {
         let mut pr_data: Vec<f64> = vec![];
@@ -37,14 +39,17 @@ pub fn export_html(config: BalanceConfigInfo, acc_name_all: &Vec<String>, x_time
         if map.contains_key(key) {
             pr_data = map.get(key).unwrap().clone();
         }
-
+        let mut income = dec!(0);
+        let mut earnings = dec!(0);
         for data in data_list.clone() {
             if data[0].clone().as_str() == key {
-                let pr = data[4].clone().parse::<f64>().unwrap();
-                pr_data.push(pr);
-                // if capital_info[key] == 0.0 { capital_info.insert(key.parse().unwrap(), pr); }
-                // let earnings = (pr - capital_info[key]) / capital_info[key] * 100.0;
-                // pr_data.push(earnings);
+                let pr = Decimal::from_str(&data[4]).unwrap();
+                if capital_info[key] == dec!(0) || data[5] == "transfer" {
+                    earnings = income;
+                    capital_info.insert(key.parse().unwrap(), pr);
+                }
+                income = if capital_info[key] == dec!(0) { dec!(0) } else { ((pr - capital_info[key]) / capital_info[key] * dec!(100.0) + earnings).round_dp(2) };
+                pr_data.push(f64::try_from(income).unwrap());
             }
         }
         map.insert(key.to_string(), pr_data);

+ 1 - 1
src/main.rs

@@ -50,7 +50,7 @@ async fn main() {
         if http::proxy::ParsingDetail::http_enable_proxy(config_clone.proxy_address.clone()) {
             info!("检测有代理配置,配置走代理");
         }
-        export_balance::export_balance(config_clone).await;
+        new_export_balance::export_balance(config_clone).await;
     }
 
     if config_obj.analyze_info.is_export {

+ 290 - 116
src/new_export_balance.rs

@@ -4,7 +4,11 @@ use std::io::BufReader;
 use std::str::FromStr;
 use chrono::NaiveDateTime;
 use rust_decimal::Decimal;
+use rust_decimal_macros::dec;
+use serde_json::json;
 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_gate::gate_swap_rest_utils::GateSwapRest;
 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_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 account_name_list: Vec<String> = vec![];
@@ -25,135 +30,287 @@ pub async fn export_balance(config_info: BalanceConfigInfo) {
         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 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 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>> {
@@ -161,6 +318,7 @@ pub fn supply_balance(source_balance_info: BTreeMap<String, Vec<Vec<String>>>, t
     for time in time_slicer.clone() {
         // 根据时间片去拿数据 ,如果有添加没有,手动添加
         let mut total_price = Decimal::ZERO;
+        let mut total_status = "profit".to_string();
         for (key, value) in source_balance_info.clone() {
             let mut balance_info = value.clone();
             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 {
                 None => {
                     let balance_info_filter: Vec<Vec<String>> = balance_info.iter().filter(|item| {
                         item[0].parse::<i64>().unwrap() < time
                     }).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 {
-                        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[5] = "fill".to_string();
                     total_price += Decimal::from_str(&last_balance_info[4]).unwrap();
                     balance_info_list.push(last_balance_info);
                 }
                 Some(ref info) => {
+                    if "transfer" == info[5] { total_status = info[5].to_string() };
                     total_price += Decimal::from_str(&info[4]).unwrap();
                     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

+ 18 - 2
src/swap_gate/gate_swap_rest_utils.rs

@@ -82,9 +82,25 @@ impl GateSwapRest {
     }
 
     //查询合约账户变更历史
-    pub async fn account_book(&mut self, settle: String) -> Response {
+    pub async fn account_book(&mut self, settle: String, start_time: i64, end_time: i64) -> Response {
         let params = serde_json::json!({
-            "limit":1000
+            "limit":1000,
+            "from":start_time-60*60*24*5,
+            "to":end_time
+        });
+        let data = self.request("GET".to_string(),
+                                "/api/v4".to_string(),
+                                format!("/futures/{}/account_book", settle),
+                                true,
+                                params.to_string(),
+        ).await;
+        data
+    }
+    pub async fn fill_account_book(&mut self, settle: String, start_time: i64, end_time: i64) -> Response {
+        let params = serde_json::json!({
+            "limit":1,
+            "from":end_time-60*60*24*30,
+            "to":end_time
         });
         let data = self.request("GET".to_string(),
                                 "/api/v4".to_string(),

+ 2 - 1
src/utils/utils.rs

@@ -73,6 +73,7 @@ pub struct BalanceConfigInfo {
     pub exchanges: Vec<String>,
     pub range_time: Vec<String>,
     pub count_range_time: Vec<String>,
+    pub add_account_list: Vec<Vec<String>>,
     pub export_mode: u64,
     pub export_path: String,
     pub export_name: String,
@@ -88,6 +89,7 @@ impl BalanceConfigInfo {
             exchanges: vec![],
             range_time: vec![],
             count_range_time: vec![],
+            add_account_list: vec![],
             export_mode: 0,
             export_path: "".to_string(),
             export_name: "".to_string(),
@@ -189,5 +191,4 @@ pub fn get_json_file(path: &str) -> serde_json::Value {
 pub fn set_json_file(path: &str, json: String) {
     let mut file = File::create(path).expect("Failed to create file");
     file.write_all(json.as_bytes()).expect("Failed to write to file");
-    println!("Data has been written to output.json");
 }