chore: import upstream snapshot with attribution
This commit is contained in:
@@ -0,0 +1,435 @@
|
||||
/*
|
||||
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
|
||||
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Linq;
|
||||
using Python.Runtime;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace QuantConnect.Securities
|
||||
{
|
||||
/// <summary>
|
||||
/// Base class for contract symbols filtering universes.
|
||||
/// Used by OptionFilterUniverse and FutureFilterUniverse
|
||||
/// </summary>
|
||||
public abstract class ContractSecurityFilterUniverse<T, TData> : IDerivativeSecurityFilterUniverse<TData>
|
||||
where T : ContractSecurityFilterUniverse<T, TData>
|
||||
where TData : IChainUniverseData
|
||||
{
|
||||
private bool _alreadyAppliedTypeFilters;
|
||||
|
||||
private IReadOnlyList<TData> _data;
|
||||
|
||||
/// <summary>
|
||||
/// Defines listed contract types with Flags attribute
|
||||
/// </summary>
|
||||
[Flags]
|
||||
protected enum ContractExpirationType : int
|
||||
{
|
||||
/// <summary>
|
||||
/// Standard contracts
|
||||
/// </summary>
|
||||
Standard = 1,
|
||||
|
||||
/// <summary>
|
||||
/// Non standard weekly contracts
|
||||
/// </summary>
|
||||
Weekly = 2
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The default expiration type filter value
|
||||
/// </summary>
|
||||
protected static readonly ContractExpirationType DefaultExpirationType = ContractExpirationType.Standard | ContractExpirationType.Weekly;
|
||||
|
||||
/// <summary>
|
||||
/// Expiration Types allowed through the filter
|
||||
/// Standards only by default
|
||||
/// </summary>
|
||||
protected ContractExpirationType Type { get; set; } = DefaultExpirationType;
|
||||
|
||||
/// <summary>
|
||||
/// The local exchange current time
|
||||
/// </summary>
|
||||
public DateTime LocalTime { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// The number of contracts in the universe
|
||||
/// </summary>
|
||||
public int Count => _data.Count;
|
||||
|
||||
/// <summary>
|
||||
/// All data in this filter
|
||||
/// Marked internal for use by extensions
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Setting it will also set AllSymbols
|
||||
/// </remarks>
|
||||
internal IReadOnlyList<TData> Data
|
||||
{
|
||||
get
|
||||
{
|
||||
return _data;
|
||||
}
|
||||
set
|
||||
{
|
||||
_data = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// All Symbols in this filter
|
||||
/// Marked internal for use by extensions
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Setting it will remove any data that doesn't have a symbol in AllSymbols
|
||||
/// </remarks>
|
||||
internal IEnumerable<Symbol> AllSymbols
|
||||
{
|
||||
get
|
||||
{
|
||||
return _data.Select(x => x.Symbol);
|
||||
}
|
||||
set
|
||||
{
|
||||
// We create a "fake" data instance for each symbol that is not in the data,
|
||||
// so we are polite to the user and keep backwards compatibility
|
||||
_data = value.Select(symbol => _data.FirstOrDefault(x => x.Symbol == symbol) ?? CreateDataInstance(symbol)).ToList();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructs ContractSecurityFilterUniverse
|
||||
/// </summary>
|
||||
protected ContractSecurityFilterUniverse()
|
||||
{
|
||||
Type = DefaultExpirationType;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructs ContractSecurityFilterUniverse
|
||||
/// </summary>
|
||||
protected ContractSecurityFilterUniverse(IReadOnlyList<TData> allData, DateTime localTime)
|
||||
{
|
||||
Data = allData;
|
||||
LocalTime = localTime;
|
||||
Type = DefaultExpirationType;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Function to determine if the given symbol is a standard contract
|
||||
/// </summary>
|
||||
/// <returns>True if standard type</returns>
|
||||
protected abstract bool IsStandard(Symbol symbol);
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new instance of the data type for the given symbol
|
||||
/// </summary>
|
||||
/// <returns>A data instance for the given symbol</returns>
|
||||
protected abstract TData CreateDataInstance(Symbol symbol);
|
||||
|
||||
/// <summary>
|
||||
/// Returns universe, filtered by contract type
|
||||
/// </summary>
|
||||
/// <returns>Universe with filter applied</returns>
|
||||
internal T ApplyTypesFilter()
|
||||
{
|
||||
if (_alreadyAppliedTypeFilters)
|
||||
{
|
||||
return (T)this;
|
||||
}
|
||||
|
||||
// memoization map for ApplyTypesFilter()
|
||||
var memoizedMap = new Dictionary<DateTime, bool>();
|
||||
|
||||
Func<TData, bool> memoizedIsStandardType = data =>
|
||||
{
|
||||
var dt = data.ID.Date;
|
||||
|
||||
bool result;
|
||||
if (memoizedMap.TryGetValue(dt, out result))
|
||||
return result;
|
||||
var res = IsStandard(data.Symbol);
|
||||
memoizedMap[dt] = res;
|
||||
|
||||
return res;
|
||||
};
|
||||
|
||||
Data = Data.Where(x =>
|
||||
{
|
||||
switch (Type)
|
||||
{
|
||||
case ContractExpirationType.Weekly:
|
||||
return !memoizedIsStandardType(x);
|
||||
case ContractExpirationType.Standard:
|
||||
return memoizedIsStandardType(x);
|
||||
case ContractExpirationType.Standard | ContractExpirationType.Weekly:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}).ToList();
|
||||
|
||||
_alreadyAppliedTypeFilters = true;
|
||||
return (T)this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Refreshes this filter universe
|
||||
/// </summary>
|
||||
/// <param name="allData">All data for contracts in the Universe</param>
|
||||
/// <param name="localTime">The local exchange current time</param>
|
||||
public virtual void Refresh(IReadOnlyList<TData> allData, DateTime localTime)
|
||||
{
|
||||
Data = allData;
|
||||
LocalTime = localTime;
|
||||
Type = DefaultExpirationType;
|
||||
_alreadyAppliedTypeFilters = false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets universe of standard contracts (if any) as selection
|
||||
/// Contracts by default are standards; only needed to switch back if changed
|
||||
/// </summary>
|
||||
/// <returns>Universe with filter applied</returns>
|
||||
public T StandardsOnly()
|
||||
{
|
||||
if (_alreadyAppliedTypeFilters)
|
||||
{
|
||||
throw new InvalidOperationException("Type filters have already been applied, " +
|
||||
"please call StandardsOnly() before applying other filters such as FrontMonth() or BackMonths()");
|
||||
}
|
||||
|
||||
Type = ContractExpirationType.Standard;
|
||||
return (T)this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Includes universe of non-standard weeklys contracts (if any) into selection
|
||||
/// </summary>
|
||||
/// <returns>Universe with filter applied</returns>
|
||||
[Obsolete("IncludeWeeklys is obsolete because weekly contracts are now included by default.")]
|
||||
public T IncludeWeeklys()
|
||||
{
|
||||
if (_alreadyAppliedTypeFilters)
|
||||
{
|
||||
throw new InvalidOperationException("Type filters have already been applied, " +
|
||||
"please call IncludeWeeklys() before applying other filters such as FrontMonth() or BackMonths()");
|
||||
}
|
||||
|
||||
Type |= ContractExpirationType.Weekly;
|
||||
return (T)this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets universe of weeklys contracts (if any) as selection
|
||||
/// </summary>
|
||||
/// <returns>Universe with filter applied</returns>
|
||||
public T WeeklysOnly()
|
||||
{
|
||||
Type = ContractExpirationType.Weekly;
|
||||
return (T)this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns front month contract
|
||||
/// </summary>
|
||||
/// <returns>Universe with filter applied</returns>
|
||||
public virtual T FrontMonth()
|
||||
{
|
||||
ApplyTypesFilter();
|
||||
var ordered = Data.OrderBy(x => x.ID.Date).ToList();
|
||||
if (ordered.Count == 0) return (T)this;
|
||||
var frontMonth = ordered.TakeWhile(x => ordered[0].ID.Date == x.ID.Date);
|
||||
|
||||
Data = frontMonth.ToList();
|
||||
return (T)this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a list of back month contracts
|
||||
/// </summary>
|
||||
/// <returns>Universe with filter applied</returns>
|
||||
public virtual T BackMonths()
|
||||
{
|
||||
ApplyTypesFilter();
|
||||
var ordered = Data.OrderBy(x => x.ID.Date).ToList();
|
||||
if (ordered.Count == 0) return (T)this;
|
||||
var backMonths = ordered.SkipWhile(x => ordered[0].ID.Date == x.ID.Date);
|
||||
|
||||
Data = backMonths.ToList();
|
||||
return (T)this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns first of back month contracts
|
||||
/// </summary>
|
||||
/// <returns>Universe with filter applied</returns>
|
||||
public T BackMonth()
|
||||
{
|
||||
return BackMonths().FrontMonth();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adjust the reference date used for expiration filtering. By default it just returns the same date.
|
||||
/// </summary>
|
||||
/// <param name="referenceDate">The reference date to be adjusted</param>
|
||||
/// <returns>The adjusted date</returns>
|
||||
protected virtual DateTime AdjustExpirationReferenceDate(DateTime referenceDate)
|
||||
{
|
||||
return referenceDate;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Applies filter selecting options contracts based on a range of expiration dates relative to the current day
|
||||
/// </summary>
|
||||
/// <param name="minExpiry">The minimum time until expiry to include, for example, TimeSpan.FromDays(10)
|
||||
/// would exclude contracts expiring in less than 10 days</param>
|
||||
/// <param name="maxExpiry">The maximum time until expiry to include, for example, TimeSpan.FromDays(10)
|
||||
/// would exclude contracts expiring in more than 10 days</param>
|
||||
/// <returns>Universe with filter applied</returns>
|
||||
public virtual T Expiration(TimeSpan minExpiry, TimeSpan maxExpiry)
|
||||
{
|
||||
if (LocalTime == default)
|
||||
{
|
||||
return (T)this;
|
||||
}
|
||||
|
||||
if (maxExpiry > Time.MaxTimeSpan) maxExpiry = Time.MaxTimeSpan;
|
||||
|
||||
var referenceDate = AdjustExpirationReferenceDate(LocalTime.Date);
|
||||
|
||||
var minExpiryToDate = referenceDate + minExpiry;
|
||||
var maxExpiryToDate = referenceDate + maxExpiry;
|
||||
|
||||
Data = Data
|
||||
.Where(symbol => symbol.ID.Date.Date >= minExpiryToDate && symbol.ID.Date.Date <= maxExpiryToDate)
|
||||
.ToList();
|
||||
|
||||
return (T)this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Applies filter selecting contracts based on a range of expiration dates relative to the current day
|
||||
/// </summary>
|
||||
/// <param name="minExpiryDays">The minimum time, expressed in days, until expiry to include, for example, 10
|
||||
/// would exclude contracts expiring in less than 10 days</param>
|
||||
/// <param name="maxExpiryDays">The maximum time, expressed in days, until expiry to include, for example, 10
|
||||
/// would exclude contracts expiring in more than 10 days</param>
|
||||
/// <returns>Universe with filter applied</returns>
|
||||
public T Expiration(int minExpiryDays, int maxExpiryDays)
|
||||
{
|
||||
return Expiration(TimeSpan.FromDays(minExpiryDays), TimeSpan.FromDays(maxExpiryDays));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Explicitly sets the selected contract symbols for this universe.
|
||||
/// This overrides and and all other methods of selecting symbols assuming it is called last.
|
||||
/// </summary>
|
||||
/// <param name="contracts">The option contract symbol objects to select</param>
|
||||
/// <returns>Universe with filter applied</returns>
|
||||
public T Contracts(PyObject contracts)
|
||||
{
|
||||
// Let's first check if the object is a selector:
|
||||
if (contracts.TrySafeAs(out Func<IEnumerable<TData>, IEnumerable<Symbol>> contractSelector))
|
||||
{
|
||||
return Contracts(contractSelector);
|
||||
}
|
||||
|
||||
// Else, it should be a list of symbols:
|
||||
return Contracts(contracts.ConvertToSymbolEnumerable());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Explicitly sets the selected contract symbols for this universe.
|
||||
/// This overrides and and all other methods of selecting symbols assuming it is called last.
|
||||
/// </summary>
|
||||
/// <param name="contracts">The option contract symbol objects to select</param>
|
||||
/// <returns>Universe with filter applied</returns>
|
||||
public T Contracts(IEnumerable<Symbol> contracts)
|
||||
{
|
||||
AllSymbols = contracts.ToList();
|
||||
return (T)this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Explicitly sets the selected contract symbols for this universe.
|
||||
/// This overrides and and all other methods of selecting symbols assuming it is called last.
|
||||
/// </summary>
|
||||
/// <param name="contracts">The option contract symbol objects to select</param>
|
||||
/// <returns>Universe with filter applied</returns>
|
||||
public T Contracts(IEnumerable<TData> contracts)
|
||||
{
|
||||
Data = contracts.ToList();
|
||||
return (T)this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets a function used to filter the set of available contract filters. The input to the 'contractSelector'
|
||||
/// function will be the already filtered list if any other filters have already been applied.
|
||||
/// </summary>
|
||||
/// <param name="contractSelector">The option contract symbol objects to select</param>
|
||||
/// <returns>Universe with filter applied</returns>
|
||||
public T Contracts(Func<IEnumerable<TData>, IEnumerable<Symbol>> contractSelector)
|
||||
{
|
||||
// force materialization using ToList
|
||||
AllSymbols = contractSelector(Data).ToList();
|
||||
return (T)this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets a function used to filter the set of available contract filters. The input to the 'contractSelector'
|
||||
/// function will be the already filtered list if any other filters have already been applied.
|
||||
/// </summary>
|
||||
/// <param name="contractSelector">The option contract symbol objects to select</param>
|
||||
/// <returns>Universe with filter applied</returns>
|
||||
public T Contracts(Func<IEnumerable<TData>, IEnumerable<TData>> contractSelector)
|
||||
{
|
||||
// force materialization using ToList
|
||||
Data = contractSelector(Data).ToList();
|
||||
return (T)this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Instructs the engine to only filter contracts on the first time step of each market day.
|
||||
/// </summary>
|
||||
/// <returns>Universe with filter applied</returns>
|
||||
/// <remarks>Deprecated since filters are always non-dynamic now</remarks>
|
||||
[Obsolete("Deprecated as of 2023-12-13. Filters are always non-dynamic as of now, which means they will only bee applied daily.")]
|
||||
public T OnlyApplyFilterAtMarketOpen()
|
||||
{
|
||||
return (T)this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// IEnumerable interface method implementation
|
||||
/// </summary>
|
||||
/// <returns>IEnumerator of Symbols in Universe</returns>
|
||||
public IEnumerator<TData> GetEnumerator()
|
||||
{
|
||||
return Data.GetEnumerator();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// IEnumerable interface method implementation
|
||||
/// </summary>
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
{
|
||||
return Data.GetEnumerator();
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user