Lean  $LEAN_TAG$
OptionPosition.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 
19 {
20  /// <summary>
21  /// Defines a lightweight structure representing a position in an option contract or underlying.
22  /// This type is heavily utilized by the options strategy matcher and is the parameter type of
23  /// option strategy definition predicates. Underlying quantities should be represented in lot sizes,
24  /// which is equal to the quantity of shares divided by the contract's multiplier and then rounded
25  /// down towards zero (truncate)
26  /// </summary>
27  public struct OptionPosition : IEquatable<OptionPosition>
28  {
29  /// <summary>
30  /// Gets a new <see cref="OptionPosition"/> with zero <see cref="Quantity"/>
31  /// </summary>
32  public static OptionPosition Empty(Symbol symbol)
33  => new OptionPosition(symbol, 0);
34 
35  /// <summary>
36  /// Determines whether or not this position has any quantity
37  /// </summary>
38  public bool HasQuantity => Quantity != 0;
39 
40  /// <summary>
41  /// Determines whether or not this position is for the underlying symbol
42  /// </summary>
44 
45  /// <summary>
46  /// Number of contracts held, can be positive or negative
47  /// </summary>
48  public int Quantity { get; }
49 
50  /// <summary>
51  /// Option contract symbol
52  /// </summary>
53  public Symbol Symbol { get; }
54 
55  /// <summary>
56  /// Gets the underlying symbol. If this position represents the underlying,
57  /// then this property is the same as the <see cref="Symbol"/> property
58  /// </summary>
60 
61  /// <summary>
62  /// Option contract expiration date
63  /// </summary>
64  public DateTime Expiration
65  {
66  get
67  {
69  {
70  return Symbol.ID.Date;
71  }
72 
73  throw new InvalidOperationException($"{nameof(Expiration)} is not valid for underlying symbols: {Symbol}");
74  }
75  }
76 
77  /// <summary>
78  /// Option contract strike price
79  /// </summary>
80  public decimal Strike
81  {
82  get
83  {
85  {
86  return Symbol.ID.StrikePrice;
87  }
88 
89  throw new InvalidOperationException($"{nameof(Strike)} is not valid for underlying symbols: {Symbol}");
90  }
91  }
92 
93  /// <summary>
94  /// Option contract right (put/call)
95  /// </summary>
96  public OptionRight Right
97  {
98  get
99  {
100  if (Symbol.HasUnderlying)
101  {
102  return Symbol.ID.OptionRight;
103  }
104 
105  throw new InvalidOperationException($"{nameof(Right)} is not valid for underlying symbols: {Symbol}");
106  }
107  }
108 
109  /// <summary>
110  /// Gets whether this position is short/long/none
111  /// </summary>
112  public PositionSide Side => (PositionSide) Math.Sign(Quantity);
113 
114  /// <summary>
115  /// Initializes a new instance of the <see cref="OptionPosition"/> structure
116  /// </summary>
117  /// <param name="symbol">The option contract symbol</param>
118  /// <param name="quantity">The number of contracts held</param>
119  public OptionPosition(Symbol symbol, int quantity)
120  {
121  Symbol = symbol;
122  Quantity = quantity;
123  }
124 
125  /// <summary>
126  /// Creates a new <see cref="OptionPosition"/> instance with negative <see cref="Quantity"/>
127  /// </summary>
129  {
130  return new OptionPosition(Symbol, -Quantity);
131  }
132 
133  /// <summary>
134  /// Creates a new <see cref="OptionPosition"/> with this position's <see cref="Symbol"/>
135  /// and the provided <paramref name="quantity"/>
136  /// </summary>
137  public OptionPosition WithQuantity(int quantity)
138  {
139  return new OptionPosition(Symbol, quantity);
140  }
141 
142  /// <summary>Indicates whether the current object is equal to another object of the same type.</summary>
143  /// <param name="other">An object to compare with this object.</param>
144  /// <returns>true if the current object is equal to the <paramref name="other" /> parameter; otherwise, false.</returns>
145  public bool Equals(OptionPosition other)
146  {
147  return Equals(Symbol, other.Symbol) && Quantity == other.Quantity;
148  }
149 
150  /// <summary>Indicates whether this instance and a specified object are equal.</summary>
151  /// <param name="obj">The object to compare with the current instance. </param>
152  /// <returns>true if <paramref name="obj" /> and this instance are the same type and represent the same value; otherwise, false. </returns>
153  public override bool Equals(object obj)
154  {
155  if (ReferenceEquals(null, obj))
156  {
157  return false;
158  }
159 
160  if (obj.GetType() != GetType())
161  {
162  return false;
163  }
164 
165  return Equals((OptionPosition) obj);
166  }
167 
168  /// <summary>Returns the hash code for this instance.</summary>
169  /// <returns>A 32-bit signed integer that is the hash code for this instance.</returns>
170  public override int GetHashCode()
171  {
172  unchecked
173  {
174  return ((Symbol != null ? Symbol.GetHashCode() : 0) * 397) ^ Quantity;
175  }
176  }
177 
178  /// <summary>Returns the fully qualified type name of this instance.</summary>
179  /// <returns>The fully qualified type name.</returns>
180  public override string ToString()
181  {
182  var s = Quantity == 1 ? "" : "s";
183  if (Symbol.HasUnderlying)
184  {
185  return $"{Quantity} {Right.ToLower()}{s} on {Symbol.Underlying.Value} at ${Strike} expiring on {Expiration:yyyy-MM-dd}";
186  }
187 
188  return $"{Quantity} share{s} of {Symbol.Value}";
189  }
190 
191  /// <summary>
192  /// OptionPosition * Operator, will multiple quantity by given factor
193  /// </summary>
194  /// <param name="left">OptionPosition to operate on</param>
195  /// <param name="factor">Factor to multiply by</param>
196  /// <returns>Resulting OptionPosition</returns>
197  public static OptionPosition operator *(OptionPosition left, int factor)
198  {
199  return new OptionPosition(left.Symbol, factor * left.Quantity);
200  }
201 
202  /// <summary>
203  /// OptionPosition * Operator, will multiple quantity by given factor
204  /// </summary>
205  /// <param name="right">OptionPosition to operate on</param>
206  /// <param name="factor">Factor to multiply by</param>
207  /// <returns>Resulting OptionPosition</returns>
208  public static OptionPosition operator *(int factor, OptionPosition right)
209  {
210  return new OptionPosition(right.Symbol, factor * right.Quantity);
211  }
212 
213  /// <summary>
214  /// OptionPosition + Operator, will add quantities together if they are for the same symbol.
215  /// </summary>
216  /// <returns>Resulting OptionPosition</returns>
218  {
219  if (!Equals(left.Symbol, right.Symbol))
220  {
221  if (left == default(OptionPosition))
222  {
223  return right;
224  }
225 
226  if (right == default(OptionPosition))
227  {
228  return left;
229  }
230 
231  throw new InvalidOperationException("Unable to add OptionPosition instances with different symbols");
232  }
233 
234  return new OptionPosition(left.Symbol, left.Quantity + right.Quantity);
235  }
236 
237  /// <summary>
238  /// OptionPosition - Operator, will subtract left - right quantities if they are for the same symbol.
239  /// </summary>
240  /// <returns>Resulting OptionPosition</returns>
242  {
243  if (!Equals(left.Symbol, right.Symbol))
244  {
245  if (left == default(OptionPosition))
246  {
247  // 0 - right
248  return right.Negate();
249  }
250 
251  if (right == default(OptionPosition))
252  {
253  // left - 0
254  return left;
255  }
256 
257  throw new InvalidOperationException("Unable to subtract OptionPosition instances with different symbols");
258  }
259 
260  return new OptionPosition(left.Symbol, left.Quantity - right.Quantity);
261  }
262 
263  /// <summary>
264  /// Option Position == Operator
265  /// </summary>
266  /// <returns>True if they are the same</returns>
267  public static bool operator ==(OptionPosition left, OptionPosition right)
268  {
269  return Equals(left, right);
270  }
271 
272  /// <summary>
273  /// Option Position != Operator
274  /// </summary>
275  /// <returns>True if they are not the same</returns>
276  public static bool operator !=(OptionPosition left, OptionPosition right)
277  {
278  return !Equals(left, right);
279  }
280  }
281 }