|
|
@@ -16,6 +16,7 @@ pub struct AvellanedaStoikov {
|
|
|
pub depth_vec: FixedTimeRangeDeque<Depth>, // 深度队列
|
|
|
pub trade_vec: FixedTimeRangeDeque<Trade>, // 交易队列
|
|
|
pub spread_vec: FixedTimeRangeDeque<Decimal>,
|
|
|
+ pub flow_ratio_vec: FixedTimeRangeDeque<Decimal>, // 資金流歷史記錄
|
|
|
|
|
|
pub mid_price: Decimal, // 中间价
|
|
|
pub ask_price: Decimal, // 卖一价
|
|
|
@@ -36,6 +37,7 @@ pub struct AvellanedaStoikov {
|
|
|
pub flow_in_value: Decimal,
|
|
|
pub flow_out_value: Decimal,
|
|
|
pub flow_ratio: Decimal, // 资金流比例
|
|
|
+ pub flow_ratio_change: Decimal, // 最近的資金流變化情況
|
|
|
|
|
|
pub ask_delta: Decimal, // δa
|
|
|
pub bid_delta: Decimal, // δb
|
|
|
@@ -49,12 +51,15 @@ pub struct AvellanedaStoikov {
|
|
|
pub is_ready: bool,
|
|
|
pub prev_trade_time: i64, // 上次交易时间,也就是t
|
|
|
pub t_diff: Decimal, // (T-t)
|
|
|
+ pub prev_close_time: i64, // 上次平倉時間
|
|
|
+ pub prev_prev_close_time: i64, // 上上次平倉時間
|
|
|
}
|
|
|
|
|
|
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 = 1 * 60_000_000;
|
|
|
// const ONE_MILLION: Decimal = dec!(1_000_000);
|
|
|
// const TWENTY_THOUSAND: Decimal = dec!(20_000);
|
|
|
const IRA: Decimal = dec!(1);
|
|
|
@@ -63,8 +68,9 @@ impl AvellanedaStoikov {
|
|
|
let avellaneda_stoikov = Self {
|
|
|
// 分别给与的长度
|
|
|
depth_vec: FixedTimeRangeDeque::new(Self::MAX_TIME_RANGE_MICROS),
|
|
|
- trade_vec: FixedTimeRangeDeque::new(Self::TRADE_RANGE_MICROS),
|
|
|
spread_vec: FixedTimeRangeDeque::new(Self::MAX_TIME_RANGE_MICROS),
|
|
|
+ trade_vec: FixedTimeRangeDeque::new(Self::TRADE_RANGE_MICROS),
|
|
|
+ flow_ratio_vec: FixedTimeRangeDeque::new(Self::FLOW_RATIO_RANGE_MICROS),
|
|
|
|
|
|
mid_price: Default::default(),
|
|
|
ask_price: Default::default(),
|
|
|
@@ -86,7 +92,6 @@ impl AvellanedaStoikov {
|
|
|
|
|
|
ratio_edge: Default::default(),
|
|
|
kappa: Default::default(),
|
|
|
- flow_in_value: Default::default(),
|
|
|
ref_price: Default::default(),
|
|
|
|
|
|
cci_arc,
|
|
|
@@ -95,8 +100,12 @@ impl AvellanedaStoikov {
|
|
|
prev_trade_time: Utc::now().timestamp_micros(),
|
|
|
t_diff: Default::default(),
|
|
|
flow_ratio: Decimal::ONE,
|
|
|
+ flow_ratio_change: Default::default(),
|
|
|
+ flow_in_value: Default::default(),
|
|
|
flow_out_value: Default::default(),
|
|
|
level: Default::default(),
|
|
|
+ prev_close_time: Utc::now().timestamp_micros(),
|
|
|
+ prev_prev_close_time: Utc::now().timestamp_micros(),
|
|
|
};
|
|
|
|
|
|
avellaneda_stoikov
|
|
|
@@ -157,27 +166,54 @@ impl AvellanedaStoikov {
|
|
|
}
|
|
|
|
|
|
pub async fn on_trade(&mut self, trade: &Trade) {
|
|
|
- self.trade_vec.push_back(trade.clone());
|
|
|
- self.flow_in_value = Decimal::ZERO;
|
|
|
- self.flow_out_value = Decimal::ZERO;
|
|
|
- for (index, trade_iter) in self.trade_vec.deque.iter().enumerate() {
|
|
|
- if index == 0 {
|
|
|
- continue
|
|
|
- }
|
|
|
- let prev_trade_iter = self.trade_vec.get(index - 1).unwrap();
|
|
|
+ if self.trade_vec.deque.len() > 0 {
|
|
|
+ let prev_trade_iter = self.trade_vec.deque.iter().last().unwrap();
|
|
|
|
|
|
- if trade_iter.price > prev_trade_iter.price {
|
|
|
- self.flow_in_value += trade_iter.value;
|
|
|
- } else if trade_iter.price < prev_trade_iter.price {
|
|
|
- self.flow_out_value += trade_iter.value;
|
|
|
+ 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_iter.size > Decimal::ZERO {
|
|
|
- self.flow_in_value += trade_iter.value;
|
|
|
+ if trade.size > Decimal::ZERO {
|
|
|
+ self.flow_in_value += trade.value;
|
|
|
} else {
|
|
|
- self.flow_out_value += trade_iter.value;
|
|
|
+ self.flow_out_value += trade.value;
|
|
|
}
|
|
|
}
|
|
|
+
|
|
|
+ if self.flow_out_value + self.flow_in_value > dec!(1_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.trade_vec.push_back(trade.clone());
|
|
|
+
|
|
|
+ // self.flow_in_value = Decimal::ZERO;
|
|
|
+ // self.flow_out_value = Decimal::ZERO;
|
|
|
+ // for (index, trade_iter) in self.trade_vec.deque.iter().enumerate() {
|
|
|
+ // if index == 0 {
|
|
|
+ // continue
|
|
|
+ // }
|
|
|
+ // let prev_trade_iter = self.trade_vec.get(index - 1).unwrap();
|
|
|
+ //
|
|
|
+ // if trade_iter.price > prev_trade_iter.price {
|
|
|
+ // self.flow_in_value += trade_iter.value;
|
|
|
+ // } else if trade_iter.price < prev_trade_iter.price {
|
|
|
+ // self.flow_out_value += trade_iter.value;
|
|
|
+ // } else {
|
|
|
+ // if trade_iter.size > Decimal::ZERO {
|
|
|
+ // self.flow_in_value += trade_iter.value;
|
|
|
+ // } else {
|
|
|
+ // self.flow_out_value += trade_iter.value;
|
|
|
+ // }
|
|
|
+ // }
|
|
|
+ // }
|
|
|
|
|
|
self.last_price = trade.price;
|
|
|
self.update_spread();
|
|
|
@@ -193,6 +229,10 @@ impl AvellanedaStoikov {
|
|
|
self.prev_trade_time = Utc::now().timestamp_micros();
|
|
|
self.inventory = (inventory / (min_amount_value / self.mid_price)).round();
|
|
|
|
|
|
+ // if self.inventory.is_zero() {
|
|
|
+ // self.prev_prev_close_time = self.prev_close_time;
|
|
|
+ // self.prev_close_time = Utc::now().timestamp_millis();
|
|
|
+ // }
|
|
|
self.update_level().await;
|
|
|
self.processor().await;
|
|
|
}
|
|
|
@@ -240,7 +280,7 @@ impl AvellanedaStoikov {
|
|
|
if self.gamma != Decimal::ZERO {
|
|
|
let pos_edge = self.gamma * self.sigma_square * self.inventory.abs().powd(Decimal::TWO) * self.t_diff / Decimal::TWO;
|
|
|
|
|
|
- self.base_delta = self.gamma * self.sigma_square * self.t_diff / Decimal::TWO + (Decimal::ONE / self.gamma) * (Decimal::ONE + self.gamma / self.kappa).ln();
|
|
|
+ self.base_delta = self.sigma_square;
|
|
|
self.ratio_edge = self.flow_ratio * self.sigma_square;
|
|
|
|
|
|
self.bid_delta = self.base_delta;
|
|
|
@@ -281,6 +321,15 @@ impl AvellanedaStoikov {
|
|
|
pub fn update_flow_ratio(&mut self) {
|
|
|
if self.trade_vec.len() > 100 {
|
|
|
self.flow_ratio = (self.flow_in_value - self.flow_out_value) / (self.flow_out_value + self.flow_in_value);
|
|
|
+ self.flow_ratio_vec.push_back(self.flow_ratio);
|
|
|
+
|
|
|
+ // 更新最後的變化
|
|
|
+ if self.flow_ratio_vec.len() > 10 {
|
|
|
+ let last = self.flow_ratio_vec.deque.iter().last().unwrap().clone();
|
|
|
+ let first = self.flow_ratio_vec.deque[0];
|
|
|
+
|
|
|
+ self.flow_ratio_change = last - first;
|
|
|
+ }
|
|
|
} else {
|
|
|
self.flow_ratio = Decimal::ZERO;
|
|
|
}
|
|
|
@@ -363,7 +412,7 @@ impl AvellanedaStoikov {
|
|
|
|
|
|
inventory: self.inventory,
|
|
|
sigma_square: self.flow_ratio,
|
|
|
- gamma: self.ratio_edge,
|
|
|
+ gamma: self.flow_ratio_change,
|
|
|
kappa: self.t_diff,
|
|
|
|
|
|
flow_ratio: self.flow_ratio,
|