pub struct BilateralHawkesOrderFlowImbalance {}Expand description
Bilateral Hawkes model with price-impact-driven adverse selection.
§State Space: [q, lambda_plus, lambda_minus]
| dim | symbol | description |
|---|---|---|
| 0 | q | Inventory level (integer, jump-controlled) |
| 1 | lambda_plus | Buy market-order intensity (ODE drift, no noise) |
| 2 | lambda_minus | Sell market-order intensity (ODE drift, no noise) |
§Dynamics
d(lambda+) = beta*(mu - lambda+) dt + alpha dN+
d(lambda-) = beta*(mu - lambda-) dt + alpha dN-
dS = sigma dW + eta_ofi (dN+ - dN-)
Each buy market order (dN+) moves the mid price UP by eta_ofi; each sell market
order (dN-) moves it DOWN by eta_ofi. The market maker accounts for this
price impact when setting optimal spreads.
§Optimal Spreads Under Price Impact
Deriving the FOC from the CARA HJB with per-fill wealth effect (q±1)*eta_ofi gives:
$$ \delta_{bid}^* = \delta_{base} - \frac{\partial V}{\partial q} + (q+1)\eta_{OFI} $$ $$ \delta_{ask}^* = \delta_{base} + \frac{\partial V}{\partial q} - (q-1)\eta_{OFI} $$
Economic interpretation:
- Long inventory (q > 0): ask narrows (selling into a rising price is favourable), bid widens (avoid accumulating more when sell MOs push price down).
- Short inventory (q < 0): ask widens (avoid shorting further into a rising price), bid narrows (cover cheaply when sell MOs push price down).
Setting eta_ofi = 0 recovers the plain BilateralHawkes (BHK) model exactly.
In the simulation pass impact_factor = -eta_ofi to SimulatedDataSource so the
price process matches the assumed dynamics dS = sigma dW + eta_ofi (dN+ - dN-).
§Hawkes Approximation
Same fluid (mean-field) approximation as BilateralHawkes:
$$ d(\lambda_+)/dt \approx \beta(\mu - \lambda_+) + \alpha \lambda_+ $$ $$ d(\lambda_-)/dt \approx \beta(\mu - \lambda_-) + \alpha \lambda_- $$
Fields§
§gamma: f64Risk-aversion parameter.
sigma: f64Price volatility.
kappa: f64Fill-rate decay (Avellaneda-Stoikov kappa).
alpha: f64Jump size added to the excited side’s intensity.
beta: f64Mean-reversion speed.
mu: f64Baseline intensity (mean-reversion target).
eta_ofi: f64Price impact per fill event (eta_ofi in dS = sigmadW + eta_ofi(dN+ - dN-)). Higher eta_ofi = stronger q-dependent spread correction. Setting eta_ofi = 0 recovers the plain BilateralHawkes (BHK) model.
lambda_step: f64Grid step for both lambda+ and lambda- dimensions.
dq: f64Grid step for the inventory dimension.
q_min: f64Minimum inventory (lower hard boundary). Defaults to -infinity.
q_max: f64Maximum inventory (upper hard boundary). Defaults to +infinity.
terminal_condition: TerminalConditionTerminal condition for the value function at T. Defaults to Zero.
terminal_liquidation_half_spread: Option<f64>Optional terminal liquidation half-spread used when terminal_condition is LiquidationCost. If None, uses the AS base spread.
Implementations§
Source§impl BilateralHawkesOrderFlowImbalance
impl BilateralHawkesOrderFlowImbalance
pub fn new( gamma: f64, sigma: f64, kappa: f64, alpha: f64, beta: f64, mu: f64, eta_ofi: f64, ) -> Self
pub fn with_terminal_condition( self, terminal_condition: TerminalCondition, ) -> Self
pub fn with_terminal_liquidation_half_spread(self, half_spread: f64) -> Self
pub fn with_inventory_bounds(self, q_min: f64, q_max: f64) -> Self
pub fn with_lambda_step(self, lambda_step: f64) -> Self
pub fn with_dq(self, dq: f64) -> Self
Sourcepub fn get_spreads(&self, state: &[f64; 3], grads: &Gradients<3>) -> (f64, f64)
pub fn get_spreads(&self, state: &[f64; 3], grads: &Gradients<3>) -> (f64, f64)
Computes optimal bid/ask half-spreads with price-impact-driven inventory correction.
When eta_ofi > 0 each fill carries an adverse-selection wealth effect (q±1)*eta_ofi.
The FOC on the CARA HJB gives:
delta_bid = base_spread - dV/dq_fwd + (q+1)*eta_ofi
delta_ask = base_spread + dV/dq_bwd - (q-1)*eta_ofi
Long inventory (q > 0): ask narrows (sell into rising price), bid widens. Short inventory (q < 0): ask widens (avoid adding short), bid narrows. eta_ofi = 0 recovers the plain BHK spread formula identically.
Trait Implementations§
Source§impl Clone for BilateralHawkesOrderFlowImbalance
impl Clone for BilateralHawkesOrderFlowImbalance
Source§fn clone(&self) -> BilateralHawkesOrderFlowImbalance
fn clone(&self) -> BilateralHawkesOrderFlowImbalance
1.0.0 (const: unstable) · Source§fn clone_from(&mut self, source: &Self)
fn clone_from(&mut self, source: &Self)
source. Read moreSource§impl Model<3> for BilateralHawkesOrderFlowImbalance
impl Model<3> for BilateralHawkesOrderFlowImbalance
Source§fn next_step(
&self,
current_state: &[f64; 3],
dt: f64,
_noise: &[f64; 3],
) -> [f64; 3]
fn next_step( &self, current_state: &[f64; 3], dt: f64, _noise: &[f64; 3], ) -> [f64; 3]
Forward step using the fluid (mean-field) drift.
Source§fn next_step_controlled(
&self,
current_state: &[f64; 3],
control: &ControlOutput<3>,
dt: f64,
noise: &[f64; 3],
) -> [f64; 3]
fn next_step_controlled( &self, current_state: &[f64; 3], control: &ControlOutput<3>, dt: f64, noise: &[f64; 3], ) -> [f64; 3]
Coupled step: inventory jumps based on current fill probabilities.
Source§fn is_diffusion_dimension(&self, _dim: usize) -> bool
fn is_diffusion_dimension(&self, _dim: usize) -> bool
Both intensity dimensions follow deterministic ODE drift with no Brownian noise.
Source§fn fill_rate_base(&self, state: &[f64; 3]) -> f64
fn fill_rate_base(&self, state: &[f64; 3]) -> f64
The base arrival intensity is state-dependent: returns the average of the buy/sell intensity states for intensity-to-spread conversion.
Source§type Process = ()
type Process = ()
() for models without a corresponding market_model process.Source§fn optimize(&self, state: &[f64; 3], grads: &Gradients<3>) -> ControlOutput<3>
fn optimize(&self, state: &[f64; 3], grads: &Gradients<3>) -> ControlOutput<3>
Source§fn terminal(&self, state: &[f64; 3]) -> f64
fn terminal(&self, state: &[f64; 3]) -> f64
Source§fn constant_discount_rate(&self) -> Option<f64>
fn constant_discount_rate(&self) -> Option<f64>
Source§fn is_integer_dimension(&self, dim: usize) -> bool
fn is_integer_dimension(&self, dim: usize) -> bool
Source§fn gradient_step(&self, dim: usize) -> f64
fn gradient_step(&self, dim: usize) -> f64
Source§fn fill_rate_decay(&self) -> f64
fn fill_rate_decay(&self) -> f64
Source§fn discount_rate(&self, _state: &[f64; N]) -> f64
fn discount_rate(&self, _state: &[f64; N]) -> f64
Auto Trait Implementations§
impl Freeze for BilateralHawkesOrderFlowImbalance
impl RefUnwindSafe for BilateralHawkesOrderFlowImbalance
impl Send for BilateralHawkesOrderFlowImbalance
impl Sync for BilateralHawkesOrderFlowImbalance
impl Unpin for BilateralHawkesOrderFlowImbalance
impl UnsafeUnpin for BilateralHawkesOrderFlowImbalance
impl UnwindSafe for BilateralHawkesOrderFlowImbalance
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read more