Browse Source

Merge branch 'dev' into test

skyfffire 1 year ago
parent
commit
bf7b4f7464

+ 2 - 2
derive/tests/gate_swap_export_test.rs

@@ -5,7 +5,7 @@ use derive::export_excel::ExportEnum;
 use crate::export_excel_test::test_new_export;
 
 
-const SYMBOL: &str = "LOOM_USDT";
+const SYMBOL: &str = "TIA_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::GateSwap).await;
-    let export_trades = export.export_trades("gate_swap", SYMBOL.to_string(), 0, 0, 100).await;
+    let export_trades = export.export_trades("gate_swap_42", SYMBOL.to_string(), 0, 0, 1000).await;
     trace!(?export_trades);
 }

+ 3 - 3
exchanges/src/okx_swap_rest.rs

@@ -99,7 +99,7 @@ impl OkxSwapRest {
         let data = self.request("GET".to_string(),
                                 "/api/v5".to_string(),
                                 "/public/time".to_string(),
-                                true,
+                                false,
                                 params.to_string(),
         ).await;
         data
@@ -127,7 +127,7 @@ impl OkxSwapRest {
         let data = self.request("GET".to_string(),
                                 "/api/v5".to_string(),
                                 "/market/ticker".to_string(),
-                                true,
+                                false,
                                 params.to_string(),
         ).await;
         data
@@ -153,7 +153,7 @@ impl OkxSwapRest {
         let data = self.request("GET".to_string(),
                                 "/api/v5".to_string(),
                                 "/public/instruments".to_string(),
-                                true,
+                                false,
                                 params.to_string(),
         ).await;
         data

+ 1 - 1
exchanges/tests/okx_swap_test.rs

@@ -298,7 +298,7 @@ async fn rest_get_ticker_test() {
     global::log_utils::init_log_with_trace();
 
     let mut ret = get_rest();
-    let req_data = ret.get_ticker("BTC-USD".to_string()).await;
+    let req_data = ret.get_ticker("BTC-USDT".to_string()).await;
     println!("okx--获取单个产品行情信息--{:?}", req_data);
 }
 

+ 1 - 1
standard/src/gate_swap.rs

@@ -551,7 +551,7 @@ impl Platform for GateSwap {
                                 result_sd.send(order).await.unwrap();
                             }
                             Err(_err) => {
-                                error!("撤单失败,而且查单也失败了,gate_io_swap,oid={}, cid={}。", order_id.clone(), custom_id.clone());
+                                // error!("撤单失败,而且查单也失败了,gate_io_swap,oid={}, cid={}。", order_id.clone(), custom_id.clone());
                                 // panic!("撤单失败,而且查单也失败了,gate_io_swap,oid={}, cid={}。", order_id.clone(), custom_id.clone());
                             }
                         }

+ 36 - 7
standard/src/okx_handle.rs

@@ -10,6 +10,29 @@ use crate::exchange::ExchangeEnum;
 use crate::handle_info::HandleSwapInfo;
 use crate::okx_swap::SwapPosition;
 
+
+#[derive(Debug, Clone, Deserialize, Serialize)]
+#[serde(rename_all = "camelCase")]
+pub struct SwapBalanceAndPositionSubscribe {
+    pos_data: Vec<SwapBalanceAndPositionPosDataSubscribe>,
+}
+
+#[derive(Debug, Clone, Deserialize, Serialize)]
+#[serde(rename_all = "camelCase")]
+pub struct SwapBalanceAndPositionPosDataSubscribe {
+    pos_id: String,
+    trade_id: String,
+    inst_id: String,
+    inst_type: String,
+    mgn_mode: String,
+    pos_side: String,
+    pos: Decimal,
+    ccy: String,
+    pos_ccy: String,
+    avg_px: Decimal,
+    u_time: String,
+}
+
 #[derive(Debug, Deserialize, Serialize)]
 #[serde(rename_all = "camelCase")]
 struct SwapPositionSubscribe {
@@ -141,15 +164,21 @@ pub fn format_special_ticker(data: serde_json::Value, label: String) -> SpecialD
     }
 }
 
+
 // 处理position信息
 pub fn handle_position(res_data: ResponseData, ct_val: Decimal) -> Vec<Position> {
     let res_data_str = res_data.data;
-    let data_list: SwapPositionSubscribe = serde_json::from_str(&res_data_str).unwrap();
-    let position_data = data_list.data;
-    position_data.iter().map(|item| format_position_item(item, ct_val)).collect()
+    let data_list: Vec<SwapBalanceAndPositionSubscribe> = serde_json::from_str(&res_data_str).unwrap();
+
+    let position_data = data_list[0].pos_data.clone();
+    if position_data.len() > 0 {
+        position_data.iter().map(|item| format_position_item(item, ct_val)).collect()
+    } else {
+        vec![]
+    }
 }
 
-pub fn format_position_item(value: &SwapPosition, ct_val: Decimal) -> Position {
+pub fn format_position_item(value: &SwapBalanceAndPositionPosDataSubscribe, ct_val: Decimal) -> Position {
     let position_mode = match value.pos_side.as_str() {
         "long" => { PositionModeEnum::Long }
         "short" => { PositionModeEnum::Short }
@@ -157,12 +186,12 @@ pub fn format_position_item(value: &SwapPosition, ct_val: Decimal) -> Position {
     };
     Position {
         symbol: value.inst_id.replace("-SWAP", ""),
-        margin_level: value.lever,
+        margin_level: Decimal::ZERO,
         amount: value.pos * ct_val,
         frozen_amount: Decimal::ZERO,
         price: value.avg_px,
-        profit: value.upl,
+        profit: Decimal::ZERO,
         position_mode,
-        margin: if value.margin != "" { Decimal::from_str(&value.margin).unwrap() } else { Decimal::ZERO },
+        margin: Decimal::ZERO,
     }
 }

+ 21 - 3
standard/src/okx_swap.rs

@@ -13,7 +13,7 @@ use tracing::{debug, error};
 use exchanges::okx_swap_rest::OkxSwapRest;
 use global::trace_stack::TraceStack;
 use crate::exchange::ExchangeEnum;
-use crate::{Account, Market, okx_handle, Order, OrderCommand, Platform, Position, Ticker, utils};
+use crate::{Account, Market, Order, OrderCommand, Platform, Position, PositionModeEnum, Ticker, utils};
 
 /// Okx交易所账户信息请求数据结构
 /// - 接口`"/api/v5/account/balance"`
@@ -567,7 +567,7 @@ impl Platform for OkxSwap {
             let res_data_str = &res_data.data;
             let data_list: Vec<SwapPosition> = serde_json::from_str(&res_data_str).unwrap();
             let position_info: Vec<&SwapPosition> = data_list.iter().filter(|item| item.inst_id == symbol_format).collect();
-            let result = position_info.iter().map(|item| okx_handle::format_position_item(item, ct_val)).collect();
+            let result = position_info.iter().map(|item| format_position_item(item, ct_val)).collect();
             Ok(result)
         } else {
             Err(Error::new(ErrorKind::Other, res_data.to_string()))
@@ -579,7 +579,7 @@ impl Platform for OkxSwap {
         if res_data.code == "200" {
             let res_data_str = &res_data.data;
             let data_list: Vec<SwapPosition> = serde_json::from_str(&res_data_str).unwrap();
-            let result = data_list.iter().map(|item| okx_handle::format_position_item(item, Decimal::ONE)).collect();
+            let result = data_list.iter().map(|item| format_position_item(item, Decimal::ONE)).collect();
             Ok(result)
         } else {
             Err(Error::new(ErrorKind::Other, res_data.to_string()))
@@ -1051,3 +1051,21 @@ pub fn format_order_item(data: SwapOrder, ct_val: Decimal) -> Order {
     debug!("format-order-end, okx_swap");
     result
 }
+
+pub fn format_position_item(value: &SwapPosition, ct_val: Decimal) -> Position {
+    let position_mode = match value.pos_side.as_str() {
+        "long" => { PositionModeEnum::Long }
+        "short" => { PositionModeEnum::Short }
+        _ => { PositionModeEnum::Both }
+    };
+    Position {
+        symbol: value.inst_id.replace("-SWAP", ""),
+        margin_level: value.lever,
+        amount: value.pos * ct_val,
+        frozen_amount: Decimal::ZERO,
+        price: value.avg_px,
+        profit: value.upl,
+        position_mode,
+        margin: if value.margin != "" { Decimal::from_str(&value.margin).unwrap() } else { Decimal::ZERO },
+    }
+}

+ 1 - 0
strategy/Cargo.toml

@@ -19,6 +19,7 @@ tracing-subscriber = "0.3.17"
 standard = { path = "../standard" }
 global = { path = "../global" }
 exchanges = { path = "../exchanges" }
+reqwest = { version = "0.11.14", features = ["json"] }
 
 futures-util = { version = "0.3.28", default-features = false, features = ["sink", "std"] }
 futures-channel = "0.3.28"

+ 8 - 1
strategy/src/exchange_disguise.rs

@@ -11,6 +11,7 @@ use crate::bitget_spot::bitget_spot_run;
 use crate::gate_swap::gate_swap_run;
 use crate::kucoin_spot::kucoin_spot_run;
 use crate::kucoin_swap::kucoin_swap_run;
+use crate::okx_usdt_swap::okex_swap_run;
 use crate::quant::Quant;
 
 // 交易交易所启动
@@ -28,8 +29,11 @@ pub async fn run_transactional_exchange(bool_v1 :Arc<AtomicBool>,
         "kucoin_usdt_swap" => {
             kucoin_swap_run(bool_v1, true, quant_arc, name, symbols, is_colo, exchange_params).await;
         },
+        "okex_usdt_swap" => {
+            okex_swap_run(bool_v1,true, quant_arc, name, symbols, is_colo, exchange_params).await;
+        },
         "bitget_spot" => {
-            bitget_spot_run(bool_v1,false, quant_arc, name, symbols, is_colo, exchange_params).await;
+            bitget_spot_run(bool_v1,true, quant_arc, name, symbols, is_colo, exchange_params).await;
         }
         _ => {
             let msg = format!("不支持的交易交易所:{}", exchange_name);
@@ -56,6 +60,9 @@ pub async fn run_reference_exchange(bool_v1: Arc<AtomicBool>,
         "gate_usdt_swap" => {
             gate_swap_run(bool_v1, false, quant_arc, name, symbols, is_colo, exchange_params).await;
         },
+        "okex_usdt_swap" => {
+            okex_swap_run(bool_v1, false, quant_arc, name, symbols, is_colo, exchange_params).await;
+        },
         "kucoin_usdt_swap" => {
             kucoin_swap_run(bool_v1, false, quant_arc, name, symbols, is_colo, exchange_params).await;
         },

+ 2 - 1
strategy/src/lib.rs

@@ -10,4 +10,5 @@ mod binance_spot;
 mod gate_swap;
 mod kucoin_swap;
 mod kucoin_spot;
-mod bitget_spot;
+mod bitget_spot;
+mod okx_usdt_swap;

+ 25 - 0
strategy/src/model.rs

@@ -107,6 +107,14 @@ pub struct OriginalTradeGa {
     pub price: Decimal
 }
 
+#[derive(Serialize, Deserialize)]
+pub struct OriginalTradeOK {
+    // 数量
+    pub sz: Decimal,
+    // 价格
+    pub px: Decimal
+}
+
 #[allow(non_snake_case)]
 #[derive(Serialize, Deserialize, Debug)]
 pub struct OriginalTicker {
@@ -122,3 +130,20 @@ pub struct OriginalTicker {
     pub A: Decimal
 }
 
+#[allow(non_snake_case)]
+#[derive(Serialize, Deserialize, Debug)]
+pub struct DealRecord {
+    // 参考价
+    pub refPrice: String,
+    // 挂单价
+    pub regPrice: String,
+    // 买单最优挂单数量
+    pub num: String,
+    // 触发时间
+    pub triggerTime: i64,
+    // 机器名称
+    pub robotName: String,
+    // 方向
+    pub side: String
+}
+

+ 208 - 0
strategy/src/okx_usdt_swap.rs

@@ -0,0 +1,208 @@
+use std::collections::BTreeMap;
+use std::sync::Arc;
+use std::sync::atomic::AtomicBool;
+use futures_util::StreamExt;
+use rust_decimal::Decimal;
+use tokio::sync::Mutex;
+use exchanges::okx_swap_ws::{OkxSwapLogin, OkxSwapSubscribeType, OkxSwapWs, OkxSwapWsType};
+use exchanges::response_base::ResponseData;
+use global::trace_stack::TraceStack;
+use standard::exchange::ExchangeEnum::OkxSwap;
+use crate::exchange_disguise::on_special_depth;
+use crate::model::{OrderInfo, OriginalTradeOK};
+use crate::quant::Quant;
+
+pub async fn okex_swap_run(bool_v1: Arc<AtomicBool>,
+                           is_trade: bool,
+                           _quant_arc: Arc<Mutex<Quant>>,
+                           name: String,
+                           symbols: Vec<String>,
+                           is_colo: bool,
+                           exchange_params: BTreeMap<String, String>) {
+    // 启动公共频道
+    let (write_tx_public, write_rx_public) = futures_channel::mpsc::unbounded();
+    let (read_tx_public, mut read_rx_public) = futures_channel::mpsc::unbounded();
+
+    let mut ws_public = OkxSwapWs::new_label(name.clone(), is_colo, None, OkxSwapWsType::Public);
+    ws_public.set_symbols(symbols.clone());
+    if is_trade {
+        ws_public.set_subscribe(vec![
+            OkxSwapSubscribeType::PuBooks5
+        ])
+    } else {
+        ws_public.set_subscribe(vec![
+            OkxSwapSubscribeType::PuBooks50L2tbt
+        ])
+    }
+    // 挂起公共ws
+    let write_tx_am_public = Arc::new(Mutex::new(write_tx_public));
+    let bool_clone_public = Arc::clone(&bool_v1);
+    tokio::spawn(async move {
+        ws_public.ws_connect_async(bool_clone_public,
+                                   &write_tx_am_public,
+                                   write_rx_public,
+                                   read_tx_public).await.expect("链接失败(内部一个心跳线程应该已经关闭了)");
+    });
+    // 消费数据
+    let bot_arc_clone = _quant_arc.clone();
+    // 接收public数据
+    tokio::spawn(async move {
+        // ticker
+        let mut update_flag_u = Decimal::ZERO;
+        let mut max_buy = Decimal::ZERO;
+        let mut min_sell = Decimal::ZERO;
+
+        loop {
+            if let Some(public_data) = read_rx_public.next().await {
+                on_public_data(bot_arc_clone.clone(),
+                               &mut update_flag_u,
+                               &mut max_buy,
+                               &mut min_sell,
+                               public_data).await;
+            }
+        }
+    });
+
+    // 交易交易所需要启动私有ws
+    if is_trade {
+        let (write_tx_private, write_rx_private) = futures_channel::mpsc::unbounded();
+        let (read_tx_private, mut read_rx_private) = futures_channel::mpsc::unbounded();
+        let auth = Some(parse_btree_map_to_okx_swap_login(exchange_params));
+
+        let mut ws_private = OkxSwapWs::new_label(name.clone(), is_colo, auth, OkxSwapWsType::Private);
+        ws_private.set_symbols(symbols.clone());
+        ws_private.set_subscribe(vec![
+            OkxSwapSubscribeType::PrBalanceAndPosition,
+            OkxSwapSubscribeType::PrAccount("USDT".to_string()),
+            OkxSwapSubscribeType::PrOrders
+        ]);
+
+
+        // 挂起私有ws
+        let write_tx_am_private = Arc::new(Mutex::new(write_tx_private));
+        let bool_clone_private = Arc::clone(&bool_v1);
+        tokio::spawn(async move {
+            ws_private.ws_connect_async(bool_clone_private,
+                                &write_tx_am_private,
+                                write_rx_private,
+                                read_tx_private).await.expect("链接失败(内部一个心跳线程应该已经关闭了)");
+        });
+
+        // 消费数据
+        let bot_arc_clone = _quant_arc.clone();
+        // 接收private信息
+        tokio::spawn(async move {
+            let ct_val = _quant_arc.clone().lock().await.platform_rest.get_self_market().ct_val;
+            let run_symbol = symbols.clone()[0].clone();
+            loop {
+                if let Some(private_data) = read_rx_private.next().await {
+                    on_private_data(bot_arc_clone.clone(),
+                                    ct_val,
+                                    private_data,
+                                    run_symbol.clone()).await;
+                }
+            }
+        });
+    }
+}
+
+async fn on_private_data(bot_arc_clone: Arc<Mutex<Quant>>, ct_val: Decimal, data: ResponseData, run_symbol: String) {
+    let mut trace_stack = TraceStack::default();
+
+    trace_stack.on_after_network(data.time);
+    trace_stack.on_before_quant();
+
+    if data.code != "200".to_string() {
+        return;
+    }
+    if data.channel == "orders" {
+        trace_stack.on_before_format();
+        let orders = standard::handle_info::HandleSwapInfo::handle_order(OkxSwap, data.clone(), ct_val);
+        trace_stack.on_after_format();
+        let mut order_infos:Vec<OrderInfo> = Vec::new();
+        for order in orders.order {
+            if order.status == "NULL" {
+                continue;
+            }
+            let order_info = OrderInfo {
+                symbol: "".to_string(),
+                amount: order.amount.abs(),
+                side: "".to_string(),
+                price: order.price,
+                client_id: order.custom_id,
+                filled_price: order.avg_price,
+                filled: order.deal_amount.abs(),
+                order_id: order.id,
+                local_time: 0,
+                create_time: 0,
+                status: order.status,
+                fee: Default::default(),
+                trace_stack: Default::default(),
+            };
+            order_infos.push(order_info);
+        }
+        {
+            let mut quant = bot_arc_clone.lock().await;
+            quant.update_order(order_infos, trace_stack);
+        }
+    } else if data.channel == "balance_and_position" {
+        let positions = standard::handle_info::HandleSwapInfo::handle_position(OkxSwap,data, ct_val);
+        {
+            let mut quant = bot_arc_clone.lock().await;
+            quant.update_position(positions);
+        }
+    } else if data.channel == "account" {
+        let account = standard::handle_info::HandleSwapInfo::handle_account_info(OkxSwap, data.clone(), run_symbol.clone());
+        {
+            let mut quant = bot_arc_clone.lock().await;
+            quant.update_equity(account);
+        }
+    }
+}
+
+async fn on_public_data(bot_arc_clone: Arc<Mutex<Quant>>, update_flag_u: &mut Decimal, max_buy: &mut Decimal, min_sell: &mut Decimal, data: ResponseData) {
+    let mut trace_stack = TraceStack::default();
+    trace_stack.on_after_network(data.time);
+    trace_stack.on_before_quant();
+
+    if data.code != "200".to_string() {
+        return;
+    }
+    if data.channel == "tickers" {
+        trace_stack.on_before_format();
+        let special_depth = standard::handle_info::HandleSwapInfo::handle_special_depth(OkxSwap, data.clone());
+        trace_stack.on_after_format();
+        on_special_depth(bot_arc_clone, update_flag_u, data.label, trace_stack, special_depth).await;
+    } else if data.channel == "trades" {
+        let mut quant = bot_arc_clone.lock().await;
+        let str = data.label.clone();
+        if quant.is_update.contains_key(&data.label) && *quant.is_update.get(str.as_str()).unwrap(){
+            *max_buy = Decimal::ZERO;
+            *min_sell = Decimal::ZERO;
+            quant.is_update.remove(str.as_str());
+        }
+        let trades: Vec<OriginalTradeOK> = serde_json::from_str(data.data.as_str()).unwrap();
+        for trade in trades {
+            if trade.px > *max_buy || *max_buy == Decimal::ZERO{
+                *max_buy = trade.px
+            }
+            if trade.px < *min_sell || *min_sell == Decimal::ZERO{
+                *min_sell = trade.px
+            }
+        }
+        quant.max_buy_min_sell_cache.insert(data.label, vec![*max_buy, *min_sell]);
+    } else if data.channel == "books5" {
+        trace_stack.on_before_format();
+        let special_depth = standard::handle_info::HandleSwapInfo::handle_special_depth(OkxSwap, data.clone());
+        trace_stack.on_after_format();
+        on_special_depth(bot_arc_clone, update_flag_u, data.label, trace_stack, special_depth).await;
+    }
+}
+
+fn parse_btree_map_to_okx_swap_login(exchange_params: BTreeMap<String, String>) -> OkxSwapLogin {
+    OkxSwapLogin {
+        api_key: exchange_params.get("access_key").unwrap().clone(),
+        secret_key: exchange_params.get("secret_key").unwrap().clone(),
+        passphrase: exchange_params.get("pass_key").unwrap().clone(),
+    }
+}

+ 5 - 2
strategy/src/quant.rs

@@ -20,7 +20,7 @@ use global::public_params::{ASK_PRICE_INDEX, BID_PRICE_INDEX, LENGTH};
 use global::trace_stack::TraceStack;
 use standard::{Account, Market, Order, OrderCommand, Platform, Position, PositionModeEnum, SpecialTicker, Ticker};
 use standard::exchange::{Exchange};
-use standard::exchange::ExchangeEnum::{BinanceSpot, BinanceSwap, BitgetSpot, GateSpot, GateSwap, KucoinSwap};
+use standard::exchange::ExchangeEnum::{BinanceSpot, BinanceSwap, BitgetSpot, GateSpot, GateSwap, KucoinSwap, OkxSwap};
 
 use crate::model::{LocalPosition, OrderInfo, TokenParam, TraderMsg};
 use crate::predictor::Predictor;
@@ -151,7 +151,7 @@ impl Quant {
             exit_msg: "正常退出".to_string(),
             position_check_series: Default::default(),
             stop_loss: params.stop_loss,
-            used_pct: params.used_pct,
+            used_pct: dec!(0.95),
             mode_signal: 0,
             trade_order_update_time: Utc::now().timestamp_millis(),
             on_tick_event_time: Utc::now().timestamp_millis(),
@@ -207,6 +207,9 @@ impl Quant {
                 "bitget_spot" => {
                     Exchange::new(BitgetSpot, symbol, params.colo != 0i8, exchange_params, order_sender, error_sender).await
                 }
+                "okex_usdt_swap" => {
+                    Exchange::new(OkxSwap, symbol, params.colo != 0i8, exchange_params, order_sender, error_sender).await
+                }
                 _ => {
                     error!("203未找到对应的交易所rest枚举!");
                     panic!("203未找到对应的交易所rest枚举!");

+ 66 - 2
strategy/src/strategy.rs

@@ -1,15 +1,18 @@
 use std::cmp::{max, min};
 use std::collections::HashMap;
 use std::ops::{Div, Mul};
+use std::str::FromStr;
 use chrono::Utc;
 use rust_decimal::Decimal;
 use rust_decimal::prelude::{FromPrimitive, ToPrimitive};
 use rust_decimal_macros::dec;
-use crate::model::{LocalPosition, OrderInfo, TraderMsg};
+use crate::model::{DealRecord, LocalPosition, OrderInfo, TraderMsg};
 use crate::utils;
 use tracing::{info, error, warn, instrument};
+use reqwest::{Client};
+use tokio::spawn;
 use global::params::Params;
-use standard::OrderCommand;
+use standard::{OrderCommand};
 
 #[derive(Debug)]
 pub struct Strategy {
@@ -1222,10 +1225,71 @@ impl Strategy {
         self._refresh_request_limit();                      // 刷新频率限制
         self._update_request_num(&mut command);             // 统计刷新频率
 
+
+        if command.limits_open.len() > 0 || command.limits_close.len() > 0{
+            let time = chrono::Utc::now().timestamp_millis();
+            let name = self.params.account_name.clone();
+            // 参考卖价
+            let ref_ap = self.ref_ap;
+            // 参考买价
+            let ref_bp = self.ref_bp;
+            let limits_open = command.limits_open.clone();
+            let limits_close = command.limits_close.clone();
+            spawn(async move {
+                let param_list = paras_limit_command(name.clone(), time.clone(), ref_ap.clone(), ref_bp.clone(), limits_open, limits_close);
+                let param_json_obj = serde_json::to_string(&param_list).unwrap();
+                market_warehouse_request(param_json_obj).await;
+            });
+        }
+
+
         return command;
     }
 }
 
+async fn market_warehouse_request(body_params: String) {
+    /****请求接口与 地址*/
+    let url = "http://as.skyfffire.com:8848/basic/saveDealRecords";
+
+    let client = Client::new();
+    let req = client.post(url).header("auth", "43626546liangjiang")
+        .header("Content-Type", "application/json").body(body_params.clone());
+
+    req.send().await.unwrap();
+    // if !response.status().is_success()  {
+    //     error!("行情数据------仓库挂单数据存储失败--------!{}", response.status());
+    //     error!(body_params);
+    // }
+}
+
+fn paras_limit_command (robot_name: String, time: i64, ref_ap: Decimal, ref_bp: Decimal, limits_open: HashMap<String, Vec<String>>, limits_close: HashMap<String, Vec<String>>) -> Vec<DealRecord>{
+    let mut limits = HashMap::new();
+    limits.extend(limits_open);
+    limits.extend(limits_close);
+    let mut list: Vec<DealRecord> = Vec::with_capacity(limits.len());
+    for item in limits.keys() {
+        let item_clone = item.clone();
+        let value = limits[&item_clone].clone();
+        let amount = Decimal::from_str(value.get(0).unwrap_or(&"0".to_string())).unwrap();
+        let side = value.get(1).unwrap();
+        let price = Decimal::from_str(value.get(2).unwrap_or(&"0".to_string())).unwrap();
+        let mut ref_price = ref_ap;
+        if "kd" == side {
+            ref_price = ref_bp;
+        }
+        let deal_recode = DealRecord {
+            refPrice: ref_price.to_string(),
+            regPrice: price.to_string(),
+            num: amount.to_string(),
+            triggerTime: time,
+            robotName: robot_name.clone(),
+            side: side.to_string(),
+        };
+        list.push(deal_recode);
+    }
+    return list;
+}
+
 #[cfg(test)]
 mod tests {
     use rust_decimal::Decimal;

+ 5 - 1
strategy/src/utils.rs

@@ -61,6 +61,8 @@ pub fn get_limit_requests_num_per_second(exchange: String) -> i64 {
         return public_params::COINEX_USDT_SWAP_LIMIT * public_params::RATIO;
     } else if exchange.eq("coinex_spot") {
         return public_params::COINEX_SPOT_LIMIT * public_params::RATIO;
+    } else if exchange.eq("okex_usdt_swap") {
+        return public_params::OKEX_USDT_SWAP_LIMIT * public_params::RATIO;
     } else if exchange.eq("bitget_spot") {
         return public_params::BITGET_USDT_SPOT_LIMIT * public_params::RATIO;
     } else {
@@ -87,6 +89,8 @@ pub fn get_limit_order_requests_num_per_second(exchange: String) -> i64 {
         return public_params::COINEX_USDT_SWAP_LIMIT
     } else if exchange.eq("coinex_spot") {
         return public_params::COINEX_SPOT_LIMIT
+    } else if exchange.eq("okex_usdt_swap") {
+        return public_params::OKEX_USDT_SWAP_LIMIT
     } else if exchange.eq("bitget_spot") {
         return public_params::BITGET_USDT_SPOT_LIMIT
     } else {
@@ -144,6 +148,6 @@ mod tests {
         println!("timestamp: {}", now.timestamp());
         println!("timestamp_millis: {}", now.timestamp_millis());
         println!("timestamp_micros: {}", now.timestamp_micros());
-        println!("timestamp_nanos: {}", now.timestamp_nanos());
+        println!("timestamp_nanos: {}", now.timestamp_nanos_opt().unwrap());
     }
 }