Lean  $LEAN_TAG$
PositionGroupCollection.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.Linq;
17 using System.Collections;
18 using System.Collections.Generic;
19 
21 {
22  /// <summary>
23  /// Provides a collection type for <see cref="IPositionGroup"/>
24  /// </summary>
25  public class PositionGroupCollection : IReadOnlyCollection<IPositionGroup>
26  {
27  /// <summary>
28  /// Gets an empty instance of the <see cref="PositionGroupCollection"/> class
29  /// </summary>
30  public static PositionGroupCollection Empty => new(new Dictionary<PositionGroupKey, IPositionGroup>(), new Dictionary<Symbol, HashSet<IPositionGroup>>());
31 
32  /// <summary>
33  /// Gets the number of positions in this group
34  /// </summary>
35  public int Count => _groups.Count;
36 
37  /// <summary>
38  /// Gets whether or not this collection contains only default position groups
39  /// </summary>
40  public bool IsOnlyDefaultGroups
41  {
42  get
43  {
44  if (_hasNonDefaultGroups == null)
45  {
46  _hasNonDefaultGroups = _groups.Count == 0 || _groups.All(grp => grp.Key.IsDefaultGroup);
47  }
48 
49  return _hasNonDefaultGroups.Value;
50  }
51  }
52 
53  private bool? _hasNonDefaultGroups;
54  private readonly Dictionary<PositionGroupKey, IPositionGroup> _groups;
55  private readonly Dictionary<Symbol, HashSet<IPositionGroup>> _groupsBySymbol;
56 
57  /// <summary>
58  /// Initializes a new instance of the <see cref="PositionGroupCollection"/> class
59  /// </summary>
60  /// <param name="groups">The position groups keyed by their group key</param>
61  /// <param name="groupsBySymbol">The position groups keyed by the symbol of each position</param>
63  Dictionary<PositionGroupKey, IPositionGroup> groups,
64  Dictionary<Symbol, HashSet<IPositionGroup>> groupsBySymbol
65  )
66  {
67  _groups = groups;
68  _groupsBySymbol = groupsBySymbol;
69  }
70 
71  /// <summary>
72  /// Initializes a new instance of the <see cref="PositionGroupCollection"/> class
73  /// </summary>
74  /// <param name="groups">The position groups</param>
75  public PositionGroupCollection(IReadOnlyCollection<IPositionGroup> groups)
76  {
77  _groups = new();
78  _groupsBySymbol = new();
79  foreach (var group in groups)
80  {
81  Add(group);
82  }
83  }
84 
85  /// <summary>
86  /// Creates a new <see cref="PositionGroupCollection"/> that contains all of the position groups
87  /// in this collection in addition to the specified <paramref name="group"/>. If a group with the
88  /// same key already exists then it is overwritten.
89  /// </summary>
91  {
92  foreach (var position in group)
93  {
94  if (!_groupsBySymbol.TryGetValue(position.Symbol, out var groups))
95  {
96  _groupsBySymbol[position.Symbol] = groups = new();
97  }
98  groups.Add(group);
99  }
100  _groups[group.Key] = group;
101 
102  return this;
103  }
104 
105  /// <summary>
106  /// Determines whether or not a group with the specified key exists in this collection
107  /// </summary>
108  /// <param name="key">The group key to search for</param>
109  /// <returns>True if a group with the specified key was found, false otherwise</returns>
110  public bool Contains(PositionGroupKey key)
111  {
112  return _groups.ContainsKey(key);
113  }
114 
115  /// <summary>
116  /// Gets the <see cref="IPositionGroup"/> matching the specified key. If one does not exist, then an empty
117  /// group is returned matching the unit quantities defined in the <paramref name="key"/>
118  /// </summary>
119  /// <param name="key">The position group key to search for</param>
120  /// <returns>The position group matching the specified key, or a new empty group if no matching group is found.</returns>
121  public IPositionGroup this[PositionGroupKey key]
122  {
123  get
124  {
125  IPositionGroup group;
126  if (!TryGetGroup(key, out group))
127  {
128  return new PositionGroup(key, 0m, key.CreateEmptyPositions());
129  }
130 
131  return group;
132  }
133  }
134 
135  /// <summary>
136  /// Attempts to retrieve the group with the specified key
137  /// </summary>
138  /// <param name="key">The group key to search for</param>
139  /// <param name="group">The position group</param>
140  /// <returns>True if group with key found, otherwise false</returns>
141  public bool TryGetGroup(PositionGroupKey key, out IPositionGroup group)
142  {
143  return _groups.TryGetValue(key, out group);
144  }
145 
146  /// <summary>
147  /// Attempts to retrieve all groups that contain the provided symbol
148  /// </summary>
149  /// <param name="symbol">The symbol</param>
150  /// <param name="groups">The groups if any were found, otherwise null</param>
151  /// <returns>True if groups were found for the specified symbol, otherwise false</returns>
152  public bool TryGetGroups(Symbol symbol, out IReadOnlyCollection<IPositionGroup> groups)
153  {
154  HashSet<IPositionGroup> list;
155  if (_groupsBySymbol.TryGetValue(symbol, out list) && list?.Count > 0)
156  {
157  groups = list;
158  return true;
159  }
160 
161  groups = null;
162  return false;
163  }
164 
165  /// <summary>
166  /// Merges this position group collection with the provided <paramref name="other"/> collection.
167  /// </summary>
169  {
170  if(other.Count == 0)
171  {
172  return this;
173  }
174  if (Count == 0)
175  {
176  return other;
177  }
178 
179  var result = this;
180  foreach (var positionGroup in other)
181  {
182  result = result.Add(positionGroup);
183  }
184 
185  return result;
186  }
187 
188  /// <summary>Returns an enumerator that iterates through the collection.</summary>
189  /// <returns>An enumerator that can be used to iterate through the collection.</returns>
190  public IEnumerator<IPositionGroup> GetEnumerator()
191  {
192  return _groups.Values.GetEnumerator();
193  }
194 
195  /// <summary>Returns an enumerator that iterates through a collection.</summary>
196  /// <returns>An <see cref="T:System.Collections.IEnumerator" /> object that can be used to iterate through the collection.</returns>
197  IEnumerator IEnumerable.GetEnumerator()
198  {
199  return GetEnumerator();
200  }
201  }
202 }