Browse Source

添加导出成交记录

gepangpang 1 năm trước cách đây
mục cha
commit
59a1187b22

+ 73 - 0
derive/src/bitget_spot_export.rs

@@ -0,0 +1,73 @@
+use std::collections::BTreeMap;
+use std::str::FromStr;
+use async_trait::async_trait;
+use chrono::{FixedOffset, NaiveDateTime, TimeZone};
+use rust_decimal::Decimal;
+use serde::{Deserialize, Serialize};
+use exchanges::bitget_spot_rest::BitgetSpotRest;
+use standard::utils;
+use crate::ExportConnector;
+
+pub struct BitgetSpotExport {
+    request: BitgetSpotRest,
+}
+
+impl BitgetSpotExport {
+    pub async fn new(is_colo: bool, params: BTreeMap<String, String>) -> BitgetSpotExport {
+        BitgetSpotExport {
+            request: BitgetSpotRest::new(is_colo, params.clone())
+        }
+    }
+}
+
+/// TradesSwap
+/// - `symbol`: String, 交易对名称
+/// - `trade_id`: String, 成交单ID
+/// - `side`: String, 交易方向
+/// - `price`: String, 成交价格
+/// - `size`: String, 成交数量
+/// - `ts`: String, 成交时间
+#[derive(Debug, Deserialize, Serialize)]
+#[serde(rename_all = "camelCase")]
+struct TradesSpot {
+    symbol: String,
+    trade_id: String,
+    side: String,
+    price: String,
+    size: String,
+    ts: String,
+}
+
+#[async_trait]
+impl ExportConnector for BitgetSpotExport {
+    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, "");
+        let start_at = if start_time > 0 { start_time.to_string() } else { "".to_string() };
+        let end_at = if end_time > 0 { end_time.to_string() } else { "".to_string() };
+        let res_data = self.request.get_market_fills_history(symbol_format, start_at.to_string(), end_at.to_string(), limit.to_string()).await;
+        if res_data.code == "200" {
+            let trades_info: Vec<TradesSpot> = serde_json::from_str(&res_data.data).unwrap();
+            let header_array = vec!["交易编号", "交易币对", "买卖方向", "订单价格", "订单数量", "成交额", "创建时间"];
+            let mut data_array: Vec<Vec<String>> = Vec::new();
+            for (index, value) in trades_info.iter().enumerate() {
+                if index >= data_array.len() {
+                    data_array.push(Vec::new());
+                }
+                let created_at = FixedOffset::east_opt(8 * 3600).unwrap().from_utc_datetime(&NaiveDateTime::from_timestamp_millis(value.ts.parse::<i64>().unwrap()).unwrap()).format("%Y-%m-%d %T").to_string();
+                let trade_value = Decimal::from_str(&value.price).unwrap() * Decimal::from_str(&value.size).unwrap();
+                data_array[index] = vec![
+                    value.trade_id.clone(),
+                    value.symbol.clone(),
+                    value.side.clone(),
+                    value.price.clone(),
+                    value.size.clone(),
+                    trade_value.to_string(),
+                    created_at,
+                ];
+            }
+            global::export_utils::export_excel(header_array, data_array, prefix_name)
+        } else {
+            res_data.to_string()
+        }
+    }
+}

+ 20 - 0
derive/src/export_excel.rs

@@ -1,12 +1,20 @@
 use std::collections::BTreeMap;
 use crate::binance_swap_export::BinanceSwapExport;
+use crate::bitget_spot_export::BitgetSpotExport;
 use crate::ExportConnector;
+use crate::gate_swap_export::GateSwapExport;
+use crate::kucoin_spot_export::KucoinSpotExport;
 use crate::kucoin_swap_export::KucoinSwapExport;
+use crate::okx_swap_export::OkxSwapExport;
 
 #[derive(Debug, Clone, PartialEq, Eq)]
 pub enum ExportEnum {
     BinanceSwap,
     KucoinSwap,
+    KucoinSpot,
+    GateSwap,
+    BitgetSpot,
+    OkxSwap,
 }
 
 #[derive(Debug, Clone)]
