Browse Source

基本传递结构。

skyffire 1 năm trước cách đây
mục cha
commit
f6759b3134

+ 31 - 5
global/src/cci.rs

@@ -1,11 +1,37 @@
 use rust_decimal::Decimal;
 use serde_derive::Serialize;
+use crate::fixed_time_range_deque::FixedTimeRangeDeque;
+
+#[derive(Serialize, Clone)]
+pub struct PredictorState {
+    pub update_time: Decimal,
+
+
+}
 
 #[derive(Serialize, Clone)]
 pub struct CentralControlInfo {
-    pub now_balance: Decimal,                   // 钱包余额
-    pub unrealized_pn_l: Decimal,               // 未实现盈亏
-    pub pos: Decimal,                           // 持仓数量
-    pub entry_price: Decimal,                   // 开仓价格
-    pub now_price: Decimal,                     // 当前价格
+    pub now_balance: Decimal,                                       // 钱包余额
+    pub unrealized_pn_l: Decimal,                                   // 未实现盈亏
+    pub pos: Decimal,                                               // 持仓数量
+    pub entry_price: Decimal,                                       // 开仓价格
+    pub now_price: Decimal,                                         // 当前价格
+
+    pub predictor_state_vec: FixedTimeRangeDeque<PredictorState>,   // 模型状态
+}
+
+impl CentralControlInfo {
+    // 时间窗口大小(微秒)
+    const MAX_TIME_RANGE_MICROS: i64 = 60_000_000_000;
+
+    pub fn new() -> Self {
+        Self {
+            now_balance: Default::default(),
+            unrealized_pn_l: Default::default(),
+            pos: Default::default(),
+            entry_price: Default::default(),
+            now_price: Default::default(),
+            predictor_state_vec: FixedTimeRangeDeque::new(Self::MAX_TIME_RANGE_MICROS),
+        }
+    }
 }

+ 42 - 0
global/src/fixed_time_range_deque.rs

@@ -0,0 +1,42 @@
+use std::collections::VecDeque;
+use chrono::Utc;
+use serde_derive::{Deserialize, Serialize};
+
+// 定制的队列,可以统一指定长度
+#[derive(Debug, Clone, Serialize, Deserialize)]
+pub struct FixedTimeRangeDeque<T> {
+    pub deque: VecDeque<T>,
+    pub deque_t: VecDeque<i64>,
+    pub time_range: i64,
+}
+
+impl<T> FixedTimeRangeDeque<T> {
+    pub fn new(range: i64) -> Self {
+        FixedTimeRangeDeque {
+            deque: VecDeque::new(),
+            deque_t: VecDeque::new(),
+            time_range: range
+        }
+    }
+
+    pub fn push_back(&mut self, value: T) {
+        let now = Utc::now().timestamp_micros();
+
+        self.deque.push_back(value);
+        self.deque_t.push_back(now);
+
+        // =================== 检查长度,如果超过时间窗口,则移除前端元素 ==================
+        while self.deque_t.len() > 0 && now - self.deque_t.get(0).unwrap() > self.time_range {
+            self.deque.pop_front();
+            self.deque_t.pop_front();
+        }
+    }
+
+    pub fn len(&self) -> usize {
+        self.deque.len()
+    }
+
+    pub fn get(&self, index: usize) -> Option<&T> {
+        self.deque.get(index)
+    }
+}

+ 1 - 0
global/src/lib.rs

@@ -8,3 +8,4 @@ pub mod cci;
 pub mod clear_position_result;
 pub mod trade;
 pub mod clear_log_utils;
+pub mod fixed_time_range_deque;

+ 1 - 7
src/main.rs

@@ -144,13 +144,7 @@ async fn main() {
     }));
 
     // 中央控制器信息
-    let cci = CentralControlInfo {
-        now_balance: Default::default(),
-        unrealized_pn_l: Default::default(),
-        pos: Default::default(),
-        entry_price: Default::default(),
-        now_price: Default::default(),
-    };
+    let cci = CentralControlInfo::new();
     let cci_arc = Arc::new(Mutex::new(cci));
 
     // ws退出程序

