|
|
@@ -1,5 +1,5 @@
|
|
|
use std::cmp::{max, min};
|
|
|
-use std::collections::{BTreeMap, VecDeque};
|
|
|
+use std::collections::{BTreeMap, HashMap, VecDeque};
|
|
|
use std::sync::Arc;
|
|
|
use chrono::Utc;
|
|
|
use rust_decimal::prelude::*;
|
|
|
@@ -17,7 +17,8 @@ pub struct AvellanedaStoikov {
|
|
|
pub fair_price_vec: Vec<Decimal>, // 深度队列
|
|
|
pub trade_long_vec: FixedTimeRangeDeque<Trade>, // 交易队列
|
|
|
pub trade_short_vec: FixedTimeRangeDeque<Trade>, // 交易队列
|
|
|
- pub spread_vec: FixedTimeRangeDeque<Decimal>,
|
|
|
+ pub spread_vec: Vec<Decimal>, // 市场冲击队列
|
|
|
+ pub spread_count_map: HashMap<Decimal, usize>, // 市场次数的字典
|
|
|
pub record_vec: VecDeque<Record>, // 蜡烛队列
|
|
|
|
|
|
pub mid_price: Decimal, // 中间价
|
|
|
@@ -26,7 +27,7 @@ pub struct AvellanedaStoikov {
|
|
|
pub last_price: Decimal, // 最后成交价
|
|
|
pub spread: Decimal, // 市场冲击
|
|
|
pub spread_max: Decimal, // 最大市场冲击
|
|
|
- pub spread_min: Decimal, // 最小市场冲击
|
|
|
+ pub spread_best: Decimal, // 最佳市场冲击
|
|
|
pub optimal_ask_price: Decimal, // 卖出挂单价
|
|
|
pub optimal_bid_price: Decimal, // 买入挂单价
|
|
|
|
|
|
@@ -53,7 +54,7 @@ impl AvellanedaStoikov {
|
|
|
// 时间窗口大小(微秒)
|
|
|
const MAX_TIME_RANGE_MICROS: i64 = 3 * 60_000_000;
|
|
|
const TRADE_LONG_RANGE_MICROS: i64 = 3 * 60_000_000;
|
|
|
- const SPREAD_RANGE_MICROS: i64 = 15 * 60_000_000;
|
|
|
+ // const SPREAD_RANGE_MICROS: i64 = 15 * 60_000_000;
|
|
|
const TRADE_SHORT_RANGE_MICROS: i64 = 60_000_000;
|
|
|
// const ONE_MILLION: Decimal = dec!(1_000_000);
|
|
|
// const TWENTY_THOUSAND: Decimal = dec!(20_000);
|
|
|
@@ -66,7 +67,8 @@ impl AvellanedaStoikov {
|
|
|
fair_price_vec: vec![Decimal::ZERO; 10],
|
|
|
|
|
|
// 老的队列
|
|
|
- spread_vec: FixedTimeRangeDeque::new(Self::SPREAD_RANGE_MICROS),
|
|
|
+ spread_vec: vec![],
|
|
|
+ spread_count_map: Default::default(),
|
|
|
trade_long_vec: FixedTimeRangeDeque::new(Self::TRADE_LONG_RANGE_MICROS),
|
|
|
trade_short_vec: FixedTimeRangeDeque::new(Self::TRADE_SHORT_RANGE_MICROS),
|
|
|
record_vec: VecDeque::new(),
|
|
|
@@ -77,7 +79,7 @@ impl AvellanedaStoikov {
|
|
|
last_price: Default::default(),
|
|
|
spread: Default::default(),
|
|
|
spread_max: Default::default(),
|
|
|
- spread_min: Default::default(),
|
|
|
+ spread_best: Default::default(),
|
|
|
optimal_ask_price: Default::default(),
|
|
|
optimal_bid_price: Default::default(),
|
|
|
|
|
|
@@ -105,13 +107,28 @@ impl AvellanedaStoikov {
|
|
|
|
|
|
// 更新最大市场冲击
|
|
|
pub fn update_spread_max(&mut self) {
|
|
|
- self.spread_max = if let Some(&max_value) = self.spread_vec.deque.iter().max() {
|
|
|
+ self.spread_max = if let Some(&max_value) = self.spread_vec.iter().max() {
|
|
|
max_value
|
|
|
} else {
|
|
|
Decimal::NEGATIVE_ONE
|
|
|
};
|
|
|
}
|
|
|
|
|
|
+ // 更新最佳市场冲击
|
|
|
+ pub fn update_spread_best(&mut self) {
|
|
|
+ self.spread_best = self.spread_max;
|
|
|
+ let mut max_count = 0usize;
|
|
|
+
|
|
|
+ for (spread, count) in self.spread_count_map.iter() {
|
|
|
+ if *count < max_count {
|
|
|
+ continue
|
|
|
+ }
|
|
|
+
|
|
|
+ self.spread_best = *spread;
|
|
|
+ max_count = *count;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
pub fn update_spread(&mut self) {
|
|
|
let prev_depth_0 = &self.depth_vec[0];
|
|
|
if prev_depth_0.time.is_zero() {
|
|
|
@@ -122,8 +139,16 @@ impl AvellanedaStoikov {
|
|
|
let now_spread = (prev_mid_price - self.mid_price).abs();
|
|
|
if !now_spread.is_zero() {
|
|
|
self.spread = now_spread;
|
|
|
- self.spread_vec.push_back(self.spread);
|
|
|
+ self.spread_vec.push(self.spread);
|
|
|
+ self.spread_count_map.insert(self.spread, self.spread_count_map.get(&self.spread).unwrap_or(&0) + 1);
|
|
|
+
|
|
|
+ if self.spread_vec.len() > 100_000 {
|
|
|
+ let pop_value = self.spread_vec.remove(0);
|
|
|
+ self.spread_count_map.insert(pop_value, self.spread_count_map.get(&pop_value).unwrap() - 1);
|
|
|
+ }
|
|
|
+
|
|
|
self.update_spread_max();
|
|
|
+ self.update_spread_best();
|
|
|
}
|
|
|
}
|
|
|
|
|
|
@@ -208,7 +233,7 @@ impl AvellanedaStoikov {
|
|
|
}
|
|
|
|
|
|
pub fn update_sigma_square(&mut self) {
|
|
|
- self.sigma_square = self.spread_max * dec!(0.2);
|
|
|
+ self.sigma_square = self.spread_best;
|
|
|
self.sigma_square.rescale(10);
|
|
|
}
|
|
|
|
|
|
@@ -240,10 +265,10 @@ impl AvellanedaStoikov {
|
|
|
self.ask_delta = self.base_delta;
|
|
|
|
|
|
if self.inventory > Decimal::ZERO {
|
|
|
- self.ask_delta = self.base_delta * dec!(0.7);
|
|
|
+ self.ask_delta = self.base_delta;
|
|
|
// self.ask_delta = Decimal::NEGATIVE_ONE;
|
|
|
} else if self.inventory < Decimal::ZERO {
|
|
|
- self.bid_delta = self.base_delta * dec!(0.7);
|
|
|
+ self.bid_delta = self.base_delta;
|
|
|
// self.bid_delta = Decimal::NEGATIVE_ONE;
|
|
|
}
|
|
|
}
|
|
|
@@ -364,12 +389,12 @@ impl AvellanedaStoikov {
|
|
|
optimal_bid_price: self.optimal_bid_price,
|
|
|
|
|
|
inventory: self.inventory,
|
|
|
- sigma_square: self.spread_max,
|
|
|
+ sigma_square: self.sigma_square,
|
|
|
gamma: self.spread,
|
|
|
kappa: self.kappa,
|
|
|
|
|
|
flow_ratio: Decimal::ZERO,
|
|
|
- ref_price: self.ref_price,
|
|
|
+ ref_price: self.fair_price_vec[0],
|
|
|
});
|
|
|
}
|
|
|
|