optionstratlib 0.16.0

OptionStratLib is a comprehensive Rust library for options trading and strategy development across multiple asset classes.
Documentation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
/******************************************************************************
    Author: Joaquín Béjar García
    Email: jb@taunais.com
    Date: 24/12/25
******************************************************************************/

use crate::error::common::OperationErrorKind;
use crate::error::metrics::MetricsError;
use crate::error::{GraphError, GreeksError, InterpolationError, OptionsError, PositionError};
use thiserror::Error;

/// Represents different types of errors that can occur in the `curves` module.
///
/// This enum categorizes errors that may be encountered when working with curve-related
/// operations such as interpolation, construction, analysis, and other mathematical
/// operations on curves and points.
///
/// # Variants
///
/// ## `Point2DError`
/// Represents errors related to 2D point operations.
///
/// * `reason` - A static string explaining the specific point-related issue.
///
/// This variant is used for fundamental issues with points like invalid coordinates,
/// missing values, or formatting problems.
///
/// ## `OperationError`
/// Encapsulates general operational errors.
///
/// * `OperationErrorKind` - The specific kind of operation failure (see `OperationErrorKind` enum).
///
/// Used when an operation fails due to unsupported features or invalid parameters.
///
/// ## `StdError`
/// Wraps standard errors with additional context.
///
/// * `reason` - A dynamic string providing detailed error information.
///
/// Suitable for general error cases where specialized variants don't apply.
///
/// ## `InterpolationError`
/// Indicates issues during the curve interpolation process.
///
/// * `String` - A human-readable explanation of the interpolation failure.
///
/// Used when problems occur during data point interpolation or curve generation.
///
/// ## `ConstructionError`
/// Represents errors during the construction of curves or related structures.
///
/// * `String` - A description of the construction issue.
///
/// Applicable when curve initialization fails due to invalid inputs, unsupported
/// configurations, or missing required parameters.
///
/// ## `AnalysisError`
/// Captures errors related to curve analysis operations.
///
/// * `String` - A detailed explanation of the analysis failure.
///
/// Used for failures in analytical methods like curve fitting, differentiation,
/// or other mathematical operations on curves.
///
/// ## `MetricsError`
/// Represents errors when calculating or processing curve metrics.
///
/// * `String` - An explanation of the metrics-related issue.
///
/// Used when metric calculations fail due to invalid inputs or computational issues.
///
/// # Usage
///
/// This error type is designed to be used throughout the `curves` module wherever
/// operations might fail. It provides structured error information to help diagnose
/// and handle various failure scenarios.
///
/// # Implementation Notes
///
/// The error variants are designed to provide useful context for debugging and error handling.
/// Each variant includes specific information relevant to its error category.
///
/// # Examples
///
/// ```rust
/// // Example of creating a construction error
/// use optionstratlib::error::CurveError;
/// let error = CurveError::ConstructionError("Insufficient points to construct curve".to_string());
///
/// // Example of creating a point error
/// let point_error = CurveError::Point2DError { reason: "Point coordinates out of bounds" };
/// ```
#[derive(Error, Debug)]
pub enum CurveError {
    /// Error related to 2D point operations
    #[error("Error: {reason}")]
    Point2DError {
        /// Static description of the point-related issue
        reason: &'static str,
    },

    /// General operational error
    #[error("Operation error: {0}")]
    OperationError(
        /// The specific kind of operation failure
        OperationErrorKind,
    ),

    /// A rendering operation failed. Preserves the backend discriminator so
    /// callers can distinguish plotters output paths from other backends
    /// without resorting to a `String` catch-all.
    #[error("rendering failed ({backend}): {reason}")]
    RenderError {
        /// Identifier of the rendering backend that failed (e.g. `"plotters"`).
        backend: &'static str,
        /// Detailed, human-readable reason for the failure.
        reason: String,
    },

    /// Error during curve interpolation
    #[error("Interpolation error: {0}")]
    InterpolationError(
        /// Description of the interpolation issue
        String,
    ),

    /// Error during curve or structure construction
    #[error("Construction error: {0}")]
    ConstructionError(
        /// Details about the construction failure
        String,
    ),

    /// Error during curve analysis operations
    #[error("Analysis error: {0}")]
    AnalysisError(
        /// Explanation of the analysis issue
        String,
    ),

    /// Error when calculating or processing curve metrics
    #[error("Metrics error: {0}")]
    MetricsError(
        /// Description of the metrics-related issue
        String,
    ),

