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}