Lean  $LEAN_TAG$
FuturesListings.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.Collections.Generic;
18 using System.Linq;
19 
21 {
22  /// <summary>
23  /// Helpers for getting the futures contracts that are trading on a given date.
24  /// This is a substitute for the BacktestingFutureChainProvider, but
25  /// does not outright replace it because of missing entries. This will resolve
26  /// the listed contracts without having any data in place. We follow the listing rules
27  /// set forth by the exchange to get the <see cref="Symbol"/>s that are listed at a given date.
28  /// </summary>
29  public static class FuturesListings
30  {
31  private static readonly Symbol _zb = Symbol.Create("ZB", SecurityType.Future, Market.CBOT);
32  private static readonly Symbol _zc = Symbol.Create("ZC", SecurityType.Future, Market.CBOT);
33  private static readonly Symbol _zs = Symbol.Create("ZS", SecurityType.Future, Market.CBOT);
34  private static readonly Symbol _zt = Symbol.Create("ZT", SecurityType.Future, Market.CBOT);
35  private static readonly Symbol _zw = Symbol.Create("ZW", SecurityType.Future, Market.CBOT);
36 
37  private static Dictionary<string, Func<DateTime, List<Symbol>>> _futuresListingRules = new Dictionary<string, Func<DateTime, List<Symbol>>>
38  {
39  { "ZB", t => QuarterlyContracts(_zb, t, 3) },
40  { "ZC", t => MonthlyContractListings(
41  _zc,
42  t,
43  12,
44  new FuturesListingCycles(new[] { 3, 5, 9 }, 9),
45  new FuturesListingCycles(new[] { 7, 12 }, 8)) },
46  { "ZN", t => QuarterlyContracts(_zt, t, 3) },
47  { "ZS", t => MonthlyContractListings(
48  _zs,
49  t,
50  11,
51  new FuturesListingCycles(new[] { 1, 3, 5, 8, 9 }, 15),
52  new FuturesListingCycles(new[] { 7, 11 }, 8)) },
53  { "ZT", t => QuarterlyContracts(_zt, t, 3) },
54  { "ZW", t => MonthlyContractListings(
55  _zw,
56  t,
57  7,
58  new FuturesListingCycles(new[] { 3, 5, 7, 9, 12 }, 15)) }
59  };
60 
61  /// <summary>
62  /// Gets the listed futures contracts on a given date
63  /// </summary>
64  /// <param name="futureTicker">Ticker of the future contract</param>
65  /// <param name="time">Contracts to look up that are listed at that time</param>
66  /// <returns>The currently trading contracts on the exchange</returns>
67  public static List<Symbol> ListedContracts(string futureTicker, DateTime time)
68  {
69  if (!_futuresListingRules.ContainsKey(futureTicker))
70  {
71  // No entries found. This differs from entries being returned as an empty array, where
72  // that would mean that no listings were found.
73  return null;
74  }
75 
76  return _futuresListingRules[futureTicker](time);
77  }
78 
79  /// <summary>
80  /// Gets contracts following a quarterly listing procedure, with a limit of
81  /// how many contracts are listed at once.
82  /// </summary>
83  /// <param name="canonicalFuture">Canonical Futures Symbol</param>
84  /// <param name="time">Contracts to look up that are listed at that time</param>
85  /// <param name="limit">Number of Symbols we get back/are listed at a given time</param>
86  /// <returns>Symbols that are listed at the given time</returns>
87  private static List<Symbol> QuarterlyContracts(Symbol canonicalFuture, DateTime time, int limit)
88  {
89  var contractMonth = new DateTime(time.Year, time.Month, 1);
90  var futureExpiry = DateTime.MinValue;
91  var expiryFunc = FuturesExpiryFunctions.FuturesExpiryFunction(canonicalFuture);
92 
93  // Skip any contracts that have already expired.
94  while (futureExpiry < time)
95  {
96  futureExpiry = FuturesExpiryFunctions.FuturesExpiryFunction(canonicalFuture)(contractMonth);
97  contractMonth = contractMonth.AddMonths(1);
98  }
99 
100  // Negate the last incrementation from the while loop to get the actual contract month of the future.
101  var firstFutureContractMonth = contractMonth.AddMonths(-1);
102 
103  var quarterlyContracts = new List<Symbol>();
104  // Gets the next closest month from the current month in multiples of 3
105  var quarterlyContractMonth = (int)Math.Ceiling((double)firstFutureContractMonth.Month / 3) * 3;
106 
107  for (var i = 0; i < limit; i++)
108  {
109  // We're past the expiration frontier due to the while loop above, which means
110  // that any contracts from here on out will be greater than the current time.
111  var currentContractMonth = firstFutureContractMonth.AddMonths(-firstFutureContractMonth.Month + quarterlyContractMonth);
112  var currentFutureExpiry = expiryFunc(currentContractMonth);
113 
114  quarterlyContracts.Add(Symbol.CreateFuture(canonicalFuture.ID.Symbol, canonicalFuture.ID.Market, currentFutureExpiry));
115  quarterlyContractMonth += 3;
116  }
117 
118  return quarterlyContracts;
119  }
120 
121  /// <summary>
122  /// Gets Futures contracts that follow a limited cyclical pattern
123  /// </summary>
124  /// <param name="canonicalFuture">Canonical Futures Symbol</param>
125  /// <param name="time">Contracts to look up that are listed at that time</param>
126  /// <param name="contractMonthForNewListings">Contract month that results in new listings after this contract's expiry</param>
127  /// <param name="futureListingCycles">
128  /// Cycles that define the number of contracts and the months the contracts are listed on, including
129  /// the limit of how many contracts will be listed.
130  /// </param>
131  /// <returns>Symbols that are listed at the given time</returns>
132  private static List<Symbol> MonthlyContractListings(
133  Symbol canonicalFuture,
134  DateTime time,
135  int contractMonthForNewListings,
136  params FuturesListingCycles[] futureListingCycles)
137  {
138  var listings = new List<Symbol>();
139  var expiryFunc = FuturesExpiryFunctions.FuturesExpiryFunction(canonicalFuture);
140  var yearDelta = 0;
141 
142  var contractMonthForNewListingCycle = new DateTime(time.Year, contractMonthForNewListings, 1);
143  var contractMonthForNewListingCycleExpiry = expiryFunc(contractMonthForNewListingCycle);
144 
145  if (time <= contractMonthForNewListingCycleExpiry)
146  {
147  // Go back a year if we haven't yet crossed this year's contract renewal expiration date.
148  contractMonthForNewListingCycleExpiry = expiryFunc(contractMonthForNewListingCycle.AddYears(-1));
149  yearDelta = -1;
150  }
151 
152  foreach (var listingCycle in futureListingCycles)
153  {
154  var year = yearDelta;
155  var count = 0;
156  var initialListings = true;
157 
158  while (count != listingCycle.Limit)
159  {
160  var monthStartIndex = 0;
161  if (initialListings)
162  {
163  // For the initial listing, we want to start counting at some month that might not be the first
164  // index of the collection. The index is discovered here and used as the starting point for listed contracts.
165  monthStartIndex = listingCycle.Cycle.Length - listingCycle.Cycle.Count(c => c > contractMonthForNewListingCycleExpiry.Month);
166  initialListings = false;
167  }
168 
169  for (var m = monthStartIndex; m < listingCycle.Cycle.Length; m++)
170  {
171  // Add the future's expiration to the listings
172  var currentContractMonth = new DateTime(time.Year + year, listingCycle.Cycle[m], 1);
173  var currentFutureExpiry = expiryFunc(currentContractMonth);
174  if (currentFutureExpiry >= time)
175  {
176  listings.Add(Symbol.CreateFuture(canonicalFuture.ID.Symbol, canonicalFuture.ID.Market, currentFutureExpiry));
177  }
178 
179  if (++count == listingCycle.Limit)
180  {
181  break;
182  }
183  }
184 
185  year++;
186  }
187  }
188 
189  return listings;
190  }
191 
192  /// <summary>
193  /// Listing Cycles, i.e. the months and number of contracts that are renewed whenever
194  /// the specified renewal expiration contract expires.
195  /// </summary>
196  /// <remarks>
197  /// Example:
198  ///
199  /// (from: https://www.cmegroup.com/trading/agricultural/grain-and-oilseed/wheat_contract_specifications.html)
200  /// "15 monthly contracts of Mar, May, Jul, Sep, Dec listed annually following the termination of trading in the July contract of the current year."
201  ///
202  /// This would equate to a cycle of [3, 5, 7, 9, 12], a limit of 15, and the contract month == 7.
203  /// </remarks>
204  private class FuturesListingCycles
205  {
206  /// <summary>
207  /// Monthly cycles that the futures listings rule follows
208  /// </summary>
209  public int[] Cycle { get; }
210 
211  /// <summary>
212  /// Max number of contracts returned by this rule
213  /// </summary>
214  public int Limit { get; }
215 
216 
217  /// <summary>
218  /// Creates a listing cycle rule
219  /// </summary>
220  /// <param name="cycle">New contract listing cycles</param>
221  /// <param name="limit">Max number of contracts to return in this rule</param>
222  public FuturesListingCycles(int[] cycle, int limit)
223  {
224  Cycle = cycle;
225  Limit = limit;
226  }
227  }
228  }
229 }