use rust_decimal::Decimal;
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct PositionConfig {
max_position_pct: Decimal,
volatility_scaling: bool,
risk_per_trade_pct: Option<Decimal>,
}
#[derive(Debug, Clone, PartialEq, Eq, thiserror::Error)]
pub enum PositionConfigError {
#[error("max_position_pct {0} out of range [0, 1]")]
MaxPositionOutOfRange(Decimal),
#[error("risk_per_trade_pct {0} out of range [0, 1]")]
RiskPerTradeOutOfRange(Decimal),
}
impl PositionConfig {
pub fn new(
max_position_pct: Decimal,
volatility_scaling: bool,
risk_per_trade_pct: Option<Decimal>,
) -> Result<Self, PositionConfigError> {
if max_position_pct < Decimal::ZERO || max_position_pct > Decimal::ONE {
return Err(PositionConfigError::MaxPositionOutOfRange(max_position_pct));
}
if let Some(risk) = risk_per_trade_pct {
if risk < Decimal::ZERO || risk > Decimal::ONE {
return Err(PositionConfigError::RiskPerTradeOutOfRange(risk));
}
}
Ok(Self {
max_position_pct,
volatility_scaling,
risk_per_trade_pct,
})
}
pub fn max_position_pct(&self) -> Decimal {
self.max_position_pct
}
pub fn volatility_scaling(&self) -> bool {
self.volatility_scaling
}
pub fn risk_per_trade_pct(&self) -> Option<Decimal> {
self.risk_per_trade_pct
}
}
impl Default for PositionConfig {
fn default() -> Self {
Self {
max_position_pct: Decimal::new(1, 1), volatility_scaling: false,
risk_per_trade_pct: None,
}
}
}
#[cfg(test)]
#[path = "position_config_tests.rs"]
mod tests;