Lean  $LEAN_TAG$
QCAlgorithm.Trading.cs
1 /*
2  * QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
3  * Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14 */
15 
16 using System;
17 using System.Linq;
18 using QuantConnect.Orders;
21 using System.Collections.Generic;
23 using static QuantConnect.StringExtensions;
26 
27 namespace QuantConnect.Algorithm
28 {
29  public partial class QCAlgorithm
30  {
31  private int _maxOrders = 10000;
32  private bool _isMarketOnOpenOrderWarningSent;
33  private bool _isMarketOnOpenOrderRestrictedForFuturesWarningSent;
34  private bool _isGtdTfiForMooAndMocOrdersValidationWarningSent;
35  private bool _isOptionsOrderOnStockSplitWarningSent;
36 
37  /// <summary>
38  /// Transaction Manager - Process transaction fills and order management.
39  /// </summary>
40  [DocumentationAttribute(TradingAndOrders)]
42 
43  /// <summary>
44  /// Buy Stock (Alias of Order)
45  /// </summary>
46  /// <param name="symbol">string Symbol of the asset to trade</param>
47  /// <param name="quantity">int Quantity of the asset to trade</param>
48  /// <seealso cref="Buy(Symbol, double)"/>
49  /// <returns>The order ticket instance.</returns>
50  [DocumentationAttribute(TradingAndOrders)]
51  public OrderTicket Buy(Symbol symbol, int quantity)
52  {
53  return Order(symbol, (decimal)Math.Abs(quantity));
54  }
55 
56  /// <summary>
57  /// Buy Stock (Alias of Order)
58  /// </summary>
59  /// <param name="symbol">string Symbol of the asset to trade</param>
60  /// <param name="quantity">double Quantity of the asset to trade</param>
61  /// <seealso cref="Buy(Symbol, decimal)"/>
62  /// <returns>The order ticket instance.</returns>
63  [DocumentationAttribute(TradingAndOrders)]
64  public OrderTicket Buy(Symbol symbol, double quantity)
65  {
66  return Order(symbol, Math.Abs(quantity).SafeDecimalCast());
67  }
68 
69  /// <summary>
70  /// Buy Stock (Alias of Order)
71  /// </summary>
72  /// <param name="symbol">string Symbol of the asset to trade</param>
73  /// <param name="quantity">decimal Quantity of the asset to trade</param>
74  /// <seealso cref="Order(Symbol, int)"/>
75  /// <returns>The order ticket instance.</returns>
76  [DocumentationAttribute(TradingAndOrders)]
77  public OrderTicket Buy(Symbol symbol, decimal quantity)
78  {
79  return Order(symbol, Math.Abs(quantity));
80  }
81 
82  /// <summary>
83  /// Buy Stock (Alias of Order)
84  /// </summary>
85  /// <param name="symbol">string Symbol of the asset to trade</param>
86  /// <param name="quantity">float Quantity of the asset to trade</param>
87  /// <seealso cref="Buy(Symbol, decimal)"/>
88  /// <returns>The order ticket instance.</returns>
89  [DocumentationAttribute(TradingAndOrders)]
90  public OrderTicket Buy(Symbol symbol, float quantity)
91  {
92  return Order(symbol, (decimal)Math.Abs(quantity));
93  }
94 
95 
96  /// <summary>
97  /// Sell stock (alias of Order)
98  /// </summary>
99  /// <param name="symbol">string Symbol of the asset to trade</param>
100  /// <param name="quantity">int Quantity of the asset to trade</param>
101  /// <seealso cref="Sell(Symbol, decimal)"/>
102  /// <returns>The order ticket instance.</returns>
103  [DocumentationAttribute(TradingAndOrders)]
104  public OrderTicket Sell(Symbol symbol, int quantity)
105  {
106  return Order(symbol, (decimal)Math.Abs(quantity) * -1);
107  }
108 
109  /// <summary>
110  /// Sell stock (alias of Order)
111  /// </summary>
112  /// <param name="symbol">String symbol to sell</param>
113  /// <param name="quantity">Quantity to order</param>
114  /// <returns>The order ticket instance.</returns>
115  [DocumentationAttribute(TradingAndOrders)]
116  public OrderTicket Sell(Symbol symbol, double quantity)
117  {
118  return Order(symbol, Math.Abs(quantity).SafeDecimalCast() * -1m);
119  }
120 
121  /// <summary>
122  /// Sell stock (alias of Order)
123  /// </summary>
124  /// <param name="symbol">String symbol</param>
125  /// <param name="quantity">Quantity to sell</param>
126  /// <returns>The order ticket instance.</returns>
127  [DocumentationAttribute(TradingAndOrders)]
128  public OrderTicket Sell(Symbol symbol, float quantity)
129  {
130  return Order(symbol, (decimal)Math.Abs(quantity) * -1m);
131  }
132 
133  /// <summary>
134  /// Sell stock (alias of Order)
135  /// </summary>
136  /// <param name="symbol">String symbol to sell</param>
137  /// <param name="quantity">Quantity to sell</param>
138  /// <returns>The order ticket instance.</returns>
139  [DocumentationAttribute(TradingAndOrders)]
140  public OrderTicket Sell(Symbol symbol, decimal quantity)
141  {
142  return Order(symbol, Math.Abs(quantity) * -1);
143  }
144 
145  /// <summary>
146  /// Issue an order/trade for asset: Alias wrapper for Order(string, int);
147  /// </summary>
148  /// <param name="symbol">Symbol to order</param>
149  /// <param name="quantity">Quantity to order</param>
150  /// <seealso cref="Order(Symbol, decimal)"/>
151  /// <returns>The order ticket instance.</returns>
152  [DocumentationAttribute(TradingAndOrders)]
153  public OrderTicket Order(Symbol symbol, double quantity)
154  {
155  return Order(symbol, quantity.SafeDecimalCast());
156  }
157 
158  /// <summary>
159  /// Issue an order/trade for asset
160  /// </summary>
161  /// <param name="symbol">Symbol to order</param>
162  /// <param name="quantity">Quantity to order</param>
163  /// <returns>The order ticket instance.</returns>
164  [DocumentationAttribute(TradingAndOrders)]
165  public OrderTicket Order(Symbol symbol, int quantity)
166  {
167  return MarketOrder(symbol, (decimal)quantity);
168  }
169 
170  /// <summary>
171  /// Issue an order/trade for asset
172  /// </summary>
173  /// <param name="symbol">Symbol to order</param>
174  /// <param name="quantity">Quantity to order</param>
175  /// <returns>The order ticket instance.</returns>
176  [DocumentationAttribute(TradingAndOrders)]
177  public OrderTicket Order(Symbol symbol, decimal quantity)
178  {
179  return MarketOrder(symbol, quantity);
180  }
181 
182  /// <summary>
183  /// Wrapper for market order method: submit a new order for quantity of symbol using type order.
184  /// </summary>
185  /// <param name="symbol">Symbol of the MarketType Required.</param>
186  /// <param name="quantity">Number of shares to request.</param>
187  /// <param name="asynchronous">Send the order asynchronously (false). Otherwise we'll block until it fills</param>
188  /// <param name="tag">Place a custom order property or tag (e.g. indicator data).</param>
189  /// <param name="orderProperties">The order properties to use. Defaults to <see cref="DefaultOrderProperties"/></param>
190  /// <returns>The order ticket instance.</returns>
191  /// <seealso cref="MarketOrder(Symbol, decimal, bool, string)"/>
192  [DocumentationAttribute(TradingAndOrders)]
193  public OrderTicket Order(Symbol symbol, decimal quantity, bool asynchronous = false, string tag = "", IOrderProperties orderProperties = null)
194  {
195  return MarketOrder(symbol, quantity, asynchronous, tag, orderProperties);
196  }
197 
198  /// <summary>
199  /// Market order implementation: Send a market order and wait for it to be filled.
200  /// </summary>
201  /// <param name="symbol">Symbol of the MarketType Required.</param>
202  /// <param name="quantity">Number of shares to request.</param>
203  /// <param name="asynchronous">Send the order asynchronously (false). Otherwise we'll block until it fills</param>
204  /// <param name="tag">Place a custom order property or tag (e.g. indicator data).</param>
205  /// <param name="orderProperties">The order properties to use. Defaults to <see cref="DefaultOrderProperties"/></param>
206  /// <returns>The order ticket instance.</returns>
207  [DocumentationAttribute(TradingAndOrders)]
208  public OrderTicket MarketOrder(Symbol symbol, int quantity, bool asynchronous = false, string tag = "", IOrderProperties orderProperties = null)
209  {
210  return MarketOrder(symbol, (decimal)quantity, asynchronous, tag, orderProperties);
211  }
212 
213  /// <summary>
214  /// Market order implementation: Send a market order and wait for it to be filled.
215  /// </summary>
216  /// <param name="symbol">Symbol of the MarketType Required.</param>
217  /// <param name="quantity">Number of shares to request.</param>
218  /// <param name="asynchronous">Send the order asynchronously (false). Otherwise we'll block until it fills</param>
219  /// <param name="tag">Place a custom order property or tag (e.g. indicator data).</param>
220  /// <param name="orderProperties">The order properties to use. Defaults to <see cref="DefaultOrderProperties"/></param>
221  /// <returns>The order ticket instance.</returns>
222  [DocumentationAttribute(TradingAndOrders)]
223  public OrderTicket MarketOrder(Symbol symbol, double quantity, bool asynchronous = false, string tag = "", IOrderProperties orderProperties = null)
224  {
225  return MarketOrder(symbol, quantity.SafeDecimalCast(), asynchronous, tag, orderProperties);
226  }
227 
228  /// <summary>
229  /// Market order implementation: Send a market order and wait for it to be filled.
230  /// </summary>
231  /// <param name="symbol">Symbol of the MarketType Required.</param>
232  /// <param name="quantity">Number of shares to request.</param>
233  /// <param name="asynchronous">Send the order asynchronously (false). Otherwise we'll block until it fills</param>
234  /// <param name="tag">Place a custom order property or tag (e.g. indicator data).</param>
235  /// <param name="orderProperties">The order properties to use. Defaults to <see cref="DefaultOrderProperties"/></param>
236  /// <returns>The order ticket instance.</returns>
237  [DocumentationAttribute(TradingAndOrders)]
238  public OrderTicket MarketOrder(Symbol symbol, decimal quantity, bool asynchronous = false, string tag = "", IOrderProperties orderProperties = null)
239  {
240  var security = Securities[symbol];
241  return MarketOrder(security, quantity, asynchronous, tag, orderProperties);
242  }
243 
244  /// <summary>
245  /// Market order implementation: Send a market order and wait for it to be filled.
246  /// </summary>
247  /// <param name="security">Symbol of the MarketType Required.</param>
248  /// <param name="quantity">Number of shares to request.</param>
249  /// <param name="asynchronous">Send the order asynchronously (false). Otherwise we'll block until it fills</param>
250  /// <param name="tag">Place a custom order property or tag (e.g. indicator data).</param>
251  /// <param name="orderProperties">The order properties to use. Defaults to <see cref="DefaultOrderProperties"/></param>
252  /// <returns>The order ticket instance.</returns>
253  [DocumentationAttribute(TradingAndOrders)]
254  public OrderTicket MarketOrder(Security security, decimal quantity, bool asynchronous = false, string tag = "", IOrderProperties orderProperties = null)
255  {
256  // check the exchange is open before sending a market order, if it's not open then convert it into a market on open order.
257  // For futures and FOPs, market orders can be submitted on extended hours, so we let them through.
258  if ((security.Type != SecurityType.Future && security.Type != SecurityType.FutureOption) && !security.Exchange.ExchangeOpen)
259  {
260  var mooTicket = MarketOnOpenOrder(security.Symbol, quantity, tag);
261  if (!_isMarketOnOpenOrderWarningSent)
262  {
263  var anyNonDailySubscriptions = security.Subscriptions.Any(x => x.Resolution != Resolution.Daily);
264  if (mooTicket.SubmitRequest.Response.IsSuccess && !anyNonDailySubscriptions)
265  {
266  Debug("Warning: all market orders sent using daily data, or market orders sent after hours are automatically converted into MarketOnOpen orders.");
267  _isMarketOnOpenOrderWarningSent = true;
268  }
269  }
270  return mooTicket;
271  }
272 
273  var request = CreateSubmitOrderRequest(OrderType.Market, security, quantity, tag, orderProperties ?? DefaultOrderProperties?.Clone());
274 
275  //Add the order and create a new order Id.
276  var ticket = SubmitOrderRequest(request);
277 
278  // Wait for the order event to process, only if the exchange is open and the order is valid
279  if (ticket.Status != OrderStatus.Invalid && !asynchronous)
280  {
281  Transactions.WaitForOrder(ticket.OrderId);
282  }
283 
284  return ticket;
285  }
286 
287  /// <summary>
288  /// Market on open order implementation: Send a market order when the exchange opens
289  /// </summary>
290  /// <param name="symbol">The symbol to be ordered</param>
291  /// <param name="quantity">The number of shares to required</param>
292  /// <param name="tag">Place a custom order property or tag (e.g. indicator data).</param>
293  /// <param name="orderProperties">The order properties to use. Defaults to <see cref="DefaultOrderProperties"/></param>
294  /// <returns>The order ticket instance.</returns>
295  [DocumentationAttribute(TradingAndOrders)]
296  public OrderTicket MarketOnOpenOrder(Symbol symbol, double quantity, string tag = "", IOrderProperties orderProperties = null)
297  {
298  return MarketOnOpenOrder(symbol, quantity.SafeDecimalCast(), tag, orderProperties);
299  }
300 
301  /// <summary>
302  /// Market on open order implementation: Send a market order when the exchange opens
303  /// </summary>
304  /// <param name="symbol">The symbol to be ordered</param>
305  /// <param name="quantity">The number of shares to required</param>
306  /// <param name="tag">Place a custom order property or tag (e.g. indicator data).</param>
307  /// <param name="orderProperties">The order properties to use. Defaults to <see cref="DefaultOrderProperties"/></param>
308  /// <returns>The order ticket instance.</returns>
309  [DocumentationAttribute(TradingAndOrders)]
310  public OrderTicket MarketOnOpenOrder(Symbol symbol, int quantity, string tag = "", IOrderProperties orderProperties = null)
311  {
312  return MarketOnOpenOrder(symbol, (decimal)quantity, tag, orderProperties);
313  }
314 
315  /// <summary>
316  /// Market on open order implementation: Send a market order when the exchange opens
317  /// </summary>
318  /// <param name="symbol">The symbol to be ordered</param>
319  /// <param name="quantity">The number of shares to required</param>
320  /// <param name="tag">Place a custom order property or tag (e.g. indicator data).</param>
321  /// <param name="orderProperties">The order properties to use. Defaults to <see cref="DefaultOrderProperties"/></param>
322  /// <returns>The order ticket instance.</returns>
323  [DocumentationAttribute(TradingAndOrders)]
324  public OrderTicket MarketOnOpenOrder(Symbol symbol, decimal quantity, string tag = "", IOrderProperties orderProperties = null)
325  {
326  var properties = orderProperties ?? DefaultOrderProperties?.Clone();
327  InvalidateGoodTilDateTimeInForce(properties);
328 
329  var security = Securities[symbol];
330  var request = CreateSubmitOrderRequest(OrderType.MarketOnOpen, security, quantity, tag, properties);
331 
332  return SubmitOrderRequest(request);
333  }
334 
335  /// <summary>
336  /// Market on close order implementation: Send a market order when the exchange closes
337  /// </summary>
338  /// <param name="symbol">The symbol to be ordered</param>
339  /// <param name="quantity">The number of shares to required</param>
340  /// <param name="tag">Place a custom order property or tag (e.g. indicator data).</param>
341  /// <param name="orderProperties">The order properties to use. Defaults to <see cref="DefaultOrderProperties"/></param>
342  /// <returns>The order ticket instance.</returns>
343  [DocumentationAttribute(TradingAndOrders)]
344  public OrderTicket MarketOnCloseOrder(Symbol symbol, int quantity, string tag = "", IOrderProperties orderProperties = null)
345  {
346  return MarketOnCloseOrder(symbol, (decimal)quantity, tag, orderProperties);
347  }
348 
349  /// <summary>
350  /// Market on close order implementation: Send a market order when the exchange closes
351  /// </summary>
352  /// <param name="symbol">The symbol to be ordered</param>
353  /// <param name="quantity">The number of shares to required</param>
354  /// <param name="tag">Place a custom order property or tag (e.g. indicator data).</param>
355  /// <param name="orderProperties">The order properties to use. Defaults to <see cref="DefaultOrderProperties"/></param>
356  /// <returns>The order ticket instance.</returns>
357  [DocumentationAttribute(TradingAndOrders)]
358  public OrderTicket MarketOnCloseOrder(Symbol symbol, double quantity, string tag = "", IOrderProperties orderProperties = null)
359  {
360  return MarketOnCloseOrder(symbol, quantity.SafeDecimalCast(), tag, orderProperties);
361  }
362 
363  /// <summary>
364  /// Market on close order implementation: Send a market order when the exchange closes
365  /// </summary>
366  /// <param name="symbol">The symbol to be ordered</param>
367  /// <param name="quantity">The number of shares to required</param>
368  /// <param name="tag">Place a custom order property or tag (e.g. indicator data).</param>
369  /// <param name="orderProperties">The order properties to use. Defaults to <see cref="DefaultOrderProperties"/></param>
370  /// <returns>The order ticket instance.</returns>
371  [DocumentationAttribute(TradingAndOrders)]
372  public OrderTicket MarketOnCloseOrder(Symbol symbol, decimal quantity, string tag = "", IOrderProperties orderProperties = null)
373  {
374  var properties = orderProperties ?? DefaultOrderProperties?.Clone();
375  InvalidateGoodTilDateTimeInForce(properties);
376 
377  var security = Securities[symbol];
378  var request = CreateSubmitOrderRequest(OrderType.MarketOnClose, security, quantity, tag, properties);
379 
380  return SubmitOrderRequest(request);
381  }
382 
383  /// <summary>
384  /// Send a limit order to the transaction handler:
385  /// </summary>
386  /// <param name="symbol">String symbol for the asset</param>
387  /// <param name="quantity">Quantity of shares for limit order</param>
388  /// <param name="limitPrice">Limit price to fill this order</param>
389  /// <param name="tag">String tag for the order (optional)</param>
390  /// <param name="orderProperties">The order properties to use. Defaults to <see cref="DefaultOrderProperties"/></param>
391  /// <returns>The order ticket instance.</returns>
392  [DocumentationAttribute(TradingAndOrders)]
393  public OrderTicket LimitOrder(Symbol symbol, int quantity, decimal limitPrice, string tag = "", IOrderProperties orderProperties = null)
394  {
395  return LimitOrder(symbol, (decimal)quantity, limitPrice, tag, orderProperties);
396  }
397 
398  /// <summary>
399  /// Send a limit order to the transaction handler:
400  /// </summary>
401  /// <param name="symbol">String symbol for the asset</param>
402  /// <param name="quantity">Quantity of shares for limit order</param>
403  /// <param name="limitPrice">Limit price to fill this order</param>
404  /// <param name="tag">String tag for the order (optional)</param>
405  /// <param name="orderProperties">The order properties to use. Defaults to <see cref="DefaultOrderProperties"/></param>
406  /// <returns>The order ticket instance.</returns>
407  [DocumentationAttribute(TradingAndOrders)]
408  public OrderTicket LimitOrder(Symbol symbol, double quantity, decimal limitPrice, string tag = "", IOrderProperties orderProperties = null)
409  {
410  return LimitOrder(symbol, quantity.SafeDecimalCast(), limitPrice, tag, orderProperties);
411  }
412 
413  /// <summary>
414  /// Send a limit order to the transaction handler:
415  /// </summary>
416  /// <param name="symbol">String symbol for the asset</param>
417  /// <param name="quantity">Quantity of shares for limit order</param>
418  /// <param name="limitPrice">Limit price to fill this order</param>
419  /// <param name="tag">String tag for the order (optional)</param>
420  /// <param name="orderProperties">The order properties to use. Defaults to <see cref="DefaultOrderProperties"/></param>
421  /// <returns>The order ticket instance.</returns>
422  [DocumentationAttribute(TradingAndOrders)]
423  public OrderTicket LimitOrder(Symbol symbol, decimal quantity, decimal limitPrice, string tag = "", IOrderProperties orderProperties = null)
424  {
425  var security = Securities[symbol];
426  var request = CreateSubmitOrderRequest(OrderType.Limit, security, quantity, tag, limitPrice: limitPrice, properties: orderProperties ?? DefaultOrderProperties?.Clone());
427 
428  return SubmitOrderRequest(request);
429  }
430 
431  /// <summary>
432  /// Create a stop market order and return the newly created order id; or negative if the order is invalid
433  /// </summary>
434  /// <param name="symbol">String symbol for the asset we're trading</param>
435  /// <param name="quantity">Quantity to be traded</param>
436  /// <param name="stopPrice">Price to fill the stop order</param>
437  /// <param name="tag">Optional string data tag for the order</param>
438  /// <param name="orderProperties">The order properties to use. Defaults to <see cref="DefaultOrderProperties"/></param>
439  /// <returns>The order ticket instance.</returns>
440  [DocumentationAttribute(TradingAndOrders)]
441  public OrderTicket StopMarketOrder(Symbol symbol, int quantity, decimal stopPrice, string tag = "", IOrderProperties orderProperties = null)
442  {
443  return StopMarketOrder(symbol, (decimal)quantity, stopPrice, tag, orderProperties);
444  }
445 
446  /// <summary>
447  /// Create a stop market order and return the newly created order id; or negative if the order is invalid
448  /// </summary>
449  /// <param name="symbol">String symbol for the asset we're trading</param>
450  /// <param name="quantity">Quantity to be traded</param>
451  /// <param name="stopPrice">Price to fill the stop order</param>
452  /// <param name="tag">Optional string data tag for the order</param>
453  /// <param name="orderProperties">The order properties to use. Defaults to <see cref="DefaultOrderProperties"/></param>
454  /// <returns>The order ticket instance.</returns>
455  [DocumentationAttribute(TradingAndOrders)]
456  public OrderTicket StopMarketOrder(Symbol symbol, double quantity, decimal stopPrice, string tag = "", IOrderProperties orderProperties = null)
457  {
458  return StopMarketOrder(symbol, quantity.SafeDecimalCast(), stopPrice, tag, orderProperties);
459  }
460 
461  /// <summary>
462  /// Create a stop market order and return the newly created order id; or negative if the order is invalid
463  /// </summary>
464  /// <param name="symbol">String symbol for the asset we're trading</param>
465  /// <param name="quantity">Quantity to be traded</param>
466  /// <param name="stopPrice">Price to fill the stop order</param>
467  /// <param name="tag">Optional string data tag for the order</param>
468  /// <param name="orderProperties">The order properties to use. Defaults to <see cref="DefaultOrderProperties"/></param>
469  /// <returns>The order ticket instance.</returns>
470  [DocumentationAttribute(TradingAndOrders)]
471  public OrderTicket StopMarketOrder(Symbol symbol, decimal quantity, decimal stopPrice, string tag = "", IOrderProperties orderProperties = null)
472  {
473  var security = Securities[symbol];
474  var request = CreateSubmitOrderRequest(OrderType.StopMarket, security, quantity, tag, stopPrice: stopPrice, properties: orderProperties ?? DefaultOrderProperties?.Clone());
475 
476  return SubmitOrderRequest(request);
477  }
478 
479  /// <summary>
480  /// Create a trailing stop order and return the newly created order id; or negative if the order is invalid.
481  /// It will calculate the stop price using the trailing amount and the current market price.
482  /// </summary>
483  /// <param name="symbol">Trading asset symbol</param>
484  /// <param name="quantity">Quantity to be traded</param>
485  /// <param name="trailingAmount">The trailing amount to be used to update the stop price</param>
486  /// <param name="trailingAsPercentage">Whether the <paramref name="trailingAmount"/> is a percentage or an absolute currency value</param>
487  /// <param name="tag">Optional string data tag for the order</param>
488  /// <param name="orderProperties">The order properties to use. Defaults to <see cref="DefaultOrderProperties"/></param>
489  /// <returns>The order ticket instance.</returns>
490  [DocumentationAttribute(TradingAndOrders)]
491  public OrderTicket TrailingStopOrder(Symbol symbol, int quantity, decimal trailingAmount, bool trailingAsPercentage,
492  string tag = "", IOrderProperties orderProperties = null)
493  {
494  return TrailingStopOrder(symbol, (decimal)quantity, trailingAmount, trailingAsPercentage, tag, orderProperties);
495  }
496 
497  /// <summary>
498  /// Create a trailing stop order and return the newly created order id; or negative if the order is invalid.
499  /// It will calculate the stop price using the trailing amount and the current market price.
500  /// </summary>
501  /// <param name="symbol">Trading asset symbol</param>
502  /// <param name="quantity">Quantity to be traded</param>
503  /// <param name="trailingAmount">The trailing amount to be used to update the stop price</param>
504  /// <param name="trailingAsPercentage">Whether the <paramref name="trailingAmount"/> is a percentage or an absolute currency value</param>
505  /// <param name="tag">Optional string data tag for the order</param>
506  /// <param name="orderProperties">The order properties to use. Defaults to <see cref="DefaultOrderProperties"/></param>
507  /// <returns>The order ticket instance.</returns>
508  [DocumentationAttribute(TradingAndOrders)]
509  public OrderTicket TrailingStopOrder(Symbol symbol, double quantity, decimal trailingAmount, bool trailingAsPercentage,
510  string tag = "", IOrderProperties orderProperties = null)
511  {
512  return TrailingStopOrder(symbol, quantity.SafeDecimalCast(), trailingAmount, trailingAsPercentage, tag, orderProperties);
513  }
514 
515  /// <summary>
516  /// Create a trailing stop order and return the newly created order id; or negative if the order is invalid.
517  /// It will calculate the stop price using the trailing amount and the current market price.
518  /// </summary>
519  /// <param name="symbol">Trading asset symbol</param>
520  /// <param name="quantity">Quantity to be traded</param>
521  /// <param name="trailingAmount">The trailing amount to be used to update the stop price</param>
522  /// <param name="trailingAsPercentage">Whether the <paramref name="trailingAmount"/> is a percentage or an absolute currency value</param>
523  /// <param name="tag">Optional string data tag for the order</param>
524  /// <param name="orderProperties">The order properties to use. Defaults to <see cref="DefaultOrderProperties"/></param>
525  /// <returns>The order ticket instance.</returns>
526  [DocumentationAttribute(TradingAndOrders)]
527  public OrderTicket TrailingStopOrder(Symbol symbol, decimal quantity, decimal trailingAmount, bool trailingAsPercentage,
528  string tag = "", IOrderProperties orderProperties = null)
529  {
530  var security = Securities[symbol];
531  var stopPrice = Orders.TrailingStopOrder.CalculateStopPrice(security.Price, trailingAmount, trailingAsPercentage,
532  quantity > 0 ? OrderDirection.Buy : OrderDirection.Sell);
533  return TrailingStopOrder(symbol, quantity, stopPrice, trailingAmount, trailingAsPercentage, tag, orderProperties);
534  }
535 
536  /// <summary>
537  /// Create a trailing stop order and return the newly created order id; or negative if the order is invalid
538  /// </summary>
539  /// <param name="symbol">Trading asset symbol</param>
540  /// <param name="quantity">Quantity to be traded</param>
541  /// <param name="stopPrice">Initial stop price at which the order should be triggered</param>
542  /// <param name="trailingAmount">The trailing amount to be used to update the stop price</param>
543  /// <param name="trailingAsPercentage">Whether the <paramref name="trailingAmount"/> is a percentage or an absolute currency value</param>
544  /// <param name="tag">Optional string data tag for the order</param>
545  /// <param name="orderProperties">The order properties to use. Defaults to <see cref="DefaultOrderProperties"/></param>
546  /// <returns>The order ticket instance.</returns>
547  [DocumentationAttribute(TradingAndOrders)]
548  public OrderTicket TrailingStopOrder(Symbol symbol, int quantity, decimal stopPrice, decimal trailingAmount, bool trailingAsPercentage,
549  string tag = "", IOrderProperties orderProperties = null)
550  {
551  return TrailingStopOrder(symbol, (decimal)quantity, stopPrice, trailingAmount, trailingAsPercentage, tag, orderProperties);
552  }
553 
554  /// <summary>
555  /// Create a trailing stop order and return the newly created order id; or negative if the order is invalid
556  /// </summary>
557  /// <param name="symbol">Trading asset symbol</param>
558  /// <param name="quantity">Quantity to be traded</param>
559  /// <param name="stopPrice">Initial stop price at which the order should be triggered</param>
560  /// <param name="trailingAmount">The trailing amount to be used to update the stop price</param>
561  /// <param name="trailingAsPercentage">Whether the <paramref name="trailingAmount"/> is a percentage or an absolute currency value</param>
562  /// <param name="tag">Optional string data tag for the order</param>
563  /// <param name="orderProperties">The order properties to use. Defaults to <see cref="DefaultOrderProperties"/></param>
564  /// <returns>The order ticket instance.</returns>
565  [DocumentationAttribute(TradingAndOrders)]
566  public OrderTicket TrailingStopOrder(Symbol symbol, double quantity, decimal stopPrice, decimal trailingAmount, bool trailingAsPercentage,
567  string tag = "", IOrderProperties orderProperties = null)
568  {
569  return TrailingStopOrder(symbol, quantity.SafeDecimalCast(), stopPrice, trailingAmount, trailingAsPercentage, tag, orderProperties);
570  }
571 
572  /// <summary>
573  /// Create a trailing stop order and return the newly created order id; or negative if the order is invalid
574  /// </summary>
575  /// <param name="symbol">Trading asset symbol</param>
576  /// <param name="quantity">Quantity to be traded</param>
577  /// <param name="stopPrice">Initial stop price at which the order should be triggered</param>
578  /// <param name="trailingAmount">The trailing amount to be used to update the stop price</param>
579  /// <param name="trailingAsPercentage">Whether the <paramref name="trailingAmount"/> is a percentage or an absolute currency value</param>
580  /// <param name="tag">Optional string data tag for the order</param>
581  /// <param name="orderProperties">The order properties to use. Defaults to <see cref="DefaultOrderProperties"/></param>
582  /// <returns>The order ticket instance.</returns>
583  [DocumentationAttribute(TradingAndOrders)]
584  public OrderTicket TrailingStopOrder(Symbol symbol, decimal quantity, decimal stopPrice, decimal trailingAmount, bool trailingAsPercentage,
585  string tag = "", IOrderProperties orderProperties = null)
586  {
587  var security = Securities[symbol];
588  var request = CreateSubmitOrderRequest(
589  OrderType.TrailingStop,
590  security,
591  quantity,
592  tag,
593  stopPrice: stopPrice,
594  trailingAmount: trailingAmount,
595  trailingAsPercentage: trailingAsPercentage,
596  properties: orderProperties ?? DefaultOrderProperties?.Clone());
597 
598  return SubmitOrderRequest(request);
599  }
600 
601  /// <summary>
602  /// Send a stop limit order to the transaction handler:
603  /// </summary>
604  /// <param name="symbol">String symbol for the asset</param>
605  /// <param name="quantity">Quantity of shares for limit order</param>
606  /// <param name="stopPrice">Stop price for this order</param>
607  /// <param name="limitPrice">Limit price to fill this order</param>
608  /// <param name="tag">String tag for the order (optional)</param>
609  /// <param name="orderProperties">The order properties to use. Defaults to <see cref="DefaultOrderProperties"/></param>
610  /// <returns>The order ticket instance.</returns>
611  [DocumentationAttribute(TradingAndOrders)]
612  public OrderTicket StopLimitOrder(Symbol symbol, int quantity, decimal stopPrice, decimal limitPrice, string tag = "", IOrderProperties orderProperties = null)
613  {
614  return StopLimitOrder(symbol, (decimal)quantity, stopPrice, limitPrice, tag, orderProperties);
615  }
616 
617  /// <summary>
618  /// Send a stop limit order to the transaction handler:
619  /// </summary>
620  /// <param name="symbol">String symbol for the asset</param>
621  /// <param name="quantity">Quantity of shares for limit order</param>
622  /// <param name="stopPrice">Stop price for this order</param>
623  /// <param name="limitPrice">Limit price to fill this order</param>
624  /// <param name="tag">String tag for the order (optional)</param>
625  /// <param name="orderProperties">The order properties to use. Defaults to <see cref="DefaultOrderProperties"/></param>
626  /// <returns>The order ticket instance.</returns>
627  [DocumentationAttribute(TradingAndOrders)]
628  public OrderTicket StopLimitOrder(Symbol symbol, double quantity, decimal stopPrice, decimal limitPrice, string tag = "", IOrderProperties orderProperties = null)
629  {
630  return StopLimitOrder(symbol, quantity.SafeDecimalCast(), stopPrice, limitPrice, tag, orderProperties);
631  }
632 
633  /// <summary>
634  /// Send a stop limit order to the transaction handler:
635  /// </summary>
636  /// <param name="symbol">String symbol for the asset</param>
637  /// <param name="quantity">Quantity of shares for limit order</param>
638  /// <param name="stopPrice">Stop price for this order</param>
639  /// <param name="limitPrice">Limit price to fill this order</param>
640  /// <param name="tag">String tag for the order (optional)</param>
641  /// <param name="orderProperties">The order properties to use. Defaults to <see cref="DefaultOrderProperties"/></param>
642  /// <returns>The order ticket instance.</returns>
643  [DocumentationAttribute(TradingAndOrders)]
644  public OrderTicket StopLimitOrder(Symbol symbol, decimal quantity, decimal stopPrice, decimal limitPrice, string tag = "", IOrderProperties orderProperties = null)
645  {
646  var security = Securities[symbol];
647  var request = CreateSubmitOrderRequest(OrderType.StopLimit, security, quantity, tag, stopPrice: stopPrice, limitPrice: limitPrice, properties: orderProperties ?? DefaultOrderProperties?.Clone());
648 
649  return SubmitOrderRequest(request);
650  }
651 
652  /// <summary>
653  /// Send a limit if touched order to the transaction handler:
654  /// </summary>
655  /// <param name="symbol">String symbol for the asset</param>
656  /// <param name="quantity">Quantity of shares for limit order</param>
657  /// <param name="triggerPrice">Trigger price for this order</param>
658  /// <param name="limitPrice">Limit price to fill this order</param>
659  /// <param name="tag">String tag for the order (optional)</param>
660  /// <param name="orderProperties">The order properties to use. Defaults to <see cref="DefaultOrderProperties"/></param>
661  /// <returns>The order ticket instance.</returns>
662  [DocumentationAttribute(TradingAndOrders)]
663  public OrderTicket LimitIfTouchedOrder(Symbol symbol, int quantity, decimal triggerPrice, decimal limitPrice, string tag = "", IOrderProperties orderProperties = null)
664  {
665  return LimitIfTouchedOrder(symbol, (decimal)quantity, triggerPrice, limitPrice, tag, orderProperties);
666  }
667 
668  /// <summary>
669  /// Send a limit if touched order to the transaction handler:
670  /// </summary>
671  /// <param name="symbol">String symbol for the asset</param>
672  /// <param name="quantity">Quantity of shares for limit order</param>
673  /// <param name="triggerPrice">Trigger price for this order</param>
674  /// <param name="limitPrice">Limit price to fill this order</param>
675  /// <param name="tag">String tag for the order (optional)</param>
676  /// <param name="orderProperties">The order properties to use. Defaults to <see cref="DefaultOrderProperties"/></param>
677  /// <returns>The order ticket instance.</returns>
678  [DocumentationAttribute(TradingAndOrders)]
679  public OrderTicket LimitIfTouchedOrder(Symbol symbol, double quantity, decimal triggerPrice, decimal limitPrice, string tag = "", IOrderProperties orderProperties = null)
680  {
681  return LimitIfTouchedOrder(symbol, quantity.SafeDecimalCast(), triggerPrice, limitPrice, tag, orderProperties);
682  }
683 
684  /// <summary>
685  /// Send a limit if touched order to the transaction handler:
686  /// </summary>
687  /// <param name="symbol">String symbol for the asset</param>
688  /// <param name="quantity">Quantity of shares for limit order</param>
689  /// <param name="triggerPrice">Trigger price for this order</param>
690  /// <param name="limitPrice">Limit price to fill this order</param>
691  /// <param name="tag">String tag for the order (optional)</param>
692  /// <param name="orderProperties">The order properties to use. Defaults to <see cref="DefaultOrderProperties"/></param>
693  /// <returns>The order ticket instance.</returns>
694  [DocumentationAttribute(TradingAndOrders)]
695  public OrderTicket LimitIfTouchedOrder(Symbol symbol, decimal quantity, decimal triggerPrice, decimal limitPrice, string tag = "", IOrderProperties orderProperties = null)
696  {
697  var security = Securities[symbol];
698  var request = CreateSubmitOrderRequest(OrderType.LimitIfTouched, security, quantity, tag, triggerPrice: triggerPrice, limitPrice: limitPrice, properties: orderProperties ?? DefaultOrderProperties?.Clone());
699 
700  return SubmitOrderRequest(request);
701  }
702 
703  /// <summary>
704  /// Send an exercise order to the transaction handler
705  /// </summary>
706  /// <param name="optionSymbol">String symbol for the option position</param>
707  /// <param name="quantity">Quantity of options contracts</param>
708  /// <param name="asynchronous">Send the order asynchronously (false). Otherwise we'll block until it fills</param>
709  /// <param name="tag">String tag for the order (optional)</param>
710  /// <param name="orderProperties">The order properties to use. Defaults to <see cref="DefaultOrderProperties"/></param>
711  /// <returns>The order ticket instance.</returns>
712  [DocumentationAttribute(TradingAndOrders)]
713  public OrderTicket ExerciseOption(Symbol optionSymbol, int quantity, bool asynchronous = false, string tag = "", IOrderProperties orderProperties = null)
714  {
715  var option = (Option) Securities[optionSymbol];
716 
717  // SubmitOrderRequest.Quantity indicates the change in holdings quantity, therefore manual exercise quantities must be negative
718  // PreOrderChecksImpl confirms that we don't hold a short position, so we're lenient here and accept +/- quantity values
719  var request = CreateSubmitOrderRequest(OrderType.OptionExercise, option, -Math.Abs(quantity), tag, orderProperties ?? DefaultOrderProperties?.Clone());
720 
721  //Initialize the exercise order parameters
722  var preOrderCheckResponse = PreOrderChecks(request);
723  if (preOrderCheckResponse.IsError)
724  {
725  return OrderTicket.InvalidSubmitRequest(Transactions, request, preOrderCheckResponse);
726  }
727 
728  //Add the order and create a new order Id.
729  var ticket = Transactions.AddOrder(request);
730 
731  // Wait for the order event to process, only if the exchange is open
732  if (!asynchronous)
733  {
734  Transactions.WaitForOrder(ticket.OrderId);
735  }
736 
737  return ticket;
738  }
739 
740  // Support for option strategies trading
741 
742  /// <summary>
743  /// Buy Option Strategy (Alias of Order)
744  /// </summary>
745  /// <param name="strategy">Specification of the strategy to trade</param>
746  /// <param name="quantity">Quantity of the strategy to trade</param>
747  /// <param name="asynchronous">Send the order asynchronously (false). Otherwise we'll block until it fills</param>
748  /// <param name="tag">String tag for the order (optional)</param>
749  /// <param name="orderProperties">The order properties to use. Defaults to <see cref="DefaultOrderProperties"/></param>
750  /// <returns>Sequence of order tickets</returns>
751  [DocumentationAttribute(TradingAndOrders)]
752  public IEnumerable<OrderTicket> Buy(OptionStrategy strategy, int quantity, bool asynchronous = false, string tag = "", IOrderProperties orderProperties = null)
753  {
754  return Order(strategy, Math.Abs(quantity), asynchronous, tag, orderProperties);
755  }
756 
757  /// <summary>
758  /// Sell Option Strategy (alias of Order)
759  /// </summary>
760  /// <param name="strategy">Specification of the strategy to trade</param>
761  /// <param name="quantity">Quantity of the strategy to trade</param>
762  /// <param name="asynchronous">Send the order asynchronously (false). Otherwise we'll block until it fills</param>
763  /// <param name="tag">String tag for the order (optional)</param>
764  /// <param name="orderProperties">The order properties to use. Defaults to <see cref="DefaultOrderProperties"/></param>
765  /// <returns>Sequence of order tickets</returns>
766  [DocumentationAttribute(TradingAndOrders)]
767  public IEnumerable<OrderTicket> Sell(OptionStrategy strategy, int quantity, bool asynchronous = false, string tag = "", IOrderProperties orderProperties = null)
768  {
769  return Order(strategy, Math.Abs(quantity) * -1, asynchronous, tag, orderProperties);
770  }
771 
772  /// <summary>
773  /// Issue an order/trade for buying/selling an option strategy
774  /// </summary>
775  /// <param name="strategy">Specification of the strategy to trade</param>
776  /// <param name="quantity">Quantity of the strategy to trade</param>
777  /// <param name="asynchronous">Send the order asynchronously (false). Otherwise we'll block until it fills</param>
778  /// <param name="tag">String tag for the order (optional)</param>
779  /// <param name="orderProperties">The order properties to use. Defaults to <see cref="DefaultOrderProperties"/></param>
780  /// <returns>Sequence of order tickets</returns>
781  [DocumentationAttribute(TradingAndOrders)]
782  public IEnumerable<OrderTicket> Order(OptionStrategy strategy, int quantity, bool asynchronous = false, string tag = "", IOrderProperties orderProperties = null)
783  {
784  return GenerateOptionStrategyOrders(strategy, quantity, asynchronous, tag, orderProperties);
785  }
786 
787  /// <summary>
788  /// Issue a combo market order/trade for multiple assets
789  /// </summary>
790  /// <param name="legs">The list of legs the order consists of</param>
791  /// <param name="quantity">The total quantity for the order</param>
792  /// <param name="asynchronous">Send the order asynchronously (false). Otherwise we'll block until it fills</param>
793  /// <param name="tag">String tag for the order (optional)</param>
794  /// <param name="orderProperties">The order properties to use. Defaults to <see cref="DefaultOrderProperties"/></param>
795  /// <returns>Sequence of order tickets, one for each leg</returns>
796  [DocumentationAttribute(TradingAndOrders)]
797  public List<OrderTicket> ComboMarketOrder(List<Leg> legs, int quantity, bool asynchronous = false, string tag = "", IOrderProperties orderProperties = null)
798  {
799  return SubmitComboOrder(legs, quantity, 0, asynchronous, tag, orderProperties);
800  }
801 
802  /// <summary>
803  /// Issue a combo leg limit order/trade for multiple assets, each having its own limit price.
804  /// </summary>
805  /// <param name="legs">The list of legs the order consists of</param>
806  /// <param name="quantity">The total quantity for the order</param>
807  /// <param name="tag">String tag for the order (optional)</param>
808  /// <param name="orderProperties">The order properties to use. Defaults to <see cref="DefaultOrderProperties"/></param>
809  /// <returns>Sequence of order tickets, one for each leg</returns>
810  /// <exception cref="ArgumentException">If not every leg has a defined limit price</exception>
811  [DocumentationAttribute(TradingAndOrders)]
812  public List<OrderTicket> ComboLegLimitOrder(List<Leg> legs, int quantity, string tag = "", IOrderProperties orderProperties = null)
813  {
814  if (legs.Any(x => x.OrderPrice == null || x.OrderPrice == 0))
815  {
816  throw new ArgumentException("ComboLegLimitOrder requires a limit price for each leg");
817  }
818 
819  return SubmitComboOrder(legs, quantity, 0, asynchronous: true, tag, orderProperties);
820  }
821 
822  /// <summary>
823  /// Issue a combo limit order/trade for multiple assets.
824  /// A single limit price is defined for the combo order and will fill only if the sum of the assets price compares properly to the limit price, depending on the direction.
825  /// </summary>
826  /// <param name="legs">The list of legs the order consists of</param>
827  /// <param name="quantity">The total quantity for the order</param>
828  /// <param name="limitPrice">The compound limit price to use for a ComboLimit order. This limit price will compared to the sum of the assets price in order to fill the order.</param>
829  /// <param name="tag">String tag for the order (optional)</param>
830  /// <param name="orderProperties">The order properties to use. Defaults to <see cref="DefaultOrderProperties"/></param>
831  /// <returns>Sequence of order tickets, one for each leg</returns>
832  /// <exception cref="ArgumentException">If the order type is neither ComboMarket, ComboLimit nor ComboLegLimit</exception>
833  [DocumentationAttribute(TradingAndOrders)]
834  public List<OrderTicket> ComboLimitOrder(List<Leg> legs, int quantity, decimal limitPrice, string tag = "", IOrderProperties orderProperties = null)
835  {
836  if (limitPrice == 0)
837  {
838  throw new ArgumentException("ComboLimitOrder requires a limit price");
839  }
840 
841  if (legs.Any(x => x.OrderPrice != null && x.OrderPrice != 0))
842  {
843  throw new ArgumentException("ComboLimitOrder does not support limit prices for individual legs");
844  }
845 
846  return SubmitComboOrder(legs, quantity, limitPrice, asynchronous: true, tag, orderProperties);
847  }
848 
849  private IEnumerable<OrderTicket> GenerateOptionStrategyOrders(OptionStrategy strategy, int strategyQuantity, bool asynchronous, string tag, IOrderProperties orderProperties)
850  {
851  // if the option strategy canonical is set let's use it to make sure we target the right option, for example SPXW for SPX underlying,
852  // it could be null if the user created the option strategy manually and just set the underlying, in which case we use the default option target by using 'null'
853  var targetOption = strategy.CanonicalOption != null ? strategy.CanonicalOption.Canonical.ID.Symbol : null;
854 
855  // setting up the tag text for all orders of one strategy
856  tag ??= $"{strategy.Name} ({strategyQuantity.ToStringInvariant()})";
857 
858  var legs = new List<Leg>(strategy.UnderlyingLegs);
859 
860  // WHY: the option strategy doesn't specify the option style (and in consequence the symbol), so we figure it out at runtime
861  foreach (var optionLeg in strategy.OptionLegs)
862  {
863  Leg leg = null;
864  // search for both american/european style -- much better than looping through all securities
865  foreach (var optionStyle in new[] { OptionStyle.American, OptionStyle.European })
866  {
867  var option = QuantConnect.Symbol.CreateOption(strategy.Underlying, targetOption, strategy.Underlying.ID.Market, optionStyle, optionLeg.Right, optionLeg.Strike, optionLeg.Expiration);
868  if (Securities.ContainsKey(option))
869  {
870  // we found it, we add it a break/stop searching
871  leg = new Leg { Symbol = option, OrderPrice = optionLeg.OrderPrice, Quantity = optionLeg.Quantity };
872  break;
873  }
874  }
875 
876  if(leg == null)
877  {
878  throw new InvalidOperationException("Couldn't find the option contract in algorithm securities list. " +
879  Invariant($"Underlying: {strategy.Underlying}, option {optionLeg.Right}, strike {optionLeg.Strike}, ") +
880  Invariant($"expiration: {optionLeg.Expiration}")
881  );
882  }
883  legs.Add(leg);
884  }
885 
886  return SubmitComboOrder(legs, strategyQuantity, 0, asynchronous, tag, orderProperties);
887  }
888 
889  private List<OrderTicket> SubmitComboOrder(List<Leg> legs, decimal quantity, decimal limitPrice, bool asynchronous, string tag, IOrderProperties orderProperties)
890  {
891  CheckComboOrderSizing(legs, quantity);
892 
893  var orderType = OrderType.ComboMarket;
894  if(limitPrice != 0)
895  {
896  orderType = OrderType.ComboLimit;
897  }
898 
899  // we create a unique Id so the algorithm and the brokerage can relate the combo orders with each other
900  var groupOrderManager = new GroupOrderManager(Transactions.GetIncrementGroupOrderManagerId(), legs.Count, quantity, limitPrice);
901 
902  List<OrderTicket> orderTickets = new(capacity: legs.Count);
903  List<SubmitOrderRequest> submitRequests = new(capacity: legs.Count);
904  foreach (var leg in legs)
905  {
906  var security = Securities[leg.Symbol];
907 
908  if (leg.OrderPrice.HasValue)
909  {
910  // limit price per leg!
911  limitPrice = leg.OrderPrice.Value;
912  orderType = OrderType.ComboLegLimit;
913  }
914  var request = CreateSubmitOrderRequest(
915  orderType,
916  security,
917  ((decimal)leg.Quantity).GetOrderLegGroupQuantity(groupOrderManager),
918  tag,
919  orderProperties ?? DefaultOrderProperties?.Clone(),
920  groupOrderManager: groupOrderManager,
921  limitPrice: limitPrice);
922 
923  // we execture pre order checks for all requests before submitting, so that if anything fails we are not left with half submitted combo orders
924  var response = PreOrderChecks(request);
925  if (response.IsError)
926  {
927  orderTickets.Add(OrderTicket.InvalidSubmitRequest(Transactions, request, response));
928  return orderTickets;
929  }
930 
931  submitRequests.Add(request);
932  }
933 
934  foreach (var request in submitRequests)
935  {
936  //Add the order and create a new order Id.
937  orderTickets.Add(Transactions.AddOrder(request));
938  }
939 
940  // Wait for the order event to process, only if the exchange is open
941  if (!asynchronous)
942  {
943  foreach (var ticket in orderTickets)
944  {
945  if (ticket.Status.IsOpen())
946  {
947  Transactions.WaitForOrder(ticket.OrderId);
948  }
949  }
950  }
951 
952  return orderTickets;
953  }
954 
955  /// <summary>
956  /// Will submit an order request to the algorithm
957  /// </summary>
958  /// <param name="request">The request to submit</param>
959  /// <remarks>Will run order prechecks, which include making sure the algorithm is not warming up, security is added and has data among others</remarks>
960  /// <returns>The order ticket</returns>
961  [DocumentationAttribute(TradingAndOrders)]
963  {
964  var response = PreOrderChecks(request);
965  if (response.IsError)
966  {
967  return OrderTicket.InvalidSubmitRequest(Transactions, request, response);
968  }
969 
970  //Add the order and create a new order Id.
971  return Transactions.AddOrder(request);
972  }
973 
974  /// <summary>
975  /// Perform pre-order checks to ensure we have sufficient capital,
976  /// the market is open, and we haven't exceeded maximum realistic orders per day.
977  /// </summary>
978  /// <returns>OrderResponse. If no error, order request is submitted.</returns>
979  private OrderResponse PreOrderChecks(SubmitOrderRequest request)
980  {
981  var response = PreOrderChecksImpl(request);
982  if (response.IsError)
983  {
984  Error(response.ErrorMessage);
985  }
986  return response;
987  }
988 
989  /// <summary>
990  /// Perform pre-order checks to ensure we have sufficient capital,
991  /// the market is open, and we haven't exceeded maximum realistic orders per day.
992  /// </summary>
993  /// <returns>OrderResponse. If no error, order request is submitted.</returns>
994  private OrderResponse PreOrderChecksImpl(SubmitOrderRequest request)
995  {
996  if (IsWarmingUp)
997  {
998  return OrderResponse.WarmingUp(request);
999  }
1000 
1001  //Most order methods use security objects; so this isn't really used.
1002  // todo: Left here for now but should review
1003  Security security;
1004  if (!Securities.TryGetValue(request.Symbol, out security))
1005  {
1006  return OrderResponse.MissingSecurity(request);
1007  }
1008 
1009  //Ordering 0 is useless.
1010  if (request.Quantity == 0)
1011  {
1012  return OrderResponse.ZeroQuantity(request);
1013  }
1014 
1015  if (Math.Abs(request.Quantity) < security.SymbolProperties.LotSize)
1016  {
1017  return OrderResponse.Error(request, OrderResponseErrorCode.OrderQuantityLessThanLotSize,
1018  Invariant($"Unable to {request.OrderRequestType.ToLower()} order with id {request.OrderId} which ") +
1019  Invariant($"quantity ({Math.Abs(request.Quantity)}) is less than lot ") +
1020  Invariant($"size ({security.SymbolProperties.LotSize}).")
1021  );
1022  }
1023 
1024  if (!security.IsTradable)
1025  {
1026  return OrderResponse.Error(request, OrderResponseErrorCode.NonTradableSecurity,
1027  $"The security with symbol '{request.Symbol}' is marked as non-tradable."
1028  );
1029  }
1030 
1031  var price = security.Price;
1032 
1033  //Check the exchange is open before sending a exercise orders
1034  if (request.OrderType == OrderType.OptionExercise && !security.Exchange.ExchangeOpen)
1035  {
1036  return OrderResponse.Error(request, OrderResponseErrorCode.ExchangeNotOpen,
1037  $"{request.OrderType} order and exchange not open."
1038  );
1039  }
1040 
1041  //Check the exchange is open before sending a market on open order for futures
1042  if ((security.Type == SecurityType.Future || security.Type == SecurityType.FutureOption) && request.OrderType == OrderType.MarketOnOpen)
1043  {
1044  if (!_isMarketOnOpenOrderRestrictedForFuturesWarningSent)
1045  {
1046  Debug("Warning: Market-On-Open orders are not allowed for futures and future options. Consider using limit orders during extended market hours.");
1047  _isMarketOnOpenOrderRestrictedForFuturesWarningSent = true;
1048  }
1049 
1050  return OrderResponse.Error(request, OrderResponseErrorCode.ExchangeNotOpen,
1051  $"{request.OrderType} orders not supported for {security.Type}."
1052  );
1053  }
1054 
1055  if (price == 0)
1056  {
1057  return OrderResponse.Error(request, OrderResponseErrorCode.SecurityPriceZero, request.Symbol.GetZeroPriceMessage());
1058  }
1059 
1060  // check quote currency existence/conversion rate on all orders
1061  var quoteCurrency = security.QuoteCurrency.Symbol;
1062  if (!Portfolio.CashBook.TryGetValue(quoteCurrency, out var quoteCash))
1063  {
1064  return OrderResponse.Error(request, OrderResponseErrorCode.QuoteCurrencyRequired,
1065  $"{request.Symbol.Value}: requires {quoteCurrency} in the cashbook to trade."
1066  );
1067  }
1068  if (security.QuoteCurrency.ConversionRate == 0m)
1069  {
1070  return OrderResponse.Error(request, OrderResponseErrorCode.ConversionRateZero,
1071  $"{request.Symbol.Value}: requires {quoteCurrency} to have a non-zero conversion rate. This can be caused by lack of data."
1072  );
1073  }
1074 
1075  // need to also check base currency existence/conversion rate on forex orders
1076  if (security.Type == SecurityType.Forex || security.Type == SecurityType.Crypto)
1077  {
1078  var baseCurrency = ((IBaseCurrencySymbol)security).BaseCurrency.Symbol;
1079  if (!Portfolio.CashBook.TryGetValue(baseCurrency, out var baseCash))
1080  {
1081  return OrderResponse.Error(request, OrderResponseErrorCode.ForexBaseAndQuoteCurrenciesRequired,
1082  $"{request.Symbol.Value}: requires {baseCurrency} and {quoteCurrency} in the cashbook to trade."
1083  );
1084  }
1085  if (baseCash.ConversionRate == 0m)
1086  {
1087  return OrderResponse.Error(request, OrderResponseErrorCode.ForexConversionRateZero,
1088  $"{request.Symbol.Value}: requires {baseCurrency} and {quoteCurrency} to have non-zero conversion rates. This can be caused by lack of data."
1089  );
1090  }
1091  }
1092 
1093  //Make sure the security has some data:
1094  if (!security.HasData)
1095  {
1096  return OrderResponse.Error(request, OrderResponseErrorCode.SecurityHasNoData,
1097  "There is no data for this symbol yet, please check the security.HasData flag to ensure there is at least one data point."
1098  );
1099  }
1100 
1101  // We've already processed too many orders: max 10k
1102  if (!LiveMode && Transactions.OrdersCount > _maxOrders)
1103  {
1104  Status = AlgorithmStatus.Stopped;
1105  return OrderResponse.Error(request, OrderResponseErrorCode.ExceededMaximumOrders,
1106  Invariant($"You have exceeded maximum number of orders ({_maxOrders}), for unlimited orders upgrade your account.")
1107  );
1108  }
1109 
1110  if (request.OrderType == OrderType.OptionExercise)
1111  {
1112  if (!security.Type.IsOption())
1113  {
1114  return OrderResponse.Error(request, OrderResponseErrorCode.NonExercisableSecurity,
1115  $"The security with symbol '{request.Symbol}' is not exercisable."
1116  );
1117  }
1118 
1119  if ((security as Option).Style == OptionStyle.European && UtcTime.Date < security.Symbol.ID.Date.ConvertToUtc(security.Exchange.TimeZone).Date)
1120  {
1121  return OrderResponse.Error(request, OrderResponseErrorCode.EuropeanOptionNotExpiredOnExercise,
1122  $"Cannot exercise European style option with symbol '{request.Symbol}' before its expiration date."
1123  );
1124  }
1125 
1126  if (security.Holdings.IsShort)
1127  {
1128  return OrderResponse.Error(request, OrderResponseErrorCode.UnsupportedRequestType,
1129  $"The security with symbol '{request.Symbol}' has a short option position. Only long option positions are exercisable."
1130  );
1131  }
1132 
1133  if (Math.Abs(request.Quantity) > security.Holdings.Quantity)
1134  {
1135  return OrderResponse.Error(request, OrderResponseErrorCode.UnsupportedRequestType,
1136  $"Cannot exercise more contracts of '{request.Symbol}' than is currently available in the portfolio. "
1137  );
1138  }
1139  }
1140 
1141  if (request.OrderType == OrderType.MarketOnOpen)
1142  {
1143  if (security.Exchange.Hours.IsMarketAlwaysOpen)
1144  {
1145  throw new InvalidOperationException($"Market never closes for this symbol {security.Symbol}, can no submit a {nameof(OrderType.MarketOnOpen)} order.");
1146  }
1147  }
1148  else if (request.OrderType == OrderType.MarketOnClose)
1149  {
1150  if (security.Exchange.Hours.IsMarketAlwaysOpen)
1151  {
1152  throw new InvalidOperationException($"Market never closes for this symbol {security.Symbol}, can no submit a {nameof(OrderType.MarketOnClose)} order.");
1153  }
1154 
1155  var nextMarketClose = security.Exchange.Hours.GetNextMarketClose(security.LocalTime, false);
1156 
1157  // Enforce MarketOnClose submission buffer
1158  var latestSubmissionTimeUtc = nextMarketClose
1159  .ConvertToUtc(security.Exchange.TimeZone)
1160  .Subtract(Orders.MarketOnCloseOrder.SubmissionTimeBuffer);
1161  if (UtcTime > latestSubmissionTimeUtc)
1162  {
1163  // Tell user the required buffer on these orders, also inform them it can be changed for special cases.
1164  // Default buffer is 15.5 minutes because with minute data a user will receive the 3:44->3:45 bar at 3:45,
1165  // if the latest time is 3:45 it is already too late to submit one of these orders
1166  return OrderResponse.Error(request, OrderResponseErrorCode.MarketOnCloseOrderTooLate,
1167  $"MarketOnClose orders must be placed within {Orders.MarketOnCloseOrder.SubmissionTimeBuffer} before market close." +
1168  " Override this TimeSpan buffer by setting Orders.MarketOnCloseOrder.SubmissionTimeBuffer in QCAlgorithm.Initialize()."
1169  );
1170  }
1171  }
1172 
1173  if (request.OrderType == OrderType.ComboMarket && request.LimitPrice != 0)
1174  {
1175  // just in case some validation
1176  throw new ArgumentException("Can not set a limit price using market combo orders");
1177  }
1178 
1179  // Check for splits. Option are selected before the security price is split-adjusted, so in this time step
1180  // we don't allow option orders to make sure they are properly filtered using the right security price.
1181  if (request.SecurityType.IsOption() &&
1182  CurrentSlice != null &&
1183  CurrentSlice.Splits.Count > 0 &&
1184  CurrentSlice.Splits.TryGetValue(request.Symbol.Underlying, out _))
1185  {
1186  if (!_isOptionsOrderOnStockSplitWarningSent)
1187  {
1188  Debug("Warning: Options orders are not allowed when a split occurred for its underlying stock");
1189  _isOptionsOrderOnStockSplitWarningSent = true;
1190  }
1191 
1192  return OrderResponse.Error(request, OrderResponseErrorCode.OptionOrderOnStockSplit,
1193  "Options orders are not allowed when a split occurred for its underlying stock");
1194  }
1195 
1196  // passes all initial order checks
1197  return OrderResponse.Success(request);
1198  }
1199 
1200  /// <summary>
1201  /// Liquidate all holdings and cancel open orders. Called at the end of day for tick-strategies.
1202  /// </summary>
1203  /// <param name="symbolToLiquidate">Symbols we wish to liquidate</param>
1204  /// <param name="tag">Custom tag to know who is calling this.</param>
1205  /// <returns>Array of order ids for liquidated symbols</returns>
1206  /// <seealso cref="MarketOrder(QuantConnect.Symbol,decimal,bool,string)"/>
1207  [DocumentationAttribute(TradingAndOrders)]
1208  public List<int> Liquidate(Symbol symbolToLiquidate = null, string tag = "Liquidated")
1209  {
1210  var orderIdList = new List<int>();
1212  {
1213  Debug("Liquidate() is currently disabled by settings. To re-enable please set 'Settings.LiquidateEnabled' to true");
1214  return orderIdList;
1215  }
1216 
1217  IEnumerable<Symbol> toLiquidate;
1218  if (symbolToLiquidate != null)
1219  {
1220  toLiquidate = Securities.ContainsKey(symbolToLiquidate)
1221  ? new[] { symbolToLiquidate } : Enumerable.Empty<Symbol>();
1222  }
1223  else
1224  {
1225  toLiquidate = Securities.Keys.OrderBy(x => x.Value);
1226  }
1227 
1228 
1229  foreach (var symbol in toLiquidate)
1230  {
1231  // get open orders
1232  var orders = Transactions.GetOpenOrders(symbol);
1233 
1234  // get quantity in portfolio
1235  var quantity = Portfolio[symbol].Quantity;
1236 
1237  // if there is only one open market order that would close the position, do nothing
1238  if (orders.Count == 1 && quantity != 0 && orders[0].Quantity == -quantity && orders[0].Type == OrderType.Market)
1239  continue;
1240 
1241  // cancel all open orders
1242  var marketOrdersQuantity = 0m;
1243  foreach (var order in orders)
1244  {
1245  if (order.Type == OrderType.Market)
1246  {
1247  // pending market order
1248  var ticket = Transactions.GetOrderTicket(order.Id);
1249  if (ticket != null)
1250  {
1251  // get remaining quantity
1252  marketOrdersQuantity += ticket.Quantity - ticket.QuantityFilled;
1253  }
1254  }
1255  else
1256  {
1257  Transactions.CancelOrder(order.Id, tag);
1258  }
1259  }
1260 
1261  // Liquidate at market price
1262  if (quantity != 0)
1263  {
1264  // calculate quantity for closing market order
1265  var ticket = Order(symbol, -quantity - marketOrdersQuantity, tag: tag);
1266  if (ticket.Status == OrderStatus.Filled)
1267  {
1268  orderIdList.Add(ticket.OrderId);
1269  }
1270  }
1271  }
1272 
1273  return orderIdList;
1274  }
1275 
1276  /// <summary>
1277  /// Maximum number of orders for the algorithm
1278  /// </summary>
1279  /// <param name="max"></param>
1280  [DocumentationAttribute(TradingAndOrders)]
1281  public void SetMaximumOrders(int max)
1282  {
1283  if (!_locked)
1284  {
1285  _maxOrders = max;
1286  }
1287  }
1288 
1289  /// <summary>
1290  /// Sets holdings for a collection of targets.
1291  /// The implementation will order the provided targets executing first those that
1292  /// reduce a position, freeing margin.
1293  /// </summary>
1294  /// <param name="targets">The portfolio desired quantities as percentages</param>
1295  /// <param name="liquidateExistingHoldings">True will liquidate existing holdings</param>
1296  /// <param name="tag">Tag the order with a short string.</param>
1297  /// <param name="orderProperties">The order properties to use. Defaults to <see cref="DefaultOrderProperties"/></param>
1298  /// <seealso cref="MarketOrder(QuantConnect.Symbol,decimal,bool,string)"/>
1299  [DocumentationAttribute(TradingAndOrders)]
1300  public void SetHoldings(List<PortfolioTarget> targets, bool liquidateExistingHoldings = false, string tag = "", IOrderProperties orderProperties = null)
1301  {
1302  //If they triggered a liquidate
1303  if (liquidateExistingHoldings)
1304  {
1305  LiquidateExistingHoldings(targets.Select(x => x.Symbol).ToHashSet(), tag, orderProperties);
1306  }
1307 
1308  foreach (var portfolioTarget in targets
1309  // we need to create targets with quantities for OrderTargetsByMarginImpact
1310  .Select(target => new PortfolioTarget(target.Symbol, CalculateOrderQuantity(target.Symbol, target.Quantity)))
1311  .OrderTargetsByMarginImpact(this, targetIsDelta:true))
1312  {
1313  SetHoldingsImpl(portfolioTarget.Symbol, portfolioTarget.Quantity, false, tag, orderProperties);
1314  }
1315  }
1316 
1317  /// <summary>
1318  /// Alias for SetHoldings to avoid the M-decimal errors.
1319  /// </summary>
1320  /// <param name="symbol">string symbol we wish to hold</param>
1321  /// <param name="percentage">double percentage of holdings desired</param>
1322  /// <param name="liquidateExistingHoldings">liquidate existing holdings if necessary to hold this stock</param>
1323  /// <param name="tag">Tag the order with a short string.</param>
1324  /// <param name="orderProperties">The order properties to use. Defaults to <see cref="DefaultOrderProperties"/></param>
1325  /// <seealso cref="MarketOrder(QuantConnect.Symbol,decimal,bool,string)"/>
1326  [DocumentationAttribute(TradingAndOrders)]
1327  public void SetHoldings(Symbol symbol, double percentage, bool liquidateExistingHoldings = false, string tag = "", IOrderProperties orderProperties = null)
1328  {
1329  SetHoldings(symbol, percentage.SafeDecimalCast(), liquidateExistingHoldings, tag, orderProperties);
1330  }
1331 
1332  /// <summary>
1333  /// Alias for SetHoldings to avoid the M-decimal errors.
1334  /// </summary>
1335  /// <param name="symbol">string symbol we wish to hold</param>
1336  /// <param name="percentage">float percentage of holdings desired</param>
1337  /// <param name="liquidateExistingHoldings">bool liquidate existing holdings if necessary to hold this stock</param>
1338  /// <param name="tag">Tag the order with a short string.</param>
1339  /// <param name="orderProperties">The order properties to use. Defaults to <see cref="DefaultOrderProperties"/></param>
1340  /// <seealso cref="MarketOrder(QuantConnect.Symbol,decimal,bool,string)"/>
1341  [DocumentationAttribute(TradingAndOrders)]
1342  public void SetHoldings(Symbol symbol, float percentage, bool liquidateExistingHoldings = false, string tag = "", IOrderProperties orderProperties = null)
1343  {
1344  SetHoldings(symbol, (decimal)percentage, liquidateExistingHoldings, tag, orderProperties);
1345  }
1346 
1347  /// <summary>
1348  /// Alias for SetHoldings to avoid the M-decimal errors.
1349  /// </summary>
1350  /// <param name="symbol">string symbol we wish to hold</param>
1351  /// <param name="percentage">float percentage of holdings desired</param>
1352  /// <param name="liquidateExistingHoldings">bool liquidate existing holdings if necessary to hold this stock</param>
1353  /// <param name="tag">Tag the order with a short string.</param>
1354  /// <param name="orderProperties">The order properties to use. Defaults to <see cref="DefaultOrderProperties"/></param>
1355  /// <seealso cref="MarketOrder(QuantConnect.Symbol,decimal,bool,string)"/>
1356  [DocumentationAttribute(TradingAndOrders)]
1357  public void SetHoldings(Symbol symbol, int percentage, bool liquidateExistingHoldings = false, string tag = "", IOrderProperties orderProperties = null)
1358  {
1359  SetHoldings(symbol, (decimal)percentage, liquidateExistingHoldings, tag, orderProperties);
1360  }
1361 
1362  /// <summary>
1363  /// Automatically place a market order which will set the holdings to between 100% or -100% of *PORTFOLIO VALUE*.
1364  /// E.g. SetHoldings("AAPL", 0.1); SetHoldings("IBM", -0.2); -> Sets portfolio as long 10% APPL and short 20% IBM
1365  /// E.g. SetHoldings("AAPL", 2); -> Sets apple to 2x leveraged with all our cash.
1366  /// If the market is closed, place a market on open order.
1367  /// </summary>
1368  /// <param name="symbol">Symbol indexer</param>
1369  /// <param name="percentage">decimal fraction of portfolio to set stock</param>
1370  /// <param name="liquidateExistingHoldings">bool flag to clean all existing holdings before setting new faction.</param>
1371  /// <param name="tag">Tag the order with a short string.</param>
1372  /// <param name="orderProperties">The order properties to use. Defaults to <see cref="DefaultOrderProperties"/></param>
1373  /// <seealso cref="MarketOrder(QuantConnect.Symbol,decimal,bool,string)"/>
1374  [DocumentationAttribute(TradingAndOrders)]
1375  public void SetHoldings(Symbol symbol, decimal percentage, bool liquidateExistingHoldings = false, string tag = "", IOrderProperties orderProperties = null)
1376  {
1377  SetHoldingsImpl(symbol, CalculateOrderQuantity(symbol, percentage), liquidateExistingHoldings, tag, orderProperties);
1378  }
1379 
1380  /// <summary>
1381  /// Set holdings implementation, which uses order quantities (delta) not percentage nor target final quantity
1382  /// </summary>
1383  private void SetHoldingsImpl(Symbol symbol, decimal orderQuantity, bool liquidateExistingHoldings = false, string tag = "", IOrderProperties orderProperties = null)
1384  {
1385  //If they triggered a liquidate
1386  if (liquidateExistingHoldings)
1387  {
1388  LiquidateExistingHoldings(new HashSet<Symbol> { symbol }, tag, orderProperties);
1389  }
1390 
1391  //Calculate total unfilled quantity for open market orders
1392  var marketOrdersQuantity = Transactions.GetOpenOrderTickets(
1393  ticket => ticket.Symbol == symbol
1394  && (ticket.OrderType == OrderType.Market
1395  || ticket.OrderType == OrderType.MarketOnOpen))
1396  .Aggregate(0m, (d, ticket) => d + ticket.Quantity - ticket.QuantityFilled);
1397 
1398  //Only place trade if we've got > 1 share to order.
1399  var quantity = orderQuantity - marketOrdersQuantity;
1400  if (Math.Abs(quantity) > 0)
1401  {
1402  Security security;
1403  if (!Securities.TryGetValue(symbol, out security))
1404  {
1405  Error($"{symbol} not found in portfolio. Request this data when initializing the algorithm.");
1406  return;
1407  }
1408 
1409  //Check whether the exchange is open to send a market order. If not, send a market on open order instead
1410  if (security.Exchange.ExchangeOpen)
1411  {
1412  MarketOrder(symbol, quantity, false, tag, orderProperties);
1413  }
1414  else
1415  {
1416  MarketOnOpenOrder(symbol, quantity, tag, orderProperties);
1417  }
1418  }
1419  }
1420 
1421  /// <summary>
1422  /// Liquidate existing holdings, except for the target list of Symbol.
1423  /// </summary>
1424  /// <param name="symbols">List of Symbol indexer</param>
1425  /// <param name="tag">Tag the order with a short string.</param>
1426  /// <param name="orderProperties">The order properties to use. Defaults to <see cref="DefaultOrderProperties"/></param>
1427  private void LiquidateExistingHoldings(HashSet<Symbol> symbols, string tag = "", IOrderProperties orderProperties = null)
1428  {
1429  foreach (var kvp in Portfolio)
1430  {
1431  var holdingSymbol = kvp.Key;
1432  var holdings = kvp.Value;
1433  if (!symbols.Contains(holdingSymbol) && holdings.AbsoluteQuantity > 0)
1434  {
1435  //Go through all existing holdings [synchronously], market order the inverse quantity:
1436  var liquidationQuantity = CalculateOrderQuantity(holdingSymbol, 0m);
1437  Order(holdingSymbol, liquidationQuantity, false, tag, orderProperties);
1438  }
1439  }
1440  }
1441 
1442  /// <summary>
1443  /// Calculate the order quantity to achieve target-percent holdings.
1444  /// </summary>
1445  /// <param name="symbol">Security object we're asking for</param>
1446  /// <param name="target">Target percentage holdings</param>
1447  /// <returns>Order quantity to achieve this percentage</returns>
1448  [DocumentationAttribute(TradingAndOrders)]
1449  public decimal CalculateOrderQuantity(Symbol symbol, double target)
1450  {
1451  return CalculateOrderQuantity(symbol, target.SafeDecimalCast());
1452  }
1453 
1454  /// <summary>
1455  /// Calculate the order quantity to achieve target-percent holdings.
1456  /// </summary>
1457  /// <param name="symbol">Security object we're asking for</param>
1458  /// <param name="target">Target percentage holdings, this is an unleveraged value, so
1459  /// if you have 2x leverage and request 100% holdings, it will utilize half of the
1460  /// available margin</param>
1461  /// <returns>Order quantity to achieve this percentage</returns>
1462  [DocumentationAttribute(TradingAndOrders)]
1463  public decimal CalculateOrderQuantity(Symbol symbol, decimal target)
1464  {
1465  var percent = PortfolioTarget.Percent(this, symbol, target, true);
1466 
1467  if (percent == null)
1468  {
1469  return 0;
1470  }
1471  return percent.Quantity;
1472  }
1473 
1474  /// <summary>
1475  /// Obsolete implementation of Order method accepting a OrderType. This was deprecated since it
1476  /// was impossible to generate other orders via this method. Any calls to this method will always default to a Market Order.
1477  /// </summary>
1478  /// <param name="symbol">Symbol we want to purchase</param>
1479  /// <param name="quantity">Quantity to buy, + is long, - short.</param>
1480  /// <param name="type">Order Type</param>
1481  /// <param name="asynchronous">Don't wait for the response, just submit order and move on.</param>
1482  /// <param name="tag">Custom data for this order</param>
1483  /// <param name="orderProperties">The order properties to use. Defaults to <see cref="DefaultOrderProperties"/></param>
1484  /// <returns>The order ticket instance.</returns>
1485  [Obsolete("This Order method has been made obsolete, use Order(string, int, bool, string) method instead. Calls to the obsolete method will only generate market orders.")]
1486  [DocumentationAttribute(TradingAndOrders)]
1487  public OrderTicket Order(Symbol symbol, int quantity, OrderType type, bool asynchronous = false, string tag = "", IOrderProperties orderProperties = null)
1488  {
1489  return Order(symbol, quantity, asynchronous, tag, orderProperties);
1490  }
1491 
1492  /// <summary>
1493  /// Obsolete method for placing orders.
1494  /// </summary>
1495  /// <param name="symbol">Symbol we want to order</param>
1496  /// <param name="quantity">The quantity to order</param>
1497  /// <param name="type">The order type</param>
1498  /// <returns>The order ticket instance.</returns>
1499  [Obsolete("This Order method has been made obsolete, use the specialized Order helper methods instead. Calls to the obsolete method will only generate market orders.")]
1500  [DocumentationAttribute(TradingAndOrders)]
1501  public OrderTicket Order(Symbol symbol, decimal quantity, OrderType type)
1502  {
1503  return Order(symbol, quantity);
1504  }
1505 
1506  /// <summary>
1507  /// Obsolete method for placing orders.
1508  /// </summary>
1509  /// <param name="symbol">Symbol we want to order</param>
1510  /// <param name="quantity">The quantity to order</param>
1511  /// <param name="type">The order type</param>
1512  /// <returns>The order ticket instance.</returns>
1513  [Obsolete("This Order method has been made obsolete, use the specialized Order helper methods instead. Calls to the obsolete method will only generate market orders.")]
1514  [DocumentationAttribute(TradingAndOrders)]
1515  public OrderTicket Order(Symbol symbol, int quantity, OrderType type)
1516  {
1517  return Order(symbol, (decimal)quantity);
1518  }
1519 
1520  /// <summary>
1521  /// Determines if the exchange for the specified symbol is open at the current time.
1522  /// </summary>
1523  /// <param name="symbol">The symbol</param>
1524  /// <returns>True if the exchange is considered open at the current time, false otherwise</returns>
1525  [DocumentationAttribute(TradingAndOrders)]
1526  [DocumentationAttribute(SecuritiesAndPortfolio)]
1527  public bool IsMarketOpen(Symbol symbol)
1528  {
1529  if (Securities.TryGetValue(symbol, out var security))
1530  {
1531  return security.IsMarketOpen(false);
1532  }
1533  return symbol.IsMarketOpen(UtcTime, false);
1534  }
1535 
1536  private SubmitOrderRequest CreateSubmitOrderRequest(OrderType orderType, Security security, decimal quantity, string tag,
1537  IOrderProperties properties, decimal stopPrice = 0m, decimal limitPrice = 0m, decimal triggerPrice = 0m, decimal trailingAmount = 0m,
1538  bool trailingAsPercentage = false, GroupOrderManager groupOrderManager = null)
1539  {
1540  return new SubmitOrderRequest(orderType, security.Type, security.Symbol, quantity, stopPrice, limitPrice, triggerPrice, trailingAmount,
1541  trailingAsPercentage, UtcTime, tag, properties, groupOrderManager);
1542  }
1543 
1544  private static void CheckComboOrderSizing(List<Leg> legs, decimal quantity)
1545  {
1546  var greatestsCommonDivisor = Math.Abs(legs.Select(leg => leg.Quantity).GreatestCommonDivisor());
1547 
1548  if (greatestsCommonDivisor != 1)
1549  {
1550  throw new ArgumentException(
1551  "The global combo quantity should be used to increase or reduce the size of the order, " +
1552  "while the leg quantities should be used to specify the ratio of the order. " +
1553  "The combo order quantities should be reduced " +
1554  $"from {quantity}x({string.Join(", ", legs.Select(leg => $"{leg.Quantity} {leg.Symbol}"))}) " +
1555  $"to {quantity * greatestsCommonDivisor}x({string.Join(", ", legs.Select(leg => $"{leg.Quantity / greatestsCommonDivisor} {leg.Symbol}"))}).");
1556  }
1557  }
1558 
1559  /// <summary>
1560  /// Resets the time-in-force to the default <see cref="TimeInForce.GoodTilCanceled" /> if the given one is a <see cref="GoodTilDateTimeInForce"/>.
1561  /// This is required for MOO and MOC orders, for which GTD is not supported.
1562  /// </summary>
1563  private void InvalidateGoodTilDateTimeInForce(IOrderProperties orderProperties)
1564  {
1565  if (orderProperties.TimeInForce as GoodTilDateTimeInForce != null)
1566  {
1567  // Good-Til-Date(GTD) Time-In-Force is not supported for MOO and MOC orders
1568  orderProperties.TimeInForce = TimeInForce.GoodTilCanceled;
1569 
1570  if (!_isGtdTfiForMooAndMocOrdersValidationWarningSent)
1571  {
1572  Debug("Warning: Good-Til-Date Time-In-Force is not supported for MOO and MOC orders. " +
1573  "The time-in-force will be reset to Good-Til-Canceled (GTC).");
1574  _isGtdTfiForMooAndMocOrdersValidationWarningSent = true;
1575  }
1576  }
1577  }
1578  }
1579 }