@@ -21,6 +29,18 @@ impl ExportExcel {
             ExportEnum::KucoinSwap => {
                 Box::new(KucoinSwapExport::new(is_colo, params).await)
             }
+            ExportEnum::KucoinSpot => {
+                Box::new(KucoinSpotExport::new(is_colo, params).await)
+            }
+            ExportEnum::GateSwap => {
+                Box::new(GateSwapExport::new(is_colo, params).await)
+            }
+            ExportEnum::BitgetSpot => {
+                Box::new(BitgetSpotExport::new(is_colo, params).await)
+            }
+            ExportEnum::OkxSwap => {
+                Box::new(OkxSwapExport::new(is_colo, params).await)
+            }
         }
     }
 }

+ 88 - 0
derive/src/gate_swap_export.rs

@@ -0,0 +1,88 @@
+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::{FromPrimitive, ToPrimitive};
+use rust_decimal_macros::dec;
+use serde::{Deserialize, Serialize};
+use exchanges::gate_swap_rest::GateSwapRest;
+use standard::utils;
+use crate::ExportConnector;
+
+pub struct GateSwapExport {
+    request: GateSwapRest,
+}
+
+impl GateSwapExport {
+    pub async fn new(is_colo: bool, params: BTreeMap<String, String>) -> GateSwapExport {
+        GateSwapExport {
+            request: GateSwapRest::new(is_colo, params.clone())
+        }
+    }
+}
+
+/// TradesSwap
+/// - `id`: i64, 成交记录 ID
+/// - `create_time`: i64, 成交时间
+/// - `contract`: String, 合约标识
+/// - `order_id`: String, 成交记录关联订单 ID
+/// - `size`: i64, 成交数量
+/// - `price`: String, 成交价格
+/// - `text`: String, 成交角色, taker - 吃单, maker - 做单
+/// - `fee`: String, 订单的自定义信息
+/// - `point_fee`: String, 成交手续费
+/// - `role`: String, 成交点卡手续费
+#[derive(Debug, Deserialize, Serialize)]
+struct TradesSwap {
+    id: i64,
+    create_time: f64,
+    contract: String,
+    order_id: String,
+    size: i64,
+    price: String,
+    text: String,
+    fee: String,
+    point_fee: String,
+    role: String,
+}
+
+#[async_trait]
+impl ExportConnector for GateSwapExport {
+    async fn export_trades(&mut self, prefix_name: &str, symbol: String, _start_time: i64, _end_time: i64, _limit: i64) -> String {
+        let symbol_array: Vec<&str> = symbol.split("_").collect();
+        let _symbol_format = utils::format_symbol(symbol.clone(), "_");
+        let res_data = self.request.my_trades(symbol_array[1].to_lowercase()).await;
+        if res_data.code == "200" {
+            let trades_info: Vec<TradesSwap> = serde_json::from_str(&res_data.data).unwrap();
+            let header_array = vec!["交易编号", "订单编号", "交易币对", "买卖方向", "成交价格", "成交数量", "成交价值", "交易费用", "成交角色", "成交时间"];
+            let mut data_array: Vec<Vec<String>> = Vec::new();
+
+            for (index, value) in trades_info.iter().enumerate() {
+                if index >= data_array.len() {
+                    data_array.push(Vec::new());
+                }
+                let size = Decimal::from_i64(value.size).unwrap();
+                let side = if size < Decimal::ZERO { "sell" } else { "buy" };
+                let created_time = Decimal::from_f64(value.create_time).unwrap() * dec!(1000);
+                let created_at = FixedOffset::east_opt(8 * 3600).unwrap().from_utc_datetime(&NaiveDateTime::from_timestamp_millis(created_time.to_i64().unwrap()).unwrap()).format("%Y-%m-%d %T").to_string();
+                let trade_value = Decimal::from_str(&value.price).unwrap() * size.abs();
+                data_array[index] = vec![
+                    value.id.to_string(),
+                    value.order_id.clone(),
+                    value.contract.clone(),
+                    side.to_string(),
+                    value.price.clone(),
+                    size.abs().to_string(),
+                    trade_value.to_string(),
+                    value.fee.clone(),
+                    value.role.clone(),
+                    created_at,
+                ];
+            }
+            global::export_utils::export_excel(header_array, data_array, prefix_name)
+        } else {
+            res_data.to_string()
+        }
+    }
+}

