|
|
@@ -9,17 +9,20 @@ use tracing::info;
|
|
|
use global::cci::CentralControlInfo;
|
|
|
use global::fixed_time_range_deque::FixedTimeRangeDeque;
|
|
|
use global::predictor_state::PredictorState;
|
|
|
-use standard::{Depth, Ticker, Trade};
|
|
|
+use standard::{Depth, Record, 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 record_vec: FixedTimeRangeDeque<Record>, // 蜡烛队列
|
|
|
|
|
|
pub mid_price: Decimal, // 中间价
|
|
|
pub ask_price: Decimal, // 卖一价
|
|
|
pub bid_price: Decimal, // 买一价
|
|
|
+ pub last_price: Decimal, // 最后成交价
|
|
|
pub spread: Decimal, // 市场冲击
|
|
|
pub spread_max: Decimal, // 最大市场冲击
|
|
|
pub spread_min: Decimal, // 最小市场冲击
|
|
|
@@ -27,18 +30,20 @@ pub struct AvellanedaStoikov {
|
|
|
pub optimal_bid_price: Decimal, // 买入挂单价
|
|
|
|
|
|
pub inventory: Decimal, // 库存,也就是q
|
|
|
+ pub level: Decimal, // martin
|
|
|
pub sigma_square: Decimal, // σ^2,波动性的平方
|
|
|
pub gamma: Decimal, // γ,库存风险厌恶参数
|
|
|
pub kappa: Decimal, // κ 订单簿 流动性 参数
|
|
|
|
|
|
- pub flow_in_value: Decimal,
|
|
|
- pub flow_out_value: Decimal,
|
|
|
- pub flow_ratio: Decimal, // 资金流比例
|
|
|
- pub flow_ratio_diff_log: Decimal, // 一阶导数
|
|
|
+ pub flow_ratio_long: Decimal, // 资金流比例
|
|
|
+ pub flow_ratio_short: Decimal, // 资金流比例
|
|
|
|
|
|
- pub delta_ask: Decimal, // δa
|
|
|
- pub delta_bid: Decimal, // δb
|
|
|
+ pub ask_delta: Decimal, // δa
|
|
|
+ pub bid_delta: Decimal, // δb
|
|
|
+ pub base_delta: Decimal, // 基础挂单距离
|
|
|
+ pub ratio_edge: Decimal, // 资金流修正的挂单距离
|
|
|
pub ref_price: Decimal, // 预定价格
|
|
|
+ pub init_delta_plus: Decimal, // 最初的delta之和
|
|
|
|
|
|
pub cci_arc: Arc<Mutex<CentralControlInfo>>, // 中控信息
|
|
|
|
|
|
@@ -50,20 +55,26 @@ pub struct AvellanedaStoikov {
|
|
|
impl AvellanedaStoikov {
|
|
|
// 时间窗口大小(微秒)
|
|
|
const MAX_TIME_RANGE_MICROS: i64 = 3 * 60_000_000;
|
|
|
- const ONE_MILLION: Decimal = dec!(1_000_000);
|
|
|
- const TWENTY_THOUSAND: Decimal = dec!(20_000);
|
|
|
+ const RECORD_RANGE_MICROS: i64 = 4 * 60_000_000;
|
|
|
+ const TRADE_LONG_RANGE_MICROS: i64 = 3 * 60_000_000;
|
|
|
+ const TRADE_SHORT_RANGE_MICROS: i64 = 20_000_000;
|
|
|
+ // const ONE_MILLION: Decimal = dec!(1_000_000);
|
|
|
+ // const TWENTY_THOUSAND: Decimal = dec!(20_000);
|
|
|
const IRA: Decimal = dec!(1);
|
|
|
-
|
|
|
+
|
|
|
pub fn new(cci_arc: Arc<Mutex<CentralControlInfo>>) -> Self {
|
|
|
let avellaneda_stoikov = Self {
|
|
|
// 分别给与的长度
|
|
|
depth_vec: FixedTimeRangeDeque::new(Self::MAX_TIME_RANGE_MICROS),
|
|
|
- trade_vec: FixedTimeRangeDeque::new(Self::MAX_TIME_RANGE_MICROS),
|
|
|
spread_vec: FixedTimeRangeDeque::new(Self::MAX_TIME_RANGE_MICROS),
|
|
|
+ trade_long_vec: FixedTimeRangeDeque::new(Self::TRADE_LONG_RANGE_MICROS),
|
|
|
+ trade_short_vec: FixedTimeRangeDeque::new(Self::TRADE_SHORT_RANGE_MICROS),
|
|
|
+ record_vec: FixedTimeRangeDeque::new(Self::RECORD_RANGE_MICROS),
|
|
|
|
|
|
mid_price: Default::default(),
|
|
|
ask_price: Default::default(),
|
|
|
bid_price: Default::default(),
|
|
|
+ last_price: Default::default(),
|
|
|
spread: Default::default(),
|
|
|
spread_max: Default::default(),
|
|
|
spread_min: Default::default(),
|
|
|
@@ -73,20 +84,23 @@ impl AvellanedaStoikov {
|
|
|
inventory: Default::default(),
|
|
|
gamma: Default::default(),
|
|
|
sigma_square: Default::default(),
|
|
|
- delta_ask: Default::default(),
|
|
|
- delta_bid: Default::default(),
|
|
|
+ ask_delta: Default::default(),
|
|
|
+ bid_delta: Default::default(),
|
|
|
+ base_delta: Default::default(),
|
|
|
+ init_delta_plus: Default::default(),
|
|
|
+
|
|
|
+ ratio_edge: Default::default(),
|
|
|
kappa: Default::default(),
|
|
|
- flow_in_value: Default::default(),
|
|
|
ref_price: Default::default(),
|
|
|
|
|
|
cci_arc,
|
|
|
|
|
|
is_ready: false,
|
|
|
- prev_trade_time: 0,
|
|
|
+ prev_trade_time: Utc::now().timestamp_micros(),
|
|
|
t_diff: Default::default(),
|
|
|
- flow_ratio: Decimal::ONE,
|
|
|
- flow_ratio_diff_log: Default::default(),
|
|
|
- flow_out_value: Default::default(),
|
|
|
+ flow_ratio_long: Decimal::ONE,
|
|
|
+ level: Default::default(),
|
|
|
+ flow_ratio_short: Default::default(),
|
|
|
};
|
|
|
|
|
|
avellaneda_stoikov
|
|
|
@@ -111,14 +125,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;
|
|
|
}
|
|
|
@@ -147,84 +161,74 @@ impl AvellanedaStoikov {
|
|
|
}
|
|
|
|
|
|
pub async fn on_trade(&mut self, trade: &Trade) {
|
|
|
- if trade.size > Decimal::ZERO {
|
|
|
- self.flow_in_value += trade.value;
|
|
|
- } else {
|
|
|
- self.flow_out_value += trade.value;
|
|
|
- }
|
|
|
- if self.flow_in_value + self.flow_out_value > Self::ONE_MILLION {
|
|
|
- self.flow_in_value = self.flow_in_value * dec!(0.618);
|
|
|
- self.flow_out_value = self.flow_out_value * dec!(0.618);
|
|
|
- }
|
|
|
+ self.trade_long_vec.push_back(trade.clone());
|
|
|
+ self.trade_short_vec.push_back(trade.clone());
|
|
|
|
|
|
- self.trade_vec.push_back(trade.clone());
|
|
|
+ self.last_price = trade.price;
|
|
|
self.update_spread();
|
|
|
self.processor().await;
|
|
|
}
|
|
|
|
|
|
- pub async fn update_inventory(&mut self, inventory: &Decimal, step_size: &Decimal) {
|
|
|
- let new_inventory = inventory / step_size;
|
|
|
+ pub async fn update_level(&mut self) {
|
|
|
+ self.level = (Decimal::NEGATIVE_ONE + (Decimal::ONE + dec!(8) * self.inventory.abs()).sqrt().unwrap()) / Decimal::TWO;
|
|
|
+ self.level = min(self.level, dec!(6));
|
|
|
+ }
|
|
|
|
|
|
- if self.inventory.abs() < new_inventory.abs() {
|
|
|
- self.prev_trade_time = Utc::now().timestamp_micros();
|
|
|
+ pub async fn on_ticker(&mut self, _ticker: &Ticker) {}
|
|
|
+
|
|
|
+ pub async fn on_record(&mut self, record: &Record) {
|
|
|
+ // 添加新蜡烛
|
|
|
+ if self.record_vec.len() == 0 {
|
|
|
+ self.record_vec.push_back(record.clone());
|
|
|
+ } else {
|
|
|
+ let last_record = self.record_vec.deque.back_mut().unwrap();
|
|
|
+
|
|
|
+ if last_record.time == record.time {
|
|
|
+ *last_record = record.clone();
|
|
|
+ } else if last_record.time < record.time {
|
|
|
+ self.record_vec.push_back(record.clone());
|
|
|
+ }
|
|
|
}
|
|
|
+ }
|
|
|
|
|
|
- self.inventory = new_inventory;
|
|
|
+ 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();
|
|
|
+ if prev_inventory != self.inventory {
|
|
|
+ self.prev_trade_time = Utc::now().timestamp_micros();
|
|
|
+ }
|
|
|
|
|
|
+ self.update_level().await;
|
|
|
self.processor().await;
|
|
|
}
|
|
|
|
|
|
pub fn update_sigma_square(&mut self) {
|
|
|
- self.sigma_square = if self.trade_vec.len() < 2 {
|
|
|
- Decimal::ZERO
|
|
|
- } else {
|
|
|
- let last_trade = self.trade_vec.get(self.trade_vec.len() - 1).unwrap();
|
|
|
-
|
|
|
- let mut volatility_total = Decimal::ZERO;
|
|
|
- for index in (0..self.trade_vec.len()).rev() {
|
|
|
- if index == self.trade_vec.len() - 1 {
|
|
|
- continue
|
|
|
- }
|
|
|
- let trade = self.trade_vec.get(index).unwrap();
|
|
|
-
|
|
|
- if last_trade.time - trade.time > Decimal::ONE_THOUSAND {
|
|
|
- break;
|
|
|
- }
|
|
|
-
|
|
|
- let prev_trade = self.trade_vec.get(index + 1).unwrap();
|
|
|
- let volatility = (trade.price - prev_trade.price).abs();
|
|
|
- volatility_total += volatility;
|
|
|
- }
|
|
|
-
|
|
|
- volatility_total / Decimal::TEN
|
|
|
- };
|
|
|
-
|
|
|
+ self.sigma_square = self.spread_max * dec!(0.5);
|
|
|
self.sigma_square.rescale(10);
|
|
|
}
|
|
|
|
|
|
pub fn update_gamma(&mut self) {
|
|
|
- self.gamma = Decimal::ONE + Self::IRA * (self.spread_max / self.spread_min).sqrt().unwrap() / Decimal::TEN;
|
|
|
- self.gamma.rescale(8);
|
|
|
+ // 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) {
|
|
|
- // if self.spread_max == Decimal::ZERO {
|
|
|
- // self.kappa = Decimal::ONE;
|
|
|
+ // self.kappa = if self.spread_max.is_zero() || self.init_delta_plus.is_zero() {
|
|
|
+ // Decimal::ONE
|
|
|
// } else {
|
|
|
- // let delta_plus_max = (Decimal::TWO - Self::IRA) * self.spread_max + Self::IRA * self.spread_min;
|
|
|
- // let mut temp = (delta_plus_max) * self.gamma - self.sigma_square * self.gamma.powd(Decimal::TWO);
|
|
|
- //
|
|
|
+ // let mut temp = self.init_delta_plus * self.gamma - self.sigma_square * self.gamma.powd(Decimal::TWO);
|
|
|
// temp.rescale(6);
|
|
|
//
|
|
|
- // self.kappa = if temp <= Decimal::ZERO {
|
|
|
- // Decimal::TEN
|
|
|
- // } else if temp >= Decimal::TEN {
|
|
|
- // Decimal::TEN
|
|
|
- // } else {
|
|
|
- // self.gamma / (temp.exp() - Decimal::ONE)
|
|
|
- // };
|
|
|
- // self.kappa.rescale(8);
|
|
|
- // }
|
|
|
+ // self.gamma / (temp.exp() - Decimal::ONE)
|
|
|
+ // };
|
|
|
+ //
|
|
|
+ // self.kappa.rescale(8);
|
|
|
|
|
|
if self.mid_price > Decimal::ZERO {
|
|
|
self.kappa = dec!(888) / self.mid_price;
|
|
|
@@ -234,73 +238,177 @@ impl AvellanedaStoikov {
|
|
|
}
|
|
|
|
|
|
pub fn update_ref_price(&mut self) {
|
|
|
- self.ref_price = self.mid_price - self.inventory * self.gamma * self.sigma_square * self.t_diff;
|
|
|
+ self.ref_price = self.mid_price;
|
|
|
}
|
|
|
|
|
|
pub fn update_delta(&mut self) {
|
|
|
if self.gamma != Decimal::ZERO {
|
|
|
- let a = (self.gamma * self.sigma_square * self.t_diff) / Decimal::TWO;
|
|
|
- // let edge = (self.flow_ratio_diff_log.abs() / dec!(0.0003)) * self.gamma * self.sigma_square * self.t_diff;
|
|
|
+ let pos_edge = self.gamma * self.sigma_square * self.inventory.abs().powd(dec!(2)) * self.t_diff;
|
|
|
|
|
|
- self.delta_bid = {
|
|
|
- let b = (Decimal::ONE / self.gamma) * (Decimal::ONE + self.gamma / self.kappa).ln();
|
|
|
+ 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.ratio_edge = self.flow_ratio_long * self.sigma_square;
|
|
|
|
|
|
- a + b
|
|
|
- };
|
|
|
+ self.bid_delta = self.base_delta;
|
|
|
+ self.ask_delta = self.base_delta;
|
|
|
|
|
|
- self.delta_ask = {
|
|
|
- let b = (Decimal::ONE / self.gamma) * (Decimal::ONE + self.gamma / self.kappa).ln();
|
|
|
+ if self.inventory > Decimal::ZERO {
|
|
|
+ self.bid_delta += pos_edge;
|
|
|
+ } else if self.inventory < Decimal::ZERO {
|
|
|
+ self.ask_delta += pos_edge;
|
|
|
+ }
|
|
|
|
|
|
- a + b
|
|
|
- };
|
|
|
+ if self.ratio_edge > Decimal::ZERO {
|
|
|
+ self.ask_delta = self.ask_delta - self.ratio_edge.abs() * (Decimal::TWO - self.t_diff);
|
|
|
+ self.bid_delta = self.bid_delta + self.ratio_edge.abs() * dec!(16);
|
|
|
+ } else if self.ratio_edge < Decimal::ZERO {
|
|
|
+ self.ask_delta = self.ask_delta + self.ratio_edge.abs() * dec!(16);
|
|
|
+ self.bid_delta = self.bid_delta - self.ratio_edge.abs() * (Decimal::TWO - self.t_diff);
|
|
|
+ }
|
|
|
+
|
|
|
+ if self.init_delta_plus.is_zero() {
|
|
|
+ self.init_delta_plus = (self.bid_delta + self.ask_delta) / Decimal::TWO
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
|
|
|
pub fn update_optimal_ask_and_bid(&mut self) {
|
|
|
- self.optimal_ask_price = max(self.ref_price + self.delta_ask / Decimal::TWO, self.ask_price);
|
|
|
- self.optimal_bid_price = min(self.ref_price - self.delta_bid / Decimal::TWO, self.bid_price);
|
|
|
+ self.optimal_ask_price = max(self.ref_price + self.ask_delta / Decimal::TWO, self.ask_price);
|
|
|
+ self.optimal_bid_price = min(self.ref_price - self.bid_delta / Decimal::TWO, self.bid_price);
|
|
|
}
|
|
|
|
|
|
pub fn update_t_diff(&mut self) {
|
|
|
- // let time_diff_decimal = Decimal::from_i64(Utc::now().timestamp_micros() - self.prev_trade_time).unwrap();
|
|
|
- // self.t_diff = time_diff_decimal / Decimal::from_i64(Self::MAX_TIME_RANGE_MICROS).unwrap();
|
|
|
- // self.t_diff = min(self.t_diff, Decimal::ONE);
|
|
|
- self.t_diff = Decimal::ONE;
|
|
|
+ if self.prev_trade_time > 0 {
|
|
|
+ let time_diff_decimal = Decimal::from_i64(Utc::now().timestamp_micros() - self.prev_trade_time).unwrap();
|
|
|
+ self.t_diff = max(Decimal::ONE - time_diff_decimal / Decimal::from_i64(Self::MAX_TIME_RANGE_MICROS).unwrap(), Decimal::ZERO);
|
|
|
+ } else {
|
|
|
+ self.t_diff = Decimal::ONE;
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
- pub fn update_flow_ratio(&mut self) {
|
|
|
- let prev_flow_ratio = self.flow_ratio;
|
|
|
- self.flow_ratio = if self.trade_vec.len() < 2 {
|
|
|
- Decimal::ZERO
|
|
|
- } else {
|
|
|
- if self.flow_out_value + self.flow_in_value <= Self::TWENTY_THOUSAND {
|
|
|
- Decimal::ZERO
|
|
|
+ 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() {
|
|
|
+ if trade_iter.size > Decimal::ZERO {
|
|
|
+ flow_in_value += trade_iter.value;
|
|
|
} else {
|
|
|
- self.flow_in_value / self.flow_out_value
|
|
|
+ flow_out_value += trade_iter.value;
|
|
|
}
|
|
|
- };
|
|
|
+ }
|
|
|
|
|
|
- self.flow_ratio.rescale(6);
|
|
|
- self.flow_ratio = if self.flow_ratio > Decimal::TEN {
|
|
|
- Decimal::ZERO
|
|
|
- } else if self.flow_ratio < dec!(-10) {
|
|
|
- Decimal::ZERO
|
|
|
+ // 使用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 {
|
|
|
- self.flow_ratio
|
|
|
- };
|
|
|
+ Decimal::ZERO
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
- if self.flow_ratio != Decimal::ZERO {
|
|
|
- if prev_flow_ratio != Decimal::ZERO && self.flow_ratio != prev_flow_ratio {
|
|
|
- let flow_ratio_diff = self.flow_ratio - prev_flow_ratio;
|
|
|
- let temp = if flow_ratio_diff > Decimal::ZERO {
|
|
|
- (flow_ratio_diff + Decimal::ONE).ln()
|
|
|
- } else {
|
|
|
- (flow_ratio_diff.abs() + Decimal::ONE).ln() * Decimal::NEGATIVE_ONE
|
|
|
- };
|
|
|
+ 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
|
|
|
+ }
|
|
|
|
|
|
- self.flow_ratio_diff_log = temp * dec!(0.03) + self.flow_ratio_diff_log * dec!(0.97)
|
|
|
+ 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_long = Self::calc_flow_ratio_2(&self.flow_ratio_long, &dec!(0), &mut self.trade_long_vec);
|
|
|
+ self.flow_ratio_short = Self::calc_flow_ratio(&self.flow_ratio_short, &dec!(0), &mut self.trade_long_vec);
|
|
|
}
|
|
|
|
|
|
pub fn check_ready(&mut self) {
|
|
|
@@ -320,11 +428,11 @@ impl AvellanedaStoikov {
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
- if self.optimal_ask_price <= self.ask_price {
|
|
|
+ if self.optimal_ask_price < self.ask_price {
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
- if self.optimal_bid_price >= self.bid_price {
|
|
|
+ if self.optimal_bid_price > self.bid_price {
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
@@ -332,7 +440,7 @@ impl AvellanedaStoikov {
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
- if self.trade_vec.len() < 100 {
|
|
|
+ if self.trade_long_vec.len() < 100 {
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
@@ -345,7 +453,7 @@ impl AvellanedaStoikov {
|
|
|
self.update_t_diff();
|
|
|
// info!(?self.t_diff);
|
|
|
self.update_flow_ratio();
|
|
|
- // info!(?self.flow_ratio);
|
|
|
+ // info!(?self.flow_ratio_long);
|
|
|
self.update_sigma_square();
|
|
|
// info!(?self.sigma_square);
|
|
|
self.update_gamma();
|
|
|
@@ -355,7 +463,7 @@ impl AvellanedaStoikov {
|
|
|
self.update_ref_price();
|
|
|
// info!(?self.ref_price);
|
|
|
self.update_delta();
|
|
|
- // info!(?self.delta_ask, ?self.delta_bid);
|
|
|
+ // info!(?self.ask_delta, ?self.bid_delta);
|
|
|
self.update_optimal_ask_and_bid();
|
|
|
// info!("=============================================");
|
|
|
|
|
|
@@ -368,23 +476,23 @@ impl AvellanedaStoikov {
|
|
|
cci.predictor_state_vec.push_back(PredictorState {
|
|
|
update_time: Decimal::from_i64(Utc::now().timestamp_millis()).unwrap(),
|
|
|
|
|
|
- mid_price: self.mid_price,
|
|
|
+ mid_price: self.last_price,
|
|
|
ask_price: self.ask_price,
|
|
|
bid_price: self.bid_price,
|
|
|
+ last_price: self.last_price,
|
|
|
spread: self.spread,
|
|
|
- spread_max: self.spread_max,
|
|
|
- spread_min: self.spread_min,
|
|
|
+ spread_max: self.ask_delta,
|
|
|
+ spread_min: self.bid_delta,
|
|
|
optimal_ask_price: self.optimal_ask_price,
|
|
|
optimal_bid_price: self.optimal_bid_price,
|
|
|
|
|
|
inventory: self.inventory,
|
|
|
- sigma_square: self.sigma_square,
|
|
|
- gamma: self.gamma,
|
|
|
- kappa: self.kappa,
|
|
|
+ sigma_square: self.flow_ratio_long,
|
|
|
+ gamma: self.flow_ratio_short,
|
|
|
+ kappa: self.t_diff,
|
|
|
|
|
|
- flow_ratio: self.flow_ratio_diff_log,
|
|
|
+ flow_ratio: self.flow_ratio_long,
|
|
|
ref_price: self.ref_price,
|
|
|
- last_price: self.mid_price,
|
|
|
});
|
|
|
}
|
|
|
|