+ 2 - 7
src/server.rs

@@ -33,13 +33,7 @@ async fn on_change(arcs: web::Data<Arcs>) -> impl Responder {
 
 pub fn run_cci_cache(cci_arc: Arc<Mutex<CentralControlInfo>>) -> Arc<Mutex<CentralControlInfo>> {
     // cci缓存,防止中控因等待时间过长杀死rust
-    let cci_cache = CentralControlInfo {
-        now_balance: Default::default(),
-        unrealized_pn_l: Default::default(),
-        pos: Default::default(),
-        entry_price: Default::default(),
-        now_price: Default::default(),
-    };
+    let cci_cache = CentralControlInfo::new();
     let cci_cache_arc = Arc::new(Mutex::new(cci_cache));
     let cci_cache_arc_clone = cci_cache_arc.clone();
     tokio::spawn(async move {
@@ -54,6 +48,7 @@ pub fn run_cci_cache(cci_arc: Arc<Mutex<CentralControlInfo>>) -> Arc<Mutex<Centr
                 cci_cache.unrealized_pn_l = cci.unrealized_pn_l;
                 cci_cache.now_balance = cci.now_balance;
                 cci_cache.entry_price = cci.entry_price;
+                cci_cache.predictor_state_vec = cci.predictor_state_vec.clone();
             }
         }
     });

+ 20 - 96
strategy/src/predictor.rs → strategy/src/avellaneda_stoikov.rs

@@ -1,62 +1,14 @@
-use std::collections::{BTreeMap, VecDeque};
-use chrono::Utc;
+use std::collections::{BTreeMap};
 use rust_decimal::prelude::*;
 use tracing::info;
+use global::fixed_time_range_deque::FixedTimeRangeDeque;
 use standard::{Depth, Ticker, Trade};
 
