Lean  $LEAN_TAG$
GroupOrderCacheManager.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.Collections.Generic;
17 using System.Collections.Concurrent;
18 
19 namespace QuantConnect.Orders
20 {
21  /// <summary>
22  /// Provides a thread-safe service for caching and managing original orders when they are part of a group.
23  /// </summary>
25  {
26  /// <summary>
27  /// A thread-safe dictionary that caches original orders when they are part of a group.
28  /// </summary>
29  /// <remarks>
30  /// The dictionary uses the order ID as the key and stores the original <see cref="Order"/> objects as values.
31  /// This allows for the modification of the original orders, such as setting the brokerage ID,
32  /// without retrieving a cloned instance from the order provider.
33  /// </remarks>
34  private readonly ConcurrentDictionary<int, Order> _pendingGroupOrders = new();
35 
36  /// <summary>
37  /// Attempts to retrieve all the orders in the combo group from the cache.
38  /// </summary>
39  /// <param name="order">Target order, which can be any of the legs of the combo</param>
40  /// <param name="orders">List of orders in the combo</param>
41  /// <returns>
42  /// <c>true</c> if all the orders in the combo group were successfully retrieved from the cache;
43  /// otherwise, <c>false</c>. If the retrieval fails, the target order is cached for future retrieval.
44  /// </returns>
45  public bool TryGetGroupCachedOrders(Order order, out List<Order> orders)
46  {
47  if (!order.TryGetGroupOrders(TryGetOrder, out orders))
48  {
49  // some order of the group is missing but cache the new one
50  CacheOrder(order);
51  return false;
52  }
53  RemoveCachedOrders(orders);
54  return true;
55  }
56 
57  /// <summary>
58  /// Attempts to retrieve an original order from the cache using the specified order ID.
59  /// </summary>
60  /// <param name="orderId">The unique identifier of the order to retrieve.</param>
61  /// <returns>
62  /// The original <see cref="Order"/> if found; otherwise, <c>null</c>.
63  /// </returns>
64  private Order TryGetOrder(int orderId)
65  {
66  _pendingGroupOrders.TryGetValue(orderId, out var order);
67  return order;
68  }
69 
70  /// <summary>
71  /// Caches an original order in the internal dictionary for future retrieval.
72  /// </summary>
73  /// <param name="order">The <see cref="Order"/> object to cache.</param>
74  private void CacheOrder(Order order)
75  {
76  _pendingGroupOrders[order.Id] = order;
77  }
78 
79  /// <summary>
80  /// Removes a list of orders from the internal cache.
81  /// </summary>
82  /// <param name="orders">The list of <see cref="Order"/> objects to remove from the cache.</param>
83  private void RemoveCachedOrders(List<Order> orders)
84  {
85  for (var i = 0; i < orders.Count; i++)
86  {
87  _pendingGroupOrders.TryRemove(orders[i].Id, out _);
88  }
89  }
90  }
91 }