quant-primitives 0.7.0

Pure trading primitives — candles, intervals, symbols, currencies, asset taxonomy
Documentation
//! Validated fraction value object.
//!
//! Represents a value in the range [0, 1] — the result of converting
//! percentages or basis points to a multiplicative factor.
//!
//! `Fraction(0.05)` means 5% — used directly in arithmetic:
//! `capital * fraction.value()` gives the position size.

use std::fmt;

use rust_decimal::Decimal;
use serde::{Deserialize, Serialize};

/// A fraction value validated to the range [0, 1].
///
/// Produced by `Percentage::to_fraction()` and `Bps::to_fraction()`.
/// Used directly in multiplication: `notional * fraction.value()`.
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
pub struct Fraction(pub(crate) Decimal);

/// Error for invalid fraction construction.
#[derive(Debug, Clone, PartialEq, Eq, thiserror::Error)]
pub enum FractionError {
    /// Value is outside the valid [0, 1] range.
    #[error("fraction {0} out of range [0, 1]")]
    OutOfRange(Decimal),
}

impl Fraction {
    /// Create a new fraction, validating that the value is in [0, 1].
    pub fn new(value: Decimal) -> Result<Self, FractionError> {
        if value < Decimal::ZERO || value > Decimal::ONE {
            return Err(FractionError::OutOfRange(value));
        }
        Ok(Self(value))
    }

    /// The raw fraction value (0-1).
    pub fn value(&self) -> Decimal {
        self.0
    }

    /// The zero fraction.
    pub fn zero() -> Self {
        Self(Decimal::ZERO)
    }

    /// The full fraction (1.0 = 100%).
    pub fn one() -> Self {
        Self(Decimal::ONE)
    }
}

impl fmt::Display for Fraction {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "{}", self.0.normalize())
    }
}

#[cfg(test)]
#[path = "fraction_tests.rs"]
mod tests;