use thiserror::Error;
#[derive(Debug, Error)]
#[non_exhaustive]
pub enum BacktestError {
#[error("Invalid parameter '{param}': {reason}")]
InvalidParameter {
param: String,
reason: String,
},
#[error("Insufficient data: need at least {need} candles, got {got}")]
InsufficientData {
need: usize,
got: usize,
},
#[error("Strategy error: {0}")]
StrategyError(String),
#[error("Indicator calculation failed: {0}")]
IndicatorError(#[from] crate::indicators::IndicatorError),
#[error("Failed to fetch chart data: {0}")]
ChartError(String),
#[error("Position error: {0}")]
PositionError(String),
}
pub type Result<T> = std::result::Result<T, BacktestError>;
impl BacktestError {
pub fn invalid_param(param: impl Into<String>, reason: impl Into<String>) -> Self {
Self::InvalidParameter {
param: param.into(),
reason: reason.into(),
}
}
pub fn insufficient_data(need: usize, got: usize) -> Self {
Self::InsufficientData { need, got }
}
pub fn strategy(msg: impl Into<String>) -> Self {
Self::StrategyError(msg.into())
}
pub fn chart(msg: impl Into<String>) -> Self {
Self::ChartError(msg.into())
}
pub fn position(msg: impl Into<String>) -> Self {
Self::PositionError(msg.into())
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_invalid_param_error() {
let err = BacktestError::invalid_param("capital", "must be positive");
assert!(err.to_string().contains("capital"));
assert!(err.to_string().contains("must be positive"));
}
#[test]
fn test_insufficient_data_error() {
let err = BacktestError::insufficient_data(50, 10);
assert!(err.to_string().contains("50"));
assert!(err.to_string().contains("10"));
}
}