Kaynağa Gözat

新版資金流計算方案,分離資金流計算算法,使用資金流的多周期共振進行實驗。

skyfffire 1 yıl önce
ebeveyn
işleme
4501da571c
1 değiştirilmiş dosya ile 91 ekleme ve 98 silme
  1. 91 98
      strategy/src/avellaneda_stoikov.rs

+ 91 - 98
strategy/src/avellaneda_stoikov.rs

@@ -14,10 +14,9 @@ use standard::{Depth, Ticker, Trade};
 #[derive(Debug)]
 pub struct AvellanedaStoikov {
     pub depth_vec: FixedTimeRangeDeque<Depth>,                                  // 深度队列
-    pub trade_vec: FixedTimeRangeDeque<Trade>,                                  // 交易队列
+    pub trade_long_vec: FixedTimeRangeDeque<Trade>,                             // 交易队列
+    pub trade_short_vec: FixedTimeRangeDeque<Trade>,                            // 交易队列
     pub spread_vec: FixedTimeRangeDeque<Decimal>,
-    pub flow_ratio_short_vec: FixedTimeRangeDeque<Decimal>,                     // 資金流歷史記錄
-    pub flow_ratio_long_vec: FixedTimeRangeDeque<Decimal>,                      // 資金流歷史記錄
 
     pub mid_price: Decimal,                                                     // 中间价
     pub ask_price: Decimal,                                                     // 卖一价
@@ -35,11 +34,8 @@ pub struct AvellanedaStoikov {
     pub gamma: Decimal,                                                         // γ,库存风险厌恶参数
     pub kappa: Decimal,                                                         // κ 订单簿 流动性 参数
 
-    pub flow_in_value: Decimal,
-    pub flow_out_value: Decimal,
-    pub flow_ratio: Decimal,                                                    // 资金流比例
-    pub flow_ratio_change_short: Decimal,                                       // 最近的資金流變化情況
-    pub flow_ratio_change_long: Decimal,                                       // 最近的資金流變化情況
+    pub flow_ratio_long: Decimal,                                               // 资金流比例
+    pub flow_ratio_short: Decimal,                                              // 资金流比例
 
     pub ask_delta: Decimal,                                                     // δa
     pub bid_delta: Decimal,                                                     // δb
@@ -60,8 +56,8 @@ pub struct AvellanedaStoikov {
 impl AvellanedaStoikov {
     // 时间窗口大小(微秒)
     const MAX_TIME_RANGE_MICROS: i64 = 5 * 60_000_000;
-    const TRADE_RANGE_MICROS: i64 = 3 * 60_000_000;
-    const FLOW_RATIO_RANGE_MICROS: i64 = 10_000_000;
+    const TRADE_LONG_RANGE_MICROS: i64 = 60_000_000;
+    const TRADE_SHORT_RANGE_MICROS: i64 = 10_000_000;
     // const ONE_MILLION: Decimal = dec!(1_000_000);
     // const TWENTY_THOUSAND: Decimal = dec!(20_000);
     const IRA: Decimal = dec!(1);
@@ -71,9 +67,8 @@ impl AvellanedaStoikov {
             // 分别给与的长度
             depth_vec: FixedTimeRangeDeque::new(Self::MAX_TIME_RANGE_MICROS),
             spread_vec: FixedTimeRangeDeque::new(Self::MAX_TIME_RANGE_MICROS),
-            trade_vec: FixedTimeRangeDeque::new(Self::TRADE_RANGE_MICROS),
-            flow_ratio_long_vec: FixedTimeRangeDeque::new(3 * Self::FLOW_RATIO_RANGE_MICROS),
-            flow_ratio_short_vec: FixedTimeRangeDeque::new(Self::FLOW_RATIO_RANGE_MICROS),
+            trade_long_vec: FixedTimeRangeDeque::new(Self::TRADE_LONG_RANGE_MICROS),
+            trade_short_vec: FixedTimeRangeDeque::new(Self::TRADE_SHORT_RANGE_MICROS),
 
             mid_price: Default::default(),
             ask_price: Default::default(),
@@ -102,14 +97,11 @@ impl AvellanedaStoikov {
             is_ready: false,
             prev_trade_time: Utc::now().timestamp_micros(),
             t_diff: Default::default(),
-            flow_ratio: Decimal::ONE,
-            flow_ratio_change_short: Default::default(),
-            flow_ratio_change_long: Default::default(),
-            flow_in_value: Default::default(),
-            flow_out_value: Default::default(),
+            flow_ratio_long: Decimal::ONE,
             level: Default::default(),
             prev_close_time: Utc::now().timestamp_micros(),
             prev_prev_close_time: Utc::now().timestamp_micros(),
+            flow_ratio_short: Default::default(),
         };
 
         avellaneda_stoikov
@@ -134,14 +126,14 @@ impl AvellanedaStoikov {
     }
 
     pub fn update_spread(&mut self) {
-        if self.trade_vec.len() > 0 {
+        if self.trade_long_vec.len() > 0 {
             //
-            let last_trade = self.trade_vec.get(self.trade_vec.len() - 1).unwrap();
+            let last_trade = self.trade_long_vec.get(self.trade_long_vec.len() - 1).unwrap();
             let last_trade_price = last_trade.price;
             let last_trade_time = last_trade.time;
 
             let mut first_trade_price = last_trade.price;
-            for trade in self.trade_vec.deque.iter().rev() {
+            for trade in self.trade_long_vec.deque.iter().rev() {
                 if last_trade_time - trade.time > Decimal::TEN {
                     break;
                 }
@@ -170,50 +162,8 @@ impl AvellanedaStoikov {
     }
 
     pub async fn on_trade(&mut self, trade: &Trade) {
-        self.trade_vec.push_back(trade.clone());
-
-        if self.trade_vec.deque.len() > 1 {
-            let prev_trade_iter = self.trade_vec.deque.get(self.trade_vec.deque.len() - 2).unwrap();
-            if trade.price > prev_trade_iter.price {
-                self.flow_in_value += trade.value;
-            } else if trade.price < prev_trade_iter.price {
-                self.flow_out_value += trade.value;
-            } else {
-                // if trade.size > Decimal::ZERO {
-                //     self.flow_in_value += trade.value;
-                // } else {
-                //     self.flow_out_value += trade.value;
-                // }
-            }
-
-            // if trade.size > Decimal::ZERO {
-            //     self.flow_in_value += trade.value;
-            // } else {
-            //     self.flow_out_value += trade.value;
-            // }
-
-            if self.flow_out_value + self.flow_in_value > dec!(2_000_000) {
-                self.flow_out_value = self.flow_out_value * dec!(0.618);
-                self.flow_in_value = self.flow_in_value * dec!(0.618);
-            }
-        }
-        // else {
-        //     if trade.size > Decimal::ZERO {
-        //         self.flow_in_value += trade.value;
-        //     } else {
-        //         self.flow_out_value += trade.value;
-        //     }
-        // }
-
-        // self.flow_in_value = Decimal::ZERO;
-        // self.flow_out_value = Decimal::ZERO;
-        // for trade_iter in self.trade_vec.deque.iter() {
-        //     if trade_iter.size > Decimal::ZERO {
-        //         self.flow_in_value += trade_iter.value;
-        //     } else {
-        //         self.flow_out_value += trade_iter.value;
-        //     }
-        // }
+        self.trade_long_vec.push_back(trade.clone());
+        self.trade_short_vec.push_back(trade.clone());
 
         self.last_price = trade.price;
         self.update_spread();
@@ -290,23 +240,23 @@ impl AvellanedaStoikov {
         //     self.ask_delta += pos_edge;
         // }
 
-        if !self.flow_ratio.is_zero() {
-            if self.flow_ratio_change_long < Decimal::ZERO {
-                if self.flow_ratio_change_short > Decimal::ZERO {
+        if !self.flow_ratio_long.is_zero() {
+            if self.flow_ratio_long < Decimal::ZERO {
+                if self.flow_ratio_short > Decimal::ZERO {
                     self.ask_delta -= self.base_delta;
                     self.bid_delta += self.base_delta;
-                } else if self.flow_ratio_change_short < Decimal::ZERO && self.inventory < Decimal::ZERO {
+                } else if self.flow_ratio_short < Decimal::ZERO && self.inventory < Decimal::ZERO {
                     self.ask_delta += self.base_delta;
                     self.bid_delta -= self.base_delta;
                 } else {
                     self.ask_delta += self.base_delta;
                     self.bid_delta += self.base_delta;
                 }
-            } else if self.flow_ratio_change_long > Decimal::ZERO {
-                if self.flow_ratio_change_short > Decimal::ZERO && self.inventory > Decimal::ZERO {
+            } else if self.flow_ratio_long > Decimal::ZERO {
+                if self.flow_ratio_short > Decimal::ZERO && self.inventory > Decimal::ZERO {
                     self.ask_delta -= self.base_delta;
                     self.bid_delta += self.base_delta;
-                } else if self.flow_ratio_change_short < Decimal::ZERO {
+                } else if self.flow_ratio_short < Decimal::ZERO {
                     self.ask_delta += self.base_delta;
                     self.bid_delta -= self.base_delta;
                 } else {
@@ -338,31 +288,74 @@ impl AvellanedaStoikov {
         }
     }
 
-    pub fn update_flow_ratio(&mut self) {
-        if self.flow_out_value + self.flow_in_value > dec!(100_000) {
-            // 使用EMA來更新資金流,確保平滑性
-            let a = Decimal::TWO / dec!(50);
-            let now = (self.flow_in_value - self.flow_out_value) / (self.flow_out_value + self.flow_in_value);
-            self.flow_ratio = a * now + (Decimal::ONE - a) * self.flow_ratio;
-            self.flow_ratio_long_vec.push_back(self.flow_ratio);
-            self.flow_ratio_short_vec.push_back(self.flow_ratio);
-
-            // 更新最後的變化
-            if self.flow_ratio_short_vec.len() > 2 {
-                let last = self.flow_ratio_short_vec.deque.iter().last().unwrap().clone();
-                let first = self.flow_ratio_short_vec.deque[0];
-
-                self.flow_ratio_change_short = last - first;
-            }
-            if self.flow_ratio_long_vec.len() > 2 {
-                let last = self.flow_ratio_long_vec.deque.iter().last().unwrap().clone();
-                let first = self.flow_ratio_long_vec.deque[0];
+    fn calc_flow_ratio(prev_flow_ratio: &Decimal, min_volume: &Decimal, trades: &mut FixedTimeRangeDeque<Trade>) -> Decimal {
+        // 使用EMA來更新資金流,確保平滑性
+        let a = Decimal::TWO / dec!(50);
 
-                self.flow_ratio_change_long = last - first;
+        let mut flow_in_value = Decimal::ZERO;
+        let mut flow_out_value = Decimal::ZERO;
+        for trade_iter in trades.deque.iter() {
+            if trade_iter.size > Decimal::ZERO {
+                flow_in_value += trade_iter.value;
+            } else {
+                flow_out_value += trade_iter.value;
             }
+        }
+
+        if flow_out_value + flow_in_value > *min_volume {
+            let now = (flow_in_value - flow_out_value) / (flow_out_value + flow_in_value);
+            a * now + (Decimal::ONE - a) * prev_flow_ratio
         } else {
-            self.flow_ratio = Decimal::ZERO;
+            Decimal::ZERO
         }
+
+        // if self.trade_vec.deque.len() > 1 {
+        //     let prev_trade_iter = self.trade_vec.deque.get(self.trade_vec.deque.len() - 2).unwrap();
+        //     if trade.price > prev_trade_iter.price {
+        //         self.flow_in_value += trade.value;
+        //     } else if trade.price < prev_trade_iter.price {
+        //         self.flow_out_value += trade.value;
+        //     } else {
+        //         // if trade.size > Decimal::ZERO {
+        //         //     self.flow_in_value += trade.value;
+        //         // } else {
+        //         //     self.flow_out_value += trade.value;
+        //         // }
+        //     }
+        //
+        //     // if trade.size > Decimal::ZERO {
+        //     //     self.flow_in_value += trade.value;
+        //     // } else {
+        //     //     self.flow_out_value += trade.value;
+        //     // }
+        //
+        //     if self.flow_out_value + self.flow_in_value > dec!(2_000_000) {
+        //         self.flow_out_value = self.flow_out_value * dec!(0.618);
+        //         self.flow_in_value = self.flow_in_value * dec!(0.618);
+        //     }
+        // }
+        // else {
+        //     if trade.size > Decimal::ZERO {
+        //         self.flow_in_value += trade.value;
+        //     } else {
+        //         self.flow_out_value += trade.value;
+        //     }
+        // }
+
+        // self.flow_in_value = Decimal::ZERO;
+        // self.flow_out_value = Decimal::ZERO;
+        // for trade_iter in self.trade_vec.deque.iter() {
+        //     if trade_iter.size > Decimal::ZERO {
+        //         self.flow_in_value += trade_iter.value;
+        //     } else {
+        //         self.flow_out_value += trade_iter.value;
+        //     }
+        // }
+    }
+
+    pub fn update_flow_ratio(&mut self) {
+        self.flow_ratio_long = Self::calc_flow_ratio(&self.flow_ratio_long, &dec!(300_000), &mut self.trade_long_vec);
+        self.flow_ratio_short = Self::calc_flow_ratio(&self.flow_ratio_short, &dec!(100_000), &mut self.trade_short_vec);
     }
 
     pub fn check_ready(&mut self) {
@@ -394,7 +387,7 @@ impl AvellanedaStoikov {
             return;
         }
 
-        if self.trade_vec.len() < 100 {
+        if self.trade_long_vec.len() < 100 {
             return;
         }
 
@@ -441,11 +434,11 @@ impl AvellanedaStoikov {
             optimal_bid_price: self.optimal_bid_price,
 
             inventory: self.inventory,
-            sigma_square: self.flow_ratio_change_long,
-            gamma: self.flow_ratio_change_short,
-            kappa: self.flow_ratio,
+            sigma_square: self.flow_ratio_long,
+            gamma: self.flow_ratio_short,
+            kappa: self.t_diff,
 
-            flow_ratio: self.flow_ratio,
+            flow_ratio: self.flow_ratio_long,
             ref_price: self.ref_price,
         });
     }