+ 99 - 0
derive/src/kucoin_spot_export.rs

@@ -0,0 +1,99 @@
+use std::collections::BTreeMap;
+use async_trait::async_trait;
+use chrono::{FixedOffset, NaiveDateTime, TimeZone};
+use serde::{Deserialize, Serialize};
+use exchanges::kucoin_spot_rest::KucoinSpotRest;
+use standard::exchange::ExchangeEnum;
+use standard::utils;
+use crate::ExportConnector;
+
+pub struct KucoinSpotExport {
+    request: KucoinSpotRest,
+}
+
+impl KucoinSpotExport {
+    pub async fn new(is_colo: bool, params: BTreeMap<String, String>) -> KucoinSpotExport {
+        KucoinSpotExport {
+            request: KucoinSpotRest::new(is_colo, params.clone())
+        }
+    }
+}
+
+/// TradesSwap
+/// - `symbol`: String, 合約編號
+/// - `trade_id`: String, 交易編號
+/// - `order_id`: String, 訂單編號
+/// - `counter_order_id`: String, 對手方訂單Id
+/// - `side`: String, 買賣方向
+/// - `liquidity`: String,流動性類型 taker or maker
+/// - `force_taker`: bool, 是否強製作爲taker處理
+/// - `price`: String, 成交價格
+/// - `size`: i64, 成交數量
+/// - `funds`: String, 成交額
+/// - `fee`: String, 交易費用
+/// - `fee_currency`: String, 收費幣種
+/// - `stop`: String, 止損單類型標記
+/// - `fee_rate`: String, 費率
+/// - `order_type`: String, 訂單類型
+/// - `created_at`: i64, 創建時間
+/// - `trade_type`: String, 交易類型: trade, liquidation, ADL or settlement
+#[derive(Debug, Deserialize, Serialize)]
+#[serde(rename_all = "camelCase")]
+struct TradesSpot {
+    symbol: String,
+    trade_id: String,
+    order_id: String,
+    counter_order_id: String,
+    side: String,
+    liquidity: String,
+    force_taker: bool,
+    price: String,
+    size: i64,
+    funds: String,
+    fee: String,
+    fee_rate: String,
+    fee_currency: String,
+    stop: String,
+    #[serde(rename = "type")]
+    order_type: String,
+    created_at: i64,
+    trade_type: String,
+}
+
+#[async_trait]
+impl ExportConnector for KucoinSpotExport {
+    async fn export_trades(&mut self, prefix_name: &str, symbol: String, start_time: i64, end_time: i64, limit: i64) -> String {
+        let symbol_mapper = utils::symbol_enter_mapper(ExchangeEnum::KucoinSwap, symbol.as_str());
+        let symbol_format = format!("{}M", utils::format_symbol(symbol_mapper.clone(), ""));
+        let res_data = self.request.get_fills(symbol_format, "".to_string(), "".to_string(), start_time, end_time, limit).await;
+        if res_data.code == "200" {
+            let res_data_json: serde_json::Value = serde_json::from_str(&res_data.data).unwrap();
+            let trades_info: Vec<TradesSpot> = serde_json::from_str(&res_data_json["items"].to_string()).unwrap();
+            let header_array = vec!["交易编号", "订单编号", "交易币对", "买卖方向", "订单价格", "订单数量", "成交额", "手续费", "手续费率", "订单类型", "创建时间"];
+            let mut data_array: Vec<Vec<String>> = Vec::new();
+            for (index, value) in trades_info.iter().enumerate() {
+                if index >= data_array.len() {
+                    data_array.push(Vec::new());
+                }
+                let created_at = FixedOffset::east_opt(8 * 3600).unwrap().from_utc_datetime(&NaiveDateTime::from_timestamp_millis(value.created_at.clone()).unwrap()).format("%Y-%m-%d %T").to_string();
+
+                data_array[index] = vec![
+                    value.trade_id.clone(),
+                    value.order_id.clone(),
+                    value.symbol.clone(),
+                    value.side.clone(),
+                    value.price.clone(),
+                    value.size.to_string(),
+                    value.funds.clone(),
+                    value.fee.clone(),
+                    value.fee_rate.clone(),
+                    value.order_type.clone(),
+                    created_at,
+                ];
+            }
+            global::export_utils::export_excel(header_array, data_array, prefix_name)
+        } else {
+            res_data.to_string()
+        }
+    }
+}

