Browse Source

整合导出账户余额
修改导出ticker主动性可配置

gepangpang 1 year ago
parent
commit
597f3f1cbd

+ 1 - 1
.gitignore

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

+ 14 - 0
config_balance.toml.sample

@@ -0,0 +1,14 @@
+#是否执行导出
+is_export = true
+# 配置代理
+proxy_address = "127.0.0.1:7890"
+# 账号列表(account_name: 导出展示名字)
+account_list = [["account_name", "access_key", "secret_key", "pass_key"]]
+# 配置交易所 目前支持["gate"]
+exchanges = ["gate"]
+# 配置查询时间(格式:2023-12-6 15:00:00)
+range_time = ["2023-12-13 11:24:00", "2023-12-13 11:24:50"]
+# 导出路径(不填则为默认路径"./")
+export_path = ""
+# 导出文件名字(不填则为默认名字"export")
+export_name = ""

+ 0 - 0
config.toml.sample → config_ticker.toml.sample


+ 0 - 2
src/export/mod.rs

@@ -1,2 +0,0 @@
-pub mod html;
-pub mod htmlzz;

+ 70 - 75
src/gate_swap/gate_export_blance.rs → src/export_balance.rs

@@ -1,81 +1,89 @@
-use std::collections::{BTreeMap, HashSet};
-use std::str::FromStr;
+use std::collections::{BTreeMap};
 use chrono::NaiveDateTime;
-
 use tracing::info;
+use crate::{export_template};
+use crate::swap_gate::gate_swap_rest_utils::GateSwapRest;
+use crate::utils::utils::BalanceConfigInfo;
 
