Lean  $LEAN_TAG$
Order.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.Collections.Generic;
18 using System.ComponentModel;
19 using System.Linq;
20 using System.Threading;
21 using Newtonsoft.Json;
25 
26 namespace QuantConnect.Orders
27 {
28  /// <summary>
29  /// Order struct for placing new trade
30  /// </summary>
31  public abstract class Order
32  {
33  private volatile int _incrementalId;
34  private decimal _quantity;
35  private decimal _price;
36  private int _id;
37 
38  /// <summary>
39  /// Order ID.
40  /// </summary>
41  [JsonProperty(PropertyName = "id")]
42  public int Id
43  {
44  get => _id;
45  internal set
46  {
47  _id = value;
48  if (_id != 0 && GroupOrderManager != null)
49  {
51  {
52  GroupOrderManager.OrderIds.Add(_id);
53  }
54  }
55  }
56  }
57 
58  /// <summary>
59  /// Order id to process before processing this order.
60  /// </summary>
61  [JsonProperty(PropertyName = "contingentId")]
62  public int ContingentId { get; internal set; }
63 
64  /// <summary>
65  /// Brokerage Id for this order for when the brokerage splits orders into multiple pieces
66  /// </summary>
67  [JsonProperty(PropertyName = "brokerId")]
68  public List<string> BrokerId { get; internal set; }
69 
70  /// <summary>
71  /// Symbol of the Asset
72  /// </summary>
73  [JsonProperty(PropertyName = "symbol")]
74  public Symbol Symbol { get; internal set; }
75 
76  /// <summary>
77  /// Price of the Order.
78  /// </summary>
79  [JsonProperty(PropertyName = "price")]
80  public decimal Price
81  {
82  get { return _price; }
83  internal set { _price = value.Normalize(); }
84  }
85 
86  /// <summary>
87  /// Currency for the order price
88  /// </summary>
89  [JsonProperty(PropertyName = "priceCurrency")]
90  public string PriceCurrency { get; internal set; }
91 
92  /// <summary>
93  /// Gets the utc time the order was created.
94  /// </summary>
95  [JsonProperty(PropertyName = "time")]
96  public DateTime Time { get; internal set; }
97 
98  /// <summary>
99  /// Gets the utc time this order was created. Alias for <see cref="Time"/>
100  /// </summary>
101  [JsonProperty(PropertyName = "createdTime")]
102  public DateTime CreatedTime => Time;
103 
104  /// <summary>
105  /// Gets the utc time the last fill was received, or null if no fills have been received
106  /// </summary>
107  [JsonProperty(PropertyName = "lastFillTime", NullValueHandling = NullValueHandling.Ignore)]
108  public DateTime? LastFillTime { get; internal set; }
109 
110  /// <summary>
111  /// Gets the utc time this order was last updated, or null if the order has not been updated.
112  /// </summary>
113  [JsonProperty(PropertyName = "lastUpdateTime", NullValueHandling = NullValueHandling.Ignore)]
114  public DateTime? LastUpdateTime { get; internal set; }
115 
116  /// <summary>
117  /// Gets the utc time this order was canceled, or null if the order was not canceled.
118  /// </summary>
119  [JsonProperty(PropertyName = "canceledTime", NullValueHandling = NullValueHandling.Ignore)]
120  public DateTime? CanceledTime { get; internal set; }
121 
122  /// <summary>
123  /// Number of shares to execute.
124  /// </summary>
125  [JsonProperty(PropertyName = "quantity")]
126  public virtual decimal Quantity
127  {
128  get { return _quantity; }
129  internal set { _quantity = value.Normalize(); }
130  }
131 
132  /// <summary>
133  /// Order Type
134  /// </summary>
135  [JsonProperty(PropertyName = "type")]
136  public abstract OrderType Type { get; }
137 
138  /// <summary>
139  /// Status of the Order
140  /// </summary>
141  [JsonProperty(PropertyName = "status")]
142  public OrderStatus Status { get; set; }
143 
144  /// <summary>
145  /// Order Time In Force
146  /// </summary>
147  [JsonIgnore]
149 
150  /// <summary>
151  /// Tag the order with some custom data
152  /// </summary>
153  [JsonProperty(PropertyName = "tag" ,DefaultValueHandling = DefaultValueHandling.Ignore)]
154  public string Tag { get; internal set; }
155 
156  /// <summary>
157  /// Additional properties of the order
158  /// </summary>
159  [JsonProperty(PropertyName = "properties")]
160  public IOrderProperties Properties { get; private set; }
161 
162  /// <summary>
163  /// The symbol's security type
164  /// </summary>
165  [JsonProperty(PropertyName = "securityType")]
167 
168  /// <summary>
169  /// Order Direction Property based off Quantity.
170  /// </summary>
171  [JsonProperty(PropertyName = "direction")]
173  {
174  get
175  {
176  if (Quantity > 0)
177  {
178  return OrderDirection.Buy;
179  }
180  if (Quantity < 0)
181  {
182  return OrderDirection.Sell;
183  }
184  return OrderDirection.Hold;
185  }
186  }
187 
188  /// <summary>
189  /// Get the absolute quantity for this order
190  /// </summary>
191  [JsonIgnore]
192  public decimal AbsoluteQuantity => Math.Abs(Quantity);
193 
194  /// <summary>
195  /// Deprecated
196  /// </summary>
197  [JsonProperty(PropertyName = "value"), Obsolete("Please use Order.GetValue(security) or security.Holdings.HoldingsValue")]
198  public decimal Value => Quantity * Price;
199 
200  /// <summary>
201  /// Gets the price data at the time the order was submitted
202  /// </summary>
203  [JsonProperty(PropertyName = "orderSubmissionData")]
204  public OrderSubmissionData OrderSubmissionData { get; internal set; }
205 
206  /// <summary>
207  /// Returns true if the order is a marketable order.
208  /// </summary>
209  [JsonProperty(PropertyName = "isMarketable")]
210  public bool IsMarketable
211  {
212  get
213  {
214  if (Type == OrderType.Limit)
215  {
216  // check if marketable limit order using bid/ask prices
217  var limitOrder = (LimitOrder)this;
218  return OrderSubmissionData != null &&
219  (Direction == OrderDirection.Buy && limitOrder.LimitPrice >= OrderSubmissionData.AskPrice ||
220  Direction == OrderDirection.Sell && limitOrder.LimitPrice <= OrderSubmissionData.BidPrice);
221  }
222 
223  return Type == OrderType.Market || Type == OrderType.ComboMarket;
224  }
225  }
226 
227  /// <summary>
228  /// Manager for the orders in the group if this is a combo order
229  /// </summary>
230  [JsonProperty(PropertyName = "groupOrderManager", DefaultValueHandling = DefaultValueHandling.Ignore)]
232 
233  /// <summary>
234  /// The adjustment mode used on the order fill price
235  /// </summary>
236  [JsonProperty(PropertyName = "priceAdjustmentMode")]
238 
239  /// <summary>
240  /// Added a default constructor for JSON Deserialization:
241  /// </summary>
242  protected Order()
243  {
244  Time = new DateTime();
245  PriceCurrency = string.Empty;
246  Symbol = Symbol.Empty;
247  Status = OrderStatus.None;
248  Tag = string.Empty;
249  BrokerId = new List<string>();
250  Properties = new OrderProperties();
251  GroupOrderManager = null;
252  }
253 
254  /// <summary>
255  /// New order constructor
256  /// </summary>
257  /// <param name="symbol">Symbol asset we're seeking to trade</param>
258  /// <param name="quantity">Quantity of the asset we're seeking to trade</param>
259  /// <param name="time">Time the order was placed</param>
260  /// <param name="groupOrderManager">Manager for the orders in the group if this is a combo order</param>
261  /// <param name="tag">User defined data tag for this order</param>
262  /// <param name="properties">The order properties for this order</param>
263  protected Order(Symbol symbol, decimal quantity, DateTime time, GroupOrderManager groupOrderManager, string tag = "",
264  IOrderProperties properties = null)
265  {
266  Time = time;
267  PriceCurrency = string.Empty;
268  Quantity = quantity;
269  Symbol = symbol;
270  Status = OrderStatus.None;
271  Tag = tag;
272  BrokerId = new List<string>();
273  Properties = properties ?? new OrderProperties();
274  GroupOrderManager = groupOrderManager;
275  }
276 
277  /// <summary>
278  /// New order constructor
279  /// </summary>
280  /// <param name="symbol">Symbol asset we're seeking to trade</param>
281  /// <param name="quantity">Quantity of the asset we're seeking to trade</param>
282  /// <param name="time">Time the order was placed</param>
283  /// <param name="tag">User defined data tag for this order</param>
284  /// <param name="properties">The order properties for this order</param>
285  protected Order(Symbol symbol, decimal quantity, DateTime time, string tag = "", IOrderProperties properties = null)
286  : this(symbol, quantity, time, null, tag, properties)
287  {
288  }
289 
290  /// <summary>
291  /// Creates an enumerable containing each position resulting from executing this order.
292  /// </summary>
293  /// <remarks>
294  /// This is provided in anticipation of a new combo order type that will need to override this method,
295  /// returning a position for each 'leg' of the order.
296  /// </remarks>
297  /// <returns>An enumerable of positions matching the results of executing this order</returns>
298  public virtual IEnumerable<IPosition> CreatePositions(SecurityManager securities)
299  {
300  var security = securities[Symbol];
301  yield return new Position(security, Quantity);
302  }
303 
304  /// <summary>
305  /// Gets the value of this order at the given market price in units of the account currency
306  /// NOTE: Some order types derive value from other parameters, such as limit prices
307  /// </summary>
308  /// <param name="security">The security matching this order's symbol</param>
309  /// <returns>The value of this order given the current market price</returns>
310  /// <remarks>TODO: we should remove this. Only used in tests</remarks>
311  public decimal GetValue(Security security)
312  {
313  var value = GetValueImpl(security);
314  return value*security.QuoteCurrency.ConversionRate*security.SymbolProperties.ContractMultiplier;
315  }
316 
317  /// <summary>
318  /// Gets the order value in units of the security's quote currency for a single unit.
319  /// A single unit here is a single share of stock, or a single barrel of oil, or the
320  /// cost of a single share in an option contract.
321  /// </summary>
322  /// <param name="security">The security matching this order's symbol</param>
323  protected abstract decimal GetValueImpl(Security security);
324 
325  /// <summary>
326  /// Gets the default tag for this order
327  /// </summary>
328  /// <returns>The default tag</returns>
329  public virtual string GetDefaultTag()
330  {
331  return string.Empty;
332  }
333 
334  /// <summary>
335  /// Gets a new unique incremental id for this order
336  /// </summary>
337  /// <returns>Returns a new id for this order</returns>
338  internal int GetNewId()
339  {
340  return Interlocked.Increment(ref _incrementalId);
341  }
342 
343  /// <summary>
344  /// Modifies the state of this order to match the update request
345  /// </summary>
346  /// <param name="request">The request to update this order object</param>
347  public virtual void ApplyUpdateOrderRequest(UpdateOrderRequest request)
348  {
349  if (request.OrderId != Id)
350  {
351  throw new ArgumentException("Attempted to apply updates to the incorrect order!");
352  }
353  if (request.Quantity.HasValue)
354  {
355  Quantity = request.Quantity.Value;
356  }
357  if (request.Tag != null)
358  {
359  Tag = request.Tag;
360  }
361  }
362 
363  /// <summary>
364  /// Returns a string that represents the current object.
365  /// </summary>
366  /// <returns>
367  /// A string that represents the current object.
368  /// </returns>
369  /// <filterpriority>2</filterpriority>
370  public override string ToString()
371  {
372  return Messages.Order.ToString(this);
373  }
374 
375  /// <summary>
376  /// Creates a deep-copy clone of this order
377  /// </summary>
378  /// <returns>A copy of this order</returns>
379  public abstract Order Clone();
380 
381  /// <summary>
382  /// Copies base Order properties to the specified order
383  /// </summary>
384  /// <param name="order">The target of the copy</param>
385  protected void CopyTo(Order order)
386  {
387  order.Id = Id;
388  // The group order manager has to be set before the quantity,
389  // since combo orders might need it to calculate the quantity in the Quantity setter.
391  order.Time = Time;
392  order.LastFillTime = LastFillTime;
394  order.CanceledTime = CanceledTime;
395  order.BrokerId = BrokerId.ToList();
396  order.ContingentId = ContingentId;
397  order.Price = Price;
399  order.Quantity = Quantity;
400  order.Status = Status;
401  order.Symbol = Symbol;
402  order.Tag = Tag;
403  order.Properties = Properties.Clone();
406  }
407 
408  /// <summary>
409  /// Creates an <see cref="Order"/> to match the specified <paramref name="request"/>
410  /// </summary>
411  /// <param name="request">The <see cref="SubmitOrderRequest"/> to create an order for</param>
412  /// <returns>The <see cref="Order"/> that matches the request</returns>
413  public static Order CreateOrder(SubmitOrderRequest request)
414  {
415  return CreateOrder(request.OrderId, request.OrderType, request.Symbol, request.Quantity, request.Time,
416  request.Tag, request.OrderProperties, request.LimitPrice, request.StopPrice, request.TriggerPrice, request.TrailingAmount,
417  request.TrailingAsPercentage, request.GroupOrderManager);
418  }
419 
420  private static Order CreateOrder(int orderId, OrderType type, Symbol symbol, decimal quantity, DateTime time,
421  string tag, IOrderProperties properties, decimal limitPrice, decimal stopPrice, decimal triggerPrice, decimal trailingAmount,
422  bool trailingAsPercentage, GroupOrderManager groupOrderManager)
423  {
424  Order order;
425  switch (type)
426  {
427  case OrderType.Market:
428  order = new MarketOrder(symbol, quantity, time, tag, properties);
429  break;
430 
431  case OrderType.Limit:
432  order = new LimitOrder(symbol, quantity, limitPrice, time, tag, properties);
433  break;
434 
435  case OrderType.StopMarket:
436  order = new StopMarketOrder(symbol, quantity, stopPrice, time, tag, properties);
437  break;
438 
439  case OrderType.StopLimit:
440  order = new StopLimitOrder(symbol, quantity, stopPrice, limitPrice, time, tag, properties);
441  break;
442 
443  case OrderType.TrailingStop:
444  order = new TrailingStopOrder(symbol, quantity, stopPrice, trailingAmount, trailingAsPercentage, time, tag, properties);
445  break;
446 
447  case OrderType.LimitIfTouched:
448  order = new LimitIfTouchedOrder(symbol, quantity, triggerPrice, limitPrice, time, tag, properties);
449  break;
450 
451  case OrderType.MarketOnOpen:
452  order = new MarketOnOpenOrder(symbol, quantity, time, tag, properties);
453  break;
454 
455  case OrderType.MarketOnClose:
456  order = new MarketOnCloseOrder(symbol, quantity, time, tag, properties);
457  break;
458 
459  case OrderType.OptionExercise:
460  order = new OptionExerciseOrder(symbol, quantity, time, tag, properties);
461  break;
462 
463  case OrderType.ComboLimit:
464  order = new ComboLimitOrder(symbol, quantity, limitPrice, time, groupOrderManager, tag, properties);
465  break;
466 
467  case OrderType.ComboLegLimit:
468  order = new ComboLegLimitOrder(symbol, quantity, limitPrice, time, groupOrderManager, tag, properties);
469  break;
470 
471  case OrderType.ComboMarket:
472  order = new ComboMarketOrder(symbol, quantity, time, groupOrderManager, tag, properties);
473  break;
474 
475  default:
476  throw new ArgumentOutOfRangeException();
477  }
478  order.Status = OrderStatus.New;
479  order.Id = orderId;
480  return order;
481  }
482  }
483 }