+ 5 - 1
derive/src/lib.rs

@@ -1,8 +1,12 @@
 use async_trait::async_trait;
 
-pub mod binance_swap_export;
+mod binance_swap_export;
 pub mod export_excel;
 mod kucoin_swap_export;
+mod kucoin_spot_export;
+mod gate_swap_export;
+mod bitget_spot_export;
+mod okx_swap_export;
 
 #[async_trait]
 pub trait ExportConnector {

+ 111 - 0
derive/src/okx_swap_export.rs

@@ -0,0 +1,111 @@
+use std::collections::BTreeMap;
+use std::str::FromStr;
+use async_trait::async_trait;
+use chrono::{FixedOffset, NaiveDateTime, TimeZone};
+use rust_decimal::Decimal;
+use serde::{Deserialize, Serialize};
+use exchanges::okx_swap_rest::OkxSwapRest;
+use standard::utils;
+use crate::ExportConnector;
+
+pub struct OkxSwapExport {
+    request: OkxSwapRest,
+}
+
+impl OkxSwapExport {
+    pub async fn new(is_colo: bool, params: BTreeMap<String, String>) -> OkxSwapExport {
+        OkxSwapExport {
+            request: OkxSwapRest::new(is_colo, params.clone())
+        }
+    }
+}
+
+/// TradesSwap
+/// - `inst_type`: String,
+/// - `inst_id`: String,
+/// - `trade_id`: String,
+/// - `ord_id`: String,
+/// - `cl_ord_id`: String,
+/// - `bill_id`: String,
+/// - `tag`: String,
+/// - `fill_px`: String,
+/// - `fill_sz`: String,
+/// - `fill_idx_px`: String,
+/// - `fill_pnl`: String,
+/// - `fill_px_vol`: String,
+/// - `fill_px_usd`: String,
+/// - `fill_mark_vol`: String,
+/// - `fill_fwd_px`: String,
+/// - `fill_mark_px`: String,
+/// - `side`: String,
+/// - `pos_side`: String,
+/// - `exec_type`: String,
+/// - `fee_ccy`: String,
+/// - `fee`: String,
+/// - `ts`: String,
+/// - `fill_time`: String,
+#[derive(Debug, Deserialize, Serialize)]
+#[serde(rename_all = "camelCase")]
+struct TradesSwap {
+    inst_type: String,
+    inst_id: String,
+    trade_id: String,
+    ord_id: String,
+    cl_ord_id: String,
+    bill_id: String,
+    tag: String,
+    fill_px: String,
+    fill_sz: String,
+    fill_idx_px: String,
+    fill_pnl: String,
+    fill_px_vol: String,
+    fill_px_usd: String,
+    fill_mark_vol: String,
+    fill_fwd_px: String,
+    fill_mark_px: String,
+    side: String,
+    pos_side: String,
+    exec_type: String,
+    fee_ccy: String,
+    fee: String,
+    ts: String,
+    fill_time: String,
+}
+
+#[async_trait]
+impl ExportConnector for OkxSwapExport {
+    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 res_data = self.request.get_trade_fills("".to_string()).await;
+        if res_data.code == "200" {
+            let trades_info: Vec<TradesSwap> = serde_json::from_str(&res_data.data).unwrap();
+            let header_array = vec!["交易编号", "订单编号", "交易币对", "买卖方向", "成交价格", "成交数量", "成交价值", "交易费用", "创建时间", "成交时间"];
+            let mut data_array: Vec<Vec<String>> = Vec::new();
+
+            for (index, value) in trades_info.iter().enumerate() {
+                if index >= data_array.len() {
+                    data_array.push(Vec::new());
+                }
+
+                let created_at = FixedOffset::east_opt(8 * 3600).unwrap().from_utc_datetime(&NaiveDateTime::from_timestamp_millis(value.ts.parse::<i64>().unwrap()).unwrap()).format("%Y-%m-%d %T").to_string();
+                let trade_time = FixedOffset::east_opt(8 * 3600).unwrap().from_utc_datetime(&NaiveDateTime::from_timestamp_millis(value.fill_time.parse::<i64>().unwrap()).unwrap()).format("%Y-%m-%d %T").to_string();
+                let trade_value = Decimal::from_str(&value.fill_px).unwrap() * Decimal::from_str(&value.fill_sz).unwrap();
+                data_array[index] = vec![
+                    value.trade_id.clone(),
+                    value.ord_id.clone(),
+                    value.inst_id.clone(),
+                    value.side.clone(),
+                    value.fill_px.clone(),
+                    value.fill_sz.clone(),
+                    trade_value.to_string(),
+                    value.fee.clone(),
+                    created_at,
+                    trade_time,
+                ];
+            }
+            global::export_utils::export_excel(header_array, data_array, prefix_name)
+        } else {
+            res_data.to_string()
+        }
+    }
+}

