Skip to main content

oanda_client/
order.rs

1//! OANDA order endpoint contracts.
2// Shared imports vary by capability; unused ones are deliberately allowed.
3#[allow(unused_imports)]
4use crate::Timestamp;
5#[allow(unused_imports)]
6use crate::ids::*;
7#[allow(unused_imports)]
8use crate::models::*;
9#[allow(unused_imports)]
10use crate::{Client, Result};
11#[allow(unused_imports)]
12use reqwest::Method;
13#[allow(unused_imports)]
14use rust_decimal::Decimal;
15#[allow(unused_imports)]
16use serde::{Deserialize, Serialize};
17
18/// Request body for `create_order`.
19#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
20#[serde(rename_all = "camelCase")]
21pub struct CreateOrderBody {
22    /// Specification of the Order to create
23    #[serde(rename = "order", default, skip_serializing_if = "Option::is_none")]
24    pub order: Option<OrderRequest>,
25}
26
27/// Successful response for `create_order`.
28#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
29#[serde(rename_all = "camelCase")]
30pub struct CreateOrderResponse {
31    /// The Transaction that created the Order specified by the request.
32    #[serde(
33        rename = "orderCreateTransaction",
34        default,
35        skip_serializing_if = "Option::is_none"
36    )]
37    pub order_create_transaction: Option<Transaction>,
38    /// The Transaction that filled the newly created Order. Only provided when the Order was immediately filled.
39    #[serde(
40        rename = "orderFillTransaction",
41        default,
42        skip_serializing_if = "Option::is_none"
43    )]
44    pub order_fill_transaction: Option<OrderFillTransaction>,
45    /// The Transaction that cancelled the newly created Order. Only provided when the Order was immediately
46    /// cancelled.
47    #[serde(
48        rename = "orderCancelTransaction",
49        default,
50        skip_serializing_if = "Option::is_none"
51    )]
52    pub order_cancel_transaction: Option<OrderCancelTransaction>,
53    /// The Transaction that reissues the Order. Only provided when the Order is configured to be reissued for
54    /// its remaining units after a partial fill and the reissue was successful.
55    #[serde(
56        rename = "orderReissueTransaction",
57        default,
58        skip_serializing_if = "Option::is_none"
59    )]
60    pub order_reissue_transaction: Option<Transaction>,
61    /// The Transaction that rejects the reissue of the Order. Only provided when the Order is configured to be
62    /// reissued for its remaining units after a partial fill and the reissue was rejected.
63    #[serde(
64        rename = "orderReissueRejectTransaction",
65        default,
66        skip_serializing_if = "Option::is_none"
67    )]
68    pub order_reissue_reject_transaction: Option<Transaction>,
69    /// The IDs of all Transactions that were created while satisfying the request.
70    #[serde(
71        rename = "relatedTransactionIDs",
72        default,
73        skip_serializing_if = "Option::is_none"
74    )]
75    pub related_transaction_ids: Option<Vec<TransactionID>>,
76    /// The ID of the most recent Transaction created for the Account
77    #[serde(
78        rename = "lastTransactionID",
79        default,
80        skip_serializing_if = "Option::is_none"
81    )]
82    pub last_transaction_id: Option<TransactionID>,
83}
84
85/// Documented rejection fields for `create_order`.
86#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Default)]
87#[serde(rename_all = "camelCase")]
88pub struct CreateOrderRejection {
89    /// The Transaction that rejected the creation of the Order as requested
90    #[serde(
91        rename = "orderRejectTransaction",
92        default,
93        skip_serializing_if = "Option::is_none"
94    )]
95    pub order_reject_transaction: Option<Transaction>,
96    /// The IDs of all Transactions that were created while satisfying the request.
97    #[serde(
98        rename = "relatedTransactionIDs",
99        default,
100        skip_serializing_if = "Option::is_none"
101    )]
102    pub related_transaction_ids: Option<Vec<TransactionID>>,
103    /// The ID of the most recent Transaction created for the Account
104    #[serde(
105        rename = "lastTransactionID",
106        default,
107        skip_serializing_if = "Option::is_none"
108    )]
109    pub last_transaction_id: Option<TransactionID>,
110    /// The code of the error that has occurred. This field may not be returned for some errors.
111    #[serde(rename = "errorCode", default, skip_serializing_if = "Option::is_none")]
112    pub error_code: Option<String>,
113    /// The human-readable description of the error that has occurred.
114    #[serde(
115        rename = "errorMessage",
116        default,
117        skip_serializing_if = "Option::is_none"
118    )]
119    pub error_message: Option<String>,
120}
121
122impl Client {
123    /// Create order.
124    pub async fn create_order(
125        &self,
126        account_id: &AccountID,
127        body: &CreateOrderBody,
128    ) -> std::result::Result<
129        crate::ApiResponse<CreateOrderResponse>,
130        crate::OperationError<CreateOrderRejection>,
131    > {
132        let account_id_encoded = crate::client::segment(account_id.as_str());
133        let path = format!("/v3/accounts/{account_id_encoded}/orders");
134        self.execute(
135            Method::POST,
136            &path,
137            None::<&()>,
138            Some(body),
139            Some(crate::client::MutationAdmission::Ordinary(account_id)),
140            None,
141        )
142        .await
143    }
144}
145
146/// Query parameters for `list_orders`.
147#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Default)]
148#[serde(rename_all = "camelCase")]
149pub struct ListOrdersQuery {
150    /// List of Order IDs to retrieve
151    #[serde(rename = "ids", default, skip_serializing_if = "Option::is_none")]
152    pub ids: Option<Vec<OrderID>>,
153    /// The state to filter the requested Orders by \[default=PENDING\]
154    #[serde(rename = "state", default, skip_serializing_if = "Option::is_none")]
155    pub state: Option<OrderStateFilter>,
156    /// The instrument to filter the requested orders by
157    #[serde(
158        rename = "instrument",
159        default,
160        skip_serializing_if = "Option::is_none"
161    )]
162    pub instrument: Option<InstrumentName>,
163    /// The maximum number of Orders to return \[default=50, maximum=500\]
164    #[serde(rename = "count", default, skip_serializing_if = "Option::is_none")]
165    pub count: Option<i64>,
166    /// The maximum Order ID to return. If not provided the most recent Orders in the Account are returned
167    #[serde(rename = "beforeID", default, skip_serializing_if = "Option::is_none")]
168    pub before_id: Option<OrderID>,
169}
170
171/// Successful response for `list_orders`.
172#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
173#[serde(rename_all = "camelCase")]
174pub struct ListOrdersResponse {
175    /// The list of Order detail objects
176    #[serde(rename = "orders", default, skip_serializing_if = "Option::is_none")]
177    pub orders: Option<Vec<Order>>,
178    /// The ID of the most recent Transaction created for the Account
179    #[serde(
180        rename = "lastTransactionID",
181        default,
182        skip_serializing_if = "Option::is_none"
183    )]
184    pub last_transaction_id: Option<TransactionID>,
185}
186
187impl Client {
188    /// List orders.
189    pub async fn list_orders(
190        &self,
191        account_id: &AccountID,
192        query: Option<&ListOrdersQuery>,
193    ) -> std::result::Result<
194        crate::ApiResponse<ListOrdersResponse>,
195        crate::OperationError<crate::GenericRejection>,
196    > {
197        let account_id_encoded = crate::client::segment(account_id.as_str());
198        let path = format!("/v3/accounts/{account_id_encoded}/orders");
199        self.execute(Method::GET, &path, query, None::<&()>, None, None)
200            .await
201    }
202}
203
204/// Successful response for `list_pending_orders`.
205#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
206#[serde(rename_all = "camelCase")]
207pub struct ListPendingOrdersResponse {
208    /// The list of pending Order details
209    #[serde(rename = "orders", default, skip_serializing_if = "Option::is_none")]
210    pub orders: Option<Vec<Order>>,
211    /// The ID of the most recent Transaction created for the Account
212    #[serde(
213        rename = "lastTransactionID",
214        default,
215        skip_serializing_if = "Option::is_none"
216    )]
217    pub last_transaction_id: Option<TransactionID>,
218}
219
220impl Client {
221    /// List pending orders.
222    pub async fn list_pending_orders(
223        &self,
224        account_id: &AccountID,
225    ) -> std::result::Result<
226        crate::ApiResponse<ListPendingOrdersResponse>,
227        crate::OperationError<crate::GenericRejection>,
228    > {
229        let account_id_encoded = crate::client::segment(account_id.as_str());
230        let path = format!("/v3/accounts/{account_id_encoded}/pendingOrders");
231        self.execute(Method::GET, &path, None::<&()>, None::<&()>, None, None)
232            .await
233    }
234}
235
236/// Successful response for `order_details`.
237#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
238#[serde(rename_all = "camelCase")]
239pub struct OrderDetailsResponse {
240    /// The details of the Order requested
241    #[serde(rename = "order", default, skip_serializing_if = "Option::is_none")]
242    pub order: Option<Order>,
243    /// The ID of the most recent Transaction created for the Account
244    #[serde(
245        rename = "lastTransactionID",
246        default,
247        skip_serializing_if = "Option::is_none"
248    )]
249    pub last_transaction_id: Option<TransactionID>,
250}
251
252impl Client {
253    /// Order details.
254    pub async fn order_details(
255        &self,
256        account_id: &AccountID,
257        order_specifier: &OrderSpecifier,
258    ) -> std::result::Result<
259        crate::ApiResponse<OrderDetailsResponse>,
260        crate::OperationError<crate::GenericRejection>,
261    > {
262        let account_id_encoded = crate::client::segment(account_id.as_str());
263        let order_specifier_encoded = crate::client::segment(order_specifier.as_str());
264        let path = format!("/v3/accounts/{account_id_encoded}/orders/{order_specifier_encoded}");
265        self.execute(Method::GET, &path, None::<&()>, None::<&()>, None, None)
266            .await
267    }
268}
269
270/// Request body for `replace_order`.
271#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
272#[serde(rename_all = "camelCase")]
273pub struct ReplaceOrderBody {
274    /// Specification of the replacing Order
275    #[serde(rename = "order", default, skip_serializing_if = "Option::is_none")]
276    pub order: Option<OrderRequest>,
277}
278
279/// Successful response for `replace_order`.
280#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
281#[serde(rename_all = "camelCase")]
282pub struct ReplaceOrderResponse {
283    /// The Transaction that cancelled the Order to be replaced.
284    #[serde(
285        rename = "orderCancelTransaction",
286        default,
287        skip_serializing_if = "Option::is_none"
288    )]
289    pub order_cancel_transaction: Option<OrderCancelTransaction>,
290    /// The Transaction that created the replacing Order as requested.
291    #[serde(
292        rename = "orderCreateTransaction",
293        default,
294        skip_serializing_if = "Option::is_none"
295    )]
296    pub order_create_transaction: Option<Transaction>,
297    /// The Transaction that filled the replacing Order. This is only provided when the replacing Order was
298    /// immediately filled.
299    #[serde(
300        rename = "orderFillTransaction",
301        default,
302        skip_serializing_if = "Option::is_none"
303    )]
304    pub order_fill_transaction: Option<OrderFillTransaction>,
305    /// The Transaction that reissues the replacing Order. Only provided when the replacing Order was partially
306    /// filled immediately and is configured to be reissued for its remaining units.
307    #[serde(
308        rename = "orderReissueTransaction",
309        default,
310        skip_serializing_if = "Option::is_none"
311    )]
312    pub order_reissue_transaction: Option<Transaction>,
313    /// The Transaction that rejects the reissue of the Order. Only provided when the replacing Order was
314    /// partially filled immediately and was configured to be reissued, however the reissue was rejected.
315    #[serde(
316        rename = "orderReissueRejectTransaction",
317        default,
318        skip_serializing_if = "Option::is_none"
319    )]
320    pub order_reissue_reject_transaction: Option<Transaction>,
321    /// The Transaction that cancelled the replacing Order. Only provided when the replacing Order was
322    /// immediately cancelled.
323    #[serde(
324        rename = "replacingOrderCancelTransaction",
325        default,
326        skip_serializing_if = "Option::is_none"
327    )]
328    pub replacing_order_cancel_transaction: Option<OrderCancelTransaction>,
329    /// The IDs of all Transactions that were created while satisfying the request.
330    #[serde(
331        rename = "relatedTransactionIDs",
332        default,
333        skip_serializing_if = "Option::is_none"
334    )]
335    pub related_transaction_ids: Option<Vec<TransactionID>>,
336    /// The ID of the most recent Transaction created for the Account
337    #[serde(
338        rename = "lastTransactionID",
339        default,
340        skip_serializing_if = "Option::is_none"
341    )]
342    pub last_transaction_id: Option<TransactionID>,
343}
344
345/// Documented rejection fields for `replace_order`.
346#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Default)]
347#[serde(rename_all = "camelCase")]
348pub struct ReplaceOrderRejection {
349    /// The Transaction that rejected the creation of the replacing Order
350    #[serde(
351        rename = "orderRejectTransaction",
352        default,
353        skip_serializing_if = "Option::is_none"
354    )]
355    pub order_reject_transaction: Option<Transaction>,
356    /// The IDs of all Transactions that were created while satisfying the request.
357    #[serde(
358        rename = "relatedTransactionIDs",
359        default,
360        skip_serializing_if = "Option::is_none"
361    )]
362    pub related_transaction_ids: Option<Vec<TransactionID>>,
363    /// The ID of the most recent Transaction created for the Account.
364    #[serde(
365        rename = "lastTransactionID",
366        default,
367        skip_serializing_if = "Option::is_none"
368    )]
369    pub last_transaction_id: Option<TransactionID>,
370    /// The code of the error that has occurred. This field may not be returned for some errors.
371    #[serde(rename = "errorCode", default, skip_serializing_if = "Option::is_none")]
372    pub error_code: Option<String>,
373    /// The human-readable description of the error that has occurred.
374    #[serde(
375        rename = "errorMessage",
376        default,
377        skip_serializing_if = "Option::is_none"
378    )]
379    pub error_message: Option<String>,
380    /// The Transaction that rejected the cancellation of the Order to be replaced. Only present if the Account
381    /// exists.
382    #[serde(
383        rename = "orderCancelRejectTransaction",
384        default,
385        skip_serializing_if = "Option::is_none"
386    )]
387    pub order_cancel_reject_transaction: Option<Transaction>,
388}
389
390impl Client {
391    /// Replace order.
392    pub async fn replace_order(
393        &self,
394        account_id: &AccountID,
395        order_specifier: &OrderSpecifier,
396        body: &ReplaceOrderBody,
397        client_request_id: Option<&ClientRequestID>,
398    ) -> std::result::Result<
399        crate::ApiResponse<ReplaceOrderResponse>,
400        crate::OperationError<ReplaceOrderRejection>,
401    > {
402        let account_id_encoded = crate::client::segment(account_id.as_str());
403        let order_specifier_encoded = crate::client::segment(order_specifier.as_str());
404        let path = format!("/v3/accounts/{account_id_encoded}/orders/{order_specifier_encoded}");
405        self.execute(
406            Method::PUT,
407            &path,
408            None::<&()>,
409            Some(body),
410            Some(crate::client::MutationAdmission::Ordinary(account_id)),
411            client_request_id,
412        )
413        .await
414    }
415}
416
417/// Successful response for `cancel_order`.
418#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
419#[serde(rename_all = "camelCase")]
420pub struct CancelOrderResponse {
421    /// The Transaction that cancelled the Order
422    #[serde(
423        rename = "orderCancelTransaction",
424        default,
425        skip_serializing_if = "Option::is_none"
426    )]
427    pub order_cancel_transaction: Option<OrderCancelTransaction>,
428    /// The IDs of all Transactions that were created while satisfying the request.
429    #[serde(
430        rename = "relatedTransactionIDs",
431        default,
432        skip_serializing_if = "Option::is_none"
433    )]
434    pub related_transaction_ids: Option<Vec<TransactionID>>,
435    /// The ID of the most recent Transaction created for the Account
436    #[serde(
437        rename = "lastTransactionID",
438        default,
439        skip_serializing_if = "Option::is_none"
440    )]
441    pub last_transaction_id: Option<TransactionID>,
442}
443
444/// Documented rejection fields for `cancel_order`.
445#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Default)]
446#[serde(rename_all = "camelCase")]
447pub struct CancelOrderRejection {
448    /// The Transaction that rejected the cancellation of the Order. Only present if the Account exists.
449    #[serde(
450        rename = "orderCancelRejectTransaction",
451        default,
452        skip_serializing_if = "Option::is_none"
453    )]
454    pub order_cancel_reject_transaction: Option<OrderCancelRejectTransaction>,
455    /// The IDs of all Transactions that were created while satisfying the request. Only present if the Account
456    /// exists.
457    #[serde(
458        rename = "relatedTransactionIDs",
459        default,
460        skip_serializing_if = "Option::is_none"
461    )]
462    pub related_transaction_ids: Option<Vec<TransactionID>>,
463    /// The ID of the most recent Transaction created for the Account. Only present if the Account exists.
464    #[serde(
465        rename = "lastTransactionID",
466        default,
467        skip_serializing_if = "Option::is_none"
468    )]
469    pub last_transaction_id: Option<TransactionID>,
470    /// The code of the error that has occurred. This field may not be returned for some errors.
471    #[serde(rename = "errorCode", default, skip_serializing_if = "Option::is_none")]
472    pub error_code: Option<String>,
473    /// The human-readable description of the error that has occurred.
474    #[serde(
475        rename = "errorMessage",
476        default,
477        skip_serializing_if = "Option::is_none"
478    )]
479    pub error_message: Option<String>,
480}
481
482impl Client {
483    /// Cancel order.
484    pub async fn cancel_order(
485        &self,
486        account_id: &AccountID,
487        order_specifier: &OrderSpecifier,
488        client_request_id: Option<&ClientRequestID>,
489    ) -> std::result::Result<
490        crate::ApiResponse<CancelOrderResponse>,
491        crate::OperationError<CancelOrderRejection>,
492    > {
493        let account_id_encoded = crate::client::segment(account_id.as_str());
494        let order_specifier_encoded = crate::client::segment(order_specifier.as_str());
495        let path =
496            format!("/v3/accounts/{account_id_encoded}/orders/{order_specifier_encoded}/cancel");
497        self.execute(
498            Method::PUT,
499            &path,
500            None::<&()>,
501            None::<&()>,
502            Some(crate::client::MutationAdmission::Exit(account_id)),
503            client_request_id,
504        )
505        .await
506    }
507}
508
509/// Request body for `update_order_client_extensions`.
510#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
511#[serde(rename_all = "camelCase")]
512pub struct UpdateOrderClientExtensionsBody {
513    /// The Client Extensions to update for the Order. Do not set, modify, or delete clientExtensions if your
514    /// account is associated with MT4.
515    #[serde(
516        rename = "clientExtensions",
517        default,
518        skip_serializing_if = "Option::is_none"
519    )]
520    pub client_extensions: Option<ClientExtensions>,
521    /// The Client Extensions to update for the Trade created when the Order is filled. Do not set, modify, or
522    /// delete clientExtensions if your account is associated with MT4.
523    #[serde(
524        rename = "tradeClientExtensions",
525        default,
526        skip_serializing_if = "Option::is_none"
527    )]
528    pub trade_client_extensions: Option<ClientExtensions>,
529}
530
531/// Successful response for `update_order_client_extensions`.
532#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
533#[serde(rename_all = "camelCase")]
534pub struct UpdateOrderClientExtensionsResponse {
535    /// The Transaction that modified the Client Extensions for the Order
536    #[serde(
537        rename = "orderClientExtensionsModifyTransaction",
538        default,
539        skip_serializing_if = "Option::is_none"
540    )]
541    pub order_client_extensions_modify_transaction: Option<OrderClientExtensionsModifyTransaction>,
542    /// The ID of the most recent Transaction created for the Account
543    #[serde(
544        rename = "lastTransactionID",
545        default,
546        skip_serializing_if = "Option::is_none"
547    )]
548    pub last_transaction_id: Option<TransactionID>,
549    /// The IDs of all Transactions that were created while satisfying the request.
550    #[serde(
551        rename = "relatedTransactionIDs",
552        default,
553        skip_serializing_if = "Option::is_none"
554    )]
555    pub related_transaction_ids: Option<Vec<TransactionID>>,
556}
557
558/// Documented rejection fields for `update_order_client_extensions`.
559#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Default)]
560#[serde(rename_all = "camelCase")]
561pub struct UpdateOrderClientExtensionsRejection {
562    /// The Transaction that rejected the modification of the Client Extensions for the Order
563    #[serde(
564        rename = "orderClientExtensionsModifyRejectTransaction",
565        default,
566        skip_serializing_if = "Option::is_none"
567    )]
568    pub order_client_extensions_modify_reject_transaction:
569        Option<OrderClientExtensionsModifyRejectTransaction>,
570    /// The ID of the most recent Transaction created for the Account
571    #[serde(
572        rename = "lastTransactionID",
573        default,
574        skip_serializing_if = "Option::is_none"
575    )]
576    pub last_transaction_id: Option<TransactionID>,
577    /// The IDs of all Transactions that were created while satisfying the request.
578    #[serde(
579        rename = "relatedTransactionIDs",
580        default,
581        skip_serializing_if = "Option::is_none"
582    )]
583    pub related_transaction_ids: Option<Vec<TransactionID>>,
584    /// The code of the error that has occurred. This field may not be returned for some errors.
585    #[serde(rename = "errorCode", default, skip_serializing_if = "Option::is_none")]
586    pub error_code: Option<String>,
587    /// The human-readable description of the error that has occurred.
588    #[serde(
589        rename = "errorMessage",
590        default,
591        skip_serializing_if = "Option::is_none"
592    )]
593    pub error_message: Option<String>,
594}
595
596impl Client {
597    /// Update order client extensions.
598    pub async fn update_order_client_extensions(
599        &self,
600        account_id: &AccountID,
601        order_specifier: &OrderSpecifier,
602        body: &UpdateOrderClientExtensionsBody,
603    ) -> std::result::Result<
604        crate::ApiResponse<UpdateOrderClientExtensionsResponse>,
605        crate::OperationError<UpdateOrderClientExtensionsRejection>,
606    > {
607        let account_id_encoded = crate::client::segment(account_id.as_str());
608        let order_specifier_encoded = crate::client::segment(order_specifier.as_str());
609        let path = format!(
610            "/v3/accounts/{account_id_encoded}/orders/{order_specifier_encoded}/clientExtensions"
611        );
612        self.execute(
613            Method::PUT,
614            &path,
615            None::<&()>,
616            Some(body),
617            Some(crate::client::MutationAdmission::Ordinary(account_id)),
618            None,
619        )
620        .await
621    }
622}