solver/analytical/drift/approximations/
mod.rs1use crate::analytical::traits::AnalyticalSolution;
2use crate::models::traits::ControlOutput;
3
4pub struct AvellanedaDriftApprox {
6 pub gamma: f64,
7 pub sigma: f64,
8 pub kappa: f64,
9 pub a: f64,
10 pub mu: f64,
11}
12
13impl AvellanedaDriftApprox {
14 pub fn new(gamma: f64, sigma: f64, kappa: f64, a: f64, mu: f64) -> Self {
15 Self {
16 gamma,
17 sigma,
18 kappa,
19 a,
20 mu,
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 term_bid = -self.mu / (self.gamma * self.sigma.powi(2)) + (2.0 * q + 1.0) / 2.0;
30 let term_ask = self.mu / (self.gamma * self.sigma.powi(2)) - (2.0 * q - 1.0) / 2.0;
31
32 let delta_bid = const_term + term_bid * factor;
33 let delta_ask = const_term + term_ask * factor;
34
35 (delta_bid, delta_ask)
36 }
37}
38
39impl AnalyticalSolution<2> for AvellanedaDriftApprox {
40 fn value_function(&self, _t: f64, _state: &[f64; 2]) -> f64 {
41 0.0
42 }
43
44 fn optimal_controls(&self, _t: f64, state: &[f64; 2]) -> ControlOutput<2> {
45 let q = state[0];
46 let (d_bid, d_ask) = self.approximate_spreads(q);
47
48 let lambda_bid = self.a * (-self.kappa * d_bid).exp();
49 let lambda_ask = self.a * (-self.kappa * d_ask).exp();
50
51 let flow = lambda_bid * d_bid + lambda_ask * d_ask;
52
53 ControlOutput {
54 lambda_plus: [lambda_bid, 0.0],
55 lambda_minus: [lambda_ask, 0.0],
56 flow,
57 }
58 }
59}