use crate::Decimal;
use crate::types::error::MMResult;
use async_trait::async_trait;
pub trait AvellanedaStoikov {
fn calculate_reservation_price(
&self,
mid_price: Decimal,
inventory: Decimal,
risk_aversion: Decimal,
volatility: Decimal,
time_to_terminal_ms: u64,
) -> MMResult<Decimal>;
fn calculate_optimal_spread(
&self,
risk_aversion: Decimal,
volatility: Decimal,
time_to_terminal_ms: u64,
order_intensity: Decimal,
) -> MMResult<Decimal>;
fn calculate_optimal_quotes(
&self,
mid_price: Decimal,
inventory: Decimal,
risk_aversion: Decimal,
volatility: Decimal,
time_to_terminal_ms: u64,
order_intensity: Decimal,
) -> MMResult<(Decimal, Decimal)>;
}
#[async_trait]
pub trait AsyncAvellanedaStoikov {
async fn calculate_reservation_price(
&self,
mid_price: Decimal,
inventory: Decimal,
risk_aversion: Decimal,
volatility: Decimal,
time_to_terminal_ms: u64,
) -> MMResult<Decimal>;
async fn calculate_optimal_spread(
&self,
risk_aversion: Decimal,
volatility: Decimal,
time_to_terminal_ms: u64,
order_intensity: Decimal,
) -> MMResult<Decimal>;
async fn calculate_optimal_quotes(
&self,
mid_price: Decimal,
inventory: Decimal,
risk_aversion: Decimal,
volatility: Decimal,
time_to_terminal_ms: u64,
order_intensity: Decimal,
) -> MMResult<(Decimal, Decimal)>;
}
#[derive(Debug, Clone, Copy, Default)]
pub struct DefaultAvellanedaStoikov;
impl AvellanedaStoikov for DefaultAvellanedaStoikov {
fn calculate_reservation_price(
&self,
mid_price: Decimal,
inventory: Decimal,
risk_aversion: Decimal,
volatility: Decimal,
time_to_terminal_ms: u64,
) -> MMResult<Decimal> {
crate::strategy::avellaneda_stoikov::calculate_reservation_price(
mid_price,
inventory,
risk_aversion,
volatility,
time_to_terminal_ms,
)
}
fn calculate_optimal_spread(
&self,
risk_aversion: Decimal,
volatility: Decimal,
time_to_terminal_ms: u64,
order_intensity: Decimal,
) -> MMResult<Decimal> {
crate::strategy::avellaneda_stoikov::calculate_optimal_spread(
risk_aversion,
volatility,
time_to_terminal_ms,
order_intensity,
)
}
fn calculate_optimal_quotes(
&self,
mid_price: Decimal,
inventory: Decimal,
risk_aversion: Decimal,
volatility: Decimal,
time_to_terminal_ms: u64,
order_intensity: Decimal,
) -> MMResult<(Decimal, Decimal)> {
crate::strategy::avellaneda_stoikov::calculate_optimal_quotes(
mid_price,
inventory,
risk_aversion,
volatility,
time_to_terminal_ms,
order_intensity,
)
}
}
#[async_trait]
impl AsyncAvellanedaStoikov for DefaultAvellanedaStoikov {
async fn calculate_reservation_price(
&self,
mid_price: Decimal,
inventory: Decimal,
risk_aversion: Decimal,
volatility: Decimal,
time_to_terminal_ms: u64,
) -> MMResult<Decimal> {
crate::strategy::avellaneda_stoikov::calculate_reservation_price(
mid_price,
inventory,
risk_aversion,
volatility,
time_to_terminal_ms,
)
}
async fn calculate_optimal_spread(
&self,
risk_aversion: Decimal,
volatility: Decimal,
time_to_terminal_ms: u64,
order_intensity: Decimal,
) -> MMResult<Decimal> {
crate::strategy::avellaneda_stoikov::calculate_optimal_spread(
risk_aversion,
volatility,
time_to_terminal_ms,
order_intensity,
)
}
async fn calculate_optimal_quotes(
&self,
mid_price: Decimal,
inventory: Decimal,
risk_aversion: Decimal,
volatility: Decimal,
time_to_terminal_ms: u64,
order_intensity: Decimal,
) -> MMResult<(Decimal, Decimal)> {
crate::strategy::avellaneda_stoikov::calculate_optimal_quotes(
mid_price,
inventory,
risk_aversion,
volatility,
time_to_terminal_ms,
order_intensity,
)
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::dec;
#[test]
fn test_default_avellaneda_stoikov_sync() {
let strategy = DefaultAvellanedaStoikov;
let (bid, ask) = <DefaultAvellanedaStoikov as AvellanedaStoikov>::calculate_optimal_quotes(
&strategy,
dec!(100.0),
dec!(0.0),
dec!(0.1),
dec!(0.2),
3600000,
dec!(1.5),
)
.unwrap();
assert!(bid < ask);
assert!(bid < dec!(100.0));
assert!(ask > dec!(100.0));
}
#[test]
fn test_default_reservation_price_sync() {
let strategy = DefaultAvellanedaStoikov;
let reservation =
<DefaultAvellanedaStoikov as AvellanedaStoikov>::calculate_reservation_price(
&strategy,
dec!(100.0),
dec!(10.0),
dec!(0.1),
dec!(0.2),
3600000,
)
.unwrap();
assert!(reservation < dec!(100.0)); }
#[test]
fn test_default_optimal_spread_sync() {
let strategy = DefaultAvellanedaStoikov;
let spread = <DefaultAvellanedaStoikov as AvellanedaStoikov>::calculate_optimal_spread(
&strategy,
dec!(0.1),
dec!(0.2),
3600000,
dec!(1.5),
)
.unwrap();
assert!(spread > Decimal::ZERO);
}
#[tokio::test]
async fn test_default_avellaneda_stoikov_async() {
let strategy = DefaultAvellanedaStoikov;
let (bid, ask) =
<DefaultAvellanedaStoikov as AsyncAvellanedaStoikov>::calculate_optimal_quotes(
&strategy,
dec!(100.0),
dec!(0.0),
dec!(0.1),
dec!(0.2),
3600000,
dec!(1.5),
)
.await
.unwrap();
assert!(bid < ask);
assert!(bid < dec!(100.0));
assert!(ask > dec!(100.0));
}
}