    /// Error from position operations
    #[error(transparent)]
    Position(#[from] PositionError),

    /// Error from options operations
    #[error(transparent)]
    Options(#[from] OptionsError),

    /// Error from Greeks calculations
    #[error(transparent)]
    Greeks(#[from] GreeksError),

    /// Error from interpolation operations  
    #[error("Interpolation error: {0}")]
    InterpolationOp(String),

    /// Error from graph operations
    #[error(transparent)]
    Graph(Box<GraphError>),
}

/// Provides helper methods for constructing specific variants of the `CurvesError` type.
///
/// These methods encapsulate common patterns of error creation, making it easier
/// to consistently generate errors with the necessary context.
///
///
/// ## Integration
/// - These methods simplify the process of creating meaningful error objects, improving readability
///   and maintainability of the code using the `CurvesError` type.
/// - The constructed errors leverage the [`OperationErrorKind`]
///   to ensure structured and detailed error categorization.
impl CurveError {
    /// ### `operation_not_supported`
    /// Constructs a `CurvesError::OperationError` with an [`OperationErrorKind::NotSupported`] variant.
    /// - **Parameters:**
    ///   - `operation` (`&str`): The name of the operation that is not supported.
    ///   - `reason` (`&str`): A description of why the operation is not supported.
    /// - **Returns:**
    ///   - A `CurvesError` containing a `NotSupported` operation error.
    /// - **Use Cases:**
    ///   - Invoked when a requested operation is not compatible with the current context.
    ///   - For example, attempting an unsupported computation method on a specific curve type.
    ///
    #[must_use]
    #[cold]
    #[inline(never)]
    pub fn operation_not_supported(operation: &str, reason: &str) -> Self {
        CurveError::OperationError(OperationErrorKind::NotSupported {
            operation: operation.to_string(),
            reason: reason.to_string(),
        })
    }

    /// ### `invalid_parameters`
    /// Constructs a `CurvesError::OperationError` with an [`OperationErrorKind::InvalidParameters`] variant.
    /// - **Parameters:**
    ///   - `operation` (`&str`): The name of the operation that encountered invalid parameters.
    ///   - `reason` (`&str`): A description of why the parameters are invalid.
    /// - **Returns:**
    ///   - A `CurvesError` containing an `InvalidParameters` operation error.
    /// - **Use Cases:**
    ///   - Used when an operation fails due to issues with the provided input.
    ///   - For example, providing malformed or missing parameters for interpolation or curve construction.
    ///
    #[must_use]
    #[cold]
    #[inline(never)]
    pub fn invalid_parameters(operation: &str, reason: &str) -> Self {
        CurveError::OperationError(OperationErrorKind::InvalidParameters {
            operation: operation.to_string(),
            reason: reason.to_string(),
        })
    }
}

/// Type alias representing the result of operations related to curve calculations.
///
/// This type alias provides a standardized result type for functions that perform operations
/// with mathematical curves, including interpolation, construction, analysis, and other
/// curve-related operations.
///
/// # Type Parameters
///
/// * `T` - The success value type returned when operations complete successfully.
///
/// # Return Value
///
/// Returns either:
/// * `Ok(T)` - The operation completed successfully with a value of type `T`.
/// * `Err(CurveError)` - The operation failed, with a [`CurveError`] describing the specific failure.
///
/// # Usage
///
/// This result type is used throughout the curves module to provide consistent error handling
/// for curve operations. It allows functions to return detailed error information using the
/// [`CurveError`] enum when operations fail, while returning the expected value when successful.
///
pub type CurvesResult<T> = Result<T, CurveError>;

/// Converts a `PositionError` into a `CurvesError` by mapping it to an
/// `OperationError` with the `InvalidParameters` variant.
///
/// This implementation ensures a smooth transition between error types
/// when a `PositionError` is encountered within a context that operates
/// on the `curves` module. The `InvalidParameters` variant is used to
/// provide detailed information about the failed operation and the reason
/// for its failure.
///
/// ## Details:
/// - The `operation` field is hardcoded as `"Position"` to indicate the
///   context of the error (i.e., relating to position management).
/// - The `reason` field is derived from the `to_string` representation of
///   the `PositionError`, ensuring a human-readable explanation.
///
/// ## Example Integration:
/// 1. If a `PositionError` is encountered during curve calculations, this
///    implementation converts it into a `CurvesError` for consistent error
///    handling within the `curves` module.
/// 2. The generated `CurvesError` provides detailed diagnostic information
///    about the reason for the failure, enabling effective debugging.
///
/// ## Implementation Notes:
/// - This conversion leverages the `OperationErrorKind::InvalidParameters`
///   variant to communicate that invalid parameters (or settings) were the
///   root cause of failure.
/// - Use this implementation to handle interoperability between error types
///   in modular design contexts.
///
/// ## Example Use Case:
/// This conversion is frequently used in scenarios where:
/// - A position-related error (e.g., from validation or limits) occurs during a
///   curve operation.
/// - Such errors need to be mapped into the `CurvesError` domain to maintain
///   consistent error handling across the library.
///
/// ## Debugging:
/// The resulting `CurvesError` will include contextual details, making it
/// straightforward to trace and debug the underlying issue.
impl From<MetricsError> for CurveError {
    fn from(err: MetricsError) -> Self {
        CurveError::MetricsError(err.to_string())
    }
}

impl From<InterpolationError> for CurveError {
    fn from(err: InterpolationError) -> Self {
        CurveError::InterpolationOp(err.to_string())
    }
}

impl From<GraphError> for CurveError {
    fn from(err: GraphError) -> Self {
        CurveError::Graph(Box::new(err))
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use std::error::Error;

    #[test]
    fn test_curves_error_display() {
        let error = CurveError::Point2DError {
            reason: "Invalid coordinates",
        };
        assert_eq!(error.to_string(), "Error: Invalid coordinates");

        let error = CurveError::RenderError {
            backend: "plotters",
            reason: "rendering failed".to_string(),
        };
        assert_eq!(
            error.to_string(),
            "rendering failed (plotters): rendering failed"
        );

        let error = CurveError::operation_not_supported("calculate", "Strategy");
        assert_eq!(
            error.to_string(),
            "Operation error: Operation 'calculate' is not supported for strategy 'Strategy'"
        );
    }

    #[test]
    fn test_operation_not_supported() {
        let error = CurveError::operation_not_supported("test_op", "TestStrat");
        match error {
            CurveError::OperationError(OperationErrorKind::NotSupported {
                operation,
                reason: strategy_type,
            }) => {
                assert_eq!(operation, "test_op");
                assert_eq!(strategy_type, "TestStrat");
            }
            _ => panic!("Wrong error variant"),
        }
    }

    #[test]
    fn test_invalid_parameters() {
        let error = CurveError::invalid_parameters("test_op", "invalid input");
        match error {
            CurveError::OperationError(OperationErrorKind::InvalidParameters {
                operation,
                reason,
            }) => {
                assert_eq!(operation, "test_op");
                assert_eq!(reason, "invalid input");
            }
            _ => panic!("Wrong error variant"),
        }
    }

    #[test]
    fn test_error_trait_implementation() {
        let error = CurveError::Point2DError {
            reason: "test error",
        };
        let error_ref: &dyn Error = &error;
        assert_eq!(error_ref.to_string(), "Error: test error");
    }

    #[test]
    fn test_render_error_constructor() {
        let error = CurveError::RenderError {
            backend: "plotters",
            reason: "Draw error".to_string(),
        };
        match error {
            CurveError::RenderError { backend, reason } => {
                assert_eq!(backend, "plotters");
                assert_eq!(reason, "Draw error");
            }
            _ => panic!("Wrong error variant"),
        }
    }

    #[test]
    fn test_from_position_error() {
        let position_error = PositionError::unsupported_operation("TestStruct", "test_op");
        let curves_error = CurveError::from(position_error);

        match curves_error {
            CurveError::Position(_) => {
                // Conversion successful
            }
            _ => panic!("Wrong error variant"),
        }
    }

    #[test]
    fn test_debug_implementation() {
        let error = CurveError::Point2DError {
            reason: "test debug",
        };
        assert!(format!("{error:?}").contains("test debug"));

        let error = CurveError::RenderError {
            backend: "plotters",
            reason: "test debug".to_string(),
        };
        assert!(format!("{error:?}").contains("test debug"));
    }
}

#[cfg(test)]
mod tests_extended {
    use super::*;

    #[test]
    fn test_curves_error_construction_error() {
        let error =
            CurveError::ConstructionError("Invalid curve construction parameters".to_string());
        assert_eq!(
            format!("{error}"),
            "Construction error: Invalid curve construction parameters"
        );
    }

    #[test]
    fn test_curves_error_analysis_error() {
        let error =
            CurveError::AnalysisError("Analysis failed due to insufficient data".to_string());
        assert_eq!(
            format!("{error}"),
            "Analysis error: Analysis failed due to insufficient data"
        );
    }
}