optionstratlib_core/error/trade.rs
1/******************************************************************************
2 Author: Joaquín Béjar García
3 Email: jb@taunais.com
4 Date: 31/12/25
5******************************************************************************/
6
7//! Target crate (ADR-0001 D6, roadmap M1-14): **core**. Owns `TradeError`.
8
9use thiserror::Error;
10
11/// Represents errors that can occur during trade-related operations.
12///
13/// This enum encapsulates various error conditions that may arise during trade execution,
14/// validation, or parameter processing. It provides detailed context about what went wrong
15/// during trading operations.
16///
17/// `TradeError` is particularly useful for diagnosing problems in trade execution and validation.
18#[derive(Error, Debug)]
19pub enum TradeError {
20 /// Error indicating that a trade is invalid.
21 ///
22 /// This variant is used when a trade doesn't meet the requirements
23 /// for valid trading operations.
24 #[error("Invalid trade: {reason}")]
25 InvalidTrade {
26 /// A description explaining why the trade is invalid.
27 reason: String,
28 },
29
30 /// Error indicating that a trade status is invalid.
31 ///
32 /// This variant is used when a trade status doesn't meet the requirements
33 /// for valid trading operations.
34 #[error("Invalid trade status: {reason}")]
35 InvalidTradeStatus {
36 /// A description explaining why the trade status is invalid.
37 reason: String,
38 },
39
40 /// Error indicating that a monetary figure of a trade (its cost, income
41 /// or net) left the representable range.
42 ///
43 /// The premium, the contract size, the fee and the quantity are public
44 /// `Positive` fields, so their product can overflow even though each
45 /// value is valid on its own.
46 #[error("Trade arithmetic overflow in {operation}: {reason}")]
47 ArithmeticOverflow {
48 /// The computation that overflowed, for example `"Trade::cost"`.
49 operation: &'static str,
50 /// The underlying arithmetic error.
51 reason: String,
52 },
53}
54
55/// Helper methods for creating trading-related errors
56///
57/// This implementation provides a set of convenience helper methods for creating
58/// different types of trading errors. These methods create properly structured
59/// error instances with clear, descriptive information about what went wrong.
60///
61/// # Methods
62///
63/// These helper methods simplify error creation throughout the codebase and ensure
64/// that errors have consistent formatting and information.
65impl TradeError {
66 /// Creates a generic invalid trade error
67 ///
68 /// # Parameters
69 ///
70 /// * `reason` - A description of why the trade is invalid
71 ///
72 /// # Returns
73 ///
74 /// A `TradeError::InvalidTrade` variant
75 #[must_use]
76 #[cold]
77 #[inline(never)]
78 pub fn invalid_trade(reason: &str) -> Self {
79 TradeError::InvalidTrade {
80 reason: reason.to_string(),
81 }
82 }
83
84 /// Creates a generic invalid trade status error
85 ///
86 /// # Parameters
87 ///
88 /// * `reason` - A description of why the trade status is invalid
89 ///
90 /// # Returns
91 ///
92 /// A `TradeError::InvalidTradeStatus` variant
93 #[must_use]
94 #[cold]
95 #[inline(never)]
96 pub fn invalid_trade_status(reason: &str) -> Self {
97 TradeError::InvalidTradeStatus {
98 reason: reason.to_string(),
99 }
100 }
101
102 /// Creates an arithmetic overflow error for `operation`.
103 ///
104 /// # Parameters
105 ///
106 /// * `operation` - The computation that overflowed
107 /// * `reason` - The underlying arithmetic error
108 ///
109 /// # Returns
110 ///
111 /// A `TradeError::ArithmeticOverflow` variant
112 #[must_use]
113 #[cold]
114 #[inline(never)]
115 pub fn arithmetic_overflow(operation: &'static str, reason: impl std::fmt::Display) -> Self {
116 TradeError::ArithmeticOverflow {
117 operation,
118 reason: reason.to_string(),
119 }
120 }
121}
122
123impl From<&str> for TradeError {
124 fn from(s: &str) -> Self {
125 TradeError::InvalidTrade {
126 reason: s.to_string(),
127 }
128 }
129}
130
131impl From<String> for TradeError {
132 fn from(s: String) -> Self {
133 TradeError::InvalidTrade { reason: s }
134 }
135}
136
137#[cfg(test)]
138mod tests_trade_errors {
139 use super::*;
140
141 #[test]
142 fn test_invalid_trade_error() {
143 let error = TradeError::InvalidTrade {
144 reason: "Trade is not valid".to_string(),
145 };
146
147 assert_eq!(error.to_string(), "Invalid trade: Trade is not valid");
148 }
149
150 #[test]
151 fn test_trade_error_arithmetic_overflow_names_operation() {
152 let error = TradeError::arithmetic_overflow("Trade::cost", "overflow");
153 assert!(matches!(
154 error,
155 TradeError::ArithmeticOverflow {
156 operation: "Trade::cost",
157 ..
158 }
159 ));
160 assert_eq!(
161 error.to_string(),
162 "Trade arithmetic overflow in Trade::cost: overflow"
163 );
164 }
165
166 #[test]
167 fn test_invalid_trade_status_error() {
168 let error = TradeError::InvalidTradeStatus {
169 reason: "Trade status is not valid".to_string(),
170 };
171
172 assert_eq!(
173 error.to_string(),
174 "Invalid trade status: Trade status is not valid"
175 );
176 }
177
178 #[test]
179 fn test_invalid_trade_error_helper_method() {
180 let error = TradeError::invalid_trade("Trade is not valid");
181 assert_eq!(error.to_string(), "Invalid trade: Trade is not valid");
182 }
183
184 #[test]
185 fn test_invalid_trade_status_error_helper_method() {
186 let error = TradeError::invalid_trade_status("Trade status is not valid");
187 assert_eq!(
188 error.to_string(),
189 "Invalid trade status: Trade status is not valid"
190 );
191 }
192}
193
194#[cfg(test)]
195mod tests_trade_error_from {
196 use super::*;
197
198 #[test]
199 fn from_str_creates_invalid_trade_error() {
200 let err: TradeError = "some error reason".into();
201
202 match err {
203 TradeError::InvalidTrade { reason } => {
204 assert_eq!(reason, "some error reason");
205 }
206 _ => panic!("Expected TradeError::InvalidTrade"),
207 }
208 }
209
210 #[test]
211 fn from_string_creates_invalid_trade_error() {
212 let input = String::from("string-based error reason");
213 let err: TradeError = input.clone().into();
214
215 match err {
216 TradeError::InvalidTrade { reason } => {
217 assert_eq!(reason, input);
218 }
219 _ => panic!("Expected TradeError::InvalidTrade"),
220 }
221 }
222}