Explorar el Código

版本1,基础逻辑实现。

skyfffire hace 11 meses
padre
commit
7f32845225
Se han modificado 5 ficheros con 41 adiciones y 52 borrados
  1. 3 3
      strategy/src/clear_core.rs
  2. 3 3
      strategy/src/core.rs
  3. 1 1
      strategy/src/lib.rs
  4. 25 36
      strategy/src/predictor.rs
  5. 9 9
      strategy/src/strategy.rs

+ 3 - 3
strategy/src/clear_core.rs

@@ -21,7 +21,7 @@ use standard::exchange::{Exchange};
 use standard::exchange::ExchangeEnum::{BinanceSwap, GateSwap, BitgetSwap};
 
 use crate::model::{LocalPosition, OrderInfo};
-use crate::avellaneda_stoikov::AvellanedaStoikov;
+use crate::predictor::Predictor;
 use crate::strategy::Strategy;
 use crate::utils;
 use crate::utils::clip;
@@ -89,7 +89,7 @@ pub struct ClearCore {
     pub ref_name: Vec<String>,
     pub trade_name: String,
     pub ready: i8,
-    pub predictor: AvellanedaStoikov,
+    pub predictor: Predictor,
     pub market: Market,
     pub platform_rest: Box<dyn Platform + Send + Sync>,
     // 市场最优买卖价
@@ -173,7 +173,7 @@ impl ClearCore {
             ref_name: Default::default(),
             trade_name: "".to_string(),
             ready: 0,
-            predictor: AvellanedaStoikov::new(cci_arc.clone(), params.clone()),
+            predictor: Predictor::new(cci_arc.clone(), params.clone()),
             market: Market {
                 symbol: symbol.clone(),
                 base_asset: "".to_string(),

+ 3 - 3
strategy/src/core.rs

@@ -23,7 +23,7 @@ use standard::exchange::{Exchange};
 use standard::exchange::ExchangeEnum::{BinanceSwap, BybitSwap, BitgetSwap, GateSwap};
 
 use crate::model::{LocalPosition, OrderInfo, TokenParam};
-use crate::avellaneda_stoikov::AvellanedaStoikov;
+use crate::predictor::Predictor;
 use crate::strategy::Strategy;
 use crate::utils;
 use crate::utils::clip;
@@ -91,7 +91,7 @@ pub struct Core {
     pub ref_name: Vec<String>,
     pub trade_name: String,
     pub ready: i8,
-    pub avellaneda_stoikov: AvellanedaStoikov,
+    pub avellaneda_stoikov: Predictor,
     pub market: Market,
     pub platform_rest: Box<dyn Platform + Send + Sync>,
     // 市场最优买卖价
@@ -175,7 +175,7 @@ impl Core {
             ref_name: Default::default(),
             trade_name: "".to_string(),
             ready: 0,
-            avellaneda_stoikov: AvellanedaStoikov::new(cci_arc.clone(), params.clone()),
+            avellaneda_stoikov: Predictor::new(cci_arc.clone(), params.clone()),
             market: Market {
                 symbol: symbol.clone(),
                 base_asset: "".to_string(),

+ 1 - 1
strategy/src/lib.rs

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

+ 25 - 36
strategy/src/avellaneda_stoikov.rs → strategy/src/predictor.rs

@@ -15,7 +15,7 @@ use standard::{Depth, Record, Ticker, Trade};
 use crate::utils;
 
 #[derive(Debug)]
-pub struct AvellanedaStoikov {
+pub struct Predictor {
     pub depth_vec: Vec<Depth>,                                                  // 深度队列
     pub fair_price_vec: Vec<Decimal>,                                           // 预定价格队列
     pub volume_vec: Vec<Decimal>,                                               // 深度队列
@@ -74,7 +74,7 @@ pub struct AvellanedaStoikov {
     pub debug_sender: UnboundedSender<Vec<Decimal>>,
 }
 
-impl AvellanedaStoikov {
+impl Predictor {
     // 时间窗口大小(微秒)
     // const MAX_TIME_RANGE_MICROS: i64 = 3 * 60_000_000;
     const TIME_DIFF_RANGE_MICROS: i64 = 10 * 60_000_000;
@@ -123,7 +123,7 @@ impl AvellanedaStoikov {
             }
         });
 
-        let avellaneda_stoikov = Self {
+        let predictor = Self {
             // 接针版本
             depth_vec: vec![Depth::new(); 10],
             fair_price_vec: vec![Decimal::ZERO; 10],
@@ -183,7 +183,7 @@ impl AvellanedaStoikov {
             debug_sender: tx,
         };
 
-        avellaneda_stoikov
+        predictor
     }
 
     // 更新最大市场冲击
@@ -424,53 +424,42 @@ impl AvellanedaStoikov {
 
             let price_diff = mp0 - mp1;
 
-            self.ref_price = self.fair_price_vec[0] * dec!(0.3) + self.fair_price_vec[1] * dec!(0.7) + price_diff / Decimal::TWO;
+            self.ref_price = self.fair_price_vec[0] * dec!(0.2) + self.fair_price_vec[1] * dec!(0.8) + price_diff / Decimal::TWO;
             // self.ref_price = (self.fair_price_vec[0] + self.fair_price_vec[1]) / Decimal::TWO;
         }
     }
 
     pub fn update_delta(&mut self) {
-        if self.gamma != Decimal::ZERO {
-            // let pos_edge = self.sigma_square * self.inventory.abs() * self.t_diff;
-
-            self.base_delta = self.sigma_square;
-
-            self.bid_delta = self.base_delta;
-            self.ask_delta = self.base_delta;
-
-            if self.inventory > Decimal::ZERO {
-                // self.ask_delta = self.base_delta;
-                self.ask_delta = self.ref_price * self.params.close;
-            } else if self.inventory < Decimal::ZERO {
-                // self.bid_delta = self.base_delta;
-                self.bid_delta = self.ref_price * self.params.close;
-            }
+        let is_open_long = self.ref_price / self.mid_price - Decimal::ONE > self.params.open;
+        let is_open_short = self.ref_price / self.mid_price - Decimal::ONE < self.params.open * Decimal::NEGATIVE_ONE;
+        let is_close_long = self.ref_price / self.mid_price - Decimal::ONE < self.params.close * Decimal::NEGATIVE_ONE;
+        let is_close_short = self.ref_price / self.mid_price - Decimal::ONE > self.params.close;
+
+        self.bid_delta = Decimal::NEGATIVE_ONE;
+        self.ask_delta = Decimal::NEGATIVE_ONE;
+
+        if self.inventory > Decimal::ZERO && is_close_long {
+            self.ask_delta = Decimal::ZERO;
+        } else if self.inventory < Decimal::ZERO && is_close_short {
+            self.bid_delta = Decimal::ZERO;
+        } else if is_open_long {
+            self.bid_delta = Decimal::ZERO;
+        } else if is_open_short {
+            self.ask_delta = Decimal::ZERO;
         }
     }
 
     pub fn update_optimal_ask_and_bid(&mut self) {
         self.optimal_ask_price = if self.ask_delta == Decimal::NEGATIVE_ONE {
-            // if self.dir < Decimal::ZERO {
-            //     self.bid_price
-            // } else {
-            //     self.ref_price + self.base_delta * dec!(0.5)
-            // }
-
-            self.ref_price + self.base_delta * dec!(0.5)
+            self.ref_price + self.sigma_square
         } else {
-            max(self.ref_price + self.ask_delta, self.bid_price)
+            max(self.ask_price + self.ask_delta, self.bid_price)
         };
 
         self.optimal_bid_price = if self.bid_delta == Decimal::NEGATIVE_ONE {
-            // if self.dir > Decimal::ZERO {
-            //     self.ask_price
-            // } else {
-            //     self.ref_price - self.base_delta * dec!(0.5)
-            // }
-
-            self.ref_price + self.base_delta * dec!(0.5)
+            self.ref_price - self.sigma_square
         } else {
-            min(self.ref_price - self.bid_delta, self.ask_price)
+            min(self.bid_price - self.bid_delta, self.ask_price)
         };
 
         self.optimal_ask_price.rescale(self.mid_price.scale());

+ 9 - 9
strategy/src/strategy.rs

@@ -11,7 +11,7 @@ use tracing::{info, error, warn};
 use tokio::time::Instant;
 use global::params::Params;
 use standard::{OrderCommand};
-use crate::avellaneda_stoikov::AvellanedaStoikov;
+use crate::predictor::Predictor;
 
 #[derive(Debug)]
 pub struct Strategy {
@@ -465,7 +465,7 @@ impl Strategy {
 
     // 修复挂单价格,不然单子打不出去
     // #[instrument(skip(self), level="TRACE")]
-    pub fn fix_price(&mut self, predictor: &mut AvellanedaStoikov) {
+    pub fn fix_price(&mut self, predictor: &mut Predictor) {
         predictor.optimal_ask_price = utils::fix_price(predictor.optimal_ask_price, self.tick_size);
         predictor.optimal_bid_price = utils::fix_price(predictor.optimal_bid_price, self.tick_size);
 
@@ -833,7 +833,7 @@ impl Strategy {
 
     // 平仓订单处理命令
     // #[instrument(skip(self, command), level="TRACE")]
-    pub fn _post_close(&self, command: &mut OrderCommand, local_orders: &HashMap<String, OrderInfo>, predictor: &mut AvellanedaStoikov) {
+    pub fn _post_close(&self, command: &mut OrderCommand, local_orders: &HashMap<String, OrderInfo>, predictor: &mut Predictor) {
         // debug!(?command);
 
         let mut pd_amount = Decimal::ZERO;
@@ -890,7 +890,7 @@ impl Strategy {
         // }
         // // debug!(?command);
 
-        if predictor.inventory > Decimal::ZERO {
+        if predictor.inventory > Decimal::ZERO && predictor.ask_delta != Decimal::NEGATIVE_ONE {
             if pd_order_num == 0 {
                 let mut price = (short_lower + short_upper) * dec!(0.5);
                 // 不限制大小
@@ -910,7 +910,7 @@ impl Strategy {
                 // debug!(?command);
             }
         }
-        if predictor.inventory < Decimal::ZERO {
+        if predictor.inventory < Decimal::ZERO && predictor.bid_delta != Decimal::NEGATIVE_ONE {
             if pk_order_num == 0 {
                 let mut price = (long_upper + long_lower) * dec!(0.5);
                 // 不限制大小
@@ -1014,7 +1014,7 @@ impl Strategy {
 
     // 开单指令生成逻辑
     // #[instrument(skip(self, command), level="TRACE")]
-    pub fn _post_open(&mut self, command: &mut OrderCommand, local_orders: &HashMap<String, OrderInfo>, predictor: &mut AvellanedaStoikov) {
+    pub fn _post_open(&mut self, command: &mut OrderCommand, local_orders: &HashMap<String, OrderInfo>, predictor: &mut Predictor) {
         // 开仓逻辑检测,主要是检测整点开仓逻辑
         if !self.check_allow_post_open() {
             return;
@@ -1062,7 +1062,7 @@ impl Strategy {
         // let one_hand_long_value = dec!(0.99) * (self.max_long_value / self.grid);
         // let one_hand_short_value = dec!(0.99) * (self.max_short_value / self.grid);
         // 挂多单
-        if self.post_side >= 0 && buy_value == Decimal::ZERO && predictor.inventory.is_zero() {
+        if self.post_side >= 0 && buy_value == Decimal::ZERO && predictor.inventory.is_zero() && predictor.bid_delta != Decimal::NEGATIVE_ONE {
             let mut target_buy_price = predictor.optimal_bid_price;
             // target_buy_price = utils::clip(target_buy_price, self.bp * dec!(0.97), self.ap * dec!(1.0005));
             target_buy_price = utils::fix_price(target_buy_price, self.tick_size);
@@ -1105,7 +1105,7 @@ impl Strategy {
             }
         }
         // 挂空单
-        if self.post_side <= 0 && sell_value == Decimal::ZERO && predictor.inventory.is_zero() {
+        if self.post_side <= 0 && sell_value == Decimal::ZERO && predictor.inventory.is_zero() && predictor.ask_delta != Decimal::NEGATIVE_ONE {
             let mut target_sell_price = predictor.optimal_ask_price;
             // target_sell_price = utils::clip(target_sell_price, self.bp * dec!(0.9995), self.ap * dec!(1.03));
             // 取消大小限制
@@ -1202,7 +1202,7 @@ impl Strategy {
         return command;
     }
 
-    pub fn do_strategy(&mut self, predictor: &mut AvellanedaStoikov, local_orders: &HashMap<String, OrderInfo>, local_coin: &Decimal, local_cash: &Decimal) -> OrderCommand {
+    pub fn do_strategy(&mut self, predictor: &mut Predictor, local_orders: &HashMap<String, OrderInfo>, local_coin: &Decimal, local_cash: &Decimal) -> OrderCommand {
         // 更新当前账户余额
         self.coin = local_coin.clone();
         self.cash = local_cash.clone();