/*
* 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;
}
}
}
}
}
}