/* * 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.Generic; namespace QuantConnect.Securities.Positions { /// /// Provides an implementation of that places all positions into a default group of one security. /// public class SecurityPositionGroupResolver : IPositionGroupResolver { private readonly IPositionGroupBuyingPowerModel _buyingPowerModel; /// /// Initializes a new instance of the class /// /// The buying power model to use for created groups public SecurityPositionGroupResolver(IPositionGroupBuyingPowerModel buyingPowerModel) { _buyingPowerModel = buyingPowerModel; } /// /// Attempts to group the specified positions into a new using an /// appropriate for position groups created via this /// resolver. /// /// The positions to be grouped /// The currently grouped positions /// The grouped positions when this resolver is able to, otherwise null /// True if this resolver can group the specified positions, otherwise false public bool TryGroup(IReadOnlyCollection newPositions, PositionGroupCollection currentPositions, out IPositionGroup group) { // we can only create default groupings containing a single security if (newPositions.Count != 1) { group = null; return false; } var key = new PositionGroupKey(_buyingPowerModel, newPositions); var position = newPositions.First(); group = new PositionGroup(key, position.GetGroupQuantity(), newPositions.ToDictionary(p => p.Symbol)); return true; } /// /// Resolves the position groups that exist within the specified collection of positions. /// /// The collection of positions /// An enumerable of position groups public PositionGroupCollection Resolve(PositionCollection positions) { var result = new PositionGroupCollection(positions .Select(position => new PositionGroup(_buyingPowerModel, position.GetGroupQuantity(), position)).ToList() ); positions.Clear(); return result; } /// /// Determines the position groups that would be evaluated for grouping of the specified /// positions were passed into the method. /// /// /// This function allows us to determine a set of impacted groups and run the resolver on just /// those groups in order to support what-if analysis /// /// The existing position groups /// The positions being changed /// An enumerable containing the position groups that could be impacted by the specified position changes public IEnumerable GetImpactedGroups( PositionGroupCollection groups, IReadOnlyCollection positions ) { var seen = new HashSet(); foreach (var position in positions) { IReadOnlyCollection groupsForSymbol; if (!groups.TryGetGroups(position.Symbol, out groupsForSymbol)) { continue; } foreach (var group in groupsForSymbol) { if (seen.Add(group.Key)) { yield return group; } } } } } }