Lean  $LEAN_TAG$
OptionStrategyDefinitionMatch.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 match of <see cref="OptionPosition"/> to a <see cref="OptionStrategyDefinition"/>
24  /// </summary>
25  public class OptionStrategyDefinitionMatch : IEquatable<OptionStrategyDefinitionMatch>
26  {
27  /// <summary>
28  /// The <see cref="OptionStrategyDefinition"/> matched
29  /// </summary>
31 
32  /// <summary>
33  /// The number of times the definition is able to match the available positions.
34  /// Since definitions are formed at the 'unit' level, such as having 1 contract,
35  /// the multiplier defines how many times the definition matched. This multiplier
36  /// is used to scale the quantity defined in each leg definition when creating the
37  /// <see cref="OptionStrategy"/> objects.
38  /// </summary>
39  public int Multiplier { get; }
40 
41  /// <summary>
42  /// The <see cref="OptionStrategyLegDefinitionMatch"/> instances matched to the definition.
43  /// </summary>
44  public IReadOnlyList<OptionStrategyLegDefinitionMatch> Legs { get; }
45 
46  /// <summary>
47  /// Initializes a new instance of the <see cref="OptionStrategyDefinitionMatch"/> class
48  /// </summary>
50  OptionStrategyDefinition definition,
51  IReadOnlyList<OptionStrategyLegDefinitionMatch> legs,
52  int multiplier
53  )
54  {
55  Legs = legs;
56  Multiplier = multiplier;
57  Definition = definition;
58  }
59 
60  /// <summary>
61  /// Deducts the matched positions from the specified <paramref name="positions"/> taking into account the multiplier
62  /// </summary>
64  {
65  var optionPositions = Legs.Select(leg => leg.CreateOptionPosition(Multiplier));
66  if (Definition.UnderlyingLots != 0)
67  {
68  optionPositions = optionPositions.Concat(new[]
69  {
70  new OptionPosition(Legs[0].Position.Symbol.Underlying, Definition.UnderlyingLots * Multiplier)
71  });
72  }
73  return positions.RemoveRange(optionPositions);
74  }
75 
76  /// <summary>
77  /// Creates the <see cref="OptionStrategy"/> instance this match represents
78  /// </summary>
80  {
81  var legs = Legs.Select(leg => leg.CreateOptionStrategyLeg(Multiplier));
82  var strategy = new OptionStrategy {
83  Name = Definition.Name,
84  Underlying = Legs[0].Position.Underlying
85  };
86 
87  foreach (var optionLeg in legs)
88  {
89  optionLeg.Invoke(strategy.UnderlyingLegs.Add, strategy.OptionLegs.Add);
90  }
91 
92  if (Definition.UnderlyingLots != 0)
93  {
94  strategy.UnderlyingLegs = new List<OptionStrategy.UnderlyingLegData>
95  {
97  };
98  }
99 
100  return strategy;
101  }
102 
103  /// <summary>Indicates whether the current object is equal to another object of the same type.</summary>
104  /// <param name="other">An object to compare with this object.</param>
105  /// <returns>true if the current object is equal to the <paramref name="other" /> parameter; otherwise, false.</returns>
107  {
108  if (ReferenceEquals(null, other))
109  {
110  return false;
111  }
112 
113  if (ReferenceEquals(this, other))
114  {
115  return true;
116  }
117 
118  if (!Equals(Definition, other.Definition))
119  {
120  return false;
121  }
122 
123  // index legs by OptionPosition so we can do the equality while ignoring ordering
124  var positions = other.Legs.ToDictionary(leg => leg.Position, leg => leg.Multiplier);
125  foreach (var leg in other.Legs)
126  {
127  int multiplier;
128  if (!positions.TryGetValue(leg.Position, out multiplier))
129  {
130  return false;
131  }
132 
133  if (leg.Multiplier != multiplier)
134  {
135  return false;
136  }
137  }
138 
139  return true;
140  }
141 
142  /// <summary>Determines whether the specified object is equal to the current object.</summary>
143  /// <param name="obj">The object to compare with the current object. </param>
144  /// <returns>true if the specified object is equal to the current object; otherwise, false.</returns>
145  public override bool Equals(object obj)
146  {
147  if (ReferenceEquals(null, obj))
148  {
149  return false;
150  }
151 
152  if (ReferenceEquals(this, obj))
153  {
154  return true;
155  }
156 
157  if (obj.GetType() != GetType())
158  {
159  return false;
160  }
161 
163  }
164 
165  /// <summary>Serves as the default hash function. </summary>
166  /// <returns>A hash code for the current object.</returns>
167  public override int GetHashCode()
168  {
169  unchecked
170  {
171  // we want to ensure that the ordering of legs does not impact equality operators in
172  // pursuit of this, we compute the hash codes of each leg, placing them into an array
173  // and then sort the array. using the sorted array, aggregates the hash codes
174 
175  var hashCode = Definition.GetHashCode();
176  var arr = new int[Legs.Count];
177  for (int i = 0; i < Legs.Count; i++)
178  {
179  arr[i] = Legs[i].GetHashCode();
180  }
181 
182  Array.Sort(arr);
183 
184  for (int i = 0; i < arr.Length; i++)
185  {
186  hashCode = (hashCode * 397) ^ arr[i];
187  }
188 
189  return hashCode;
190  }
191  }
192 
193  /// <summary>Returns a string that represents the current object.</summary>
194  /// <returns>A string that represents the current object.</returns>
195  public override string ToString()
196  {
197  return $"{Definition.Name}: {string.Join("|", Legs.Select(leg => leg.Position))}";
198  }
199 
200  /// <summary>
201  /// OptionStrategyDefinitionMatch == Operator
202  /// </summary>
203  /// <returns>True if they are the same</returns>
205  {
206  return Equals(left, right);
207  }
208 
209  /// <summary>
210  /// OptionStrategyDefinitionMatch != Operator
211  /// </summary>
212  /// <returns>True if they are not the same</returns>
214  {
215  return !Equals(left, right);
216  }
217  }
218 }