Skip to main content

oanda_client/models/
trade.rs

1//! OANDA v20 trade definitions.
2use super::{ClientExtensions, StopLossOrder, TakeProfitOrder, TrailingStopLossOrder};
3use crate::ids::{InstrumentName, OrderID, TradeID, TransactionID};
4use crate::timestamp::Timestamp;
5use rust_decimal::Decimal;
6use serde::{Deserialize, Serialize};
7
8provider_enum! {
9    /// The current state of the Trade.
10    #[derive(Debug, Clone, PartialEq, Eq, Hash)]
11    #[non_exhaustive]
12    pub enum TradeState {
13        /// The Trade is currently open
14        Open => "OPEN",
15        /// The Trade has been fully closed
16        Closed => "CLOSED",
17        /// The Trade will be closed as soon as the trade’s instrument becomes tradeable
18        CloseWhenTradeable => "CLOSE_WHEN_TRADEABLE",
19        ;
20        /// An unrecognized provider value, preserved for forward compatibility.
21        Unknown(String),
22    }
23}
24
25provider_enum! {
26    /// Unrecognized spellings are retained and serialized unchanged for provider
27    /// compatibility; endpoint admission applies any operation-specific restrictions.
28    /// The state to filter the Trades by
29    #[derive(Debug, Clone, PartialEq, Eq, Hash)]
30    #[non_exhaustive]
31    pub enum TradeStateFilter {
32        /// The Trades that are currently open
33        Open => "OPEN",
34        /// The Trades that have been fully closed
35        Closed => "CLOSED",
36        /// The Trades that will be closed as soon as the trades’ instrument becomes tradeable
37        CloseWhenTradeable => "CLOSE_WHEN_TRADEABLE",
38        /// The Trades that are in any of the possible states listed above.
39        All => "ALL",
40        ;
41        /// An unrecognized provider value, preserved for forward compatibility.
42        Unknown(String),
43    }
44}
45
46/// The specification of a Trade within an Account. This includes the full representation of the Trade’s
47/// dependent Orders in addition to the IDs of those Orders.
48#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
49#[serde(rename_all = "camelCase")]
50pub struct Trade {
51    /// The Trade’s identifier, unique within the Trade’s Account.
52    #[serde(rename = "id", default, skip_serializing_if = "Option::is_none")]
53    pub id: Option<TradeID>,
54    /// The Trade’s Instrument.
55    #[serde(
56        rename = "instrument",
57        default,
58        skip_serializing_if = "Option::is_none"
59    )]
60    pub instrument: Option<InstrumentName>,
61    /// The execution price of the Trade.
62    #[serde(rename = "price", default, skip_serializing_if = "Option::is_none")]
63    #[serde(deserialize_with = "crate::decimal_wire::optional_number_or_string")]
64    pub price: Option<Decimal>,
65    /// The date/time when the Trade was opened.
66    #[serde(rename = "openTime", default, skip_serializing_if = "Option::is_none")]
67    pub open_time: Option<Timestamp>,
68    /// The current state of the Trade.
69    #[serde(rename = "state", default, skip_serializing_if = "Option::is_none")]
70    pub state: Option<TradeState>,
71    /// The initial size of the Trade. Negative values indicate a short Trade, and positive values indicate a
72    /// long Trade.
73    #[serde(
74        rename = "initialUnits",
75        default,
76        skip_serializing_if = "Option::is_none"
77    )]
78    #[serde(deserialize_with = "crate::decimal_wire::optional_number_or_string")]
79    pub initial_units: Option<Decimal>,
80    /// The margin required at the time the Trade was created. Note, this is the ‘pure’ margin required, it is
81    /// not the ‘effective’ margin used that factors in the trade risk if a GSLO is attached to the trade.
82    #[serde(
83        rename = "initialMarginRequired",
84        default,
85        skip_serializing_if = "Option::is_none"
86    )]
87    #[serde(deserialize_with = "crate::decimal_wire::optional_number_or_string")]
88    pub initial_margin_required: Option<Decimal>,
89    /// The number of units currently open for the Trade. This value is reduced to 0.0 as the Trade is closed.
90    #[serde(
91        rename = "currentUnits",
92        default,
93        skip_serializing_if = "Option::is_none"
94    )]
95    #[serde(deserialize_with = "crate::decimal_wire::optional_number_or_string")]
96    pub current_units: Option<Decimal>,
97    /// The total profit/loss realized on the closed portion of the Trade.
98    #[serde(
99        rename = "realizedPL",
100        default,
101        skip_serializing_if = "Option::is_none"
102    )]
103    #[serde(deserialize_with = "crate::decimal_wire::optional_number_or_string")]
104    pub realized_pl: Option<Decimal>,
105    /// The unrealized profit/loss on the open portion of the Trade.
106    #[serde(
107        rename = "unrealizedPL",
108        default,
109        skip_serializing_if = "Option::is_none"
110    )]
111    #[serde(deserialize_with = "crate::decimal_wire::optional_number_or_string")]
112    pub unrealized_pl: Option<Decimal>,
113    /// Margin currently used by the Trade.
114    #[serde(
115        rename = "marginUsed",
116        default,
117        skip_serializing_if = "Option::is_none"
118    )]
119    #[serde(deserialize_with = "crate::decimal_wire::optional_number_or_string")]
120    pub margin_used: Option<Decimal>,
121    /// The average closing price of the Trade. Only present if the Trade has been closed or reduced at least
122    /// once.
123    #[serde(
124        rename = "averageClosePrice",
125        default,
126        skip_serializing_if = "Option::is_none"
127    )]
128    #[serde(deserialize_with = "crate::decimal_wire::optional_number_or_string")]
129    pub average_close_price: Option<Decimal>,
130    /// The IDs of the Transactions that have closed portions of this Trade.
131    #[serde(
132        rename = "closingTransactionIDs",
133        default,
134        skip_serializing_if = "Option::is_none"
135    )]
136    pub closing_transaction_ids: Option<Vec<TransactionID>>,
137    /// The financing paid/collected for this Trade.
138    #[serde(rename = "financing", default, skip_serializing_if = "Option::is_none")]
139    #[serde(deserialize_with = "crate::decimal_wire::optional_number_or_string")]
140    pub financing: Option<Decimal>,
141    /// The dividend adjustment paid for this Trade.
142    #[serde(
143        rename = "dividendAdjustment",
144        default,
145        skip_serializing_if = "Option::is_none"
146    )]
147    #[serde(deserialize_with = "crate::decimal_wire::optional_number_or_string")]
148    pub dividend_adjustment: Option<Decimal>,
149    /// The date/time when the Trade was fully closed. Only provided for Trades whose state is CLOSED.
150    #[serde(rename = "closeTime", default, skip_serializing_if = "Option::is_none")]
151    pub close_time: Option<Timestamp>,
152    /// The client extensions of the Trade.
153    #[serde(
154        rename = "clientExtensions",
155        default,
156        skip_serializing_if = "Option::is_none"
157    )]
158    pub client_extensions: Option<ClientExtensions>,
159    /// Full representation of the Trade’s Take Profit Order, only provided if such an Order exists.
160    #[serde(
161        rename = "takeProfitOrder",
162        default,
163        skip_serializing_if = "Option::is_none"
164    )]
165    pub take_profit_order: Option<TakeProfitOrder>,
166    /// Full representation of the Trade’s Stop Loss Order, only provided if such an Order exists.
167    #[serde(
168        rename = "stopLossOrder",
169        default,
170        skip_serializing_if = "Option::is_none"
171    )]
172    pub stop_loss_order: Option<StopLossOrder>,
173    /// Full representation of the Trade’s Trailing Stop Loss Order, only provided if such an Order exists.
174    #[serde(
175        rename = "trailingStopLossOrder",
176        default,
177        skip_serializing_if = "Option::is_none"
178    )]
179    pub trailing_stop_loss_order: Option<TrailingStopLossOrder>,
180}
181
182/// The summary of a Trade within an Account. This representation does not provide the full details of the
183/// Trade’s dependent Orders.
184#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
185#[serde(rename_all = "camelCase")]
186pub struct TradeSummary {
187    /// The Trade’s identifier, unique within the Trade’s Account.
188    #[serde(rename = "id", default, skip_serializing_if = "Option::is_none")]
189    pub id: Option<TradeID>,
190    /// The Trade’s Instrument.
191    #[serde(
192        rename = "instrument",
193        default,
194        skip_serializing_if = "Option::is_none"
195    )]
196    pub instrument: Option<InstrumentName>,
197    /// The execution price of the Trade.
198    #[serde(rename = "price", default, skip_serializing_if = "Option::is_none")]
199    #[serde(deserialize_with = "crate::decimal_wire::optional_number_or_string")]
200    pub price: Option<Decimal>,
201    /// The date/time when the Trade was opened.
202    #[serde(rename = "openTime", default, skip_serializing_if = "Option::is_none")]
203    pub open_time: Option<Timestamp>,
204    /// The current state of the Trade.
205    #[serde(rename = "state", default, skip_serializing_if = "Option::is_none")]
206    pub state: Option<TradeState>,
207    /// The initial size of the Trade. Negative values indicate a short Trade, and positive values indicate a
208    /// long Trade.
209    #[serde(
210        rename = "initialUnits",
211        default,
212        skip_serializing_if = "Option::is_none"
213    )]
214    #[serde(deserialize_with = "crate::decimal_wire::optional_number_or_string")]
215    pub initial_units: Option<Decimal>,
216    /// The margin required at the time the Trade was created. Note, this is the ‘pure’ margin required, it is
217    /// not the ‘effective’ margin used that factors in the trade risk if a GSLO is attached to the trade.
218    #[serde(
219        rename = "initialMarginRequired",
220        default,
221        skip_serializing_if = "Option::is_none"
222    )]
223    #[serde(deserialize_with = "crate::decimal_wire::optional_number_or_string")]
224    pub initial_margin_required: Option<Decimal>,
225    /// The number of units currently open for the Trade. This value is reduced to 0.0 as the Trade is closed.
226    #[serde(
227        rename = "currentUnits",
228        default,
229        skip_serializing_if = "Option::is_none"
230    )]
231    #[serde(deserialize_with = "crate::decimal_wire::optional_number_or_string")]
232    pub current_units: Option<Decimal>,
233    /// The total profit/loss realized on the closed portion of the Trade.
234    #[serde(
235        rename = "realizedPL",
236        default,
237        skip_serializing_if = "Option::is_none"
238    )]
239    #[serde(deserialize_with = "crate::decimal_wire::optional_number_or_string")]
240    pub realized_pl: Option<Decimal>,
241    /// The unrealized profit/loss on the open portion of the Trade.
242    #[serde(
243        rename = "unrealizedPL",
244        default,
245        skip_serializing_if = "Option::is_none"
246    )]
247    #[serde(deserialize_with = "crate::decimal_wire::optional_number_or_string")]
248    pub unrealized_pl: Option<Decimal>,
249    /// Margin currently used by the Trade.
250    #[serde(
251        rename = "marginUsed",
252        default,
253        skip_serializing_if = "Option::is_none"
254    )]
255    #[serde(deserialize_with = "crate::decimal_wire::optional_number_or_string")]
256    pub margin_used: Option<Decimal>,
257    /// The average closing price of the Trade. Only present if the Trade has been closed or reduced at least
258    /// once.
259    #[serde(
260        rename = "averageClosePrice",
261        default,
262        skip_serializing_if = "Option::is_none"
263    )]
264    #[serde(deserialize_with = "crate::decimal_wire::optional_number_or_string")]
265    pub average_close_price: Option<Decimal>,
266    /// The IDs of the Transactions that have closed portions of this Trade.
267    #[serde(
268        rename = "closingTransactionIDs",
269        default,
270        skip_serializing_if = "Option::is_none"
271    )]
272    pub closing_transaction_ids: Option<Vec<TransactionID>>,
273    /// The financing paid/collected for this Trade.
274    #[serde(rename = "financing", default, skip_serializing_if = "Option::is_none")]
275    #[serde(deserialize_with = "crate::decimal_wire::optional_number_or_string")]
276    pub financing: Option<Decimal>,
277    /// The dividend adjustment paid for this Trade.
278    #[serde(
279        rename = "dividendAdjustment",
280        default,
281        skip_serializing_if = "Option::is_none"
282    )]
283    #[serde(deserialize_with = "crate::decimal_wire::optional_number_or_string")]
284    pub dividend_adjustment: Option<Decimal>,
285    /// The date/time when the Trade was fully closed. Only provided for Trades whose state is CLOSED.
286    #[serde(rename = "closeTime", default, skip_serializing_if = "Option::is_none")]
287    pub close_time: Option<Timestamp>,
288    /// The client extensions of the Trade.
289    #[serde(
290        rename = "clientExtensions",
291        default,
292        skip_serializing_if = "Option::is_none"
293    )]
294    pub client_extensions: Option<ClientExtensions>,
295    /// ID of the Trade’s Take Profit Order, only provided if such an Order exists.
296    #[serde(
297        rename = "takeProfitOrderID",
298        default,
299        skip_serializing_if = "Option::is_none"
300    )]
301    pub take_profit_order_id: Option<OrderID>,
302    /// ID of the Trade’s Stop Loss Order, only provided if such an Order exists.
303    #[serde(
304        rename = "stopLossOrderID",
305        default,
306        skip_serializing_if = "Option::is_none"
307    )]
308    pub stop_loss_order_id: Option<OrderID>,
309    /// ID of the Trade’s Guaranteed Stop Loss Order, only provided if such an Order exists.
310    #[serde(
311        rename = "guaranteedStopLossOrderID",
312        default,
313        skip_serializing_if = "Option::is_none"
314    )]
315    pub guaranteed_stop_loss_order_id: Option<OrderID>,
316    /// ID of the Trade’s Trailing Stop Loss Order, only provided if such an Order exists.
317    #[serde(
318        rename = "trailingStopLossOrderID",
319        default,
320        skip_serializing_if = "Option::is_none"
321    )]
322    pub trailing_stop_loss_order_id: Option<OrderID>,
323}
324
325/// The dynamic (calculated) state of an open Trade
326#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
327#[serde(rename_all = "camelCase")]
328pub struct CalculatedTradeState {
329    /// The Trade’s ID.
330    #[serde(rename = "id", default, skip_serializing_if = "Option::is_none")]
331    pub id: Option<TradeID>,
332    /// The Trade’s unrealized profit/loss.
333    #[serde(
334        rename = "unrealizedPL",
335        default,
336        skip_serializing_if = "Option::is_none"
337    )]
338    #[serde(deserialize_with = "crate::decimal_wire::optional_number_or_string")]
339    pub unrealized_pl: Option<Decimal>,
340    /// Margin currently used by the Trade.
341    #[serde(
342        rename = "marginUsed",
343        default,
344        skip_serializing_if = "Option::is_none"
345    )]
346    #[serde(deserialize_with = "crate::decimal_wire::optional_number_or_string")]
347    pub margin_used: Option<Decimal>,
348}
349
350provider_enum! {
351    /// The classification of `TradePLs`.
352    #[derive(Debug, Clone, PartialEq, Eq, Hash)]
353    #[non_exhaustive]
354    pub enum TradePL {
355        /// An open Trade currently has a positive (profitable) unrealized P/L, or a closed Trade realized a
356        /// positive amount of P/L.
357        Positive => "POSITIVE",
358        /// An open Trade currently has a negative (losing) unrealized P/L, or a closed Trade realized a negative
359        /// amount of P/L.
360        Negative => "NEGATIVE",
361        /// An open Trade currently has unrealized P/L of zero (neither profitable nor losing), or a closed Trade
362        /// realized a P/L amount of zero.
363        Zero => "ZERO",
364        ;
365        /// An unrecognized provider value, preserved for forward compatibility.
366        Unknown(String),
367    }
368}