/* * 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; using System; using QuantConnect.Securities.Option; namespace QuantConnect.Securities.Positions { /// /// Provides a default implementation of /// public class PositionGroup : IPositionGroup { /// /// Gets the number of positions in the group /// public int Count => _positions.Count; /// /// Gets the key identifying this group /// public PositionGroupKey Key { get; } /// /// Gets the whole number of units in this position group /// public decimal Quantity { get; } /// /// Gets the positions in this group /// public IEnumerable Positions => _positions.Values; /// /// Gets the buying power model defining how margin works in this group /// public IPositionGroupBuyingPowerModel BuyingPowerModel => Key.BuyingPowerModel; private readonly Dictionary _positions; /// /// Initializes a new instance of the class /// /// The buying power model to use for this group /// The group quantity, which must be the ratio of quantity to unit quantity of each position /// The positions comprising this group /// Thrown when the quantity is not the ratio of quantity to unit quantity of each position public PositionGroup(IPositionGroupBuyingPowerModel buyingPowerModel, decimal quantity, params IPosition[] positions) : this(new PositionGroupKey(buyingPowerModel, positions), quantity, positions.ToDictionary(p => p.Symbol)) { } /// /// Initializes a new instance of the class /// /// The deterministic key for this group /// The group quantity, which must be the ratio of quantity to unit quantity of each position /// The positions comprising this group /// Thrown when the quantity is not the ratio of quantity to unit quantity of each position public PositionGroup(PositionGroupKey key, decimal quantity, params IPosition[] positions) : this(key, quantity, positions.ToDictionary(p => p.Symbol)) { } /// /// Initializes a new instance of the class /// /// The deterministic key for this group /// The group quantity, which must be the ratio of quantity to unit quantity of each position /// The positions comprising this group /// Thrown when the quantity is not the ratio of quantity to unit quantity of each position public PositionGroup(PositionGroupKey key, decimal quantity, Dictionary positions) { Key = key; Quantity = quantity; _positions = positions; #if DEBUG if (positions.Any(kvp => Math.Abs(kvp.Value.Quantity / kvp.Value.UnitQuantity) != Math.Abs(Quantity))) { throw new ArgumentException(Messages.PositionGroup.InvalidQuantity(Quantity, positions.Values)); } #endif } /// /// Attempts to retrieve the position with the specified symbol /// /// The symbol /// The position, if found /// True if the position was found, otherwise false public bool TryGetPosition(Symbol symbol, out IPosition position) { return _positions.TryGetValue(symbol, out position); } /// Returns a string that represents the current object. /// A string that represents the current object. public override string ToString() { return $"{Key}: {Quantity}"; } /// Returns an enumerator that iterates through the collection. /// An enumerator that can be used to iterate through the collection. public IEnumerator GetEnumerator() { return Positions.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(); } /// /// Instantiates a default empty position group instance /// /// The buying power model to use for this group public static PositionGroup Empty(IPositionGroupBuyingPowerModel buyingPowerModel) { return new PositionGroup(new PositionGroupKey(buyingPowerModel, new List()), 0m); } } }