+ 1 - 1
derive/tests/binance_swap_export_test.rs

@@ -14,6 +14,6 @@ async fn test_get_self_exchange() {
     global::log_utils::init_log_with_trace();
 
     let mut export = test_new_export(ExportEnum::BinanceSwap).await;
-    let export_trades = export.export_trades("binance_swap","".to_string(), 0, 0, 50).await;
+    let export_trades = export.export_trades("binance_swap",SYMBOL.to_string(), 0, 0, 50).await;
     trace!(?export_trades);
 }

+ 18 - 0
derive/tests/bitget_spot_export_test.rs

@@ -0,0 +1,18 @@
+mod export_excel_test;
+
+use tracing::{instrument, trace};
+use derive::export_excel::ExportEnum;
+use crate::export_excel_test::test_new_export;
+
+
+const SYMBOL: &str = "LOOM_USDT";
+// 测试获取Exchange实体
+#[tokio::test]
+#[instrument(level = "TRACE")]
+async fn test_get_self_exchange() {
+    global::log_utils::init_log_with_trace();
+
+    let mut export = test_new_export(ExportEnum::BitgetSpot).await;
+    let export_trades = export.export_trades("bitget_spot",SYMBOL.to_string(), 0, 0, 100).await;
+    trace!(?export_trades);
+}

+ 38 - 0
derive/tests/export_excel_test.rs

@@ -35,5 +35,43 @@ pub async fn test_new_export(export_enum: ExportEnum) -> Box<dyn ExportConnector
             params.insert("pass_key".to_string(), pass_key);
             ExportExcel::new(ExportEnum::KucoinSwap, false, params).await
         }
