|
|
@@ -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,
|
|
|
});
|
|
|
}
|