Skip to main content

oanda_client/models/
primitives.rs

1//! OANDA v20 primitives definitions.
2// Shared imports vary by definition family; unused ones are deliberately allowed.
3#[allow(unused_imports)]
4use super::*;
5#[allow(unused_imports)]
6use crate::ids::*;
7#[allow(unused_imports)]
8use crate::timestamp::Timestamp;
9#[allow(unused_imports)]
10use rust_decimal::Decimal;
11#[allow(unused_imports)]
12use serde::{Deserialize, Serialize};
13
14/// A tag associated with an entity.
15#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
16#[serde(rename_all = "camelCase")]
17pub struct Tag {
18    /// The type of the tag.
19    #[serde(rename = "type", default, skip_serializing_if = "Option::is_none")]
20    pub r#type: Option<String>,
21    /// The name of the tag.
22    #[serde(rename = "name", default, skip_serializing_if = "Option::is_none")]
23    pub name: Option<String>,
24}
25
26/// The type of an Instrument.
27#[derive(Debug, Clone, PartialEq, Eq, Hash)]
28#[non_exhaustive]
29pub enum InstrumentType {
30    /// Currency
31    Currency,
32    /// Contract For Difference
33    Cfd,
34    /// Metal
35    Metal,
36    /// An unrecognized provider value, preserved for forward compatibility.
37    Unknown(String),
38}
39
40impl InstrumentType {
41    /// Return the exact provider spelling.
42    pub fn as_str(&self) -> &str {
43        match self {
44            Self::Currency => "CURRENCY",
45            Self::Cfd => "CFD",
46            Self::Metal => "METAL",
47            Self::Unknown(value) => value,
48        }
49    }
50}
51
52impl Serialize for InstrumentType {
53    fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
54        serializer.serialize_str(self.as_str())
55    }
56}
57
58impl<'de> Deserialize<'de> for InstrumentType {
59    fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
60        let value = String::deserialize(deserializer)?;
61        Ok(match value.as_str() {
62            "CURRENCY" => Self::Currency,
63            "CFD" => Self::Cfd,
64            "METAL" => Self::Metal,
65            _ => Self::Unknown(value),
66        })
67    }
68}
69
70/// The DayOfWeek provides a representation of the day of the week.
71#[derive(Debug, Clone, PartialEq, Eq, Hash)]
72#[non_exhaustive]
73pub enum DayOfWeek {
74    /// Sunday
75    Sunday,
76    /// Monday
77    Monday,
78    /// Tuesday
79    Tuesday,
80    /// Wednesday
81    Wednesday,
82    /// Thursday
83    Thursday,
84    /// Friday
85    Friday,
86    /// Saturday
87    Saturday,
88    /// An unrecognized provider value, preserved for forward compatibility.
89    Unknown(String),
90}
91
92impl DayOfWeek {
93    /// Return the exact provider spelling.
94    pub fn as_str(&self) -> &str {
95        match self {
96            Self::Sunday => "SUNDAY",
97            Self::Monday => "MONDAY",
98            Self::Tuesday => "TUESDAY",
99            Self::Wednesday => "WEDNESDAY",
100            Self::Thursday => "THURSDAY",
101            Self::Friday => "FRIDAY",
102            Self::Saturday => "SATURDAY",
103            Self::Unknown(value) => value,
104        }
105    }
106}
107
108impl Serialize for DayOfWeek {
109    fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
110        serializer.serialize_str(self.as_str())
111    }
112}
113
114impl<'de> Deserialize<'de> for DayOfWeek {
115    fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
116        let value = String::deserialize(deserializer)?;
117        Ok(match value.as_str() {
118            "SUNDAY" => Self::Sunday,
119            "MONDAY" => Self::Monday,
120            "TUESDAY" => Self::Tuesday,
121            "WEDNESDAY" => Self::Wednesday,
122            "THURSDAY" => Self::Thursday,
123            "FRIDAY" => Self::Friday,
124            "SATURDAY" => Self::Saturday,
125            _ => Self::Unknown(value),
126        })
127    }
128}
129
130/// A FinancingDayOfWeek message defines a day of the week when financing charges are debited or credited.
131#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
132#[serde(rename_all = "camelCase")]
133pub struct FinancingDayOfWeek {
134    /// The day of the week to charge the financing.
135    #[serde(rename = "dayOfWeek", default, skip_serializing_if = "Option::is_none")]
136    pub day_of_week: Option<DayOfWeek>,
137    /// The number of days worth of financing to be charged on dayOfWeek.
138    #[serde(
139        rename = "daysCharged",
140        default,
141        skip_serializing_if = "Option::is_none"
142    )]
143    pub days_charged: Option<i64>,
144}
145
146/// Financing data for the instrument.
147#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
148#[serde(rename_all = "camelCase")]
149pub struct InstrumentFinancing {
150    /// The financing rate to be used for a long position for the instrument. The value is in decimal rather
151    /// than percentage points, i.e. 5% is represented as 0.05.
152    #[serde(rename = "longRate", default, skip_serializing_if = "Option::is_none")]
153    #[serde(deserialize_with = "crate::decimal_wire::optional_number_or_string")]
154    pub long_rate: Option<Decimal>,
155    /// The financing rate to be used for a short position for the instrument. The value is in decimal rather
156    /// than percentage points, i.e. 5% is represented as 0.05.
157    #[serde(rename = "shortRate", default, skip_serializing_if = "Option::is_none")]
158    #[serde(deserialize_with = "crate::decimal_wire::optional_number_or_string")]
159    pub short_rate: Option<Decimal>,
160    /// The days of the week to debit or credit financing charges; the exact time of day at which to charge the
161    /// financing is set in the DivisionTradingGroup for the client’s account.
162    #[serde(
163        rename = "financingDaysOfWeek",
164        default,
165        skip_serializing_if = "Option::is_none"
166    )]
167    pub financing_days_of_week: Option<Vec<FinancingDayOfWeek>>,
168}
169
170/// Full specification of an Instrument.
171#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
172#[serde(rename_all = "camelCase")]
173pub struct Instrument {
174    /// The name of the Instrument
175    #[serde(rename = "name", default, skip_serializing_if = "Option::is_none")]
176    pub name: Option<InstrumentName>,
177    /// The type of the Instrument
178    #[serde(rename = "type", default, skip_serializing_if = "Option::is_none")]
179    pub r#type: Option<InstrumentType>,
180    /// The display name of the Instrument
181    #[serde(
182        rename = "displayName",
183        default,
184        skip_serializing_if = "Option::is_none"
185    )]
186    pub display_name: Option<String>,
187    /// The location of the “pip” for this instrument. The decimal position of the pip in this Instrument’s
188    /// price can be found at 10 ^ pipLocation (e.g. -4 pipLocation results in a decimal pip position of 10 ^ -4
189    /// = 0.0001).
190    #[serde(
191        rename = "pipLocation",
192        default,
193        skip_serializing_if = "Option::is_none"
194    )]
195    pub pip_location: Option<i64>,
196    /// The number of decimal places that should be used to display prices for this instrument. (e.g. a
197    /// displayPrecision of 5 would result in a price of “1” being displayed as “1.00000”)
198    #[serde(
199        rename = "displayPrecision",
200        default,
201        skip_serializing_if = "Option::is_none"
202    )]
203    pub display_precision: Option<i64>,
204    /// The amount of decimal places that may be provided when specifying the number of units traded for this
205    /// instrument.
206    #[serde(
207        rename = "tradeUnitsPrecision",
208        default,
209        skip_serializing_if = "Option::is_none"
210    )]
211    pub trade_units_precision: Option<i64>,
212    /// The smallest number of units allowed to be traded for this instrument.
213    #[serde(
214        rename = "minimumTradeSize",
215        default,
216        skip_serializing_if = "Option::is_none"
217    )]
218    #[serde(deserialize_with = "crate::decimal_wire::optional_number_or_string")]
219    pub minimum_trade_size: Option<Decimal>,
220    /// The maximum trailing stop distance allowed for a trailing stop loss created for this instrument.
221    /// Specified in price units.
222    #[serde(
223        rename = "maximumTrailingStopDistance",
224        default,
225        skip_serializing_if = "Option::is_none"
226    )]
227    #[serde(deserialize_with = "crate::decimal_wire::optional_number_or_string")]
228    pub maximum_trailing_stop_distance: Option<Decimal>,
229    /// The minimum distance allowed between the Trade’s fill price and the configured price for guaranteed Stop
230    /// Loss Orders created for this instrument. Specified in price units.
231    #[serde(
232        rename = "minimumGuaranteedStopLossDistance",
233        default,
234        skip_serializing_if = "Option::is_none"
235    )]
236    #[serde(deserialize_with = "crate::decimal_wire::optional_number_or_string")]
237    pub minimum_guaranteed_stop_loss_distance: Option<Decimal>,
238    /// The minimum trailing stop distance allowed for a trailing stop loss created for this instrument.
239    /// Specified in price units.
240    #[serde(
241        rename = "minimumTrailingStopDistance",
242        default,
243        skip_serializing_if = "Option::is_none"
244    )]
245    #[serde(deserialize_with = "crate::decimal_wire::optional_number_or_string")]
246    pub minimum_trailing_stop_distance: Option<Decimal>,
247    /// The maximum position size allowed for this instrument. Specified in units.
248    #[serde(
249        rename = "maximumPositionSize",
250        default,
251        skip_serializing_if = "Option::is_none"
252    )]
253    #[serde(deserialize_with = "crate::decimal_wire::optional_number_or_string")]
254    pub maximum_position_size: Option<Decimal>,
255    /// The maximum units allowed for an Order placed for this instrument. Specified in units.
256    #[serde(
257        rename = "maximumOrderUnits",
258        default,
259        skip_serializing_if = "Option::is_none"
260    )]
261    #[serde(deserialize_with = "crate::decimal_wire::optional_number_or_string")]
262    pub maximum_order_units: Option<Decimal>,
263    /// The margin rate for this instrument.
264    #[serde(
265        rename = "marginRate",
266        default,
267        skip_serializing_if = "Option::is_none"
268    )]
269    #[serde(deserialize_with = "crate::decimal_wire::optional_number_or_string")]
270    pub margin_rate: Option<Decimal>,
271    /// The commission structure for this instrument.
272    #[serde(
273        rename = "commission",
274        default,
275        skip_serializing_if = "Option::is_none"
276    )]
277    pub commission: Option<InstrumentCommission>,
278    /// The current Guaranteed Stop Loss Order mode of the Account for this Instrument.
279    #[serde(
280        rename = "guaranteedStopLossOrderMode",
281        default,
282        skip_serializing_if = "Option::is_none"
283    )]
284    pub guaranteed_stop_loss_order_mode: Option<GuaranteedStopLossOrderModeForInstrument>,
285    /// The amount that is charged to the account if a guaranteed Stop Loss Order is triggered and filled. The
286    /// value is in price units and is charged for each unit of the Trade. This field will only be present if
287    /// the Account’s guaranteedStopLossOrderMode for this Instrument is not ‘DISABLED’.
288    #[serde(
289        rename = "guaranteedStopLossOrderExecutionPremium",
290        default,
291        skip_serializing_if = "Option::is_none"
292    )]
293    #[serde(deserialize_with = "crate::decimal_wire::optional_number_or_string")]
294    pub guaranteed_stop_loss_order_execution_premium: Option<Decimal>,
295    /// The guaranteed Stop Loss Order level restriction for this instrument. This field will only be present if
296    /// the Account’s guaranteedStopLossOrderMode for this Instrument is not ‘DISABLED’.
297    #[serde(
298        rename = "guaranteedStopLossOrderLevelRestriction",
299        default,
300        skip_serializing_if = "Option::is_none"
301    )]
302    pub guaranteed_stop_loss_order_level_restriction:
303        Option<GuaranteedStopLossOrderLevelRestriction>,
304    /// Financing data for this instrument.
305    #[serde(rename = "financing", default, skip_serializing_if = "Option::is_none")]
306    pub financing: Option<InstrumentFinancing>,
307    /// The tags associated with this instrument.
308    #[serde(rename = "tags", default, skip_serializing_if = "Option::is_none")]
309    pub tags: Option<Vec<Tag>>,
310}
311
312/// DateTime header
313#[derive(Debug, Clone, PartialEq, Eq, Hash)]
314#[non_exhaustive]
315pub enum AcceptDatetimeFormat {
316    /// If “UNIX” is specified DateTime fields will be specified or returned in the “12345678.000000123” format.
317    Unix,
318    /// If “RFC3339” is specified DateTime will be specified or returned in “YYYY-MM-DDTHH:MM:SS.nnnnnnnnnZ”
319    /// format.
320    Rfc3339,
321    /// An unrecognized provider value, preserved for forward compatibility.
322    Unknown(String),
323}
324
325impl AcceptDatetimeFormat {
326    /// Return the exact provider spelling.
327    pub fn as_str(&self) -> &str {
328        match self {
329            Self::Unix => "UNIX",
330            Self::Rfc3339 => "RFC3339",
331            Self::Unknown(value) => value,
332        }
333    }
334}
335
336impl Serialize for AcceptDatetimeFormat {
337    fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
338        serializer.serialize_str(self.as_str())
339    }
340}
341
342impl<'de> Deserialize<'de> for AcceptDatetimeFormat {
343    fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
344        let value = String::deserialize(deserializer)?;
345        Ok(match value.as_str() {
346            "UNIX" => Self::Unix,
347            "RFC3339" => Self::Rfc3339,
348            _ => Self::Unknown(value),
349        })
350    }
351}
352
353/// An InstrumentCommission represents an instrument-specific commission
354#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
355#[serde(rename_all = "camelCase")]
356pub struct InstrumentCommission {
357    /// The commission amount (in the Account’s home currency) charged per unitsTraded of the instrument
358    #[serde(
359        rename = "commission",
360        default,
361        skip_serializing_if = "Option::is_none"
362    )]
363    #[serde(deserialize_with = "crate::decimal_wire::optional_number_or_string")]
364    pub commission: Option<Decimal>,
365    /// The number of units traded that the commission amount is based on.
366    #[serde(
367        rename = "unitsTraded",
368        default,
369        skip_serializing_if = "Option::is_none"
370    )]
371    #[serde(deserialize_with = "crate::decimal_wire::optional_number_or_string")]
372    pub units_traded: Option<Decimal>,
373    /// The minimum commission amount (in the Account’s home currency) that is charged when an Order is filled
374    /// for this instrument.
375    #[serde(
376        rename = "minimumCommission",
377        default,
378        skip_serializing_if = "Option::is_none"
379    )]
380    #[serde(deserialize_with = "crate::decimal_wire::optional_number_or_string")]
381    pub minimum_commission: Option<Decimal>,
382}
383
384/// The overall behaviour of the Account regarding Guaranteed Stop Loss Orders for a specific Instrument.
385#[derive(Debug, Clone, PartialEq, Eq, Hash)]
386#[non_exhaustive]
387pub enum GuaranteedStopLossOrderModeForInstrument {
388    /// The Account is not permitted to create Guaranteed Stop Loss Orders for this Instrument.
389    Disabled,
390    /// The Account is able, but not required to have Guaranteed Stop Loss Orders for open Trades for this
391    /// Instrument.
392    Allowed,
393    /// The Account is required to have Guaranteed Stop Loss Orders for all open Trades for this Instrument.
394    Required,
395    /// An unrecognized provider value, preserved for forward compatibility.
396    Unknown(String),
397}
398
399impl GuaranteedStopLossOrderModeForInstrument {
400    /// Return the exact provider spelling.
401    pub fn as_str(&self) -> &str {
402        match self {
403            Self::Disabled => "DISABLED",
404            Self::Allowed => "ALLOWED",
405            Self::Required => "REQUIRED",
406            Self::Unknown(value) => value,
407        }
408    }
409}
410
411impl Serialize for GuaranteedStopLossOrderModeForInstrument {
412    fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
413        serializer.serialize_str(self.as_str())
414    }
415}
416
417impl<'de> Deserialize<'de> for GuaranteedStopLossOrderModeForInstrument {
418    fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
419        let value = String::deserialize(deserializer)?;
420        Ok(match value.as_str() {
421            "DISABLED" => Self::Disabled,
422            "ALLOWED" => Self::Allowed,
423            "REQUIRED" => Self::Required,
424            _ => Self::Unknown(value),
425        })
426    }
427}
428
429/// A GuaranteedStopLossOrderLevelRestriction represents the total position size that can exist within a
430/// given price window for Trades with guaranteed Stop Loss Orders attached for a specific Instrument.
431#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
432#[serde(rename_all = "camelCase")]
433pub struct GuaranteedStopLossOrderLevelRestriction {
434    /// Applies to Trades with a guaranteed Stop Loss Order attached for the specified Instrument. This is the
435    /// total allowed Trade volume that can exist within the priceRange based on the trigger prices of the
436    /// guaranteed Stop Loss Orders.
437    #[serde(rename = "volume", default, skip_serializing_if = "Option::is_none")]
438    #[serde(deserialize_with = "crate::decimal_wire::optional_number_or_string")]
439    pub volume: Option<Decimal>,
440    /// The price range the volume applies to. This value is in price units.
441    #[serde(
442        rename = "priceRange",
443        default,
444        skip_serializing_if = "Option::is_none"
445    )]
446    #[serde(deserialize_with = "crate::decimal_wire::optional_number_or_string")]
447    pub price_range: Option<Decimal>,
448}
449
450/// In the context of an Order or a Trade, defines whether the units are positive or negative.
451#[derive(Debug, Clone, PartialEq, Eq, Hash)]
452#[non_exhaustive]
453pub enum Direction {
454    /// A long Order is used to to buy units of an Instrument. A Trade is long when it has bought units of an
455    /// Instrument.
456    Long,
457    /// A short Order is used to to sell units of an Instrument. A Trade is short when it has sold units of an
458    /// Instrument.
459    Short,
460    /// An unrecognized provider value, preserved for forward compatibility.
461    Unknown(String),
462}
463
464impl Direction {
465    /// Return the exact provider spelling.
466    pub fn as_str(&self) -> &str {
467        match self {
468            Self::Long => "LONG",
469            Self::Short => "SHORT",
470            Self::Unknown(value) => value,
471        }
472    }
473}
474
475impl Serialize for Direction {
476    fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
477        serializer.serialize_str(self.as_str())
478    }
479}
480
481impl<'de> Deserialize<'de> for Direction {
482    fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
483        let value = String::deserialize(deserializer)?;
484        Ok(match value.as_str() {
485            "LONG" => Self::Long,
486            "SHORT" => Self::Short,
487            _ => Self::Unknown(value),
488        })
489    }
490}
491
492/// A ConversionFactor contains information used to convert an amount, from an Instrument’s base or quote
493/// currency, to the home currency of an Account.
494#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
495#[serde(rename_all = "camelCase")]
496pub struct ConversionFactor {
497    /// The factor by which to multiply the amount in the given currency to obtain the amount in the home
498    /// currency of the Account.
499    #[serde(rename = "factor", default, skip_serializing_if = "Option::is_none")]
500    #[serde(deserialize_with = "crate::decimal_wire::optional_number_or_string")]
501    pub factor: Option<Decimal>,
502}
503
504/// A HomeConversionFactors message contains information used to convert amounts, from an Instrument’s base
505/// or quote currency, to the home currency of an Account.
506#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
507#[serde(rename_all = "camelCase")]
508pub struct HomeConversionFactors {
509    /// The ConversionFactor in effect for the Account for converting any gains realized in Instrument quote
510    /// units into units of the Account’s home currency.
511    #[serde(
512        rename = "gainQuoteHome",
513        default,
514        skip_serializing_if = "Option::is_none"
515    )]
516    pub gain_quote_home: Option<ConversionFactor>,
517    /// The ConversionFactor in effect for the Account for converting any losses realized in Instrument quote
518    /// units into units of the Account’s home currency.
519    #[serde(
520        rename = "lossQuoteHome",
521        default,
522        skip_serializing_if = "Option::is_none"
523    )]
524    pub loss_quote_home: Option<ConversionFactor>,
525    /// The ConversionFactor in effect for the Account for converting any gains realized in Instrument base
526    /// units into units of the Account’s home currency.
527    #[serde(
528        rename = "gainBaseHome",
529        default,
530        skip_serializing_if = "Option::is_none"
531    )]
532    pub gain_base_home: Option<ConversionFactor>,
533    /// The ConversionFactor in effect for the Account for converting any losses realized in Instrument base
534    /// units into units of the Account’s home currency.
535    #[serde(
536        rename = "lossBaseHome",
537        default,
538        skip_serializing_if = "Option::is_none"
539    )]
540    pub loss_base_home: Option<ConversionFactor>,
541}