Lean  $LEAN_TAG$
PositionGroup.cs
1 /*
2  * QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
3  * Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14 */
15 
16 using System.Linq;
17 using System.Collections;
18 using System.Collections.Generic;
19 using System;
21 
23 {
24  /// <summary>
25  /// Provides a default implementation of <see cref="IPositionGroup"/>
26  /// </summary>
28  {
29  /// <summary>
30  /// Gets the number of positions in the group
31  /// </summary>
32  public int Count => _positions.Count;
33 
34  /// <summary>
35  /// Gets the key identifying this group
36  /// </summary>
37  public PositionGroupKey Key { get; }
38 
39  /// <summary>
40  /// Gets the whole number of units in this position group
41  /// </summary>
42  public decimal Quantity { get; }
43 
44  /// <summary>
45  /// Gets the positions in this group
46  /// </summary>
47  public IEnumerable<IPosition> Positions => _positions.Values;
48 
49  /// <summary>
50  /// Gets the buying power model defining how margin works in this group
51  /// </summary>
53 
54  private readonly Dictionary<Symbol, IPosition> _positions;
55 
56  /// <summary>
57  /// Initializes a new instance of the <see cref="PositionGroup"/> class
58  /// </summary>
59  /// <param name="buyingPowerModel">The buying power model to use for this group</param>
60  /// <param name="quantity">The group quantity, which must be the ratio of quantity to unit quantity of each position</param>
61  /// <param name="positions">The positions comprising this group</param>
62  /// <exception cref="ArgumentException">Thrown when the quantity is not the ratio of quantity to unit quantity of each position</exception>
63  public PositionGroup(IPositionGroupBuyingPowerModel buyingPowerModel, decimal quantity, params IPosition[] positions)
64  : this(new PositionGroupKey(buyingPowerModel, positions), quantity, positions.ToDictionary(p => p.Symbol))
65  {
66  }
67 
68  /// <summary>
69  /// Initializes a new instance of the <see cref="PositionGroup"/> class
70  /// </summary>
71  /// <param name="key">The deterministic key for this group</param>
72  /// <param name="quantity">The group quantity, which must be the ratio of quantity to unit quantity of each position</param>
73  /// <param name="positions">The positions comprising this group</param>
74  /// <exception cref="ArgumentException">Thrown when the quantity is not the ratio of quantity to unit quantity of each position</exception>
75  public PositionGroup(PositionGroupKey key, decimal quantity, params IPosition[] positions)
76  : this(key, quantity, positions.ToDictionary(p => p.Symbol))
77  {
78  }
79 
80  /// <summary>
81  /// Initializes a new instance of the <see cref="PositionGroup"/> class
82  /// </summary>
83  /// <param name="key">The deterministic key for this group</param>
84  /// <param name="quantity">The group quantity, which must be the ratio of quantity to unit quantity of each position</param>
85  /// <param name="positions">The positions comprising this group</param>
86  /// <exception cref="ArgumentException">Thrown when the quantity is not the ratio of quantity to unit quantity of each position</exception>
87  public PositionGroup(PositionGroupKey key, decimal quantity, Dictionary<Symbol, IPosition> positions)
88  {
89  Key = key;
90  Quantity = quantity;
91  _positions = positions;
92 
93 #if DEBUG
94  if (positions.Any(kvp => Math.Abs(kvp.Value.Quantity / kvp.Value.UnitQuantity) != Math.Abs(Quantity)))
95  {
96  throw new ArgumentException(Messages.PositionGroup.InvalidQuantity(Quantity, positions.Values));
97  }
98 #endif
99  }
100 
101  /// <summary>
102  /// Attempts to retrieve the position with the specified symbol
103  /// </summary>
104  /// <param name="symbol">The symbol</param>
105  /// <param name="position">The position, if found</param>
106  /// <returns>True if the position was found, otherwise false</returns>
107  public bool TryGetPosition(Symbol symbol, out IPosition position)
108  {
109  return _positions.TryGetValue(symbol, out position);
110  }
111 
112  /// <summary>Returns a string that represents the current object.</summary>
113  /// <returns>A string that represents the current object.</returns>
114  public override string ToString()
115  {
116  return $"{Key}: {Quantity}";
117  }
118 
119  /// <summary>Returns an enumerator that iterates through the collection.</summary>
120  /// <returns>An enumerator that can be used to iterate through the collection.</returns>
121  public IEnumerator<IPosition> GetEnumerator()
122  {
123  return Positions.GetEnumerator();
124  }
125 
126  /// <summary>Returns an enumerator that iterates through a collection.</summary>
127  /// <returns>An <see cref="T:System.Collections.IEnumerator" /> object that can be used to iterate through the collection.</returns>
128  IEnumerator IEnumerable.GetEnumerator()
129  {
130  return GetEnumerator();
131  }
132 
133  /// <summary>
134  /// Instantiates a default empty position group instance
135  /// </summary>
136  /// <param name="buyingPowerModel">The buying power model to use for this group</param>
137  public static PositionGroup Empty(IPositionGroupBuyingPowerModel buyingPowerModel)
138  {
139  return new PositionGroup(new PositionGroupKey(buyingPowerModel, new List<IPosition>()), 0m);
140  }
141  }
142 }