/*
* 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;
using System.Linq;
using QuantConnect.Orders;
using System.Collections.Generic;
using System.Collections.Specialized;
namespace QuantConnect.Securities.Positions
{
///
/// Responsible for managing the resolution of position groups for an algorithm
///
public class SecurityPositionGroupModel : ExtendedDictionary
{
///
/// Gets an implementation of that will not group multiple securities
///
public static readonly SecurityPositionGroupModel Null = new NullSecurityPositionGroupModel();
private bool _requiresGroupResolution;
private SecurityManager _securities;
private PositionGroupCollection _groups;
private IPositionGroupResolver _resolver;
///
/// Get's the single security position group buying power model to use
///
protected virtual IPositionGroupBuyingPowerModel PositionGroupBuyingPowerModel { get; } = new SecurityPositionGroupBuyingPowerModel();
///
/// Gets the set of currently resolved position groups
///
public PositionGroupCollection Groups
{
get
{
ResolvePositionGroups();
return _groups;
}
private set
{
_groups = value;
}
}
///
/// Gets whether or not the algorithm is using only default position groups
///
public bool IsOnlyDefaultGroups => Groups.IsOnlyDefaultGroups;
///
/// Gets the number of position groups in this collection
///
public override int Count => Groups.Count;
///
/// Gets all the available position group keys
///
protected override IEnumerable GetKeys => Groups.Keys;
///
/// Gets all the available position groups
///
protected override IEnumerable GetValues => Groups.Values;
///
/// Gets all the items in the dictionary
///
/// All the items in the dictionary
public override IEnumerable> GetItems() => Groups.GetGroups();
///
/// Initializes a new instance of the class
///
/// The algorithm's security manager
public virtual void Initialize(SecurityManager securities)
{
_securities = securities;
Groups = PositionGroupCollection.Empty;
_resolver = GetPositionGroupResolver();
foreach (var security in _securities.Values)
{
// if any security already present let's wire the holdings change event
security.Holdings.QuantityChanged += HoldingsOnQuantityChanged;
}
// we must be notified each time our holdings change, so each time a security is added, we
// want to bind to its SecurityHolding.QuantityChanged event so we can trigger the resolver
securities.CollectionChanged += (sender, args) =>
{
var items = args.NewItems ?? new List