|
|
@@ -35,10 +35,6 @@ pub struct AvellanedaStoikov {
|
|
|
pub gamma: Decimal, // γ,库存风险厌恶参数
|
|
|
pub kappa: Decimal, // κ 订单簿 流动性 参数
|
|
|
|
|
|
- pub flow_ratio_mfi: Decimal, // 资金流比例(专供MFI)
|
|
|
- pub flow_ratio_trades: Decimal, // 资金流比例(trades生成)
|
|
|
- pub money_flow_index: Decimal, // MFI
|
|
|
-
|
|
|
pub ask_delta: Decimal, // δa
|
|
|
pub bid_delta: Decimal, // δb
|
|
|
pub base_delta: Decimal, // 基础挂单距离
|
|
|
@@ -97,9 +93,6 @@ impl AvellanedaStoikov {
|
|
|
prev_trade_time: Utc::now().timestamp_micros(),
|
|
|
t_diff: Default::default(),
|
|
|
level: Default::default(),
|
|
|
- flow_ratio_mfi: Default::default(),
|
|
|
- flow_ratio_trades: Default::default(),
|
|
|
- money_flow_index: Default::default(),
|
|
|
};
|
|
|
|
|
|
avellaneda_stoikov
|
|
|
@@ -199,30 +192,6 @@ impl AvellanedaStoikov {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- 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) {
|
|
|
let prev_inventory = self.inventory;
|
|
|
self.inventory = (inventory / (min_amount_value / self.mid_price)).round();
|
|
|
@@ -240,28 +209,10 @@ impl AvellanedaStoikov {
|
|
|
}
|
|
|
|
|
|
pub fn update_gamma(&mut self) {
|
|
|
- // self.gamma = if self.sigma_square == Decimal::ZERO || self.inventory == Decimal::ZERO {
|
|
|
- // Decimal::ONE
|
|
|
- // } else {
|
|
|
- // Self::IRA * (self.spread_max - self.spread_min) / (Decimal::TWO * self.inventory.abs() * self.sigma_square)
|
|
|
- // };
|
|
|
- // self.gamma.rescale(8);
|
|
|
-
|
|
|
self.gamma = dec!(0.236) * Self::IRA;
|
|
|
}
|
|
|
|
|
|
pub fn update_kappa(&mut self) {
|
|
|
- // self.kappa = if self.spread_max.is_zero() || self.init_delta_plus.is_zero() {
|
|
|
- // Decimal::ONE
|
|
|
- // } else {
|
|
|
- // let mut temp = self.init_delta_plus * self.gamma - self.sigma_square * self.gamma.powd(Decimal::TWO);
|
|
|
- // temp.rescale(6);
|
|
|
- //
|
|
|
- // self.gamma / (temp.exp() - Decimal::ONE)
|
|
|
- // };
|
|
|
- //
|
|
|
- // self.kappa.rescale(8);
|
|
|
-
|
|
|
if self.mid_price > Decimal::ZERO {
|
|
|
self.kappa = dec!(888) / self.mid_price;
|
|
|
} else {
|
|
|
@@ -278,7 +229,6 @@ impl AvellanedaStoikov {
|
|
|
let pos_edge = self.sigma_square * self.inventory.abs() * self.t_diff;
|
|
|
|
|
|
self.base_delta = self.sigma_square;
|
|
|
- // self.ratio_edge = self.flow_ratio_mfi * self.sigma_square;
|
|
|
|
|
|
self.bid_delta = self.base_delta;
|
|
|
self.ask_delta = self.base_delta;
|
|
|
@@ -290,27 +240,6 @@ impl AvellanedaStoikov {
|
|
|
self.bid_delta = Decimal::NEGATIVE_ONE;
|
|
|
self.ask_delta += pos_edge * Decimal::TWO;
|
|
|
}
|
|
|
- //
|
|
|
- // if (self.ratio_edge > Decimal::ZERO) || (self.money_flow_index > dec!(60) && self.inventory > Decimal::ZERO) {
|
|
|
- // if self.inventory > Decimal::ZERO {
|
|
|
- // self.ask_delta = Decimal::ZERO;
|
|
|
- // self.bid_delta += self.sigma_square.abs() * dec!(5);
|
|
|
- // } else {
|
|
|
- // self.ask_delta = self.base_delta;
|
|
|
- // self.bid_delta += self.sigma_square.abs() * dec!(5);
|
|
|
- // }
|
|
|
- // } else if (self.ratio_edge < Decimal::ZERO) || (self.money_flow_index < dec!(40) && self.inventory < Decimal::ZERO) {
|
|
|
- // if self.inventory < Decimal::ZERO {
|
|
|
- // self.ask_delta += self.sigma_square.abs() * dec!(5);
|
|
|
- // self.bid_delta = Decimal::ZERO;
|
|
|
- // } else {
|
|
|
- // self.ask_delta += self.sigma_square.abs() * dec!(5);
|
|
|
- // self.bid_delta = self.base_delta;
|
|
|
- // }
|
|
|
- // } else if self.ratio_edge == Decimal::ZERO {
|
|
|
- // self.ask_delta += self.base_delta.abs() * dec!(5);
|
|
|
- // self.bid_delta += self.base_delta.abs() * dec!(5);
|
|
|
- // }
|
|
|
}
|
|
|
}
|
|
|
|
|
|
@@ -337,69 +266,6 @@ impl AvellanedaStoikov {
|
|
|
}
|
|
|
|
|
|
fn calc_flow_ratio(_prev_flow_ratio: &Decimal, min_volume: &Decimal, trades: &mut FixedTimeRangeDeque<Trade>) -> Decimal {
|
|
|
- // let mut flow_in_value = Decimal::ZERO;
|
|
|
- // let mut flow_out_value = Decimal::ZERO;
|
|
|
- // for (index, trade_iter) in trades.deque.iter().enumerate() {
|
|
|
- // if index == 0 {
|
|
|
- // continue
|
|
|
- // }
|
|
|
- //
|
|
|
- // let prev_trade_iter = trades.deque.get(index - 1).unwrap();
|
|
|
- // let trade = trade_iter;
|
|
|
- // if trade.price > prev_trade_iter.price {
|
|
|
- // flow_in_value += trade.value * (prev_trade_iter.price - trade.price).abs();
|
|
|
- // // flow_in_value += Decimal::ONE;
|
|
|
- // } else if trade.price < prev_trade_iter.price {
|
|
|
- // flow_out_value += trade.value * (prev_trade_iter.price - trade.price).abs();
|
|
|
- // // flow_out_value += Decimal::ONE;
|
|
|
- // } else {
|
|
|
- // // if trade.size > Decimal::ZERO {
|
|
|
- // // flow_in_value += trade.value;
|
|
|
- // // } else {
|
|
|
- // // flow_out_value += trade.value;
|
|
|
- // // }
|
|
|
- // }
|
|
|
- //
|
|
|
- // // if trade_iter.size > Decimal::ZERO {
|
|
|
- // // flow_in_value += trade_iter.value;
|
|
|
- // // } else {
|
|
|
- // // flow_out_value += trade_iter.value;
|
|
|
- // // }
|
|
|
- // }
|
|
|
-
|
|
|
- // 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;
|
|
|
- // }
|
|
|
- // }
|
|
|
-
|
|
|
let mut flow_in_value = Decimal::ZERO;
|
|
|
let mut flow_out_value = Decimal::ZERO;
|
|
|
for trade_iter in trades.deque.iter() {
|
|
|
@@ -411,64 +277,14 @@ impl AvellanedaStoikov {
|
|
|
}
|
|
|
|
|
|
// 使用EMA來更新資金流,確保平滑性
|
|
|
- // let a = Decimal::TWO / dec!(50);
|
|
|
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
|
|
|
- // Decimal::ONE_HUNDRED * flow_in_value / (flow_out_value + flow_in_value)
|
|
|
now
|
|
|
} else {
|
|
|
Decimal::ZERO
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- // fn calc_flow_ratio_2(_prev_flow_ratio: &Decimal, min_volume: &Decimal, trades: &mut FixedTimeRangeDeque<Trade>) -> Decimal {
|
|
|
- // let mut flow_in_value = Decimal::ZERO;
|
|
|
- // let mut flow_out_value = Decimal::ZERO;
|
|
|
- // for (index, trade_iter) in trades.deque.iter().enumerate() {
|
|
|
- // if index == 0 {
|
|
|
- // continue
|
|
|
- // }
|
|
|
- //
|
|
|
- // let prev_trade_iter = trades.deque.get(index - 1).unwrap();
|
|
|
- // let trade = trade_iter;
|
|
|
- // if trade.price > prev_trade_iter.price {
|
|
|
- // flow_in_value += trade.value;
|
|
|
- // // flow_in_value += Decimal::ONE;
|
|
|
- // } else if trade.price < prev_trade_iter.price {
|
|
|
- // flow_out_value += trade.value;
|
|
|
- // // flow_out_value += Decimal::ONE;
|
|
|
- // } else {
|
|
|
- // if trade.size > Decimal::ZERO {
|
|
|
- // flow_in_value += trade.value;
|
|
|
- // } else {
|
|
|
- // flow_out_value += trade.value;
|
|
|
- // }
|
|
|
- // }
|
|
|
- // }
|
|
|
- //
|
|
|
- // // 使用EMA來更新資金流,確保平滑性
|
|
|
- // // let a = Decimal::TWO / dec!(50);
|
|
|
- // 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
|
|
|
- // (flow_in_value - flow_out_value) / (flow_out_value + flow_in_value)
|
|
|
- // } else {
|
|
|
- // Decimal::ZERO
|
|
|
- // }
|
|
|
- // }
|
|
|
-
|
|
|
- pub fn update_flow_ratio(&mut self) {
|
|
|
- self.flow_ratio_mfi = 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
|
|
|
- };
|
|
|
- self.flow_ratio_trades = Self::calc_flow_ratio(&self.flow_ratio_trades, &dec!(0), &mut self.trade_short_vec);
|
|
|
- }
|
|
|
-
|
|
|
pub fn check_ready(&mut self) {
|
|
|
if self.is_ready {
|
|
|
return;
|
|
|
@@ -545,11 +361,11 @@ impl AvellanedaStoikov {
|
|
|
optimal_bid_price: self.optimal_bid_price,
|
|
|
|
|
|
inventory: self.inventory,
|
|
|
- sigma_square: self.money_flow_index,
|
|
|
- gamma: self.flow_ratio_trades,
|
|
|
- kappa: self.t_diff,
|
|
|
+ sigma_square: self.sigma_square,
|
|
|
+ gamma: self.gamma,
|
|
|
+ kappa: self.kappa,
|
|
|
|
|
|
- flow_ratio: self.flow_ratio_mfi,
|
|
|
+ flow_ratio: Decimal::ZERO,
|
|
|
ref_price: self.ref_price,
|
|
|
});
|
|
|
}
|