Bladeren bron

添加bitget数据导出

gepangpang 11 maanden geleden
bovenliggende
commit
72525ffe83

+ 84 - 0
derive/src/bitget_swap_export.rs

@@ -0,0 +1,84 @@
+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_json::Value::Null;
+use tracing::{warn};
+use exchanges::bitget_swap_rest::BitgetSwapRest;
+use standard::utils;
+use crate::ExportConnector;
+
+pub struct BitgetSwapExport {
+    request: BitgetSwapRest,
+}
+
+impl BitgetSwapExport {
+    pub async fn new(is_colo: bool, params: BTreeMap<String, String>) -> BitgetSwapExport {
+        BitgetSwapExport {
+            request: BitgetSwapRest::new(is_colo, params.clone())
+        }
+    }
+}
+
+#[async_trait]
+impl ExportConnector for BitgetSwapExport {
+    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 > 100 {
+            warn!("查询条数最大为100条,已修改为100条!");
+            100
+        } else { limit };
+        let mut last_id = "".to_string();
+        let mut data_array = vec![];
+        loop {
+            let res_data = self.request.get_histories(symbol_format.clone(), 100, last_id.clone()).await;
+            if res_data.code == 200 {
+                if res_data.data["endId"] == Null { break; }
+                last_id = res_data.data["endId"].as_str().unwrap().to_string();
+                let trades_info = res_data.data["fillList"].as_array().unwrap();
+                for value in trades_info.iter() {
+                    let id = value["tradeId"].as_str().unwrap();
+                    let order_id = value["orderId"].as_str().unwrap();
+                    let symbol = value["symbol"].as_str().unwrap();
+                    let side = value["side"].as_str().unwrap();
+                    let price = value["price"].as_str().unwrap();
+                    let size = Decimal::from_str(value["baseVolume"].as_str().unwrap()).unwrap();
+                    let created_time = Decimal::from_str(value["cTime"].as_str().unwrap()).unwrap();
+                    let trade_value = Decimal::from_str(price).unwrap() * size.abs();
+                    let fee = value["feeDetail"][0]["totalFee"].as_str().unwrap();
+                    let profit = value["profit"].as_str().unwrap();
+                    let role = value["tradeScope"].as_str().unwrap();
+                    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 %H:%M:%S%.3f").to_string();
+
+                    data_array.push(vec![
+                        id.to_string(),
+                        order_id.to_string(),
+                        symbol.to_string(),
+                        side.to_string(),
+                        price.to_string(),
+                        size.abs().to_string(),
+                        trade_value.to_string(),
+                        fee.to_string(),
+                        profit.to_string(),
+                        role.to_string(),
+                        created_at,
+                    ]);
+                }
+
+                let last_time = (trades_info.last().unwrap()["cTime"].as_str().unwrap().parse::<i64>().unwrap() * 1000).to_i64().unwrap();
+                if last_time < start_time {
+                    data_array = data_array.iter().filter(|item| {
+                        NaiveDateTime::parse_from_str(item.last().unwrap(), "%Y-%m-%d %H:%M:%S%.3f")
+                            .unwrap()
+                            .timestamp_millis() > start_time
+                    }).cloned().collect();
+                    break;
+                }
+            }
+        }
+        let header_array = vec!["交易编号", "订单编号", "交易币对", "买卖方向", "成交价格", "成交数量", "成交价值", "交易费用", "利润", "成交角色", "成交时间"];
+        global::export_utils::export_excel(header_array, data_array, prefix_name)
+    }
+}

+ 0 - 0
derive/src/bitget_swap_rest.rs


+ 0 - 0
derive/src/bitget_swap_ws.rs


+ 5 - 0
derive/src/export_excel.rs

@@ -1,6 +1,7 @@
 use std::collections::BTreeMap;
 use crate::binance_swap_export::BinanceSwapExport;
 use crate::bybit_swap_export::BybitSwapExport;
+use crate::bitget_swap_export::BitgetSwapExport;
 // use crate::bitget_spot_export::BitgetSpotExport;
 use crate::ExportConnector;
 use crate::gate_swap_export::GateSwapExport;
@@ -15,6 +16,7 @@ pub enum ExportEnum {
     // KucoinSpot,
     GateSwap,
     BybitSwap,
+    BitgetSwap,
     // BitgetSpot,
     // OkxSwap,
 }
@@ -40,6 +42,9 @@ impl ExportExcel {
             ExportEnum::BybitSwap => {
                 Box::new(BybitSwapExport::new(is_colo, params).await)
             }
+            ExportEnum::BitgetSwap => {
+                Box::new(BitgetSwapExport::new(is_colo, params).await)
+            }
             // ExportEnum::BitgetSpot => {
             //     Box::new(BitgetSpotExport::new(is_colo, params).await)
             // }

+ 1 - 0
derive/src/lib.rs

@@ -8,6 +8,7 @@ mod gate_swap_export;
 mod bitget_spot_export;
 mod okx_swap_export;
 mod bybit_swap_export;
+mod bitget_swap_export;
 
 #[async_trait]
 pub trait ExportConnector {

+ 19 - 0
derive/tests/bitget_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 = "sushi_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::BitgetSwap).await;
+    let export_trades = export.export_trades("bitget_swap_42", SYMBOL.to_string(), 1733720400000, 1733796040000, 100).await;
+    trace!(?export_trades);
+}

+ 2 - 2
derive/tests/bybit_swap_export_test.rs

@@ -5,7 +5,7 @@ use derive::export_excel::ExportEnum;
 use crate::export_excel_test::test_new_export;
 
 
-const SYMBOL: &str = "1000PEPE_USDT";
+const SYMBOL: &str = "MEMEFI_USDT";
 
 // 测试获取Exchange实体
 #[tokio::test]
@@ -14,6 +14,6 @@ async fn test_get_self_exchange() {
     global::log_utils::init_log_with_trace();
 
     let mut export = test_new_export(ExportEnum::BybitSwap).await;
-    let export_trades = export.export_trades("bybit_swap", SYMBOL.to_string(), 1726131600000, 1726192800000, 100).await;
+    let export_trades = export.export_trades("bybit_swap_01", SYMBOL.to_string(), 1732605480000, 1732672800000, 100).await;
     trace!(?export_trades);
 }

+ 10 - 0
derive/tests/export_excel_test.rs

@@ -61,6 +61,16 @@ pub async fn test_new_export(export_enum: ExportEnum) -> Box<dyn ExportConnector
             params.insert("secret_key".to_string(), secret_key);
             ExportExcel::new(ExportEnum::BybitSwap, false, params).await
         }
