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(QuantConnect.Symbol, decimal, bool, string, IOrderProperties)"/>
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 your portfolio holdings
1202  /// </summary>
1203  /// <param name="symbol">Specific asset to liquidate, defaults to all</param>
1204  /// <param name="asynchronous">Flag to indicate if the symbols should be liquidated asynchronously</param>
1205  /// <param name="tag">Custom tag to know who is calling this</param>
1206  /// <param name="orderProperties">Order properties to use</param>
1207  [DocumentationAttribute(TradingAndOrders)]
1208  public List<OrderTicket> Liquidate(Symbol symbol = null, bool asynchronous = false, string tag = "Liquidated", IOrderProperties orderProperties = null)
1209  {
1210  IEnumerable<Symbol> toLiquidate;
1211  if (symbol != null)
1212  {
1213  toLiquidate = Securities.ContainsKey(symbol)
1214  ? new[] { symbol } : Enumerable.Empty<Symbol>();
1215  }
1216  else
1217  {
1218  toLiquidate = Securities.Keys.OrderBy(x => x.Value);
1219  }
1220 
1221  return Liquidate(toLiquidate, asynchronous, tag, orderProperties);
1222  }
1223 
1224  /// <summary>
1225  /// Liquidate your portfolio holdings
1226  /// </summary>
1227  /// <param name="symbols">List of symbols to liquidate, defaults to all</param>
1228  /// <param name="asynchronous">Flag to indicate if the symbols should be liquidated asynchronously</param>
1229  /// <param name="tag">Custom tag to know who is calling this</param>
1230  /// <param name="orderProperties">Order properties to use</param>
1231  [DocumentationAttribute(TradingAndOrders)]
1232  public List<OrderTicket> Liquidate(IEnumerable<Symbol> symbols, bool asynchronous = false, string tag = "Liquidated", IOrderProperties orderProperties = null)
1233  {
1234  var orderTickets = new List<OrderTicket>();
1236  {
1237  Debug("Liquidate() is currently disabled by settings. To re-enable please set 'Settings.LiquidateEnabled' to true");
1238  return orderTickets;
1239  }
1240 
1241  foreach (var symbolToLiquidate in symbols)
1242  {
1243  // get open orders
1244  var orders = Transactions.GetOpenOrders(symbolToLiquidate);
1245 
1246  // get quantity in portfolio
1247  var quantity = 0m;
1248  var holdings = Portfolio[symbolToLiquidate];
1249  if (holdings.Invested)
1250  {
1251  // invested flag might filter some quantity that's less than lot size
1252  quantity = holdings.Quantity;
1253  }
1254 
1255  // if there is only one open market order that would close the position, do nothing
1256  if (orders.Count == 1 && quantity != 0 && orders[0].Quantity == -quantity && orders[0].Type == OrderType.Market)
1257  {
1258  continue;
1259  }
1260 
1261  // cancel all open orders
1262  var marketOrdersQuantity = 0m;
1263  foreach (var order in orders)
1264  {
1265  if (order.Type == OrderType.Market)
1266  {
1267  // pending market order
1268  var ticket = Transactions.GetOrderTicket(order.Id);
1269  if (ticket != null)
1270  {
1271  // get remaining quantity
1272  marketOrdersQuantity += ticket.Quantity - ticket.QuantityFilled;
1273  }
1274  }
1275  else
1276  {
1277  Transactions.CancelOrder(order.Id, tag);
1278  }
1279  }
1280 
1281  // Liquidate at market price
1282  if (quantity != 0)
1283  {
1284  // calculate quantity for closing market order
1285  var ticket = Order(symbolToLiquidate, -quantity - marketOrdersQuantity, asynchronous: asynchronous, tag: tag, orderProperties: orderProperties);
1286  orderTickets.Add(ticket);
1287  }
1288  }
1289 
1290  return orderTickets;
1291  }
1292 
1293  /// <summary>
1294  /// Liquidate all holdings and cancel open orders. Called at the end of day for tick-strategies.
1295  /// </summary>
1296  /// <param name="symbolToLiquidate">Symbol we wish to liquidate</param>
1297  /// <param name="tag">Custom tag to know who is calling this.</param>
1298  /// <returns>Array of order ids for liquidated symbols</returns>
1299  /// <seealso cref="MarketOrder(QuantConnect.Symbol, decimal, bool, string, IOrderProperties)"/>
1300  [Obsolete($"This method is obsolete, please use Liquidate(symbol: symbolToLiquidate, tag: tag) method")]
1301  public List<int> Liquidate(Symbol symbolToLiquidate, string tag)
1302  {
1303  return Liquidate(symbol: symbolToLiquidate, tag:tag).Select(x => x.OrderId).ToList();
1304  }
1305 
1306  /// <summary>
1307  /// Maximum number of orders for the algorithm
1308  /// </summary>
1309  /// <param name="max"></param>
1310  [DocumentationAttribute(TradingAndOrders)]
1311  public void SetMaximumOrders(int max)
1312  {
1313  if (!_locked)
1314  {
1315  _maxOrders = max;
1316  }
1317  }
1318 
1319  /// <summary>
1320  /// Sets holdings for a collection of targets.
1321  /// The implementation will order the provided targets executing first those that
1322  /// reduce a position, freeing margin.
1323  /// </summary>
1324  /// <param name="targets">The portfolio desired quantities as percentages</param>
1325  /// <param name="liquidateExistingHoldings">True will liquidate existing holdings</param>
1326  /// <param name="tag">Tag the order with a short string.</param>
1327  /// <param name="orderProperties">The order properties to use. Defaults to <see cref="DefaultOrderProperties"/></param>
1328  /// <seealso cref="MarketOrder(QuantConnect.Symbol, decimal, bool, string, IOrderProperties)"/>
1329  [DocumentationAttribute(TradingAndOrders)]
1330  public void SetHoldings(List<PortfolioTarget> targets, bool liquidateExistingHoldings = false, string tag = "", IOrderProperties orderProperties = null)
1331  {
1332  //If they triggered a liquidate
1333  if (liquidateExistingHoldings)
1334  {
1335  LiquidateExistingHoldings(targets.Select(x => x.Symbol).ToHashSet(), tag, orderProperties);
1336  }
1337 
1338  foreach (var portfolioTarget in targets
1339  // we need to create targets with quantities for OrderTargetsByMarginImpact
1340  .Select(target => new PortfolioTarget(target.Symbol, CalculateOrderQuantity(target.Symbol, target.Quantity)))
1341  .OrderTargetsByMarginImpact(this, targetIsDelta:true))
1342  {
1343  SetHoldingsImpl(portfolioTarget.Symbol, portfolioTarget.Quantity, false, tag, orderProperties);
1344  }
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">double percentage of holdings desired</param>
1352  /// <param name="liquidateExistingHoldings">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, IOrderProperties)"/>
1356  [DocumentationAttribute(TradingAndOrders)]
1357  public void SetHoldings(Symbol symbol, double percentage, bool liquidateExistingHoldings = false, string tag = "", IOrderProperties orderProperties = null)
1358  {
1359  SetHoldings(symbol, percentage.SafeDecimalCast(), liquidateExistingHoldings, tag, orderProperties);
1360  }
1361 
1362  /// <summary>
1363  /// Alias for SetHoldings to avoid the M-decimal errors.
1364  /// </summary>
1365  /// <param name="symbol">string symbol we wish to hold</param>
1366  /// <param name="percentage">float percentage of holdings desired</param>
1367  /// <param name="liquidateExistingHoldings">bool liquidate existing holdings if necessary to hold this stock</param>
1368  /// <param name="tag">Tag the order with a short string.</param>
1369  /// <param name="orderProperties">The order properties to use. Defaults to <see cref="DefaultOrderProperties"/></param>
1370  /// <seealso cref="MarketOrder(QuantConnect.Symbol, decimal, bool, string, IOrderProperties)"/>
1371  [DocumentationAttribute(TradingAndOrders)]
1372  public void SetHoldings(Symbol symbol, float percentage, bool liquidateExistingHoldings = false, string tag = "", IOrderProperties orderProperties = null)
1373  {
1374  SetHoldings(symbol, (decimal)percentage, liquidateExistingHoldings, tag, orderProperties);
1375  }
1376 
1377  /// <summary>
1378  /// Alias for SetHoldings to avoid the M-decimal errors.
1379  /// </summary>
1380  /// <param name="symbol">string symbol we wish to hold</param>
1381  /// <param name="percentage">float percentage of holdings desired</param>
1382  /// <param name="liquidateExistingHoldings">bool liquidate existing holdings if necessary to hold this stock</param>
1383  /// <param name="tag">Tag the order with a short string.</param>
1384  /// <param name="orderProperties">The order properties to use. Defaults to <see cref="DefaultOrderProperties"/></param>
1385  /// <seealso cref="MarketOrder(QuantConnect.Symbol, decimal, bool, string, IOrderProperties)"/>
1386  [DocumentationAttribute(TradingAndOrders)]
1387  public void SetHoldings(Symbol symbol, int percentage, bool liquidateExistingHoldings = false, string tag = "", IOrderProperties orderProperties = null)
1388  {
1389  SetHoldings(symbol, (decimal)percentage, liquidateExistingHoldings, tag, orderProperties);
1390  }
1391 
1392  /// <summary>
1393  /// Automatically place a market order which will set the holdings to between 100% or -100% of *PORTFOLIO VALUE*.
1394  /// E.g. SetHoldings("AAPL", 0.1); SetHoldings("IBM", -0.2); -> Sets portfolio as long 10% APPL and short 20% IBM
1395  /// E.g. SetHoldings("AAPL", 2); -> Sets apple to 2x leveraged with all our cash.
1396  /// If the market is closed, place a market on open order.
1397  /// </summary>
1398  /// <param name="symbol">Symbol indexer</param>
1399  /// <param name="percentage">decimal fraction of portfolio to set stock</param>
1400  /// <param name="liquidateExistingHoldings">bool flag to clean all existing holdings before setting new faction.</param>
1401  /// <param name="tag">Tag the order with a short string.</param>
1402  /// <param name="orderProperties">The order properties to use. Defaults to <see cref="DefaultOrderProperties"/></param>
1403  /// <seealso cref="MarketOrder(QuantConnect.Symbol, decimal, bool, string, IOrderProperties)"/>
1404  [DocumentationAttribute(TradingAndOrders)]
1405  public void SetHoldings(Symbol symbol, decimal percentage, bool liquidateExistingHoldings = false, string tag = "", IOrderProperties orderProperties = null)
1406  {
1407  SetHoldingsImpl(symbol, CalculateOrderQuantity(symbol, percentage), liquidateExistingHoldings, tag, orderProperties);
1408  }
1409 
1410  /// <summary>
1411  /// Set holdings implementation, which uses order quantities (delta) not percentage nor target final quantity
1412  /// </summary>
1413  private void SetHoldingsImpl(Symbol symbol, decimal orderQuantity, bool liquidateExistingHoldings = false, string tag = "", IOrderProperties orderProperties = null)
1414  {
1415  //If they triggered a liquidate
1416  if (liquidateExistingHoldings)
1417  {
1418  LiquidateExistingHoldings(new HashSet<Symbol> { symbol }, tag, orderProperties);
1419  }
1420 
1421  //Calculate total unfilled quantity for open market orders
1422  var marketOrdersQuantity = Transactions.GetOpenOrderTickets(
1423  ticket => ticket.Symbol == symbol
1424  && (ticket.OrderType == OrderType.Market
1425  || ticket.OrderType == OrderType.MarketOnOpen))
1426  .Aggregate(0m, (d, ticket) => d + ticket.Quantity - ticket.QuantityFilled);
1427 
1428  //Only place trade if we've got > 1 share to order.
1429  var quantity = orderQuantity - marketOrdersQuantity;
1430  if (Math.Abs(quantity) > 0)
1431  {
1432  Security security;
1433  if (!Securities.TryGetValue(symbol, out security))
1434  {
1435  Error($"{symbol} not found in portfolio. Request this data when initializing the algorithm.");
1436  return;
1437  }
1438 
1439  //Check whether the exchange is open to send a market order. If not, send a market on open order instead
1440  if (security.Exchange.ExchangeOpen)
1441  {
1442  MarketOrder(symbol, quantity, false, tag, orderProperties);
1443  }
1444  else
1445  {
1446  MarketOnOpenOrder(symbol, quantity, tag, orderProperties);
1447  }
1448  }
1449  }
1450 
1451  /// <summary>
1452  /// Liquidate existing holdings, except for the target list of Symbol.
1453  /// </summary>
1454  /// <param name="symbols">List of Symbol indexer</param>
1455  /// <param name="tag">Tag the order with a short string.</param>
1456  /// <param name="orderProperties">The order properties to use. Defaults to <see cref="DefaultOrderProperties"/></param>
1457  private void LiquidateExistingHoldings(HashSet<Symbol> symbols, string tag = "", IOrderProperties orderProperties = null)
1458  {
1459  foreach (var kvp in Portfolio)
1460  {
1461  var holdingSymbol = kvp.Key;
1462  var holdings = kvp.Value;
1463  if (!symbols.Contains(holdingSymbol) && holdings.AbsoluteQuantity > 0)
1464  {
1465  //Go through all existing holdings [synchronously], market order the inverse quantity:
1466  var liquidationQuantity = CalculateOrderQuantity(holdingSymbol, 0m);
1467  Order(holdingSymbol, liquidationQuantity, false, tag, orderProperties);
1468  }
1469  }
1470  }
1471 
1472  /// <summary>
1473  /// Calculate the order quantity to achieve target-percent holdings.
1474  /// </summary>
1475  /// <param name="symbol">Security object we're asking for</param>
1476  /// <param name="target">Target percentage holdings</param>
1477  /// <returns>Order quantity to achieve this percentage</returns>
1478  [DocumentationAttribute(TradingAndOrders)]
1479  public decimal CalculateOrderQuantity(Symbol symbol, double target)
1480  {
1481  return CalculateOrderQuantity(symbol, target.SafeDecimalCast());
1482  }
1483 
1484  /// <summary>
1485  /// Calculate the order quantity to achieve target-percent holdings.
1486  /// </summary>
1487  /// <param name="symbol">Security object we're asking for</param>
1488  /// <param name="target">Target percentage holdings, this is an unleveraged value, so
1489  /// if you have 2x leverage and request 100% holdings, it will utilize half of the
1490  /// available margin</param>
1491  /// <returns>Order quantity to achieve this percentage</returns>
1492  [DocumentationAttribute(TradingAndOrders)]
1493  public decimal CalculateOrderQuantity(Symbol symbol, decimal target)
1494  {
1495  var percent = PortfolioTarget.Percent(this, symbol, target, true);
1496 
1497  if (percent == null)
1498  {
1499  return 0;
1500  }
1501  return percent.Quantity;
1502  }
1503 
1504  /// <summary>
1505  /// Obsolete implementation of Order method accepting a OrderType. This was deprecated since it
1506  /// was impossible to generate other orders via this method. Any calls to this method will always default to a Market Order.
1507  /// </summary>
1508  /// <param name="symbol">Symbol we want to purchase</param>
1509  /// <param name="quantity">Quantity to buy, + is long, - short.</param>
1510  /// <param name="type">Order Type</param>
1511  /// <param name="asynchronous">Don't wait for the response, just submit order and move on.</param>
1512  /// <param name="tag">Custom data for this order</param>
1513  /// <param name="orderProperties">The order properties to use. Defaults to <see cref="DefaultOrderProperties"/></param>
1514  /// <returns>The order ticket instance.</returns>
1515  [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.")]
1516  [DocumentationAttribute(TradingAndOrders)]
1517  public OrderTicket Order(Symbol symbol, int quantity, OrderType type, bool asynchronous = false, string tag = "", IOrderProperties orderProperties = null)
1518  {
1519  return Order(symbol, quantity, asynchronous, tag, orderProperties);
1520  }
1521 
1522  /// <summary>
1523  /// Obsolete method for placing orders.
1524  /// </summary>
1525  /// <param name="symbol">Symbol we want to order</param>
1526  /// <param name="quantity">The quantity to order</param>
1527  /// <param name="type">The order type</param>
1528  /// <returns>The order ticket instance.</returns>
1529  [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.")]
1530  [DocumentationAttribute(TradingAndOrders)]
1531  public OrderTicket Order(Symbol symbol, decimal quantity, OrderType type)
1532  {
1533  return Order(symbol, quantity);
1534  }
1535 
1536  /// <summary>
1537  /// Obsolete method for placing orders.
1538  /// </summary>
1539  /// <param name="symbol">Symbol we want to order</param>
1540  /// <param name="quantity">The quantity to order</param>
1541  /// <param name="type">The order type</param>
1542  /// <returns>The order ticket instance.</returns>
1543  [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.")]
1544  [DocumentationAttribute(TradingAndOrders)]
1545  public OrderTicket Order(Symbol symbol, int quantity, OrderType type)
1546  {
1547  return Order(symbol, (decimal)quantity);
1548  }
1549 
1550  /// <summary>
1551  /// Determines if the exchange for the specified symbol is open at the current time.
1552  /// </summary>
1553  /// <param name="symbol">The symbol</param>
1554  /// <returns>True if the exchange is considered open at the current time, false otherwise</returns>
1555  [DocumentationAttribute(TradingAndOrders)]
1556  [DocumentationAttribute(SecuritiesAndPortfolio)]
1557  public bool IsMarketOpen(Symbol symbol)
1558  {
1559  if (Securities.TryGetValue(symbol, out var security))
1560  {
1561  return security.IsMarketOpen(false);
1562  }
1563  return symbol.IsMarketOpen(UtcTime, false);
1564  }
1565 
1566  private SubmitOrderRequest CreateSubmitOrderRequest(OrderType orderType, Security security, decimal quantity, string tag,
1567  IOrderProperties properties, decimal stopPrice = 0m, decimal limitPrice = 0m, decimal triggerPrice = 0m, decimal trailingAmount = 0m,
1568  bool trailingAsPercentage = false, GroupOrderManager groupOrderManager = null)
1569  {
1570  return new SubmitOrderRequest(orderType, security.Type, security.Symbol, quantity, stopPrice, limitPrice, triggerPrice, trailingAmount,
1571  trailingAsPercentage, UtcTime, tag, properties, groupOrderManager);
1572  }
1573 
1574  private static void CheckComboOrderSizing(List<Leg> legs, decimal quantity)
1575  {
1576  var greatestsCommonDivisor = Math.Abs(legs.Select(leg => leg.Quantity).GreatestCommonDivisor());
1577 
1578  if (greatestsCommonDivisor != 1)
1579  {
1580  throw new ArgumentException(
1581  "The global combo quantity should be used to increase or reduce the size of the order, " +
1582  "while the leg quantities should be used to specify the ratio of the order. " +
1583  "The combo order quantities should be reduced " +
1584  $"from {quantity}x({string.Join(", ", legs.Select(leg => $"{leg.Quantity} {leg.Symbol}"))}) " +
1585  $"to {quantity * greatestsCommonDivisor}x({string.Join(", ", legs.Select(leg => $"{leg.Quantity / greatestsCommonDivisor} {leg.Symbol}"))}).");
1586  }
1587  }
1588 
1589  /// <summary>
1590  /// Resets the time-in-force to the default <see cref="TimeInForce.GoodTilCanceled" /> if the given one is a <see cref="GoodTilDateTimeInForce"/>.
1591  /// This is required for MOO and MOC orders, for which GTD is not supported.
1592  /// </summary>
1593  private void InvalidateGoodTilDateTimeInForce(IOrderProperties orderProperties)
1594  {
1595  if (orderProperties.TimeInForce as GoodTilDateTimeInForce != null)
1596  {
1597  // Good-Til-Date(GTD) Time-In-Force is not supported for MOO and MOC orders
1598  orderProperties.TimeInForce = TimeInForce.GoodTilCanceled;
1599 
1600  if (!_isGtdTfiForMooAndMocOrdersValidationWarningSent)
1601  {
1602  Debug("Warning: Good-Til-Date Time-In-Force is not supported for MOO and MOC orders. " +
1603  "The time-in-force will be reset to Good-Til-Canceled (GTC).");
1604  _isGtdTfiForMooAndMocOrdersValidationWarningSent = true;
1605  }
1606  }
1607  }
1608  }
1609 }