|
|
@@ -0,0 +1,135 @@
|
|
|
+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};
|
|
|
+use exchanges::bybit_swap_rest::BybitSwapRest;
|
|
|
+use standard::utils;
|
|
|
+use crate::ExportConnector;
|
|
|
+
|
|
|
+pub struct BybitSwapExport {
|
|
|
+ request: BybitSwapRest,
|
|
|
+}
|
|
|
+
|
|
|
+impl BybitSwapExport {
|
|
|
+ pub async fn new(is_colo: bool, params: BTreeMap<String, String>) -> BybitSwapExport {
|
|
|
+ BybitSwapExport {
|
|
|
+ request: BybitSwapRest::new(is_colo, params.clone())
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+/// TradesSwap
|
|
|
+/// - `symbol`: String,
|
|
|
+/// - `order_id`: String,
|
|
|
+/// - `order_link_id`: String,
|
|
|
+/// - `side`: String,
|
|
|
+/// - `order_price`: String,
|
|
|
+/// - `order_qty`: String,
|
|
|
+/// - `leaves_qty`: String,
|
|
|
+/// - `create_type`: String,
|
|
|
+/// - `order_type`: String,
|
|
|
+/// - `stop_order_type`: String,
|
|
|
+/// - `exec_fee`: String,
|
|
|
+/// - `exec_id`: String,
|
|
|
+/// - `exec_price`: String,
|
|
|
+/// - `exec_qty`: String,
|
|
|
+/// - `exec_type`: String,
|
|
|
+/// - `exec_value`: String,
|
|
|
+/// - `exec_time`: String,
|
|
|
+/// - `fee_currency`: String,
|
|
|
+/// - `is_maker`: bool,
|
|
|
+/// - `fee_rate`: String,
|
|
|
+/// - `trade_iv`: String,
|
|
|
+/// - `mark_iv`: String,
|
|
|
+/// - `mark_price`: String,
|
|
|
+/// - `index_price`: String,
|
|
|
+/// - `underlying_price`: String,
|
|
|
+/// - `block_trade_id`: String,
|
|
|
+/// - `closed_size`: String,
|
|
|
+/// - `seq`: i64,
|
|
|
+#[derive(Debug, Deserialize, Serialize)]
|
|
|
+#[serde(rename_all = "camelCase")]
|
|
|
+struct TradesSwap {
|
|
|
+ symbol: String,
|
|
|
+ order_id: String,
|
|
|
+ order_link_id: String,
|
|
|
+ side: String,
|
|
|
+ order_price: String,
|
|
|
+ order_qty: String,
|
|
|
+ leaves_qty: String,
|
|
|
+ create_type: String,
|
|
|
+ order_type: String,
|
|
|
+ stop_order_type: String,
|
|
|
+ exec_fee: String,
|
|
|
+ exec_id: String,
|
|
|
+ exec_price: String,
|
|
|
+ exec_qty: String,
|
|
|
+ exec_type: String,
|
|
|
+ exec_value: String,
|
|
|
+ exec_time: String,
|
|
|
+ fee_currency: String,
|
|
|
+ is_maker: bool,
|
|
|
+ fee_rate: String,
|
|
|
+ trade_iv: String,
|
|
|
+ mark_iv: String,
|
|
|
+ mark_price: String,
|
|
|
+ index_price: String,
|
|
|
+ underlying_price: String,
|
|
|
+ block_trade_id: String,
|
|
|
+ closed_size: String,
|
|
|
+ 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![];
|
|
|
+
|
|
|
+ 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();
|
|
|
+
|
|
|
+ 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,
|
|
|
+ ]);
|
|
|
+ }
|
|
|
+
|
|
|
+ if trades_info.len().to_i64().unwrap() < limit_params {
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ let header_array = vec!["交易编号", "订单编号", "交易币对", "买卖方向", "成交价格", "成交数量", "交易类型", "成交价值", "交易费用", "交易费率", "交易盈亏", "交易时间"];
|
|
|
+ data_array.reverse();
|
|
|
+ global::export_utils::export_excel(header_array, data_array, prefix_name)
|
|
|
+ }
|
|
|
+}
|