|
|
@@ -1,8 +1,6 @@
|
|
|
use std::collections::{BTreeMap};
|
|
|
-use std::str::FromStr;
|
|
|
use async_trait::async_trait;
|
|
|
use chrono::{FixedOffset, NaiveDateTime, TimeZone};
|
|
|
-use rust_decimal::Decimal;
|
|
|
use rust_decimal::prelude::ToPrimitive;
|
|
|
use serde::{Deserialize, Serialize};
|
|
|
use tracing::{warn};
|
|
|
@@ -22,6 +20,17 @@ impl BybitSwapExport {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+#[async_trait]
|
|
|
+impl ExportConnector for BybitSwapExport {
|
|
|
+ async fn export_trades(&mut self, prefix_name: &str, symbol: String, start_time: i64, end_time: i64, limit: i64) -> String {
|
|
|
+ let pnl_array = get_position_pnl(self.request.clone(), symbol.clone(), start_time.clone(), end_time.clone(), limit.clone()).await;
|
|
|
+ let trades_array = get_trades(self.request.clone(), symbol.clone(), start_time.clone(), end_time.clone(), limit.clone()).await;
|
|
|
+ let pnl_header_array = vec!["订单编号", "交易币对", "买卖方向", "入场价格", "出场价格", "交易类型", "成交数量", "交易盈亏", "创建时间", "更新时间"];
|
|
|
+ let trades_header_array = vec!["交易编号", "订单编号", "交易币对", "买卖方向", "成交价格", "成交数量", "交易类型", "成交价值", "交易费用", "交易费率", "交易时间"];
|
|
|
+ global::export_utils::export_excel_sheets(vec![pnl_header_array, trades_header_array], vec![pnl_array, trades_array], vec!["pnl", "trades"], prefix_name)
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
/// TradesSwap
|
|
|
/// - `symbol`: String,
|
|
|
/// - `order_id`: String,
|
|
|
@@ -84,52 +93,109 @@ struct TradesSwap {
|
|
|
seq: i64,
|
|
|
}
|
|
|
|
|
|
-#[async_trait]
|
|
|
-impl ExportConnector for BybitSwapExport {
|
|
|
- async fn export_trades(&mut self, prefix_name: &str, symbol: String, start_time: i64, end_time: i64, limit: i64) -> String {
|
|
|
- let symbol_format = utils::format_symbol(symbol.clone(), "");
|
|
|
- let limit_params = if limit > 1000 {
|
|
|
- warn!("查询条数最大为1000条,已修改为1000条!");
|
|
|
- 1000
|
|
|
- } else { limit };
|
|
|
- let mut cursor = "".to_string();
|
|
|
- let mut data_array = vec![];
|
|
|
+async fn get_trades(mut request: BybitSwapRest, symbol: String, start_time: i64, end_time: i64, limit: i64) -> Vec<Vec<String>> {
|
|
|
+ let symbol_format = utils::format_symbol(symbol.clone(), "");
|
|
|
+ let limit_params = if limit > 100 {
|
|
|
+ warn!("查询条数最大为1000条,已修改为100条!");
|
|
|
+ 100
|
|
|
+ } else { limit };
|
|
|
+ let mut cursor = "".to_string();
|
|
|
+ let mut data_array = vec![];
|
|
|
|
|
|
- loop {
|
|
|
- let res_data = self.request.get_user_trades(symbol_format.clone(), start_time, end_time, limit_params, cursor.clone()).await;
|
|
|
- if res_data.code == 200 {
|
|
|
- let data_clone = res_data.data.clone();
|
|
|
- let trades_info: Vec<TradesSwap> = serde_json::from_str(&*data_clone["list"].to_string()).unwrap();
|
|
|
- cursor = data_clone["nextPageCursor"].as_str().unwrap_or("").to_string();
|
|
|
- for value in trades_info.iter() {
|
|
|
- let time = FixedOffset::east_opt(8 * 3600).unwrap().from_utc_datetime(&NaiveDateTime::from_timestamp_millis(value.exec_time.parse::<i64>().unwrap()).unwrap()).format("%Y-%m-%d %H:%M:%S%.3f").to_string();
|
|
|
- let order_type = value.order_type.clone();
|
|
|
- let income = (Decimal::from_str(&value.exec_price).unwrap() - Decimal::from_str(&value.order_price).unwrap()) * Decimal::from_str(&value.exec_qty).unwrap();
|
|
|
+ loop {
|
|
|
+ let res_data = request.get_user_trades(symbol_format.clone(), start_time, end_time, limit_params, cursor.clone()).await;
|
|
|
+ if res_data.code == 200 {
|
|
|
+ let data_clone = res_data.data.clone();
|
|
|
+ let trades_info: Vec<TradesSwap> = serde_json::from_str(&*data_clone["list"].to_string()).unwrap();
|
|
|
+ cursor = data_clone["nextPageCursor"].as_str().unwrap_or("").to_string();
|
|
|
+ for value in trades_info.iter() {
|
|
|
+ let time = FixedOffset::east_opt(8 * 3600).unwrap().from_utc_datetime(&NaiveDateTime::from_timestamp_millis(value.exec_time.parse::<i64>().unwrap()).unwrap()).format("%Y-%m-%d %H:%M:%S%.3f").to_string();
|
|
|
+ let order_type = value.order_type.clone();
|
|
|
|
|
|
- data_array.push(vec![
|
|
|
- value.exec_id.clone(),
|
|
|
- value.order_id.clone(),
|
|
|
- value.symbol.clone(),
|
|
|
- value.side.clone(),
|
|
|
- value.exec_price.clone(),
|
|
|
- value.exec_qty.clone(),
|
|
|
- order_type.to_string(),
|
|
|
- value.exec_value.clone(),
|
|
|
- value.exec_fee.clone(),
|
|
|
- value.fee_rate.clone(),
|
|
|
- income.to_string(),
|
|
|
- time,
|
|
|
- ]);
|
|
|
- }
|
|
|
+ data_array.push(vec![
|
|
|
+ value.exec_id.clone(),
|
|
|
+ value.order_id.clone(),
|
|
|
+ value.symbol.clone(),
|
|
|
+ value.side.clone(),
|
|
|
+ value.exec_price.clone(),
|
|
|
+ value.exec_qty.clone(),
|
|
|
+ order_type.to_string(),
|
|
|
+ value.exec_value.clone(),
|
|
|
+ value.exec_fee.clone(),
|
|
|
+ value.fee_rate.clone(),
|
|
|
+ time,
|
|
|
+ ]);
|
|
|
+ }
|
|
|
|
|
|
- if trades_info.len().to_i64().unwrap() < limit_params {
|
|
|
- break;
|
|
|
- }
|
|
|
+ if trades_info.len().to_i64().unwrap() < limit_params {
|
|
|
+ break;
|
|
|
}
|
|
|
}
|
|
|
+ }
|
|
|
+ data_array.reverse();
|
|
|
+ data_array
|
|
|
+}
|
|
|
|
|
|
- let header_array = vec!["交易编号", "订单编号", "交易币对", "买卖方向", "成交价格", "成交数量", "交易类型", "成交价值", "交易费用", "交易费率", "交易盈亏", "交易时间"];
|
|
|
- data_array.reverse();
|
|
|
- global::export_utils::export_excel(header_array, data_array, prefix_name)
|
|
|
+#[derive(Debug, Deserialize, Serialize)]
|
|
|
+#[serde(rename_all = "camelCase")]
|
|
|
+struct PositionPnlSwap {
|
|
|
+ symbol: String,
|
|
|
+ order_id: String,
|
|
|
+ side: String,
|
|
|
+ qty: String,
|
|
|
+ order_price: String,
|
|
|
+ order_type: String,
|
|
|
+ exec_type: String,
|
|
|
+ closed_size: String,
|
|
|
+ cum_entry_value: String,
|
|
|
+ avg_entry_price: String,
|
|
|
+ cum_exit_value: String,
|
|
|
+ avg_exit_price: String,
|
|
|
+ closed_pnl: String,
|
|
|
+ fill_count: String,
|
|
|
+ leverage: String,
|
|
|
+ created_time: String,
|
|
|
+ updated_time: String,
|
|
|
+}
|
|
|
+async fn get_position_pnl(mut request: BybitSwapRest, symbol: String, start_time: i64, end_time: i64, limit: i64) -> Vec<Vec<String>> {
|
|
|
+ let symbol_format = utils::format_symbol(symbol.clone(), "");
|
|
|
+ let limit_params = if limit > 100 {
|
|
|
+ warn!("查询条数最大为1000条,已修改为100条!");
|
|
|
+ 100
|
|
|
+ } else { limit };
|
|
|
+ let mut cursor = "".to_string();
|
|
|
+ let mut data_array = vec![];
|
|
|
+
|
|
|
+ loop {
|
|
|
+ let res_data = request.get_position_closed_pnl(symbol_format.clone(), start_time, end_time, limit_params, cursor.clone()).await;
|
|
|
+ if res_data.code == 200 {
|
|
|
+ let data_clone = res_data.data.clone();
|
|
|
+ let trades_info: Vec<PositionPnlSwap> = serde_json::from_str(&*data_clone["list"].to_string()).unwrap();
|
|
|
+ cursor = data_clone["nextPageCursor"].as_str().unwrap_or("").to_string();
|
|
|
+ for value in trades_info.iter() {
|
|
|
+ let create_time = FixedOffset::east_opt(8 * 3600).unwrap().from_utc_datetime(&NaiveDateTime::from_timestamp_millis(value.created_time.parse::<i64>().unwrap()).unwrap()).format("%Y-%m-%d %H:%M:%S%.3f").to_string();
|
|
|
+ let update_time = FixedOffset::east_opt(8 * 3600).unwrap().from_utc_datetime(&NaiveDateTime::from_timestamp_millis(value.updated_time.parse::<i64>().unwrap()).unwrap()).format("%Y-%m-%d %H:%M:%S%.3f").to_string();
|
|
|
+
|
|
|
+ data_array.push(vec![
|
|
|
+ value.order_id.clone(),
|
|
|
+ value.symbol.clone(),
|
|
|
+ value.side.clone(),
|
|
|
+ value.avg_entry_price.clone(),
|
|
|
+ value.avg_exit_price.clone(),
|
|
|
+ value.order_type.clone(),
|
|
|
+ value.closed_size.clone(),
|
|
|
+ value.closed_pnl.clone(),
|
|
|
+ create_time,
|
|
|
+ update_time,
|
|
|
+ ]);
|
|
|
+ }
|
|
|
+
|
|
|
+ if trades_info.len().to_i64().unwrap() < limit_params {
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|
|
|
+
|
|
|
+ data_array.reverse();
|
|
|
+ data_array
|
|
|
}
|