-use crate::{export, utils};
-use crate::gate_swap::gate_swap_rest_utils::GateSwapRest;
-
-pub async fn creation_account_book_html(start_time: i64) {
-    let config = utils::utils::get_config_info("./config.toml");
-
+pub async fn export_balance(config_info: BalanceConfigInfo) {
+    let config_info_clone = config_info.clone();
+    let start_time = NaiveDateTime::parse_from_str(&config_info.range_time[0].clone(), "%Y-%m-%d %H:%M:%S").unwrap().timestamp() - 8 * 3600;
+    let end_time = NaiveDateTime::parse_from_str(&config_info.range_time[1].clone(), "%Y-%m-%d %H:%M:%S").unwrap().timestamp() - 8 * 3600;
 
     //获取不同账号的数据
-    let mut acc_array: Vec<BTreeMap<String, String>> = vec![];
     let mut acc_all_data: BTreeMap<String, Vec<Vec<String>>> = BTreeMap::new();
-    let mut acc_all_data_clone: BTreeMap<String, Vec<Vec<String>>> = BTreeMap::new();
     let mut data_array_all: Vec<Vec<String>> = vec![];
-    let mut acc_name_all: Vec<String> = vec![];
-    let mut time_all: Vec<i64> = vec![];
+    let mut account_name_list: Vec<String> = vec![];
     loop {
-        let mut gate60: BTreeMap<String, String> = BTreeMap::new();
-        gate60.insert("acc_name".to_string(), String::from(""));
-        gate60.insert("access_key".to_string(), String::from(""));
-        gate60.insert("secret_key".to_string(), String::from(""));
-        acc_array.push(gate60);
-
-
-        if acc_array.len() == 0 {
+        if config_info_clone.account_list.len() == 0 {
             info!("没有账号信息");
             return;
         }
 
+        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());
 
-        for acc in acc_array {
-            let mut gate_exc = GateSwapRest::new(false, acc.clone());
-            let data = gate_exc.account_book("usdt".to_string(),start_time).await;
-            info!("请求完成{:?}",data.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 acc_name = acc.get("acc_name").unwrap().clone();
-                acc_name_all.push(acc_name.clone());
+                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 name_data_all_clone: Vec<Vec<String>> = vec![];
                     let mut times = 0;
 
                     for item in array {
                         let time = item["time"].as_i64().unwrap();//秒级
-                        if time == times{ continue;}
+                        if time == times { continue; }
                         times = time;
 
-                        time_all.push(time);
-                        // let time_str = NaiveDateTime::from_timestamp_millis((time + 8 * 3600) * 1000).unwrap().format("%Y-%m-%d %H:%M:%S%.3f").to_string();
-                        // info!("{:?}数据时间解析:{:?}",acc_name.clone(),time_str);
-
-
                         let change = item["change"].as_str().unwrap();
 
                         let balance = item["balance"].as_str().unwrap();
                         let type_str = match item["type"].as_str().unwrap() {
-                            "dnw" => { "转入转出" ;continue; }
+                            "dnw" => {
+                                "转入转出";
+                                continue;
+                            }
                             "pnl" => { "减仓盈亏" }
-                            "fee" => { "交易手续费";continue; }
-                            "refr" => { "推荐人返佣" ;continue;}
-                            "fund" => { "资金费用";continue; }
-                            "point_dnw" => { "点卡转入转出" ;continue;}
-                            "point_fee" => { "点卡交易手续费" ;continue;}
-                            "point_refr" => { "点卡推荐人返佣";continue; }
+                            "fee" => {
+                                "交易手续费";
+                                continue;
+                            }
+                            "refr" => {
+                                "推荐人返佣";
+                                continue;
+                            }
+                            "fund" => {
+                                "资金费用";
+                                continue;
+                            }
+                            "point_dnw" => {
+                                "点卡转入转出";
+                                continue;
+                            }
+                            "point_fee" => {
+                                "点卡交易手续费";
+                                continue;
+                            }
+                            "point_refr" => {
+                                "点卡推荐人返佣";
+                                continue;
+                            }
                             _ => {
-                                "未知-变更类型";continue;
+                                "未知-变更类型";
+                                continue;
                             }
                         };
 
 
-
                         let text = item["text"].as_str().unwrap();
                         let contract = item["contract"].as_str().unwrap();
                         let trade_id = item["trade_id"].as_str().unwrap();
@@ -91,7 +99,7 @@ pub async fn creation_account_book_html(start_time: i64) {
 
                         name_data_all.push(name_data_array.clone());
                     }
-                    acc_all_data.insert(acc_name.clone(), name_data_all.clone());
+                    acc_all_data.insert(account_name.clone(), name_data_all.clone());
                 } else {
                     info!("不是数组 检查数据");
                 }
@@ -100,16 +108,20 @@ pub async fn creation_account_book_html(start_time: i64) {
         }
         break;//这里是为了 代码收纳,用了loop来放置代码
     }
-    // info!("数据如下:{:?}",acc_all_data);
 
-    //1. 生成时间片
-    let mut unique = HashSet::new();
-    time_all.retain(|e| unique.insert(*e));
-    time_all.sort_by(|a, b| a.cmp(&b));
-    // info!("数据如下1:{:?}",time_all);
+    // 按小时取时间片
+    let mut last_timestamp: i64 = -1;
+    let mut export_time_list: Vec<i64> = vec![];
+    for item in start_time..end_time {
+        if item / 3600 != last_timestamp / 3600 {
+            last_timestamp = item;
+            export_time_list.push(last_timestamp);
+        }
+    }
+    export_time_list.push(end_time);
 
     //2. 数据根据时间片 补全数据
-    for time in &time_all {
+    for time in &export_time_list {
         // 根据时间片去拿数据 ,如果有添加没有,手动添加
         let mut sum_pr: f64 = 0 as f64;
         for (key, vale) in acc_all_data.clone() {
@@ -130,7 +142,6 @@ pub async fn creation_account_book_html(start_time: i64) {
                         }
                     }
                 }
-                // info!("数据如下2:{:?}",time_all);
             }
 
             //如果匹配到时间片,直接使用,没有则创建
@@ -150,7 +161,6 @@ pub async fn creation_account_book_html(start_time: i64) {
                     let mut acc_balance = "0".to_string();
                     let acc_type = "填补数据类型".to_string();
                     let mut acc_contract = "填补数据类型".to_string();
-                    let acc_text = "填补数据类型".to_string();
 
                     if filter_arrya.len() > 0 {
                         // info!("{:?}--{}--{:?}",acc_name, time, filter_arrya[filter_arrya.len() - 1].clone());
@@ -178,7 +188,7 @@ pub async fn creation_account_book_html(start_time: i64) {
                     row
                 }
             };
-            let time_str = NaiveDateTime::from_timestamp_millis((new_d[1].clone().parse::<i64>().unwrap() + 8 * 3600) * 1000).unwrap().format("%Y-%m-%d %H:%M:%S%.3f").to_string();
+            // let time_str = NaiveDateTime::from_timestamp_millis((new_d[1].clone().parse::<i64>().unwrap() + 8 * 3600) * 1000).unwrap().format("%Y-%m-%d %H:%M:%S%.3f").to_string();
             // info!("{:?}----时间片:{:?}",new_d[0].clone(),time_str);
             // info!("计算3333:---{:?}",time_str);
             // info!("{:?}=----pr:{:?}",key.clone().to_string(),new_d[4].clone());
@@ -195,30 +205,15 @@ pub async fn creation_account_book_html(start_time: i64) {
         sum_row.push("".to_string());
         sum_row.push("".to_string());
         data_array_all.push(sum_row.clone());
-        let time_str2 = NaiveDateTime::from_timestamp_millis((time + 8 * 3600) * 1000).unwrap().format("%Y-%m-%d %H:%M:%S%.3f").to_string();
-        // info!("------------------计算111:-----{:?}",time_str2);
     }
-    // println!("数据如下:{:?}", data_array_all);
 
-    // info!("时间片:{:?}",time_all.clone());
-    // info!("时间片长度:{:?}---数据节点长度{:?}", time_all.clone().len(),data_array_all.clone().len());
-
-
-    //限制时间之外的数据过滤
-    let start_time_str = NaiveDateTime::from_timestamp_millis((start_time + 8 * 3600) * 1000).unwrap().format("%Y-%m-%d %H:%M:%S%.3f").to_string();
-    let time_all_array: Vec<i64> = time_all.clone().into_iter().filter(|s| {
-        s >= &start_time
+    let data_array_all_array: Vec<Vec<String>> = data_array_all.clone().into_iter().filter(|value| {
+        let t = value[1].clone().parse::<i64>().unwrap();
+        t >= start_time && t <= end_time
     }).collect();
-    time_all = time_all_array;
-
-    let time_all_array: Vec<Vec<String>> = data_array_all.clone().into_iter().filter(|s| {
-        let t = s[1].clone().parse::<i64>().unwrap();
-        t >= start_time
-    }).collect();
-    data_array_all = time_all_array;
-
+    data_array_all = data_array_all_array;
 
     //生成 html
-    acc_name_all.push("sum_acc".to_string());
-    export::htmlzz::export_html(config.clone(), &acc_name_all, &time_all, &data_array_all);
+    account_name_list.push("sum_acc".to_string());
+    export_template::template_balance::export_html(config_info_clone.clone(), &account_name_list, &export_time_list, &data_array_all);
 }

+ 2 - 0
src/export_template/mod.rs

@@ -0,0 +1,2 @@
+pub mod template_ticker;
+pub mod template_balance;

+ 7 - 15
src/export/htmlzz.rs → src/export_template/template_balance.rs

@@ -1,25 +1,17 @@
 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 uuid::Uuid;
-use rust_decimal_macros::dec;
-use serde::{Deserialize, Serialize};
-use serde_json::{json, Value};
+use serde_json::json;
 use tracing::info;
-use crate::export::html::{ExportExchangeTickerInfo, SeriesInfo};
-use crate::struct_standard::Trades;
-use crate::utils::utils::ConfigInfo;
+use crate::utils::utils::{BalanceConfigInfo};
 
 
-pub fn export_html(config: ConfigInfo, acc_name_all: &Vec<String>, x_time: &Vec<i64>, data_list: &Vec<Vec<String>>) {
+pub fn export_html(config: BalanceConfigInfo, acc_name_all: &Vec<String>, x_time: &Vec<i64>, data_list: &Vec<Vec<String>>) {
     info!("正在生成网页,请稍后!");
     let export_path = if config.export_path == "" { "./" } else { config.export_path.as_str() };
-    let export_name = if config.export_name == "" { "acc_all" } else { config.export_name.as_str() };
+    let export_name = if config.export_name == "" { "export_balance" } else { config.export_name.as_str() };
     let path = format!("{}/{}.html", export_path, export_name).replace("//", "/");
     // 创建 Handlebars 实例
     let mut handlebars = Handlebars::new();
@@ -65,7 +57,7 @@ pub fn export_html(config: ConfigInfo, acc_name_all: &Vec<String>, x_time: &Vec<
         "data":series_all
     });
 
-    let strzzz =  format!("{}",json["data"]);
+    let series_str =  format!("{}",json["data"]);
     // info!("时间片:{:?}----{:?}",time_str_x.len(),time_str_x[time_str_x.len()-1]);
 
     let data = serde_json::json!({
@@ -131,7 +123,7 @@ pub fn export_html(config: ConfigInfo, acc_name_all: &Vec<String>, x_time: &Vec<
                     type: 'value',
                     scale: true
                   },
-                  series: "# + format!("{}", strzzz).as_ref() + r#"
+                  series: "# + format!("{}", series_str).as_ref() + r#"
                 };
 
             option && myChart.setOption(option);
@@ -152,5 +144,5 @@ pub fn export_html(config: ConfigInfo, acc_name_all: &Vec<String>, x_time: &Vec<
     // 将 HTML 写入文件
     let mut file = File::create(&path).expect("创建文件失败!");
     file.write_all(output.as_bytes()).expect("写入文件到本地失败!");
-    info!("网页生成成功!路径:{:?}", path);
+    info!("Balance信息网页生成成功!路径:{:?}\n\n", path);
 }

+ 89 - 75
src/export/html.rs → src/export_template/template_ticker.rs

@@ -10,7 +10,7 @@ use rust_decimal_macros::dec;
 use serde::{Deserialize, Serialize};
 use tracing::info;
 use crate::struct_standard::Trades;
-use crate::utils::utils::ConfigInfo;
+use crate::utils::utils::TickerConfigInfo;
 
 #[derive(Debug, Clone, Deserialize, Serialize)]
 pub struct ExportExchangeTickerInfo {
@@ -27,91 +27,103 @@ pub struct SeriesInfo {
     pub data: Vec<Trades>,
 }
 
-pub fn export_html(export_info: Vec<ExportExchangeTickerInfo>, start_at: &str, end_at: &str, config: ConfigInfo, robot_info: Vec<Trades>) {
+impl SeriesInfo {
+    fn new() -> SeriesInfo {
+        SeriesInfo {
+            name: "".to_string(),
+            classify: "".to_string(),
+            data: vec![],
+        }
+    }
+}
+
+pub fn export_html(export_info: Vec<ExportExchangeTickerInfo>, start_at: &str, end_at: &str, config: TickerConfigInfo, robot_info: Vec<Trades>) {
     info!("正在生成网页,请稍后!");
     let export_path = if config.export_path == "" { "./" } else { config.export_path.as_str() };
-    let export_name = if config.export_name == "" { "export" } else { config.export_name.as_str() };
+    let export_name = if config.export_name == "" { "export_ticker" } else { config.export_name.as_str() };
     let path = format!("{}/{}.html", export_path, export_name).replace("//", "/");
     // 创建 Handlebars 实例
     let mut handlebars = Handlebars::new();
 
+    let mut initiative_info = SeriesInfo::new();
+    if config.recall_time != 0 {
+        let mut max_price = Decimal::ZERO;
+        for item in export_info.clone() {
+            let exchange_max_price = Decimal::from_str(&item.max_price).unwrap();
+            max_price = if max_price < exchange_max_price { exchange_max_price } else { max_price };
+        }
 
-    let mut max_price = Decimal::ZERO;
-    for item in export_info.clone() {
-        let exchange_max_price = Decimal::from_str(&item.max_price).unwrap();
-        max_price = if max_price < exchange_max_price { exchange_max_price } else { max_price };
-    }
-
-    let mut initiative_info: Vec<Trades> = export_info.iter().flat_map(|exchange| exchange.ticker_info.clone()).collect();
-    initiative_info.sort_by(|a, b| a.create_time.cmp(&b.create_time));
+        let mut old_ticker_info: Vec<Trades> = export_info.iter().flat_map(|exchange| exchange.ticker_info.clone()).collect();
+        old_ticker_info.sort_by(|a, b| a.create_time.cmp(&b.create_time));
 
-    let mut recall_initiative_info: Vec<Trades> = export_info.iter().flat_map(|exchange| exchange.recall_ticker_info.clone()).collect();
-    recall_initiative_info.sort_by(|a, b| a.create_time.cmp(&b.create_time));
+        let mut old_recall_ticker_info: Vec<Trades> = export_info.iter().flat_map(|exchange| exchange.recall_ticker_info.clone()).collect();
+        old_recall_ticker_info.sort_by(|a, b| a.create_time.cmp(&b.create_time));
 
-    let mut ticker_info = vec![];
-    let mut last_bool = "";
-    for trades in initiative_info {
-        // 计算交易量差
-        let mut volume = Decimal::ZERO;
-        let mut short_volume = Decimal::ZERO;
-        let mut long_volume = Decimal::ZERO;
-        let mut sum_volume = Decimal::ZERO;
-        let recall_ticker_info: Vec<Trades> = recall_initiative_info.iter().filter(|recall_trades| {
-            let recall_create_time = Decimal::from_str(&recall_trades.create_time).unwrap();
-            let create_time = Decimal::from_str(&trades.create_time).unwrap();
-            let recall_time = Decimal::from_i64(config.recall_time).unwrap();
-            recall_create_time <= create_time && create_time - recall_create_time <= recall_time
-        }).cloned().collect();
-        for recall_trades in recall_ticker_info.clone() {
-            let size = Decimal::from_str(&recall_trades.size).unwrap();
-            volume += size;
-            sum_volume += size.abs();
-            if size > dec!(0) { long_volume += size } else { short_volume += size.abs() }
-        };
-        let long_volume_bool = long_volume / sum_volume >= config.long_volume_rate;
-        let short_volume_bool = short_volume / sum_volume >= config.short_volume_rate;
+        let mut ticker_info = vec![];
+        let mut last_bool = "";
+        for trades in old_ticker_info {
+            // 计算交易量差
+            let mut volume = Decimal::ZERO;
+            let mut short_volume = Decimal::ZERO;
+            let mut long_volume = Decimal::ZERO;
+            let mut sum_volume = Decimal::ZERO;
+            let recall_ticker_info: Vec<Trades> = old_recall_ticker_info.iter().filter(|recall_trades| {
+                let recall_create_time = Decimal::from_str(&recall_trades.create_time).unwrap();
+                let create_time = Decimal::from_str(&trades.create_time).unwrap();
+                let recall_time = Decimal::from_i64(config.recall_time).unwrap();
+                recall_create_time <= create_time && create_time - recall_create_time <= recall_time
+            }).cloned().collect();
+            for recall_trades in recall_ticker_info.clone() {
+                let size = Decimal::from_str(&recall_trades.size).unwrap();
+                volume += size;
+                sum_volume += size.abs();
+                if size > dec!(0) { long_volume += size } else { short_volume += size.abs() }
+            };
+            let long_volume_bool = long_volume / sum_volume >= config.long_volume_rate;
+            let short_volume_bool = short_volume / sum_volume >= config.short_volume_rate;
 
-        if (long_volume_bool && last_bool != "initiative_long") || (short_volume_bool && last_bool != "initiative_short") || (!long_volume_bool && !short_volume_bool && last_bool != "initiative_none") {
-            // 新增订单流主动性数据
-            let max_price = max_price * dec!(1.005);
-            let mut side = "";
-            if long_volume_bool {
-                last_bool = "initiative_long";
-                side = "LONG";
-            }
-            if short_volume_bool {
-                last_bool = "initiative_short";
-                side = "SHORT";
-            }
-            if !long_volume_bool && !short_volume_bool {
-                last_bool = "initiative_none";
-                side = "NONE";
+            if (long_volume_bool && last_bool != "initiative_long") || (short_volume_bool && last_bool != "initiative_short") || (!long_volume_bool && !short_volume_bool && last_bool != "initiative_none") {
+                // 新增订单流主动性数据
+                let max_price = max_price * dec!(1.005);
+                let mut side = "";
+                if long_volume_bool {
+                    last_bool = "initiative_long";
+                    side = "LONG";
+                }
+                if short_volume_bool {
+                    last_bool = "initiative_short";
+                    side = "SHORT";
+                }
+                if !long_volume_bool && !short_volume_bool {
+                    last_bool = "initiative_none";
+                    side = "NONE";
+                }
+                ticker_info.push(Trades {
+                    id: Uuid::new_v4().to_string()[0..8].to_string(),
+                    data_type: last_bool.to_string(),
+                    symbol: trades.symbol,
+                    create_time: trades.create_time,
+                    size: volume.to_string(),
+                    price: max_price.to_string(),
+                    side: side.to_string(),
+                    is_effect: true,
+                });
             }
-            ticker_info.push(Trades {
-                id: Uuid::new_v4().to_string()[0..8].to_string(),
-                data_type: last_bool.to_string(),
-                symbol: trades.symbol,
-                create_time: trades.create_time,
-                size: volume.to_string(),
-                price: max_price.to_string(),
-                side: side.to_string(),
-                is_effect: true,
-            });
-        }
-    }
-    // 对订单流主动性数据(recall)去重
-    let mut ticker_set = std::collections::HashSet::new();
-    let mut end_ticker_info = vec![];
-    for trades in ticker_info {
-        if ticker_set.insert((trades.data_type.clone(), trades.create_time.clone())) {
-            end_ticker_info.push(trades.clone());
         }
+        // 对订单流主动性数据(recall)去重
+        let mut ticker_set = std::collections::HashSet::new();
+        let mut initiative_ticker_info = vec![];
+        for trades in ticker_info {
+            if ticker_set.insert((trades.data_type.clone(), trades.create_time.clone())) {
+                initiative_ticker_info.push(trades.clone());
+            }
+        };
+        initiative_info = SeriesInfo {
+            name: "主动性".to_string(),
+            classify: "initiative".to_string(),
+            data: initiative_ticker_info.clone(),
+        };
     }
-    let initiative_info = SeriesInfo {
-        name: "主动性".to_string(),
-        classify: "initiative".to_string(),
-        data: end_ticker_info.clone(),
-    };
 
     let start_time_d = Decimal::from_str(start_at).unwrap() * dec!(1000) + dec!(8) * dec!(3600000);
     let end_time_d = Decimal::from_str(end_at).unwrap() * dec!(1000) + dec!(8) * dec!(3600000);
@@ -130,7 +142,9 @@ pub fn export_html(export_info: Vec<ExportExchangeTickerInfo>, start_at: &str, e
             data: item.ticker_info.clone(),
         })
     }
-    series_info.push(initiative_info);
+    if config.recall_time != 0 {
+        series_info.push(initiative_info);
+    }
 
     if config.robot_name != "" {
         let ref_robot_info: Vec<Trades> = robot_info.iter().filter(|trades| trades.data_type == "robot_ref_info").cloned().collect();
@@ -347,5 +361,5 @@ pub fn export_html(export_info: Vec<ExportExchangeTickerInfo>, start_at: &str, e
     // 将 HTML 写入文件
     let mut file = File::create(&path).expect("创建文件失败!");
     file.write_all(output.as_bytes()).expect("写入文件到本地失败!");
-    info!("网页生成成功!路径:{:?}", path);
+    info!("Ticker信息网页生成成功!路径:{:?}\n\n", path);
 }

+ 84 - 0
src/export_ticker.rs

@@ -0,0 +1,84 @@
+use std::str::FromStr;
+use chrono::NaiveDateTime;
+use rust_decimal::Decimal;
+use rust_decimal::prelude::ToPrimitive;
+use tracing::error;
+use crate::export_template::template_ticker::ExportExchangeTickerInfo;
+use crate::{export_template, handle_ticker};
+use crate::struct_standard::Trades;
+use crate::utils::utils::TickerConfigInfo;
+
+pub async fn export_ticker(config_info: TickerConfigInfo) {
+    let config_clone = config_info.clone();
+
+    let symbol = config_clone.symbol;
+    let start_at = NaiveDateTime::parse_from_str(&config_info.range_time[0].clone(), "%Y-%m-%d %H:%M:%S").unwrap().timestamp() - 8 * 3600;
+    let end_at = NaiveDateTime::parse_from_str(&config_info.range_time[1].clone(), "%Y-%m-%d %H:%M:%S").unwrap().timestamp() - 8 * 3600;
+
+    let recall_start_at = start_at - config_info.recall_time / 1000;
+
+    let mut exchange_list = vec![];
+    for exchange in config_info.exchanges.clone() {
+        let exchange_up = exchange.to_uppercase();
+        let exchange_result = match exchange_up.as_str() {
+            "BINANCE" => {
+                let recall_ticker_info = handle_ticker::get_binance_ticker_info(&symbol, &recall_start_at.to_string(), &end_at.to_string()).await;
+                let ticker_info: Vec<Trades> = recall_ticker_info.iter().filter(|item| item.create_time.parse::<i64>().unwrap() >= start_at * 1000).cloned().collect();
+                let mut max_price = Decimal::ZERO;
+                for trades in ticker_info.clone() {
+                    let trades_price = Decimal::from_str(&trades.price).unwrap();
+                    max_price = if trades_price > max_price { trades_price } else { max_price };
+                };
+                let start_index = recall_ticker_info.len().saturating_sub(ticker_info.len()).saturating_sub(config_clone.recall_max_count.to_usize().unwrap());
+                ExportExchangeTickerInfo {
+                    name: exchange.to_string(),
+                    ticker_info,
+                    recall_ticker_info: recall_ticker_info[start_index..].to_vec(),
+                    max_price: max_price.to_string(),
+                }
+            }
+            "GATE" => {
+                let recall_ticker_info = handle_ticker::get_gate_ticker_info(&symbol, &recall_start_at.to_string(), &end_at.to_string()).await;
+                let ticker_info: Vec<Trades> = recall_ticker_info.iter().filter(|item| item.create_time.parse::<i64>().unwrap() >= start_at * 1000).cloned().collect();
+                let mut max_price = Decimal::ZERO;
+                for trades in ticker_info.clone() {
+                    let trades_price = Decimal::from_str(&trades.price).unwrap();
+                    max_price = if trades_price > max_price { trades_price } else { max_price };
+                };
+                let start_index = recall_ticker_info.len().saturating_sub(ticker_info.len()).saturating_sub(config_clone.recall_max_count.to_usize().unwrap());
+                ExportExchangeTickerInfo {
+                    name: exchange.to_string(),
+                    ticker_info,
+                    recall_ticker_info: recall_ticker_info[start_index..].to_vec(),
+                    max_price: max_price.to_string(),
+                }
+            }
+            "OKX" => {
+                let recall_ticker_info = handle_ticker::get_okx_ticker_info(&symbol, &recall_start_at.to_string(), &end_at.to_string()).await;
+                let ticker_info: Vec<Trades> = recall_ticker_info.iter().filter(|item| item.create_time.parse::<i64>().unwrap() >= start_at * 1000).cloned().collect();
+                let mut max_price = Decimal::ZERO;
+                for trades in ticker_info.clone() {
+                    let trades_price = Decimal::from_str(&trades.price).unwrap();
+                    max_price = if trades_price > max_price { trades_price } else { max_price };
+                };
+                let start_index = recall_ticker_info.len().saturating_sub(ticker_info.len()).saturating_sub(config_clone.recall_max_count.to_usize().unwrap());
+                ExportExchangeTickerInfo {
+                    name: exchange.to_string(),
+                    ticker_info,
+                    recall_ticker_info: recall_ticker_info[start_index..].to_vec(),
+                    max_price: max_price.to_string(),
+                }
+            }
+            _ => {
+                error!("交易所输入错误!");
+                panic!("交易所输入错误!")
+            }
+        };
+        exchange_list.push(exchange_result);
+    }
+    let mut robot_info = vec![];
+    if config_clone.robot_name != "" {
+        robot_info = handle_ticker::get_robot_info(&symbol, &config_clone.robot_name, &start_at.to_string(), &end_at.to_string()).await;
+    }
+    export_template::template_ticker::export_html(exchange_list, &start_at.to_string(), &end_at.to_string(), config_info.clone(), robot_info);
+}

+ 3 - 31
src/handle_ticker.rs

@@ -5,9 +5,9 @@ use rust_decimal::Decimal;
 use rust_decimal_macros::dec;
 use tracing::{error, info};
 
-use crate::binance_swap::binance_swap_standard;
-use crate::gate_swap::gate_swap_standard;
-use crate::okx_swap::okx_swap_standard;
+use crate::swap_binance::binance_swap_standard;
+use crate::swap_gate::gate_swap_standard;
+use crate::swap_okx::okx_swap_standard;
 use crate::robot_data;
 use crate::struct_standard::{AggTrades, Trades};
 
@@ -82,20 +82,6 @@ pub async fn get_binance_ticker_info(symbol: &str, start_at: &str, end_at: &str)
             side: if agg_trades_size > Decimal::ZERO { "BUY".to_string() } else { "SELL".to_string() },
             is_effect: true,
         })
-        // let id_diff = Decimal::from_str(&agg_trades.end_id).unwrap() - Decimal::from_str(&agg_trades.start_id).unwrap();
-        // if id_diff > Decimal::ONE {
-        //     println!("{},{},{},{}", agg_ticker_info_list[agg_ticker_info_list.len() - 1].id, agg_trades.id, agg_trades.start_id, agg_trades.end_id);
-        //     let trades_info = binance_swap_standard::standard_trades(symbol, &(id_diff + dec!(1)).to_string(), &agg_trades.start_id).await;
-        //     ticker_info_list.extend(trades_info.unwrap());
-        // } else {
-        //     ticker_info_list.push(Trades {
-        //         id: agg_trades.start_id,
-        //         symbol: agg_trades.symbol,
-        //         create_time: agg_trades.create_time,
-        //         size: agg_trades.size,
-        //         price: agg_trades.price,z
-        //     })
-        // }
     }
     ticker_info_list.iter().filter(|trades| trades.is_effect).cloned().collect()
 }
@@ -130,7 +116,6 @@ pub async fn get_okx_ticker_info(symbol: &str, start_at: &str, end_at: &str) ->
                 tokio::time::sleep(Duration::from_millis(500)).await;
                 i = i + 1;
                 let start_at_str = format!("{}000", start_at);
-                // info!("比较:{:?}-{:?}",start_at_str , create_time_size);
                 if start_at_str < create_time_size {
                     let ticker_one2 = okx_swap_standard::standard_history_candles(symbol, "", create_time_size.as_ref(), ct_val).await.unwrap();
 
@@ -155,19 +140,6 @@ pub async fn get_okx_ticker_info(symbol: &str, start_at: &str, end_at: &str) ->
     list_array.clone().into_iter().filter(|trades| {
         trades.create_time > start_at_d_str && trades.create_time < end_at_d_str && trades.is_effect && set.insert(trades.clone())
     }).collect()
-    //
-    // list_array = list_array.iter().filter(|item| item.create_time <= end_at.to_string()).cloned().collect();
-    // let mut ticker_info_list: Vec<Trades> = vec![];
-    // for agg_trades in list_array.clone() {
-    //     ticker_info_list.push(Trades {
-    //         id: agg_trades.start_id,
-    //         symbol: agg_trades.symbol,
-    //         create_time: agg_trades.create_time,
-    //         size: agg_trades.size,
-    //         price: agg_trades.price,
-    //     })
-    // }
-    // ticker_info_list
 }
 
 pub async fn get_robot_info(symbol: &str, robot_name: &str, start_at: &str, end_at: &str) -> Vec<Trades> {

+ 36 - 89
src/main.rs

@@ -1,101 +1,48 @@
-use std::str::FromStr;
-
-use rust_decimal::prelude::ToPrimitive;
-
-use crate::gate_swap::gate_export_blance::{ creation_account_book_html};
+use tracing::info;
 use crate::utils::logs;
+use crate::utils::utils::{BalanceConfigInfo, TickerConfigInfo};
 
-pub mod binance_swap;
-pub mod gate_swap;
-pub mod okx_swap;
+pub mod swap_binance;
+pub mod swap_gate;
+pub mod swap_okx;
 pub mod robot_data;
 pub mod utils;
 pub mod http;
 pub mod struct_standard;
-pub mod export;
+pub mod export_template;
 pub mod handle_ticker;
+pub mod export_balance;
+pub mod export_ticker;
+
+struct ConfigList {
+    ticker_info: TickerConfigInfo,
+    balance_info: BalanceConfigInfo,
+}
 
 #[tokio::main]
 async fn main() {
     logs::init_log_with_info();
+    let ticker_config = utils::utils::get_ticker_config_info("./config_ticker.toml");
+    let balance_config = utils::utils::get_balance_config_info("./config_balance.toml");
+    let config_obj = ConfigList {
+        ticker_info: ticker_config,
+        balance_info: balance_config,
+    };
 
-    // let config = utils::utils::get_config_info("./config.toml");
-    // let config_clone = config.clone();
-    // if http::proxy::ParsingDetail::http_enable_proxy(config_clone.proxy_address) {
-    //     info!("检测有代理配置,配置走代理");
-    // }
-    // let symbol = config_clone.symbol;
-    // let start_at = NaiveDateTime::parse_from_str(&config.range_time[0].clone(), "%Y-%m-%d %H:%M:%S").unwrap().timestamp() - 8 * 3600;
-    // let end_at = NaiveDateTime::parse_from_str(&config.range_time[1].clone(), "%Y-%m-%d %H:%M:%S").unwrap().timestamp() - 8 * 3600;
-    //
-    // let recall_start_at = start_at - config.recall_time / 1000;
-    //
-    // let mut exchange_list = vec![];
-    // for exchange in config.exchanges.clone() {
-    //     let exchange_up = exchange.to_uppercase();
-    //     let exchange_result = match exchange_up.as_str() {
-    //         "BINANCE" => {
-    //             let recall_ticker_info = handle_ticker::get_binance_ticker_info(&symbol, &recall_start_at.to_string(), &end_at.to_string()).await;
-    //             let ticker_info: Vec<Trades> = recall_ticker_info.iter().filter(|item| item.create_time.parse::<i64>().unwrap() >= start_at * 1000).cloned().collect();
-    //             let mut max_price = Decimal::ZERO;
-    //             for trades in ticker_info.clone() {
-    //                 let trades_price = Decimal::from_str(&trades.price).unwrap();
-    //                 max_price = if trades_price > max_price { trades_price } else { max_price };
-    //             };
-    //             let start_index = recall_ticker_info.len().saturating_sub(ticker_info.len()).saturating_sub(config_clone.recall_max_count.to_usize().unwrap());
-    //             ExportExchangeTickerInfo {
-    //                 name: exchange.to_string(),
-    //                 ticker_info,
-    //                 recall_ticker_info: recall_ticker_info[start_index..].to_vec(),
-    //                 max_price: max_price.to_string(),
-    //             }
-    //         }
-    //         "GATE" => {
-    //             let recall_ticker_info = handle_ticker::get_gate_ticker_info(&symbol, &recall_start_at.to_string(), &end_at.to_string()).await;
-    //             let ticker_info: Vec<Trades> = recall_ticker_info.iter().filter(|item| item.create_time.parse::<i64>().unwrap() >= start_at * 1000).cloned().collect();
-    //             let mut max_price = Decimal::ZERO;
-    //             for trades in ticker_info.clone() {
-    //                 let trades_price = Decimal::from_str(&trades.price).unwrap();
-    //                 max_price = if trades_price > max_price { trades_price } else { max_price };
-    //             };
-    //             let start_index = recall_ticker_info.len().saturating_sub(ticker_info.len()).saturating_sub(config_clone.recall_max_count.to_usize().unwrap());
-    //             ExportExchangeTickerInfo {
-    //                 name: exchange.to_string(),
-    //                 ticker_info,
-    //                 recall_ticker_info: recall_ticker_info[start_index..].to_vec(),
-    //                 max_price: max_price.to_string(),
-    //             }
-    //         }
-    //         "OKX" => {
-    //             let recall_ticker_info = handle_ticker::get_okx_ticker_info(&symbol, &recall_start_at.to_string(), &end_at.to_string()).await;
-    //             let ticker_info: Vec<Trades> = recall_ticker_info.iter().filter(|item| item.create_time.parse::<i64>().unwrap() >= start_at * 1000).cloned().collect();
-    //             let mut max_price = Decimal::ZERO;
-    //             for trades in ticker_info.clone() {
-    //                 let trades_price = Decimal::from_str(&trades.price).unwrap();
-    //                 max_price = if trades_price > max_price { trades_price } else { max_price };
-    //             };
-    //             let start_index = recall_ticker_info.len().saturating_sub(ticker_info.len()).saturating_sub(config_clone.recall_max_count.to_usize().unwrap());
-    //             ExportExchangeTickerInfo {
-    //                 name: exchange.to_string(),
-    //                 ticker_info,
-    //                 recall_ticker_info: recall_ticker_info[start_index..].to_vec(),
-    //                 max_price: max_price.to_string(),
-    //             }
-    //         }
-    //         _ => {
-    //             error!("交易所输入错误!");
-    //             panic!("交易所输入错误!")
-    //         }
-    //     };
-    //     exchange_list.push(exchange_result);
-    // }
-    // let mut robot_info = vec![];
-    // if config_clone.robot_name != "" {
-    //     robot_info = handle_ticker::get_robot_info(&symbol, &config_clone.robot_name, &start_at.to_string(), &end_at.to_string()).await;
-    // }
-    // export::html::export_html(exchange_list, &start_at.to_string(), &end_at.to_string(), config.clone(), robot_info);
-
-
-    //账号变更统计
-    creation_account_book_html(1702008000).await;
-}
+    if config_obj.ticker_info.is_export {
+        info!("----------正在导出Ticker信息----------");
+        let config_clone = config_obj.ticker_info.clone();
+        if http::proxy::ParsingDetail::http_enable_proxy(config_clone.proxy_address.clone()) {
+            info!("检测有代理配置,配置走代理");
+        }
+        export_ticker::export_ticker(config_clone).await;
+    }
+    if config_obj.balance_info.is_export {
+        info!("----------正在导出Balance信息----------");
+        let config_clone = config_obj.balance_info.clone();
+        if http::proxy::ParsingDetail::http_enable_proxy(config_clone.proxy_address.clone()) {
+            info!("检测有代理配置,配置走代理");
+        }
+        export_balance::export_balance(config_clone).await;
+    }
+}

+ 0 - 0
src/binance_swap/binance_swap_rest.rs → src/swap_binance/binance_swap_rest.rs


+ 1 - 1
src/binance_swap/binance_swap_standard.rs → src/swap_binance/binance_swap_standard.rs

@@ -1,7 +1,7 @@
 use std::io::{Error, ErrorKind};
 use rust_decimal::Decimal;
 use serde::{Deserialize, Serialize};
-use crate::binance_swap::binance_swap_rest::{get_agg_trades, get_trades};
+use crate::swap_binance::binance_swap_rest::{get_agg_trades, get_trades};
 use crate::struct_standard::{AggTrades, Trades};
 use crate::utils::utils::format_symbol;
 

+ 0 - 0
src/binance_swap/mod.rs → src/swap_binance/mod.rs


+ 0 - 0
src/gate_swap/gate_swap_rest.rs → src/swap_gate/gate_swap_rest.rs


+ 20 - 55
src/gate_swap/gate_swap_rest_utils.rs → src/swap_gate/gate_swap_rest_utils.rs

@@ -2,20 +2,18 @@ use std::collections::BTreeMap;
 
 use hex;
 use hmac::{Hmac, Mac, NewMac};
-use reqwest::Client;
-use reqwest::header::HeaderMap;
 use ring::digest;
 use rust_decimal::Decimal;
-use rust_decimal::prelude::FromPrimitive;
 use rust_decimal_macros::dec;
 use serde_json::Value;
 use sha2::Sha512;
-use tracing::{info, trace};
+use tracing::info;
 use crate::http::request::Response;
 use crate::utils::utils::parse_params_to_str;
 
 
 #[derive(Clone)]
+#[allow(dead_code)]
 pub struct GateSwapRest {
     label: String,
     base_url: String,
@@ -54,7 +52,7 @@ impl GateSwapRest {
         GateSwapRest {
             label,
             base_url: base_url.to_string(),
-            client: Client::new(),
+            client: reqwest::Client::new(),
             login_param,
             delays: vec![],
             max_delay: 0,
@@ -84,10 +82,10 @@ impl GateSwapRest {
     }
 
     //查询合约账户变更历史
-    pub async fn account_book(&mut self, settle: String,from:i64) -> Response {
+    pub async fn account_book(&mut self, settle: String) -> Response {
         let params = serde_json::json!({
-                "limit":100
-             });
+            "limit":1000
+        });
         let data = self.request("GET".to_string(),
                                 "/api/v4".to_string(),
                                 format!("/futures/{}/account_book", settle),
@@ -97,41 +95,9 @@ impl GateSwapRest {
         data
     }
 
-
-    /*******************************************************************************************************/
-    /*****************************************工具函数********************************************************/
-    /*******************************************************************************************************/
-    pub fn get_delays(&self) -> Vec<i64> {
-        self.delays.clone()
-    }
-    pub fn get_avg_delay(&self) -> Decimal {
-        self.avg_delay.clone()
-    }
-    pub fn get_max_delay(&self) -> i64 {
-        self.max_delay.clone()
-    }
-    fn get_delay_info(&mut self) {
-        let last_100 = if self.delays.len() > 100 {
-            self.delays[self.delays.len() - 100..].to_vec()
-        } else {
-            self.delays.clone()
-        };
-
-        let max_value = last_100.iter().max().unwrap();
-        if max_value.clone().to_owned() > self.max_delay {
-            self.max_delay = max_value.clone().to_owned();
-        }
-
-        let sum: i64 = last_100.iter().sum();
-        let sum_v = Decimal::from_i64(sum).unwrap();
-        let len_v = Decimal::from_u64(last_100.len() as u64).unwrap();
-        self.avg_delay = (sum_v / len_v).round_dp(1);
-        self.delays = last_100.clone().into_iter().collect();
-    }
-
     //调用请求
     async fn request(&mut self,
-                     requesst_type: String,
+                     request_type: String,
                      prefix_url: String,
                      request_url: String,
                      is_login: bool,
@@ -156,8 +122,8 @@ impl GateSwapRest {
         let mut body = "".to_string();
         let timestamp = chrono::Utc::now().timestamp().to_string();
 
-        let mut headers = HeaderMap::new();
-        if requesst_type == "GET" {
+        let mut headers = reqwest::header::HeaderMap::new();
+        if request_type == "GET" {
             headers.insert("Content-type", "application/x-www-form-urlencoded".parse().unwrap());
             headers.insert("User-Agent", "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) ".parse().unwrap());
         } else {
@@ -165,7 +131,7 @@ impl GateSwapRest {
             headers.insert("Content-Type", "application/json".parse().unwrap());
         }
 
-        if requesst_type == "POST" {
+        if request_type == "POST" {
             body = params.clone();
         }
 
@@ -179,7 +145,7 @@ impl GateSwapRest {
             } else {//需要登陆-且登陆参数齐全
                 //组装sing
                 let sing = Self::sign(secret_key.clone(),
-                                      requesst_type.clone(),
+                                      request_type.clone(),
                                       prefix_url.clone(),
                                       request_url.clone(),
                                       params.clone(),
@@ -194,10 +160,9 @@ impl GateSwapRest {
 
         // trace!("headers:{:?}", headers);
         let base_url = format!("{}{}", prefix_url.clone(), request_url.clone());
-        let start_time = chrono::Utc::now().timestamp_millis();
         let get_response = self.http_toll(
             base_url.clone(),
-            requesst_type.to_string(),
+            request_type.to_string(),
             params.clone(),
             headers,
         ).await;
@@ -205,15 +170,15 @@ impl GateSwapRest {
         res_data
     }
 
-    pub fn headers(access_key: String, timestamp: String, sign: String) -> HeaderMap {
-        let mut headers = HeaderMap::new();
+    pub fn headers(access_key: String, timestamp: String, sign: String) -> reqwest::header::HeaderMap {
+        let mut headers = reqwest::header::HeaderMap::new();
         headers.insert("KEY", access_key.clone().parse().unwrap());
         headers.insert("Timestamp", timestamp.clone().parse().unwrap());
         headers.insert("SIGN", sign.clone().parse().unwrap());
         headers
     }
     pub fn sign(secret_key: String,
-                requesst_type: String, prefix_url: String, request_url: String,
+                request_type: String, prefix_url: String, request_url: String,
                 params: String, body_data: String, timestamp: String) -> String
     {
         let url = format!("{}{}", prefix_url, request_url);
@@ -229,7 +194,7 @@ impl GateSwapRest {
         // trace!("hashed_payload:{}", hashed_payload);
 
         let message = format!("{}\n{}\n{}\n{}\n{}",
-                              requesst_type,
+                              request_type,
                               url,
                               params_str,
                               hashed_payload,
@@ -246,7 +211,7 @@ impl GateSwapRest {
     }
 
 
-    async fn http_toll(&mut self, request_path: String, request_type: String, params: String, headers: HeaderMap) -> Result<Response, reqwest::Error> {
+    async fn http_toll(&mut self, request_path: String, request_type: String, params: String, headers: reqwest::header::HeaderMap) -> Result<Response, reqwest::Error> {
         /****请求接口与 地址*/
         let url = format!("{}{}", self.base_url.to_string(), request_path);
         let request_type = request_type.clone().to_uppercase();
@@ -267,7 +232,7 @@ impl GateSwapRest {
                 res.code = "-1".to_string();
                 res.msg = "请求类型错误".to_string();
                 res.data = "".to_string();
-                return Ok((res));
+                return Ok(res);
             }
         };
 
@@ -286,7 +251,7 @@ impl GateSwapRest {
             res.msg = body;
             res.data = "".to_string();
         }
-        Ok((res))
+        Ok(res)
     }
 
     //res_data 解析
@@ -300,7 +265,7 @@ impl GateSwapRest {
                     // let json_value: serde_json::Value = serde_json::from_str(&message).unwrap();//这种方式会触发 解析错误
                     let json_value = serde_json::from_str::<Value>(&message);
                     match json_value {
-                        Ok(data) => {
+                        Ok(_data) => {
                             let mut error = Response::new();
                             error.code = "-1".to_string();
                             error.msg = format!("请求错误{:?}", res.msg);

+ 1 - 1
src/gate_swap/gate_swap_standard.rs → src/swap_gate/gate_swap_standard.rs

@@ -3,7 +3,7 @@ use std::io::{Error, ErrorKind};
 use rust_decimal::Decimal;
 use rust_decimal::prelude::FromPrimitive;
 use serde::{Deserialize, Serialize};
-use crate::gate_swap::gate_swap_rest::{get_market, get_trades};
+use crate::swap_gate::gate_swap_rest::{get_market, get_trades};
 use crate::struct_standard::{Market, Trades};
 use crate::utils::utils::format_symbol;
 

+ 0 - 1
src/gate_swap/mod.rs → src/swap_gate/mod.rs

@@ -1,4 +1,3 @@
 pub mod gate_swap_rest_utils;
 pub mod gate_swap_standard;
 pub mod gate_swap_rest;
-pub mod gate_export_blance;

+ 0 - 0
src/okx_swap/mod.rs → src/swap_okx/mod.rs


+ 0 - 0
src/okx_swap/okx_swap_rest.rs → src/swap_okx/okx_swap_rest.rs


+ 1 - 1
src/okx_swap/okx_swap_standard.rs → src/swap_okx/okx_swap_standard.rs

@@ -3,7 +3,7 @@ use rust_decimal::Decimal;
 
 use serde::{Deserialize, Serialize};
 
-use crate::okx_swap::okx_swap_rest::{get_history_trades, get_symbol_details_all};
+use crate::swap_okx::okx_swap_rest::{get_history_trades, get_symbol_details_all};
 use crate::struct_standard::Trades;
 
 #[derive(Debug, Deserialize, Serialize)]

+ 51 - 7
src/utils/utils.rs

@@ -13,7 +13,8 @@ pub fn format_symbol(symbol: &str, pat: &str) -> String {
 }
 
 #[derive(Debug, Clone, Deserialize)]
-pub struct ConfigInfo {
+pub struct TickerConfigInfo {
+    pub is_export:bool,
     pub proxy_address: String,
     pub exchanges: Vec<String>,
     pub symbol: String,
@@ -27,9 +28,10 @@ pub struct ConfigInfo {
     pub export_name: String,
 }
 
-impl ConfigInfo {
-    fn new() -> ConfigInfo {
-        ConfigInfo {
+impl TickerConfigInfo {
+    fn new() -> TickerConfigInfo {
+        TickerConfigInfo {
+            is_export: false,
             proxy_address: "".to_string(),
             exchanges: vec![],
             symbol: "".to_string(),
@@ -46,17 +48,59 @@ impl ConfigInfo {
 }
 
 // 获取文件内容
-pub fn get_config_info(file_path: &str) -> ConfigInfo {
+pub fn get_ticker_config_info(file_path: &str) -> TickerConfigInfo {
     let file = File::open(file_path);
     let mut contents = String::new();
     let result = match file {
         Ok(mut value) => {
             value.read_to_string(&mut contents).unwrap_or_default();
-            from_str(&contents).unwrap_or(ConfigInfo::new())
+            from_str(&contents).unwrap_or(TickerConfigInfo::new())
         }
         Err(_) => {
             error!("没有获取到配置文件!");
-            ConfigInfo::new()
+            TickerConfigInfo::new()
+        }
+    };
+    result
+}
+
+#[derive(Debug, Clone, Deserialize)]
+pub struct BalanceConfigInfo {
+    pub is_export:bool,
+    pub proxy_address: String,
+    pub account_list: Vec<Vec<String>>,
+    pub exchanges: Vec<String>,
+    pub range_time: Vec<String>,
+    pub export_path: String,
+    pub export_name: String,
+}
+
+impl BalanceConfigInfo {
+    fn new() -> BalanceConfigInfo {
+        BalanceConfigInfo {
+            is_export: false,
+            proxy_address: "".to_string(),
+            account_list: vec![],
+            exchanges: vec![],
+            range_time: vec![],
+            export_path: "".to_string(),
+            export_name: "".to_string(),
+        }
+    }
+}
+
+// 获取文件内容
+pub fn get_balance_config_info(file_path: &str) -> BalanceConfigInfo {
+    let file = File::open(file_path);
+    let mut contents = String::new();
+    let result = match file {
+        Ok(mut value) => {
+            value.read_to_string(&mut contents).unwrap_or_default();
+            from_str(&contents).unwrap_or(BalanceConfigInfo::new())
+        }
+        Err(_) => {
+            error!("没有获取到配置文件!");
+            BalanceConfigInfo::new()
         }
     };
     result