Skip to main content

xtb_client/schema/
enums.rs

1use std::fmt;
2use num_enum::{IntoPrimitive, TryFromPrimitive};
3use serde::{Deserialize, Deserializer, Serialize};
4use serde_repr::{Deserialize_repr, Serialize_repr};
5
6/// Enum representing various types
7#[derive(Default, Clone, Copy, PartialEq, Debug, Serialize_repr, Deserialize_repr, TryFromPrimitive, IntoPrimitive)]
8#[repr(u8)]
9pub enum QuoteId {
10    /// fixed
11    #[default]
12    Fixed = 1,
13    /// float
14    Float = 2,
15    /// depth
16    Depth = 3,
17    /// cross
18    Cross = 4,
19    /// Undocumented option
20    Unknown1 = 5,
21    /// Undocumented option
22    Unknown2 = 6,
23}
24
25
26/// Enum representing different margin modes
27#[derive(Default, Clone, Copy, PartialEq, Debug, Serialize_repr, Deserialize_repr, TryFromPrimitive, IntoPrimitive)]
28#[repr(u8)]
29pub enum MarginMode {
30    /// Forex
31    #[default]
32    Forex = 101,
33    /// CFD leveraged
34    CFDLeveraged = 102,
35    /// CFD
36    CFD = 103,
37    /// Undocumented option
38    Unknown1 = 104
39}
40
41
42/// Enum representing different profit modes
43#[derive(Default, Clone, Copy, PartialEq, Debug, Serialize_repr, Deserialize_repr, TryFromPrimitive, IntoPrimitive)]
44#[repr(u8)]
45pub enum ProfitMode {
46    /// FOREX
47    #[default]
48    Forex = 5,
49    /// CFD
50    Cfd = 6,
51}
52
53
54/// Expected impact level of event in calendar
55#[derive(Default, Clone, Copy, PartialEq, Debug, Serialize, Deserialize, TryFromPrimitive, IntoPrimitive)]
56#[repr(u8)]
57pub enum ImpactLevel {
58    /// low
59    #[serde(rename = "1")]
60    #[default]
61    Low = 1,
62    /// medium
63    #[serde(rename = "2")]
64    Medium = 2,
65    /// high
66    #[serde(rename = "3")]
67    High = 3,
68}
69
70
71/// Enum representing different time periods
72#[derive(Default, Clone, Copy, PartialEq, Debug, Serialize_repr, Deserialize_repr, TryFromPrimitive, IntoPrimitive)]
73#[repr(u16)]
74pub enum TimePeriod {
75    /// 1 minute
76    PeriodM1 = 1,
77    /// 5 minutes
78    #[default]
79    PeriodM5 = 5,
80    /// 15 minutes
81    PeriodM15 = 15,
82    /// 30 minutes
83    PeriodM30 = 30,
84    /// 60 minutes (1 hour)
85    PeriodH1 = 60,
86    /// 240 minutes (4 hours)
87    PeriodH4 = 240,
88    /// 1440 minutes (1 day)
89    PeriodD1 = 1440,
90    /// 10080 minutes (1 week)
91    PeriodW1 = 10080,
92    /// 43200 minutes (30 days)
93    PeriodMN1 = 43200,
94}
95
96
97/// Enum representing types of trading actions
98#[derive(Default, Clone, Copy, PartialEq, Debug, Serialize_repr, Deserialize_repr, TryFromPrimitive, IntoPrimitive)]
99#[repr(u8)]
100pub enum TradingAction {
101    /// Buy
102    #[default]
103    Buy = 0,
104    /// Sell
105    Sell = 1,
106}
107
108
109/// Enum representing different types of trading actions
110#[derive(Default, Clone, Copy, PartialEq, Debug, Serialize_repr, Deserialize_repr, TryFromPrimitive, IntoPrimitive)]
111#[repr(u8)]
112pub enum TradingCommand {
113    /// Buy
114    #[default]
115    Buy = 0,
116    /// Sell
117    Sell = 1,
118    /// Buy limit
119    BuyLimit = 2,
120    /// Sell limit
121    SellLimit = 3,
122    /// Buy stop
123    BuyStop = 4,
124    /// Sell stop
125    SellStop = 5,
126    /// Read only. Used in getTradesHistory for manager's deposit/withdrawal operations (profit>0 for deposit, profit<0 for withdrawal).
127    Balance = 6,
128    /// Read only
129    Credit = 7,
130}
131
132#[derive(Default, Clone, Copy, PartialEq, Debug, Serialize_repr, Deserialize_repr, TryFromPrimitive, IntoPrimitive)]
133#[repr(u8)]
134pub enum DayOfWeek {
135    /// Monday
136    #[default]
137    Monday = 1,
138    /// Tuesday
139    Tuesday = 2,
140    /// Wednesday
141    Wednesday = 3,
142    /// Thursday
143    Thursday = 4,
144    /// Friday
145    Friday = 5,
146    /// Saturday
147    Saturday = 6,
148    /// Sunday
149    Sunday = 7,
150}
151
152
153#[derive(Default, Clone, Copy, PartialEq, Debug, Serialize_repr, Deserialize_repr, TryFromPrimitive, IntoPrimitive)]
154#[repr(u8)]
155pub enum TransactionStatus {
156    /// Error
157    #[default]
158    Error = 0,
159    /// Pending
160    Pending = 1,
161    /// The transaction has been executed successfully
162    Accepted = 3,
163    /// The transaction has been rejected
164    Rejected = 4,
165}
166
167
168#[derive(Default, Clone, Copy, PartialEq, Debug, Serialize_repr, Deserialize_repr, TryFromPrimitive, IntoPrimitive)]
169#[repr(u8)]
170pub enum TransactionType {
171    /// Order open, used for opening orders
172    #[default]
173    Open = 0,
174    /// Order pending, only used in the streaming getTrades command
175    Pending = 1,
176    /// Order close
177    Close = 2,
178    /// Order modify, only used in the tradeTransaction command
179    Modify = 3,
180    /// Order delete, only used in the tradeTransaction command
181    Delete = 4,
182}
183
184#[derive(Default, Clone, Copy, PartialEq, Debug, Serialize)]
185#[serde(rename_all = "lowercase")]
186pub enum TradeStatus {
187    /// Modified
188    #[default]
189    Modified,
190    /// Deleted
191    Deleted,
192}
193
194
195// Implementation of custom Deserializer to allow case insensitive deserialization
196impl<'de> Deserialize<'de> for TradeStatus {
197    fn deserialize<D>(deserializer: D) -> Result<TradeStatus, D::Error>
198        where
199            D: Deserializer<'de>,
200    {
201        struct TradeStatusVisitor;
202
203        impl<'de> serde::de::Visitor<'de> for TradeStatusVisitor {
204            type Value = TradeStatus;
205
206            fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
207                formatter.write_str("a string representing TradeStatus")
208            }
209
210            fn visit_str<E>(self, value: &str) -> Result<TradeStatus, E>
211                where
212                    E: serde::de::Error,
213            {
214                let lowercase_value = value.to_lowercase();
215                match lowercase_value.as_str() {
216                    "modified" => Ok(TradeStatus::Modified),
217                    "deleted" => Ok(TradeStatus::Deleted),
218                    _ => Err(serde::de::Error::unknown_variant(value, &["Modified", "Deleted"])),
219                }
220            }
221        }
222
223        deserializer.deserialize_str(TradeStatusVisitor)
224    }
225}
226
227
228#[cfg(test)]
229mod tests {
230    mod serialize_deserialize {
231        use std::fmt::Debug;
232        use rstest::rstest;
233        use serde::{Deserialize, Serialize};
234        use crate::schema::enums::{TradeStatus, TransactionStatus, TransactionType, DayOfWeek, TradingCommand, QuoteId, MarginMode, ProfitMode, ImpactLevel, TimePeriod, TradingAction};
235        use serde_json::{from_value, to_value, Value};
236
237        #[rstest]
238        #[case::QuoteId_Fixed(QuoteId::Fixed, to_value(1).unwrap())]
239        #[case::QuoteId_Float(QuoteId::Float, to_value(2).unwrap())]
240        #[case::QuoteId_Depth(QuoteId::Depth, to_value(3).unwrap())]
241        #[case::QuoteId_Cross(QuoteId::Cross, to_value(4).unwrap())]
242
243        #[case::QuoteId_Forex(MarginMode::Forex, to_value(101).unwrap())]
244        #[case::QuoteId_CfdLeveraged(MarginMode::CFDLeveraged, to_value(102).unwrap())]
245        #[case::QuoteId_Cfd(MarginMode::CFD, to_value(103).unwrap())]
246
247        #[case::QuoteId_Forex(ProfitMode::Forex, to_value(5).unwrap())]
248        #[case::QuoteId_Cfd(ProfitMode::Cfd, to_value(6).unwrap())]
249
250        #[case::ImpactLevel_Low(ImpactLevel::Low, to_value("1").unwrap())]
251        #[case::ImpactLevel_Medium(ImpactLevel::Medium, to_value("2").unwrap())]
252        #[case::ImpactLevel_High(ImpactLevel::High, to_value("3").unwrap())]
253
254        #[case::TimePeriod_M1(TimePeriod::PeriodM1, to_value(1).unwrap())]
255        #[case::TimePeriod_M5(TimePeriod::PeriodM5, to_value(5).unwrap())]
256        #[case::TimePeriod_M15(TimePeriod::PeriodM15, to_value(15).unwrap())]
257        #[case::TimePeriod_M30(TimePeriod::PeriodM30, to_value(30).unwrap())]
258        #[case::TimePeriod_H1(TimePeriod::PeriodH1, to_value(60).unwrap())]
259        #[case::TimePeriod_H4(TimePeriod::PeriodH4, to_value(240).unwrap())]
260        #[case::TimePeriod_D1(TimePeriod::PeriodD1, to_value(1440).unwrap())]
261        #[case::TimePeriod_W1(TimePeriod::PeriodW1, to_value(10080).unwrap())]
262        #[case::TimePeriod_MN11(TimePeriod::PeriodMN1, to_value(43200).unwrap())]
263
264        #[case::TradingAction_Buy(TradingAction::Buy, to_value(0).unwrap())]
265        #[case::TradingAction_Sell(TradingAction::Sell, to_value(1).unwrap())]
266
267        #[case::TradingCommand_Buy(TradingCommand::Buy, to_value(0).unwrap())]
268        #[case::TradingCommand_Sell(TradingCommand::Sell, to_value(1).unwrap())]
269        #[case::TradingCommand_BuyLimit(TradingCommand::BuyLimit, to_value(2).unwrap())]
270        #[case::TradingCommand_SellLimit(TradingCommand::SellLimit, to_value(3).unwrap())]
271        #[case::TradingCommand_BuyStop(TradingCommand::BuyStop, to_value(4).unwrap())]
272        #[case::TradingCommand_SellStop(TradingCommand::SellStop, to_value(5).unwrap())]
273        #[case::TradingCommand_Balance(TradingCommand::Balance, to_value(6).unwrap())]
274        #[case::TradingCommand_Credit(TradingCommand::Credit, to_value(7).unwrap())]
275
276        #[case::DayOfWeek_Monday(DayOfWeek::Monday, to_value(1).unwrap())]
277        #[case::DayOfWeek_Tuesday(DayOfWeek::Tuesday, to_value(2).unwrap())]
278        #[case::DayOfWeek_Wednesday(DayOfWeek::Wednesday, to_value(3).unwrap())]
279        #[case::DayOfWeek_Thursday(DayOfWeek::Thursday, to_value(4).unwrap())]
280        #[case::DayOfWeek_Friday(DayOfWeek::Friday, to_value(5).unwrap())]
281        #[case::DayOfWeek_Saturday(DayOfWeek::Saturday, to_value(6).unwrap())]
282        #[case::DayOfWeek_Sunday(DayOfWeek::Sunday, to_value(7).unwrap())]
283
284        #[case::TransactionType_Open(TransactionType::Open, to_value(0).unwrap())]
285        #[case::TransactionType_Pending(TransactionType::Pending, to_value(1).unwrap())]
286        #[case::TransactionType_Close(TransactionType::Close, to_value(2).unwrap())]
287        #[case::TransactionType_Modify(TransactionType::Modify, to_value(3).unwrap())]
288        #[case::TransactionType_Delete(TransactionType::Delete, to_value(4).unwrap())]
289
290        #[case::TransactionStatus_Error(TransactionStatus::Error, to_value(0).unwrap())]
291        #[case::TransactionStatus_Pending(TransactionStatus::Pending, to_value(1).unwrap())]
292        #[case::TransactionStatus_Accepted(TransactionStatus::Accepted, to_value(3).unwrap())]
293        #[case::TransactionStatus_Rejected(TransactionStatus::Rejected, to_value(4).unwrap())]
294
295        #[case::TradeStatus_Rejected(TradeStatus::Modified, to_value("modified").unwrap())]
296        #[case::TradeStatus_Deleted(TradeStatus::Deleted, to_value("deleted").unwrap())]
297        fn serialize_value<T: Serialize + Debug>(#[case] inp: T, #[case] expected: Value) {
298            let serialized = to_value(inp).unwrap();
299            assert_eq!(serialized, expected);
300        }
301
302        #[rstest]
303        #[case::QuoteId_Fixed(QuoteId::Fixed, to_value(1).unwrap())]
304        #[case::QuoteId_Float(QuoteId::Float, to_value(2).unwrap())]
305        #[case::QuoteId_Depth(QuoteId::Depth, to_value(3).unwrap())]
306        #[case::QuoteId_Cross(QuoteId::Cross, to_value(4).unwrap())]
307
308        #[case::QuoteId_Forex(MarginMode::Forex, to_value(101).unwrap())]
309        #[case::QuoteId_CfdLeveraged(MarginMode::CFDLeveraged, to_value(102).unwrap())]
310        #[case::QuoteId_Cfd(MarginMode::CFD, to_value(103).unwrap())]
311
312        #[case::QuoteId_Forex(ProfitMode::Forex, to_value(5).unwrap())]
313        #[case::QuoteId_Cfd(ProfitMode::Cfd, to_value(6).unwrap())]
314
315        #[case::ImpactLevel_Low(ImpactLevel::Low, to_value("1").unwrap())]
316        #[case::ImpactLevel_Medium(ImpactLevel::Medium, to_value("2").unwrap())]
317        #[case::ImpactLevel_High(ImpactLevel::High, to_value("3").unwrap())]
318
319        #[case::TimePeriod_M1(TimePeriod::PeriodM1, to_value(1).unwrap())]
320        #[case::TimePeriod_M5(TimePeriod::PeriodM5, to_value(5).unwrap())]
321        #[case::TimePeriod_M15(TimePeriod::PeriodM15, to_value(15).unwrap())]
322        #[case::TimePeriod_M30(TimePeriod::PeriodM30, to_value(30).unwrap())]
323        #[case::TimePeriod_H1(TimePeriod::PeriodH1, to_value(60).unwrap())]
324        #[case::TimePeriod_H4(TimePeriod::PeriodH4, to_value(240).unwrap())]
325        #[case::TimePeriod_D1(TimePeriod::PeriodD1, to_value(1440).unwrap())]
326        #[case::TimePeriod_W1(TimePeriod::PeriodW1, to_value(10080).unwrap())]
327        #[case::TimePeriod_MN11(TimePeriod::PeriodMN1, to_value(43200).unwrap())]
328
329        #[case::TradingAction_1(TradingAction::Buy, to_value(0).unwrap())]
330        #[case::TradingAction_1(TradingAction::Sell, to_value(1).unwrap())]
331
332        #[case::TradingCommand_Buy(TradingCommand::Buy, to_value(0).unwrap())]
333        #[case::TradingCommand_Sell(TradingCommand::Sell, to_value(1).unwrap())]
334        #[case::TradingCommand_BuyLimit(TradingCommand::BuyLimit, to_value(2).unwrap())]
335        #[case::TradingCommand_SellLimit(TradingCommand::SellLimit, to_value(3).unwrap())]
336        #[case::TradingCommand_BuyStop(TradingCommand::BuyStop, to_value(4).unwrap())]
337        #[case::TradingCommand_SellStop(TradingCommand::SellStop, to_value(5).unwrap())]
338        #[case::TradingCommand_Balance(TradingCommand::Balance, to_value(6).unwrap())]
339        #[case::TradingCommand_Credit(TradingCommand::Credit, to_value(7).unwrap())]
340
341        #[case::DayOfWeek_Monday(DayOfWeek::Monday, to_value(1).unwrap())]
342        #[case::DayOfWeek_Tuesday(DayOfWeek::Tuesday, to_value(2).unwrap())]
343        #[case::DayOfWeek_Wednesday(DayOfWeek::Wednesday, to_value(3).unwrap())]
344        #[case::DayOfWeek_Thursday(DayOfWeek::Thursday, to_value(4).unwrap())]
345        #[case::DayOfWeek_Friday(DayOfWeek::Friday, to_value(5).unwrap())]
346        #[case::DayOfWeek_Saturday(DayOfWeek::Saturday, to_value(6).unwrap())]
347        #[case::DayOfWeek_Sunday(DayOfWeek::Sunday, to_value(7).unwrap())]
348
349        #[case::TransactionType_Open(TransactionType::Open, to_value(0).unwrap())]
350        #[case::TransactionType_Pending(TransactionType::Pending, to_value(1).unwrap())]
351        #[case::TransactionType_Close(TransactionType::Close, to_value(2).unwrap())]
352        #[case::TransactionType_Modify(TransactionType::Modify, to_value(3).unwrap())]
353        #[case::TransactionType_Delete(TransactionType::Delete, to_value(4).unwrap())]
354
355        #[case::TransactionStatus_Error(TransactionStatus::Error, to_value(0).unwrap())]
356        #[case::TransactionStatus_Pending(TransactionStatus::Pending, to_value(1).unwrap())]
357        #[case::TransactionStatus_Accepted(TransactionStatus::Accepted, to_value(3).unwrap())]
358        #[case::TransactionStatus_Rejected(TransactionStatus::Rejected, to_value(4).unwrap())]
359
360        #[case::TradeStatus_Rejected(TradeStatus::Modified, to_value("modified").unwrap())]
361        #[case::TradeStatus_Rejected(TradeStatus::Modified, to_value("MODIFIED").unwrap())]
362        #[case::TradeStatus_Deleted(TradeStatus::Deleted, to_value("deleted").unwrap())]
363        #[case::TradeStatus_Deleted(TradeStatus::Deleted, to_value("DELETED").unwrap())]
364        fn deserialize_value<T: for<'de> Deserialize<'de> + Debug + PartialEq>(#[case] expected: T, #[case] inp: Value) {
365            let deserialized: T = from_value(inp).unwrap();
366            assert_eq!(deserialized, expected);
367        }
368    }
369
370    mod primitive_conversion {
371        use std::fmt::Debug;
372        use rstest::rstest;
373        use crate::schema::enums::{QuoteId, MarginMode, ProfitMode, ImpactLevel, TimePeriod, TradingAction, TradingCommand, DayOfWeek, TransactionStatus, TransactionType};
374
375        #[rstest]
376        #[case::QuoteId_Fixed(QuoteId::Fixed, 1u8)]
377        #[case::QuoteId_Float(QuoteId::Float, 2u8)]
378        #[case::QuoteId_Depth(QuoteId::Depth, 3u8)]
379        #[case::QuoteId_Cross(QuoteId::Cross, 4u8)]
380        #[case::QuoteId_Unknown1(QuoteId::Unknown1, 5u8)]
381        #[case::QuoteId_Unknown2(QuoteId::Unknown2, 6u8)]
382
383        #[case::MarginMode_Forex(MarginMode::Forex, 101u8)]
384        #[case::MarginMode_CFDLeveraged(MarginMode::CFDLeveraged, 102u8)]
385        #[case::MarginMode_CFD(MarginMode::CFD, 103u8)]
386        #[case::MarginMode_Unknown1(MarginMode::Unknown1, 104u8)]
387
388        #[case::ProfitMode_Forex(ProfitMode::Forex, 5u8)]
389        #[case::ProfitMode_CFD(ProfitMode::Cfd, 6u8)]
390
391        #[case::ImpactLevel_Low(ImpactLevel::Low, 1u8)]
392        #[case::ImpactLevel_Medium(ImpactLevel::Medium, 2u8)]
393        #[case::ImpactLevel_High(ImpactLevel::High, 3u8)]
394
395        #[case::TimePeriod_PeriodM1(TimePeriod::PeriodM1, 1u16)]
396        #[case::TimePeriod_PeriodM5(TimePeriod::PeriodM5, 5u16)]
397        #[case::TimePeriod_PeriodM15(TimePeriod::PeriodM15, 15u16)]
398        #[case::TimePeriod_PeriodM30(TimePeriod::PeriodM30, 30u16)]
399        #[case::TimePeriod_PeriodH1(TimePeriod::PeriodH1, 60u16)]
400        #[case::TimePeriod_PeriodH4(TimePeriod::PeriodH4, 240u16)]
401        #[case::TimePeriod_PeriodD1(TimePeriod::PeriodD1, 1440u16)]
402        #[case::TimePeriod_PeriodW1(TimePeriod::PeriodW1, 10080u16)]
403        #[case::TimePeriod_PeriodMN1(TimePeriod::PeriodMN1, 43200u16)]
404
405        #[case::TradingAction_Buy(TradingAction::Buy, 0u8)]
406        #[case::TradingAction_Sell(TradingAction::Sell, 1u8)]
407
408        #[case::TradingCommand_Buy(TradingCommand::Buy, 0u8)]
409        #[case::TradingCommand_Sell(TradingCommand::Sell, 1u8)]
410        #[case::TradingCommand_BuyLimit(TradingCommand::BuyLimit, 2u8)]
411        #[case::TradingCommand_SellLimit(TradingCommand::SellLimit, 3u8)]
412        #[case::TradingCommand_BuyStop(TradingCommand::BuyStop, 4u8)]
413        #[case::TradingCommand_SellStop(TradingCommand::SellStop, 5u8)]
414        #[case::TradingCommand_Balance(TradingCommand::Balance, 6u8)]
415        #[case::TradingCommand_Credit(TradingCommand::Credit, 7u8)]
416
417        #[case::DayOfWeek_Monday(DayOfWeek::Monday, 1u8)]
418        #[case::DayOfWeek_Tuesday(DayOfWeek::Tuesday, 2u8)]
419        #[case::DayOfWeek_Wednesday(DayOfWeek::Wednesday, 3u8)]
420        #[case::DayOfWeek_Thursday(DayOfWeek::Thursday, 4u8)]
421        #[case::DayOfWeek_Friday(DayOfWeek::Friday, 5u8)]
422        #[case::DayOfWeek_Saturday(DayOfWeek::Saturday, 6u8)]
423        #[case::DayOfWeek_Sunday(DayOfWeek::Sunday, 7u8)]
424
425        #[case::TransactionStatus_Error(TransactionStatus::Error, 0u8)]
426        #[case::TransactionStatus_Pending(TransactionStatus::Pending, 1u8)]
427        #[case::TransactionStatus_Accepted(TransactionStatus::Accepted, 3u8)]
428        #[case::TransactionStatus_Rejected(TransactionStatus::Rejected, 4u8)]
429
430        #[case::TransactionType_Open(TransactionType::Open, 0u8)]
431        #[case::TransactionType_Pending(TransactionType::Pending, 1u8)]
432        #[case::TransactionType_Close(TransactionType::Close, 2u8)]
433        #[case::TransactionType_Modify(TransactionType::Modify, 3u8)]
434        #[case::TransactionType_Delete(TransactionType::Delete, 4u8)]
435        fn into_primitive<T, P: From<T> + PartialEq + Debug>(#[case] val: T, #[case] expected_value: P) {
436            let result: P = val.into();
437            assert_eq!(result, expected_value)
438        }
439
440        #[rstest]
441        #[case::QuoteId_Fixed(QuoteId::Fixed, 1u8)]
442        #[case::QuoteId_Float(QuoteId::Float, 2u8)]
443        #[case::QuoteId_Depth(QuoteId::Depth, 3u8)]
444        #[case::QuoteId_Cross(QuoteId::Cross, 4u8)]
445        #[case::QuoteId_Unknown1(QuoteId::Unknown1, 5u8)]
446        #[case::QuoteId_Unknown2(QuoteId::Unknown2, 6u8)]
447
448        #[case::MarginMode_Forex(MarginMode::Forex, 101u8)]
449        #[case::MarginMode_CFDLeveraged(MarginMode::CFDLeveraged, 102u8)]
450        #[case::MarginMode_CFD(MarginMode::CFD, 103u8)]
451        #[case::MarginMode_Unknown1(MarginMode::Unknown1, 104u8)]
452
453        #[case::ProfitMode_Forex(ProfitMode::Forex, 5u8)]
454        #[case::ProfitMode_CFD(ProfitMode::Cfd, 6u8)]
455
456        #[case::ImpactLevel_Low(ImpactLevel::Low, 1u8)]
457        #[case::ImpactLevel_Medium(ImpactLevel::Medium, 2u8)]
458        #[case::ImpactLevel_High(ImpactLevel::High, 3u8)]
459
460        #[case::TimePeriod_PeriodM1(TimePeriod::PeriodM1, 1u16)]
461        #[case::TimePeriod_PeriodM5(TimePeriod::PeriodM5, 5u16)]
462        #[case::TimePeriod_PeriodM15(TimePeriod::PeriodM15, 15u16)]
463        #[case::TimePeriod_PeriodM30(TimePeriod::PeriodM30, 30u16)]
464        #[case::TimePeriod_PeriodH1(TimePeriod::PeriodH1, 60u16)]
465        #[case::TimePeriod_PeriodH4(TimePeriod::PeriodH4, 240u16)]
466        #[case::TimePeriod_PeriodD1(TimePeriod::PeriodD1, 1440u16)]
467        #[case::TimePeriod_PeriodW1(TimePeriod::PeriodW1, 10080u16)]
468        #[case::TimePeriod_PeriodMN1(TimePeriod::PeriodMN1, 43200u16)]
469
470        #[case::TradingAction_Buy(TradingAction::Buy, 0u8)]
471        #[case::TradingAction_Sell(TradingAction::Sell, 1u8)]
472
473        #[case::TradingCommand_Buy(TradingCommand::Buy, 0u8)]
474        #[case::TradingCommand_Sell(TradingCommand::Sell, 1u8)]
475        #[case::TradingCommand_BuyLimit(TradingCommand::BuyLimit, 2u8)]
476        #[case::TradingCommand_SellLimit(TradingCommand::SellLimit, 3u8)]
477        #[case::TradingCommand_BuyStop(TradingCommand::BuyStop, 4u8)]
478        #[case::TradingCommand_SellStop(TradingCommand::SellStop, 5u8)]
479        #[case::TradingCommand_Balance(TradingCommand::Balance, 6u8)]
480        #[case::TradingCommand_Credit(TradingCommand::Credit, 7u8)]
481
482        #[case::DayOfWeek_Monday(DayOfWeek::Monday, 1u8)]
483        #[case::DayOfWeek_Tuesday(DayOfWeek::Tuesday, 2u8)]
484        #[case::DayOfWeek_Wednesday(DayOfWeek::Wednesday, 3u8)]
485        #[case::DayOfWeek_Thursday(DayOfWeek::Thursday, 4u8)]
486        #[case::DayOfWeek_Friday(DayOfWeek::Friday, 5u8)]
487        #[case::DayOfWeek_Saturday(DayOfWeek::Saturday, 6u8)]
488        #[case::DayOfWeek_Sunday(DayOfWeek::Sunday, 7u8)]
489
490        #[case::TransactionStatus_Error(TransactionStatus::Error, 0u8)]
491        #[case::TransactionStatus_Pending(TransactionStatus::Pending, 1u8)]
492        #[case::TransactionStatus_Accepted(TransactionStatus::Accepted, 3u8)]
493        #[case::TransactionStatus_Rejected(TransactionStatus::Rejected, 4u8)]
494
495        #[case::TransactionType_Open(TransactionType::Open, 0u8)]
496        #[case::TransactionType_Pending(TransactionType::Pending, 1u8)]
497        #[case::TransactionType_Close(TransactionType::Close, 2u8)]
498        #[case::TransactionType_Modify(TransactionType::Modify, 3u8)]
499        #[case::TransactionType_Delete(TransactionType::Delete, 4u8)]
500        fn try_from_primitive<T: TryFrom<P> + PartialEq + Debug, P>(#[case] expected_value: T, #[case] value: P)
501        where
502            <T as TryFrom<P>>::Error: Debug
503        {
504            let result: T = T::try_from(value).unwrap();
505            assert_eq!(result, expected_value)
506        }
507
508        #[rstest]
509        #[case::QuoteId_Unknown2(QuoteId::Unknown2, 7u8)]
510        #[case::MarginMode_Unknown1(MarginMode::Unknown1, 105u8)]
511        #[case::ProfitMode_CFD(ProfitMode::Cfd, 7u8)]
512        #[case::ImpactLevel_High(ImpactLevel::High, 4u8)]
513        #[case::TimePeriod_PeriodMN1(TimePeriod::PeriodMN1, 43201u16)]
514        #[case::TradingAction_Sell(TradingAction::Sell, 2u8)]
515        #[case::TradingCommand_Credit(TradingCommand::Credit, 8u8)]
516        #[case::DayOfWeek_Sunday(DayOfWeek::Sunday, 8u8)]
517        #[case::TransactionStatus_Rejected(TransactionStatus::Rejected, 5u8)]
518        #[case::TransactionType_Delete(TransactionType::Delete, 5u8)]
519        fn try_from_invalid_primitive<T: TryFrom<P> + PartialEq + Debug, P>(#[case] expected_value: T, #[case] value: P)
520        where
521            <T as TryFrom<P>>::Error: Debug
522        {
523            let result = T::try_from(value);
524            assert!(result.is_err())
525        }
526    }
527}