1use crate::ai_client::AiClient;
4use crate::risk_adjuster::RiskAdjuster;
5use crate::spread::{FixedSpreadModel, SpreadModel};
6use fx_md::Quote;
7use fx_risk::RiskEngine;
8use fx_utils::{Price, Result};
9use std::sync::Arc;
10
11pub struct PricingEngine {
13 spread_model: Box<dyn SpreadModel + Send + Sync>,
14 risk_adjuster: RiskAdjuster,
15 ai_client: Option<Arc<AiClient>>,
16}
17
18impl PricingEngine {
19 pub fn new() -> Self {
20 Self {
21 spread_model: Box::new(FixedSpreadModel::new(2)), risk_adjuster: RiskAdjuster::new(None),
23 ai_client: None,
24 }
25 }
26
27 pub fn with_risk_engine(mut self, risk_engine: Arc<RiskEngine>) -> Self {
28 self.risk_adjuster = RiskAdjuster::new(Some(risk_engine));
29 self
30 }
31
32 pub fn with_ai_client(mut self, ai_client: Arc<AiClient>) -> Self {
33 self.ai_client = Some(ai_client);
34 self
35 }
36
37 pub async fn calculate_prices(&self, base_quote: &Quote) -> Result<(Price, Price)> {
38 let mid = base_quote.mid_price();
39
40 let volatility = if let Some(ai_client) = &self.ai_client {
42 ai_client
43 .predict_volatility(&base_quote.instrument)
44 .await
45 .unwrap_or(0.0) } else {
47 0.0
48 };
49
50 let spread = self.spread_model.calculate_spread(mid, volatility);
51
52 let bid = Price(mid.0.saturating_sub(spread.0 / 2));
53 let ask = Price(mid.0 + spread.0 / 2);
54
55 let (adjusted_bid, adjusted_ask) =
57 self.risk_adjuster
58 .adjust_prices(&base_quote.instrument, bid, ask);
59
60 Ok((adjusted_bid, adjusted_ask))
61 }
62}
63
64impl Default for PricingEngine {
65 fn default() -> Self {
66 Self::new()
67 }
68}