+        ExportEnum::BitgetSwap => {
+            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::BitgetSwap, false, params).await
+        }
         // ExportEnum::BitgetSpot => {
         //     let mut params: BTreeMap<String, String> = BTreeMap::new();
         //     let access_key = account_info.bitget_access_key;

+ 20 - 4
exchanges/src/bitget_swap_rest.rs

@@ -8,7 +8,7 @@ use crate::http_tool::RestTool;
 use crate::response_base::ResponseData;
 use ring::hmac;
 use rust_decimal::prelude::FromPrimitive;
-use serde_json::Value;
+use serde_json::{json, Value};
 
 #[derive(Clone, Debug)]
 pub struct BitgetSwapRest {
@@ -23,7 +23,7 @@ pub struct BitgetSwapRest {
 
 impl BitgetSwapRest {
     pub fn new(is_colo: bool, login_param: BTreeMap<String, String>) -> BitgetSwapRest {
-        return BitgetSwapRest::new_label("default-BitgetSwapRest".to_string(), is_colo, login_param)
+        return BitgetSwapRest::new_label("default-BitgetSwapRest".to_string(), is_colo, login_param);
     }
 
     // 构造Bitget,可以自定义label
@@ -106,6 +106,22 @@ impl BitgetSwapRest {
         ).await
     }
 
+    // 获取历史成交记录
+    pub async fn get_histories(&mut self, symbol: String, limit: i64, last_id: String) -> ResponseData {
+        let mut params = json!({
+            "productType": "USDT-FUTURES",
+            "idLessThan": last_id,
+            "limit": limit
+         });
+        if symbol != "" { params["symbol"] = json!(symbol); }
+        self.request("GET".to_string(),
+                     "/api/v2".to_string(),
+                     "/mix/order/fill-history".to_string(),
+                     true,
+                     params.to_string(),
+        ).await
+    }
+
     // 获取仓位信息(单个)
     pub async fn get_single_position(&mut self, params: Value) -> ResponseData {
         self.request("GET".to_string(),
@@ -382,8 +398,8 @@ impl BitgetSwapRest {
 
     // 对请求进行签名处理
     pub fn sign(secret_key: String,
-            method: String, prefix_url: String, request_url: String,
-            params: String, body: String, timestamp: String) -> String {
+                method: String, prefix_url: String, request_url: String,
+                params: String, body: String, timestamp: String) -> String {
         let url_param_str = RestTool::parse_params_to_str(params);
         let base_url = if method == "GET" && url_param_str.len() > 0 {
             format!("{}{}?{}", prefix_url, request_url, url_param_str)

+ 1 - 0
standard/src/bitget_swap.rs

@@ -481,6 +481,7 @@ impl Platform for BitgetSwap {
             _ => { panic!("bitget_usdt_swap 下单参数错误"); }
         };
 
+        info!("{:?}" ,params.to_string());
         let res_data = self.request.swap_order(params).await;
         if res_data.code != 200 {
             return Err(Error::new(ErrorKind::Other, res_data.to_string()));

+ 7 - 3
tests/framework_3_0_test.rs

@@ -5,10 +5,14 @@ use std::sync::Arc;
 use tokio::sync::Mutex;
 use tracing::info;
 use global::log_utils::init_log_with_info;
+// {"clientOid": "1453351218bitget", "force": "gtc", "marginCoin": "USDT", "marginMode": "crossed", "orderType": "limit","price": "0.61810", "productType": "USDT-FUTURES", "reduceOnly": "NO", "side": "sell", "size": "17","symbol": "MOODENGUSDT"}
+// {"clientOid": "1439414436bitget", "force": "gtc", "marginCoin": "USDT", "marginMode": "crossed", "orderType": "limit","price": "0.61253", "productType": "USDT-FUTURES", "reduceOnly": "NO", "side": "buy", "size": "17","symbol": "MOODENGUSDT"}
+
+
 
 
 struct Core {
-    pub max_delay: u128
+    pub max_delay: u128,
 }
 
 #[tokio::test]
@@ -34,7 +38,7 @@ async fn framework_3_0() {
 async fn generator<F, Fut>(handle_function: F)
 where
     F: Fn(ResponseData) -> Fut,
-    Fut: Future<Output = ()> + Send + 'static, // 确保 Fut 是一个 Future,且输出类型为 ()
+    Fut: Future<Output=()> + Send + 'static, // 确保 Fut 是一个 Future,且输出类型为 ()
 {
     let data = ResponseData::new("aaa".to_string(),
                                  "code".to_string(),
@@ -53,7 +57,7 @@ where
 }
 
 struct TestHandler {
-    pub core_am: Arc<Mutex<Core>>
+    pub core_am: Arc<Mutex<Core>>,
 }
 
 impl TestHandler {