ibapi/orders/order_builder.rs
1use super::{Action, Order, OrderComboLeg, TagValue};
2
3/// An auction order is entered into the electronic trading system during the pre-market opening period for execution at the
4/// Calculated Opening Price (COP). If your order is not filled on the open, the order is re-submitted as a limit order with
5/// the limit price set to the COP or the best bid/ask after the market opens.
6/// Products: FUT, STK
7pub fn at_auction(action: Action, quantity: f64, price: f64) -> Order {
8 Order {
9 action,
10 tif: "AUC".to_owned(),
11 order_type: "MTL".to_owned(),
12 total_quantity: quantity,
13 limit_price: Some(price),
14 ..Order::default()
15 }
16}
17
18/// A Discretionary order is a limit order submitted with a hidden, specified 'discretionary' amount off the limit price which
19/// may be used to increase the price range over which the limit order is eligible to execute. The market sees only the limit price.
20/// Products: STK
21pub fn discretionary(action: Action, quantity: f64, price: f64, discretionary_amount: f64) -> Order {
22 Order {
23 action,
24 order_type: "LMT".to_owned(),
25 total_quantity: quantity,
26 limit_price: Some(price),
27 discretionary_amt: discretionary_amount,
28 ..Order::default()
29 }
30}
31
32/// A Market order is an order to buy or sell at the market bid or offer price. A market order may increase the likelihood of a fill
33/// and the speed of execution, but unlike the Limit order a Market order provides no price protection and may fill at a price far
34/// lower/higher than the current displayed bid/ask.
35/// Products: BOND, CFD, EFP, CASH, FUND, FUT, FOP, OPT, STK, WAR
36pub fn market_order(action: Action, quantity: f64) -> Order {
37 Order {
38 action,
39 order_type: "MKT".to_owned(),
40 total_quantity: quantity,
41 ..Order::default()
42 }
43}
44
45/// A Market if Touched (MIT) is an order to buy (or sell) a contract below (or above) the market. Its purpose is to take advantage
46/// of sudden or unexpected changes in share or other prices and provides investors with a trigger price to set an order in motion.
47/// Investors may be waiting for excessive strength (or weakness) to cease, which might be represented by a specific price point.
48/// MIT orders can be used to determine whether or not to enter the market once a specific price level has been achieved. This order
49/// is held in the system until the trigger price is touched, and is then submitted as a market order. An MIT order is similar to a
50/// stop order, except that an MIT sell order is placed above the current market price, and a stop sell order is placed below
51/// Products: BOND, CFD, CASH, FUT, FOP, OPT, STK, WAR
52pub fn market_if_touched(action: Action, quantity: f64, price: f64) -> Order {
53 Order {
54 action,
55 order_type: "MIT".to_owned(),
56 total_quantity: quantity,
57 aux_price: Some(price),
58 ..Order::default()
59 }
60}
61
62/// A Market-on-Close (MOC) order is a market order that is submitted to execute as close to the closing price as possible.
63/// Products: CFD, FUT, STK, WAR
64pub fn market_on_close(action: Action, quantity: f64) -> Order {
65 Order {
66 action,
67 order_type: "MOC".to_owned(),
68 total_quantity: quantity,
69 ..Order::default()
70 }
71}
72
73/// A Market-on-Open (MOO) order combines a market order with the OPG time in force to create an order that is automatically
74/// submitted at the market's open and fills at the market price.
75/// Products: CFD, STK, OPT, WAR
76pub fn market_on_open(action: Action, quantity: f64) -> Order {
77 Order {
78 action,
79 order_type: "MKT".to_owned(),
80 total_quantity: quantity,
81 tif: "OPG".to_owned(),
82 ..Order::default()
83 }
84}
85
86/// ISE Midpoint Match (MPM) orders always execute at the midpoint of the NBBO. You can submit market and limit orders direct-routed
87/// to ISE for MPM execution. Market orders execute at the midpoint whenever an eligible contra-order is available. Limit orders
88/// execute only when the midpoint price is better than the limit price. Standard MPM orders are completely anonymous.
89/// Products: STK
90pub fn midpoint_match(action: Action, quantity: f64) -> Order {
91 Order {
92 action,
93 order_type: "MKT".to_owned(),
94 total_quantity: quantity,
95 ..Order::default()
96 }
97}
98
99// A Midprice order is designed to split the difference between the bid and ask prices, and fill at the current midpoint of
100// the NBBO or better. Set an optional price cap to define the highest price (for a buy order) or the lowest price (for a sell
101// order) you are willing to accept. Requires TWS 975+. Smart-routing to US stocks only.
102pub fn midprice(action: Action, quantity: f64, price_cap: f64) -> Order {
103 Order {
104 action,
105 order_type: "MIDPRICE".to_owned(),
106 total_quantity: quantity,
107 limit_price: Some(price_cap),
108 ..Order::default()
109 }
110}
111
112/// A pegged-to-market order is designed to maintain a purchase price relative to the national best offer (NBO) or a sale price
113/// relative to the national best bid (NBB). Depending on the width of the quote, this order may be passive or aggressive.
114/// The trader creates the order by entering a limit price which defines the worst limit price that they are willing to accept.
115/// Next, the trader enters an offset amount which computes the active limit price as follows:
116/// Sell order price = Bid price + offset amount
117/// Buy order price = Ask price - offset amount
118/// Products: STK
119pub fn pegged_to_market(action: Action, quantity: f64, market_offset: f64) -> Order {
120 Order {
121 action,
122 order_type: "PEG MKT".to_owned(),
123 total_quantity: quantity,
124 aux_price: Some(market_offset),
125 ..Order::default()
126 }
127}
128
129/// A Pegged to Stock order continually adjusts the option order price by the product of a signed user-define delta and the change of
130/// the option's underlying stock price. The delta is entered as an absolute and assumed to be positive for calls and negative for puts.
131/// A buy or sell call order price is determined by adding the delta times a change in an underlying stock price to a specified starting
132/// price for the call. To determine the change in price, the stock reference price is subtracted from the current NBBO midpoint.
133/// The Stock Reference Price can be defined by the user, or defaults to the NBBO midpoint at the time of the order if no reference price
134/// is entered. You may also enter a high/low stock price range which cancels the order when reached. The delta times the change in stock
135/// price will be rounded to the nearest penny in favor of the order.
136/// Products: OPT
137pub fn pegged_to_stock(action: Action, quantity: f64, delta: f64, stock_reference_price: f64, starting_price: f64) -> Order {
138 Order {
139 action,
140 order_type: "PEG STK".to_owned(),
141 total_quantity: quantity,
142 delta: Some(delta),
143 stock_ref_price: Some(stock_reference_price),
144 starting_price: Some(starting_price),
145 ..Order::default()
146 }
147}
148
149/// Relative (a.k.a. Pegged-to-Primary) orders provide a means for traders to seek a more aggressive price than the National Best Bid
150/// and Offer (NBBO). By acting as liquidity providers, and placing more aggressive bids and offers than the current best bids and offers,
151/// traders increase their odds of filling their order. Quotes are automatically adjusted as the markets move, to remain aggressive.
152/// For a buy order, your bid is pegged to the NBB by a more aggressive offset, and if the NBB moves up, your bid will also move up.
153/// If the NBB moves down, there will be no adjustment because your bid will become even more aggressive and execute. For sales, your
154/// offer is pegged to the NBO by a more aggressive offset, and if the NBO moves down, your offer will also move down. If the NBO moves up,
155/// there will be no adjustment because your offer will become more aggressive and execute. In addition to the offset, you can define an
156/// absolute cap, which works like a limit price, and will prevent your order from being executed above or below a specified level.
157/// Stocks, Options and Futures - not available on paper trading
158/// Products: CFD, STK, OPT, FUT
159pub fn relative_pegged_to_primary(action: Action, quantity: f64, price_cap: f64, offset_amount: f64) -> Order {
160 Order {
161 action,
162 order_type: "REL".to_owned(),
163 total_quantity: quantity,
164 limit_price: Some(price_cap),
165 aux_price: Some(offset_amount),
166 ..Order::default()
167 }
168}
169
170/// Sweep-to-fill orders are useful when a trader values speed of execution over price. A sweep-to-fill order identifies the best price
171/// and the exact quantity offered/available at that price, and transmits the corresponding portion of your order for immediate execution.
172/// Simultaneously it identifies the next best price and quantity offered/available, and submits the matching quantity of your order for
173/// immediate execution.
174/// Products: CFD, STK, WAR
175pub fn sweep_to_fill(action: Action, quantity: f64, price: f64) -> Order {
176 Order {
177 action,
178 order_type: "LMT".to_owned(),
179 total_quantity: quantity,
180 limit_price: Some(price),
181 sweep_to_fill: true,
182 ..Order::default()
183 }
184}
185
186/// For option orders routed to the Boston Options Exchange (BOX) you may elect to participate in the BOX's price improvement auction in
187/// pennies. All BOX-directed price improvement orders are immediately sent from Interactive Brokers to the BOX order book, and when the
188/// terms allow, IB will evaluate it for inclusion in a price improvement auction based on price and volume priority. In the auction, your
189/// order will have priority over broker-dealer price improvement orders at the same price.
190/// An Auction Limit order at a specified price. Use of a limit order ensures that you will not receive an execution at a price less favorable
191/// than the limit price. Enter limit orders in penny increments with your auction improvement amount computed as the difference between your
192/// limit order price and the nearest listed increment.
193/// Products: OPT
194/// Supported Exchanges: BOX
195pub fn auction_limit(action: Action, quantity: f64, price: f64, auction_strategy: i32) -> Order {
196 Order {
197 action,
198 order_type: "LMT".to_owned(),
199 total_quantity: quantity,
200 limit_price: Some(price),
201 auction_strategy: Some(auction_strategy),
202 ..Order::default()
203 }
204}
205
206/// For option orders routed to the Boston Options Exchange (BOX) you may elect to participate in the BOX's price improvement auction in pennies.
207/// All BOX-directed price improvement orders are immediately sent from Interactive Brokers to the BOX order book, and when the terms allow,
208/// IB will evaluate it for inclusion in a price improvement auction based on price and volume priority. In the auction, your order will have
209/// priority over broker-dealer price improvement orders at the same price.
210/// An Auction Pegged to Stock order adjusts the order price by the product of a signed delta (which is entered as an absolute and assumed to be
211/// positive for calls, negative for puts) and the change of the option's underlying stock price. A buy or sell call order price is determined
212/// by adding the delta times a change in an underlying stock price change to a specified starting price for the call. To determine the change
213/// in price, a stock reference price (NBBO midpoint at the time of the order is assumed if no reference price is entered) is subtracted from
214/// the current NBBO midpoint. A stock range may also be entered that cancels an order when reached. The delta times the change in stock price
215/// will be rounded to the nearest penny in favor of the order and will be used as your auction improvement amount.
216/// Products: OPT
217/// Supported Exchanges: BOX
218pub fn auction_pegged_to_stock(action: Action, quantity: f64, starting_price: f64, delta: f64) -> Order {
219 Order {
220 action,
221 order_type: "PEG STK".to_owned(),
222 total_quantity: quantity,
223 delta: Some(delta),
224 starting_price: Some(starting_price),
225 ..Order::default()
226 }
227}
228
229/// For option orders routed to the Boston Options Exchange (BOX) you may elect to participate in the BOX's price improvement auction in pennies.
230/// All BOX-directed price improvement orders are immediately sent from Interactive Brokers to the BOX order book, and when the terms allow,
231/// IB will evaluate it for inclusion in a price improvement auction based on price and volume priority. In the auction, your order will have
232/// priority over broker-dealer price improvement orders at the same price.
233/// An Auction Relative order that adjusts the order price by the product of a signed delta (which is entered as an absolute and assumed to be
234/// positive for calls, negative for puts) and the change of the option's underlying stock price. A buy or sell call order price is determined
235/// by adding the delta times a change in an underlying stock price change to a specified starting price for the call. To determine the change
236/// in price, a stock reference price (NBBO midpoint at the time of the order is assumed if no reference price is entered) is subtracted from
237/// the current NBBO midpoint. A stock range may also be entered that cancels an order when reached. The delta times the change in stock price
238/// will be rounded to the nearest penny in favor of the order and will be used as your auction improvement amount.
239/// Products: OPT
240/// Supported Exchanges: BOX
241pub fn auction_relative(action: Action, quantity: f64, offset: f64) -> Order {
242 Order {
243 action,
244 order_type: "REL".to_owned(),
245 total_quantity: quantity,
246 aux_price: Some(offset),
247 ..Order::default()
248 }
249}
250
251/// The Block attribute is used for large volume option orders on ISE that consist of at least 50 contracts. To execute large-volume
252/// orders over time without moving the market, use the Accumulate/Distribute algorithm.
253/// Products: OPT
254pub fn block(action: Action, quantity: f64, price: f64) -> Order {
255 Order {
256 action,
257 order_type: "LMT".to_owned(),
258 total_quantity: quantity,
259 limit_price: Some(price),
260 block_order: true,
261 ..Order::default()
262 }
263}
264
265/// A Box Top order executes as a market order at the current best price. If the order is only partially filled, the remainder is submitted as
266/// a limit order with the limit price equal to the price at which the filled portion of the order executed.
267/// Products: OPT
268/// Supported Exchanges: BOX
269pub fn box_top(action: Action, quantity: f64) -> Order {
270 Order {
271 action,
272 order_type: "BOX TOP".to_owned(),
273 total_quantity: quantity,
274 ..Order::default()
275 }
276}
277
278/// A Limit order is an order to buy or sell at a specified price or better. The Limit order ensures that if the order fills,
279/// it will not fill at a price less favorable than your limit price, but it does not guarantee a fill.
280/// Products: BOND, CFD, CASH, FUT, FOP, OPT, STK, WAR
281pub fn limit_order(action: Action, quantity: f64, limit_price: f64) -> Order {
282 Order {
283 action,
284 order_type: "LMT".to_owned(),
285 total_quantity: quantity,
286 limit_price: Some(limit_price),
287 ..Order::default()
288 }
289}
290
291/// Forex orders can be placed in denomination of second currency in pair using cash_qty field
292/// Requires TWS or IBG 963+
293/// <https://www.interactivebrokers.com/en/index.php?f=23876#963-02>
294pub fn limit_order_with_cash_qty(action: Action, limit_price: f64, cash_qty: f64) -> Order {
295 Order {
296 action,
297 order_type: "LMT".to_owned(),
298 limit_price: Some(limit_price),
299 cash_qty: Some(cash_qty),
300 ..Order::default()
301 }
302}
303
304/// A Limit if Touched is an order to buy (or sell) a contract at a specified price or better, below (or above) the market. This order is
305/// held in the system until the trigger price is touched. An LIT order is similar to a stop limit order, except that an LIT sell order is
306/// placed above the current market price, and a stop limit sell order is placed below.
307/// Products: BOND, CFD, CASH, FUT, FOP, OPT, STK, WAR
308pub fn limit_if_touched(action: Action, quantity: f64, limit_price: f64, trigger_price: f64) -> Order {
309 Order {
310 action,
311 order_type: "LIT".to_owned(),
312 total_quantity: quantity,
313 limit_price: Some(limit_price),
314 aux_price: Some(trigger_price),
315 ..Order::default()
316 }
317}
318
319/// A Limit-on-close (LOC) order will be submitted at the close and will execute if the closing price is at or better than the submitted
320/// limit price.
321/// Products: CFD, FUT, STK, WAR
322pub fn limit_on_close(action: Action, quantity: f64, limit_price: f64) -> Order {
323 Order {
324 action,
325 order_type: "LOC".to_owned(),
326 total_quantity: quantity,
327 limit_price: Some(limit_price),
328 ..Order::default()
329 }
330}
331
332/// A Limit-on-Open (LOO) order combines a limit order with the OPG time in force to create an order that is submitted at the market's open,
333/// and that will only execute at the specified limit price or better. Orders are filled in accordance with specific exchange rules.
334/// Products: CFD, STK, OPT, WAR
335pub fn limit_on_open(action: Action, quantity: f64, limit_price: f64) -> Order {
336 Order {
337 action,
338 order_type: "LMT".to_owned(),
339 total_quantity: quantity,
340 limit_price: Some(limit_price),
341 tif: "OPG".to_owned(),
342 ..Order::default()
343 }
344}
345
346/// Passive Relative orders provide a means for traders to seek a less aggressive price than the National Best Bid and Offer (NBBO) while
347/// keeping the order pegged to the best bid (for a buy) or ask (for a sell). The order price is automatically adjusted as the markets move
348/// to keep the order less aggressive. For a buy order, your order price is pegged to the NBB by a less aggressive offset, and if the NBB
349/// moves up, your bid will also move up. If the NBB moves down, there will be no adjustment because your bid will become aggressive and execute.
350/// For a sell order, your price is pegged to the NBO by a less aggressive offset, and if the NBO moves down, your offer will also move down.
351/// If the NBO moves up, there will be no adjustment because your offer will become aggressive and execute. In addition to the offset, you can
352/// define an absolute cap, which works like a limit price, and will prevent your order from being executed above or below a specified level.
353/// The Passive Relative order is similar to the Relative/Pegged-to-Primary order, except that the Passive relative subtracts the offset from
354/// the bid and the Relative adds the offset to the bid.
355/// Products: STK, WAR
356pub fn passive_relative(action: Action, quantity: f64, offset: f64) -> Order {
357 Order {
358 action,
359 order_type: "PASSV REL".to_owned(),
360 total_quantity: quantity,
361 aux_price: Some(offset),
362 ..Order::default()
363 }
364}
365
366/// A pegged-to-midpoint order provides a means for traders to seek a price at the midpoint of the National Best Bid and Offer (NBBO).
367/// The price automatically adjusts to peg the midpoint as the markets move, to remain aggressive. For a buy order, your bid is pegged to
368/// the NBBO midpoint and the order price adjusts automatically to continue to peg the midpoint if the market moves. The price only adjusts
369/// to be more aggressive. If the market moves in the opposite direction, the order will execute.
370/// Products: STK
371pub fn pegged_to_midpoint(action: Action, quantity: f64, offset: f64, limit_price: f64) -> Order {
372 Order {
373 action,
374 order_type: "PEG MID".to_owned(),
375 total_quantity: quantity,
376 aux_price: Some(offset),
377 limit_price: Some(limit_price),
378 ..Order::default()
379 }
380}
381
382/// Bracket orders are designed to help limit your loss and lock in a profit by "bracketing" an order with two opposite-side orders.
383/// A BUY order is bracketed by a high-side sell limit order and a low-side sell stop order. A SELL order is bracketed by a high-side buy
384/// stop order and a low side buy limit order.
385/// Products: CFD, BAG, FOP, CASH, FUT, OPT, STK, WAR
386pub fn bracket_order(
387 parent_order_id: i32,
388 action: Action,
389 quantity: f64,
390 limit_price: f64,
391 take_profit_limit_price: f64,
392 stop_loss_price: f64,
393) -> Vec<Order> {
394 //This will be our main or "parent" order
395 let parent = Order {
396 order_id: parent_order_id,
397 action,
398 order_type: "LMT".to_owned(),
399 total_quantity: quantity,
400 limit_price: Some(limit_price),
401 transmit: false,
402 ..Order::default()
403 };
404
405 let take_profit = Order {
406 order_id: parent.order_id + 1,
407 action: action.reverse(),
408 order_type: "LMT".to_owned(),
409 total_quantity: quantity,
410 limit_price: Some(take_profit_limit_price),
411 parent_id: parent_order_id,
412 transmit: false,
413 ..Order::default()
414 };
415
416 let stop_loss = Order {
417 order_id: parent.order_id + 2,
418 action: action.reverse(),
419 order_type: "STP".to_owned(),
420 //Stop trigger price
421 aux_price: Some(stop_loss_price),
422 total_quantity: quantity,
423 parent_id: parent_order_id,
424 //In this case, the low side order will be the last child being sent. Therefore, it needs to set this attribute to true
425 //to activate all its predecessors
426 transmit: true,
427 ..Order::default()
428 };
429
430 vec![parent, take_profit, stop_loss]
431}
432
433/// Products:CFD, FUT, FOP, OPT, STK, WAR
434/// A Market-to-Limit (MTL) order is submitted as a market order to execute at the current best market price. If the order is only
435/// partially filled, the remainder of the order is canceled and re-submitted as a limit order with the limit price equal to the price
436/// at which the filled portion of the order executed.
437pub fn market_to_limit(action: Action, quantity: f64) -> Order {
438 Order {
439 action,
440 order_type: "MTL".to_owned(),
441 total_quantity: quantity,
442 ..Order::default()
443 }
444}
445
446/// This order type is useful for futures traders using Globex. A Market with Protection order is a market order that will be cancelled and
447/// resubmitted as a limit order if the entire order does not immediately execute at the market price. The limit price is set by Globex to be
448/// close to the current market price, slightly higher for a sell order and lower for a buy order.
449/// Products: FUT, FOP
450pub fn market_with_protection(action: Action, quantity: f64) -> Order {
451 Order {
452 action,
453 order_type: "MKT PRT".to_owned(),
454 total_quantity: quantity,
455 ..Order::default()
456 }
457}
458
459/// A Stop order is an instruction to submit a buy or sell market order if and when the user-specified stop trigger price is attained or
460/// penetrated. A Stop order is not guaranteed a specific execution price and may execute significantly away from its stop price. A Sell
461/// Stop order is always placed below the current market price and is typically used to limit a loss or protect a profit on a long stock
462/// position. A Buy Stop order is always placed above the current market price. It is typically used to limit a loss or help protect a
463/// profit on a short sale.
464/// Products: CFD, BAG, CASH, FUT, FOP, OPT, STK, WAR
465pub fn stop(action: Action, quantity: f64, stop_price: f64) -> Order {
466 Order {
467 action,
468 order_type: "STP".to_owned(),
469 total_quantity: quantity,
470 aux_price: Some(stop_price),
471 ..Order::default()
472 }
473}
474
475/// A Stop-Limit order is an instruction to submit a buy or sell limit order when the user-specified stop trigger price is attained or
476/// penetrated. The order has two basic components: the stop price and the limit price. When a trade has occurred at or through the stop
477/// price, the order becomes executable and enters the market as a limit order, which is an order to buy or sell at a specified price or better.
478/// Products: CFD, CASH, FUT, FOP, OPT, STK, WAR
479pub fn stop_limit(action: Action, quantity: f64, limit_price: f64, stop_price: f64) -> Order {
480 Order {
481 action,
482 order_type: "STP LMT".to_owned(),
483 total_quantity: quantity,
484 limit_price: Some(limit_price),
485 aux_price: Some(stop_price),
486 ..Order::default()
487 }
488}
489
490/// A Stop with Protection order combines the functionality of a stop limit order with a market with protection order. The order is set
491/// to trigger at a specified stop price. When the stop price is penetrated, the order is triggered as a market with protection order,
492/// which means that it will fill within a specified protected price range equal to the trigger price +/- the exchange-defined protection
493/// point range. Any portion of the order that does not fill within this protected range is submitted as a limit order at the exchange-defined
494/// trigger price +/- the protection points.
495/// Products: FUT
496pub fn stop_with_protection(action: Action, quantity: f64, stop_price: f64) -> Order {
497 Order {
498 action,
499 order_type: "STP PRT".to_owned(),
500 total_quantity: quantity,
501 aux_price: Some(stop_price),
502 ..Order::default()
503 }
504}
505
506/// A sell trailing stop order sets the stop price at a fixed amount below the market price with an attached "trailing" amount. As the
507/// market price rises, the stop price rises by the trail amount, but if the stock price falls, the stop loss price doesn't change,
508/// and a market order is submitted when the stop price is hit. This technique is designed to allow an investor to specify a limit on the
509/// maximum possible loss, without setting a limit on the maximum possible gain. "Buy" trailing stop orders are the mirror image of sell
510/// trailing stop orders, and are most appropriate for use in falling markets.
511/// Products: CFD, CASH, FOP, FUT, OPT, STK, WAR
512pub fn trailing_stop(action: Action, quantity: f64, trailing_percent: f64, trail_stop_price: f64) -> Order {
513 Order {
514 action,
515 order_type: "TRAIL".to_owned(),
516 total_quantity: quantity,
517 trailing_percent: Some(trailing_percent),
518 trail_stop_price: Some(trail_stop_price),
519 ..Order::default()
520 }
521}
522
523/// A trailing stop limit order is designed to allow an investor to specify a limit on the maximum possible loss, without setting a limit
524/// on the maximum possible gain. A SELL trailing stop limit moves with the market price, and continually recalculates the stop trigger
525/// price at a fixed amount below the market price, based on the user-defined "trailing" amount. The limit order price is also continually
526/// recalculated based on the limit offset. As the market price rises, both the stop price and the limit price rise by the trail amount and
527/// limit offset respectively, but if the stock price falls, the stop price remains unchanged, and when the stop price is hit a limit order
528/// is submitted at the last calculated limit price. A "Buy" trailing stop limit order is the mirror image of a sell trailing stop limit,
529/// and is generally used in falling markets.
530/// Products: BOND, CFD, CASH, FUT, FOP, OPT, STK, WAR
531pub fn trailing_stop_limit(action: Action, quantity: f64, lmt_price_offset: f64, trailing_amount: f64, trail_stop_price: f64) -> Order {
532 Order {
533 action,
534 order_type: "TRAIL LIMIT".to_owned(),
535 total_quantity: quantity,
536 trail_stop_price: Some(trail_stop_price),
537 limit_price_offset: Some(lmt_price_offset),
538 aux_price: Some(trailing_amount),
539 ..Order::default()
540 }
541}
542
543/// Create combination orders that include options, stock and futures legs (stock legs can be included if the order is routed
544/// through SmartRouting). Although a combination/spread order is constructed of separate legs, it is executed as a single transaction
545/// if it is routed directly to an exchange. For combination orders that are SmartRouted, each leg may be executed separately to ensure
546/// best execution.
547/// Products: OPT, STK, FUT
548pub fn combo_limit_order(action: Action, quantity: f64, limit_price: f64, non_guaranteed: bool) -> Order {
549 let mut order = Order {
550 action,
551 order_type: "LMT".to_owned(),
552 total_quantity: quantity,
553 limit_price: Some(limit_price),
554 ..Order::default()
555 };
556
557 if non_guaranteed {
558 order = tag_order_non_guaranteed(order)
559 }
560
561 order
562}
563
564fn tag_order_non_guaranteed(mut order: Order) -> Order {
565 order.smart_combo_routing_params = vec![];
566 order.smart_combo_routing_params.push(TagValue {
567 tag: "NonGuaranteed".to_owned(),
568 value: "1".to_owned(),
569 });
570 order
571}
572
573/// Create combination orders that include options, stock and futures legs (stock legs can be included if the order is routed
574/// through SmartRouting). Although a combination/spread order is constructed of separate legs, it is executed as a single transaction
575/// if it is routed directly to an exchange. For combination orders that are SmartRouted, each leg may be executed separately to ensure
576/// best execution.
577/// Products: OPT, STK, FUT
578pub fn combo_market_order(action: Action, quantity: f64, non_guaranteed: bool) -> Order {
579 let mut order = Order {
580 action,
581 order_type: "MKT".to_owned(),
582 total_quantity: quantity,
583 ..Order::default()
584 };
585
586 if non_guaranteed {
587 order = tag_order_non_guaranteed(order)
588 }
589
590 order
591}
592
593/// Create combination orders that include options, stock and futures legs (stock legs can be included if the order is routed
594/// through SmartRouting). Although a combination/spread order is constructed of separate legs, it is executed as a single transaction
595/// if it is routed directly to an exchange. For combination orders that are SmartRouted, each leg may be executed separately to ensure
596/// best execution.
597/// Products: OPT, STK, FUT
598pub fn limit_order_for_combo_with_leg_prices(action: Action, quantity: f64, leg_prices: Vec<f64>, non_guaranteed: bool) -> Order {
599 let mut order = Order {
600 action,
601 order_type: "LMT".to_owned(),
602 total_quantity: quantity,
603 order_combo_legs: vec![],
604 ..Order::default()
605 };
606
607 for price in leg_prices {
608 order.order_combo_legs.push(OrderComboLeg { price: Some(price) });
609 }
610
611 if non_guaranteed {
612 order = tag_order_non_guaranteed(order)
613 }
614
615 order
616}
617
618/// Create combination orders that include options, stock and futures legs (stock legs can be included if the order is routed
619/// through SmartRouting). Although a combination/spread order is constructed of separate legs, it is executed as a single transaction
620/// if it is routed directly to an exchange. For combination orders that are SmartRouted, each leg may be executed separately to ensure
621/// best execution.
622/// Products: OPT, STK, FUT
623pub fn relative_limit_combo(action: Action, quantity: f64, limit_price: f64, non_guaranteed: bool) -> Order {
624 let mut order = Order {
625 action,
626 order_type: "REL + LMT".to_owned(),
627 total_quantity: quantity,
628 limit_price: Some(limit_price),
629 ..Order::default()
630 };
631
632 if non_guaranteed {
633 order = tag_order_non_guaranteed(order)
634 }
635
636 order
637}
638
639/// Create combination orders that include options, stock and futures legs (stock legs can be included if the order is routed
640/// through SmartRouting). Although a combination/spread order is constructed of separate legs, it is executed as a single transaction
641/// if it is routed directly to an exchange. For combination orders that are SmartRouted, each leg may be executed separately to ensure
642/// best execution.
643/// Products: OPT, STK, FUT
644pub fn relative_market_combo(action: Action, quantity: f64, non_guaranteed: bool) -> Order {
645 let mut order = Order {
646 action,
647 order_type: "REL + MKT".to_owned(),
648 total_quantity: quantity,
649 ..Order::default()
650 };
651
652 if non_guaranteed {
653 order = tag_order_non_guaranteed(order)
654 }
655
656 order
657}
658
659/// One-Cancels All (OCA) order type allows an investor to place multiple and possibly unrelated orders assigned to a group. The aim is
660/// to complete just one of the orders, which in turn will cause TWS to cancel the remaining orders. The investor may submit several
661/// orders aimed at taking advantage of the most desirable price within the group. Completion of one piece of the group order causes
662/// cancellation of the remaining group orders while partial completion causes the group to rebalance. An investor might desire to sell
663/// 1000 shares of only ONE of three positions held above prevailing market prices. The OCA order group allows the investor to enter prices
664/// at specified target levels and if one is completed, the other two will automatically cancel. Alternatively, an investor may wish to take
665/// a LONG position in eMini S&P stock index futures in a falling market or else SELL US treasury futures at a more favorable price.
666/// Grouping the two orders using an OCA order type offers the investor two chance to enter a similar position, while only running the risk
667/// of taking on a single position.
668/// Products: BOND, CASH, FUT, FOP, STK, OPT, WAR
669pub fn one_cancels_all(oca_group: &str, mut oca_orders: Vec<Order>, oca_type: i32) -> Vec<Order> {
670 for order in &mut oca_orders {
671 order.oca_group = oca_group.to_owned();
672 order.oca_type = oca_type;
673 }
674
675 oca_orders
676}
677
678/// Specific to US options, investors are able to create and enter Volatility-type orders for options and combinations rather than price orders.
679/// Option traders may wish to trade and position for movements in the price of the option determined by its implied volatility. Because
680/// implied volatility is a key determinant of the premium on an option, traders position in specific contract months in an effort to take
681/// advantage of perceived changes in implied volatility arising before, during or after earnings or when company specific or broad market
682/// volatility is predicted to change. In order to create a Volatility order, clients must first create a Volatility Trader page from the
683/// Trading Tools menu and as they enter option contracts, premiums will display in percentage terms rather than premium. The buy/sell process
684/// is the same as for regular orders priced in premium terms except that the client can limit the volatility level they are willing to pay or
685/// receive.
686/// Products: FOP, OPT
687pub fn volatility(action: Action, quantity: f64, volatility_percent: f64, volatility_type: i32) -> Order {
688 Order {
689 action,
690 order_type: "VOL".to_owned(),
691 total_quantity: quantity,
692 volatility: Some(volatility_percent), //Expressed in percentage (40%)
693 volatility_type: Some(volatility_type), // 1=daily, 2=annual
694 ..Order::default()
695 }
696}
697
698pub fn market_f_hedge(parent_order_id: i32, action: Action) -> Order {
699 //FX Hedge orders can only have a quantity of 0
700 let mut order = market_order(action, 0.0);
701 order.parent_id = parent_order_id;
702 order.hedge_type = "F".to_owned();
703
704 order
705}
706
707#[allow(clippy::too_many_arguments)]
708pub fn pegged_to_benchmark(
709 action: Action,
710 quantity: f64,
711 starting_price: f64,
712 pegged_change_amount_decrease: bool,
713 pegged_change_amount: f64,
714 reference_change_amount: f64,
715 reference_contract_id: i32,
716 reference_exchange: &str,
717 stock_reference_price: f64,
718 reference_contract_lower_range: f64,
719 reference_contract_upper_range: f64,
720) -> Order {
721 Order {
722 action,
723 order_type: "PEG BENCH".to_owned(),
724 total_quantity: quantity,
725 starting_price: Some(starting_price),
726 is_pegged_change_amount_decrease: pegged_change_amount_decrease,
727 pegged_change_amount: Some(pegged_change_amount), // by ... (and likewise for price moving in opposite direction)
728 reference_change_amount: Some(reference_change_amount), // whenever there is a price change of ...
729 reference_contract_id, // in the reference contract ...
730 reference_exchange: reference_exchange.to_owned(), // being traded at ...
731 stock_ref_price: Some(stock_reference_price), // starting reference price is ...
732 //Keep order active as long as reference contract trades between ...
733 stock_range_lower: Some(reference_contract_lower_range),
734 stock_range_upper: Some(reference_contract_upper_range),
735 ..Order::default()
736 }
737}
738
739/// An attached order that turns the parent order (a conventional STP order) into a STP order
740/// in the opposite direction when the trigger is hit.
741pub fn attach_adjustable_to_stop(parent: &Order, attached_order_stop_price: f64, trigger_price: f64, adjusted_stop_price: f64) -> Order {
742 // Attached order is a conventional STP order
743 let mut order = stop(parent.action.reverse(), parent.total_quantity, attached_order_stop_price);
744
745 order.parent_id = parent.order_id;
746 order.trigger_price = Some(trigger_price); // When trigger price is penetrated
747 order.adjusted_order_type = "STP".to_owned(); // The parent order will be turned into a STP order
748 order.adjusted_stop_price = Some(adjusted_stop_price); // With the given STP price
749
750 order
751}
752
753/// An attached order that turns the parent order (a conventional STP order) into a STP LMT order
754/// in the opposite direction when the trigger is hit.
755pub fn attach_adjustable_to_stop_limit(
756 parent: &Order,
757 attached_order_stop_price: f64,
758 trigger_price: f64,
759 adjusted_stop_price: f64,
760 adjusted_stop_limit_price: f64,
761) -> Order {
762 // Attached order is a conventional STP order
763 let mut order = stop(parent.action.reverse(), parent.total_quantity, attached_order_stop_price);
764
765 order.parent_id = parent.order_id;
766 order.trigger_price = Some(trigger_price); // When trigger price is penetrated
767 order.adjusted_order_type = "STP LMT".to_owned(); // The parent order will be turned into a STP LMT order
768 order.adjusted_stop_price = Some(adjusted_stop_price); // With the given STP price
769 order.adjusted_stop_limit_price = Some(adjusted_stop_limit_price); // And the given limit price
770
771 order
772}
773
774/// An attached order that turns the parent order (a conventional STP order) into a
775/// TRAIL order in the opposite direction when the trigger is hit.
776pub fn attach_adjustable_to_trail(
777 parent: &Order,
778 attached_order_stop_price: f64,
779 trigger_price: f64,
780 adjusted_stop_price: f64,
781 adjusted_trail_amount: f64,
782 trail_unit: i32,
783) -> Order {
784 // Attached order is a conventional STP order
785 let mut order = stop(parent.action.reverse(), parent.total_quantity, attached_order_stop_price);
786
787 order.parent_id = parent.order_id;
788 order.trigger_price = Some(trigger_price); // When trigger price is penetrated
789 "TRAIL".clone_into(&mut order.adjusted_order_type); // The parent order will be turned into a TRAIL order
790 order.adjusted_stop_price = Some(adjusted_stop_price); // With a stop price of ...
791 order.adjustable_trailing_unit = trail_unit; // trailing by and amount (0) or a percent (100) ...
792 order.adjusted_trailing_amount = Some(adjusted_trail_amount); // of ...
793
794 order
795}
796
797pub fn what_if_limit_order(action: Action, quantity: f64, limit_price: f64) -> Order {
798 let mut order = limit_order(action, quantity, limit_price);
799 order.what_if = true;
800
801 order
802}
803
804// https://github.com/InteractiveBrokers/tws-api/blob/07e54ceecda2c9cbd6ffb5f524894f0c837a9ecb/source/csharpclient/client/ContractCondition.cs
805// pub fn price_condition(contract_id: i32, exchange: &str, price: f64, is_more: bool, is_conjunction: bool) -> PriceCondition
806// {
807// //! [price_condition]
808// //Conditions have to be created via the OrderCondition.Create
809// PriceCondition priceCondition = (PriceCondition)OrderCondition.Create(OrderConditionType.Price);
810// //When this contract...
811// priceCondition.ConId = conId;
812// //traded on this exchange
813// priceCondition.Exchange = exchange;
814// //has a price above/below
815// priceCondition.IsMore = isMore;
816// //this quantity
817// priceCondition.Price = price;
818// //AND | OR next condition (will be ignored if no more conditions are added)
819// priceCondition.IsConjunctionConnection = isConjunction;
820// //! [price_condition]
821// return priceCondition;
822// }
823
824// public static ExecutionCondition ExecutionCondition(string symbol, string secType, string exchange, bool isConjunction)
825// {
826// //! [execution_condition]
827// ExecutionCondition execCondition = (ExecutionCondition)OrderCondition.Create(OrderConditionType.Execution);
828// //When an execution on symbol
829// execCondition.Symbol = symbol;
830// //at exchange
831// execCondition.Exchange = exchange;
832// //for this secType
833// execCondition.SecType = secType;
834// //AND | OR next condition (will be ignored if no more conditions are added)
835// execCondition.IsConjunctionConnection = isConjunction;
836// //! [execution_condition]
837// return execCondition;
838// }
839
840// public static MarginCondition MarginCondition(int percent, bool isMore, bool isConjunction)
841// {
842// //! [margin_condition]
843// MarginCondition marginCondition = (MarginCondition)OrderCondition.Create(OrderConditionType.Margin);
844// //If margin is above/below
845// marginCondition.IsMore = isMore;
846// //given percent
847// marginCondition.Percent = percent;
848// //AND | OR next condition (will be ignored if no more conditions are added)
849// marginCondition.IsConjunctionConnection = isConjunction;
850// //! [margin_condition]
851// return marginCondition;
852// }
853
854// public static PercentChangeCondition PercentageChangeCondition(double pctChange, int conId, string exchange, bool isMore, bool isConjunction)
855// {
856// //! [percentage_condition]
857// PercentChangeCondition pctChangeCondition = (PercentChangeCondition)OrderCondition.Create(OrderConditionType.PercentCange);
858// //If there is a price percent change measured against last close price above or below...
859// pctChangeCondition.IsMore = isMore;
860// //this amount...
861// pctChangeCondition.ChangePercent = pctChange;
862// //on this contract
863// pctChangeCondition.ConId = conId;
864// //when traded on this exchange...
865// pctChangeCondition.Exchange = exchange;
866// //AND | OR next condition (will be ignored if no more conditions are added)
867// pctChangeCondition.IsConjunctionConnection = isConjunction;
868// //! [percentage_condition]
869// return pctChangeCondition;
870// }
871
872// public static TimeCondition TimeCondition(string time, bool isMore, bool isConjunction)
873// {
874// //! [time_condition]
875// TimeCondition timeCondition = (TimeCondition)OrderCondition.Create(OrderConditionType.Time);
876// //Before or after...
877// timeCondition.IsMore = isMore;
878// //this time..
879// timeCondition.Time = time;
880// //AND | OR next condition (will be ignored if no more conditions are added)
881// timeCondition.IsConjunctionConnection = isConjunction;
882// //! [time_condition]
883// return timeCondition;
884// }
885
886// public static VolumeCondition VolumeCondition(int conId, string exchange, bool isMore, int volume, bool isConjunction)
887// {
888// //! [volume_condition]
889// VolumeCondition volCond = (VolumeCondition)OrderCondition.Create(OrderConditionType.Volume);
890// //Whenever contract...
891// volCond.ConId = conId;
892// //When traded at
893// volCond.Exchange = exchange;
894// //reaches a volume higher/lower
895// volCond.IsMore = isMore;
896// //than this...
897// volCond.Volume = volume;
898// //AND | OR next condition (will be ignored if no more conditions are added)
899// volCond.IsConjunctionConnection = isConjunction;
900// //! [volume_condition]
901// return volCond;
902
903// }
904
905pub fn limit_ibkrats(action: Action, quantity: f64, limit_price: f64) -> Order {
906 Order {
907 action,
908 order_type: "LMT".to_owned(),
909 total_quantity: quantity,
910 limit_price: Some(limit_price),
911 not_held: true,
912 ..Order::default()
913 }
914}
915
916pub fn limit_order_with_manual_order_time(action: Action, quantity: f64, limit_price: f64, manual_order_time: &str) -> Order {
917 let mut order = limit_order(action, quantity, limit_price);
918 manual_order_time.clone_into(&mut order.manual_order_time);
919
920 order
921}
922
923pub fn peg_best_up_to_mid_order(
924 action: Action,
925 quantity: f64,
926 limit_price: f64,
927 min_trade_qty: i32,
928 min_compete_size: i32,
929 mid_offset_at_whole: f64,
930 mid_offset_at_half: f64,
931) -> Order {
932 Order {
933 action,
934 order_type: "PEG BEST".to_owned(),
935 total_quantity: quantity,
936 limit_price: Some(limit_price),
937 not_held: true,
938 min_trade_qty: Some(min_trade_qty),
939 min_compete_size: Some(min_compete_size),
940 compete_against_best_offset: super::COMPETE_AGAINST_BEST_OFFSET_UP_TO_MID,
941 mid_offset_at_whole: Some(mid_offset_at_whole),
942 mid_offset_at_half: Some(mid_offset_at_half),
943 ..Order::default()
944 }
945}
946
947pub fn peg_best_order(
948 action: Action,
949 quantity: f64,
950 limit_price: f64,
951 min_trade_qty: i32,
952 min_compete_size: i32,
953 compete_against_best_offset: f64,
954) -> Order {
955 Order {
956 action,
957 order_type: "PEG BEST".to_owned(),
958 total_quantity: quantity,
959 limit_price: Some(limit_price),
960 not_held: true,
961 min_trade_qty: Some(min_trade_qty),
962 min_compete_size: Some(min_compete_size),
963 compete_against_best_offset: Some(compete_against_best_offset),
964 ..Order::default()
965 }
966}
967
968pub fn peg_mid_order(
969 action: Action,
970 quantity: f64,
971 limit_price: f64,
972 min_trade_qty: i32,
973 mid_offset_at_whole: f64,
974 mid_offset_at_half: f64,
975) -> Order {
976 Order {
977 action,
978 order_type: "PEG MID".to_owned(),
979 total_quantity: quantity,
980 limit_price: Some(limit_price),
981 not_held: true,
982 min_trade_qty: Some(min_trade_qty),
983 mid_offset_at_whole: Some(mid_offset_at_whole),
984 mid_offset_at_half: Some(mid_offset_at_half),
985 ..Order::default()
986 }
987}