Skip to main content

solver/analytical/market_impact/approximations/
mod.rs

1use crate::analytical::traits::AnalyticalSolution;
2use crate::models::traits::ControlOutput;
3
4/// The asymptotic approximation for the Avellaneda-Stoikov model with Market Impact.
5pub struct AvellanedaImpactApprox {
6    pub gamma: f64,
7    pub sigma: f64,
8    pub kappa: f64,
9    pub a: f64,
10    pub xi: f64,
11}
12
13impl AvellanedaImpactApprox {
14    pub fn new(gamma: f64, sigma: f64, kappa: f64, a: f64, xi: f64) -> Self {
15        Self {
16            gamma,
17            sigma,
18            kappa,
19            a,
20            xi,
21        }
22    }
23
24    pub fn approximate_spreads(&self, q: f64) -> (f64, f64) {
25        let const_term = (1.0 / self.gamma) * (1.0 + self.gamma / self.kappa).ln();
26        let factor = (self.sigma.powi(2) * self.gamma / (2.0 * self.kappa * self.a)).sqrt()
27            * (1.0 + self.gamma / self.kappa).powf(0.5 * (1.0 + self.kappa / self.gamma));
28
29        let exp_xi = (self.kappa * self.xi / 4.0).exp();
30
31        let delta_bid = const_term + self.xi / 2.0 + (2.0 * q + 1.0) / 2.0 * exp_xi * factor;
32        let delta_ask = const_term + self.xi / 2.0 - (2.0 * q - 1.0) / 2.0 * exp_xi * factor;
33
34        (delta_bid, delta_ask)
35    }
36}
37
38impl AnalyticalSolution<2> for AvellanedaImpactApprox {
39    fn value_function(&self, _t: f64, _state: &[f64; 2]) -> f64 {
40        0.0
41    }
42
43    fn optimal_controls(&self, _t: f64, state: &[f64; 2]) -> ControlOutput<2> {
44        let q = state[0];
45        let (d_bid, d_ask) = self.approximate_spreads(q);
46
47        let lambda_bid = self.a * (-self.kappa * d_bid).exp();
48        let lambda_ask = self.a * (-self.kappa * d_ask).exp();
49
50        let flow = lambda_bid * d_bid + lambda_ask * d_ask;
51
52        ControlOutput {
53            lambda_plus: [lambda_bid, 0.0],
54            lambda_minus: [lambda_ask, 0.0],
55            flow,
56        }
57    }
58}