-// 定制的队列,可以统一指定长度
-#[derive(Debug)]
-pub struct FixedLengthDeque<T> {
-    pub deque: VecDeque<T>,
-    pub deque_t: VecDeque<i64>
-}
-
-impl<T> FixedLengthDeque<T> {
-    // 时间窗口大小(微秒)
-    const MAX_TIME_RANGE_MICROS: i64 = 10_000_000_000;
-
-    fn new() -> Self {
-        FixedLengthDeque {
-            deque: VecDeque::new(),
-            deque_t: VecDeque::new()
-        }
-    }
-
-    pub fn push_back(&mut self, value: T) {
-        let now = Utc::now().timestamp_micros();
-
-        self.deque.push_back(value);
-        self.deque_t.push_back(now);
-
-        // =================== 检查长度,如果超过时间窗口,则移除前端元素 ==================
-        while self.deque_t.len() > 0 && now - self.deque_t.get(0).unwrap() > Self::MAX_TIME_RANGE_MICROS {
-            self.deque.pop_front();
-            self.deque_t.pop_front();
-        }
-    }
-
-    pub fn len(&self) -> usize {
-        self.deque.len()
-    }
-
-    pub fn get(&self, index: usize) -> Option<&T> {
-        self.deque.get(index)
-    }
-}
-
 #[derive(Debug)]
 pub struct AvellanedaStoikov {
-    pub depth_vec: FixedLengthDeque<Depth>,                                     // 深度队列
-    pub trade_vec: FixedLengthDeque<Trade>,                                     // 交易队列
-
-    pub mid_price_vec: FixedLengthDeque<Decimal>,
-    pub ask_price_vec: FixedLengthDeque<Decimal>,
-    pub bid_price_vec: FixedLengthDeque<Decimal>,
-    pub spread_vec: FixedLengthDeque<Decimal>,
-    pub spread_max_vec: FixedLengthDeque<Decimal>,
-    pub spread_min_vec: FixedLengthDeque<Decimal>,
-    pub optimal_ask_price_vec: FixedLengthDeque<Decimal>,
-    pub optimal_bid_price_vec: FixedLengthDeque<Decimal>,
+    pub depth_vec: FixedTimeRangeDeque<Depth>,                                  // 深度队列
+    pub trade_vec: FixedTimeRangeDeque<Trade>,                                  // 交易队列
+    pub spread_vec: FixedTimeRangeDeque<Decimal>,
 
     pub mid_price: Decimal,                                                     // 中间价
     pub ask_price: Decimal,                                                     // 卖一价
@@ -64,15 +16,8 @@ pub struct AvellanedaStoikov {
     pub spread: Decimal,                                                        // 市场冲击
     pub spread_max: Decimal,                                                    // 最大市场冲击
     pub spread_min: Decimal,                                                    // 最小市场冲击
-    pub optimal_ask_price: Decimal,                                             // 卖出价挂单
-    pub optimal_bid_price: Decimal,                                             // 买入价挂单
-
-    pub inventory_vec: FixedLengthDeque<Decimal>,
-    pub sigma_square_vec: FixedLengthDeque<Decimal>,
-    pub gamma_vec: FixedLengthDeque<Decimal>,
-    pub kappa_vec: FixedLengthDeque<Decimal>,
-    pub delta_plus_vec: FixedLengthDeque<Decimal>,
-    pub ref_price_vec: FixedLengthDeque<Decimal>,
+    pub optimal_ask_price: Decimal,                                             // 卖出挂单价
+    pub optimal_bid_price: Decimal,                                             // 买入挂单价
 
     pub inventory: Decimal,                                                     // 库存,也就是q
     pub sigma_square: Decimal,                                                  // σ^2,波动性的平方
@@ -82,26 +27,17 @@ pub struct AvellanedaStoikov {
     pub ref_price: Decimal,                                                     // 预定价格
 }
 
-/*
-    使用Builder设计模式创建价格预测器,可以有效提高代码整洁度
-    下面的单元测试有使用示例
-*/
 impl AvellanedaStoikov {
+    // 时间窗口大小(微秒)
+    const MAX_TIME_RANGE_MICROS: i64 = 10_000_000_000;
+    
     pub fn new() -> Self {
         let avellaneda_stoikov = Self {
             // 分别给与的长度
-            depth_vec: FixedLengthDeque::new(),
-            trade_vec: FixedLengthDeque::new(),
-            
-            mid_price_vec: FixedLengthDeque::new(),
-            ask_price_vec: FixedLengthDeque::new(),
-            bid_price_vec: FixedLengthDeque::new(),
-            spread_vec: FixedLengthDeque::new(),
-            spread_max_vec: FixedLengthDeque::new(),
-            spread_min_vec: FixedLengthDeque::new(),
-            optimal_ask_price_vec: FixedLengthDeque::new(),
-            optimal_bid_price_vec: FixedLengthDeque::new(),
-            
+            depth_vec: FixedTimeRangeDeque::new(Self::MAX_TIME_RANGE_MICROS),
+            trade_vec: FixedTimeRangeDeque::new(Self::MAX_TIME_RANGE_MICROS),
+            spread_vec: FixedTimeRangeDeque::new(Self::MAX_TIME_RANGE_MICROS),
+
             mid_price: Default::default(),
             ask_price: Default::default(),
             bid_price: Default::default(),
@@ -111,13 +47,6 @@ impl AvellanedaStoikov {
             optimal_ask_price: Default::default(),
             optimal_bid_price: Default::default(),
 
-            inventory_vec: FixedLengthDeque::new(),
-            gamma_vec: FixedLengthDeque::new(),
-            sigma_square_vec: FixedLengthDeque::new(),
-            delta_plus_vec: FixedLengthDeque::new(),
-            kappa_vec: FixedLengthDeque::new(),
-            ref_price_vec: FixedLengthDeque::new(),
-
             inventory: Default::default(),
             gamma: Default::default(),
             sigma_square: Default::default(),
@@ -136,7 +65,6 @@ impl AvellanedaStoikov {
         } else {
             Decimal::NEGATIVE_ONE
         };
-        self.spread_max_vec.push_back(self.spread_max);
     }
 
     // 更新最小市场冲击
@@ -146,7 +74,6 @@ impl AvellanedaStoikov {
         } else {
             Decimal::NEGATIVE_ONE
         };
-        self.spread_min_vec.push_back(self.spread_min);
     }
 
     pub fn update_spread(&mut self, mid_price_now: &Decimal) {
@@ -164,15 +91,12 @@ impl AvellanedaStoikov {
         self.depth_vec.push_back(depth.clone());
 
         self.ask_price = depth.asks[0].price;
-        self.ask_price_vec.push_back(self.ask_price);
 
         self.bid_price = depth.bids[0].price;
-        self.bid_price_vec.push_back(self.bid_price);
 
         let mid_price_now = (self.ask_price + self.bid_price) / Decimal::TWO;
         self.update_spread(&mid_price_now);
         self.mid_price = mid_price_now;
-        self.mid_price_vec.push_back(self.mid_price);
 
         self.processor();
     }
@@ -184,7 +108,6 @@ impl AvellanedaStoikov {
 
     pub fn update_inventory(&mut self, inventory: Decimal) {
         self.inventory = inventory;
-        self.inventory_vec.push_back(inventory);
 
         self.processor();
     }
@@ -216,7 +139,6 @@ impl AvellanedaStoikov {
         };
 
         self.sigma_square.rescale(10);
-        self.sigma_square_vec.push_back(self.sigma_square);
     }
 
     pub fn update_gamma(&mut self) {
@@ -228,7 +150,6 @@ impl AvellanedaStoikov {
             IRA * (self.spread_max - self.spread_min) / (Decimal::TWO * self.inventory.abs() * self.sigma_square)
         };
         self.gamma.rescale(8);
-        self.gamma_vec.push_back(self.gamma);
     }
 
     pub fn update_kappa(&mut self) {
@@ -239,12 +160,10 @@ impl AvellanedaStoikov {
             self.gamma / (temp.exp() - Decimal::ONE)
         };
         self.kappa.rescale(8);
-        self.kappa_vec.push_back(self.kappa);
     }
 
     pub fn update_ref_price(&mut self) {
         self.ref_price = self.mid_price - self.inventory * self.gamma * self.sigma_square;
-        self.ref_price_vec.push_back(self.ref_price);
     }
 
     pub fn update_delta_plus(&mut self) {
@@ -256,7 +175,11 @@ impl AvellanedaStoikov {
             left_value + right_value
         };
         self.delta_plus.rescale(8);
-        self.delta_plus_vec.push_back(self.delta_plus);
+    }
+
+    pub fn update_optimal_ask_and_bid(&mut self) {
+        self.optimal_ask_price = self.ref_price + self.delta_plus / Decimal::TWO;
+        self.optimal_bid_price = self.ref_price - self.delta_plus / Decimal::TWO;
     }
 
     // #[instrument(skip(self), level="TRACE")]
@@ -271,6 +194,7 @@ impl AvellanedaStoikov {
         info!(?self.ref_price);
         self.update_delta_plus();
         info!(?self.delta_plus);
+        self.update_optimal_ask_and_bid();
         info!(?self.spread_max, ?self.mid_price, ?self.ref_price, ?self.inventory);
     }
 

+ 6 - 6
strategy/src/clear_core.rs

@@ -21,7 +21,7 @@ use standard::exchange::{Exchange};
 use standard::exchange::ExchangeEnum::{BinanceSwap, GateSwap};
 
 use crate::model::{LocalPosition, OrderInfo};
-use crate::predictor::AvellanedaStoikov;
+use crate::avellaneda_stoikov::AvellanedaStoikov;
 use crate::strategy::Strategy;
 use crate::utils;
 use crate::utils::clip;
@@ -307,14 +307,14 @@ impl ClearCore {
 
         // 更新中控持仓相关的信息
         {
-            let mut pos = self.local_position_by_orders.long_pos - self.local_position_by_orders.short_pos;
+            let mut inventory = self.local_position_by_orders.long_pos - self.local_position_by_orders.short_pos;
             if !self.exchange.contains("spot") {
-                pos = self.local_position.long_pos - self.local_position.short_pos;
+                inventory = self.local_position.long_pos - self.local_position.short_pos;
             }
-            pos.rescale(8);
+            inventory.rescale(8);
 
             let mut entry_price;
-            if pos.gt(&Decimal::ZERO) {
+            if inventory.gt(&Decimal::ZERO) {
                 entry_price = self.local_position_by_orders.long_avg;
             } else {
                 entry_price = self.local_position_by_orders.short_avg;
@@ -322,7 +322,7 @@ impl ClearCore {
             entry_price.rescale(8);
 
             let mut cci = self.cci_arc.lock().await;
-            cci.pos = pos;
+            cci.pos = inventory;
             cci.entry_price = entry_price;
         }
     }

+ 18 - 21
strategy/src/core.rs

@@ -24,7 +24,7 @@ use standard::exchange::{Exchange};
 use standard::exchange::ExchangeEnum::{BinanceSwap, GateSwap};
 
 use crate::model::{LocalPosition, OrderInfo, TokenParam};
-use crate::predictor::AvellanedaStoikov;
+use crate::avellaneda_stoikov::AvellanedaStoikov;
 use crate::strategy::Strategy;
 use crate::utils;
 use crate::utils::clip;
@@ -677,7 +677,7 @@ impl Core {
             }
         }
 
-        // 同步更新余额数据到中控的信息
+        // 同步更新核心数据到中控数据显示和策略层
         {
             let mut unrealized_pn_l = self.local_profit;
             unrealized_pn_l.rescale(4);
@@ -713,27 +713,24 @@ impl Core {
             self.local_position = position;
         }
 
-        // 更新中控持仓相关的信息
-        {
-            let mut pos = self.local_position_by_orders.long_pos - self.local_position_by_orders.short_pos;
-            if !self.exchange.contains("spot") {
-                pos = self.local_position.long_pos - self.local_position.short_pos;
-            }
-            pos.rescale(8);
-
-            let mut entry_price;
-            if pos.gt(&Decimal::ZERO) {
-                entry_price = self.local_position_by_orders.long_avg;
-            } else {
-                entry_price = self.local_position_by_orders.short_avg;
-            }
-            entry_price.rescale(8);
+        // 持仓相关信息
+        let mut pos = self.local_position_by_orders.long_pos - self.local_position_by_orders.short_pos;
+        if !self.exchange.contains("spot") {
+            pos = self.local_position.long_pos - self.local_position.short_pos;
+        }
+        pos.rescale(8);
+        self.avellaneda_stoikov.update_inventory(pos);
 
-            self.avellaneda_stoikov.update_inventory(pos);
-            let mut cci = self.cci_arc.lock().await;
-            cci.pos = pos;
-            cci.entry_price = entry_price;
+        let mut entry_price;
+        if pos.gt(&Decimal::ZERO) {
+            entry_price = self.local_position_by_orders.long_avg;
+        } else {
+            entry_price = self.local_position_by_orders.short_avg;
         }
+        entry_price.rescale(8);
+        let mut cci = self.cci_arc.lock().await;
+        cci.pos = pos;
+        cci.entry_price = entry_price;
     }
 
     // #[instrument(skip(self), level="TRACE")]

+ 1 - 1
strategy/src/lib.rs

@@ -1,7 +1,7 @@
 pub mod core;
 pub mod model;
 mod strategy;
-mod predictor;
+mod avellaneda_stoikov;
 mod utils;
 pub mod exchange_disguise;
 mod binance_usdt_swap;