market-maker-rs 0.1.2

A Rust library implementing quantitative market making strategies, starting with the Avellaneda-Stoikov model
Documentation
//! Quote structure and generation logic.

use crate::Decimal;

#[cfg(feature = "serde")]
use pretty_simple_display::{DebugPretty, DisplaySimple};

/// Represents a bid/ask quote pair generated by the strategy.
///
/// A quote contains the optimal bid and ask prices along with their sizes.
#[derive(Clone, PartialEq)]
#[cfg_attr(not(feature = "serde"), derive(Debug))]
#[cfg_attr(
    feature = "serde",
    derive(serde::Serialize, serde::Deserialize, DebugPretty, DisplaySimple)
)]
pub struct Quote {
    /// Bid price (price to buy at).
    pub bid_price: Decimal,

    /// Bid size (quantity to buy).
    pub bid_size: Decimal,

    /// Ask price (price to sell at).
    pub ask_price: Decimal,

    /// Ask size (quantity to sell).
    pub ask_size: Decimal,

    /// Timestamp when quote was generated, in milliseconds since Unix epoch.
    pub timestamp: u64,
}

impl Quote {
    /// Returns the spread (difference between ask and bid).
    #[must_use]
    pub fn spread(&self) -> Decimal {
        self.ask_price - self.bid_price
    }

    /// Returns the mid-price (average of bid and ask).
    #[must_use]
    pub fn mid_price(&self) -> Decimal {
        (self.bid_price + self.ask_price) / Decimal::from(2)
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::dec;

    #[test]
    fn test_quote_spread() {
        let quote = Quote {
            bid_price: dec!(100.0),
            bid_size: dec!(10.0),
            ask_price: dec!(101.0),
            ask_size: dec!(10.0),
            timestamp: 1000,
        };

        assert_eq!(quote.spread(), dec!(1.0));
    }

    #[test]
    fn test_quote_mid_price() {
        let quote = Quote {
            bid_price: dec!(100.0),
            bid_size: dec!(10.0),
            ask_price: dec!(102.0),
            ask_size: dec!(10.0),
            timestamp: 1000,
        };

        assert_eq!(quote.mid_price(), dec!(101.0));
    }

    #[test]
    fn test_quote_creation() {
        let quote = Quote {
            bid_price: dec!(99.5),
            bid_size: dec!(5.0),
            ask_price: dec!(100.5),
            ask_size: dec!(7.5),
            timestamp: 123456789,
        };

        assert_eq!(quote.bid_price, dec!(99.5));
        assert_eq!(quote.bid_size, dec!(5.0));
        assert_eq!(quote.ask_price, dec!(100.5));
        assert_eq!(quote.ask_size, dec!(7.5));
        assert_eq!(quote.timestamp, 123456789);
    }

    #[cfg(feature = "serde")]
    #[test]
    fn test_quote_display() {
        let quote = Quote {
            bid_price: dec!(100.0),
            bid_size: dec!(10.0),
            ask_price: dec!(101.0),
            ask_size: dec!(10.0),
            timestamp: 1000,
        };

        let display_str = format!("{}", quote);
        assert!(display_str.contains("bid_price"));
        assert!(display_str.contains("100"));
        assert!(display_str.contains("ask_price"));
        assert!(display_str.contains("101"));
    }
}