Skip to main content

finance_query/backtesting/
error.rs

1//! Error types for backtesting operations.
2
3use thiserror::Error;
4
5/// Backtest-specific errors
6#[derive(Debug, Error)]
7#[non_exhaustive]
8pub enum BacktestError {
9    /// Invalid configuration parameter
10    #[error("Invalid parameter '{param}': {reason}")]
11    InvalidParameter {
12        /// Parameter name
13        param: String,
14        /// Reason for invalidity
15        reason: String,
16    },
17
18    /// Insufficient data for backtest
19    #[error("Insufficient data: need at least {need} candles, got {got}")]
20    InsufficientData {
21        /// Minimum required candles
22        need: usize,
23        /// Actual candles provided
24        got: usize,
25    },
26
27    /// Strategy error during execution
28    #[error("Strategy error: {0}")]
29    StrategyError(String),
30
31    /// Indicator calculation failed
32    #[error("Indicator calculation failed: {0}")]
33    IndicatorError(#[from] crate::indicators::IndicatorError),
34
35    /// Chart data fetch failed
36    #[error("Failed to fetch chart data: {0}")]
37    ChartError(String),
38
39    /// Position management error
40    #[error("Position error: {0}")]
41    PositionError(String),
42}
43
44/// Result type for backtest operations
45pub type Result<T> = std::result::Result<T, BacktestError>;
46
47impl BacktestError {
48    /// Create an invalid parameter error
49    pub fn invalid_param(param: impl Into<String>, reason: impl Into<String>) -> Self {
50        Self::InvalidParameter {
51            param: param.into(),
52            reason: reason.into(),
53        }
54    }
55
56    /// Create an insufficient data error
57    pub fn insufficient_data(need: usize, got: usize) -> Self {
58        Self::InsufficientData { need, got }
59    }
60
61    /// Create a strategy error
62    pub fn strategy(msg: impl Into<String>) -> Self {
63        Self::StrategyError(msg.into())
64    }
65
66    /// Create a chart error
67    pub fn chart(msg: impl Into<String>) -> Self {
68        Self::ChartError(msg.into())
69    }
70
71    /// Create a position error
72    pub fn position(msg: impl Into<String>) -> Self {
73        Self::PositionError(msg.into())
74    }
75}
76
77#[cfg(test)]
78mod tests {
79    use super::*;
80
81    #[test]
82    fn test_invalid_param_error() {
83        let err = BacktestError::invalid_param("capital", "must be positive");
84        assert!(err.to_string().contains("capital"));
85        assert!(err.to_string().contains("must be positive"));
86    }
87
88    #[test]
89    fn test_insufficient_data_error() {
90        let err = BacktestError::insufficient_data(50, 10);
91        assert!(err.to_string().contains("50"));
92        assert!(err.to_string().contains("10"));
93    }
94}