oanda_client/models/pricing.rs
1//! OANDA v20 pricing definitions.
2use super::{PriceBucket, UnitsAvailable};
3use crate::ids::{Currency, InstrumentName};
4use crate::timestamp::Timestamp;
5use rust_decimal::Decimal;
6use serde::{Deserialize, Serialize};
7
8/// The specification of an Account-specific Price.
9#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
10#[serde(rename_all = "camelCase")]
11pub struct ClientPrice {
12 /// The string “PRICE”. Used to identify the a Price object when found in a stream.
13 /// This optional wire field preserves provider evidence. Stream consumers use
14 /// [`crate::PriceStreamEvent`] for typed event dispatch.
15 #[serde(rename = "type", default, skip_serializing_if = "Option::is_none")]
16 pub r#type: Option<String>,
17 /// The Price’s Instrument.
18 #[serde(
19 rename = "instrument",
20 default,
21 skip_serializing_if = "Option::is_none"
22 )]
23 pub instrument: Option<InstrumentName>,
24 /// The date/time when the Price was created
25 #[serde(rename = "time", default, skip_serializing_if = "Option::is_none")]
26 pub time: Option<Timestamp>,
27 /// The status of the Price. Deprecated: Will be removed in a future API update.
28 #[serde(rename = "status", default, skip_serializing_if = "Option::is_none")]
29 pub status: Option<PriceStatus>,
30 /// Flag indicating if the Price is tradeable or not
31 #[serde(rename = "tradeable", default, skip_serializing_if = "Option::is_none")]
32 pub tradeable: Option<bool>,
33 /// The list of prices and liquidity available on the Instrument’s bid side. It is possible for this list to
34 /// be empty if there is no bid liquidity currently available for the Instrument in the Account.
35 #[serde(rename = "bids", default, skip_serializing_if = "Option::is_none")]
36 pub bids: Option<Vec<PriceBucket>>,
37 /// The list of prices and liquidity available on the Instrument’s ask side. It is possible for this list to
38 /// be empty if there is no ask liquidity currently available for the Instrument in the Account.
39 #[serde(rename = "asks", default, skip_serializing_if = "Option::is_none")]
40 pub asks: Option<Vec<PriceBucket>>,
41 /// The closeout bid Price. This Price is used when a bid is required to closeout a Position (margin
42 /// closeout or manual) yet there is no bid liquidity. The closeout bid is never used to open a new position.
43 #[serde(
44 rename = "closeoutBid",
45 default,
46 skip_serializing_if = "Option::is_none"
47 )]
48 #[serde(deserialize_with = "crate::decimal_wire::optional_number_or_string")]
49 pub closeout_bid: Option<Decimal>,
50 /// The closeout ask Price. This Price is used when a ask is required to closeout a Position (margin
51 /// closeout or manual) yet there is no ask liquidity. The closeout ask is never used to open a new position.
52 #[serde(
53 rename = "closeoutAsk",
54 default,
55 skip_serializing_if = "Option::is_none"
56 )]
57 #[serde(deserialize_with = "crate::decimal_wire::optional_number_or_string")]
58 pub closeout_ask: Option<Decimal>,
59 /// The factors used to convert quantities of this price’s Instrument’s quote currency into a quantity of
60 /// the Account’s home currency. When the includeHomeConversions is present in the pricing request
61 /// (regardless of its value), this field will not be present. Deprecated: Will be removed in a future API
62 /// update.
63 #[serde(
64 rename = "quoteHomeConversionFactors",
65 default,
66 skip_serializing_if = "Option::is_none"
67 )]
68 pub quote_home_conversion_factors: Option<QuoteHomeConversionFactors>,
69 /// Representation of how many units of an Instrument are available to be traded by an Order depending on
70 /// its positionFill option. Deprecated: Will be removed in a future API update.
71 #[serde(
72 rename = "unitsAvailable",
73 default,
74 skip_serializing_if = "Option::is_none"
75 )]
76 pub units_available: Option<UnitsAvailable>,
77}
78
79provider_enum! {
80 /// The status of the Price.
81 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
82 #[non_exhaustive]
83 pub enum PriceStatus {
84 /// The Instrument’s price is tradeable.
85 Tradeable => "tradeable",
86 /// The Instrument’s price is not tradeable.
87 NonTradeable => "non-tradeable",
88 /// The Instrument of the price is invalid or there is no valid Price for the Instrument.
89 Invalid => "invalid",
90 ;
91 /// An unrecognized provider value, preserved for forward compatibility.
92 Unknown(String),
93 }
94}
95
96/// `QuoteHomeConversionFactors` represents the factors that can be used to convert quantities of a Price’s
97/// Instrument’s quote currency into the Account’s home currency.
98#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
99#[serde(rename_all = "camelCase")]
100pub struct QuoteHomeConversionFactors {
101 /// The factor used to convert a positive amount of the Price’s Instrument’s quote currency into a positive
102 /// amount of the Account’s home currency. Conversion is performed by multiplying the quote units by the
103 /// conversion factor.
104 #[serde(
105 rename = "positiveUnits",
106 default,
107 skip_serializing_if = "Option::is_none"
108 )]
109 #[serde(deserialize_with = "crate::decimal_wire::optional_number_or_string")]
110 pub positive_units: Option<Decimal>,
111 /// The factor used to convert a negative amount of the Price’s Instrument’s quote currency into a negative
112 /// amount of the Account’s home currency. Conversion is performed by multiplying the quote units by the
113 /// conversion factor.
114 #[serde(
115 rename = "negativeUnits",
116 default,
117 skip_serializing_if = "Option::is_none"
118 )]
119 #[serde(deserialize_with = "crate::decimal_wire::optional_number_or_string")]
120 pub negative_units: Option<Decimal>,
121}
122
123/// `HomeConversions` represents the factors to use to convert quantities of a given currency into the
124/// Account’s home currency. The conversion factor depends on the scenario the conversion is required for.
125#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
126#[serde(rename_all = "camelCase")]
127pub struct HomeConversions {
128 /// The currency to be converted into the home currency.
129 #[serde(rename = "currency", default, skip_serializing_if = "Option::is_none")]
130 pub currency: Option<Currency>,
131 /// The factor used to convert any gains for an Account in the specified currency into the Account’s home
132 /// currency. This would include positive realized P/L and positive financing amounts. Conversion is
133 /// performed by multiplying the positive P/L by the conversion factor.
134 #[serde(
135 rename = "accountGain",
136 default,
137 skip_serializing_if = "Option::is_none"
138 )]
139 #[serde(deserialize_with = "crate::decimal_wire::optional_number_or_string")]
140 pub account_gain: Option<Decimal>,
141 /// The factor used to convert any losses for an Account in the specified currency into the Account’s home
142 /// currency. This would include negative realized P/L and negative financing amounts. Conversion is
143 /// performed by multiplying the positive P/L by the conversion factor.
144 #[serde(
145 rename = "accountLoss",
146 default,
147 skip_serializing_if = "Option::is_none"
148 )]
149 #[serde(deserialize_with = "crate::decimal_wire::optional_number_or_string")]
150 pub account_loss: Option<Decimal>,
151 /// The factor used to convert a Position or Trade Value in the specified currency into the Account’s home
152 /// currency. Conversion is performed by multiplying the Position or Trade Value by the conversion factor.
153 #[serde(
154 rename = "positionValue",
155 default,
156 skip_serializing_if = "Option::is_none"
157 )]
158 #[serde(deserialize_with = "crate::decimal_wire::optional_number_or_string")]
159 pub position_value: Option<Decimal>,
160}
161
162/// A `PricingHeartbeat` object is injected into the Pricing stream to ensure that the HTTP connection remains
163/// active.
164#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
165#[serde(rename_all = "camelCase")]
166pub struct PricingHeartbeat {
167 /// The string “HEARTBEAT”
168 /// This optional wire field preserves provider evidence; use
169 /// [`crate::PriceStreamEvent`] for typed stream dispatch.
170 #[serde(rename = "type", default, skip_serializing_if = "Option::is_none")]
171 pub r#type: Option<String>,
172 /// The date/time when the Heartbeat was created.
173 #[serde(rename = "time", default, skip_serializing_if = "Option::is_none")]
174 pub time: Option<Timestamp>,
175}