use bot_core::{ClientOrderId, OrderSide, Price, Qty};
use rust_decimal::Decimal;
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub enum OrderState {
Idle,
Placed,
Active,
CancelPending,
}
impl Default for OrderState {
fn default() -> Self {
Self::Idle
}
}
#[derive(Debug, Clone, Default)]
pub struct SideState {
pub state: OrderState,
pub order_id: Option<ClientOrderId>,
pub price: Option<Price>,
pub size: Option<Qty>,
}
impl SideState {
pub fn new() -> Self {
Self::default()
}
pub fn reset(&mut self) {
self.state = OrderState::Idle;
self.order_id = None;
self.price = None;
self.size = None;
}
pub fn set_placed(&mut self, order_id: ClientOrderId, price: Price, size: Qty) {
self.state = OrderState::Placed;
self.order_id = Some(order_id);
self.price = Some(price);
self.size = Some(size);
}
pub fn set_active(&mut self) {
if self.state == OrderState::Placed {
self.state = OrderState::Active;
}
}
pub fn set_cancel_pending(&mut self) {
if self.state == OrderState::Active {
self.state = OrderState::CancelPending;
}
}
pub fn can_place(&self) -> bool {
self.state == OrderState::Idle
}
pub fn is_cancel_pending(&self) -> bool {
self.state == OrderState::CancelPending
}
}
#[derive(Debug, Clone, Default)]
pub struct InventoryMetrics {
pub current_qty: Decimal,
pub position_pct: Decimal,
pub inventory_ratio: Decimal,
pub imbalance: Decimal,
}
#[derive(Debug, Clone)]
pub struct SkewAdjustments {
pub price_skew: Decimal,
pub buy_size_mult: Decimal,
pub sell_size_mult: Decimal,
}
impl Default for SkewAdjustments {
fn default() -> Self {
Self {
price_skew: Decimal::ZERO,
buy_size_mult: Decimal::ONE,
sell_size_mult: Decimal::ONE,
}
}
}
#[derive(Debug, Clone)]
pub struct MarketMakerState {
pub mid_price: Option<Price>,
pub last_refresh_price: Option<Price>,
pub last_log_ts: i64,
pub current_position: Decimal,
pub buy_side: SideState,
pub sell_side: SideState,
pub order_registry: HashMap<String, OrderSide>,
pub inventory_metrics: InventoryMetrics,
pub skew_adjustments: SkewAdjustments,
pub exit_reason: Option<String>,
pub current_pnl: Option<Decimal>,
}
impl MarketMakerState {
pub fn new() -> Self {
Self {
mid_price: None,
last_refresh_price: None,
last_log_ts: 0,
current_position: Decimal::ZERO,
buy_side: SideState::new(),
sell_side: SideState::new(),
order_registry: HashMap::new(),
inventory_metrics: InventoryMetrics::default(),
skew_adjustments: SkewAdjustments::default(),
exit_reason: None,
current_pnl: None,
}
}
pub fn reset_all_orders(&mut self) {
self.buy_side.reset();
self.sell_side.reset();
self.order_registry.clear();
}
pub fn register_order(&mut self, client_id: &ClientOrderId, side: OrderSide) {
self.order_registry.insert(client_id.0.clone(), side);
}
pub fn unregister_order(&mut self, client_id: &ClientOrderId) -> Option<OrderSide> {
self.order_registry.remove(&client_id.0)
}
pub fn order_side(&self, client_id: &ClientOrderId) -> Option<OrderSide> {
self.order_registry.get(&client_id.0).copied()
}
pub fn side_mut(&mut self, side: OrderSide) -> &mut SideState {
match side {
OrderSide::Buy => &mut self.buy_side,
OrderSide::Sell => &mut self.sell_side,
}
}
pub fn side(&self, side: OrderSide) -> &SideState {
match side {
OrderSide::Buy => &self.buy_side,
OrderSide::Sell => &self.sell_side,
}
}
}
impl Default for MarketMakerState {
fn default() -> Self {
Self::new()
}
}