tradestation_rs/
execution.rs

1use crate::{
2    account::{AssetType, MarketActivationRule, OrderType, TimeActivationRule, TrailingStop},
3    responses::execution::{
4        ConfirmOrderResp, ConfirmOrderRespRaw, GetActivationTriggersResp,
5        GetActivationTriggersRespRaw, GetExecutionRoutesResp, GetExecutionRoutesRespRaw, OrderResp,
6        OrderRespRaw,
7    },
8    Client, Error,
9};
10use serde::{Deserialize, Serialize};
11
12#[derive(Clone, Debug, Deserialize, Serialize)]
13#[serde(rename_all = "PascalCase")]
14/// An Active Order
15pub struct Order {
16    /// Short text summary / description of the order.
17    pub message: String,
18
19    #[serde(rename = "OrderID")]
20    /// The id of the order.
21    pub order_id: String,
22
23    /// The error for the order.
24    pub error: Option<String>,
25}
26impl Order {
27    /// Confirm an order getting back an estimated cost
28    /// and commission information for the order without
29    /// actually placing the order.
30    ///
31    /// NOTE: Only valid for `Market Limit`, `Stop Market`,
32    /// `Options`, and `Order Sends Order (OSO)` order types.
33    ///
34    /// # Example
35    /// ---
36    ///
37    /// Confirm a limit buy order for 3 Month SOFR Futures at the
38    /// March 2025 contract @ 96.0725 with a quantity of 50 contracts
39    /// and a duration of Good Till Close (GTC).
40    ///
41    /// ```ignore
42    /// use tradestation::{
43    ///     ClientBuilder, Error, Token,
44    ///     execution::{Duration, OrderRequestBuilder, Order},
45    /// };
46    ///
47    /// #[tokio::main]
48    /// async fn main() -> Result<(), Error> {
49    ///     // Create client
50    ///     let mut client = ClientBuilder::new()?
51    ///         .credentials("YOUR_CLIENT_ID", "YOUR_CLIENT_SECRET")?
52    ///         .token(Token { /* YOUR BEARER AUTH TOKEN */ })?
53    ///         .build()
54    ///         .await?;
55    ///
56    ///     let order_req = OrderRequestBuilder::new()
57    ///         .account_id("YOUR_FUTURES_ACCOUNT_ID")
58    ///         .symbol("SR3H25")
59    ///         .trade_action(TradeAction::Buy)
60    ///         .quantity("50")
61    ///         .order_type(OrderType::Limit)
62    ///         .limit_price("96.0725")
63    ///         .time_in_force(OrderTimeInForce {
64    ///             duration: Duration::GTC,
65    ///             expiration: None,
66    ///         })
67    ///         .build()?;
68    ///
69    ///     match Order::confirm(&mut client, &order_req).await {
70    ///         Ok(confirmation) => println!("Confirmed Order: {confirmation:?}"),
71    ///         Err(e) => println!("Issue Confirming Order: {e:?}"),
72    ///     };
73    ///     Ok(())
74    /// }
75    ///```
76    pub async fn confirm(
77        client: &mut Client,
78        order_request: &OrderRequest,
79    ) -> Result<Vec<OrderConfirmation>, Error> {
80        let endpoint = String::from("orderexecution/orderconfirm");
81        let resp: ConfirmOrderResp = client
82            .post(&endpoint, order_request)
83            .await?
84            .json::<ConfirmOrderRespRaw>()
85            .await?
86            .into();
87
88        if let Some(confirmations) = resp.confirmations {
89            Ok(confirmations)
90        } else {
91            Err(resp.error.unwrap_or(Error::UnknownTradeStationAPIError))
92        }
93    }
94
95    /// Place the `OrderRequest` getting back the result of the Order Request.
96    ///
97    /// # Example
98    /// ---
99    /// Place an order to buy 100 shares of JP Morgan (`"JPM"`)
100    /// using a limit order with the limit price of $`"220.50"`, with
101    /// a order duration of Good Till Closed.
102    ///
103    ///```ignore
104    /// let order_req = OrderRequestBuilder::new()
105    ///     .account_id("YOUR_EQUITIES_ACCOUNT_ID")
106    ///     .symbol("JPM")
107    ///     .trade_action(TradeAction::Buy)
108    ///     .quantity("100")
109    ///     .order_type(OrderType::Limit)
110    ///     .limit_price("220.50")
111    ///     .time_in_force(OrderTimeInForce {
112    ///         duration: Duration::GTC,
113    ///         expiration: None,
114    ///     })
115    ///     .build()?;
116    ///
117    /// match Order::place(&mut client, order_req).await {
118    ///     Ok(resp) => println!("Order Response: {resp:?}"),
119    ///     Err(e) => println!("Order Response: {e:?}"),
120    /// }
121    /// ```
122    pub async fn place(
123        client: &mut Client,
124        order_request: &OrderRequest,
125    ) -> Result<Vec<Order>, Error> {
126        let endpoint = String::from("orderexecution/orders");
127
128        let resp: OrderResp = client
129            .post(&endpoint, &order_request)
130            .await?
131            .json::<OrderRespRaw>()
132            .await?
133            .into();
134
135        if let Some(orders) = resp.orders {
136            Ok(orders)
137        } else {
138            Err(resp.error.unwrap_or(Error::UnknownTradeStationAPIError))
139        }
140    }
141
142    /// Creates an Order Confirmation for a group order. Request valid for
143    /// Order Cancels Order (OCO) and Bracket (BRK) order types as well as
144    /// grouped orders of other types (NORMAL).
145    ///
146    /// # Order Cancels Order (OCO)
147    ///
148    /// An OCO order is a group of orders whereby if one of the orders is
149    /// filled or partially-filled, then all of the other orders in the
150    /// group are cancelled.
151    ///
152    /// # Bracket OCO Orders
153    ///
154    /// A bracket order is a special instance of an OCO (Order Cancel Order).
155    /// Bracket orders are used to exit an existing position. They are designed
156    /// to limit loss and lock in profit by “bracketing” an order with a simultaneous
157    /// stop and limit order.
158    ///
159    /// Bracket orders are limited so that the orders are all for the same symbol
160    /// and are on the same side of the market (either all to sell or all to cover),
161    /// and they are restricted to closing transactions.
162    ///
163    /// The reason that they follow these rules is because the orders need to be
164    /// able to auto decrement when a partial fill occurs with one of the orders.
165    /// For example, if the customer has a sell limit order for 1000 shares and
166    /// a sell stop order for 1000 shares, and the limit order is partially filled
167    /// for 500 shares, then the customer would want the stop to remain open, but
168    /// it should automatically decrement the order to 500 shares to match the
169    /// remaining open position.
170    ///
171    /// NOTE: When a group order is submitted, the order execution system treats
172    /// each sibling order as an individual order. Thus, the system does not validate
173    /// that each order has the same Quantity, and currently it is not able to update
174    /// a bracket order as one transaction, instead you must update each order within
175    /// a bracket.
176    ///
177    /// # Example
178    /// ---
179    /// Confirm a trade involving a bracket group of orders with one order
180    /// for opening the position, one order for closing the position at a
181    /// take profit price, and one order for closing the position at a stop
182    /// loss price. A total of 3 orders making up this position.
183    /// ```ignore
184    /// use tradestation::{
185    ///     execution::{Duration, Order, OrderRequestBuilder},
186    ///     ClientBuilder, Error, Token,
187    /// };
188    ///
189    /// #[tokio::main]
190    /// async fn main() -> Result<(), Error> {
191    ///     // Create client
192    ///     let mut client = ClientBuilder::new()?
193    ///         .credentials("YOUR_CLIENT_ID", "YOUR_CLIENT_SECRET")?
194    ///         .token(Token { /* YOUR BEARER AUTH TOKEN */ })?
195    ///         .build()
196    ///         .await?;
197    ///
198    ///     let entry_order_req = OrderRequestBuilder::new()
199    ///         .account_id("YOUR_EQUITIES_ACCOUNT_ID")
200    ///         .symbol("XLRE")
201    ///         .trade_action(TradeAction::SellShort)
202    ///         .quantity("1000")
203    ///         .order_type(OrderType::Market)
204    ///         .time_in_force(OrderTimeInForce {
205    ///             duration: Duration::GTC,
206    ///             expiration: None,
207    ///         })
208    ///         .build()?;
209    ///
210    ///     let take_profit_order_req = OrderRequestBuilder::new()
211    ///         .account_id("YOUR_EQUITIES_ACCOUNT_ID")
212    ///         .symbol("XLRE")
213    ///         .trade_action(TradeAction::BuyToCover)
214    ///         .quantity("1000")
215    ///         .order_type(OrderType::Limit)
216    ///         .limit_price("35.75")
217    ///         .time_in_force(OrderTimeInForce {
218    ///             duration: Duration::GTC,
219    ///             expiration: None,
220    ///         })
221    ///         .build()?;
222    ///
223    ///     let stop_loss_order_req = OrderRequestBuilder::new()
224    ///         .account_id("YOUR_EQUITIES_ACCOUNT_ID")
225    ///         .symbol("XLRE")
226    ///         .trade_action(TradeAction::BuyToCover)
227    ///         .quantity("1000")
228    ///         .order_type(OrderType::StopMarket)
229    ///         .stop_price("46.50")
230    ///         .time_in_force(OrderTimeInForce {
231    ///             duration: Duration::GTC,
232    ///             expiration: None,
233    ///         })
234    ///         .build()?;
235    ///
236    ///     let order_group = OrderRequestGroupBuilder::new()
237    ///         .order_requests(Vec::from([
238    ///             entry_order_req,
239    ///             take_profit_order_req,
240    ///             stop_loss_order_req,
241    ///         ]))
242    ///         .group_type(OrderGroupType::BRK)
243    ///         .build()?;
244    ///
245    ///     let order_confirmations = Order::confirm(&mut client, &order_group).await?;
246    ///     println!("Confirm Orders Result: {order_confirmations:?}");
247    /// }
248    /// ```
249    pub async fn confirm_group(
250        client: &mut Client,
251        order_req_group: &OrderRequestGroup,
252    ) -> Result<Vec<OrderConfirmation>, Error> {
253        let endpoint = String::from("orderexecution/ordergroupconfirm");
254
255        let resp: ConfirmOrderResp = client
256            .post(&endpoint, order_req_group)
257            .await?
258            .json::<ConfirmOrderRespRaw>()
259            .await?
260            .into();
261
262        if let Some(confirmations) = resp.confirmations {
263            Ok(confirmations)
264        } else {
265            Err(resp.error.unwrap_or(Error::UnknownTradeStationAPIError))
266        }
267    }
268
269    /// Submits a group order. Request valid for Order Cancels Order (OCO)
270    /// and Bracket (BRK) order types as well as grouped orders of other
271    /// types (NORMAL).
272    ///
273    /// # Order Cancels Order (OCO)
274    ///
275    /// An OCO order is a group of orders whereby if one of the orders is
276    /// filled or partially-filled, then all of the other orders in the
277    /// group are cancellCreates an Order Confirmation for a group order. Request valid for all account types. Request valid for Order Cancels Order (OCO) and Bracket (BRK) order types as well as grouped orders of other types (NORMAL).ed.
278    ///
279    /// # Bracket OCO Orders
280    ///
281    /// A bracket order is a special instance of an OCO (Order Cancel Order).
282    /// Bracket orders are used to exit an existing position. They are designed
283    /// to limit loss and lock in profit by “bracketing” an order with a simultaneous
284    /// stop and limit order.
285    ///
286    /// Bracket orders are limited so that the orders are all for the same symbol
287    /// and are on the same side of the market (either all to sell or all to cover),
288    /// and they are restricted to closing transactions.
289    ///
290    /// The reason that they follow these rules is because the orders need to be
291    /// able to auto decrement when a partial fill occurs with one of the orders.
292    /// For example, if the customer has a sell limit order for 1000 shares and
293    /// a sell stop order for 1000 shares, and the limit order is partially filled
294    /// for 500 shares, then the customer would want the stop to remain open, but
295    /// it should automatically decrement the order to 500 shares to match the
296    /// remaining open position.
297    ///
298    /// NOTE: When a group order is submitted, the order execution system treats
299    /// each sibling order as an individual order. Thus, the system does not validate
300    /// that each order has the same Quantity, and currently it is not able to update
301    /// a bracket order as one transaction, instead you must update each order within
302    /// a bracket.
303    ///
304    /// # Example
305    /// ---
306    /// Place a trade involving a bracket group of orders with one order
307    /// for opening the position, one order for closing the position at a
308    /// take profit price, and one order for closing the position at a stop
309    /// loss price. A total of 3 orders making up this position.
310    /// ```ignore
311    /// use tradestation::{
312    ///     execution::{Duration, Order, OrderRequestBuilder},
313    ///     ClientBuilder, Error, Token,
314    /// };
315    ///
316    /// #[tokio::main]
317    /// async fn main() -> Result<(), Error> {
318    ///     // Create client
319    ///     let mut client = ClientBuilder::new()?
320    ///         .credentials("YOUR_CLIENT_ID", "YOUR_CLIENT_SECRET")?
321    ///         .token(Token { /* YOUR BEARER AUTH TOKEN */ })?
322    ///         .build()
323    ///         .await?;
324    ///
325    ///     let entry_order_req = OrderRequestBuilder::new()
326    ///         .account_id("YOUR_EQUITIES_ACCOUNT_ID")
327    ///         .symbol("XLRE")
328    ///         .trade_action(TradeAction::SellShort)
329    ///         .quantity("1000")
330    ///         .order_type(OrderType::Market)
331    ///         .time_in_force(OrderTimeInForce {
332    ///             duration: Duration::GTC,
333    ///             expiration: None,
334    ///         })
335    ///         .build()?;
336    ///
337    ///     let take_profit_order_req = OrderRequestBuilder::new()
338    ///         .account_id("YOUR_EQUITIES_ACCOUNT_ID")
339    ///         .symbol("XLRE")
340    ///         .trade_action(TradeAction::BuyToCover)
341    ///         .quantity("1000")
342    ///         .order_type(OrderType::Limit)
343    ///         .limit_price("35.75")
344    ///         .time_in_force(OrderTimeInForce {
345    ///             duration: Duration::GTC,
346    ///             expiration: None,
347    ///         })
348    ///         .build()?;
349    ///
350    ///     let stop_loss_order_req = OrderRequestBuilder::new()
351    ///         .account_id("YOUR_EQUITIES_ACCOUNT_ID")
352    ///         .symbol("XLRE")
353    ///         .trade_action(TradeAction::BuyToCover)
354    ///         .quantity("1000")
355    ///         .order_type(OrderType::StopMarket)
356    ///         .stop_price("46.50")
357    ///         .time_in_force(OrderTimeInForce {
358    ///             duration: Duration::GTC,
359    ///             expiration: None,
360    ///         })
361    ///         .build()?;
362    ///
363    ///     let order_group = OrderRequestGroupBuilder::new()
364    ///         .order_requests(Vec::from([
365    ///             entry_order_req,
366    ///             take_profit_order_req,
367    ///             stop_loss_order_req,
368    ///         ]))
369    ///         .group_type(OrderGroupType::BRK)
370    ///         .build()?;
371    ///
372    ///     let orders = Order::place_group(&mut client, &order_group).await?;
373    ///     println!("Place Orders Result: {orders:?}");
374    /// }
375    /// ```
376    pub async fn place_group(
377        client: &mut Client,
378        order_req_group: &OrderRequestGroup,
379    ) -> Result<Vec<Order>, Error> {
380        let endpoint = String::from("orderexecution/ordergroups");
381
382        let resp: OrderResp = client
383            .post(&endpoint, order_req_group)
384            .await?
385            .json::<OrderRespRaw>()
386            .await?
387            .into();
388
389        if let Some(orders) = resp.orders {
390            Ok(orders)
391        } else {
392            Err(resp.error.unwrap_or(Error::UnknownTradeStationAPIError))
393        }
394    }
395
396    /// Replace an `Order` with an Order Update.
397    ///
398    /// # Example
399    /// ---
400    /// Replace an order to buy 100 shares of Palantir `"PLTR"`
401    /// at the limit price of $`"40.00"` to instead be 25 shares
402    /// at the limit price of $`"42.50"`.
403    ///
404    /// ```ignore
405    /// let order_req = OrderRequestBuilder::new()
406    ///     .account_id("YOUR_EQUITIES_ACCOUNT_ID")
407    ///     .symbol("PLTR")
408    ///     .trade_action(TradeAction::Buy)
409    ///     .quantity("100")
410    ///     .order_type(OrderType::Limit)
411    ///     .limit_price("40.00")
412    ///     .time_in_force(OrderTimeInForce {
413    ///         duration: Duration::GTC,
414    ///         expiration: None,
415    ///     })
416    ///     .build()?;
417    ///
418    /// let order = Order::place(&mut client, &order_req)
419    ///     .await?
420    ///     .into_iter()
421    ///     .next();
422    ///
423    /// if let Some(order) = order {
424    ///     order
425    ///         .clone()
426    ///         .replace(
427    ///             &mut client,
428    ///             OrderUpdate::new().limit_price("42.50").quantity("25"),
429    ///         )
430    ///         .await?;
431    /// }
432    /// ```
433    pub async fn replace(
434        self,
435        client: &mut Client,
436        order_update: OrderUpdate,
437    ) -> Result<Vec<Order>, Error> {
438        let endpoint = format!("orderexecution/orders/{}", self.order_id);
439
440        let resp: OrderResp = client
441            .put(&endpoint, &order_update)
442            .await?
443            .json::<OrderRespRaw>()
444            .await?
445            .into();
446
447        if let Some(orders) = resp.orders {
448            Ok(orders)
449        } else {
450            Err(resp.error.unwrap_or(Error::UnknownTradeStationAPIError))
451        }
452    }
453
454    /// Cancel an active `Order`.
455    ///
456    /// # Example
457    /// ---
458    ///
459    /// ```ignore
460    /// let order_req = OrderRequestBuilder::new()
461    ///     .account_id("YOUR_EQUITIES_ACCOUNT_ID")
462    ///     .symbol("JPM")
463    ///     .trade_action(TradeAction::Buy)
464    ///     .quantity("100")
465    ///     .order_type(OrderType::Limit)
466    ///     .limit_price("220.50")
467    ///     .time_in_force(OrderTimeInForce {
468    ///         duration: Duration::GTC,
469    ///         expiration: None,
470    ///     })
471    ///     .build()?;
472    ///
473    /// let order = Order::place(&mut client, &order_req)
474    ///     .await?
475    ///     .into_iter()
476    ///     .next();
477    ///
478    /// if let Some(order) = order {
479    ///     order.cancel(&mut client).await?;
480    /// }
481    /// ```
482    pub async fn cancel(self, client: &mut Client) -> Result<Vec<Order>, Error> {
483        let endpoint = format!("orderexecution/orders/{}", self.order_id);
484
485        let resp: OrderResp = client
486            .delete(&endpoint)
487            .await?
488            .json::<OrderRespRaw>()
489            .await?
490            .into();
491
492        if let Some(orders) = resp.orders {
493            Ok(orders)
494        } else {
495            Err(resp.error.unwrap_or(Error::UnknownTradeStationAPIError))
496        }
497    }
498}
499
500#[derive(Clone, Debug, Deserialize, Serialize)]
501pub struct OrderRequestGroup {
502    pub order_requests: Vec<OrderRequest>,
503    pub group_type: OrderGroupType,
504}
505impl OrderRequestGroup {
506    /// Submits a group order. Request valid for Order Cancels Order (OCO)
507    /// and Bracket (BRK) order types as well as grouped orders of other
508    /// types (NORMAL).
509    ///
510    /// # Order Cancels Order (OCO)
511    ///
512    /// An OCO order is a group of orders whereby if one of the orders is
513    /// filled or partially-filled, then all of the other orders in the
514    /// group are cancellCreates an Order Confirmation for a group order. Request valid for all account types. Request valid for Order Cancels Order (OCO) and Bracket (BRK) order types as well as grouped orders of other types (NORMAL).ed.
515    ///
516    /// # Bracket OCO Orders
517    ///
518    /// A bracket order is a special instance of an OCO (Order Cancel Order).
519    /// Bracket orders are used to exit an existing position. They are designed
520    /// to limit loss and lock in profit by “bracketing” an order with a simultaneous
521    /// stop and limit order.
522    ///
523    /// Bracket orders are limited so that the orders are all for the same symbol
524    /// and are on the same side of the market (either all to sell or all to cover),
525    /// and they are restricted to closing transactions.
526    ///
527    /// The reason that they follow these rules is because the orders need to be
528    /// able to auto decrement when a partial fill occurs with one of the orders.
529    /// For example, if the customer has a sell limit order for 1000 shares and
530    /// a sell stop order for 1000 shares, and the limit order is partially filled
531    /// for 500 shares, then the customer would want the stop to remain open, but
532    /// it should automatically decrement the order to 500 shares to match the
533    /// remaining open position.
534    ///
535    /// NOTE: When a group order is submitted, the order execution system treats
536    /// each sibling order as an individual order. Thus, the system does not validate
537    /// that each order has the same Quantity, and currently it is not able to update
538    /// a bracket order as one transaction, instead you must update each order within
539    /// a bracket.
540    ///
541    /// # Example
542    /// ---
543    /// Place a trade involving a bracket group of orders with one order
544    /// for opening the position, one order for closing the position at a
545    /// take profit price, and one order for closing the position at a stop
546    /// loss price. A total of 3 orders making up this position.
547    /// ```ignore
548    /// use tradestation::{
549    ///     execution::{Duration, Order, OrderRequestBuilder},
550    ///     ClientBuilder, Error, Token,
551    /// };
552    ///
553    /// #[tokio::main]
554    /// async fn main() -> Result<(), Error> {
555    ///     // Create client
556    ///     let mut client = ClientBuilder::new()?
557    ///         .credentials("YOUR_CLIENT_ID", "YOUR_CLIENT_SECRET")?
558    ///         .token(Token { /* YOUR BEARER AUTH TOKEN */ })?
559    ///         .build()
560    ///         .await?;
561    ///
562    ///     let entry_order_req = OrderRequestBuilder::new()
563    ///         .account_id("YOUR_EQUITIES_ACCOUNT_ID")
564    ///         .symbol("XLRE")
565    ///         .trade_action(TradeAction::SellShort)
566    ///         .quantity("1000")
567    ///         .order_type(OrderType::Market)
568    ///         .time_in_force(OrderTimeInForce {
569    ///             duration: Duration::GTC,
570    ///             expiration: None,
571    ///         })
572    ///         .build()?;
573    ///
574    ///     let take_profit_order_req = OrderRequestBuilder::new()
575    ///         .account_id("YOUR_EQUITIES_ACCOUNT_ID")
576    ///         .symbol("XLRE")
577    ///         .trade_action(TradeAction::BuyToCover)
578    ///         .quantity("1000")
579    ///         .order_type(OrderType::Limit)
580    ///         .limit_price("35.75")
581    ///         .time_in_force(OrderTimeInForce {
582    ///             duration: Duration::GTC,
583    ///             expiration: None,
584    ///         })
585    ///         .build()?;
586    ///
587    ///     let stop_loss_order_req = OrderRequestBuilder::new()
588    ///         .account_id("YOUR_EQUITIES_ACCOUNT_ID")
589    ///         .symbol("XLRE")
590    ///         .trade_action(TradeAction::BuyToCover)
591    ///         .quantity("1000")
592    ///         .order_type(OrderType::StopMarket)
593    ///         .stop_price("46.50")
594    ///         .time_in_force(OrderTimeInForce {
595    ///             duration: Duration::GTC,
596    ///             expiration: None,
597    ///         })
598    ///         .build()?;
599    ///
600    ///     let order_group = OrderRequestGroupBuilder::new()
601    ///         .order_requests(Vec::from([
602    ///             entry_order_req,
603    ///             take_profit_order_req,
604    ///             stop_loss_order_req,
605    ///         ]))
606    ///         .group_type(OrderGroupType::BRK)
607    ///         .build()?;
608    ///
609    ///     let orders = order_group.place(&mut client).await?;
610    ///     println!("Place Orders Result: {orders:?}");
611    /// }
612    /// ```
613    pub async fn place(&self, client: &mut Client) -> Result<Vec<Order>, Error> {
614        Order::place_group(client, self).await
615    }
616
617    /// Creates an Order Confirmation for a group order. Request valid for
618    /// Order Cancels Order (OCO) and Bracket (BRK) order types as well as
619    /// grouped orders of other types (NORMAL).
620    ///
621    /// # Order Cancels Order (OCO)
622    ///
623    /// An OCO order is a group of orders whereby if one of the orders is
624    /// filled or partially-filled, then all of the other orders in the
625    /// group are cancelled.
626    ///
627    /// # Bracket OCO Orders
628    ///
629    /// A bracket order is a special instance of an OCO (Order Cancel Order).
630    /// Bracket orders are used to exit an existing position. They are designed
631    /// to limit loss and lock in profit by “bracketing” an order with a simultaneous
632    /// stop and limit order.
633    ///
634    /// Bracket orders are limited so that the orders are all for the same symbol
635    /// and are on the same side of the market (either all to sell or all to cover),
636    /// and they are restricted to closing transactions.
637    ///
638    /// The reason that they follow these rules is because the orders need to be
639    /// able to auto decrement when a partial fill occurs with one of the orders.
640    /// For example, if the customer has a sell limit order for 1000 shares and
641    /// a sell stop order for 1000 shares, and the limit order is partially filled
642    /// for 500 shares, then the customer would want the stop to remain open, but
643    /// it should automatically decrement the order to 500 shares to match the
644    /// remaining open position.
645    ///
646    /// NOTE: When a group order is submitted, the order execution system treats
647    /// each sibling order as an individual order. Thus, the system does not validate
648    /// that each order has the same Quantity, and currently it is not able to update
649    /// a bracket order as one transaction, instead you must update each order within
650    /// a bracket.
651    ///
652    /// # Example
653    /// ---
654    /// Confirm a trade involving a bracket group of orders with one order
655    /// for opening the position, one order for closing the position at a
656    /// take profit price, and one order for closing the position at a stop
657    /// loss price. A total of 3 orders making up this position.
658    /// ```ignore
659    /// use tradestation::{
660    ///     execution::{Duration, Order, OrderRequestBuilder},
661    ///     ClientBuilder, Error, Token,
662    /// };
663    ///
664    /// #[tokio::main]
665    /// async fn main() -> Result<(), Error> {
666    ///     // Create client
667    ///     let mut client = ClientBuilder::new()?
668    ///         .credentials("YOUR_CLIENT_ID", "YOUR_CLIENT_SECRET")?
669    ///         .token(Token { /* YOUR BEARER AUTH TOKEN */ })?
670    ///         .build()
671    ///         .await?;
672    ///
673    ///     let entry_order_req = OrderRequestBuilder::new()
674    ///         .account_id("YOUR_EQUITIES_ACCOUNT_ID")
675    ///         .symbol("XLRE")
676    ///         .trade_action(TradeAction::SellShort)
677    ///         .quantity("1000")
678    ///         .order_type(OrderType::Market)
679    ///         .time_in_force(OrderTimeInForce {
680    ///             duration: Duration::GTC,
681    ///             expiration: None,
682    ///         })
683    ///         .build()?;
684    ///
685    ///     let take_profit_order_req = OrderRequestBuilder::new()
686    ///         .account_id("YOUR_EQUITIES_ACCOUNT_ID")
687    ///         .symbol("XLRE")
688    ///         .trade_action(TradeAction::BuyToCover)
689    ///         .quantity("1000")
690    ///         .order_type(OrderType::Limit)
691    ///         .limit_price("35.75")
692    ///         .time_in_force(OrderTimeInForce {
693    ///             duration: Duration::GTC,
694    ///             expiration: None,
695    ///         })
696    ///         .build()?;
697    ///
698    ///     let stop_loss_order_req = OrderRequestBuilder::new()
699    ///         .account_id("YOUR_EQUITIES_ACCOUNT_ID")
700    ///         .symbol("XLRE")
701    ///         .trade_action(TradeAction::BuyToCover)
702    ///         .quantity("1000")
703    ///         .order_type(OrderType::StopMarket)
704    ///         .stop_price("46.50")
705    ///         .time_in_force(OrderTimeInForce {
706    ///             duration: Duration::GTC,
707    ///             expiration: None,
708    ///         })
709    ///         .build()?;
710    ///
711    ///     let order_group = OrderRequestGroupBuilder::new()
712    ///         .order_requests(Vec::from([
713    ///             entry_order_req,
714    ///             take_profit_order_req,
715    ///             stop_loss_order_req,
716    ///         ]))
717    ///         .group_type(OrderGroupType::BRK)
718    ///         .build()?;
719    ///
720    ///     let order_confirmations = order_group.confirm(&mut client).await?;
721    ///     println!("Confirm Orders Result: {order_confirmations:?}");
722    /// }
723    /// ```
724    pub async fn confirm(self, client: &mut Client) -> Result<Vec<OrderConfirmation>, Error> {
725        Order::confirm_group(client, &self).await
726    }
727}
728
729#[derive(Clone, Debug, Deserialize, Serialize, Default)]
730/// `OrderRequestGroup` builder
731pub struct OrderRequestGroupBuilder {
732    order_requests: Option<Vec<OrderRequest>>,
733    group_type: Option<OrderGroupType>,
734}
735impl OrderRequestGroupBuilder {
736    /// Initialize a default builder struct for an `OrderRequestGroup`.
737    pub fn new() -> Self {
738        Self::default()
739    }
740
741    /// Set the Order Requests (`Vec<execution::OrderRequest>`) for the group.
742    pub fn order_requests(mut self, order_reqs: Vec<OrderRequest>) -> Self {
743        self.order_requests = Some(order_reqs);
744        self
745    }
746
747    /// Set the Order Group Type (`execution::OrderGroupType`).
748    pub fn group_type(mut self, group_type: OrderGroupType) -> Self {
749        self.group_type = Some(group_type);
750        self
751    }
752
753    /// Finish building the `OrderRequestGroup`.
754    ///
755    /// NOTE: Setting `order_requests` is required before building.
756    ///
757    /// NOTE: Setting `group_type` is required before building.
758    pub fn build(self) -> Result<OrderRequestGroup, Error> {
759        Ok(OrderRequestGroup {
760            order_requests: self.order_requests.ok_or(Error::OrderRequestsNotSet)?,
761            group_type: self.group_type.ok_or(Error::OrderGroupTypeNotSet)?,
762        })
763    }
764}
765
766#[derive(Clone, Debug, Deserialize, Serialize)]
767/// The different types of order groups
768pub enum OrderGroupType {
769    /// Bracket Order
770    BRK,
771    /// Order Cancels Order
772    OCO,
773    /// Normal Group of Orders
774    NORMAL,
775}
776
777#[derive(Clone, Debug, Deserialize, Serialize, Default)]
778#[serde(rename_all = "PascalCase")]
779pub struct OrderUpdate {
780    /// The limit price for this updated `Order`.
781    pub limit_price: Option<String>,
782    /// The stop price for this updated `Order`.
783    pub stop_price: Option<String>,
784    /// The order type for this updated `Order`.
785    pub order_type: Option<OrderType>,
786    /// The quantity for this updated `Order`.
787    pub quantity: Option<String>,
788    /// The advanced options of this updated `Order`.
789    pub advanced_options: Option<AdvancedOrderOptions>,
790}
791impl OrderUpdate {
792    /// Create a new default `OrderUpdate`.
793    pub fn new() -> Self {
794        Self::default()
795    }
796
797    /// Set the limit price of the updated `Order`.
798    pub fn limit_price(mut self, price: impl Into<String>) -> Self {
799        self.limit_price = Some(price.into());
800
801        self
802    }
803
804    /// Set the stop price of the updated `Order`.
805    pub fn stop_price(mut self, price: impl Into<String>) -> Self {
806        self.stop_price = Some(price.into());
807
808        self
809    }
810
811    /// Set the order type of the updated `Order`.
812    pub fn order_type(mut self, order_type: OrderType) -> Self {
813        self.order_type = Some(order_type);
814
815        self
816    }
817
818    /// Set the quantity for the updated `Order`.
819    pub fn quantity(mut self, qty: impl Into<String>) -> Self {
820        self.quantity = Some(qty.into());
821
822        self
823    }
824
825    /// Set the advanced options of the updated `Order`.
826    pub fn advanced_options(mut self, opts: AdvancedOrderOptions) -> Self {
827        self.advanced_options = Some(opts);
828
829        self
830    }
831}
832
833// TODO: Support builder pattern's for `OrderRequest`
834#[derive(Clone, Debug, Deserialize, Serialize)]
835#[serde(rename_all = "PascalCase")]
836/// The initial stage of an `Order`, this is what
837/// is sent to the route for creating a `Order`.
838pub struct OrderRequest {
839    /// The TradeStation Account ID the order is for.
840    pub account_id: String,
841
842    /// Advanced Options for configuring an order.
843    pub advanced_options: Option<AdvancedOrderOptions>,
844
845    /// The different statuses for buing power warnings.
846    pub buying_power_warning: Option<BPWarningStatus>,
847
848    /// The additional legs to this order.
849    pub legs: Option<Vec<OrderRequestLeg>>,
850
851    /// The limit price for this order.
852    pub limit_price: Option<String>,
853
854    /// Order Sends Orders
855    pub osos: Option<Vec<Oso>>,
856
857    /// A unique identifier regarding an order used
858    /// to prevent duplicates. Must be unique per API
859    /// key, per order, per user.
860    pub order_confirm_id: Option<String>,
861
862    /// The order type of the order.
863    pub order_type: OrderType,
864
865    /// The quantity of shares, or contracts for the order.
866    pub quantity: String,
867
868    /// The route of the order.
869    ///
870    /// NOTE: For Stocks and Options, Route value will
871    /// default to Intelligent if no value is set.
872    ///
873    /// NOTE: Routes can be obtained from `Order::get_routes()`.
874    pub route: Option<String>,
875
876    /// The stop price for this order.
877    ///
878    /// NOTE: If a TrailingStop amount or percent is passed
879    /// in with the request (in the `AdvancedOrderOptions`),
880    /// and a Stop Price value is also passed in, the Stop
881    /// Price value is ignored.
882    pub stop_price: Option<String>,
883
884    /// The symbol used for this order.
885    pub symbol: String,
886
887    /// Defines the duration and expiration timestamp of an Order.
888    pub time_in_force: OrderTimeInForce,
889
890    /// The different trade actions that can be sent or
891    /// received, and conveys the intent of the order.
892    pub trade_action: TradeAction,
893}
894impl OrderRequest {
895    /// Confirm an order getting back an estimated cost
896    /// and commission information for the order without
897    /// actually placing the order.
898    ///
899    /// NOTE: Only valid for `Market Limit`, `Stop Market`,
900    /// `Options`, and `Order Sends Order (OSO)` order types.
901    ///
902    /// # Example
903    /// ---
904    ///
905    /// Confirm a limit buy order for 3 Month SOFR Futures at the
906    /// March 2025 contract @ 96.0725 with a quantity of 50 contracts
907    /// and a duration of Good Till Close (GTC).
908    ///
909    /// ```ignore
910    /// use tradestation::{ClientBuilder, Error, Token, execution::Duration};
911    ///
912    /// #[tokio::main]
913    /// async fn main() -> Result<(), Error> {
914    ///     // Create client
915    ///     let mut client = ClientBuilder::new()?
916    ///         .credentials("YOUR_CLIENT_ID", "YOUR_CLIENT_SECRET")?
917    ///         .token(Token { /* YOUR BEARER AUTH TOKEN */ })?
918    ///         .build()
919    ///         .await?;
920    ///
921    ///     let order_req = OrderRequestBuilder::new()
922    ///         .account_id("YOUR_FUTURES_ACCOUNT_ID")
923    ///         .symbol("SR3H25")
924    ///         .trade_action(TradeAction::Buy)
925    ///         .quantity("50")
926    ///         .order_type(OrderType::Limit)
927    ///         .limit_price("96.0725")
928    ///         .time_in_force(OrderTimeInForce {
929    ///             duration: Duration::GTC,
930    ///             expiration: None,
931    ///         })
932    ///         .build()?;
933    ///
934    ///     match order_req.confirm(&mut client).await {
935    ///         Ok(confirmation) => println!("Confirmed Order: {confirmation:?}"),
936    ///         Err(e) => println!("Issue Confirming Order: {e:?}"),
937    ///     };
938    ///     Ok(())
939    /// }
940    ///```
941    pub async fn confirm(self, client: &mut Client) -> Result<Vec<OrderConfirmation>, Error> {
942        Order::confirm(client, &self).await
943    }
944}
945
946#[derive(Debug, Default)]
947/// The initial stage of an `Order`, this is what
948/// is sent to the route for creating a `Order`.
949pub struct OrderRequestBuilder {
950    account_id: Option<String>,
951    advanced_options: Option<AdvancedOrderOptions>,
952    buying_power_warning: Option<BPWarningStatus>,
953    legs: Option<Vec<OrderRequestLeg>>,
954    limit_price: Option<String>,
955    osos: Option<Vec<Oso>>,
956    order_confirm_id: Option<String>,
957    order_type: Option<OrderType>,
958    quantity: Option<String>,
959    route: Option<String>,
960    stop_price: Option<String>,
961    symbol: Option<String>,
962    time_in_force: Option<OrderTimeInForce>,
963    trade_action: Option<TradeAction>,
964}
965impl OrderRequestBuilder {
966    /// Initialize a new builder for `OrderRequest`.
967    pub fn new() -> Self {
968        OrderRequestBuilder::default()
969    }
970
971    /// Set the Account ID the `OrderRequest` belongs to.
972    ///
973    /// NOTE: Required to be set to build an `OrderRequest`.
974    pub fn account_id(mut self, id: impl Into<String>) -> Self {
975        self.account_id = Some(id.into());
976        self
977    }
978
979    /// Set the Order Type for the `OrderRequest`.
980    ///
981    /// NOTE: Required to be set to build an `OrderRequest`.
982    pub fn order_type(mut self, order_type: OrderType) -> Self {
983        self.order_type = Some(order_type);
984        self
985    }
986
987    /// Set the Symbol the `OrderRequest` is for.
988    ///
989    /// NOTE: Required to be set to build an `OrderRequest`.
990    pub fn symbol(mut self, symbol: impl Into<String>) -> Self {
991        self.symbol = Some(symbol.into());
992        self
993    }
994
995    /// Set the Time In Force (Duration or expiration timestamp)
996    /// for the `OrderRequest`.
997    ///
998    /// NOTE: Required to be set to build an `OrderRequest`.
999    pub fn time_in_force(mut self, time_in_force: OrderTimeInForce) -> Self {
1000        self.time_in_force = Some(time_in_force);
1001        self
1002    }
1003
1004    /// Set the Quantity of shares or contracts for the `OrderRequest`.
1005    pub fn quantity(mut self, quantity: impl Into<String>) -> Self {
1006        self.quantity = Some(quantity.into());
1007        self
1008    }
1009
1010    /// Set the Trade Action for the `OrderRequest`.
1011    ///
1012    /// NOTE: Required to be set to build an `OrderRequest`.
1013    pub fn trade_action(mut self, action: TradeAction) -> Self {
1014        self.trade_action = Some(action);
1015        self
1016    }
1017
1018    /// Set the Execution Route for the `OrderRequest`.
1019    pub fn route(mut self, route: impl Into<String>) -> Self {
1020        self.route = Some(route.into());
1021        self
1022    }
1023
1024    /// Set a Stop Price for the `OrderRequest`.
1025    pub fn stop_price(mut self, price: impl Into<String>) -> Self {
1026        self.stop_price = Some(price.into());
1027        self
1028    }
1029
1030    /// Set an Order Confirm ID for the `OrderRequest`.
1031    pub fn order_confirm_id(mut self, id: impl Into<String>) -> Self {
1032        self.order_confirm_id = Some(id.into());
1033        self
1034    }
1035
1036    /// Set the Order Sends Order for the `OrderRequest`.
1037    pub fn osos(mut self, osos: Vec<Oso>) -> Self {
1038        self.osos = Some(osos);
1039        self
1040    }
1041
1042    /// Set a Limit Price for the `OrderRequest`.
1043    pub fn limit_price(mut self, price: impl Into<String>) -> Self {
1044        self.limit_price = Some(price.into());
1045        self
1046    }
1047
1048    /// Set the Legs of the `OrderRequest`.
1049    pub fn legs(mut self, legs: Vec<OrderRequestLeg>) -> Self {
1050        self.legs = Some(legs);
1051        self
1052    }
1053
1054    /// Set the Buying Power Warning Status for the `OrderRequest`.
1055    pub fn buying_power_warning(mut self, status: BPWarningStatus) -> Self {
1056        self.buying_power_warning = Some(status);
1057        self
1058    }
1059
1060    /// Set the Advanced Options for the `OrderRequest`.
1061    pub fn advanced_options(mut self, options: AdvancedOrderOptions) -> Self {
1062        self.advanced_options = Some(options);
1063        self
1064    }
1065
1066    /// Finish building the `OrderRequest`.
1067    ///
1068    /// NOTE: `account_id`, `order_type`, `quantity`, `symbol`,
1069    /// `time_in_force`, and `trade_action` are all required.
1070    pub fn build(self) -> Result<OrderRequest, Error> {
1071        Ok(OrderRequest {
1072            account_id: self.account_id.ok_or(Error::AccountIdNotSet)?,
1073            advanced_options: self.advanced_options,
1074            buying_power_warning: self.buying_power_warning,
1075            legs: self.legs,
1076            osos: self.osos,
1077            order_confirm_id: self.order_confirm_id,
1078            route: self.route,
1079            trade_action: self.trade_action.ok_or(Error::TradeActionNotSet)?,
1080            time_in_force: self.time_in_force.ok_or(Error::TimeInForceNotSet)?,
1081            symbol: self.symbol.ok_or(Error::SymbolNotSet)?,
1082            order_type: self.order_type.ok_or(Error::OrderTypeNotSet)?,
1083            quantity: self.quantity.ok_or(Error::QuantityNotSet)?,
1084            stop_price: self.stop_price,
1085            limit_price: self.limit_price,
1086        })
1087    }
1088}
1089
1090#[derive(Clone, Debug, Deserialize, Serialize)]
1091#[serde(rename_all = "PascalCase")]
1092/// Advanced options for configuring orders.
1093pub struct AdvancedOrderOptions {
1094    /// This option allows you to place orders that will
1095    /// only add liquidity on the route you selected. To
1096    /// place an Add Liquidity order, the user must also
1097    /// select Book Only order type.
1098    ///
1099    /// NOTE: Only calid for Equities.
1100    pub add_liquidity: bool,
1101
1102    /// Use this advanced order feature when you do not
1103    /// want a partial fill. Your order will be filled
1104    /// in its entirety or not at all.
1105    ///
1106    /// NOTE: Valid for Equities and Options.
1107    pub all_or_none: bool,
1108
1109    /// This option restricts the destination you choose
1110    /// in the direct routing from re-routing your order
1111    /// to another destination. This type of order is useful
1112    /// in controlling your execution costs by avoiding
1113    /// fees the Exchanges can charge for rerouting your
1114    /// order to another market center.
1115    ///
1116    /// NOTE: Only valid for Equities.
1117    pub book_only: bool,
1118
1119    /// You can use this option to reflect a Bid/Ask
1120    /// at a lower/higher price than you are willing
1121    /// to pay using a specified price increment.
1122    ///
1123    /// NOTE: Only valid for `Limit` and `StopLimit` orders.
1124    ///
1125    /// NOTE: Only valid for Equities.
1126    pub discretionary_price: String,
1127
1128    /// Allows you to specify when an order will be placed
1129    /// based on the price action of one or more symbols.
1130    pub market_activation_rules: Vec<MarketActivationRule>,
1131
1132    /// When you send a non-display order, it will not be
1133    /// reflected in either the Market Depth display or
1134    /// ECN books.
1135    ///
1136    /// NOTE: Only valid for Equities.
1137    pub non_display: bool,
1138
1139    // TODO: I think I can enum this
1140    /// This order type is useful to achieve a fair price in
1141    /// a fast or volatile market.
1142    ///
1143    /// NOTE: Only valid for Equities.
1144    pub peg_value: String,
1145
1146    /// Hides the true number of shares or contracts intended
1147    /// to be bought or sold.
1148    ///
1149    /// NOTE: Only valid for `Limit` and `StopLimit` order types.
1150    ///
1151    /// NOTE: Only valid for Equities and Futures.
1152    ///
1153    /// <div class="warning">NOTE: Not valid for all exchanges.</div>
1154    pub show_only_quantity: String,
1155
1156    /// Allows you to specify a time that an order will be placed.
1157    pub time_activation_rules: Vec<TimeActivationRule>,
1158
1159    /// Trailing Stop offeset, amount or percent.
1160    pub trailing_stop: TrailingStop,
1161}
1162
1163// TODO: There is a similar enum in `crate::account`
1164// it should instead just use this enum.
1165#[derive(Clone, Debug, Deserialize, Serialize)]
1166/// The different trade actions that can be sent or
1167/// received, and conveys the intent of the order.
1168pub enum TradeAction {
1169    #[serde(rename = "BUY")]
1170    /// NOTE: Only for Equities and Futures
1171    Buy,
1172
1173    #[serde(rename = "SELL")]
1174    /// NOTE: Only for Equities and Futures
1175    Sell,
1176
1177    #[serde(rename = "BUYTOCOVER")]
1178    /// NOTE: Only for Equities
1179    BuyToCover,
1180
1181    #[serde(rename = "SELLSHORT")]
1182    /// NOTE: Only for Equities
1183    SellShort,
1184
1185    #[serde(rename = "BUYTOOPEN")]
1186    /// NOTE: Only for Options
1187    BuyToOpen,
1188
1189    #[serde(rename = "BUYTOCLOSE")]
1190    /// NOTE: Only for Options
1191    BuyToClose,
1192
1193    #[serde(rename = "SELLTOOPEN")]
1194    /// NOTE: Only for Options
1195    SellToOpen,
1196
1197    #[serde(rename = "SELLTOCLOSE")]
1198    /// NOTE: Only for Options
1199    SellToClose,
1200}
1201
1202#[derive(Clone, Debug, Deserialize, Serialize)]
1203#[serde(rename_all = "PascalCase")]
1204/// Defines the duration and expiration of an Order.
1205pub struct OrderTimeInForce {
1206    /// The duration type for the order.
1207    pub duration: Duration,
1208
1209    /// The expiration timestamp for the order.
1210    pub expiration: Option<String>,
1211}
1212
1213#[derive(Clone, Debug, Deserialize, Serialize)]
1214#[serde(rename_all = "PascalCase")]
1215/// A sub component order apart of the overall
1216/// trade the Order is for.
1217pub struct OrderRequestLeg {
1218    /// The quantity of the order.
1219    pub quantity: String,
1220    /// The symbol used for this leg of the order.
1221    pub symbol: String,
1222    /// The intent of the order.
1223    pub trade_action: TradeAction,
1224}
1225
1226#[derive(Clone, Debug, Deserialize, Serialize)]
1227/// The different statuses for buing power warnings.
1228pub enum BPWarningStatus {
1229    /// Enforce, this status indicates that a buying
1230    /// power warning should be enforced.
1231    Enforce,
1232    /// Preconfirmed, this status indicates that a buying
1233    /// power warning has been displayed but not yet confirmed.
1234    Preconfirmed,
1235    /// Confirmed, this status indicates that a buying power
1236    /// warning has been displayed and is confirmed.
1237    Confirmed,
1238}
1239
1240#[derive(Clone, Debug, Deserialize, Serialize)]
1241/// The length of time for which an order will
1242/// remain valid in the market.
1243pub enum Duration {
1244    /// Day, valid until the end of the
1245    /// regular trading session.
1246    DAY,
1247
1248    /// Day Plus, valid until the end of the
1249    /// extended trading session.
1250    DYP,
1251
1252    /// Good Till Canceled, valid until the
1253    /// order is canceled.
1254    ///
1255    /// NOTE: There is a maximum lifespan of
1256    /// 90 calendar days.
1257    GTC,
1258
1259    /// Good till Canceled Plus, valid until
1260    /// the order is canceled.
1261    ///
1262    /// NOTE: There is a maximum lifespan of
1263    /// 90 calendar days.
1264    GCP,
1265
1266    /// Good Through Date, valid until a
1267    /// specified date.
1268    ///
1269    /// NOTE: There is a maximum lifespan of
1270    /// 90 calendar days.
1271    GTD,
1272
1273    /// Good thourgh Date Plus, valid until a
1274    /// specified date.
1275    ///
1276    /// NOTE: There is a maximum lifespan of
1277    /// 90 calendar days.
1278    GDP,
1279
1280    /// Opening, only valid for listed
1281    /// stocks at the opening session price.
1282    OPG,
1283
1284    /// Close, orders that target the closing
1285    /// session of an exchange.
1286    CLO,
1287
1288    /// Immediate Or Cancel, filled immediatly
1289    /// or canceled.
1290    ///
1291    /// NOTE: Partial fills of an order are accepted.
1292    IOC,
1293
1294    /// Fill Or Kill, filled entirely or canceled.
1295    ///
1296    /// NOTE: Does NOT accept partial fills.
1297    FOK,
1298
1299    /// 1 Minute, expires after one minute of
1300    /// being placed.
1301    #[serde(rename = "1")]
1302    OneMinute,
1303
1304    /// 3 Minute, expires after three minutes of
1305    /// being placed.
1306    #[serde(rename = "3")]
1307    ThreeMinute,
1308
1309    /// 5 Minute, expires after five minutes of
1310    /// being placed.
1311    #[serde(rename = "5")]
1312    FiveMinute,
1313}
1314
1315#[derive(Clone, Debug, Deserialize, Serialize)]
1316#[serde(rename_all = "PascalCase")]
1317/// Order Sends Orders
1318pub struct Oso {
1319    /// Other orders in the OSO
1320    pub orders: Vec<OrderRequest>,
1321    /// The type of OSO Order
1322    pub r#type: AdvancedOrderType,
1323}
1324
1325#[derive(Clone, Debug, Deserialize, Serialize)]
1326/// Different types of advanced order types
1327pub enum AdvancedOrderType {
1328    /// Normal Order
1329    Normal,
1330
1331    /// Bracket Order, multiple orders ranged
1332    /// in price.
1333    BRK,
1334
1335    /// Order Cancels Other, multiple orders
1336    /// but only one can be filled as the rest
1337    /// cancel when any of the orders is filled.
1338    OCO,
1339}
1340
1341#[derive(Clone, Debug, Deserialize, Serialize)]
1342#[serde(rename_all = "PascalCase")]
1343/// A Route for Order Execution
1344pub struct Route {
1345    /// The ID that must be sent in the optional Route
1346    /// property of a POST order request, when specifying
1347    /// a route for an order.
1348    pub id: String,
1349    /// The name of the route.
1350    pub name: String,
1351    /// The asset type of the route
1352    pub asset_types: Vec<AssetType>,
1353}
1354impl Route {
1355    /// Fetch valid routes for sending an order for execution.
1356    ///
1357    /// # Example
1358    /// ---
1359    /// Example: Fetch a list of routes to send orders for execution.
1360    /// ```ignore
1361    /// use tradestation::{ClientBuilder, Error, Token};
1362    ///
1363    /// #[tokio::main]
1364    /// async fn main() -> Result<(), Error> {
1365    ///     // Create client
1366    ///     let mut client = ClientBuilder::new()?
1367    ///         .credentials("YOUR_CLIENT_ID", "YOUR_CLIENT_SECRET")?
1368    ///         .token(Token { /* YOUR BEARER AUTH TOKEN */ })?
1369    ///         .build()
1370    ///         .await?;
1371    ///
1372    ///     // Example: Fetch a list of routes to send orders for execution.
1373    ///     let routes = client.get_execution_routes().await?;
1374    ///     println!("Valid routes for order execution: {routes:?}");
1375    ///
1376    ///     Ok(())
1377    /// }
1378    /// ```
1379    pub async fn fetch(client: &mut Client) -> Result<Vec<Route>, Error> {
1380        let endpoint = String::from("orderexecution/routes");
1381        let resp: GetExecutionRoutesResp = client
1382            .get(&endpoint)
1383            .await?
1384            .json::<GetExecutionRoutesRespRaw>()
1385            .await?
1386            .into();
1387
1388        if let Some(routes) = resp.routes {
1389            Ok(routes)
1390        } else {
1391            Err(resp.error.unwrap_or(Error::UnknownTradeStationAPIError))
1392        }
1393    }
1394}
1395impl Client {
1396    /// Fetch valid routes for sending an order for execution.
1397    ///
1398    /// # Example
1399    /// ---
1400    /// Example: Fetch a list of routes to send orders for execution.
1401    /// ```ignore
1402    /// use tradestation::{ClientBuilder, Error, Token};
1403    ///
1404    /// #[tokio::main]
1405    /// async fn main() -> Result<(), Error> {
1406    ///     // Create client
1407    ///     let mut client = ClientBuilder::new()?
1408    ///         .credentials("YOUR_CLIENT_ID", "YOUR_CLIENT_SECRET")?
1409    ///         .token(Token { /* YOUR BEARER AUTH TOKEN */ })?
1410    ///         .build()
1411    ///         .await?;
1412    ///
1413    ///     // Example: Fetch a list of routes to send orders for execution.
1414    ///     let routes = client.get_execution_routes().await?;
1415    ///     println!("Valid routes for order execution: {routes:?}");
1416    ///
1417    ///     Ok(())
1418    /// }
1419    /// ```
1420    pub async fn get_execution_routes(&mut self) -> Result<Vec<Route>, Error> {
1421        Route::fetch(self).await
1422    }
1423}
1424
1425#[derive(Clone, Debug, Deserialize, Serialize)]
1426#[serde(rename_all = "PascalCase")]
1427/// Valid Activation Triggers for an Order.
1428pub struct ActivationTrigger {
1429    /// The Activation Trigger Key
1430    ///
1431    /// NOTE: This is what you with your orders.
1432    pub key: ActivationTriggerKey,
1433
1434    /// Name of the Activation Trigger.
1435    pub name: String,
1436
1437    /// Description of the Activation Trigger.
1438    pub description: String,
1439}
1440impl ActivationTrigger {
1441    /// Fetch Activation Triggers for Order Execution.
1442    ///
1443    /// NOTE: This provides the `key` that must be sent with an
1444    /// order to utilize and be triggered by the activation function.
1445    ///
1446    /// # Example
1447    /// ---
1448    /// Fetch valid activation triggers to utilize with your orders.
1449    ///
1450    /// ```ignore
1451    /// use tradestation::{ClientBuilder, Error, Token};
1452    ///
1453    /// #[tokio::main]
1454    /// async fn main() -> Result<(), Error> {
1455    ///     // Initialize client
1456    ///     let mut client = ClientBuilder::new()?
1457    ///         .credentials("YOUR_CLIENT_ID", "YOUR_CLIENT_SECRET")?
1458    ///         .token(Token {
1459    ///             access_token: String::from("YOUR_ACCESS_TOKEN"),
1460    ///             refresh_token: String::from("YOUR_REFRESH_TOKEN"),
1461    ///             id_token: String::from("YOUR_ID_TOKEN"),
1462    ///             token_type: String::from("Bearer"),
1463    ///             scope: String::from("YOUR_SCOPES SPACE_SEPERATED FOR_EACH_SCOPE"),
1464    ///             expires_in: 1200,
1465    ///         })?
1466    ///         .build()
1467    ///         .await?;
1468    ///
1469    ///     // Fetch a list of valid activation triggers for order execution.
1470    ///     let triggers = client.get_activation_triggers().await?;
1471    ///     println!("Valid activation triggers for order execution: {triggers:?}");
1472    ///
1473    ///     Ok(())
1474    /// }
1475    /// ```
1476    pub async fn fetch(client: &mut Client) -> Result<Vec<ActivationTrigger>, Error> {
1477        let endpoint = String::from("orderexecution/activationtriggers");
1478        let resp: GetActivationTriggersResp = client
1479            .get(&endpoint)
1480            .await?
1481            .json::<GetActivationTriggersRespRaw>()
1482            .await?
1483            .into();
1484
1485        if let Some(triggers) = resp.activation_triggers {
1486            Ok(triggers)
1487        } else {
1488            Err(resp.error.unwrap_or(Error::UnknownTradeStationAPIError))
1489        }
1490    }
1491}
1492impl Client {
1493    /// Fetch Activation Triggers for Order Execution.
1494    ///
1495    /// NOTE: This provides the `key` that must be sent with an
1496    /// order to utilize and be triggered by the activation function.
1497    ///
1498    /// # Example
1499    /// ---
1500    /// Fetch valid activation triggers to utilize with your orders.
1501    ///
1502    /// ```ignore
1503    /// use tradestation::{ClientBuilder, Error, Token};
1504    ///
1505    /// #[tokio::main]
1506    /// async fn main() -> Result<(), Error> {
1507    ///     // Initialize client
1508    ///     let mut client = ClientBuilder::new()?
1509    ///         .credentials("YOUR_CLIENT_ID", "YOUR_CLIENT_SECRET")?
1510    ///         .token(Token {
1511    ///             access_token: String::from("YOUR_ACCESS_TOKEN"),
1512    ///             refresh_token: String::from("YOUR_REFRESH_TOKEN"),
1513    ///             id_token: String::from("YOUR_ID_TOKEN"),
1514    ///             token_type: String::from("Bearer"),
1515    ///             scope: String::from("YOUR_SCOPES SPACE_SEPERATED FOR_EACH_SCOPE"),
1516    ///             expires_in: 1200,
1517    ///         })?
1518    ///         .build()
1519    ///         .await?;
1520    ///
1521    ///     // Fetch a list of valid activation triggers for order execution.
1522    ///     let triggers = client.get_activation_triggers().await?;
1523    ///     println!("Valid activation triggers for order execution: {triggers:?}");
1524    ///
1525    ///     Ok(())
1526    /// }
1527    /// ```
1528    pub async fn get_activation_triggers(&mut self) -> Result<Vec<ActivationTrigger>, Error> {
1529        ActivationTrigger::fetch(self).await
1530    }
1531}
1532
1533#[derive(Clone, Debug, Deserialize, Serialize)]
1534/// The different types of activation trigger keys.
1535pub enum ActivationTriggerKey {
1536    /// Single Trade Tick, one trade tick must print
1537    /// within your stop price to trigger your stop.
1538    STT,
1539
1540    /// Single Trade Tick Within NBBO, one trade tick
1541    /// within the National Best Bid or Offer (NBBO)
1542    /// must print within your stop price to trigger
1543    /// your stop.
1544    STTN,
1545
1546    /// Single Bid/Ask Tick
1547    /// ---
1548    /// * Buy/Cover Orders: One Ask tick must print within
1549    ///   your stop price to trigger your stop.
1550    ///
1551    /// * Sell/Short Orders: One Bid tick must print within
1552    ///   your stop price to trigger your stop.
1553    SBA,
1554
1555    /// Single Ask/Bid Tick
1556    /// ---
1557    /// * Buy/Cover Orders: One Bid tick must print within
1558    ///   your stop price to trigger your stop.
1559    ///
1560    /// * Sell/Short Orders: One Ask tick must print within
1561    ///   your stop price to trigger your stop.
1562    SAB,
1563
1564    /// Double Trade Tick, two consecutive trade ticks must
1565    /// print within your stop price to trigger your stop.
1566    DTT,
1567
1568    /// Double Trade Tick Within NBBO, two consecutive trade
1569    /// ticks within the National Best Bid or Offer (NBBO) must
1570    /// print within your stop price to trigger your stop.
1571    DTTN,
1572
1573    /// Double Bid/Ask Tick
1574    /// ---
1575    /// * Buy/Cover Orders: Two consecutive Ask ticks must print
1576    ///   within your stop price to trigger your stop.
1577    ///
1578    /// * Sell/Short Orders: Two consecutive Bid ticks must print
1579    ///   within your stop price to trigger your stop.
1580    DBA,
1581
1582    /// Double Ask/Bid Tick
1583    /// ---
1584    /// * Buy/Cover Orders: Two consecutive Bid ticks must print
1585    ///   within your stop price to trigger your stop.
1586    ///
1587    /// * Sell/Short Orders: Two consecutive Ask ticks must print
1588    ///   within your stop price to trigger your stop.
1589    DAB,
1590
1591    /// Twice Trade Tick, two trade ticks must print within your
1592    /// stop price to trigger your stop.
1593    TTT,
1594
1595    /// Twice Trade Tick Within NBBO, two trade ticks within the
1596    /// National Best Bid or Offer (NBBO) must print within your
1597    /// stop price to trigger your stop.
1598    TTTN,
1599
1600    /// Twice Bid/Ask Tick
1601    /// ---
1602    /// * Buy/Cover Orders: Two Ask ticks must print within your
1603    ///   stop price to trigger your stop.
1604    ///
1605    /// * Sell/Short Orders: Two Bid ticks must print within your
1606    ///   stop price to trigger your stop.
1607    TBA,
1608
1609    /// Twice Ask/Bid Tick
1610    /// ---
1611    /// * Buy/Cover Orders: Two Bid ticks must print within your
1612    ///   stop price to trigger your stop.
1613    ///
1614    /// * Sell/Short Orders: Two Ask ticks must print within your
1615    ///   stop price to trigger your stop.
1616    TAB,
1617}
1618
1619#[derive(Clone, Debug, Deserialize, Serialize)]
1620#[serde(rename_all = "PascalCase")]
1621pub struct OrderConfirmation {
1622    /// The route of the order.
1623    ///
1624    /// NOTE: For Stocks and Options, Route value will
1625    /// default to Intelligent if no value is set.
1626    pub route: String,
1627
1628    /// Defines the duration or expiration timestamp of an Order.
1629    pub time_in_force: OrderTimeInForce,
1630
1631    #[serde(rename = "AccountID")]
1632    /// The ID of the Account the order belongs to.
1633    pub account_id: String,
1634
1635    /// A short text summary / description of the order.
1636    pub summary_message: String,
1637
1638    #[serde(rename = "OrderConfirmID")]
1639    /// The ID of the order confirm.
1640    pub order_confirm_id: String,
1641
1642    /// The estimated price of the order.
1643    pub estimated_price: String,
1644
1645    /// The estimated display price of the order.
1646    pub estimated_price_display: Option<String>,
1647
1648    /// The estimated cost of the order.
1649    pub estimated_cost: String,
1650
1651    /// The estimated display cost of the order.
1652    pub estimated_cost_display: Option<String>,
1653
1654    /// The estimated commission cost for the order.
1655    pub estimated_commission: String,
1656
1657    /// The estimated commission cost display for the order.
1658    pub estimated_commission_display: Option<String>,
1659
1660    /// The estimated debit or credit cost of the the order.
1661    ///
1662    /// NOTE: Debit costs will have a positive cost, and credit
1663    /// costs will have a negative cost.
1664    pub debit_credit_estimated_cost: Option<String>,
1665
1666    /// The estimated debit or credit display cost of the the order.
1667    ///
1668    /// NOTE: Debit costs will have a positive cost, and credit
1669    /// costs will have a negative cost.
1670    pub debit_credit_estimated_cost_display: Option<String>,
1671
1672    /// The currency the product is based on.
1673    ///
1674    /// NOTE: Only valid for futures orders.
1675    pub product_currency: Option<String>,
1676
1677    /// The currency the account is based on.
1678    ///
1679    /// NOTE: Only valid for futures orders.
1680    pub account_currency: Option<String>,
1681
1682    /// The initial margin display cost of the order.
1683    ///
1684    /// NOTE: Only valid for futures orders.
1685    pub initial_margin_display: Option<String>,
1686}