/* * QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals. * Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ using System.Linq; using System.Collections; using System.Collections.Generic; namespace QuantConnect.Securities.Positions { /// /// Provides a collection type for /// public class PositionGroupCollection : IReadOnlyCollection { /// /// Gets an empty instance of the class /// public static PositionGroupCollection Empty => new(new Dictionary(), new Dictionary>()); /// /// Gets the number of positions in this group /// public int Count => _groups.Count; /// /// Gets whether or not this collection contains only default position groups /// public bool IsOnlyDefaultGroups { get { if (_hasNonDefaultGroups == null) { _hasNonDefaultGroups = _groups.Count == 0 || _groups.All(grp => grp.Key.IsDefaultGroup); } return _hasNonDefaultGroups.Value; } } /// /// Gets the position groups keys in this collection /// public IReadOnlyCollection Keys => _groups.Keys; /// /// Gets the position groups in this collection /// public IReadOnlyCollection Values => _groups.Values; private bool? _hasNonDefaultGroups; private readonly Dictionary _groups; private readonly Dictionary> _groupsBySymbol; internal IEnumerable> GetGroups() => _groups; /// /// Initializes a new instance of the class /// /// The position groups keyed by their group key /// The position groups keyed by the symbol of each position public PositionGroupCollection( Dictionary groups, Dictionary> groupsBySymbol ) { _groups = groups; _groupsBySymbol = groupsBySymbol; } /// /// Initializes a new instance of the class /// /// The position groups public PositionGroupCollection(IReadOnlyCollection groups) { _groups = new(); _groupsBySymbol = new(); foreach (var group in groups) { Add(group); } } /// /// Creates a new that contains all of the position groups /// in this collection in addition to the specified . If a group with the /// same key already exists then it is overwritten. /// public PositionGroupCollection Add(IPositionGroup group) { foreach (var position in group) { if (!_groupsBySymbol.TryGetValue(position.Symbol, out var groups)) { _groupsBySymbol[position.Symbol] = groups = new(); } groups.Add(group); } _groups[group.Key] = group; return this; } /// /// Determines whether or not a group with the specified key exists in this collection /// /// The group key to search for /// True if a group with the specified key was found, false otherwise public bool Contains(PositionGroupKey key) { return _groups.ContainsKey(key); } /// /// Gets the matching the specified key. If one does not exist, then an empty /// group is returned matching the unit quantities defined in the /// /// The position group key to search for /// The position group matching the specified key, or a new empty group if no matching group is found. public IPositionGroup this[PositionGroupKey key] { get { IPositionGroup group; if (!TryGetGroup(key, out group)) { return new PositionGroup(key, 0m, key.CreateEmptyPositions()); } return group; } } /// /// Attempts to retrieve the group with the specified key /// /// The group key to search for /// The position group /// True if group with key found, otherwise false public bool TryGetGroup(PositionGroupKey key, out IPositionGroup group) { return _groups.TryGetValue(key, out group); } /// /// Attempts to retrieve all groups that contain the provided symbol /// /// The symbol /// The groups if any were found, otherwise null /// True if groups were found for the specified symbol, otherwise false public bool TryGetGroups(Symbol symbol, out IReadOnlyCollection groups) { HashSet list; if (_groupsBySymbol.TryGetValue(symbol, out list) && list?.Count > 0) { groups = list; return true; } groups = null; return false; } /// /// Merges this position group collection with the provided collection. /// public PositionGroupCollection CombineWith(PositionGroupCollection other) { if(other.Count == 0) { return this; } if (Count == 0) { return other; } var result = this; foreach (var positionGroup in other) { result = result.Add(positionGroup); } return result; } /// Returns an enumerator that iterates through the collection. /// An enumerator that can be used to iterate through the collection. public IEnumerator GetEnumerator() { return _groups.Values.GetEnumerator(); } /// Returns an enumerator that iterates through a collection. /// An object that can be used to iterate through the collection. IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } } }