Lean  $LEAN_TAG$
PositionGroupKey.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;
17 using System.Linq;
18 using System.Collections.Generic;
19 
21 {
22  /// <summary>
23  /// Defines a unique and deterministic key for <see cref="IPositionGroup"/>
24  /// </summary>
25  public sealed class PositionGroupKey : IEquatable<PositionGroupKey>
26  {
27  /// <summary>
28  /// Gets whether or not this key defines a default group
29  /// </summary>
30  public bool IsDefaultGroup { get; }
31 
32  /// <summary>
33  /// Gets the <see cref="IPositionGroupBuyingPowerModel"/> being used by the group
34  /// </summary>
36 
37  /// <summary>
38  /// Gets the unit quantities defining the ratio between position quantities in the group
39  /// </summary>
40  public IReadOnlyList<Tuple<Symbol, decimal>> UnitQuantities { get; }
41 
42  /// <summary>
43  /// Initializes a new instance of the <see cref="PositionGroupKey"/> class for groups with a single security
44  /// </summary>
45  /// <param name="buyingPowerModel">The group's buying power model</param>
46  /// <param name="security">The security</param>
47  public PositionGroupKey(IPositionGroupBuyingPowerModel buyingPowerModel, Security security)
48  {
49  IsDefaultGroup = buyingPowerModel.GetType() == typeof(SecurityPositionGroupBuyingPowerModel);
50  BuyingPowerModel = buyingPowerModel;
51  UnitQuantities = new[]
52  {
53  Tuple.Create(security.Symbol, security.SymbolProperties.LotSize)
54  };
55  }
56 
57  /// <summary>
58  /// Initializes a new instance of the <see cref="PositionGroupKey"/> class
59  /// </summary>
60  /// <param name="buyingPowerModel">The group's buying power model</param>
61  /// <param name="positions">The positions comprising the group</param>
62  public PositionGroupKey(IPositionGroupBuyingPowerModel buyingPowerModel, IReadOnlyCollection<IPosition> positions)
63  {
64  BuyingPowerModel = buyingPowerModel;
65  if(positions.Count == 1)
66  {
67  var position = positions.First();
68  UnitQuantities = new[]
69  {
70  Tuple.Create(position.Symbol, position.UnitQuantity)
71  };
72  }
73  else
74  {
75  // these have to be sorted for determinism
76  UnitQuantities = positions.OrderBy(x => x.Symbol).Select(p => Tuple.Create(p.Symbol, p.UnitQuantity)).ToList();
77  }
79  }
80 
81  /// <summary>
82  /// Creates a new array of empty positions with unit quantities according to this key
83  /// </summary>
85  {
86  var positions = new IPosition[UnitQuantities.Count];
87  for (var i = 0; i < UnitQuantities.Count; i++)
88  {
89  var unitQuantity = UnitQuantities[i];
90  positions[i] = new Position(unitQuantity.Item1, 0m, unitQuantity.Item2);
91  }
92  return positions;
93  }
94 
95  /// <summary>Indicates whether the current object is equal to another object of the same type.</summary>
96  /// <param name="other">An object to compare with this object.</param>
97  /// <returns>true if the current object is equal to the <paramref name="other" /> parameter; otherwise, false.</returns>
98  public bool Equals(PositionGroupKey other)
99  {
100  if (ReferenceEquals(null, other))
101  {
102  return false;
103  }
104 
105  if (ReferenceEquals(this, other))
106  {
107  return true;
108  }
109 
110  return BuyingPowerModel.Equals(other.BuyingPowerModel)
111  && UnitQuantities.ListEquals(other.UnitQuantities);
112  }
113 
114  /// <summary>Determines whether the specified object is equal to the current object.</summary>
115  /// <param name="obj">The object to compare with the current object. </param>
116  /// <returns>true if the specified object is equal to the current object; otherwise, false.</returns>
117  public override bool Equals(object obj)
118  {
119  if (ReferenceEquals(null, obj))
120  {
121  return false;
122  }
123 
124  if (ReferenceEquals(this, obj))
125  {
126  return true;
127  }
128 
129  return obj is PositionGroupKey && Equals((PositionGroupKey) obj);
130  }
131 
132  /// <summary>Serves as the default hash function. </summary>
133  /// <returns>A hash code for the current object.</returns>
134  public override int GetHashCode()
135  {
136  unchecked
137  {
138  return (BuyingPowerModel.GetHashCode() * 397) ^ UnitQuantities.GetListHashCode();
139  }
140  }
141 
142  /// <summary>Returns a string that represents the current object.</summary>
143  /// <returns>A string that represents the current object.</returns>
144  public override string ToString()
145  {
146  return $"{string.Join("|", UnitQuantities.Select(x => $"{x.Item1}:{x.Item2.Normalize()}"))}";
147  }
148 
149  /// <summary>
150  /// Equals operator
151  /// </summary>
152  public static bool operator ==(PositionGroupKey left, PositionGroupKey right)
153  {
154  return Equals(left, right);
155  }
156 
157  /// <summary>
158  /// Not equals operator
159  /// </summary>
160  public static bool operator !=(PositionGroupKey left, PositionGroupKey right)
161  {
162  return !Equals(left, right);
163  }
164  }
165 }