chore: import upstream snapshot with attribution
This commit is contained in:
@@ -0,0 +1,192 @@
|
||||
/*
|
||||
* 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.IO;
|
||||
using QuantConnect.Python;
|
||||
using QuantConnect.Securities;
|
||||
using QuantConnect.Util;
|
||||
|
||||
namespace QuantConnect.Data.UniverseSelection
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a chain universe.
|
||||
/// Intended as a base for options and futures universe data.
|
||||
/// </summary>
|
||||
public abstract class BaseChainUniverseData : BaseDataCollection, IChainUniverseData
|
||||
{
|
||||
/// <summary>
|
||||
/// Csv line to get the values from
|
||||
/// </summary>
|
||||
/// <remarks>We keep the properties as they are in the csv file to reduce memory usage (strings vs decimals)</remarks>
|
||||
protected string CsvLine { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The security identifier of the option symbol
|
||||
/// </summary>
|
||||
[PandasIgnore]
|
||||
public SecurityIdentifier ID => Symbol.ID;
|
||||
|
||||
/// <summary>
|
||||
/// Price of the security
|
||||
/// </summary>
|
||||
[PandasIgnore]
|
||||
public override decimal Value => Close;
|
||||
|
||||
/// <summary>
|
||||
/// Open price of the security
|
||||
/// </summary>
|
||||
public decimal Open
|
||||
{
|
||||
get
|
||||
{
|
||||
// Parse the values every time to avoid keeping them in memory
|
||||
return CsvLine.GetDecimalFromCsv(0);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// High price of the security
|
||||
/// </summary>
|
||||
public decimal High
|
||||
{
|
||||
get
|
||||
{
|
||||
return CsvLine.GetDecimalFromCsv(1);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Low price of the security
|
||||
/// </summary>
|
||||
public decimal Low
|
||||
{
|
||||
get
|
||||
{
|
||||
return CsvLine.GetDecimalFromCsv(2);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Close price of the security
|
||||
/// </summary>
|
||||
public decimal Close
|
||||
{
|
||||
get
|
||||
{
|
||||
return CsvLine.GetDecimalFromCsv(3);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Volume value of the security
|
||||
/// </summary>
|
||||
public decimal Volume
|
||||
{
|
||||
get
|
||||
{
|
||||
return CsvLine.GetDecimalFromCsv(4);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Open interest value
|
||||
/// </summary>
|
||||
public virtual decimal OpenInterest
|
||||
{
|
||||
get
|
||||
{
|
||||
return CsvLine.GetDecimalFromCsv(5);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Time that the data became available to use
|
||||
/// </summary>
|
||||
public override DateTime EndTime
|
||||
{
|
||||
get { return Time + QuantConnect.Time.OneDay; }
|
||||
set { Time = value - QuantConnect.Time.OneDay; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new instance of the <see cref="BaseChainUniverseData"/> class
|
||||
/// </summary>
|
||||
protected BaseChainUniverseData()
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new instance of the <see cref="BaseChainUniverseData"/> class
|
||||
/// </summary>
|
||||
protected BaseChainUniverseData(DateTime date, Symbol symbol, string csv)
|
||||
: base(date, date, symbol, null, null)
|
||||
{
|
||||
CsvLine = csv;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new instance of the <see cref="BaseChainUniverseData"/> class as a copy of the given instance
|
||||
/// </summary>
|
||||
protected BaseChainUniverseData(BaseChainUniverseData other)
|
||||
: base(other)
|
||||
{
|
||||
CsvLine = other.CsvLine;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Return the URL string source of the file. This will be converted to a stream
|
||||
/// </summary>
|
||||
/// <param name="config">Configuration object</param>
|
||||
/// <param name="date">Date of this source file</param>
|
||||
/// <param name="isLiveMode">true if we're in live mode, false for backtesting mode</param>
|
||||
/// <returns>String URL of source file.</returns>
|
||||
public override SubscriptionDataSource GetSource(SubscriptionDataConfig config, DateTime date, bool isLiveMode)
|
||||
{
|
||||
var path = GetUniverseFullFilePath(config.Symbol, date);
|
||||
return new SubscriptionDataSource(path, SubscriptionTransportMedium.LocalFile, FileFormat.FoldingCollection);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Generates the file path for a universe data file based on the given symbol and date.
|
||||
/// Optionally, creates the directory if it does not exist.
|
||||
/// </summary>
|
||||
/// <param name="symbol">The financial symbol for which the universe file is generated.</param>
|
||||
/// <param name="date">The date associated with the universe file.</param>
|
||||
/// <returns>The full file path to the universe data file.</returns>
|
||||
public static string GetUniverseFullFilePath(Symbol symbol, DateTime date)
|
||||
{
|
||||
return Path.Combine(LeanData.GenerateUniversesDirectory(Globals.DataFolder, symbol), $"{date:yyyyMMdd}.csv");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the default resolution for this data and security type
|
||||
/// </summary>
|
||||
/// <remarks>This is a method and not a property so that python
|
||||
/// custom data types can override it</remarks>
|
||||
public override Resolution DefaultResolution()
|
||||
{
|
||||
return Resolution.Daily;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the symbol of the option
|
||||
/// </summary>
|
||||
public Symbol ToSymbol()
|
||||
{
|
||||
return Symbol;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,223 @@
|
||||
/*
|
||||
* 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 System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
using QuantConnect.Python;
|
||||
|
||||
namespace QuantConnect.Data.UniverseSelection
|
||||
{
|
||||
/// <summary>
|
||||
/// This type exists for transport of data as a single packet
|
||||
/// </summary>
|
||||
public class BaseDataCollection : BaseData, IEnumerable<BaseData>
|
||||
{
|
||||
private static int _universeCount;
|
||||
private DateTime _endTime;
|
||||
|
||||
/// <summary>
|
||||
/// The associated underlying price data if any
|
||||
/// </summary>
|
||||
[PandasNonExpandable]
|
||||
public BaseData Underlying { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the contracts selected by the universe
|
||||
/// </summary>
|
||||
[PandasIgnore]
|
||||
public HashSet<Symbol> FilteredContracts { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the data list
|
||||
/// </summary>
|
||||
public List<BaseData> Data { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the end time of this data
|
||||
/// </summary>
|
||||
[PandasIgnore]
|
||||
public override DateTime EndTime
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_endTime == default)
|
||||
{
|
||||
// to be user friendly let's return Time if not set, like BaseData does
|
||||
return Time;
|
||||
}
|
||||
return _endTime;
|
||||
}
|
||||
set
|
||||
{
|
||||
_endTime = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new default instance of the <see cref="BaseDataCollection"/> c;ass
|
||||
/// </summary>
|
||||
public BaseDataCollection()
|
||||
: this(DateTime.MinValue, Symbol.Empty)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="BaseDataCollection"/> class
|
||||
/// </summary>
|
||||
/// <param name="time">The time of this data</param>
|
||||
/// <param name="symbol">A common identifier for all data in this packet</param>
|
||||
/// <param name="data">The data to add to this collection</param>
|
||||
public BaseDataCollection(DateTime time, Symbol symbol, IEnumerable<BaseData> data = null)
|
||||
: this(time, time, symbol, data)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="BaseDataCollection"/> class
|
||||
/// </summary>
|
||||
/// <param name="time">The start time of this data</param>
|
||||
/// <param name="endTime">The end time of this data</param>
|
||||
/// <param name="symbol">A common identifier for all data in this packet</param>
|
||||
/// <param name="data">The data to add to this collection</param>
|
||||
/// <param name="underlying">The associated underlying price data if any</param>
|
||||
/// <param name="filteredContracts">The contracts selected by the universe</param>
|
||||
public BaseDataCollection(DateTime time, DateTime endTime, Symbol symbol, IEnumerable<BaseData> data = null, BaseData underlying = null, HashSet<Symbol> filteredContracts = null)
|
||||
: this(time, endTime, symbol, data != null ? data.ToList() : new List<BaseData>(), underlying, filteredContracts)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="BaseDataCollection"/> class
|
||||
/// </summary>
|
||||
/// <param name="time">The start time of this data</param>
|
||||
/// <param name="endTime">The end time of this data</param>
|
||||
/// <param name="symbol">A common identifier for all data in this packet</param>
|
||||
/// <param name="data">The data to add to this collection</param>
|
||||
/// <param name="underlying">The associated underlying price data if any</param>
|
||||
/// <param name="filteredContracts">The contracts selected by the universe</param>
|
||||
public BaseDataCollection(DateTime time, DateTime endTime, Symbol symbol, List<BaseData> data, BaseData underlying, HashSet<Symbol> filteredContracts)
|
||||
: this(time, endTime, symbol, underlying, filteredContracts)
|
||||
{
|
||||
if (data != null && data.Count == 1 && data[0] is BaseDataCollection collection && collection.Data != null && collection.Data.Count > 0)
|
||||
{
|
||||
// we were given a base data collection, let's be nice and fetch it's data if it has any
|
||||
Data = collection.Data;
|
||||
}
|
||||
else
|
||||
{
|
||||
Data = data ?? new List<BaseData>();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Helper method to create an instance without setting the data list
|
||||
/// </summary>
|
||||
protected BaseDataCollection(DateTime time, DateTime endTime, Symbol symbol, BaseData underlying, HashSet<Symbol> filteredContracts)
|
||||
{
|
||||
Symbol = symbol;
|
||||
Time = time;
|
||||
_endTime = endTime;
|
||||
Underlying = underlying;
|
||||
FilteredContracts = filteredContracts;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Copy constructor for <see cref="BaseDataCollection"/>
|
||||
/// </summary>
|
||||
/// <param name="other">The base data collection being copied</param>
|
||||
public BaseDataCollection(BaseDataCollection other)
|
||||
: this(other.Time, other.EndTime, other.Symbol, other.Underlying, other.FilteredContracts)
|
||||
{
|
||||
Data = other.Data;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates the universe symbol for the target market
|
||||
/// </summary>
|
||||
/// <returns>The universe symbol to use</returns>
|
||||
public virtual Symbol UniverseSymbol(string market = null)
|
||||
{
|
||||
market ??= QuantConnect.Market.USA;
|
||||
var ticker = $"{GetType().Name}-{market}-{Interlocked.Increment(ref _universeCount):D10}-{Guid.NewGuid()}";
|
||||
return Symbol.Create(ticker, SecurityType.Base, market, baseDataType: GetType());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Indicates whether this contains data that should be stored in the security cache
|
||||
/// </summary>
|
||||
/// <returns>Whether this contains data that should be stored in the security cache</returns>
|
||||
public override bool ShouldCacheToSecurity()
|
||||
{
|
||||
if (Data == null || Data.Count == 0)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
// if we hold the same data type we are, else we ask underlying type
|
||||
return Data[0].GetType() == GetType() || Data[0].ShouldCacheToSecurity();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a new data point to this collection
|
||||
/// </summary>
|
||||
/// <param name="newDataPoint">The new data point to add</param>
|
||||
public virtual void Add(BaseData newDataPoint)
|
||||
{
|
||||
Data.Add(newDataPoint);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a new data points to this collection
|
||||
/// </summary>
|
||||
/// <param name="newDataPoints">The new data points to add</param>
|
||||
public virtual void AddRange(IEnumerable<BaseData> newDataPoints)
|
||||
{
|
||||
Data.AddRange(newDataPoints);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Return a new instance clone of this object, used in fill forward
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This base implementation uses reflection to copy all public fields and properties
|
||||
/// </remarks>
|
||||
/// <returns>A clone of the current object</returns>
|
||||
public override BaseData Clone()
|
||||
{
|
||||
return new BaseDataCollection(this);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns an IEnumerator for this enumerable Object. The enumerator provides
|
||||
/// a simple way to access all the contents of a collection.
|
||||
/// </summary>
|
||||
public IEnumerator<BaseData> GetEnumerator()
|
||||
{
|
||||
return (Data ?? Enumerable.Empty<BaseData>()).GetEnumerator();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns an IEnumerator for this enumerable Object. The enumerator provides
|
||||
/// a simple way to access all the contents of a collection.
|
||||
/// </summary>
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
{
|
||||
return GetEnumerator();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,113 @@
|
||||
/*
|
||||
* 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.Globalization;
|
||||
using QuantConnect.Interfaces;
|
||||
using QuantConnect.Data.Fundamental;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace QuantConnect.Data.UniverseSelection
|
||||
{
|
||||
/// <summary>
|
||||
/// Base fundamental data provider
|
||||
/// </summary>
|
||||
public class BaseFundamentalDataProvider : IFundamentalDataProvider
|
||||
{
|
||||
/// <summary>
|
||||
/// True if live trading
|
||||
/// </summary>
|
||||
public bool LiveMode { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// THe data provider instance to use
|
||||
/// </summary>
|
||||
protected IDataProvider DataProvider { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes the service
|
||||
/// </summary>
|
||||
/// <param name="dataProvider">The data provider instance to use</param>
|
||||
/// <param name="liveMode">True if running in live mode</param>
|
||||
public virtual void Initialize(IDataProvider dataProvider, bool liveMode)
|
||||
{
|
||||
LiveMode = liveMode;
|
||||
DataProvider = dataProvider;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Will fetch the requested fundamental information for the requested time and symbol
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The expected data type</typeparam>
|
||||
/// <param name="time">The time to request this data for</param>
|
||||
/// <param name="securityIdentifier">The security identifier</param>
|
||||
/// <param name="name">The name of the fundamental property</param>
|
||||
/// <returns>The fundamental information</returns>
|
||||
public virtual T Get<T>(DateTime time, SecurityIdentifier securityIdentifier, FundamentalProperty name)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get's the default value for the given T type
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The expected T type</typeparam>
|
||||
/// <returns>The default value</returns>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static T GetDefault<T>()
|
||||
{
|
||||
if (typeof(T) == typeof(double))
|
||||
{
|
||||
return (T)Convert.ChangeType(double.NaN, typeof(T), CultureInfo.InvariantCulture);
|
||||
}
|
||||
else if (typeof(T) == typeof(decimal))
|
||||
{
|
||||
return (T)Convert.ChangeType(decimal.Zero, typeof(T), CultureInfo.InvariantCulture);
|
||||
}
|
||||
return default;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// True if the given value is none
|
||||
/// </summary>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static bool IsNone(object value) => IsNone(value?.GetType(), value);
|
||||
|
||||
/// <summary>
|
||||
/// True if the given value is none
|
||||
/// </summary>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static bool IsNone(Type type, object value)
|
||||
{
|
||||
if (type == null || value == null)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else if(type == typeof(double))
|
||||
{
|
||||
return ((double)value).IsNaNOrInfinity();
|
||||
}
|
||||
else if (type == typeof(decimal))
|
||||
{
|
||||
return default(decimal) == (decimal)value;
|
||||
}
|
||||
else if (type == typeof(DateTime))
|
||||
{
|
||||
return default(DateTime) == (DateTime)value;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,135 @@
|
||||
/*
|
||||
* 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 System.Globalization;
|
||||
|
||||
namespace QuantConnect.Data.UniverseSelection
|
||||
{
|
||||
/// <summary>
|
||||
/// Defines summary information about a single symbol for a given date
|
||||
/// </summary>
|
||||
public class CoarseFundamental : BaseData
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the market for this symbol
|
||||
/// </summary>
|
||||
public string Market => Symbol.ID.Market;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the day's dollar volume for this symbol
|
||||
/// </summary>
|
||||
public virtual double DollarVolume { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the day's total volume
|
||||
/// </summary>
|
||||
public virtual long Volume { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Returns whether the symbol has fundamental data for the given date
|
||||
/// </summary>
|
||||
public virtual bool HasFundamentalData { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the price factor for the given date
|
||||
/// </summary>
|
||||
public virtual decimal PriceFactor { get; } = 1;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the split factor for the given date
|
||||
/// </summary>
|
||||
public virtual decimal SplitFactor { get; } = 1;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the combined factor used to create adjusted prices from raw prices
|
||||
/// </summary>
|
||||
public decimal PriceScaleFactor => PriceFactor * SplitFactor;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the split and dividend adjusted price
|
||||
/// </summary>
|
||||
public decimal AdjustedPrice => Price * PriceScaleFactor;
|
||||
|
||||
/// <summary>
|
||||
/// The end time of this data.
|
||||
/// </summary>
|
||||
public override DateTime EndTime
|
||||
{
|
||||
get { return Time + QuantConnect.Time.OneDay; }
|
||||
set { Time = value - QuantConnect.Time.OneDay; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the raw price
|
||||
/// </summary>
|
||||
public override decimal Price => Value;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="CoarseFundamental"/> class
|
||||
/// </summary>
|
||||
public CoarseFundamental()
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Return the URL string source of the file. This will be converted to a stream
|
||||
/// </summary>
|
||||
/// <param name="config">Configuration object</param>
|
||||
/// <param name="date">Date of this source file</param>
|
||||
/// <param name="isLiveMode">true if we're in live mode, false for backtesting mode</param>
|
||||
/// <returns>String URL of source file.</returns>
|
||||
public override SubscriptionDataSource GetSource(SubscriptionDataConfig config, DateTime date, bool isLiveMode)
|
||||
{
|
||||
throw new InvalidOperationException($"Coarse type is obsolete, please use {nameof(Fundamental)}");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reader converts each line of the data source into BaseData objects. Each data type creates its own factory method, and returns a new instance of the object
|
||||
/// each time it is called.
|
||||
/// </summary>
|
||||
/// <param name="config">Subscription data config setup object</param>
|
||||
/// <param name="line">Line of the source document</param>
|
||||
/// <param name="date">Date of the requested data</param>
|
||||
/// <param name="isLiveMode">true if we're in live mode, false for backtesting mode</param>
|
||||
/// <returns>Instance of the T:BaseData object generated by this line of the CSV</returns>
|
||||
public override BaseData Reader(SubscriptionDataConfig config, string line, DateTime date, bool isLiveMode)
|
||||
{
|
||||
throw new InvalidOperationException($"Coarse type is obsolete, please use {nameof(Fundamental)}");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts a given fundamental data point into row format
|
||||
/// </summary>
|
||||
public static string ToRow(CoarseFundamental coarse)
|
||||
{
|
||||
// sid,symbol,close,volume,dollar volume,has fundamental data,price factor,split factor
|
||||
var values = new object[]
|
||||
{
|
||||
coarse.Symbol.ID,
|
||||
coarse.Symbol.Value,
|
||||
coarse.Value,
|
||||
coarse.Volume,
|
||||
coarse.DollarVolume,
|
||||
coarse.HasFundamentalData,
|
||||
coarse.PriceFactor,
|
||||
coarse.SplitFactor
|
||||
};
|
||||
|
||||
return string.Join(",", values.Select(s => Convert.ToString(s, CultureInfo.InvariantCulture)));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,198 @@
|
||||
/*
|
||||
* 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.IO;
|
||||
using System.Collections.Generic;
|
||||
using QuantConnect.Data.Fundamental;
|
||||
|
||||
namespace QuantConnect.Data.UniverseSelection
|
||||
{
|
||||
/// <summary>
|
||||
/// Coarse base fundamental data provider
|
||||
/// </summary>
|
||||
public class CoarseFundamentalDataProvider : BaseFundamentalDataProvider
|
||||
{
|
||||
private DateTime _date;
|
||||
private readonly Dictionary<SecurityIdentifier, CoarseFundamental> _coarseFundamental = new();
|
||||
|
||||
/// <summary>
|
||||
/// Will fetch the requested fundamental information for the requested time and symbol
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The expected data type</typeparam>
|
||||
/// <param name="time">The time to request this data for</param>
|
||||
/// <param name="securityIdentifier">The security identifier</param>
|
||||
/// <param name="name">The name of the fundamental property</param>
|
||||
/// <returns>The fundamental information</returns>
|
||||
public override T Get<T>(DateTime time, SecurityIdentifier securityIdentifier, FundamentalProperty name)
|
||||
{
|
||||
var enumName = Enum.GetName(name);
|
||||
lock (_coarseFundamental)
|
||||
{
|
||||
if (time == _date)
|
||||
{
|
||||
return GetProperty<T>(securityIdentifier, enumName);
|
||||
}
|
||||
_date = time;
|
||||
|
||||
var path = Path.Combine(Globals.DataFolder, "equity", "usa", "fundamental", "coarse", $"{time:yyyyMMdd}.csv");
|
||||
var fileStream = DataProvider.Fetch(path);
|
||||
if (fileStream == null)
|
||||
{
|
||||
return GetDefault<T>();
|
||||
}
|
||||
|
||||
_coarseFundamental.Clear();
|
||||
using (var reader = new StreamReader(fileStream))
|
||||
{
|
||||
while (!reader.EndOfStream)
|
||||
{
|
||||
var line = reader.ReadLine();
|
||||
var coarse = Read(line, time);
|
||||
if (coarse != null)
|
||||
{
|
||||
_coarseFundamental[coarse.Symbol.ID] = coarse;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return GetProperty<T>(securityIdentifier, enumName);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads the given line and returns a CoarseFundamentalSource with the information within it
|
||||
/// </summary>
|
||||
public static CoarseFundamentalSource Read(string line, DateTime date)
|
||||
{
|
||||
try
|
||||
{
|
||||
var csv = line.Split(',');
|
||||
var coarse = new CoarseFundamentalSource
|
||||
{
|
||||
Symbol = new Symbol(SecurityIdentifier.Parse(csv[0]), csv[1]),
|
||||
Time = date,
|
||||
Value = csv[2].ToDecimal(),
|
||||
VolumeSetter = csv[3].ToInt64(),
|
||||
DollarVolumeSetter = (double)csv[4].ToDecimal()
|
||||
};
|
||||
|
||||
if (csv.Length > 5)
|
||||
{
|
||||
coarse.HasFundamentalDataSetter = csv[5].ConvertInvariant<bool>();
|
||||
}
|
||||
|
||||
if (csv.Length > 7)
|
||||
{
|
||||
coarse.PriceFactorSetter = csv[6].ToDecimal();
|
||||
coarse.SplitFactorSetter = csv[7].ToDecimal();
|
||||
}
|
||||
|
||||
return coarse;
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private dynamic GetProperty<T>(SecurityIdentifier securityIdentifier, string property)
|
||||
{
|
||||
if (!_coarseFundamental.TryGetValue(securityIdentifier, out var coarse))
|
||||
{
|
||||
return GetDefault<T>();
|
||||
}
|
||||
|
||||
switch (property)
|
||||
{
|
||||
case nameof(CoarseFundamental.Price):
|
||||
return coarse.Price;
|
||||
case nameof(CoarseFundamental.Value):
|
||||
return coarse.Value;
|
||||
case nameof(CoarseFundamental.Market):
|
||||
return coarse.Market;
|
||||
case nameof(CoarseFundamental.Volume):
|
||||
return coarse.Volume;
|
||||
case nameof(CoarseFundamental.PriceFactor):
|
||||
return coarse.PriceFactor;
|
||||
case nameof(CoarseFundamental.SplitFactor):
|
||||
return coarse.SplitFactor;
|
||||
case nameof(CoarseFundamental.DollarVolume):
|
||||
return coarse.DollarVolume;
|
||||
case nameof(CoarseFundamental.HasFundamentalData):
|
||||
return false;
|
||||
}
|
||||
|
||||
return GetDefault<T>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Coarse fundamental with setters
|
||||
/// </summary>
|
||||
public class CoarseFundamentalSource : CoarseFundamental
|
||||
{
|
||||
/// <summary>
|
||||
/// Property to set the volume of the Coarse Fundamental
|
||||
/// </summary>
|
||||
public long VolumeSetter { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Property to set the dollar volume of the Coarse Fundamental
|
||||
/// </summary>
|
||||
public double DollarVolumeSetter { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Property to set the price factor of the Coarse Fundamental
|
||||
/// </summary>
|
||||
public decimal PriceFactorSetter { get; set; } = 1;
|
||||
|
||||
/// <summary>
|
||||
/// Property to set the split factor of the Coarse Fundamental
|
||||
/// </summary>
|
||||
public decimal SplitFactorSetter { get; set; } = 1;
|
||||
|
||||
/// <summary>
|
||||
/// Property to indicate if the Coarse Fundamental has fundamental data
|
||||
/// </summary>
|
||||
public bool HasFundamentalDataSetter { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the day's dollar volume for this symbol
|
||||
/// </summary>
|
||||
public override double DollarVolume => DollarVolumeSetter;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the day's total volume
|
||||
/// </summary>
|
||||
public override long Volume => VolumeSetter;
|
||||
|
||||
/// <summary>
|
||||
/// Returns whether the symbol has fundamental data for the given date
|
||||
/// </summary>
|
||||
public override bool HasFundamentalData => HasFundamentalDataSetter;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the price factor for the given date
|
||||
/// </summary>
|
||||
public override decimal PriceFactor => PriceFactorSetter;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the split factor for the given date
|
||||
/// </summary>
|
||||
public override decimal SplitFactor => SplitFactorSetter;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,104 @@
|
||||
/*
|
||||
* 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.Generic;
|
||||
using QuantConnect.Util;
|
||||
|
||||
namespace QuantConnect.Data.UniverseSelection
|
||||
{
|
||||
/// <summary>
|
||||
/// Defines a universe that reads coarse us equity data
|
||||
/// </summary>
|
||||
public class CoarseFundamentalUniverse : Universe
|
||||
{
|
||||
private readonly Func<IEnumerable<CoarseFundamental>, IEnumerable<Symbol>> _selector;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="CoarseFundamentalUniverse"/> class
|
||||
/// </summary>
|
||||
/// <param name="universeSettings">The settings used for new subscriptions generated by this universe</param>
|
||||
/// <param name="selector">Returns the symbols that should be included in the universe</param>
|
||||
public CoarseFundamentalUniverse(UniverseSettings universeSettings, Func<IEnumerable<CoarseFundamental>, IEnumerable<Symbol>> selector)
|
||||
: base(CreateConfiguration(FundamentalUniverseFactory.SymbolFactory.UniverseSymbol()))
|
||||
{
|
||||
UniverseSettings = universeSettings;
|
||||
_selector = selector;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="CoarseFundamentalUniverse"/> class
|
||||
/// </summary>
|
||||
/// <param name="universeSettings">The settings used for new subscriptions generated by this universe</param>
|
||||
/// <param name="selector">Returns the symbols that should be included in the universe</param>
|
||||
public CoarseFundamentalUniverse(UniverseSettings universeSettings, PyObject selector)
|
||||
: this(FundamentalUniverseFactory.SymbolFactory.UniverseSymbol(), universeSettings, selector)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="CoarseFundamentalUniverse"/> class
|
||||
/// </summary>
|
||||
/// <param name="symbol">Defines the symbol to use for this universe</param>
|
||||
/// <param name="universeSettings">The settings used for new subscriptions generated by this universe</param>
|
||||
/// <param name="selector">Returns the symbols that should be included in the universe</param>
|
||||
public CoarseFundamentalUniverse(Symbol symbol, UniverseSettings universeSettings, Func<IEnumerable<CoarseFundamental>, IEnumerable<Symbol>> selector)
|
||||
: base(CreateConfiguration(symbol))
|
||||
{
|
||||
UniverseSettings = universeSettings;
|
||||
_selector = selector;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="CoarseFundamentalUniverse"/> class
|
||||
/// </summary>
|
||||
/// <param name="symbol">Defines the symbol to use for this universe</param>
|
||||
/// <param name="universeSettings">The settings used for new subscriptions generated by this universe</param>
|
||||
/// <param name="selector">Returns the symbols that should be included in the universe</param>
|
||||
public CoarseFundamentalUniverse(Symbol symbol, UniverseSettings universeSettings, PyObject selector)
|
||||
: base(CreateConfiguration(symbol))
|
||||
{
|
||||
UniverseSettings = universeSettings;
|
||||
Func<IEnumerable<CoarseFundamental>, object> func;
|
||||
if (selector.TrySafeAs(out func))
|
||||
{
|
||||
_selector = func.ConvertToUniverseSelectionSymbolDelegate();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Performs universe selection using the data specified
|
||||
/// </summary>
|
||||
/// <param name="utcTime">The current utc time</param>
|
||||
/// <param name="data">The symbols to remain in the universe</param>
|
||||
/// <returns>The data that passes the filter</returns>
|
||||
public override IEnumerable<Symbol> SelectSymbols(DateTime utcTime, BaseDataCollection data)
|
||||
{
|
||||
return _selector(new CastingEnumerable<BaseData, CoarseFundamental>(data.Data));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a <see cref="CoarseFundamental"/> subscription configuration for the US-equity market
|
||||
/// </summary>
|
||||
/// <param name="symbol">The symbol used in the returned configuration</param>
|
||||
/// <returns>A coarse fundamental subscription configuration with the specified symbol</returns>
|
||||
public static SubscriptionDataConfig CreateConfiguration(Symbol symbol)
|
||||
{
|
||||
return FundamentalUniverseFactory.CreateConfiguration(symbol);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,157 @@
|
||||
/*
|
||||
* 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.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Python.Runtime;
|
||||
|
||||
namespace QuantConnect.Data.UniverseSelection
|
||||
{
|
||||
/// <summary>
|
||||
/// ConstituentsUniverse allows to perform universe selection based on an
|
||||
/// already preselected set of <see cref="Symbol"/>.
|
||||
/// </summary>
|
||||
/// <remarks>Using this class allows a performance improvement, since there is no
|
||||
/// runtime logic computation required for selecting the <see cref="Symbol"/></remarks>
|
||||
public class ConstituentsUniverse<T> : FuncUniverse<T>
|
||||
where T : BaseData
|
||||
{
|
||||
/// <summary>
|
||||
/// Creates a new instance of the <see cref="ConstituentsUniverse"/>
|
||||
/// </summary>
|
||||
/// <param name="symbol">The universe symbol</param>
|
||||
/// <param name="universeSettings">The universe settings to use</param>
|
||||
/// <param name="constituentsFilter">User-provided function to filter constituents universe with</param>
|
||||
public ConstituentsUniverse(
|
||||
Symbol symbol,
|
||||
UniverseSettings universeSettings,
|
||||
Func<IEnumerable<T>, IEnumerable<Symbol>> constituentsFilter = null)
|
||||
: this(new SubscriptionDataConfig(typeof(T),
|
||||
symbol,
|
||||
Resolution.Daily,
|
||||
TimeZones.NewYork,
|
||||
TimeZones.NewYork,
|
||||
false,
|
||||
false,
|
||||
true,
|
||||
true),
|
||||
universeSettings,
|
||||
constituentsFilter)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new instance of the <see cref="ConstituentsUniverse"/>
|
||||
/// </summary>
|
||||
/// <param name="symbol">The universe symbol</param>
|
||||
/// <param name="universeSettings">The universe settings to use</param>
|
||||
/// <param name="constituentsFilter">User-provided function to filter constituents universe with</param>
|
||||
public ConstituentsUniverse(
|
||||
Symbol symbol,
|
||||
UniverseSettings universeSettings,
|
||||
PyObject constituentsFilter = null)
|
||||
: this(symbol, universeSettings, constituentsFilter.ConvertPythonUniverseFilterFunction<T>())
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new instance of the <see cref="ConstituentsUniverse"/>
|
||||
/// </summary>
|
||||
/// <param name="subscriptionDataConfig">The universe configuration to use</param>
|
||||
/// <param name="universeSettings">The universe settings to use</param>
|
||||
/// <param name="constituentsFilter">User-provided function to filter constituents universe with</param>
|
||||
public ConstituentsUniverse(
|
||||
SubscriptionDataConfig subscriptionDataConfig,
|
||||
UniverseSettings universeSettings,
|
||||
Func<IEnumerable<T>, IEnumerable<Symbol>> constituentsFilter = null)
|
||||
: base(subscriptionDataConfig,
|
||||
universeSettings,
|
||||
constituentsFilter ?? (constituents =>
|
||||
{
|
||||
var symbols = constituents.Select(baseData => baseData.Symbol).ToList();
|
||||
// for performance, just compare to Symbol.None if we have 1 Symbol
|
||||
if (symbols.Count == 1 && symbols[0] == Symbol.None)
|
||||
{
|
||||
// no symbol selected
|
||||
return Enumerable.Empty<Symbol>();
|
||||
}
|
||||
|
||||
return symbols;
|
||||
}))
|
||||
{
|
||||
if (!subscriptionDataConfig.IsCustomData)
|
||||
{
|
||||
throw new InvalidOperationException($"{typeof(T).Name} {nameof(SubscriptionDataConfig)}" +
|
||||
$" only supports custom data property set to 'true'");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constituent universe for a Python function
|
||||
/// </summary>
|
||||
/// <param name="subscriptionDataConfig">The universe configuration to use</param>
|
||||
/// <param name="universeSettings">The universe settings to use</param>
|
||||
/// <param name="constituentsFilter">User-provided function to filter constituents universe with</param>
|
||||
public ConstituentsUniverse(
|
||||
SubscriptionDataConfig subscriptionDataConfig,
|
||||
UniverseSettings universeSettings,
|
||||
PyObject constituentsFilter = null)
|
||||
: this(subscriptionDataConfig, universeSettings, constituentsFilter.ConvertPythonUniverseFilterFunction<T>())
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// ConstituentsUniverse allows to perform universe selection based on an
|
||||
/// already preselected set of <see cref="Symbol"/>.
|
||||
/// </summary>
|
||||
/// <remarks>Using this class allows a performance improvement, since there is no
|
||||
/// runtime logic computation required for selecting the <see cref="Symbol"/></remarks>
|
||||
public class ConstituentsUniverse : ConstituentsUniverse<ConstituentsUniverseData>
|
||||
{
|
||||
/// <summary>
|
||||
/// Creates a new instance of the <see cref="ConstituentsUniverse"/>
|
||||
/// </summary>
|
||||
/// <param name="symbol">The universe symbol</param>
|
||||
/// <param name="universeSettings">The universe settings to use</param>
|
||||
/// <param name="filterFunc">The constituents filter function</param>
|
||||
public ConstituentsUniverse(Symbol symbol, UniverseSettings universeSettings, Func<IEnumerable<ConstituentsUniverseData>, IEnumerable<Symbol>> filterFunc)
|
||||
: base(symbol, universeSettings, filterFunc)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new instance of the <see cref="ConstituentsUniverse"/>
|
||||
/// </summary>
|
||||
/// <param name="symbol">The universe symbol</param>
|
||||
/// <param name="universeSettings">The universe settings to use</param>
|
||||
public ConstituentsUniverse(Symbol symbol, UniverseSettings universeSettings)
|
||||
: base(symbol, universeSettings, (Func<IEnumerable<ConstituentsUniverseData>, IEnumerable<Symbol>>)null)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new instance of the <see cref="ConstituentsUniverse"/>
|
||||
/// </summary>
|
||||
/// <param name="symbol">The universe symbol</param>
|
||||
/// <param name="universeSettings">The universe settings to use</param>
|
||||
/// <param name="filterFunc">The constituents filter function</param>
|
||||
public ConstituentsUniverse(Symbol symbol, UniverseSettings universeSettings, PyObject filterFunc)
|
||||
: base(symbol, universeSettings, filterFunc)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,139 @@
|
||||
/*
|
||||
* 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.IO;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace QuantConnect.Data.UniverseSelection
|
||||
{
|
||||
/// <summary>
|
||||
/// Custom base data class used for <see cref="ConstituentsUniverse"/>
|
||||
/// </summary>
|
||||
public class ConstituentsUniverseData : BaseData
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="CoarseFundamental"/> class
|
||||
/// </summary>
|
||||
public ConstituentsUniverseData()
|
||||
{
|
||||
DataType = MarketDataType.Auxiliary;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The end time of this data.
|
||||
/// </summary>
|
||||
public override DateTime EndTime
|
||||
{
|
||||
get { return Time + QuantConnect.Time.OneDay; }
|
||||
set { Time = value - QuantConnect.Time.OneDay; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Return the URL string source of the file. This will be converted to a stream
|
||||
/// </summary>
|
||||
/// <param name="config">Configuration object</param>
|
||||
/// <param name="date">Date of this source file</param>
|
||||
/// <param name="isLiveMode">true if we're in live mode, false for backtesting mode</param>
|
||||
/// <returns>String URL of source file.</returns>
|
||||
public override SubscriptionDataSource GetSource(SubscriptionDataConfig config, DateTime date, bool isLiveMode)
|
||||
{
|
||||
var universe = config.Symbol.ID.Symbol.Substring(config.MappedSymbol.LastIndexOf('-') + 1);
|
||||
|
||||
if (isLiveMode)
|
||||
{
|
||||
date = date.AddDays(-1);
|
||||
}
|
||||
var path = Path.Combine(Globals.DataFolder,
|
||||
config.SecurityType.SecurityTypeToLower(),
|
||||
config.Market,
|
||||
"universes",
|
||||
config.Resolution.ResolutionToLower(),
|
||||
universe,
|
||||
$"{date:yyyyMMdd}.csv");
|
||||
return new SubscriptionDataSource(path, SubscriptionTransportMedium.LocalFile, FileFormat.Csv);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reader converts each line of the data source into BaseData objects. Each data type creates its own factory method, and returns a new instance of the object
|
||||
/// each time it is called.
|
||||
/// </summary>
|
||||
/// <param name="config">Subscription data config setup object</param>
|
||||
/// <param name="line">Line of the source document</param>
|
||||
/// <param name="date">Date of the requested data</param>
|
||||
/// <param name="isLiveMode">true if we're in live mode, false for backtesting mode</param>
|
||||
/// <returns>Instance of the T:BaseData object generated by this line of the CSV</returns>
|
||||
public override BaseData Reader(SubscriptionDataConfig config, string line, DateTime date, bool isLiveMode)
|
||||
{
|
||||
try
|
||||
{
|
||||
var csv = line.Split(',');
|
||||
var preselected = new ConstituentsUniverseData
|
||||
{
|
||||
Symbol = new Symbol(SecurityIdentifier.Parse(csv[1]), csv[0]),
|
||||
Time = isLiveMode ? date.AddDays(-1) : date
|
||||
};
|
||||
|
||||
return preselected;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Indicates that the data set is expected to be sparse
|
||||
/// </summary>
|
||||
/// <remarks>Relies on the <see cref="Symbol"/> property value</remarks>
|
||||
/// <remarks>This is a method and not a property so that python
|
||||
/// custom data types can override it</remarks>
|
||||
/// <returns>True if the data set represented by this type is expected to be sparse</returns>
|
||||
public override bool IsSparseData()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Indicates if there is support for mapping
|
||||
/// </summary>
|
||||
/// <returns>True indicates mapping should be used</returns>
|
||||
public override bool RequiresMapping()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the default resolution for this data and security type
|
||||
/// </summary>
|
||||
/// <remarks>This is a method and not a property so that python
|
||||
/// custom data types can override it</remarks>
|
||||
public override Resolution DefaultResolution()
|
||||
{
|
||||
return Resolution.Daily;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the supported resolution for this data and security type
|
||||
/// </summary>
|
||||
/// <remarks>Relies on the <see cref="Symbol"/> property value</remarks>
|
||||
/// <remarks>This is a method and not a property so that python
|
||||
/// custom data types can override it</remarks>
|
||||
public override List<Resolution> SupportedResolutions()
|
||||
{
|
||||
return DailyResolution;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,164 @@
|
||||
/*
|
||||
* 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 QuantConnect.Util;
|
||||
using QuantConnect.Interfaces;
|
||||
using QuantConnect.Securities;
|
||||
using System.Collections.Generic;
|
||||
using QuantConnect.Data.Auxiliary;
|
||||
|
||||
namespace QuantConnect.Data.UniverseSelection
|
||||
{
|
||||
/// <summary>
|
||||
/// Continuous contract universe selection that based on the requested mapping mode will select each symbol
|
||||
/// </summary>
|
||||
public class ContinuousContractUniverse : Universe, ITimeTriggeredUniverse
|
||||
{
|
||||
private readonly IMapFileProvider _mapFileProvider;
|
||||
private readonly SubscriptionDataConfig _config;
|
||||
private readonly Security _security;
|
||||
private readonly bool _liveMode;
|
||||
private Symbol _currentSymbol;
|
||||
private string _mappedSymbol;
|
||||
|
||||
/// <summary>
|
||||
/// True if this universe filter can run async in the data stack
|
||||
/// TODO: see IContinuousSecurity.Mapped
|
||||
/// </summary>
|
||||
public override bool Asynchronous => false;
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new instance
|
||||
/// </summary>
|
||||
public ContinuousContractUniverse(Security security, UniverseSettings universeSettings, bool liveMode, SubscriptionDataConfig universeConfig)
|
||||
: base(universeConfig)
|
||||
{
|
||||
_security = security;
|
||||
_liveMode = liveMode;
|
||||
UniverseSettings = universeSettings;
|
||||
_mapFileProvider = Composer.Instance.GetPart<IMapFileProvider>();
|
||||
|
||||
_config = new SubscriptionDataConfig(Configuration, dataMappingMode: UniverseSettings.DataMappingMode, symbol: _security.Symbol.Canonical);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Performs universe selection based on the symbol mapping
|
||||
/// </summary>
|
||||
/// <param name="utcTime">The current utc time</param>
|
||||
/// <param name="data">Empty data</param>
|
||||
/// <returns>The symbols to use</returns>
|
||||
public override IEnumerable<Symbol> SelectSymbols(DateTime utcTime, BaseDataCollection data)
|
||||
{
|
||||
yield return _security.Symbol.Canonical;
|
||||
|
||||
var mapFile = _mapFileProvider.ResolveMapFile(_config);
|
||||
var mappedSymbol = mapFile.GetMappedSymbol(utcTime.ConvertFromUtc(_security.Exchange.TimeZone), dataMappingMode: _config.DataMappingMode);
|
||||
if (!string.IsNullOrEmpty(mappedSymbol) && mappedSymbol != _mappedSymbol)
|
||||
{
|
||||
if (_currentSymbol != null)
|
||||
{
|
||||
// let's emit the old and new for the mapping date
|
||||
yield return _currentSymbol;
|
||||
}
|
||||
_mappedSymbol = mappedSymbol;
|
||||
|
||||
_currentSymbol = _security.Symbol.Canonical
|
||||
.UpdateMappedSymbol(mappedSymbol, Configuration.ContractDepthOffset)
|
||||
.Underlying;
|
||||
}
|
||||
|
||||
if (_currentSymbol != null)
|
||||
{
|
||||
// TODO: this won't work with async universe selection
|
||||
((IContinuousSecurity)_security).Mapped = _currentSymbol;
|
||||
yield return _currentSymbol;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the subscription requests to be added for the specified security
|
||||
/// </summary>
|
||||
/// <param name="security">The security to get subscriptions for</param>
|
||||
/// <param name="currentTimeUtc">The current time in utc. This is the frontier time of the algorithm</param>
|
||||
/// <param name="maximumEndTimeUtc">The max end time</param>
|
||||
/// <param name="subscriptionService">Instance which implements <see cref="ISubscriptionDataConfigService"/> interface</param>
|
||||
/// <returns>All subscriptions required by this security</returns>
|
||||
public override IEnumerable<SubscriptionRequest> GetSubscriptionRequests(Security security,
|
||||
DateTime currentTimeUtc,
|
||||
DateTime maximumEndTimeUtc,
|
||||
ISubscriptionDataConfigService subscriptionService)
|
||||
{
|
||||
var configs = AddConfigurations(subscriptionService, UniverseSettings, security.Symbol);
|
||||
return configs.Select(config => new SubscriptionRequest(isUniverseSubscription: false,
|
||||
universe: this,
|
||||
security: security,
|
||||
configuration: new SubscriptionDataConfig(config, isInternalFeed: config.IsInternalFeed || config.TickType == TickType.OpenInterest),
|
||||
startTimeUtc: currentTimeUtc,
|
||||
endTimeUtc: maximumEndTimeUtc));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Each tradeable day of the future we trigger a new selection.
|
||||
/// Allows use to select the current contract
|
||||
/// </summary>
|
||||
public IEnumerable<DateTime> GetTriggerTimes(DateTime startTimeUtc, DateTime endTimeUtc, MarketHoursDatabase marketHoursDatabase)
|
||||
{
|
||||
var startTimeLocal = startTimeUtc.ConvertFromUtc(_security.Exchange.TimeZone);
|
||||
var endTimeLocal = endTimeUtc.ConvertFromUtc(_security.Exchange.TimeZone);
|
||||
|
||||
return Time.EachTradeableDay(_security, startTimeLocal, endTimeLocal, Configuration.ExtendedMarketHours)
|
||||
// in live trading selection happens on start see 'DataQueueFuturesChainUniverseDataCollectionEnumerator'
|
||||
.Where(tradeableDay => _liveMode || tradeableDay >= startTimeLocal)
|
||||
// in live trading we delay selection so that we make sure auxiliary data is ready
|
||||
.Select(time => _liveMode ? time.Add(Time.LiveAuxiliaryDataOffset) : time);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Helper method to add and get the required configurations associated with a continuous universe
|
||||
/// </summary>
|
||||
public static List<SubscriptionDataConfig> AddConfigurations(ISubscriptionDataConfigService subscriptionService, UniverseSettings universeSettings, Symbol symbol)
|
||||
{
|
||||
List<SubscriptionDataConfig> configs = new(universeSettings.SubscriptionDataTypes.Count);
|
||||
foreach (var pair in universeSettings.SubscriptionDataTypes)
|
||||
{
|
||||
configs.AddRange(subscriptionService.Add(symbol,
|
||||
universeSettings.Resolution,
|
||||
universeSettings.FillForward,
|
||||
universeSettings.ExtendedMarketHours,
|
||||
dataNormalizationMode: universeSettings.DataNormalizationMode,
|
||||
// we need to provider the data types we want, else since it's canonical it would assume the default ZipEntry type used in universe chain
|
||||
subscriptionDataTypes: new List<Tuple<Type, TickType>> { pair },
|
||||
dataMappingMode: universeSettings.DataMappingMode,
|
||||
contractDepthOffset: (uint)Math.Abs(universeSettings.ContractDepthOffset),
|
||||
// open interest is internal and the underlying mapped contracts of the continuous canonical
|
||||
isInternalFeed: !symbol.IsCanonical() || pair.Item2 == TickType.OpenInterest));
|
||||
}
|
||||
return configs;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a continuous universe symbol
|
||||
/// </summary>
|
||||
/// <param name="symbol">The associated symbol</param>
|
||||
/// <returns>A symbol for a continuous universe of the specified symbol</returns>
|
||||
public static Symbol CreateSymbol(Symbol symbol)
|
||||
{
|
||||
var ticker = $"qc-universe-continuous-{symbol.ID.Market.ToLowerInvariant()}-{symbol.SecurityType}-{symbol.ID.Symbol}";
|
||||
return UniverseExtensions.CreateSymbol(symbol.SecurityType, symbol.ID.Market, ticker);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,122 @@
|
||||
/*
|
||||
* 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 QuantConnect.Data.Market;
|
||||
|
||||
namespace QuantConnect.Data.UniverseSelection;
|
||||
|
||||
/// <summary>
|
||||
/// Represents derivative market data including trade and open interest information.
|
||||
/// </summary>
|
||||
public class DerivativeUniverseData
|
||||
{
|
||||
private readonly Symbol _symbol;
|
||||
private decimal _open;
|
||||
private decimal _high;
|
||||
private decimal _low;
|
||||
private decimal _close;
|
||||
private decimal _volume;
|
||||
private decimal? _openInterest;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of <see cref="DerivativeUniverseData"/> using open interest data.
|
||||
/// </summary>
|
||||
/// <param name="openInterest">The open interest data.</param>
|
||||
public DerivativeUniverseData(OpenInterest openInterest)
|
||||
{
|
||||
_symbol = openInterest.Symbol;
|
||||
_openInterest = openInterest.Value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of <see cref="DerivativeUniverseData"/> using trade bar data.
|
||||
/// </summary>
|
||||
/// <param name="tradeBar">The trade bar data.</param>
|
||||
public DerivativeUniverseData(TradeBar tradeBar)
|
||||
{
|
||||
_symbol = tradeBar.Symbol;
|
||||
_open = tradeBar.Open;
|
||||
_high = tradeBar.High;
|
||||
_low = tradeBar.Low;
|
||||
_close = tradeBar.Close;
|
||||
_volume = tradeBar.Volume;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of <see cref="DerivativeUniverseData"/> using quote bar data.
|
||||
/// </summary>
|
||||
/// <param name="quoteBar">The quote bar data.</param>
|
||||
public DerivativeUniverseData(QuoteBar quoteBar)
|
||||
{
|
||||
_symbol = quoteBar.Symbol;
|
||||
_open = quoteBar.Open;
|
||||
_high = quoteBar.High;
|
||||
_low = quoteBar.Low;
|
||||
_close = quoteBar.Close;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Updates the instance with new trade bar data.
|
||||
/// </summary>
|
||||
/// <param name="tradeBar">The new trade bar data.</param>
|
||||
/// <exception cref="ArgumentNullException">Thrown when tradeBar is null.</exception>
|
||||
public void UpdateByTradeBar(TradeBar tradeBar)
|
||||
{
|
||||
// If price data has already been initialized (likely from a QuoteBar)
|
||||
if (_open != 0 || _high != 0 || _low != 0 || _close != 0)
|
||||
{
|
||||
_volume = tradeBar.Volume;
|
||||
return;
|
||||
}
|
||||
|
||||
_open = tradeBar.Open;
|
||||
_high = tradeBar.High;
|
||||
_low = tradeBar.Low;
|
||||
_close = tradeBar.Close;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Updates the instance with new quote bar data.
|
||||
/// </summary>
|
||||
/// <param name="quoteBar">The new quote bar data.</param>
|
||||
public void UpdateByQuoteBar(QuoteBar quoteBar)
|
||||
{
|
||||
_open = quoteBar.Open;
|
||||
_high = quoteBar.High;
|
||||
_low = quoteBar.Low;
|
||||
_close = quoteBar.Close;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Updates the instance with new open interest data.
|
||||
/// </summary>
|
||||
/// <param name="openInterest">The new open interest data.</param>
|
||||
/// <exception cref="ArgumentNullException">Thrown when openInterest is null.</exception>
|
||||
public void UpdateByOpenInterest(OpenInterest openInterest)
|
||||
{
|
||||
_openInterest = openInterest.Value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts the current data to a CSV format string.
|
||||
/// </summary>
|
||||
/// <returns>A CSV formatted string representing the data.</returns>
|
||||
public string ToCsv()
|
||||
{
|
||||
return OptionUniverse.ToCsv(_symbol, _open, _high, _low, _close, _volume, _openInterest, null, NullGreeks.Instance);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,210 @@
|
||||
/*
|
||||
* 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.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using NodaTime;
|
||||
using QuantConnect.Util;
|
||||
|
||||
namespace QuantConnect.Data.UniverseSelection
|
||||
{
|
||||
/// <summary>
|
||||
/// ETF Constituent data
|
||||
/// </summary>
|
||||
[Obsolete("'ETFConstituentData' was renamed to 'ETFConstituentUniverse'")]
|
||||
public class ETFConstituentData : ETFConstituentUniverse { }
|
||||
|
||||
/// <summary>
|
||||
/// ETF constituent data
|
||||
/// </summary>
|
||||
public class ETFConstituentUniverse : BaseDataCollection
|
||||
{
|
||||
/// <summary>
|
||||
/// Time of the previous ETF constituent data update
|
||||
/// </summary>
|
||||
public DateTime? LastUpdate { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The percentage of the ETF allocated to this constituent
|
||||
/// </summary>
|
||||
public decimal? Weight { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Number of shares held in the ETF
|
||||
/// </summary>
|
||||
public decimal? SharesHeld { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Market value of the current asset held in U.S. dollars
|
||||
/// </summary>
|
||||
public decimal? MarketValue { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Period of the data
|
||||
/// </summary>
|
||||
public TimeSpan Period { get; set; } = TimeSpan.FromDays(1);
|
||||
|
||||
/// <summary>
|
||||
/// Time that the data became available to use
|
||||
/// </summary>
|
||||
public override DateTime EndTime
|
||||
{
|
||||
get { return Time + Period; }
|
||||
set { Time = value - Period; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Return the URL string source of the file. This will be converted to a stream
|
||||
/// </summary>
|
||||
/// <param name="config">Configuration object</param>
|
||||
/// <param name="date">Date of this source file</param>
|
||||
/// <param name="isLiveMode">true if we're in live mode, false for backtesting mode</param>
|
||||
/// <returns>String URL of source file.</returns>
|
||||
public override SubscriptionDataSource GetSource(SubscriptionDataConfig config, DateTime date, bool isLiveMode)
|
||||
{
|
||||
return new SubscriptionDataSource(
|
||||
Path.Combine(
|
||||
Globals.DataFolder,
|
||||
config.SecurityType.SecurityTypeToLower(),
|
||||
config.Market,
|
||||
"universes",
|
||||
"etf",
|
||||
config.Symbol.Underlying.Value.ToLowerInvariant(),
|
||||
$"{date:yyyyMMdd}.csv"),
|
||||
SubscriptionTransportMedium.LocalFile,
|
||||
FileFormat.FoldingCollection);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reader converts each line of the data source into BaseData objects. Each data type creates its own factory method, and returns a new instance of the object
|
||||
/// each time it is called.
|
||||
/// </summary>
|
||||
/// <param name="config">Subscription data config setup object</param>
|
||||
/// <param name="line">Line of the source document</param>
|
||||
/// <param name="date">Date of the requested data</param>
|
||||
/// <param name="isLiveMode">true if we're in live mode, false for backtesting mode</param>
|
||||
/// <returns>Instance of the T:BaseData object generated by this line of the CSV</returns>
|
||||
public override BaseData Reader(SubscriptionDataConfig config, string line, DateTime date, bool isLiveMode)
|
||||
{
|
||||
if (string.IsNullOrEmpty(line))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var split = line.Split(',');
|
||||
|
||||
var symbol = new Symbol(SecurityIdentifier.Parse(split[1]), split[0]);
|
||||
var lastUpdateDate = Parse.TryParseExact(split[2], "yyyyMMdd", DateTimeStyles.None, out var lastUpdateDateParsed)
|
||||
? lastUpdateDateParsed
|
||||
: (DateTime?)null;
|
||||
var weighting = split[3].IsNullOrEmpty()
|
||||
? (decimal?)null
|
||||
: Parse.Decimal(split[3], NumberStyles.Any);
|
||||
var sharesHeld = split[4].IsNullOrEmpty()
|
||||
? (decimal?)null
|
||||
: Parse.Decimal(split[4], NumberStyles.Any);
|
||||
var marketValue = split[5].IsNullOrEmpty()
|
||||
? (decimal?)null
|
||||
: Parse.Decimal(split[5], NumberStyles.Any);
|
||||
|
||||
return new ETFConstituentUniverse
|
||||
{
|
||||
LastUpdate = lastUpdateDate,
|
||||
Weight = weighting,
|
||||
SharesHeld = sharesHeld,
|
||||
MarketValue = marketValue,
|
||||
|
||||
Symbol = symbol,
|
||||
Time = date
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Indicates if there is support for mapping
|
||||
/// </summary>
|
||||
/// <returns>True indicates mapping should be used</returns>
|
||||
public override bool RequiresMapping()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a copy of the instance
|
||||
/// </summary>
|
||||
/// <returns>Clone of the instance</returns>
|
||||
public override BaseData Clone()
|
||||
{
|
||||
return new ETFConstituentUniverse
|
||||
{
|
||||
LastUpdate = LastUpdate,
|
||||
Weight = Weight,
|
||||
SharesHeld = SharesHeld,
|
||||
MarketValue = MarketValue,
|
||||
|
||||
Symbol = Symbol,
|
||||
Time = Time,
|
||||
Data = Data
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Indicates that the data set is expected to be sparse
|
||||
/// </summary>
|
||||
/// <remarks>Relies on the <see cref="Symbol"/> property value</remarks>
|
||||
/// <remarks>This is a method and not a property so that python
|
||||
/// custom data types can override it</remarks>
|
||||
/// <returns>True if the data set represented by this type is expected to be sparse</returns>
|
||||
public override bool IsSparseData()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the default resolution for this data and security type
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This is a method and not a property so that python
|
||||
/// custom data types can override it.
|
||||
/// </remarks>
|
||||
public override Resolution DefaultResolution()
|
||||
{
|
||||
return Resolution.Daily;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the supported resolution for this data and security type
|
||||
/// </summary>
|
||||
/// <remarks>Relies on the <see cref="Symbol"/> property value</remarks>
|
||||
/// <remarks>This is a method and not a property so that python
|
||||
/// custom data types can override it</remarks>
|
||||
public override List<Resolution> SupportedResolutions()
|
||||
{
|
||||
return DailyResolution;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Specifies the data time zone for this data type. This is useful for custom data types
|
||||
/// </summary>
|
||||
/// <remarks>Will throw <see cref="InvalidOperationException"/> for security types
|
||||
/// other than <see cref="SecurityType.Base"/></remarks>
|
||||
/// <returns>The <see cref="DateTimeZone"/> of this data type</returns>
|
||||
public override DateTimeZone DataTimeZone()
|
||||
{
|
||||
return TimeZones.Utc;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
/*
|
||||
* 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.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using Python.Runtime;
|
||||
|
||||
namespace QuantConnect.Data.UniverseSelection
|
||||
{
|
||||
/// <summary>
|
||||
/// Creates a universe based on an ETF's holdings at a given date
|
||||
/// </summary>
|
||||
public class ETFConstituentsUniverseFactory : ConstituentsUniverse<ETFConstituentUniverse>
|
||||
{
|
||||
private static int _universeCount;
|
||||
private const string _etfConstituentsUniverseIdentifier = "qc-universe-etf-constituents";
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new universe for the constituents of the ETF provided as <paramref name="symbol"/>
|
||||
/// </summary>
|
||||
/// <param name="symbol">The ETF to load constituents for</param>
|
||||
/// <param name="universeSettings">Universe settings</param>
|
||||
/// <param name="constituentsFilter">The filter function used to filter out ETF constituents from the universe</param>
|
||||
public ETFConstituentsUniverseFactory(Symbol symbol, UniverseSettings universeSettings, Func<IEnumerable<ETFConstituentUniverse>, IEnumerable<Symbol>> constituentsFilter = null)
|
||||
: base(CreateConstituentUniverseETFSymbol(symbol), universeSettings, constituentsFilter ?? (constituents => constituents.Select(c => c.Symbol)))
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new universe for the constituents of the ETF provided as <paramref name="symbol"/>
|
||||
/// </summary>
|
||||
/// <param name="symbol">The ETF to load constituents for</param>
|
||||
/// <param name="universeSettings">Universe settings</param>
|
||||
/// <param name="constituentsFilter">The filter function used to filter out ETF constituents from the universe</param>
|
||||
public ETFConstituentsUniverseFactory(Symbol symbol, UniverseSettings universeSettings, PyObject constituentsFilter)
|
||||
: this(symbol, universeSettings, constituentsFilter.ConvertPythonUniverseFilterFunction<ETFConstituentUniverse>())
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a universe Symbol for constituent ETFs
|
||||
/// </summary>
|
||||
/// <param name="compositeSymbol">The Symbol of the ETF</param>
|
||||
/// <returns>Universe Symbol with ETF set as underlying</returns>
|
||||
private static Symbol CreateConstituentUniverseETFSymbol(Symbol compositeSymbol)
|
||||
{
|
||||
var universeTicker = $"{_etfConstituentsUniverseIdentifier}-{Interlocked.Increment(ref _universeCount):D10}-{Guid.NewGuid()}";
|
||||
|
||||
return new Symbol(
|
||||
SecurityIdentifier.GenerateConstituentIdentifier(
|
||||
universeTicker,
|
||||
compositeSymbol.SecurityType,
|
||||
compositeSymbol.ID.Market),
|
||||
universeTicker,
|
||||
compositeSymbol);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
* 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 Python.Runtime;
|
||||
using System.Collections.Generic;
|
||||
using QuantConnect.Data.Fundamental;
|
||||
|
||||
namespace QuantConnect.Data.UniverseSelection
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides a universe that can be filtered with a <see cref="FineFundamental"/> selection function
|
||||
/// </summary>
|
||||
public class FineFundamentalFilteredUniverse : SelectSymbolsUniverseDecorator
|
||||
{
|
||||
/// <summary>
|
||||
/// The universe that will be used for fine universe selection
|
||||
/// </summary>
|
||||
public FineFundamentalUniverse FineFundamentalUniverse { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="FineFundamentalFilteredUniverse"/> class
|
||||
/// </summary>
|
||||
/// <param name="universe">The universe to be filtered</param>
|
||||
/// <param name="fineSelector">The fine selection function</param>
|
||||
public FineFundamentalFilteredUniverse(Universe universe, Func<IEnumerable<FineFundamental>, IEnumerable<Symbol>> fineSelector)
|
||||
: base(universe, universe.SelectSymbols)
|
||||
{
|
||||
if (universe is CoarseFundamentalUniverse && universe.UniverseSettings.Asynchronous.HasValue && universe.UniverseSettings.Asynchronous.Value)
|
||||
{
|
||||
throw new ArgumentException("Asynchronous universe setting is not supported for coarse & fine selections, please use the new Fundamental single pass selection");
|
||||
}
|
||||
|
||||
FineFundamentalUniverse = new FineFundamentalUniverse(universe.UniverseSettings, fineSelector);
|
||||
FineFundamentalUniverse.SelectionChanged += (sender, args) => OnSelectionChanged(((SelectionEventArgs) args).CurrentSelection);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="FineFundamentalFilteredUniverse"/> class
|
||||
/// </summary>
|
||||
/// <param name="universe">The universe to be filtered</param>
|
||||
/// <param name="fineSelector">The fine selection function</param>
|
||||
public FineFundamentalFilteredUniverse(Universe universe, PyObject fineSelector)
|
||||
: base(universe, universe.SelectSymbols)
|
||||
{
|
||||
var func = fineSelector.SafeAs<Func< IEnumerable<FineFundamental>, object>>();
|
||||
FineFundamentalUniverse = new FineFundamentalUniverse(universe.UniverseSettings, func.ConvertToUniverseSelectionSymbolDelegate());
|
||||
FineFundamentalUniverse.SelectionChanged += (sender, args) => OnSelectionChanged(((SelectionEventArgs)args).CurrentSelection);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
/*
|
||||
* 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 System.Collections.Generic;
|
||||
using QuantConnect.Data.Fundamental;
|
||||
using QuantConnect.Util;
|
||||
|
||||
namespace QuantConnect.Data.UniverseSelection
|
||||
{
|
||||
/// <summary>
|
||||
/// Defines a universe that reads fine us equity data
|
||||
/// </summary>
|
||||
public class FineFundamentalUniverse : Universe
|
||||
{
|
||||
private readonly Func<IEnumerable<FineFundamental>, IEnumerable<Symbol>> _selector;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="FineFundamentalUniverse"/> class
|
||||
/// </summary>
|
||||
/// <param name="universeSettings">The settings used for new subscriptions generated by this universe</param>
|
||||
/// <param name="selector">Returns the symbols that should be included in the universe</param>
|
||||
public FineFundamentalUniverse(UniverseSettings universeSettings, Func<IEnumerable<FineFundamental>, IEnumerable<Symbol>> selector)
|
||||
: base(CreateConfiguration(FundamentalUniverseFactory.SymbolFactory.UniverseSymbol()))
|
||||
{
|
||||
UniverseSettings = universeSettings;
|
||||
_selector = selector;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="FineFundamentalUniverse"/> class
|
||||
/// </summary>
|
||||
/// <param name="symbol">Defines the symbol to use for this universe</param>
|
||||
/// <param name="universeSettings">The settings used for new subscriptions generated by this universe</param>
|
||||
/// <param name="selector">Returns the symbols that should be included in the universe</param>
|
||||
public FineFundamentalUniverse(Symbol symbol, UniverseSettings universeSettings, Func<IEnumerable<FineFundamental>, IEnumerable<Symbol>> selector)
|
||||
: base(CreateConfiguration(symbol))
|
||||
{
|
||||
UniverseSettings = universeSettings;
|
||||
_selector = selector;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Performs universe selection using the data specified
|
||||
/// </summary>
|
||||
/// <param name="utcTime">The current utc time</param>
|
||||
/// <param name="data">The symbols to remain in the universe</param>
|
||||
/// <returns>The data that passes the filter</returns>
|
||||
public override IEnumerable<Symbol> SelectSymbols(DateTime utcTime, BaseDataCollection data)
|
||||
{
|
||||
return _selector(new CastingEnumerable<BaseData, FineFundamental>(data.Data));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a <see cref="FineFundamental"/> subscription configuration for the US-equity market
|
||||
/// </summary>
|
||||
/// <param name="symbol">The symbol used in the returned configuration</param>
|
||||
/// <returns>A fine fundamental subscription configuration with the specified symbol</returns>
|
||||
public static SubscriptionDataConfig CreateConfiguration(Symbol symbol)
|
||||
{
|
||||
return FundamentalUniverseFactory.CreateConfiguration(symbol);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,97 @@
|
||||
/*
|
||||
* 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.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Python.Runtime;
|
||||
using QuantConnect.Util;
|
||||
|
||||
namespace QuantConnect.Data.UniverseSelection
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides a functional implementation of <see cref="Universe"/>
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The BaseData type to provide to the user defined universe filter</typeparam>
|
||||
public class FuncUniverse<T> : Universe
|
||||
where T : BaseData
|
||||
{
|
||||
private readonly Func<IEnumerable<T>, IEnumerable<Symbol>> _universeSelector;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="FuncUniverse{T}"/> class
|
||||
/// </summary>
|
||||
/// <param name="configuration">The configuration used to resolve the data for universe selection</param>
|
||||
/// <param name="universeSettings">The settings used for new subscriptions generated by this universe</param>
|
||||
/// <param name="universeSelector">Returns the symbols that should be included in the universe</param>
|
||||
public FuncUniverse(SubscriptionDataConfig configuration, UniverseSettings universeSettings, Func<IEnumerable<T>, IEnumerable<Symbol>> universeSelector)
|
||||
: base(configuration)
|
||||
{
|
||||
_universeSelector = universeSelector;
|
||||
_universeSelector ??= (dataPoints) => dataPoints.Select(x => x.Symbol);
|
||||
UniverseSettings = universeSettings;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="FuncUniverse{T}"/> class for a filter function loaded from Python
|
||||
/// </summary>
|
||||
/// <param name="configuration">The configuration used to resolve the data for universe selection</param>
|
||||
/// <param name="universeSettings">The settings used for new subscriptions generated by this universe</param>
|
||||
/// <param name="universeSelector">Function that returns the symbols that should be included in the universe</param>
|
||||
public FuncUniverse(SubscriptionDataConfig configuration, UniverseSettings universeSettings, PyObject universeSelector)
|
||||
: this(configuration, universeSettings, universeSelector.ConvertPythonUniverseFilterFunction<T>())
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Performs an initial, coarse filter
|
||||
/// </summary>
|
||||
/// <param name="utcTime">The current utc time</param>
|
||||
/// <param name="data">The coarse fundamental data</param>
|
||||
/// <returns>The data that passes the filter</returns>
|
||||
public override IEnumerable<Symbol> SelectSymbols(DateTime utcTime, BaseDataCollection data)
|
||||
{
|
||||
return _universeSelector(new CastingEnumerable<BaseData, T>(data.Data));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Provides a functional implementation of <see cref="Universe"/>
|
||||
/// </summary>
|
||||
public class FuncUniverse : FuncUniverse<BaseData>
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="FuncUniverse"/> class
|
||||
/// </summary>
|
||||
/// <param name="configuration">The configuration used to resolve the data for universe selection</param>
|
||||
/// <param name="universeSettings">The settings used for new subscriptions generated by this universe</param>
|
||||
/// <param name="universeSelector">Returns the symbols that should be included in the universe</param>
|
||||
public FuncUniverse(SubscriptionDataConfig configuration, UniverseSettings universeSettings, Func<IEnumerable<BaseData>, IEnumerable<Symbol>> universeSelector)
|
||||
: base(configuration, universeSettings, universeSelector)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="FuncUniverse"/> class
|
||||
/// </summary>
|
||||
/// <param name="configuration">The configuration used to resolve the data for universe selection</param>
|
||||
/// <param name="universeSettings">The settings used for new subscriptions generated by this universe</param>
|
||||
/// <param name="universeSelector">Returns the symbols that should be included in the universe</param>
|
||||
public FuncUniverse(SubscriptionDataConfig configuration, UniverseSettings universeSettings, PyObject universeSelector)
|
||||
: base(configuration, universeSettings, universeSelector)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* 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 Python.Runtime;
|
||||
using System.Collections.Generic;
|
||||
using QuantConnect.Data.Fundamental;
|
||||
|
||||
namespace QuantConnect.Data.UniverseSelection
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides a universe that can be filtered with a <see cref="Fundamental.Fundamental"/> selection function
|
||||
/// </summary>
|
||||
public class FundamentalFilteredUniverse : SelectSymbolsUniverseDecorator
|
||||
{
|
||||
/// <summary>
|
||||
/// The universe that will be used for fine universe selection
|
||||
/// </summary>
|
||||
public FundamentalUniverseFactory FundamentalUniverse { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="FundamentalFilteredUniverse"/> class
|
||||
/// </summary>
|
||||
/// <param name="universe">The universe to be filtered</param>
|
||||
/// <param name="fundamentalSelector">The fundamental selection function</param>
|
||||
public FundamentalFilteredUniverse(Universe universe, Func<IEnumerable<Fundamental.Fundamental>, IEnumerable<Symbol>> fundamentalSelector)
|
||||
: base(universe, universe.SelectSymbols)
|
||||
{
|
||||
FundamentalUniverse = Fundamental.FundamentalUniverse.USA(fundamentalSelector, universe.UniverseSettings);
|
||||
FundamentalUniverse.SelectionChanged += (sender, args) => OnSelectionChanged(((SelectionEventArgs)args).CurrentSelection);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="FundamentalFilteredUniverse"/> class
|
||||
/// </summary>
|
||||
/// <param name="universe">The universe to be filtered</param>
|
||||
/// <param name="fundamentalSelector">The fundamental selection function</param>
|
||||
public FundamentalFilteredUniverse(Universe universe, PyObject fundamentalSelector)
|
||||
: base(universe, universe.SelectSymbols)
|
||||
{
|
||||
var func = fundamentalSelector.SafeAs<Func<IEnumerable<Fundamental.Fundamental>, object>>();
|
||||
FundamentalUniverse = Fundamental.FundamentalUniverse.USA(func.ConvertToUniverseSelectionSymbolDelegate(), universe.UniverseSettings);
|
||||
FundamentalUniverse.SelectionChanged += (sender, args) => OnSelectionChanged(((SelectionEventArgs)args).CurrentSelection);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
/*
|
||||
* 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 QuantConnect.Util;
|
||||
using QuantConnect.Interfaces;
|
||||
using QuantConnect.Configuration;
|
||||
using QuantConnect.Data.Fundamental;
|
||||
|
||||
namespace QuantConnect.Data.UniverseSelection
|
||||
{
|
||||
/// <summary>
|
||||
/// Fundamental data provider service
|
||||
/// </summary>
|
||||
public static class FundamentalService
|
||||
{
|
||||
private static IFundamentalDataProvider _fundamentalDataProvider;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes the service
|
||||
/// </summary>
|
||||
/// <param name="dataProvider">The data provider instance to use</param>
|
||||
/// <param name="liveMode">True if running in live mode</param>
|
||||
public static void Initialize(IDataProvider dataProvider, bool liveMode)
|
||||
{
|
||||
Initialize(dataProvider, Config.Get("fundamental-data-provider", nameof(CoarseFundamentalDataProvider)), liveMode);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes the service
|
||||
/// </summary>
|
||||
/// <param name="dataProvider">The data provider instance to use</param>
|
||||
/// <param name="fundamentalDataProvider">The fundamental data provider</param>
|
||||
/// <param name="liveMode">True if running in live mode</param>
|
||||
public static void Initialize(IDataProvider dataProvider, string fundamentalDataProvider, bool liveMode)
|
||||
{
|
||||
Initialize(dataProvider, Composer.Instance.GetExportedValueByTypeName<IFundamentalDataProvider>(fundamentalDataProvider), liveMode);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes the service
|
||||
/// </summary>
|
||||
/// <param name="dataProvider">The data provider instance to use</param>
|
||||
/// <param name="fundamentalDataProvider">The fundamental data provider</param>
|
||||
/// <param name="liveMode">True if running in live mode</param>
|
||||
public static void Initialize(IDataProvider dataProvider, IFundamentalDataProvider fundamentalDataProvider, bool liveMode)
|
||||
{
|
||||
_fundamentalDataProvider = fundamentalDataProvider;
|
||||
_fundamentalDataProvider.Initialize(dataProvider, liveMode);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Will fetch the requested fundamental information for the requested time and symbol
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The expected data type</typeparam>
|
||||
/// <param name="time">The time to request this data for</param>
|
||||
/// <param name="symbol">The symbol instance</param>
|
||||
/// <param name="name">The name of the fundamental property</param>
|
||||
/// <returns>The fundamental information</returns>
|
||||
public static T Get<T>(DateTime time, Symbol symbol, FundamentalProperty name) => Get<T>(time, symbol.ID, name);
|
||||
|
||||
/// <summary>
|
||||
/// Will fetch the requested fundamental information for the requested time and symbol
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The expected data type</typeparam>
|
||||
/// <param name="time">The time to request this data for</param>
|
||||
/// <param name="securityIdentifier">The security identifier</param>
|
||||
/// <param name="name">The name of the fundamental property</param>
|
||||
/// <returns>The fundamental information</returns>
|
||||
public static T Get<T>(DateTime time, SecurityIdentifier securityIdentifier, FundamentalProperty name)
|
||||
{
|
||||
return _fundamentalDataProvider.Get<T>(time.Date, securityIdentifier, name);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,112 @@
|
||||
/*
|
||||
* 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.Generic;
|
||||
using QuantConnect.Data.Fundamental;
|
||||
using QuantConnect.Util;
|
||||
|
||||
namespace QuantConnect.Data.UniverseSelection
|
||||
{
|
||||
/// <summary>
|
||||
/// Defines a universe that reads fundamental us equity data
|
||||
/// </summary>
|
||||
public class FundamentalUniverseFactory : Universe
|
||||
{
|
||||
internal static readonly FundamentalUniverse SymbolFactory = new();
|
||||
|
||||
private readonly Func<IEnumerable<Fundamental.Fundamental>, IEnumerable<Symbol>> _selector;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="FundamentalUniverseFactory"/> class
|
||||
/// </summary>
|
||||
/// <param name="market">The target market</param>
|
||||
/// <param name="universeSettings">The settings used for new subscriptions generated by this universe</param>
|
||||
/// <param name="selector">Returns the symbols that should be included in the universe</param>
|
||||
public FundamentalUniverseFactory(string market, UniverseSettings universeSettings, Func<IEnumerable<Fundamental.Fundamental>, IEnumerable<Symbol>> selector)
|
||||
: this(SymbolFactory.UniverseSymbol(market), universeSettings, selector)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="FundamentalUniverseFactory"/> class
|
||||
/// </summary>
|
||||
/// <param name="market">The target market</param>
|
||||
/// <param name="universeSettings">The settings used for new subscriptions generated by this universe</param>
|
||||
/// <param name="selector">Returns the symbols that should be included in the universe</param>
|
||||
public FundamentalUniverseFactory(string market, UniverseSettings universeSettings, PyObject selector)
|
||||
: this(market, universeSettings, selector.SafeAs<Func<IEnumerable<Fundamental.Fundamental>, object>>())
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="FundamentalUniverseFactory"/> class
|
||||
/// </summary>
|
||||
/// <param name="market">The target market</param>
|
||||
/// <param name="universeSettings">The settings used for new subscriptions generated by this universe</param>
|
||||
/// <param name="selector">Returns the symbols that should be included in the universe</param>
|
||||
public FundamentalUniverseFactory(string market, UniverseSettings universeSettings, Func<IEnumerable<Fundamental.Fundamental>, object> selector)
|
||||
: this(market, universeSettings, selector.ConvertToUniverseSelectionSymbolDelegate())
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="FundamentalUniverseFactory"/> class
|
||||
/// </summary>
|
||||
/// <param name="symbol">Defines the symbol to use for this universe</param>
|
||||
/// <param name="universeSettings">The settings used for new subscriptions generated by this universe</param>
|
||||
/// <param name="selector">Returns the symbols that should be included in the universe</param>
|
||||
public FundamentalUniverseFactory(Symbol symbol, UniverseSettings universeSettings, Func<IEnumerable<Fundamental.Fundamental>, IEnumerable<Symbol>> selector)
|
||||
: base(CreateConfiguration(symbol))
|
||||
{
|
||||
UniverseSettings = universeSettings;
|
||||
_selector = selector;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Performs universe selection using the data specified
|
||||
/// </summary>
|
||||
/// <param name="utcTime">The current utc time</param>
|
||||
/// <param name="data">The symbols to remain in the universe</param>
|
||||
/// <returns>The data that passes the filter</returns>
|
||||
public override IEnumerable<Symbol> SelectSymbols(DateTime utcTime, BaseDataCollection data)
|
||||
{
|
||||
return _selector(new CastingEnumerable<BaseData, Fundamental.Fundamental>(data.Data));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a <see cref="Fundamental.Fundamental"/> subscription configuration for the US-equity market
|
||||
/// </summary>
|
||||
/// <param name="symbol">The symbol used in the returned configuration</param>
|
||||
/// <returns>A fundamental subscription configuration with the specified symbol</returns>
|
||||
public static SubscriptionDataConfig CreateConfiguration(Symbol symbol)
|
||||
{
|
||||
return new SubscriptionDataConfig(typeof(Fundamental.FundamentalUniverse),
|
||||
symbol: symbol,
|
||||
resolution: Resolution.Daily,
|
||||
dataTimeZone: TimeZones.NewYork,
|
||||
exchangeTimeZone: TimeZones.NewYork,
|
||||
fillForward: false,
|
||||
extendedHours: false,
|
||||
isInternalFeed: true,
|
||||
isCustom: false,
|
||||
tickType: null,
|
||||
isFilteredSubscription: false
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,168 @@
|
||||
/*
|
||||
* 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.IO;
|
||||
using QuantConnect.Util;
|
||||
using System.Collections.Generic;
|
||||
using QuantConnect.Securities.Future;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace QuantConnect.Data.UniverseSelection
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a universe of futures data
|
||||
/// </summary>
|
||||
public class FutureUniverse : BaseChainUniverseData
|
||||
{
|
||||
/// <summary>
|
||||
/// Cache for the symbols to avoid creating them multiple times
|
||||
/// </summary>
|
||||
/// <remarks>Key: securityType, market, ticker, expiry</remarks>
|
||||
private static readonly Dictionary<(SecurityType, string, string, DateTime), Symbol> _symbolsCache = new();
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new instance of the <see cref="FutureUniverse"/> class
|
||||
/// </summary>
|
||||
public FutureUniverse()
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new instance of the <see cref="FutureUniverse"/> class
|
||||
/// </summary>
|
||||
public FutureUniverse(DateTime date, Symbol symbol, string csv)
|
||||
: base(date, symbol, csv)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new instance of the <see cref="FutureUniverse"/> class as a copy of the given instance
|
||||
/// </summary>
|
||||
public FutureUniverse(FutureUniverse other)
|
||||
: base(other)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reader converts each line of the data source into BaseData objects. Each data type creates its own factory method, and returns a new instance of the object
|
||||
/// each time it is called.
|
||||
/// </summary>
|
||||
/// <param name="config">Subscription data config setup object</param>
|
||||
/// <param name="stream">Stream reader of the source document</param>
|
||||
/// <param name="date">Date of the requested data</param>
|
||||
/// <param name="isLiveMode">true if we're in live mode, false for backtesting mode</param>
|
||||
/// <returns>Instance of the T:BaseData object generated by this line of the CSV</returns>
|
||||
[StubsIgnore]
|
||||
public override BaseData Reader(SubscriptionDataConfig config, StreamReader stream, DateTime date, bool isLiveMode)
|
||||
{
|
||||
if (stream == null || stream.EndOfStream)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
if (stream.Peek() == '#')
|
||||
{
|
||||
// Skip header
|
||||
stream.ReadLine();
|
||||
return null;
|
||||
}
|
||||
|
||||
var futureContractMonth = stream.GetDateTime(DateFormat.YearMonth);
|
||||
var cacheKey = (config.SecurityType, config.Market, config.Symbol.ID.Symbol, futureContractMonth);
|
||||
if (!TryGetCachedSymbol(cacheKey, out var symbol))
|
||||
{
|
||||
var expiry = FuturesExpiryUtilityFunctions.GetFutureExpirationFromContractMonth(config.Symbol, futureContractMonth);
|
||||
symbol = Symbol.CreateFuture(config.Symbol.ID.Symbol, config.Symbol.ID.Market, expiry);
|
||||
CacheSymbol(cacheKey, symbol);
|
||||
}
|
||||
|
||||
return new FutureUniverse(date, symbol, stream.ReadLine());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a copy of the instance
|
||||
/// </summary>
|
||||
/// <returns>Clone of the instance</returns>
|
||||
public override BaseData Clone()
|
||||
{
|
||||
return new FutureUniverse(this);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the default resolution for this data and security type
|
||||
/// </summary>
|
||||
/// <remarks>This is a method and not a property so that python
|
||||
/// custom data types can override it</remarks>
|
||||
public override Resolution DefaultResolution()
|
||||
{
|
||||
return Resolution.Daily;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Implicit conversion into <see cref="Symbol"/>
|
||||
/// </summary>
|
||||
/// <param name="data">The option universe data to be converted</param>
|
||||
#pragma warning disable CA2225 // Operator overloads have named alternates
|
||||
public static implicit operator Symbol(FutureUniverse data)
|
||||
#pragma warning restore CA2225 // Operator overloads have named alternates
|
||||
{
|
||||
return data.Symbol;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the CSV string representation of this universe entry
|
||||
/// </summary>
|
||||
public static string ToCsv(Symbol symbol, decimal open, decimal high, decimal low, decimal close, decimal volume, decimal? openInterest)
|
||||
{
|
||||
var contractMonth = FuturesExpiryUtilityFunctions.GetFutureContractMonth(symbol);
|
||||
return $"{contractMonth.ToString(DateFormat.YearMonth)},{open},{high},{low},{close},{volume},{openInterest}";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the CSV header string for this universe entry
|
||||
/// </summary>
|
||||
public static string CsvHeader => "expiry,open,high,low,close,volume,open_interest";
|
||||
|
||||
/// <summary>
|
||||
/// Tries to get a symbol from the cache
|
||||
/// </summary>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
protected static bool TryGetCachedSymbol((SecurityType, string, string, DateTime) key, out Symbol symbol)
|
||||
{
|
||||
lock (_symbolsCache)
|
||||
{
|
||||
return _symbolsCache.TryGetValue(key, out symbol);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Caches a symbol
|
||||
/// </summary>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
protected static void CacheSymbol((SecurityType, string, string, DateTime) key, Symbol symbol)
|
||||
{
|
||||
lock (_symbolsCache)
|
||||
{
|
||||
// limit the cache size to help with memory usage
|
||||
if (_symbolsCache.Count >= 100000)
|
||||
{
|
||||
_symbolsCache.Clear();
|
||||
}
|
||||
_symbolsCache.TryAdd(key, symbol);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,94 @@
|
||||
/*
|
||||
* 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.Collections.Generic;
|
||||
using System.Linq;
|
||||
using QuantConnect.Securities;
|
||||
using QuantConnect.Securities.Future;
|
||||
using QuantConnect.Util;
|
||||
|
||||
namespace QuantConnect.Data.UniverseSelection
|
||||
{
|
||||
/// <summary>
|
||||
/// Defines a universe for a single futures chain
|
||||
/// </summary>
|
||||
public class FuturesChainUniverse : Universe
|
||||
{
|
||||
/// <summary>
|
||||
/// True if this universe filter can run async in the data stack
|
||||
/// </summary>
|
||||
public override bool Asynchronous
|
||||
{
|
||||
get
|
||||
{
|
||||
if (UniverseSettings.Asynchronous.HasValue)
|
||||
{
|
||||
return UniverseSettings.Asynchronous.Value;
|
||||
}
|
||||
return Future.ContractFilter.Asynchronous;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="FuturesChainUniverse"/> class
|
||||
/// </summary>
|
||||
/// <param name="future">The canonical future chain security</param>
|
||||
/// <param name="universeSettings">The universe settings to be used for new subscriptions</param>
|
||||
public FuturesChainUniverse(Future future,
|
||||
UniverseSettings universeSettings)
|
||||
: base(future.SubscriptionDataConfig)
|
||||
{
|
||||
Future = future;
|
||||
UniverseSettings = universeSettings;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The canonical future chain security
|
||||
/// </summary>
|
||||
public Future Future { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the settings used for subscriptons added for this universe
|
||||
/// </summary>
|
||||
public override UniverseSettings UniverseSettings
|
||||
{
|
||||
set
|
||||
{
|
||||
if (value != null)
|
||||
{
|
||||
// make sure data mode is raw
|
||||
base.UniverseSettings = new UniverseSettings(value) { DataNormalizationMode = DataNormalizationMode.Raw };
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Performs universe selection using the data specified
|
||||
/// </summary>
|
||||
/// <param name="utcTime">The current utc time</param>
|
||||
/// <param name="data">The symbols to remain in the universe</param>
|
||||
/// <returns>The data that passes the filter</returns>
|
||||
public override IEnumerable<Symbol> SelectSymbols(DateTime utcTime, BaseDataCollection data)
|
||||
{
|
||||
var localEndTime = utcTime.ConvertFromUtc(Future.Exchange.TimeZone);
|
||||
var availableContracts = new CastingEnumerable<BaseData, FutureUniverse>(data.Data);
|
||||
var results = Future.ContractFilter.Filter(new FutureFilterUniverse(availableContracts, localEndTime));
|
||||
|
||||
return results.Select(x => x.Symbol);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* 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.Collections.Generic;
|
||||
using QuantConnect.Securities;
|
||||
|
||||
namespace QuantConnect.Data.UniverseSelection
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides a universe decoration that replaces the implementation of <see cref="GetSubscriptionRequests"/>
|
||||
/// </summary>
|
||||
public class GetSubscriptionRequestsUniverseDecorator : UniverseDecorator
|
||||
{
|
||||
private readonly GetSubscriptionRequestsDelegate _getRequests;
|
||||
|
||||
/// <summary>
|
||||
/// Delegate type for the <see cref="GetSubscriptionRequests"/> method
|
||||
/// </summary>
|
||||
/// <param name="security">The security to get subscription requests for</param>
|
||||
/// <param name="currentTimeUtc">The current utc frontier time</param>
|
||||
/// <param name="maximumEndTimeUtc"></param>
|
||||
/// <returns>The subscription requests for the security to be given to the data feed</returns>
|
||||
public delegate IEnumerable<SubscriptionRequest> GetSubscriptionRequestsDelegate(Security security, DateTime currentTimeUtc, DateTime maximumEndTimeUtc);
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="GetSubscriptionRequestsUniverseDecorator"/> class
|
||||
/// </summary>
|
||||
/// <param name="universe">The universe to be decorated</param>
|
||||
/// <param name="getRequests"></param>
|
||||
public GetSubscriptionRequestsUniverseDecorator(Universe universe, GetSubscriptionRequestsDelegate getRequests)
|
||||
: base(universe)
|
||||
{
|
||||
_getRequests = getRequests;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the subscription requests to be added for the specified security
|
||||
/// </summary>
|
||||
/// <param name="security">The security to get subscriptions for</param>
|
||||
/// <param name="currentTimeUtc">The current time in utc. This is the frontier time of the algorithm</param>
|
||||
/// <param name="maximumEndTimeUtc">The max end time</param>
|
||||
/// <returns>All subscriptions required by this security</returns>
|
||||
public override IEnumerable<SubscriptionRequest> GetSubscriptionRequests(Security security, DateTime currentTimeUtc, DateTime maximumEndTimeUtc)
|
||||
{
|
||||
return _getRequests(security, currentTimeUtc, maximumEndTimeUtc);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* 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 QuantConnect.Data.Fundamental;
|
||||
using QuantConnect.Interfaces;
|
||||
|
||||
namespace QuantConnect.Data.UniverseSelection
|
||||
{
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public interface IFundamentalDataProvider
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes the service
|
||||
/// </summary>
|
||||
/// <param name="dataProvider">The data provider instance to use</param>
|
||||
/// <param name="liveMode">True if running in live mode</param>
|
||||
void Initialize(IDataProvider dataProvider, bool liveMode);
|
||||
|
||||
/// <summary>
|
||||
/// Will fetch the requested fundamental information for the requested time and symbol
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The expected data type</typeparam>
|
||||
/// <param name="time">The time to request this data for</param>
|
||||
/// <param name="securityIdentifier">The security identifier</param>
|
||||
/// <param name="name">The name of the fundamental property</param>
|
||||
/// <returns>The fundamental information</returns>
|
||||
T Get<T>(DateTime time, SecurityIdentifier securityIdentifier, FundamentalProperty name);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* 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.Collections.Generic;
|
||||
using QuantConnect.Securities;
|
||||
|
||||
namespace QuantConnect.Data.UniverseSelection
|
||||
{
|
||||
/// <summary>
|
||||
/// A universe implementing this interface will NOT use it's SubscriptionDataConfig to generate data
|
||||
/// that is used to 'pulse' the universe selection function -- instead, the times output by
|
||||
/// GetTriggerTimes are used to 'pulse' the universe selection function WITHOUT data.
|
||||
/// </summary>
|
||||
public interface ITimeTriggeredUniverse
|
||||
{
|
||||
/// <summary>
|
||||
/// Returns an enumerator that defines when this user defined universe will be invoked
|
||||
/// </summary>
|
||||
/// <returns>An enumerator of DateTime that defines when this universe will be invoked</returns>
|
||||
IEnumerable<DateTime> GetTriggerTimes(DateTime startTimeUtc, DateTime endTimeUtc, MarketHoursDatabase marketHoursDatabase);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,162 @@
|
||||
/*
|
||||
* 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 QuantConnect.Interfaces;
|
||||
using QuantConnect.Securities;
|
||||
using System.Collections.Generic;
|
||||
using QuantConnect.Securities.Option;
|
||||
using QuantConnect.Util;
|
||||
|
||||
namespace QuantConnect.Data.UniverseSelection
|
||||
{
|
||||
/// <summary>
|
||||
/// Defines a universe for a single option chain
|
||||
/// </summary>
|
||||
public class OptionChainUniverse : Universe
|
||||
{
|
||||
private readonly OptionFilterUniverse _optionFilterUniverse;
|
||||
// as an array to make it easy to prepend to selected symbols
|
||||
private readonly Symbol[] _underlyingSymbol;
|
||||
|
||||
/// <summary>
|
||||
/// True if this universe filter can run async in the data stack
|
||||
/// </summary>
|
||||
public override bool Asynchronous
|
||||
{
|
||||
get
|
||||
{
|
||||
if (UniverseSettings.Asynchronous.HasValue)
|
||||
{
|
||||
return UniverseSettings.Asynchronous.Value;
|
||||
}
|
||||
return Option.ContractFilter.Asynchronous;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="OptionChainUniverse"/> class
|
||||
/// </summary>
|
||||
/// <param name="option">The canonical option chain security</param>
|
||||
/// <param name="universeSettings">The universe settings to be used for new subscriptions</param>
|
||||
public OptionChainUniverse(Option option,
|
||||
UniverseSettings universeSettings)
|
||||
: base(option.SubscriptionDataConfig)
|
||||
{
|
||||
Option = option;
|
||||
UniverseSettings = universeSettings;
|
||||
_underlyingSymbol = new[] { Option.Symbol.Underlying };
|
||||
_optionFilterUniverse = new OptionFilterUniverse(Option);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The canonical option chain security
|
||||
/// </summary>
|
||||
public Option Option { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the settings used for subscriptons added for this universe
|
||||
/// </summary>
|
||||
public override UniverseSettings UniverseSettings
|
||||
{
|
||||
set
|
||||
{
|
||||
if (value != null)
|
||||
{
|
||||
// make sure data mode is raw
|
||||
base.UniverseSettings = new UniverseSettings(value) { DataNormalizationMode = DataNormalizationMode.Raw };
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Performs universe selection using the data specified
|
||||
/// </summary>
|
||||
/// <param name="utcTime">The current utc time</param>
|
||||
/// <param name="data">The symbols to remain in the universe</param>
|
||||
/// <returns>The data that passes the filter</returns>
|
||||
public override IEnumerable<Symbol> SelectSymbols(DateTime utcTime, BaseDataCollection data)
|
||||
{
|
||||
var localEndTime = utcTime.ConvertFromUtc(Option.Exchange.TimeZone);
|
||||
// we will only update unique strikes when there is an exchange date change
|
||||
_optionFilterUniverse.Refresh(new CastingEnumerable<BaseData, OptionUniverse>(data.Data), data.Underlying, localEndTime);
|
||||
|
||||
var results = Option.ContractFilter.Filter(_optionFilterUniverse);
|
||||
|
||||
// always prepend the underlying symbol
|
||||
return _underlyingSymbol.Concat(results.Select(x => x.Symbol));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds the specified security to this universe
|
||||
/// </summary>
|
||||
/// <param name="utcTime">The current utc date time</param>
|
||||
/// <param name="security">The security to be added</param>
|
||||
/// <param name="isInternal">True if internal member</param>
|
||||
/// <returns>True if the security was successfully added,
|
||||
/// false if the security was already in the universe</returns>
|
||||
internal override bool AddMember(DateTime utcTime, Security security, bool isInternal)
|
||||
{
|
||||
// never add members to disposed universes
|
||||
if (DisposeRequested)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (Securities.ContainsKey(security.Symbol))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// method take into account the case, when the option has experienced an adjustment
|
||||
// we update member reference in this case
|
||||
if (Securities.Any(x => x.Value.Security == security))
|
||||
{
|
||||
Member member;
|
||||
Securities.TryRemove(security.Symbol, out member);
|
||||
}
|
||||
|
||||
return Securities.TryAdd(security.Symbol, new Member(utcTime, security, isInternal));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the subscription requests to be added for the specified security
|
||||
/// </summary>
|
||||
/// <param name="security">The security to get subscriptions for</param>
|
||||
/// <param name="currentTimeUtc">The current time in utc. This is the frontier time of the algorithm</param>
|
||||
/// <param name="maximumEndTimeUtc">The max end time</param>
|
||||
/// <param name="subscriptionService">Instance which implements <see cref="ISubscriptionDataConfigService"/> interface</param>
|
||||
/// <returns>All subscriptions required by this security</returns>
|
||||
public override IEnumerable<SubscriptionRequest> GetSubscriptionRequests(Security security, DateTime currentTimeUtc, DateTime maximumEndTimeUtc,
|
||||
ISubscriptionDataConfigService subscriptionService)
|
||||
{
|
||||
if (Option.Symbol.Underlying == security.Symbol)
|
||||
{
|
||||
Option.Underlying = security;
|
||||
security.SetDataNormalizationMode(DataNormalizationMode.Raw);
|
||||
}
|
||||
else
|
||||
{
|
||||
// set the underlying security and pricing model from the canonical security
|
||||
var option = (Option)security;
|
||||
option.PriceModel = Option.PriceModel;
|
||||
}
|
||||
|
||||
return base.GetSubscriptionRequests(security, currentTimeUtc, maximumEndTimeUtc, subscriptionService);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,313 @@
|
||||
/*
|
||||
* 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.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Runtime.CompilerServices;
|
||||
using QuantConnect.Data.Market;
|
||||
using QuantConnect.Python;
|
||||
using QuantConnect.Util;
|
||||
|
||||
namespace QuantConnect.Data.UniverseSelection
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a universe of options data
|
||||
/// </summary>
|
||||
public class OptionUniverse : BaseChainUniverseData
|
||||
{
|
||||
/// <summary>
|
||||
/// Cache for the symbols to avoid creating them multiple times
|
||||
/// </summary>
|
||||
/// <remarks>Key: securityType, market, ticker, expiry, strike, right</remarks>
|
||||
private static readonly Dictionary<(SecurityType, string, string, DateTime, decimal, OptionRight), Symbol> _symbolsCache = new();
|
||||
|
||||
private const int StartingGreeksCsvIndex = 7;
|
||||
|
||||
/// <summary>
|
||||
/// Open interest value of the option
|
||||
/// </summary>
|
||||
public override decimal OpenInterest
|
||||
{
|
||||
get
|
||||
{
|
||||
ThrowIfNotAnOption(nameof(OpenInterest));
|
||||
return base.OpenInterest;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Implied volatility value of the option
|
||||
/// </summary>
|
||||
public decimal ImpliedVolatility
|
||||
{
|
||||
get
|
||||
{
|
||||
ThrowIfNotAnOption(nameof(ImpliedVolatility));
|
||||
return CsvLine.GetDecimalFromCsv(6);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Greeks values of the option
|
||||
/// </summary>
|
||||
public Greeks Greeks
|
||||
{
|
||||
get
|
||||
{
|
||||
ThrowIfNotAnOption(nameof(Greeks));
|
||||
return new PreCalculatedGreeks(CsvLine);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new instance of the <see cref="OptionUniverse"/> class
|
||||
/// </summary>
|
||||
public OptionUniverse()
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new instance of the <see cref="OptionUniverse"/> class
|
||||
/// </summary>
|
||||
public OptionUniverse(DateTime date, Symbol symbol, string csv)
|
||||
: base(date, symbol, csv)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new instance of the <see cref="OptionUniverse"/> class as a copy of the given instance
|
||||
/// </summary>
|
||||
public OptionUniverse(OptionUniverse other)
|
||||
: base(other)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reader converts each line of the data source into BaseData objects. Each data type creates its own factory method, and returns a new instance of the object
|
||||
/// each time it is called.
|
||||
/// </summary>
|
||||
/// <param name="config">Subscription data config setup object</param>
|
||||
/// <param name="stream">Stream reader of the source document</param>
|
||||
/// <param name="date">Date of the requested data</param>
|
||||
/// <param name="isLiveMode">true if we're in live mode, false for backtesting mode</param>
|
||||
/// <returns>Instance of the T:BaseData object generated by this line of the CSV</returns>
|
||||
[StubsIgnore]
|
||||
public override BaseData Reader(SubscriptionDataConfig config, StreamReader stream, DateTime date, bool isLiveMode)
|
||||
{
|
||||
if (stream == null || stream.EndOfStream)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var firstChar = (char)stream.Peek();
|
||||
if (firstChar == '#')
|
||||
{
|
||||
// Skip header
|
||||
stream.ReadLine();
|
||||
return null;
|
||||
}
|
||||
|
||||
Symbol symbol;
|
||||
if (!char.IsDigit(firstChar))
|
||||
{
|
||||
// This is the underlying line
|
||||
symbol = config.Symbol.Underlying;
|
||||
// Skip the first 3 cells, expiry, strike and right, which will be empty for the underlying
|
||||
stream.GetChar();
|
||||
stream.GetChar();
|
||||
stream.GetChar();
|
||||
}
|
||||
else
|
||||
{
|
||||
var expiry = stream.GetDateTime("yyyyMMdd");
|
||||
var strike = stream.GetDecimal();
|
||||
var right = char.ToUpperInvariant(stream.GetChar()) == 'C' ? OptionRight.Call : OptionRight.Put;
|
||||
var targetOption = config.Symbol.SecurityType != SecurityType.IndexOption ? null : config.Symbol.ID.Symbol;
|
||||
|
||||
var cacheKey = (config.SecurityType, config.Market, targetOption ?? config.Symbol.Underlying.Value, expiry, strike, right);
|
||||
if (!TryGetCachedSymbol(cacheKey, out symbol))
|
||||
{
|
||||
symbol = Symbol.CreateOption(config.Symbol.Underlying, targetOption, config.Symbol.ID.Market,
|
||||
config.Symbol.SecurityType.DefaultOptionStyle(), right, strike, expiry);
|
||||
CacheSymbol(cacheKey, symbol);
|
||||
}
|
||||
}
|
||||
|
||||
return new OptionUniverse(date, symbol, stream.ReadLine());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a new data point to this collection.
|
||||
/// If the data point is for the underlying, it will be stored in the <see cref="BaseDataCollection.Underlying"/> property.
|
||||
/// </summary>
|
||||
/// <param name="newDataPoint">The new data point to add</param>
|
||||
public override void Add(BaseData newDataPoint)
|
||||
{
|
||||
if (newDataPoint is BaseChainUniverseData optionUniverseDataPoint)
|
||||
{
|
||||
if (optionUniverseDataPoint.Symbol.HasUnderlying)
|
||||
{
|
||||
optionUniverseDataPoint.Underlying = Underlying;
|
||||
base.Add(optionUniverseDataPoint);
|
||||
}
|
||||
else
|
||||
{
|
||||
Underlying = optionUniverseDataPoint;
|
||||
foreach (BaseChainUniverseData data in Data)
|
||||
{
|
||||
data.Underlying = optionUniverseDataPoint;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a copy of the instance
|
||||
/// </summary>
|
||||
/// <returns>Clone of the instance</returns>
|
||||
public override BaseData Clone()
|
||||
{
|
||||
return new OptionUniverse(this);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private static string GetOptionSymbolCsv(Symbol symbol)
|
||||
{
|
||||
if (!symbol.SecurityType.IsOption())
|
||||
{
|
||||
return ",,";
|
||||
}
|
||||
|
||||
return $"{symbol.ID.Date:yyyyMMdd},{symbol.ID.StrikePrice},{(symbol.ID.OptionRight == OptionRight.Call ? 'C' : 'P')}";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the CSV string representation of this universe entry
|
||||
/// </summary>
|
||||
public static string ToCsv(Symbol symbol, decimal open, decimal high, decimal low, decimal close, decimal volume, decimal? openInterest,
|
||||
decimal? impliedVolatility, Greeks greeks)
|
||||
{
|
||||
if (symbol.SecurityType == SecurityType.Future || symbol.SecurityType == SecurityType.FutureOption)
|
||||
{
|
||||
return $"{GetOptionSymbolCsv(symbol)},{open},{high},{low},{close},{volume},{openInterest}";
|
||||
}
|
||||
|
||||
return $"{GetOptionSymbolCsv(symbol)},{open},{high},{low},{close},{volume},"
|
||||
+ $"{openInterest},{impliedVolatility},{greeks?.Delta},{greeks?.Gamma},{greeks?.Vega},{greeks?.ThetaPerDay},{greeks?.Rho}";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Implicit conversion into <see cref="Symbol"/>
|
||||
/// </summary>
|
||||
/// <param name="data">The option universe data to be converted</param>
|
||||
#pragma warning disable CA2225 // Operator overloads have named alternates
|
||||
public static implicit operator Symbol(OptionUniverse data)
|
||||
#pragma warning restore CA2225 // Operator overloads have named alternates
|
||||
{
|
||||
return data.Symbol;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the CSV header string for this universe entry
|
||||
/// </summary>
|
||||
public static string CsvHeader(SecurityType securityType)
|
||||
{
|
||||
// FOPs don't have greeks
|
||||
if (securityType == SecurityType.FutureOption || securityType == SecurityType.Future)
|
||||
{
|
||||
return "expiry,strike,right,open,high,low,close,volume,open_interest";
|
||||
}
|
||||
|
||||
return "expiry,strike,right,open,high,low,close,volume,open_interest,implied_volatility,delta,gamma,vega,theta,rho";
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private void ThrowIfNotAnOption(string propertyName)
|
||||
{
|
||||
if (!Symbol.SecurityType.IsOption())
|
||||
{
|
||||
throw new InvalidOperationException($"{propertyName} is only available for options.");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Pre-calculated greeks lazily parsed from csv line.
|
||||
/// It parses the greeks values from the csv line only when they are requested to avoid holding decimals in memory.
|
||||
/// </summary>
|
||||
private class PreCalculatedGreeks : Greeks
|
||||
{
|
||||
private readonly string _csvLine;
|
||||
|
||||
public override decimal Delta => _csvLine.GetDecimalFromCsv(StartingGreeksCsvIndex);
|
||||
|
||||
public override decimal Gamma => _csvLine.GetDecimalFromCsv(StartingGreeksCsvIndex + 1);
|
||||
|
||||
public override decimal Vega => _csvLine.GetDecimalFromCsv(StartingGreeksCsvIndex + 2);
|
||||
|
||||
public override decimal Theta => GetSafeTheta(_csvLine.GetDecimalFromCsv(StartingGreeksCsvIndex + 3));
|
||||
|
||||
public override decimal Rho => _csvLine.GetDecimalFromCsv(StartingGreeksCsvIndex + 4);
|
||||
|
||||
[PandasIgnore]
|
||||
public override decimal Lambda => decimal.Zero;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new default instance of the <see cref="PreCalculatedGreeks"/> class
|
||||
/// </summary>
|
||||
public PreCalculatedGreeks(string csvLine)
|
||||
{
|
||||
_csvLine = csvLine;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a string representation of the greeks values
|
||||
/// </summary>
|
||||
public override string ToString()
|
||||
{
|
||||
return $"D: {Delta}, G: {Gamma}, V: {Vega}, T: {Theta}, R: {Rho}";
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tries to get a symbol from the cache
|
||||
/// </summary>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
protected static bool TryGetCachedSymbol((SecurityType, string, string, DateTime, decimal, OptionRight) key, out Symbol symbol)
|
||||
{
|
||||
lock (_symbolsCache)
|
||||
{
|
||||
return _symbolsCache.TryGetValue(key, out symbol);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Caches a symbol
|
||||
/// </summary>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
protected static void CacheSymbol((SecurityType, string, string, DateTime, decimal, OptionRight) key, Symbol symbol)
|
||||
{
|
||||
lock (_symbolsCache)
|
||||
{
|
||||
// limit the cache size to help with memory usage
|
||||
if (_symbolsCache.Count >= 500000)
|
||||
{
|
||||
_symbolsCache.Clear();
|
||||
}
|
||||
_symbolsCache.TryAdd(key, symbol);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* 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 QuantConnect.Scheduling;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace QuantConnect.Data.UniverseSelection
|
||||
{
|
||||
/// <summary>
|
||||
/// Entity in charge of managing a schedule
|
||||
/// </summary>
|
||||
public class Schedule
|
||||
{
|
||||
private IDateRule _dateRule;
|
||||
|
||||
/// <summary>
|
||||
/// True if this schedule is set
|
||||
/// </summary>
|
||||
public bool Initialized => _dateRule != null;
|
||||
|
||||
/// <summary>
|
||||
/// Set a <see cref="IDateRule"/> for this schedule
|
||||
/// </summary>
|
||||
public void On(IDateRule dateRule)
|
||||
{
|
||||
_dateRule = dateRule;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the current schedule for a given start time
|
||||
/// </summary>
|
||||
public IEnumerable<DateTime> Get(DateTime startTime, DateTime endTime)
|
||||
{
|
||||
return _dateRule?.GetDates(startTime, endTime) ?? Enumerable.Empty<DateTime>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new instance holding the same schedule if any
|
||||
/// </summary>
|
||||
public Schedule Clone()
|
||||
{
|
||||
return new Schedule { _dateRule = _dateRule };
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,177 @@
|
||||
/*
|
||||
* 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 NodaTime;
|
||||
using Python.Runtime;
|
||||
using QuantConnect.Data.Market;
|
||||
using QuantConnect.Scheduling;
|
||||
using QuantConnect.Securities;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace QuantConnect.Data.UniverseSelection
|
||||
{
|
||||
/// <summary>
|
||||
/// Defines a user that is fired based on a specified <see cref="IDateRule"/> and <see cref="ITimeRule"/>
|
||||
/// </summary>
|
||||
public class ScheduledUniverse : Universe, ITimeTriggeredUniverse
|
||||
{
|
||||
private readonly IDateRule _dateRule;
|
||||
private readonly ITimeRule _timeRule;
|
||||
private readonly Func<DateTime, IEnumerable<Symbol>> _selector;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ScheduledUniverse"/> class
|
||||
/// </summary>
|
||||
/// <param name="timeZone">The time zone the date/time rules are in</param>
|
||||
/// <param name="dateRule">Date rule defines what days the universe selection function will be invoked</param>
|
||||
/// <param name="timeRule">Time rule defines what times on each day selected by date rule the universe selection function will be invoked</param>
|
||||
/// <param name="selector">Selector function accepting the date time firing time and returning the universe selected symbols</param>
|
||||
/// <param name="settings">Universe settings for subscriptions added via this universe, null will default to algorithm's universe settings</param>
|
||||
public ScheduledUniverse(DateTimeZone timeZone, IDateRule dateRule, ITimeRule timeRule, Func<DateTime, IEnumerable<Symbol>> selector, UniverseSettings settings = null)
|
||||
: base(CreateConfiguration(timeZone, dateRule, timeRule))
|
||||
{
|
||||
_dateRule = dateRule;
|
||||
_timeRule = timeRule;
|
||||
_selector = selector;
|
||||
UniverseSettings = settings;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ScheduledUniverse"/> class
|
||||
/// </summary>
|
||||
/// <param name="dateRule">Date rule defines what days the universe selection function will be invoked</param>
|
||||
/// <param name="timeRule">Time rule defines what times on each day selected by date rule the universe selection function will be invoked</param>
|
||||
/// <param name="selector">Selector function accepting the date time firing time and returning the universe selected symbols</param>
|
||||
/// <param name="settings">Universe settings for subscriptions added via this universe, null will default to algorithm's universe settings</param>
|
||||
public ScheduledUniverse(IDateRule dateRule, ITimeRule timeRule, Func<DateTime, IEnumerable<Symbol>> selector, UniverseSettings settings = null)
|
||||
: this(TimeZones.Utc, dateRule, timeRule, selector, settings)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ScheduledUniverse"/> class
|
||||
/// </summary>
|
||||
/// <param name="timeZone">The time zone the date/time rules are in</param>
|
||||
/// <param name="dateRule">Date rule defines what days the universe selection function will be invoked</param>
|
||||
/// <param name="timeRule">Time rule defines what times on each day selected by date rule the universe selection function will be invoked</param>
|
||||
/// <param name="selector">Selector function accepting the date time firing time and returning the universe selected symbols</param>
|
||||
/// <param name="settings">Universe settings for subscriptions added via this universe, null will default to algorithm's universe settings</param>
|
||||
public ScheduledUniverse(DateTimeZone timeZone, IDateRule dateRule, ITimeRule timeRule, PyObject selector, UniverseSettings settings = null)
|
||||
: base(CreateConfiguration(timeZone, dateRule, timeRule))
|
||||
{
|
||||
selector.TrySafeAs<Func<DateTime, object>>(out var func);
|
||||
_dateRule = dateRule;
|
||||
_timeRule = timeRule;
|
||||
_selector = func.ConvertSelectionSymbolDelegate();
|
||||
UniverseSettings = settings;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ScheduledUniverse"/> class
|
||||
/// </summary>
|
||||
/// <param name="dateRule">Date rule defines what days the universe selection function will be invoked</param>
|
||||
/// <param name="timeRule">Time rule defines what times on each day selected by date rule the universe selection function will be invoked</param>
|
||||
/// <param name="selector">Selector function accepting the date time firing time and returning the universe selected symbols</param>
|
||||
/// <param name="settings">Universe settings for subscriptions added via this universe, null will default to algorithm's universe settings</param>
|
||||
public ScheduledUniverse(IDateRule dateRule, ITimeRule timeRule, PyObject selector, UniverseSettings settings = null)
|
||||
: this(TimeZones.Utc, dateRule, timeRule, selector, settings)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Performs universe selection using the data specified
|
||||
/// </summary>
|
||||
/// <param name="utcTime">The current utc time</param>
|
||||
/// <param name="data">The symbols to remain in the universe</param>
|
||||
/// <returns>The data that passes the filter</returns>
|
||||
public override IEnumerable<Symbol> SelectSymbols(DateTime utcTime, BaseDataCollection data)
|
||||
{
|
||||
return _selector(DateTime.SpecifyKind(utcTime, DateTimeKind.Unspecified));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get an enumerator of UTC DateTimes that defines when this universe will be invoked,
|
||||
/// only including times within [startTimeUtc, endTimeUtc], both bounds inclusive.
|
||||
/// </summary>
|
||||
/// <param name="startTimeUtc">The start time of the range in UTC</param>
|
||||
/// <param name="endTimeUtc">The end time of the range in UTC</param>
|
||||
/// <returns>An enumerator of UTC DateTimes that defines when this universe will be invoked</returns>
|
||||
public IEnumerable<DateTime> GetTriggerTimes(DateTime startTimeUtc, DateTime endTimeUtc, MarketHoursDatabase marketHoursDatabase)
|
||||
{
|
||||
var startTimeLocal = startTimeUtc.ConvertFromUtc(Configuration.ExchangeTimeZone);
|
||||
var endTimeLocal = endTimeUtc.ConvertFromUtc(Configuration.ExchangeTimeZone);
|
||||
|
||||
// define date/time rule enumerable
|
||||
var dates = _dateRule.GetDates(startTimeLocal, endTimeLocal);
|
||||
var times = _timeRule.CreateUtcEventTimes(dates).GetEnumerator();
|
||||
|
||||
// Make sure and filter out any times before our start time
|
||||
// GH #5440
|
||||
do
|
||||
{
|
||||
if (!times.MoveNext())
|
||||
{
|
||||
times.Dispose();
|
||||
yield break;
|
||||
}
|
||||
}
|
||||
while (times.Current < startTimeUtc);
|
||||
|
||||
// Start yielding times
|
||||
do
|
||||
{
|
||||
if (times.Current > endTimeUtc)
|
||||
{
|
||||
times.Dispose();
|
||||
yield break;
|
||||
}
|
||||
yield return times.Current;
|
||||
}
|
||||
while (times.MoveNext());
|
||||
times.Dispose();
|
||||
}
|
||||
|
||||
private static SubscriptionDataConfig CreateConfiguration(DateTimeZone timeZone, IDateRule dateRule, ITimeRule timeRule)
|
||||
{
|
||||
// remove forbidden characters
|
||||
var ticker = $"{dateRule.Name}_{timeRule.Name}";
|
||||
foreach (var c in SecurityIdentifier.InvalidSymbolCharacters)
|
||||
{
|
||||
ticker = ticker.Replace(c.ToStringInvariant(), "_");
|
||||
}
|
||||
|
||||
var symbol = Symbol.Create(ticker, SecurityType.Base, QuantConnect.Market.USA);
|
||||
var config = new SubscriptionDataConfig(typeof(Tick),
|
||||
symbol: symbol,
|
||||
resolution: Resolution.Daily,
|
||||
dataTimeZone: timeZone,
|
||||
exchangeTimeZone: timeZone,
|
||||
fillForward: false,
|
||||
extendedHours: false,
|
||||
isInternalFeed: true,
|
||||
isCustom: false,
|
||||
tickType: null,
|
||||
isFilteredSubscription: false
|
||||
);
|
||||
|
||||
// force always open hours so we don't inadvertently mess with the scheduled firing times
|
||||
MarketHoursDatabase.FromDataFolder()
|
||||
.SetEntryAlwaysOpen(config.Market, config.Symbol.Value, config.SecurityType, config.ExchangeTimeZone);
|
||||
|
||||
return config;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,286 @@
|
||||
/*
|
||||
* 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 QuantConnect.Securities;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace QuantConnect.Data.UniverseSelection
|
||||
{
|
||||
/// <summary>
|
||||
/// Defines the additions and subtractions to the algorithm's security subscriptions
|
||||
/// </summary>
|
||||
public class SecurityChanges
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets an instance that represents no changes have been made
|
||||
/// </summary>
|
||||
public static readonly SecurityChanges None = new (Enumerable.Empty<Security>(), Enumerable.Empty<Security>(),
|
||||
Enumerable.Empty<Security>(), Enumerable.Empty<Security>());
|
||||
|
||||
private readonly IReadOnlySet<Security> _addedSecurities;
|
||||
private readonly IReadOnlySet<Security> _removedSecurities;
|
||||
private readonly IReadOnlySet<Security> _internalAddedSecurities;
|
||||
private readonly IReadOnlySet<Security> _internalRemovedSecurities;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the total count of added and removed securities
|
||||
/// </summary>
|
||||
public int Count => _addedSecurities.Count + _removedSecurities.Count
|
||||
+ _internalAddedSecurities.Count + _internalRemovedSecurities.Count;
|
||||
|
||||
/// <summary>
|
||||
/// True will filter out custom securities from the
|
||||
/// <see cref="AddedSecurities"/> and <see cref="RemovedSecurities"/> properties
|
||||
/// </summary>
|
||||
/// <remarks>This allows us to filter but also to disable
|
||||
/// the filtering if desired</remarks>
|
||||
public bool FilterCustomSecurities { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// True will filter out internal securities from the
|
||||
/// <see cref="AddedSecurities"/> and <see cref="RemovedSecurities"/> properties
|
||||
/// </summary>
|
||||
/// <remarks>This allows us to filter but also to disable
|
||||
/// the filtering if desired</remarks>
|
||||
public bool FilterInternalSecurities { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the symbols that were added by universe selection
|
||||
/// </summary>
|
||||
/// <remarks>Will use <see cref="FilterCustomSecurities"/> value
|
||||
/// to determine if custom securities should be filtered</remarks>
|
||||
/// <remarks>Will use <see cref="FilterInternalSecurities"/> value
|
||||
/// to determine if internal securities should be filtered</remarks>
|
||||
public IReadOnlyList<Security> AddedSecurities => GetFilteredList(_addedSecurities,
|
||||
!FilterInternalSecurities ? _internalAddedSecurities : null);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the symbols that were removed by universe selection. This list may
|
||||
/// include symbols that were removed, but are still receiving data due to
|
||||
/// existing holdings or open orders
|
||||
/// </summary>
|
||||
/// <remarks>Will use <see cref="FilterCustomSecurities"/> value
|
||||
/// to determine if custom securities should be filtered</remarks>
|
||||
/// <remarks>Will use <see cref="FilterInternalSecurities"/> value
|
||||
/// to determine if internal securities should be filtered</remarks>
|
||||
public IReadOnlyList<Security> RemovedSecurities => GetFilteredList(_removedSecurities,
|
||||
!FilterInternalSecurities ? _internalRemovedSecurities : null);
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="SecurityChanges"/> class
|
||||
/// </summary>
|
||||
/// <param name="additions">Added symbols list</param>
|
||||
/// <param name="removals">Removed symbols list</param>
|
||||
/// <param name="internalAdditions">Internal added symbols list</param>
|
||||
/// <param name="internalRemovals">Internal removed symbols list</param>
|
||||
private SecurityChanges(IEnumerable<Security> additions, IEnumerable<Security> removals,
|
||||
IEnumerable<Security> internalAdditions, IEnumerable<Security> internalRemovals)
|
||||
{
|
||||
_addedSecurities = additions.ToHashSet();
|
||||
_removedSecurities = removals.ToHashSet();
|
||||
_internalAddedSecurities = internalAdditions.ToHashSet();
|
||||
_internalRemovedSecurities = internalRemovals.ToHashSet();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="SecurityChanges"/> class
|
||||
/// as a shallow clone of a given instance, sharing the same collections
|
||||
/// </summary>
|
||||
/// <param name="changes">The instance to clone</param>
|
||||
public SecurityChanges(SecurityChanges changes)
|
||||
{
|
||||
_addedSecurities = changes._addedSecurities;
|
||||
_removedSecurities = changes._removedSecurities;
|
||||
_internalAddedSecurities = changes._internalAddedSecurities;
|
||||
_internalRemovedSecurities = changes._internalRemovedSecurities;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Combines the results of two <see cref="SecurityChanges"/>
|
||||
/// </summary>
|
||||
/// <param name="left">The left side of the operand</param>
|
||||
/// <param name="right">The right side of the operand</param>
|
||||
/// <returns>Adds the additions together and removes any removals found in the additions, that is, additions take precedence</returns>
|
||||
public static SecurityChanges operator +(SecurityChanges left, SecurityChanges right)
|
||||
{
|
||||
// common case is adding something to nothing, shortcut these to prevent linqness
|
||||
if (left == None || left.Count == 0) return right;
|
||||
if (right == None || right.Count == 0) return left;
|
||||
|
||||
var additions = Merge(left._addedSecurities, right._addedSecurities);
|
||||
var internalAdditions = Merge(left._internalAddedSecurities, right._internalAddedSecurities);
|
||||
|
||||
var removals = Merge(left._removedSecurities, right._removedSecurities,
|
||||
security => !additions.Contains(security) && !internalAdditions.Contains(security));
|
||||
var internalRemovals = Merge(left._internalRemovedSecurities, right._internalRemovedSecurities,
|
||||
security => !additions.Contains(security) && !internalAdditions.Contains(security));
|
||||
|
||||
return new SecurityChanges(additions, removals, internalAdditions, internalRemovals);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="SecurityChanges"/> class all none internal
|
||||
/// </summary>
|
||||
/// <param name="additions">Added symbols list</param>
|
||||
/// <param name="removals">Removed symbols list</param>
|
||||
/// <param name="internalAdditions">Internal added symbols list</param>
|
||||
/// <param name="internalRemovals">Internal removed symbols list</param>
|
||||
/// <remarks>Useful for testing</remarks>
|
||||
public static SecurityChanges Create(IReadOnlyCollection<Security> additions, IReadOnlyCollection<Security> removals,
|
||||
IReadOnlyCollection<Security> internalAdditions, IReadOnlyCollection<Security> internalRemovals)
|
||||
{
|
||||
// return None if there's no changes, otherwise return what we've modified
|
||||
return additions?.Count + removals?.Count + internalAdditions?.Count + internalRemovals?.Count > 0
|
||||
? new SecurityChanges(additions, removals, internalAdditions, internalRemovals)
|
||||
: None;
|
||||
}
|
||||
|
||||
#region Overrides of Object
|
||||
|
||||
/// <summary>
|
||||
/// Returns a string that represents the current object.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// A string that represents the current object.
|
||||
/// </returns>
|
||||
/// <filterpriority>2</filterpriority>
|
||||
public override string ToString()
|
||||
{
|
||||
if (Count == 0)
|
||||
{
|
||||
return "SecurityChanges: None";
|
||||
}
|
||||
|
||||
var added = string.Empty;
|
||||
if (AddedSecurities.Count != 0)
|
||||
{
|
||||
added = $" Added: {string.Join(",", AddedSecurities.Select(x => x.Symbol.ID))}";
|
||||
}
|
||||
var removed = string.Empty;
|
||||
if (RemovedSecurities.Count != 0)
|
||||
{
|
||||
removed = $" Removed: {string.Join(",", RemovedSecurities.Select(x => x.Symbol.ID))}";
|
||||
}
|
||||
|
||||
return $"SecurityChanges: {added}{removed}";
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Helper method to filter added and removed securities based on current settings
|
||||
/// </summary>
|
||||
private IReadOnlyList<Security> GetFilteredList(IReadOnlySet<Security> source, IReadOnlySet<Security> secondSource = null)
|
||||
{
|
||||
IEnumerable<Security> enumerable = source;
|
||||
if (secondSource != null && secondSource.Count > 0)
|
||||
{
|
||||
enumerable = enumerable.Union(secondSource);
|
||||
}
|
||||
return enumerable.Where(kvp => !FilterCustomSecurities || kvp.Type != SecurityType.Base)
|
||||
.Select(kvp => kvp)
|
||||
.OrderBy(security => security.Symbol.Value)
|
||||
.ToList();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Helper method that will merge two security sets, taken into account an optional filter
|
||||
/// </summary>
|
||||
/// <returns>Will return merged set</returns>
|
||||
private static HashSet<Security> Merge(IReadOnlyCollection<Security> left, IReadOnlyCollection<Security> right, Func<Security, bool> filter = null)
|
||||
{
|
||||
// if right is emtpy we just use left
|
||||
IEnumerable<Security> result = left;
|
||||
if (right.Count != 0)
|
||||
{
|
||||
if (left.Count == 0)
|
||||
{
|
||||
// left is emtpy so let's just use right
|
||||
result = right;
|
||||
}
|
||||
else
|
||||
{
|
||||
// merge, both are not empty
|
||||
result = result.Concat(right);
|
||||
}
|
||||
}
|
||||
|
||||
if (filter != null)
|
||||
{
|
||||
result = result.Where(filter.Invoke);
|
||||
}
|
||||
|
||||
return new HashSet<Security>(result);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Helper method to create security changes
|
||||
/// </summary>
|
||||
public class SecurityChangesConstructor
|
||||
{
|
||||
private readonly List<Security> _internalAdditions = new();
|
||||
private readonly List<Security> _internalRemovals = new();
|
||||
private readonly List<Security> _additions = new();
|
||||
private readonly List<Security> _removals = new();
|
||||
|
||||
/// <summary>
|
||||
/// Inserts a security addition change
|
||||
/// </summary>
|
||||
public void Add(Security security, bool isInternal)
|
||||
{
|
||||
if (isInternal)
|
||||
{
|
||||
_internalAdditions.Add(security);
|
||||
}
|
||||
else
|
||||
{
|
||||
_additions.Add(security);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Inserts a security removal change
|
||||
/// </summary>
|
||||
public void Remove(Security security, bool isInternal)
|
||||
{
|
||||
if (isInternal)
|
||||
{
|
||||
_internalRemovals.Add(security);
|
||||
}
|
||||
else
|
||||
{
|
||||
_removals.Add(security);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the current security changes clearing state
|
||||
/// </summary>
|
||||
public SecurityChanges Flush()
|
||||
{
|
||||
var result = SecurityChanges.Create(_additions, _removals, _internalAdditions, _internalRemovals);
|
||||
|
||||
_internalAdditions.Clear();
|
||||
_removals.Clear();
|
||||
_internalRemovals.Clear();
|
||||
_additions.Clear();
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* 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.Collections.Generic;
|
||||
|
||||
namespace QuantConnect.Data.UniverseSelection
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides a univese decoration that replaces the implementation of <see cref="SelectSymbols"/>
|
||||
/// </summary>
|
||||
public class SelectSymbolsUniverseDecorator : UniverseDecorator
|
||||
{
|
||||
private readonly SelectSymbolsDelegate _selectSymbols;
|
||||
|
||||
/// <summary>
|
||||
/// Delegate type for the <see cref="SelectSymbols"/> method
|
||||
/// </summary>
|
||||
/// <param name="utcTime">The current utc frontier time</param>
|
||||
/// <param name="data">The universe selection data</param>
|
||||
/// <returns>The symbols selected by the universe</returns>
|
||||
public delegate IEnumerable<Symbol> SelectSymbolsDelegate(DateTime utcTime, BaseDataCollection data);
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="SelectSymbolsUniverseDecorator"/> class
|
||||
/// </summary>
|
||||
/// <param name="universe">The universe to be decorated</param>
|
||||
/// <param name="selectSymbols">The new implementation of <see cref="SelectSymbols"/></param>
|
||||
public SelectSymbolsUniverseDecorator(Universe universe, SelectSymbolsDelegate selectSymbols)
|
||||
: base(universe)
|
||||
{
|
||||
_selectSymbols = selectSymbols;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Performs universe selection using the data specified
|
||||
/// </summary>
|
||||
/// <param name="utcTime">The current utc time</param>
|
||||
/// <param name="data">The symbols to remain in the universe</param>
|
||||
/// <returns>The data that passes the filter</returns>
|
||||
public override IEnumerable<Symbol> SelectSymbols(DateTime utcTime, BaseDataCollection data)
|
||||
{
|
||||
return _selectSymbols(utcTime, data);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,101 @@
|
||||
/*
|
||||
* 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.Collections.Generic;
|
||||
using QuantConnect.Securities;
|
||||
|
||||
namespace QuantConnect.Data.UniverseSelection
|
||||
{
|
||||
/// <summary>
|
||||
/// Defines the parameters required to add a subscription to a data feed.
|
||||
/// </summary>
|
||||
public class SubscriptionRequest : BaseDataRequest
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets true if the subscription is a universe
|
||||
/// </summary>
|
||||
public bool IsUniverseSubscription { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the universe this subscription resides in
|
||||
/// </summary>
|
||||
public Universe Universe { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the security. This is the destination of data for non-internal subscriptions.
|
||||
/// </summary>
|
||||
public Security Security { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the subscription configuration. This defines how/where to read the data.
|
||||
/// </summary>
|
||||
public SubscriptionDataConfig Configuration { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the tradable days specified by this request, in the security's data time zone
|
||||
/// </summary>
|
||||
public override IEnumerable<DateTime> TradableDaysInDataTimeZone => Time.EachTradeableDayInTimeZone(ExchangeHours,
|
||||
StartTimeLocal,
|
||||
EndTimeLocal,
|
||||
Configuration.DataTimeZone,
|
||||
Configuration.ExtendedMarketHours);
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="SubscriptionRequest"/> class
|
||||
/// </summary>
|
||||
public SubscriptionRequest(bool isUniverseSubscription,
|
||||
Universe universe,
|
||||
Security security,
|
||||
SubscriptionDataConfig configuration,
|
||||
DateTime startTimeUtc,
|
||||
DateTime endTimeUtc)
|
||||
: base(startTimeUtc, endTimeUtc, security.Exchange.Hours, configuration.TickType, configuration.IsCustomData, configuration.Type)
|
||||
{
|
||||
IsUniverseSubscription = isUniverseSubscription;
|
||||
Universe = universe;
|
||||
Security = security;
|
||||
Configuration = configuration;
|
||||
|
||||
// open interest data comes in once a day before market open,
|
||||
// make the subscription start from midnight and use always open exchange
|
||||
if (Configuration.TickType == TickType.OpenInterest)
|
||||
{
|
||||
StartTimeUtc = StartTimeUtc.ConvertFromUtc(ExchangeHours.TimeZone).Date.ConvertToUtc(ExchangeHours.TimeZone);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="SubscriptionRequest"/> class
|
||||
/// </summary>
|
||||
public SubscriptionRequest(SubscriptionRequest template,
|
||||
bool? isUniverseSubscription = null,
|
||||
Universe universe = null,
|
||||
Security security = null,
|
||||
SubscriptionDataConfig configuration = null,
|
||||
DateTime? startTimeUtc = null,
|
||||
DateTime? endTimeUtc = null
|
||||
)
|
||||
: this(isUniverseSubscription ?? template.IsUniverseSubscription,
|
||||
universe ?? template.Universe,
|
||||
security ?? template.Security,
|
||||
configuration ?? template.Configuration,
|
||||
startTimeUtc ?? template.StartTimeUtc,
|
||||
endTimeUtc ?? template.EndTimeUtc
|
||||
)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,469 @@
|
||||
/*
|
||||
* 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.Collections;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using QuantConnect.Interfaces;
|
||||
using QuantConnect.Securities;
|
||||
using QuantConnect.Util;
|
||||
|
||||
namespace QuantConnect.Data.UniverseSelection
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides a base class for all universes to derive from.
|
||||
/// </summary>
|
||||
public abstract class Universe : IDisposable
|
||||
{
|
||||
/// <summary>
|
||||
/// Used to round the members time in universe <see cref="CanRemoveMember"/>, this is
|
||||
/// done because we can not guarantee exact selection time in live mode, see GH issue 3287
|
||||
/// </summary>
|
||||
private TimeSpan? _minimumTimeInUniverseRoundingInterval;
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating that no change to the universe should be made
|
||||
/// </summary>
|
||||
public static readonly UnchangedUniverse Unchanged = UnchangedUniverse.Instance;
|
||||
|
||||
private HashSet<Symbol> _previousSelections;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the internal security collection used to define membership in this universe
|
||||
/// </summary>
|
||||
public virtual ConcurrentDictionary<Symbol, Member> Securities
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The currently selected symbol set
|
||||
/// </summary>
|
||||
/// <remarks>This set might be different than <see cref="Securities"/> which might hold members that are no longer selected
|
||||
/// but have not been removed yet, this can be because they have some open position, orders, haven't completed the minimum time in universe</remarks>
|
||||
public HashSet<Symbol> Selected
|
||||
{
|
||||
get; set;
|
||||
} = [];
|
||||
|
||||
/// <summary>
|
||||
/// True if this universe filter can run async in the data stack
|
||||
/// </summary>
|
||||
public virtual bool Asynchronous
|
||||
{
|
||||
get
|
||||
{
|
||||
if (UniverseSettings.Asynchronous.HasValue)
|
||||
{
|
||||
return UniverseSettings.Asynchronous.Value;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
set
|
||||
{
|
||||
UniverseSettings.Asynchronous = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Event fired when the universe selection has changed
|
||||
/// </summary>
|
||||
public event EventHandler SelectionChanged;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the security type of this universe
|
||||
/// </summary>
|
||||
public SecurityType SecurityType => Configuration.SecurityType;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the market of this universe
|
||||
/// </summary>
|
||||
public string Market => Configuration.Market;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the symbol of this universe
|
||||
/// </summary>
|
||||
public Symbol Symbol => Configuration.Symbol;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the data type of this universe
|
||||
/// </summary>
|
||||
public Type DataType => Configuration.Type;
|
||||
|
||||
/// <summary>
|
||||
/// Flag indicating if disposal of this universe has been requested
|
||||
/// </summary>
|
||||
public virtual bool DisposeRequested
|
||||
{
|
||||
get;
|
||||
protected set;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the settings used for subscriptions added for this universe
|
||||
/// </summary>
|
||||
public virtual UniverseSettings UniverseSettings
|
||||
{
|
||||
get; set;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the configuration used to get universe data
|
||||
/// </summary>
|
||||
public virtual SubscriptionDataConfig Configuration
|
||||
{
|
||||
get; private set;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the current listing of members in this universe. Modifications
|
||||
/// to this dictionary do not change universe membership.
|
||||
/// </summary>
|
||||
public Dictionary<Symbol, Security> Members
|
||||
{
|
||||
get { return Securities.Select(x => x.Value.Security).ToDictionary(x => x.Symbol); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="Universe"/> class
|
||||
/// </summary>
|
||||
/// <param name="config">The configuration used to source data for this universe</param>
|
||||
protected Universe(SubscriptionDataConfig config)
|
||||
{
|
||||
_previousSelections = new HashSet<Symbol>();
|
||||
Securities = new ConcurrentDictionary<Symbol, Member>();
|
||||
|
||||
Configuration = config;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether or not the specified security can be removed from
|
||||
/// this universe. This is useful to prevent securities from being taken
|
||||
/// out of a universe before the algorithm has had enough time to make
|
||||
/// decisions on the security
|
||||
/// </summary>
|
||||
/// <param name="utcTime">The current utc time</param>
|
||||
/// <param name="security">The security to check if its ok to remove</param>
|
||||
/// <returns>True if we can remove the security, false otherwise</returns>
|
||||
public virtual bool CanRemoveMember(DateTime utcTime, Security security)
|
||||
{
|
||||
// can always remove securities after dispose requested
|
||||
if (DisposeRequested)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// can always remove delisted securities from the universe
|
||||
if (security.IsDelisted)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
Member member;
|
||||
if (Securities.TryGetValue(security.Symbol, out member))
|
||||
{
|
||||
if (_minimumTimeInUniverseRoundingInterval == null)
|
||||
{
|
||||
// lets set _minimumTimeInUniverseRoundingInterval once
|
||||
_minimumTimeInUniverseRoundingInterval = UniverseSettings.MinimumTimeInUniverse;
|
||||
AdjustMinimumTimeInUniverseRoundingInterval();
|
||||
}
|
||||
|
||||
var timeInUniverse = utcTime - member.Added;
|
||||
if (timeInUniverse.Round(_minimumTimeInUniverseRoundingInterval.Value)
|
||||
>= UniverseSettings.MinimumTimeInUniverse)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Performs universe selection using the data specified
|
||||
/// </summary>
|
||||
/// <param name="utcTime">The current utc time</param>
|
||||
/// <param name="data">The symbols to remain in the universe</param>
|
||||
/// <returns>The data that passes the filter</returns>
|
||||
public IEnumerable<Symbol> PerformSelection(DateTime utcTime, BaseDataCollection data)
|
||||
{
|
||||
// select empty set of symbols after dispose requested
|
||||
if (DisposeRequested)
|
||||
{
|
||||
OnSelectionChanged();
|
||||
return Enumerable.Empty<Symbol>();
|
||||
}
|
||||
|
||||
var selections = data.FilteredContracts;
|
||||
if (selections == null)
|
||||
{
|
||||
// only trigger selection if it hasn't already been run
|
||||
var result = SelectSymbols(utcTime, data);
|
||||
if (ReferenceEquals(result, Unchanged))
|
||||
{
|
||||
data.FilteredContracts = _previousSelections;
|
||||
return Unchanged;
|
||||
}
|
||||
|
||||
selections = result.ToHashSet();
|
||||
data.FilteredContracts = selections;
|
||||
}
|
||||
|
||||
var hasDiffs = _previousSelections.AreDifferent(selections);
|
||||
_previousSelections = selections;
|
||||
if (!hasDiffs)
|
||||
{
|
||||
return Unchanged;
|
||||
}
|
||||
|
||||
OnSelectionChanged(selections);
|
||||
return selections;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Performs universe selection using the data specified
|
||||
/// </summary>
|
||||
/// <param name="utcTime">The current utc time</param>
|
||||
/// <param name="data">The symbols to remain in the universe</param>
|
||||
/// <returns>The data that passes the filter</returns>
|
||||
public abstract IEnumerable<Symbol> SelectSymbols(DateTime utcTime, BaseDataCollection data);
|
||||
|
||||
/// <summary>
|
||||
/// Creates and configures a security for the specified symbol
|
||||
/// </summary>
|
||||
/// <param name="symbol">The symbol of the security to be created</param>
|
||||
/// <param name="algorithm">The algorithm instance</param>
|
||||
/// <param name="marketHoursDatabase">The market hours database</param>
|
||||
/// <param name="symbolPropertiesDatabase">The symbol properties database</param>
|
||||
/// <returns>The newly initialized security object</returns>
|
||||
/// <obsolete>The CreateSecurity won't be called</obsolete>
|
||||
[Obsolete("CreateSecurity is obsolete and will not be called. The system will create the required Securities based on selected symbols")]
|
||||
public virtual Security CreateSecurity(Symbol symbol, IAlgorithm algorithm, MarketHoursDatabase marketHoursDatabase, SymbolPropertiesDatabase symbolPropertiesDatabase)
|
||||
{
|
||||
throw new InvalidOperationException("CreateSecurity is obsolete and should not be called." +
|
||||
"The system will create the required Securities based on selected symbols");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the subscription requests to be added for the specified security
|
||||
/// </summary>
|
||||
/// <param name="security">The security to get subscriptions for</param>
|
||||
/// <param name="currentTimeUtc">The current time in utc. This is the frontier time of the algorithm</param>
|
||||
/// <param name="maximumEndTimeUtc">The max end time</param>
|
||||
/// <returns>All subscriptions required by this security</returns>
|
||||
[Obsolete("This overload is obsolete and will not be called. It was not capable of creating new SubscriptionDataConfig due to lack of information")]
|
||||
public virtual IEnumerable<SubscriptionRequest> GetSubscriptionRequests(Security security, DateTime currentTimeUtc, DateTime maximumEndTimeUtc)
|
||||
{
|
||||
throw new InvalidOperationException("This overload is obsolete and should not be called." +
|
||||
"It was not capable of creating new SubscriptionDataConfig due to lack of information");
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Gets the subscription requests to be added for the specified security
|
||||
/// </summary>
|
||||
/// <param name="security">The security to get subscriptions for</param>
|
||||
/// <param name="currentTimeUtc">The current time in utc. This is the frontier time of the algorithm</param>
|
||||
/// <param name="maximumEndTimeUtc">The max end time</param>
|
||||
/// <param name="subscriptionService">Instance which implements <see cref="ISubscriptionDataConfigService"/> interface</param>
|
||||
/// <returns>All subscriptions required by this security</returns>
|
||||
public virtual IEnumerable<SubscriptionRequest> GetSubscriptionRequests(Security security,
|
||||
DateTime currentTimeUtc,
|
||||
DateTime maximumEndTimeUtc,
|
||||
ISubscriptionDataConfigService subscriptionService)
|
||||
{
|
||||
var result = subscriptionService.Add(security.Symbol,
|
||||
UniverseSettings.Resolution,
|
||||
UniverseSettings.FillForward,
|
||||
UniverseSettings.ExtendedMarketHours,
|
||||
dataNormalizationMode: UniverseSettings.DataNormalizationMode,
|
||||
subscriptionDataTypes: UniverseSettings.SubscriptionDataTypes,
|
||||
dataMappingMode: UniverseSettings.DataMappingMode,
|
||||
contractDepthOffset: (uint)Math.Abs(UniverseSettings.ContractDepthOffset));
|
||||
return result.Select(config => new SubscriptionRequest(isUniverseSubscription: false,
|
||||
universe: this,
|
||||
security: security,
|
||||
configuration: config,
|
||||
startTimeUtc: currentTimeUtc,
|
||||
endTimeUtc: maximumEndTimeUtc));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether or not the specified symbol is currently a member of this universe
|
||||
/// </summary>
|
||||
/// <param name="symbol">The symbol whose membership is to be checked</param>
|
||||
/// <returns>True if the specified symbol is part of this universe, false otherwise</returns>
|
||||
public bool ContainsMember(Symbol symbol)
|
||||
{
|
||||
return Securities.ContainsKey(symbol);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds the specified security to this universe
|
||||
/// </summary>
|
||||
/// <param name="utcTime">The current utc date time</param>
|
||||
/// <param name="security">The security to be added</param>
|
||||
/// <param name="isInternal">True if internal member</param>
|
||||
/// <returns>True if the security was successfully added,
|
||||
/// false if the security was already in the universe</returns>
|
||||
internal virtual bool AddMember(DateTime utcTime, Security security, bool isInternal)
|
||||
{
|
||||
// never add members to disposed universes
|
||||
if (DisposeRequested)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (security.IsDelisted)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return Securities.TryAdd(security.Symbol, new Member(utcTime, security, isInternal));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tries to remove the specified security from the universe. This
|
||||
/// will first check to verify that we can remove the security by
|
||||
/// calling the <see cref="CanRemoveMember"/> function.
|
||||
/// </summary>
|
||||
/// <param name="utcTime">The current utc time</param>
|
||||
/// <param name="security">The security to be removed</param>
|
||||
/// <returns>True if the security was successfully removed, false if
|
||||
/// we're not allowed to remove or if the security didn't exist</returns>
|
||||
internal virtual bool RemoveMember(DateTime utcTime, Security security)
|
||||
{
|
||||
if (CanRemoveMember(utcTime, security))
|
||||
{
|
||||
Member member;
|
||||
return Securities.TryRemove(security.Symbol, out member);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Marks this universe as disposed and ready to remove all child subscriptions
|
||||
/// </summary>
|
||||
public virtual void Dispose()
|
||||
{
|
||||
DisposeRequested = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Event invocator for the <see cref="SelectionChanged"/> event
|
||||
/// </summary>
|
||||
/// <param name="selection">The current universe selection</param>
|
||||
protected void OnSelectionChanged(HashSet<Symbol> selection = null)
|
||||
{
|
||||
SelectionChanged?.Invoke(this, new SelectionEventArgs(selection ?? new HashSet<Symbol>()));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Provides a value to indicate that no changes should be made to the universe.
|
||||
/// This value is intended to be returned by reference via <see cref="Universe.SelectSymbols"/>
|
||||
/// </summary>
|
||||
public sealed class UnchangedUniverse : IEnumerable<string>, IEnumerable<Symbol>
|
||||
{
|
||||
/// <summary>
|
||||
/// Read-only instance of the <see cref="UnchangedUniverse"/> value
|
||||
/// </summary>
|
||||
public static readonly UnchangedUniverse Instance = new UnchangedUniverse();
|
||||
private UnchangedUniverse() { }
|
||||
IEnumerator<Symbol> IEnumerable<Symbol>.GetEnumerator() { yield break; }
|
||||
IEnumerator<string> IEnumerable<string>.GetEnumerator() { yield break; }
|
||||
IEnumerator IEnumerable.GetEnumerator() { yield break; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Will adjust the <see cref="_minimumTimeInUniverseRoundingInterval"/>
|
||||
/// so rounding is performed as expected
|
||||
/// </summary>
|
||||
private void AdjustMinimumTimeInUniverseRoundingInterval()
|
||||
{
|
||||
if (_minimumTimeInUniverseRoundingInterval >= Time.OneDay)
|
||||
{
|
||||
_minimumTimeInUniverseRoundingInterval = Time.OneDay;
|
||||
}
|
||||
else if (_minimumTimeInUniverseRoundingInterval >= Time.OneHour)
|
||||
{
|
||||
_minimumTimeInUniverseRoundingInterval = Time.OneHour;
|
||||
}
|
||||
else if (_minimumTimeInUniverseRoundingInterval >= Time.OneMinute)
|
||||
{
|
||||
_minimumTimeInUniverseRoundingInterval = Time.OneMinute;
|
||||
}
|
||||
else if (_minimumTimeInUniverseRoundingInterval >= Time.OneSecond)
|
||||
{
|
||||
_minimumTimeInUniverseRoundingInterval = Time.OneSecond;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Member of the Universe
|
||||
/// </summary>
|
||||
public sealed class Member
|
||||
{
|
||||
/// <summary>
|
||||
/// DateTime when added
|
||||
/// </summary>
|
||||
public DateTime Added { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// The security that was added
|
||||
/// </summary>
|
||||
public Security Security { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// True if the security was added as internal by this universe
|
||||
/// </summary>
|
||||
public bool IsInternal { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Initialize a new member for the universe
|
||||
/// </summary>
|
||||
/// <param name="added">DateTime added</param>
|
||||
/// <param name="security">Security to add</param>
|
||||
/// <param name="isInternal">True if internal member</param>
|
||||
public Member(DateTime added, Security security, bool isInternal)
|
||||
{
|
||||
Added = added;
|
||||
Security = security;
|
||||
IsInternal = isInternal;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Event fired when the universe selection changes
|
||||
/// </summary>
|
||||
public class SelectionEventArgs : EventArgs
|
||||
{
|
||||
/// <summary>
|
||||
/// The current universe selection
|
||||
/// </summary>
|
||||
public HashSet<Symbol> CurrentSelection { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new instance
|
||||
/// </summary>
|
||||
public SelectionEventArgs(HashSet<Symbol> currentSelection)
|
||||
{
|
||||
CurrentSelection = currentSelection;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,156 @@
|
||||
/*
|
||||
* 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.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using QuantConnect.Interfaces;
|
||||
using QuantConnect.Securities;
|
||||
|
||||
namespace QuantConnect.Data.UniverseSelection
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides an implementation of <see cref="UniverseSelection.Universe"/> that redirects all calls to a
|
||||
/// wrapped (or decorated) universe. This provides scaffolding for other decorators who
|
||||
/// only need to override one or two methods.
|
||||
/// </summary>
|
||||
/// <remarks> Requires special handling due to `this != this.Universe`
|
||||
/// <see cref="GetSubscriptionRequests(Security, DateTime, DateTime, ISubscriptionDataConfigService)"/></remarks>
|
||||
public abstract class UniverseDecorator : Universe
|
||||
{
|
||||
/// <summary>
|
||||
/// The decorated universe instance
|
||||
/// </summary>
|
||||
protected Universe Universe { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the settings used for subscriptions added for this universe
|
||||
/// </summary>
|
||||
public override UniverseSettings UniverseSettings
|
||||
{
|
||||
get
|
||||
{
|
||||
return Universe.UniverseSettings;
|
||||
}
|
||||
set
|
||||
{
|
||||
Universe.UniverseSettings = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the internal security collection used to define membership in this universe
|
||||
/// </summary>
|
||||
public override ConcurrentDictionary<Symbol, Member> Securities
|
||||
{
|
||||
get { return Universe.Securities; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="UniverseDecorator"/> class
|
||||
/// </summary>
|
||||
/// <param name="universe">The decorated universe. All overridable methods delegate to this instance.</param>
|
||||
protected UniverseDecorator(Universe universe)
|
||||
: base(universe.Configuration)
|
||||
{
|
||||
Universe = universe;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the subscription requests to be added for the specified security
|
||||
/// </summary>
|
||||
/// <param name="security">The security to get subscriptions for</param>
|
||||
/// <param name="currentTimeUtc">The current time in utc. This is the frontier time of the algorithm</param>
|
||||
/// <param name="maximumEndTimeUtc">The max end time</param>
|
||||
/// <returns>All subscriptions required by this security</returns>
|
||||
[Obsolete("This overload is obsolete and will not be called. It was not capable of creating new SubscriptionDataConfig due to lack of information")]
|
||||
public override IEnumerable<SubscriptionRequest> GetSubscriptionRequests(Security security, DateTime currentTimeUtc, DateTime maximumEndTimeUtc)
|
||||
{
|
||||
return Universe.GetSubscriptionRequests(security, currentTimeUtc, maximumEndTimeUtc);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the subscription requests to be added for the specified security
|
||||
/// </summary>
|
||||
/// <param name="security">The security to get subscriptions for</param>
|
||||
/// <param name="currentTimeUtc">The current time in utc. This is the frontier time of the algorithm</param>
|
||||
/// <param name="maximumEndTimeUtc">The max end time</param>
|
||||
/// <param name="subscriptionService">Instance which implements <see cref="ISubscriptionDataConfigService"/> interface</param>
|
||||
/// <returns>All subscriptions required by this security</returns>
|
||||
public override IEnumerable<SubscriptionRequest> GetSubscriptionRequests(Security security,
|
||||
DateTime currentTimeUtc,
|
||||
DateTime maximumEndTimeUtc,
|
||||
ISubscriptionDataConfigService subscriptionService)
|
||||
{
|
||||
var result = Universe.GetSubscriptionRequests(
|
||||
security,
|
||||
currentTimeUtc,
|
||||
maximumEndTimeUtc,
|
||||
subscriptionService).ToList();
|
||||
|
||||
for (var i = 0; i < result.Count; i++)
|
||||
{
|
||||
// This is required because the system tracks which universe
|
||||
// is requesting to add or remove each SubscriptionRequest.
|
||||
// UniverseDecorator is a special case because
|
||||
// `this != UniverseDecorator.Universe`
|
||||
result[i] =
|
||||
new SubscriptionRequest(result[i], universe: this);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether or not the specified security can be removed from
|
||||
/// this universe. This is useful to prevent securities from being taken
|
||||
/// out of a universe before the algorithm has had enough time to make
|
||||
/// decisions on the security
|
||||
/// </summary>
|
||||
/// <param name="utcTime">The current utc time</param>
|
||||
/// <param name="security">The security to check if its ok to remove</param>
|
||||
/// <returns>True if we can remove the security, false otherwise</returns>
|
||||
public override bool CanRemoveMember(DateTime utcTime, Security security)
|
||||
{
|
||||
return Universe.CanRemoveMember(utcTime, security);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates and configures a security for the specified symbol
|
||||
/// </summary>
|
||||
/// <param name="symbol">The symbol of the security to be created</param>
|
||||
/// <param name="algorithm">The algorithm instance</param>
|
||||
/// <param name="marketHoursDatabase">The market hours database</param>
|
||||
/// <param name="symbolPropertiesDatabase">The symbol properties database</param>
|
||||
/// <returns>The newly initialized security object</returns>
|
||||
[Obsolete("CreateSecurity is obsolete and will not be called. The system will create the required Securities based on selected symbols")]
|
||||
public override Security CreateSecurity(Symbol symbol, IAlgorithm algorithm, MarketHoursDatabase marketHoursDatabase, SymbolPropertiesDatabase symbolPropertiesDatabase)
|
||||
{
|
||||
return Universe.CreateSecurity(symbol, algorithm, marketHoursDatabase, symbolPropertiesDatabase);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Performs universe selection using the data specified
|
||||
/// </summary>
|
||||
/// <param name="utcTime">The current utc time</param>
|
||||
/// <param name="data">The symbols to remain in the universe</param>
|
||||
/// <returns>The data that passes the filter</returns>
|
||||
public override IEnumerable<Symbol> SelectSymbols(DateTime utcTime, BaseDataCollection data)
|
||||
{
|
||||
return Universe.SelectSymbols(utcTime, data);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,226 @@
|
||||
/*
|
||||
* 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.IO;
|
||||
using System.Linq;
|
||||
using QuantConnect.Logging;
|
||||
using QuantConnect.Data.Market;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace QuantConnect.Data.UniverseSelection
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides extension methods for the <see cref="Universe"/> class
|
||||
/// </summary>
|
||||
public static class UniverseExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Creates a new universe that logically is the result of wiring the two universes together such that
|
||||
/// the first will produce subscriptions for the second and the second will only select on data that has
|
||||
/// passed the first.
|
||||
///
|
||||
/// NOTE: The <paramref name="first"/> and <paramref name="second"/> universe instances provided
|
||||
/// to this method should not be manually added to the algorithm.
|
||||
/// </summary>
|
||||
/// <param name="first">The first universe in this 'chain'</param>
|
||||
/// <param name="second">The second universe in this 'chain'</param>
|
||||
/// <param name="configurationPerSymbol">True if each symbol as its own configuration, false otherwise</param>
|
||||
/// <returns>A new universe that can be added to the algorithm that represents invoking the first universe
|
||||
/// and then the second universe using the outputs of the first. </returns>
|
||||
public static Universe ChainedTo(this Universe first, Universe second, bool configurationPerSymbol)
|
||||
{
|
||||
var prefilteredSecond = second.PrefilterUsing(first);
|
||||
return new GetSubscriptionRequestsUniverseDecorator(first, (security, currentTimeUtc, maximumEndTimeUtc) =>
|
||||
{
|
||||
return first.GetSubscriptionRequests(security, currentTimeUtc, maximumEndTimeUtc).Select(request => new SubscriptionRequest(
|
||||
template: request,
|
||||
isUniverseSubscription: true,
|
||||
universe: prefilteredSecond,
|
||||
security: security,
|
||||
configuration: configurationPerSymbol ? new SubscriptionDataConfig(prefilteredSecond.Configuration, symbol: security.Symbol) : prefilteredSecond.Configuration,
|
||||
startTimeUtc: currentTimeUtc - prefilteredSecond.Configuration.Resolution.ToTimeSpan(),
|
||||
endTimeUtc: currentTimeUtc.AddSeconds(-1)
|
||||
));
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new universe that restricts the universe selection data to symbols that passed the
|
||||
/// first universe's selection critera
|
||||
///
|
||||
/// NOTE: The <paramref name="second"/> universe instance provided to this method should not be manually
|
||||
/// added to the algorithm. The <paramref name="first"/> should still be manually (assuming no other changes).
|
||||
/// </summary>
|
||||
/// <param name="second">The universe to be filtere</param>
|
||||
/// <param name="first">The universe providing the set of symbols used for filtered</param>
|
||||
/// <returns>A new universe that can be added to the algorithm that represents invoking the second
|
||||
/// using the selections from the first as a filter.</returns>
|
||||
public static Universe PrefilterUsing(this Universe second, Universe first)
|
||||
{
|
||||
return new SelectSymbolsUniverseDecorator(second, (utcTime, data) =>
|
||||
{
|
||||
var clone = (BaseDataCollection)data.Clone();
|
||||
clone.Data = clone.Data.Where(d => first.ContainsMember(d.Symbol)).ToList();
|
||||
return second.SelectSymbols(utcTime, clone);
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a universe symbol
|
||||
/// </summary>
|
||||
/// <param name="securityType">The security</param>
|
||||
/// <param name="market">The market</param>
|
||||
/// <param name="ticker">The Universe ticker</param>
|
||||
/// <returns>A symbol for user defined universe of the specified security type and market</returns>
|
||||
public static Symbol CreateSymbol(SecurityType securityType, string market, string ticker)
|
||||
{
|
||||
// TODO looks like we can just replace this for Symbol.Create?
|
||||
|
||||
SecurityIdentifier sid;
|
||||
switch (securityType)
|
||||
{
|
||||
case SecurityType.Base:
|
||||
sid = SecurityIdentifier.GenerateBase(null, ticker, market);
|
||||
break;
|
||||
|
||||
case SecurityType.Equity:
|
||||
sid = SecurityIdentifier.GenerateEquity(SecurityIdentifier.DefaultDate, ticker, market);
|
||||
break;
|
||||
|
||||
case SecurityType.Option:
|
||||
var underlying = SecurityIdentifier.GenerateEquity(SecurityIdentifier.DefaultDate, ticker, market);
|
||||
sid = SecurityIdentifier.GenerateOption(SecurityIdentifier.DefaultDate, underlying, market, 0, 0, 0);
|
||||
break;
|
||||
|
||||
case SecurityType.FutureOption:
|
||||
var underlyingFuture = SecurityIdentifier.GenerateFuture(SecurityIdentifier.DefaultDate, ticker, market);
|
||||
sid = SecurityIdentifier.GenerateOption(SecurityIdentifier.DefaultDate, underlyingFuture, market, 0, 0, 0);
|
||||
break;
|
||||
|
||||
case SecurityType.IndexOption:
|
||||
var underlyingIndex = SecurityIdentifier.GenerateIndex(ticker, market);
|
||||
sid = SecurityIdentifier.GenerateOption(SecurityIdentifier.DefaultDate, underlyingIndex, market, 0, 0, OptionStyle.European);
|
||||
break;
|
||||
|
||||
case SecurityType.Forex:
|
||||
sid = SecurityIdentifier.GenerateForex(ticker, market);
|
||||
break;
|
||||
|
||||
case SecurityType.Cfd:
|
||||
sid = SecurityIdentifier.GenerateCfd(ticker, market);
|
||||
break;
|
||||
|
||||
case SecurityType.Index:
|
||||
sid = SecurityIdentifier.GenerateIndex(ticker, market);
|
||||
break;
|
||||
|
||||
case SecurityType.Future:
|
||||
sid = SecurityIdentifier.GenerateFuture(SecurityIdentifier.DefaultDate, ticker, market);
|
||||
break;
|
||||
|
||||
case SecurityType.Crypto:
|
||||
sid = SecurityIdentifier.GenerateCrypto(ticker, market);
|
||||
break;
|
||||
|
||||
case SecurityType.CryptoFuture:
|
||||
sid = SecurityIdentifier.GenerateCryptoFuture(SecurityIdentifier.DefaultDate, ticker, market);
|
||||
break;
|
||||
|
||||
case SecurityType.Commodity:
|
||||
default:
|
||||
throw new NotImplementedException($"The specified security type is not implemented yet: {securityType}");
|
||||
}
|
||||
|
||||
return new Symbol(sid, ticker);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Processes the universe download based on parameters.
|
||||
/// </summary>
|
||||
/// <param name="dataDownloader">The data downloader instance.</param>
|
||||
/// <param name="universeDownloadParameters">The parameters for universe downloading.</param>
|
||||
public static void RunUniverseDownloader(IDataDownloader dataDownloader, DataUniverseDownloaderGetParameters universeDownloadParameters)
|
||||
{
|
||||
var universeDataBySymbol = new Dictionary<Symbol, DerivativeUniverseData>();
|
||||
foreach (var (processingDate, universeDownloaderParameters) in universeDownloadParameters.CreateDataDownloaderGetParameters())
|
||||
{
|
||||
universeDataBySymbol.Clear();
|
||||
|
||||
foreach (var downloaderParameters in universeDownloaderParameters)
|
||||
{
|
||||
Log.Debug($"{nameof(UniverseExtensions)}.{nameof(RunUniverseDownloader)}:Generating universe for {downloaderParameters.Symbol} on {processingDate:yyyy/MM/dd}");
|
||||
|
||||
var historyData = dataDownloader.Get(downloaderParameters);
|
||||
|
||||
if (historyData == null)
|
||||
{
|
||||
Log.Debug($"{nameof(UniverseExtensions)}.{nameof(RunUniverseDownloader)}: No data available for the following parameters: {universeDownloadParameters}");
|
||||
continue;
|
||||
}
|
||||
|
||||
foreach (var baseData in historyData)
|
||||
{
|
||||
switch (baseData)
|
||||
{
|
||||
case TradeBar tradeBar:
|
||||
if (!universeDataBySymbol.TryAdd(tradeBar.Symbol, new(tradeBar)))
|
||||
{
|
||||
universeDataBySymbol[tradeBar.Symbol].UpdateByTradeBar(tradeBar);
|
||||
}
|
||||
break;
|
||||
case OpenInterest openInterest:
|
||||
if (!universeDataBySymbol.TryAdd(openInterest.Symbol, new(openInterest)))
|
||||
{
|
||||
universeDataBySymbol[openInterest.Symbol].UpdateByOpenInterest(openInterest);
|
||||
}
|
||||
break;
|
||||
case QuoteBar quoteBar:
|
||||
if (!universeDataBySymbol.TryAdd(quoteBar.Symbol, new(quoteBar)))
|
||||
{
|
||||
universeDataBySymbol[quoteBar.Symbol].UpdateByQuoteBar(quoteBar);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
throw new InvalidOperationException($"{nameof(UniverseExtensions)}.{nameof(RunUniverseDownloader)}: Unexpected data type encountered.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (universeDataBySymbol.Count == 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
using var writer = new StreamWriter(universeDownloadParameters.GetUniverseFileName(processingDate));
|
||||
|
||||
writer.WriteLine($"#{OptionUniverse.CsvHeader}");
|
||||
|
||||
// Write option data, sorted by contract type (Call/Put), strike price, expiration date, and then by full ID
|
||||
foreach (var universeData in universeDataBySymbol
|
||||
.OrderBy(x => x.Key.Underlying != null)
|
||||
.ThenBy(d => d.Key.SecurityType.IsOption() ? d.Key.ID.OptionRight : 0)
|
||||
.ThenBy(d => d.Key.SecurityType.IsOption() ? d.Key.ID.StrikePrice : 0)
|
||||
.ThenBy(d => d.Key.ID.Date)
|
||||
.ThenBy(d => d.Key.ID))
|
||||
{
|
||||
writer.WriteLine(universeData.Value.ToCsv());
|
||||
}
|
||||
|
||||
Log.Trace($"{nameof(UniverseExtensions)}.{nameof(RunUniverseDownloader)}:Generated for {universeDownloadParameters.Symbol} on {processingDate:yyyy/MM/dd} with {universeDataBySymbol.Count} entries");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,122 @@
|
||||
/*
|
||||
* 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.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using Python.Runtime;
|
||||
using QuantConnect.Interfaces;
|
||||
using QuantConnect.Python;
|
||||
using QuantConnect.Securities;
|
||||
|
||||
namespace QuantConnect.Data.UniverseSelection
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides an implementation of <see cref="Universe"/> that wraps a <see cref="PyObject"/> object
|
||||
/// </summary>
|
||||
public class UniversePythonWrapper : Universe
|
||||
{
|
||||
private readonly BasePythonWrapper<Universe> _model;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the settings used for subscriptions added for this universe
|
||||
/// </summary>
|
||||
public override UniverseSettings UniverseSettings
|
||||
{
|
||||
get
|
||||
{
|
||||
return _model.GetProperty<UniverseSettings>(nameof(UniverseSettings));
|
||||
}
|
||||
set
|
||||
{
|
||||
_model.SetProperty(nameof(UniverseSettings), value);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Flag indicating if disposal of this universe has been requested
|
||||
/// </summary>
|
||||
public override bool DisposeRequested
|
||||
{
|
||||
get
|
||||
{
|
||||
return _model.GetProperty<bool>(nameof(DisposeRequested));
|
||||
}
|
||||
protected set
|
||||
{
|
||||
_model.SetProperty(nameof(DisposeRequested), value);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the configuration used to get universe data
|
||||
/// </summary>
|
||||
public override SubscriptionDataConfig Configuration
|
||||
{
|
||||
get
|
||||
{
|
||||
return _model.GetProperty<SubscriptionDataConfig>(nameof(Configuration));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the internal security collection used to define membership in this universe
|
||||
/// </summary>
|
||||
public override ConcurrentDictionary<Symbol, Member> Securities
|
||||
{
|
||||
get
|
||||
{
|
||||
return _model.GetProperty<ConcurrentDictionary<Symbol, Member>>(nameof(Securities));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="UniversePythonWrapper"/> class
|
||||
/// </summary>
|
||||
public UniversePythonWrapper(PyObject universe) : base(null)
|
||||
{
|
||||
_model = new BasePythonWrapper<Universe>(universe, false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Performs universe selection using the data specified
|
||||
/// </summary>
|
||||
/// <param name="utcTime">The current utc time</param>
|
||||
/// <param name="data">The symbols to remain in the universe</param>
|
||||
/// <returns>The data that passes the filter</returns>
|
||||
public override IEnumerable<Symbol> SelectSymbols(DateTime utcTime, BaseDataCollection data)
|
||||
{
|
||||
return _model.InvokeMethodAndEnumerate<Symbol>(nameof(SelectSymbols), utcTime, data);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the subscription requests to be added for the specified security
|
||||
/// </summary>
|
||||
/// <param name="security">The security to get subscriptions for</param>
|
||||
/// <param name="currentTimeUtc">The current time in utc. This is the frontier time of the algorithm</param>
|
||||
/// <param name="maximumEndTimeUtc">The max end time</param>
|
||||
/// <param name="subscriptionService">Instance which implements <see cref="ISubscriptionDataConfigService"/> interface</param>
|
||||
/// <returns>All subscriptions required by this security</returns>
|
||||
public override IEnumerable<SubscriptionRequest> GetSubscriptionRequests(Security security, DateTime currentTimeUtc, DateTime maximumEndTimeUtc,
|
||||
ISubscriptionDataConfigService subscriptionService)
|
||||
{
|
||||
var requests = _model.InvokeMethodAndEnumerate<SubscriptionRequest>(nameof(GetSubscriptionRequests), security, currentTimeUtc,
|
||||
maximumEndTimeUtc, subscriptionService);
|
||||
foreach (var subscriptionRequest in requests)
|
||||
{
|
||||
yield return new SubscriptionRequest(subscriptionRequest, universe: this);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,140 @@
|
||||
/*
|
||||
* 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 QuantConnect.Scheduling;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace QuantConnect.Data.UniverseSelection
|
||||
{
|
||||
/// <summary>
|
||||
/// Defines settings required when adding a subscription
|
||||
/// </summary>
|
||||
public class UniverseSettings
|
||||
{
|
||||
/// <summary>
|
||||
/// The resolution to be used
|
||||
/// </summary>
|
||||
public Resolution Resolution { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The leverage to be used
|
||||
/// </summary>
|
||||
public decimal Leverage { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// True to fill data forward, false otherwise
|
||||
/// </summary>
|
||||
public bool FillForward { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// If configured, will be used to determine universe selection schedule and filter or skip selection data
|
||||
/// that does not fit the schedule
|
||||
/// </summary>
|
||||
public Schedule Schedule { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// True to allow extended market hours data, false otherwise
|
||||
/// </summary>
|
||||
public bool ExtendedMarketHours { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Defines the minimum amount of time a security must be in
|
||||
/// the universe before being removed.
|
||||
/// </summary>
|
||||
/// <remarks>When selection takes place, the actual members time in the universe
|
||||
/// will be rounded based on this TimeSpan, so that relative small differences do not
|
||||
/// cause an unexpected behavior <see cref="Universe.CanRemoveMember"/></remarks>
|
||||
public TimeSpan MinimumTimeInUniverse { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Defines how universe data is normalized before being send into the algorithm
|
||||
/// </summary>
|
||||
public DataNormalizationMode DataNormalizationMode { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Defines how universe data is mapped together
|
||||
/// </summary>
|
||||
/// <remarks>This is particular useful when generating continuous futures</remarks>
|
||||
public DataMappingMode DataMappingMode { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The continuous contract desired offset from the current front month.
|
||||
/// For example, 0 (default) will use the front month, 1 will use the back month contra
|
||||
/// </summary>
|
||||
public int ContractDepthOffset { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Allows a universe to specify which data types to add for a selected symbol
|
||||
/// </summary>
|
||||
public List<Tuple<Type, TickType>> SubscriptionDataTypes { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// True if universe selection can run asynchronous
|
||||
/// </summary>
|
||||
public bool? Asynchronous { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="UniverseSettings"/> class
|
||||
/// </summary>
|
||||
/// <param name="resolution">The resolution</param>
|
||||
/// <param name="leverage">The leverage to be used</param>
|
||||
/// <param name="fillForward">True to fill data forward, false otherwise</param>
|
||||
/// <param name="extendedMarketHours">True to allow extended market hours data, false otherwise</param>
|
||||
/// <param name="minimumTimeInUniverse">Defines the minimum amount of time a security must remain in the universe before being removed</param>
|
||||
/// <param name="dataNormalizationMode">Defines how universe data is normalized before being send into the algorithm</param>
|
||||
/// <param name="dataMappingMode">The contract mapping mode to use for the security</param>
|
||||
/// <param name="contractDepthOffset">The continuous contract desired offset from the current front month.
|
||||
/// For example, 0 (default) will use the front month, 1 will use the back month contract</param>
|
||||
/// <param name="asynchronous">True if universe selection can run asynchronous</param>
|
||||
/// <param name="selectionDateRule">If provided, will be used to determine universe selection schedule</param>
|
||||
public UniverseSettings(Resolution resolution, decimal leverage, bool fillForward, bool extendedMarketHours, TimeSpan minimumTimeInUniverse, DataNormalizationMode dataNormalizationMode = DataNormalizationMode.Adjusted,
|
||||
DataMappingMode dataMappingMode = DataMappingMode.OpenInterest, int contractDepthOffset = 0, bool? asynchronous = null, IDateRule selectionDateRule = null)
|
||||
{
|
||||
Resolution = resolution;
|
||||
Leverage = leverage;
|
||||
FillForward = fillForward;
|
||||
DataMappingMode = dataMappingMode;
|
||||
ContractDepthOffset = contractDepthOffset;
|
||||
ExtendedMarketHours = extendedMarketHours;
|
||||
MinimumTimeInUniverse = minimumTimeInUniverse;
|
||||
DataNormalizationMode = dataNormalizationMode;
|
||||
Asynchronous = asynchronous;
|
||||
Schedule = new Schedule();
|
||||
if (selectionDateRule != null)
|
||||
{
|
||||
Schedule.On(selectionDateRule);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="UniverseSettings"/> class
|
||||
/// </summary>
|
||||
public UniverseSettings(UniverseSettings universeSettings)
|
||||
{
|
||||
Resolution = universeSettings.Resolution;
|
||||
Leverage = universeSettings.Leverage;
|
||||
FillForward = universeSettings.FillForward;
|
||||
DataMappingMode = universeSettings.DataMappingMode;
|
||||
ContractDepthOffset = universeSettings.ContractDepthOffset;
|
||||
ExtendedMarketHours = universeSettings.ExtendedMarketHours;
|
||||
MinimumTimeInUniverse = universeSettings.MinimumTimeInUniverse;
|
||||
DataNormalizationMode = universeSettings.DataNormalizationMode;
|
||||
SubscriptionDataTypes = universeSettings.SubscriptionDataTypes;
|
||||
Asynchronous = universeSettings.Asynchronous;
|
||||
Schedule = universeSettings.Schedule.Clone();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,292 @@
|
||||
/*
|
||||
* 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 QuantConnect.Util;
|
||||
using QuantConnect.Interfaces;
|
||||
using QuantConnect.Securities;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Specialized;
|
||||
|
||||
namespace QuantConnect.Data.UniverseSelection
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents the universe defined by the user's algorithm. This is
|
||||
/// the default universe where manually added securities live by
|
||||
/// market/security type. They can also be manually generated and
|
||||
/// can be configured to fire on certain interval and will always
|
||||
/// return the internal list of symbols.
|
||||
/// </summary>
|
||||
public class UserDefinedUniverse : Universe, INotifyCollectionChanged, ITimeTriggeredUniverse
|
||||
{
|
||||
private readonly TimeSpan _interval;
|
||||
private readonly HashSet<SubscriptionDataConfig> _subscriptionDataConfigs = new HashSet<SubscriptionDataConfig>();
|
||||
private readonly HashSet<Symbol> _symbols = new HashSet<Symbol>();
|
||||
// `UniverseSelection.RemoveSecurityFromUniverse()` will query us at `GetSubscriptionRequests()` to get the `SubscriptionDataConfig` and remove it from the DF
|
||||
// and we need to return the config even after the call to `Remove()`
|
||||
private readonly HashSet<SubscriptionDataConfig> _pendingRemovedConfigs = new HashSet<SubscriptionDataConfig>();
|
||||
private readonly Func<DateTime, IEnumerable<Symbol>> _selector;
|
||||
private readonly object _lock = new ();
|
||||
|
||||
/// <summary>
|
||||
/// Event fired when a symbol is added or removed from this universe
|
||||
/// </summary>
|
||||
public event NotifyCollectionChangedEventHandler CollectionChanged;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the interval of this user defined universe
|
||||
/// </summary>
|
||||
public TimeSpan Interval
|
||||
{
|
||||
get { return _interval; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="UserDefinedUniverse"/> class
|
||||
/// </summary>
|
||||
/// <param name="configuration">The configuration used to resolve the data for universe selection</param>
|
||||
/// <param name="universeSettings">The settings used for new subscriptions generated by this universe</param>
|
||||
/// <param name="interval">The interval at which selection should be performed</param>
|
||||
/// <param name="symbols">The initial set of symbols in this universe</param>
|
||||
public UserDefinedUniverse(SubscriptionDataConfig configuration, UniverseSettings universeSettings, TimeSpan interval, IEnumerable<Symbol> symbols)
|
||||
: base(configuration)
|
||||
{
|
||||
_interval = interval;
|
||||
_symbols = symbols.ToHashSet();
|
||||
UniverseSettings = universeSettings;
|
||||
// the selector Func will be the union of the provided symbols and the added symbols or subscriptions data configurations
|
||||
_selector = time => {
|
||||
lock(_lock)
|
||||
{
|
||||
return _subscriptionDataConfigs.Select(x => x.Symbol).Union(_symbols).ToHashSet();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="UserDefinedUniverse"/> class
|
||||
/// </summary>
|
||||
/// <param name="configuration">The configuration used to resolve the data for universe selection</param>
|
||||
/// <param name="universeSettings">The settings used for new subscriptions generated by this universe</param>
|
||||
/// <param name="interval">The interval at which selection should be performed</param>
|
||||
/// <param name="selector">Universe selection function invoked for each time returned via GetTriggerTimes.
|
||||
/// The function parameter is a DateTime in the time zone of configuration.ExchangeTimeZone</param>
|
||||
public UserDefinedUniverse(SubscriptionDataConfig configuration, UniverseSettings universeSettings, TimeSpan interval, Func<DateTime, IEnumerable<string>> selector)
|
||||
: base(configuration)
|
||||
{
|
||||
_interval = interval;
|
||||
UniverseSettings = universeSettings;
|
||||
_selector = time =>
|
||||
{
|
||||
var selectSymbolsResult = selector(time.ConvertFromUtc(Configuration.ExchangeTimeZone));
|
||||
// if we received an unchaged then short circuit the symbol creation and return it directly
|
||||
if (ReferenceEquals(selectSymbolsResult, Unchanged)) return Unchanged;
|
||||
return selectSymbolsResult.Select(sym => Symbol.Create(sym, Configuration.SecurityType, Configuration.Market));
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a user defined universe symbol
|
||||
/// </summary>
|
||||
/// <param name="securityType">The security</param>
|
||||
/// <param name="market">The market</param>
|
||||
/// <returns>A symbol for user defined universe of the specified security type and market</returns>
|
||||
public static Symbol CreateSymbol(SecurityType securityType, string market)
|
||||
{
|
||||
var ticker = $"qc-universe-userdefined-{market.ToLowerInvariant()}-{securityType}";
|
||||
return UniverseExtensions.CreateSymbol(securityType, market, ticker);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds the specified <see cref="Symbol"/> to this universe
|
||||
/// </summary>
|
||||
/// <param name="symbol">The symbol to be added to this universe</param>
|
||||
/// <returns>True if the symbol was added, false if it was already present</returns>
|
||||
public bool Add(Symbol symbol)
|
||||
{
|
||||
var added = false;
|
||||
lock (_lock)
|
||||
{
|
||||
// let's not call the event having the lock if we don't need too
|
||||
added = _symbols.Add(symbol);
|
||||
}
|
||||
|
||||
if (added)
|
||||
{
|
||||
OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, symbol));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds the specified <see cref="SubscriptionDataConfig"/> to this universe
|
||||
/// </summary>
|
||||
/// <param name="subscriptionDataConfig">The subscription data configuration to be added to this universe</param>
|
||||
/// <returns>True if the subscriptionDataConfig was added, false if it was already present</returns>
|
||||
public bool Add(SubscriptionDataConfig subscriptionDataConfig)
|
||||
{
|
||||
var added = false;
|
||||
lock (_lock)
|
||||
{
|
||||
// let's not call the event having the lock if we don't need too
|
||||
added = _subscriptionDataConfigs.Add(subscriptionDataConfig);
|
||||
}
|
||||
|
||||
if (added)
|
||||
{
|
||||
OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, subscriptionDataConfig.Symbol));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes the specified <see cref="Symbol"/> from this universe
|
||||
/// </summary>
|
||||
/// <param name="symbol">The symbol to be removed</param>
|
||||
/// <returns>True if the symbol was removed, false if the symbol was not present</returns>
|
||||
public bool Remove(Symbol symbol)
|
||||
{
|
||||
if (RemoveAndKeepTrack(symbol))
|
||||
{
|
||||
OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, symbol));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the symbols defined by the user for this universe
|
||||
/// </summary>
|
||||
/// <param name="utcTime">The current utc time</param>
|
||||
/// <param name="data">The symbols to remain in the universe</param>
|
||||
/// <returns>The data that passes the filter</returns>
|
||||
public override IEnumerable<Symbol> SelectSymbols(DateTime utcTime, BaseDataCollection data)
|
||||
{
|
||||
return _selector(utcTime);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns an enumerator that defines when this user defined universe will be invoked
|
||||
/// </summary>
|
||||
/// <returns>An enumerator of DateTime that defines when this universe will be invoked</returns>
|
||||
public virtual IEnumerable<DateTime> GetTriggerTimes(DateTime startTimeUtc, DateTime endTimeUtc, MarketHoursDatabase marketHoursDatabase)
|
||||
{
|
||||
var exchangeHours = marketHoursDatabase.GetExchangeHours(Configuration);
|
||||
var localStartTime = startTimeUtc.ConvertFromUtc(exchangeHours.TimeZone);
|
||||
var localEndTime = endTimeUtc.ConvertFromUtc(exchangeHours.TimeZone);
|
||||
|
||||
var first = true;
|
||||
foreach (var dateTime in LinqExtensions.Range(localStartTime, localEndTime, dt => dt + Interval))
|
||||
{
|
||||
if (first)
|
||||
{
|
||||
yield return dateTime;
|
||||
first = false;
|
||||
}
|
||||
else if (exchangeHours.IsOpen(dateTime, dateTime + Interval, Configuration.ExtendedMarketHours))
|
||||
{
|
||||
yield return dateTime;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Event invocator for the <see cref="CollectionChanged"/> event
|
||||
/// </summary>
|
||||
/// <param name="e">The notify collection changed event arguments</param>
|
||||
protected virtual void OnCollectionChanged(NotifyCollectionChangedEventArgs e)
|
||||
{
|
||||
CollectionChanged?.Invoke(this, e);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the subscription requests to be added for the specified security
|
||||
/// </summary>
|
||||
/// <param name="security">The security to get subscriptions for</param>
|
||||
/// <param name="currentTimeUtc">The current time in utc. This is the frontier time of the algorithm</param>
|
||||
/// <param name="maximumEndTimeUtc">The max end time</param>
|
||||
/// <param name="subscriptionService">Instance which implements <see cref="ISubscriptionDataConfigService"/> interface</param>
|
||||
/// <returns>All subscriptions required by this security</returns>
|
||||
public override IEnumerable<SubscriptionRequest> GetSubscriptionRequests(Security security,
|
||||
DateTime currentTimeUtc,
|
||||
DateTime maximumEndTimeUtc,
|
||||
ISubscriptionDataConfigService subscriptionService)
|
||||
{
|
||||
List<SubscriptionDataConfig> result;
|
||||
lock (_lock)
|
||||
{
|
||||
result = _subscriptionDataConfigs.Where(x => x.Symbol == security.Symbol).ToList();
|
||||
if (!result.Any())
|
||||
{
|
||||
result = _pendingRemovedConfigs.Where(x => x.Symbol == security.Symbol).ToList();
|
||||
if (result.Any())
|
||||
{
|
||||
_pendingRemovedConfigs.RemoveWhere(x => x.Symbol == security.Symbol);
|
||||
}
|
||||
else
|
||||
{
|
||||
result = base.GetSubscriptionRequests(security, currentTimeUtc, maximumEndTimeUtc, subscriptionService).Select(x => x.Configuration).ToList();
|
||||
// we create subscription data configs ourselves, add the configs
|
||||
_subscriptionDataConfigs.UnionWith(result);
|
||||
}
|
||||
}
|
||||
}
|
||||
return result.Select(config => new SubscriptionRequest(isUniverseSubscription: false,
|
||||
universe: this,
|
||||
security: security,
|
||||
configuration: config,
|
||||
startTimeUtc: currentTimeUtc,
|
||||
endTimeUtc: maximumEndTimeUtc));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tries to remove the specified security from the universe.
|
||||
/// </summary>
|
||||
/// <param name="utcTime">The current utc time</param>
|
||||
/// <param name="security">The security to be removed</param>
|
||||
/// <returns>True if the security was successfully removed, false if
|
||||
/// we're not allowed to remove or if the security didn't exist</returns>
|
||||
internal override bool RemoveMember(DateTime utcTime, Security security)
|
||||
{
|
||||
if (base.RemoveMember(utcTime, security))
|
||||
{
|
||||
RemoveAndKeepTrack(security.Symbol);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private bool RemoveAndKeepTrack(Symbol symbol)
|
||||
{
|
||||
lock (_lock)
|
||||
{
|
||||
var toBeRemoved = _subscriptionDataConfigs.Where(x => x.Symbol == symbol).ToList();
|
||||
var removedSymbol = _symbols.Remove(symbol);
|
||||
|
||||
if (removedSymbol || toBeRemoved.Any())
|
||||
{
|
||||
_subscriptionDataConfigs.RemoveWhere(x => x.Symbol == symbol);
|
||||
_pendingRemovedConfigs.UnionWith(toBeRemoved);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user