Lean  $LEAN_TAG$
ContractSecurityFilterUniverse.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 
17 using System;
18 using System.Linq;
19 using Python.Runtime;
20 using System.Collections;
21 using System.Collections.Generic;
22 
24 {
25  /// <summary>
26  /// Base class for contract symbols filtering universes.
27  /// Used by OptionFilterUniverse and FutureFilterUniverse
28  /// </summary>
31  {
32  /// <summary>
33  /// Defines listed contract types with Flags attribute
34  /// </summary>
35  [Flags]
36  protected enum ContractExpirationType : int
37  {
38  /// <summary>
39  /// Standard contracts
40  /// </summary>
41  Standard = 1,
42 
43  /// <summary>
44  /// Non standard weekly contracts
45  /// </summary>
46  Weekly = 2
47  }
48 
49  /// <summary>
50  /// Expiration Types allowed through the filter
51  /// Standards only by default
52  /// </summary>
53  protected ContractExpirationType Type = ContractExpirationType.Standard;
54 
55  /// <summary>
56  /// The local exchange current time
57  /// </summary>
58  public DateTime LocalTime { get; private set; }
59 
60  /// <summary>
61  /// All Symbols in this filter
62  /// Marked internal for use by extensions
63  /// </summary>
64  internal IEnumerable<Symbol> AllSymbols;
65 
66  /// <summary>
67  /// Constructs ContractSecurityFilterUniverse
68  /// </summary>
70  {
71  }
72 
73  /// <summary>
74  /// Constructs ContractSecurityFilterUniverse
75  /// </summary>
76  protected ContractSecurityFilterUniverse(IEnumerable<Symbol> allSymbols, DateTime localTime)
77  {
78  AllSymbols = allSymbols;
79  LocalTime = localTime;
80  Type = ContractExpirationType.Standard;
81  }
82 
83  /// <summary>
84  /// Function to determine if the given symbol is a standard contract
85  /// </summary>
86  /// <returns>True if standard type</returns>
87  protected abstract bool IsStandard(Symbol symbol);
88 
89  /// <summary>
90  /// Returns universe, filtered by contract type
91  /// </summary>
92  /// <returns>Universe with filter applied</returns>
93  internal T ApplyTypesFilter()
94  {
95  // memoization map for ApplyTypesFilter()
96  var memoizedMap = new Dictionary<DateTime, bool>();
97 
98  Func<Symbol, bool> memoizedIsStandardType = symbol =>
99  {
100  var dt = symbol.ID.Date;
101 
102  bool result;
103  if (memoizedMap.TryGetValue(dt, out result))
104  return result;
105  var res = IsStandard(symbol);
106  memoizedMap[dt] = res;
107 
108  return res;
109  };
110 
111  AllSymbols = AllSymbols.Where(x =>
112  {
113  switch (Type)
114  {
115  case ContractExpirationType.Weekly:
116  return !memoizedIsStandardType(x);
117  case ContractExpirationType.Standard:
118  return memoizedIsStandardType(x);
119  case ContractExpirationType.Standard | ContractExpirationType.Weekly:
120  return true;
121  default:
122  return false;
123  }
124  }).ToList();
125 
126  return (T) this;
127  }
128 
129  /// <summary>
130  /// Refreshes this filter universe
131  /// </summary>
132  /// <param name="allSymbols">All the contract symbols for the Universe</param>
133  /// <param name="localTime">The local exchange current time</param>
134  public virtual void Refresh(IEnumerable<Symbol> allSymbols, DateTime localTime)
135  {
136  AllSymbols = allSymbols;
137  LocalTime = localTime;
138  Type = ContractExpirationType.Standard;
139  }
140 
141  /// <summary>
142  /// Sets universe of standard contracts (if any) as selection
143  /// Contracts by default are standards; only needed to switch back if changed
144  /// </summary>
145  /// <returns>Universe with filter applied</returns>
146  public T StandardsOnly()
147  {
148  Type = ContractExpirationType.Standard;
149  return (T)this;
150  }
151 
152  /// <summary>
153  /// Includes universe of non-standard weeklys contracts (if any) into selection
154  /// </summary>
155  /// <returns>Universe with filter applied</returns>
156  public T IncludeWeeklys()
157  {
158  Type |= ContractExpirationType.Weekly;
159  return (T)this;
160  }
161 
162  /// <summary>
163  /// Sets universe of weeklys contracts (if any) as selection
164  /// </summary>
165  /// <returns>Universe with filter applied</returns>
166  public T WeeklysOnly()
167  {
168  Type = ContractExpirationType.Weekly;
169  return (T)this;
170  }
171 
172  /// <summary>
173  /// Returns front month contract
174  /// </summary>
175  /// <returns>Universe with filter applied</returns>
176  public virtual T FrontMonth()
177  {
178  var ordered = this.OrderBy(x => x.ID.Date).ToList();
179  if (ordered.Count == 0) return (T) this;
180  var frontMonth = ordered.TakeWhile(x => ordered[0].ID.Date == x.ID.Date);
181 
182  AllSymbols = frontMonth.ToList();
183  return (T) this;
184  }
185 
186  /// <summary>
187  /// Returns a list of back month contracts
188  /// </summary>
189  /// <returns>Universe with filter applied</returns>
190  public virtual T BackMonths()
191  {
192  var ordered = this.OrderBy(x => x.ID.Date).ToList();
193  if (ordered.Count == 0) return (T) this;
194  var backMonths = ordered.SkipWhile(x => ordered[0].ID.Date == x.ID.Date);
195 
196  AllSymbols = backMonths.ToList();
197  return (T) this;
198  }
199 
200  /// <summary>
201  /// Returns first of back month contracts
202  /// </summary>
203  /// <returns>Universe with filter applied</returns>
204  public T BackMonth()
205  {
206  return BackMonths().FrontMonth();
207  }
208 
209  /// <summary>
210  /// Applies filter selecting options contracts based on a range of expiration dates relative to the current day
211  /// </summary>
212  /// <param name="minExpiry">The minimum time until expiry to include, for example, TimeSpan.FromDays(10)
213  /// would exclude contracts expiring in less than 10 days</param>
214  /// <param name="maxExpiry">The maximum time until expiry to include, for example, TimeSpan.FromDays(10)
215  /// would exclude contracts expiring in more than 10 days</param>
216  /// <returns>Universe with filter applied</returns>
217  public virtual T Expiration(TimeSpan minExpiry, TimeSpan maxExpiry)
218  {
219  if (LocalTime == default)
220  {
221  return (T) this;
222  }
223 
224  if (maxExpiry > Time.MaxTimeSpan) maxExpiry = Time.MaxTimeSpan;
225 
226  var minExpiryToDate = LocalTime.Date + minExpiry;
227  var maxExpiryToDate = LocalTime.Date + maxExpiry;
228 
229  AllSymbols = AllSymbols
230  .Where(symbol => symbol.ID.Date.Date >= minExpiryToDate && symbol.ID.Date.Date <= maxExpiryToDate)
231  .ToList();
232 
233  return (T) this;
234  }
235 
236  /// <summary>
237  /// Applies filter selecting contracts based on a range of expiration dates relative to the current day
238  /// </summary>
239  /// <param name="minExpiryDays">The minimum time, expressed in days, until expiry to include, for example, 10
240  /// would exclude contracts expiring in less than 10 days</param>
241  /// <param name="maxExpiryDays">The maximum time, expressed in days, until expiry to include, for example, 10
242  /// would exclude contracts expiring in more than 10 days</param>
243  /// <returns>Universe with filter applied</returns>
244  public T Expiration(int minExpiryDays, int maxExpiryDays)
245  {
246  return Expiration(TimeSpan.FromDays(minExpiryDays), TimeSpan.FromDays(maxExpiryDays));
247  }
248 
249  /// <summary>
250  /// Explicitly sets the selected contract symbols for this universe.
251  /// This overrides and and all other methods of selecting symbols assuming it is called last.
252  /// </summary>
253  /// <param name="contracts">The option contract symbol objects to select</param>
254  /// <returns>Universe with filter applied</returns>
255  public T Contracts(PyObject contracts)
256  {
257  AllSymbols = contracts.ConvertToSymbolEnumerable();
258  return (T) this;
259  }
260 
261  /// <summary>
262  /// Explicitly sets the selected contract symbols for this universe.
263  /// This overrides and and all other methods of selecting symbols assuming it is called last.
264  /// </summary>
265  /// <param name="contracts">The option contract symbol objects to select</param>
266  /// <returns>Universe with filter applied</returns>
267  public T Contracts(IEnumerable<Symbol> contracts)
268  {
269  AllSymbols = contracts.ToList();
270  return (T) this;
271  }
272 
273  /// <summary>
274  /// Sets a function used to filter the set of available contract filters. The input to the 'contractSelector'
275  /// function will be the already filtered list if any other filters have already been applied.
276  /// </summary>
277  /// <param name="contractSelector">The option contract symbol objects to select</param>
278  /// <returns>Universe with filter applied</returns>
279  public T Contracts(Func<IEnumerable<Symbol>, IEnumerable<Symbol>> contractSelector)
280  {
281  // force materialization using ToList
282  AllSymbols = contractSelector(AllSymbols).ToList();
283  return (T) this;
284  }
285 
286  /// <summary>
287  /// Instructs the engine to only filter contracts on the first time step of each market day.
288  /// </summary>
289  /// <returns>Universe with filter applied</returns>
290  /// <remarks>Deprecated since filters are always non-dynamic now</remarks>
291  [Obsolete("Deprecated as of 2023-12-13. Filters are always non-dynamic as of now, which means they will only bee applied daily.")]
293  {
294  return (T) this;
295  }
296 
297  /// <summary>
298  /// IEnumerable interface method implementation
299  /// </summary>
300  /// <returns>IEnumerator of Symbols in Universe</returns>
301  public IEnumerator<Symbol> GetEnumerator()
302  {
303  return AllSymbols.GetEnumerator();
304  }
305 
306  /// <summary>
307  /// IEnumerable interface method implementation
308  /// </summary>
309  IEnumerator IEnumerable.GetEnumerator()
310  {
311  return AllSymbols.GetEnumerator();
312  }
313  }
314 }