Lean  $LEAN_TAG$
CancelPendingOrders.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 using System.Collections.Concurrent;
16 using QuantConnect.Orders;
17 
19 {
20  /// <summary>
21  /// Class used to keep track of CancelPending orders and their original or updated status
22  /// </summary>
23  public class CancelPendingOrders
24  {
25  private readonly ConcurrentDictionary<int, CancelPendingOrder> _cancelPendingOrders = new ConcurrentDictionary<int, CancelPendingOrder>();
26 
27  /// <summary>
28  /// Amount of CancelPending Orders
29  /// </summary>
30  public int GetCancelPendingOrdersSize => _cancelPendingOrders.Count;
31 
32  /// <summary>
33  /// Adds an order which will be canceled and we want to keep track of it Status in case of fallback
34  /// </summary>
35  /// <param name="orderId">The order id</param>
36  /// <param name="status">The order Status, before the cancel request</param>
37  public void Set(int orderId, OrderStatus status)
38  {
39  _cancelPendingOrders[orderId] = new CancelPendingOrder { Status = status };
40  }
41 
42  /// <summary>
43  /// Updates an order that is pending to be canceled.
44  /// </summary>
45  /// <param name="newStatus">The new status of the order. If its OrderStatus.Canceled or OrderStatus.Filled it will be removed</param>
46  /// <param name="orderId">The id of the order</param>
47  public void UpdateOrRemove(int orderId, OrderStatus newStatus)
48  {
49  CancelPendingOrder cancelPendingOrder;
50  if (_cancelPendingOrders.TryGetValue(orderId, out cancelPendingOrder))
51  {
52  // The purpose of this pattern 'trygetvalue/lock/if containskey' is to guarantee that threads working on the same order will be correctly synchronized
53  // Thread 1 at HandleCancelOrderRequest() processing a failed cancel request will call RemoveAndFallback() and revert order status
54  // Thread 2 at HandleOrderEvent() with a filled order event will call UpdateOrRemove() and remove the order, ignoring its 'saved' status.
55  lock (cancelPendingOrder)
56  {
57  if (newStatus.IsClosed())
58  {
59  RemoveOrderFromCollection(orderId);
60  }
61  else if (newStatus != OrderStatus.CancelPending)
62  {
63  // check again because it might of been removed by the failed to cancel event
64  if (_cancelPendingOrders.ContainsKey(orderId))
65  {
66  _cancelPendingOrders[orderId].Status = newStatus;
67  }
68  }
69  }
70  }
71  }
72 
73  /// <summary>
74  /// Removes an order which we failed to cancel and falls back the order Status to previous value
75  /// </summary>
76  /// <param name="order">The order that failed to be canceled</param>
77  public void RemoveAndFallback(Order order)
78  {
79  CancelPendingOrder cancelPendingOrder;
80  if (_cancelPendingOrders.TryGetValue(order.Id, out cancelPendingOrder))
81  {
82  // The purpose of this pattern 'trygetvalue/lock/if containskey' is to guarantee that threads working on the same order will be correctly synchronized
83  // Thread 1 at HandleCancelOrderRequest() processing a failed cancel request will call RemoveAndFallback() and revert order status
84  // Thread 2 at HandleOrderEvent() with a filled order event will call UpdateOrRemove() and remove the order, ignoring its 'saved' status.
85  lock (cancelPendingOrder)
86  {
87  if (_cancelPendingOrders.ContainsKey(order.Id))
88  {
89  // update Status before removing from _cancelPendingOrders
90  order.Status = _cancelPendingOrders[order.Id].Status;
91  RemoveOrderFromCollection(order.Id);
92  }
93  }
94  }
95  }
96 
97  private void RemoveOrderFromCollection(int orderId)
98  {
99  CancelPendingOrder cancelPendingOrderTrash;
100  _cancelPendingOrders.TryRemove(orderId, out cancelPendingOrderTrash);
101  }
102 
103  private class CancelPendingOrder
104  {
105  public OrderStatus Status { get; set; }
106  }
107  }
108 }