+        ExportEnum::KucoinSpot => {
+            let mut params: BTreeMap<String, String> = BTreeMap::new();
+            let access_key = account_info.kucoin_access_key;
+            let secret_key = account_info.kucoin_secret_key;
+            let pass_key = account_info.kucoin_pass;
+            params.insert("access_key".to_string(), access_key);
+            params.insert("secret_key".to_string(), secret_key);
+            params.insert("pass_key".to_string(), pass_key);
+            ExportExcel::new(ExportEnum::KucoinSpot, false, params).await
+        }
+        ExportEnum::GateSwap => {
+            let mut params: BTreeMap<String, String> = BTreeMap::new();
+            let access_key = account_info.gate_access_key;
+            let secret_key = account_info.gate_secret_key;
+            params.insert("access_key".to_string(), access_key);
+            params.insert("secret_key".to_string(), secret_key);
+            ExportExcel::new(ExportEnum::GateSwap, false, params).await
+        }
+        ExportEnum::BitgetSpot => {
+            let mut params: BTreeMap<String, String> = BTreeMap::new();
+            let access_key = account_info.bitget_access_key;
+            let secret_key = account_info.bitget_secret_key;
+            let pass_key = account_info.bitget_pass;
+            params.insert("access_key".to_string(), access_key);
+            params.insert("secret_key".to_string(), secret_key);
+            params.insert("pass_key".to_string(), pass_key);
+            ExportExcel::new(ExportEnum::BitgetSpot, false, params).await
+        }
+        ExportEnum::OkxSwap => {
+            let mut params: BTreeMap<String, String> = BTreeMap::new();
+            let access_key = account_info.okx_access_key;
+            let secret_key = account_info.okx_secret_key;
+            let pass_key = account_info.okx_pass;
+            params.insert("access_key".to_string(), access_key);
+            params.insert("secret_key".to_string(), secret_key);
+            params.insert("pass_key".to_string(), pass_key);
+            ExportExcel::new(ExportEnum::OkxSwap, false, params).await
+        }
     }
 }

+ 19 - 0
derive/tests/gate_swap_export_test.rs

@@ -0,0 +1,19 @@
+mod export_excel_test;
+
+use tracing::{instrument, trace};
+use derive::export_excel::ExportEnum;
+use crate::export_excel_test::test_new_export;
+
+
+const SYMBOL: &str = "LOOM_USDT";
+
+// 测试获取Exchange实体
+#[tokio::test]
+#[instrument(level = "TRACE")]
+async fn test_get_self_exchange() {
+    global::log_utils::init_log_with_trace();
+
+    let mut export = test_new_export(ExportEnum::GateSwap).await;
+    let export_trades = export.export_trades("gate_swap", SYMBOL.to_string(), 0, 0, 100).await;
+    trace!(?export_trades);
+}

+ 18 - 0
derive/tests/kucoin_spot_export_test.rs

@@ -0,0 +1,18 @@
+mod export_excel_test;
+
+use tracing::{instrument, trace};
+use derive::export_excel::ExportEnum;
+use crate::export_excel_test::test_new_export;
+
+
+const SYMBOL: &str = "LOOM_USDT";
+// 测试获取Exchange实体
+#[tokio::test]
+#[instrument(level = "TRACE")]
+async fn test_get_self_exchange() {
+    global::log_utils::init_log_with_trace();
+
+    let mut export = test_new_export(ExportEnum::KucoinSpot).await;
+    let export_trades = export.export_trades("kucoin_spot",SYMBOL.to_string(), 0, 0, 100).await;
+    trace!(?export_trades);
+}

+ 18 - 0
derive/tests/okx_swap_export_test.rs

@@ -0,0 +1,18 @@
+mod export_excel_test;
+
+use tracing::{instrument, trace};
+use derive::export_excel::ExportEnum;
+use crate::export_excel_test::test_new_export;
+
+
+const SYMBOL: &str = "LOOM_USDT";
+// 测试获取Exchange实体
+#[tokio::test]
+#[instrument(level = "TRACE")]
+async fn test_get_self_exchange() {
+    global::log_utils::init_log_with_trace();
+
+    let mut export = test_new_export(ExportEnum::OkxSwap).await;
+    let export_trades = export.export_trades("okx_swap",SYMBOL.to_string(), 0, 0, 100).await;
+    trace!(?export_trades);
+}