17 using System.Collections.Generic;
34 private readonly
int? _chainContractsLookupLimit;
36 private readonly
int? _resultsLimit;
47 int? resultsLimit = 1) : base(TimeSpan.FromDays(1), futureChainSymbolSelector)
50 if (algorithm ==
null)
52 throw new ArgumentNullException(nameof(algorithm));
55 _algorithm = algorithm;
56 _resultsLimit = resultsLimit;
57 _chainContractsLookupLimit = chainContractsLookupLimit;
68 int? resultsLimit = 1) : this(algorithm, ConvertFutureChainSymbolSelectorToFunc(futureChainSymbolSelector), chainContractsLookupLimit, resultsLimit)
78 return filter.
Contracts(
FilterByOpenInterest(filter.DistinctBy(x => x).ToDictionary(x => x, x => _marketHoursDatabase.GetEntry(x.ID.Market, x, x.ID.SecurityType))));
86 public IEnumerable<Symbol>
FilterByOpenInterest(IReadOnlyDictionary<Symbol, MarketHoursDatabase.Entry> contracts)
88 var symbols =
new List<Symbol>(_chainContractsLookupLimit.HasValue ? contracts.Keys.OrderBy(x => x.ID.Date).Take(_chainContractsLookupLimit.Value) : contracts.Keys);
89 var openInterest = symbols.GroupBy(x => contracts[x]).SelectMany(g => GetOpenInterest(g.Key, g.Select(i => i))).ToDictionary(x => x.Key, x => x.Value);
91 if (openInterest.Count == 0)
94 $
"{nameof(OpenInterestFutureUniverseSelectionModel)}.{nameof(FilterByOpenInterest)}: Failed to get historical open interest, no symbol will be selected."
96 return Enumerable.Empty<
Symbol>();
99 var filtered = openInterest.OrderByDescending(x => x.Value).ThenBy(x => x.Key.ID.Date).Select(x => x.Key);
100 if (_resultsLimit.HasValue)
102 filtered = filtered.Take(_resultsLimit.Value);
108 private Dictionary<Symbol, decimal> GetOpenInterest(
MarketHoursDatabase.
Entry marketHours, IEnumerable<Symbol> symbols)
110 var current = _algorithm.UtcTime;
111 var exchangeHours = marketHours.ExchangeHours;
112 var endTime = Instant.FromDateTimeUtc(_algorithm.UtcTime).InZone(exchangeHours.TimeZone).ToDateTimeUnspecified();
114 var requests = symbols.Select(
122 exchangeHours.TimeZone,
131 return _algorithm.HistoryProvider.GetHistory(requests, exchangeHours.TimeZone)
132 .Where(s => s.HasData && s.Ticks.Keys.Count > 0)
133 .SelectMany(s => s.Ticks.Select(x =>
new Tuple<Symbol, Tick>(x.Key, x.Value.LastOrDefault())))
134 .GroupBy(x => x.Item1)
135 .ToDictionary(x => x.Key, x => x.OrderByDescending(i => i.Item2.Time).LastOrDefault().Item2.Value);
144 private static Func<DateTime, IEnumerable<Symbol>> ConvertFutureChainSymbolSelectorToFunc(PyObject futureChainSymbolSelector)
146 if (futureChainSymbolSelector.TryConvertToDelegate(out Func<DateTime, IEnumerable<Symbol>> futureSelector))
148 return futureSelector;
154 throw new ArgumentException($
"FutureUniverseSelectionModel.ConvertFutureChainSymbolSelectorToFunc: {futureChainSymbolSelector.Repr()} is not a valid argument.");