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