浏览代码

这个版本实验处理风险的能力。

skyfffire 1 年之前
父节点
当前提交
7a85268e5d
共有 2 个文件被更改,包括 50 次插入2 次删除
  1. 45 1
      strategy/src/avellaneda_stoikov.rs
  2. 5 1
      strategy/src/strategy.rs

+ 45 - 1
strategy/src/avellaneda_stoikov.rs

@@ -38,6 +38,9 @@ pub struct AvellanedaStoikov {
     pub gamma: Decimal,                                                         // γ,库存风险厌恶参数
     pub kappa: Decimal,                                                         // κ 订单簿 流动性 参数
 
+    pub flow_ratio: Decimal,                                                    // 资金流比例
+    pub money_flow_index: Decimal,                                              // MFI
+
     pub ask_delta: Decimal,                                                     // δa
     pub bid_delta: Decimal,                                                     // δb
     pub base_delta: Decimal,                                                    // 基础挂单距离
@@ -102,6 +105,8 @@ impl AvellanedaStoikov {
             prev_trade_time: Utc::now().timestamp_micros(),
             t_diff: Default::default(),
             level: Default::default(),
+            flow_ratio: Default::default(),
+            money_flow_index: Default::default(),
         };
 
         avellaneda_stoikov
@@ -235,6 +240,35 @@ impl AvellanedaStoikov {
         if self.record_vec.len() > 4 {
             self.record_vec.pop_front();
         }
+
+        // 如果蜡烛数量足够,则更新mfi
+        if self.record_vec.len() >= 4 {
+            self.update_mfi();
+        }
+    }
+
+    pub fn update_mfi(&mut self) {
+        let mut money_flow_in = Decimal::ZERO;
+        let mut money_flow_out = Decimal::ZERO;
+        let _3 = dec!(3);
+
+        for record in self.record_vec.iter() {
+            let typical_price = (record.high + record.low + record.close) / _3;
+            let money_flow = typical_price * record.volume;
+            if record.close > record.open {
+                money_flow_in += money_flow;
+            } else if record.close < record.open {
+                money_flow_out += money_flow;
+            }
+        }
+
+        self.money_flow_index = if money_flow_out.is_zero() {
+            Decimal::ONE_HUNDRED
+        } else {
+            let money_flow_ratio = money_flow_in / money_flow_out;
+
+            Decimal::ONE_HUNDRED - Decimal::ONE_HUNDRED / (Decimal::ONE + money_flow_ratio)
+        };
     }
 
     pub async fn update_inventory(&mut self, inventory: &Decimal, min_amount_value: &Decimal) {
@@ -343,6 +377,16 @@ impl AvellanedaStoikov {
     //     }
     // }
 
+    pub fn update_flow_ratio(&mut self) {
+        self.flow_ratio = if self.money_flow_index > dec!(80) {
+            (self.money_flow_index - dec!(80)) / dec!(20)
+        } else if self.money_flow_index < dec!(20) {
+            Decimal::NEGATIVE_ONE * (dec!(20) - self.money_flow_index) / dec!(20)
+        } else {
+            Decimal::ZERO
+        };
+    }
+
     pub fn check_ready(&mut self) {
         if self.is_ready {
             return;
@@ -417,7 +461,7 @@ impl AvellanedaStoikov {
 
             inventory: self.inventory,
             sigma_square: self.sigma_square,
-            gamma: self.spread,
+            gamma: self.money_flow_index,
             kappa: self.kappa,
 
             flow_ratio: Decimal::ZERO,

+ 5 - 1
strategy/src/strategy.rs

@@ -992,7 +992,11 @@ impl Strategy {
             // target_sell_price = utils::clip(target_sell_price, self.bp * dec!(0.9995), self.ap * dec!(1.03));
             // 取消大小限制
             target_sell_price = utils::fix_price(target_sell_price, self.tick_size);
-            let amount = utils::get_amount_by_min_amount_value(self.min_amount_value, target_sell_price, self.step_size);
+            let amount = if predictor.inventory > Decimal::TWO && predictor.flow_ratio > Decimal::ZERO {
+                utils::get_amount_by_min_amount_value(self.min_amount_value * Decimal::TWO, target_sell_price, self.step_size)
+            } else {
+                utils::get_amount_by_min_amount_value(self.min_amount_value, target_sell_price, self.step_size)
+            };
             // let amount = if predictor.inventory > Decimal::ZERO {
             //     if predictor.level >= dec!(3) {
             //         utils::get_amount_by_min_amount_value(self.min_amount_value * predictor.inventory.abs(), target_sell_price, self.step_size)