chore: import upstream snapshot with attribution
This commit is contained in:
@@ -0,0 +1,100 @@
|
||||
/*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
namespace QuantConnect.Data.Auxiliary
|
||||
{
|
||||
/// <summary>
|
||||
/// Unique definition key for a collection of auxiliary data for a Market and SecurityType
|
||||
/// </summary>
|
||||
public class AuxiliaryDataKey
|
||||
{
|
||||
/// <summary>
|
||||
/// USA equities market corporate actions key definition
|
||||
/// </summary>
|
||||
public static AuxiliaryDataKey EquityUsa { get; } = new (QuantConnect.Market.USA, SecurityType.Equity);
|
||||
|
||||
/// <summary>
|
||||
/// The market associated with these corporate actions
|
||||
/// </summary>
|
||||
public string Market { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The associated security type
|
||||
/// </summary>
|
||||
public SecurityType SecurityType { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new instance
|
||||
/// </summary>
|
||||
public AuxiliaryDataKey(string market, SecurityType securityType)
|
||||
{
|
||||
Market = market;
|
||||
SecurityType = securityType;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Serves as a hash function for a particular type.
|
||||
/// </summary>
|
||||
public override int GetHashCode()
|
||||
{
|
||||
unchecked
|
||||
{
|
||||
var hashCode = Market.GetHashCode();
|
||||
return (hashCode*397) ^ SecurityType.GetHashCode();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether the specified <see cref="T:System.Object"/> is equal to the current <see cref="T:System.Object"/>.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// true if the specified object is equal to the current object; otherwise, false.
|
||||
/// </returns>
|
||||
/// <param name="obj">The object to compare with the current object. </param><filterpriority>2</filterpriority>
|
||||
public override bool Equals(object? obj)
|
||||
{
|
||||
if (ReferenceEquals(null, obj)) return false;
|
||||
if (obj.GetType() != GetType()) return false;
|
||||
|
||||
var other = (AuxiliaryDataKey)obj;
|
||||
|
||||
return other.Market == Market
|
||||
&& other.SecurityType == SecurityType;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a string containing the market and security type
|
||||
/// </summary>
|
||||
public override string ToString()
|
||||
{
|
||||
return $"{Market}:{SecurityType}";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Helper method to create a new instance from a Symbol
|
||||
/// </summary>
|
||||
public static AuxiliaryDataKey Create(Symbol symbol) => Create(symbol.HasUnderlying ? symbol.Underlying.ID : symbol.ID);
|
||||
|
||||
/// <summary>
|
||||
/// Helper method to create a new instance from a SecurityIdentifier
|
||||
/// </summary>
|
||||
public static AuxiliaryDataKey Create(SecurityIdentifier securityIdentifier)
|
||||
{
|
||||
securityIdentifier = securityIdentifier.HasUnderlying ? securityIdentifier.Underlying : securityIdentifier;
|
||||
return new AuxiliaryDataKey(securityIdentifier.Market, securityIdentifier.SecurityType);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,274 @@
|
||||
/*
|
||||
* 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.Logging;
|
||||
using QuantConnect.Securities;
|
||||
using QuantConnect.Data.Market;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace QuantConnect.Data.Auxiliary
|
||||
{
|
||||
/// <summary>
|
||||
/// Corporate related factor provider. Factors based on splits and dividends
|
||||
/// </summary>
|
||||
public class CorporateFactorProvider : FactorFile<CorporateFactorRow>
|
||||
{
|
||||
/// <summary>
|
||||
///Creates a new instance
|
||||
/// </summary>
|
||||
public CorporateFactorProvider(string permtick, IEnumerable<CorporateFactorRow> data, DateTime? factorFileMinimumDate = null) : base(permtick, data, factorFileMinimumDate)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the price scale factor that includes dividend and split adjustments for the specified search date
|
||||
/// </summary>
|
||||
public override decimal GetPriceFactor(DateTime searchDate, DataNormalizationMode dataNormalizationMode, DataMappingMode? dataMappingMode = null, uint contractOffset = 0)
|
||||
{
|
||||
if (dataNormalizationMode == DataNormalizationMode.Raw)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
var factor = 1m;
|
||||
|
||||
for (var i = 0; i < ReversedFactorFileDates.Count; i++)
|
||||
{
|
||||
var factorDate = ReversedFactorFileDates[i];
|
||||
if (factorDate.Date < searchDate.Date)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
var factorFileRow = SortedFactorFileData[factorDate];
|
||||
switch (dataNormalizationMode)
|
||||
{
|
||||
case DataNormalizationMode.TotalReturn:
|
||||
case DataNormalizationMode.SplitAdjusted:
|
||||
factor = factorFileRow.First().SplitFactor;
|
||||
break;
|
||||
case DataNormalizationMode.Adjusted:
|
||||
case DataNormalizationMode.ScaledRaw:
|
||||
factor = factorFileRow.First().PriceScaleFactor;
|
||||
break;
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException();
|
||||
}
|
||||
}
|
||||
|
||||
return factor;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets price and split factors to be applied at the specified date
|
||||
/// </summary>
|
||||
public CorporateFactorRow GetScalingFactors(DateTime searchDate)
|
||||
{
|
||||
var factors = new CorporateFactorRow(searchDate, 1m, 1m, 0m);
|
||||
|
||||
// Iterate backwards to find the most recent factors
|
||||
foreach (var splitDate in ReversedFactorFileDates)
|
||||
{
|
||||
if (splitDate.Date < searchDate.Date) break;
|
||||
factors = SortedFactorFileData[splitDate][0];
|
||||
}
|
||||
|
||||
return factors;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if the specified date is the last trading day before a dividend event
|
||||
/// is to be fired
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// NOTE: The dividend event in the algorithm should be fired at the end or AFTER
|
||||
/// this date. This is the date in the file that a factor is applied, so for example,
|
||||
/// MSFT has a 31 cent dividend on 2015.02.17, but in the factor file the factor is applied
|
||||
/// to 2015.02.13, which is the first trading day BEFORE the actual effective date.
|
||||
/// </remarks>
|
||||
/// <param name="date">The date to check the factor file for a dividend event</param>
|
||||
/// <param name="priceFactorRatio">When this function returns true, this value will be populated
|
||||
/// with the price factor ratio required to scale the closing value (pf_i/pf_i+1)</param>
|
||||
/// <param name="referencePrice">When this function returns true, this value will be populated
|
||||
/// with the reference raw price, which is the close of the provided date</param>
|
||||
public bool HasDividendEventOnNextTradingDay(DateTime date, out decimal priceFactorRatio, out decimal referencePrice)
|
||||
{
|
||||
priceFactorRatio = 0;
|
||||
referencePrice = 0;
|
||||
var index = SortedFactorFileData.IndexOfKey(date);
|
||||
if (index > -1 && index < SortedFactorFileData.Count - 1)
|
||||
{
|
||||
// grab the next key to ensure it's a dividend event
|
||||
var thisRow = SortedFactorFileData.Values[index].First();
|
||||
var nextRow = SortedFactorFileData.Values[index + 1].First();
|
||||
|
||||
// if the price factors have changed then it's a dividend event
|
||||
if (thisRow.PriceFactor != nextRow.PriceFactor)
|
||||
{
|
||||
priceFactorRatio = thisRow.PriceFactor / nextRow.PriceFactor;
|
||||
referencePrice = thisRow.ReferencePrice;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if the specified date is the last trading day before a split event
|
||||
/// is to be fired
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// NOTE: The split event in the algorithm should be fired at the end or AFTER this
|
||||
/// date. This is the date in the file that a factor is applied, so for example MSFT
|
||||
/// has a split on 1999.03.29, but in the factor file the split factor is applied on
|
||||
/// 1999.03.26, which is the first trading day BEFORE the actual split date.
|
||||
/// </remarks>
|
||||
/// <param name="date">The date to check the factor file for a split event</param>
|
||||
/// <param name="splitFactor">When this function returns true, this value will be populated
|
||||
/// with the split factor ratio required to scale the closing value</param>
|
||||
/// <param name="referencePrice">When this function returns true, this value will be populated
|
||||
/// with the reference raw price, which is the close of the provided date</param>
|
||||
public bool HasSplitEventOnNextTradingDay(DateTime date, out decimal splitFactor, out decimal referencePrice)
|
||||
{
|
||||
splitFactor = 1;
|
||||
referencePrice = 0;
|
||||
var index = SortedFactorFileData.IndexOfKey(date);
|
||||
if (index > -1 && index < SortedFactorFileData.Count - 1)
|
||||
{
|
||||
// grab the next key to ensure it's a split event
|
||||
var thisRow = SortedFactorFileData.Values[index].First();
|
||||
var nextRow = SortedFactorFileData.Values[index + 1].First();
|
||||
|
||||
// if the split factors have changed then it's a split event
|
||||
if (thisRow.SplitFactor != nextRow.SplitFactor)
|
||||
{
|
||||
splitFactor = thisRow.SplitFactor / nextRow.SplitFactor;
|
||||
referencePrice = thisRow.ReferencePrice;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets all of the splits and dividends represented by this factor file
|
||||
/// </summary>
|
||||
/// <param name="symbol">The symbol to ues for the dividend and split objects</param>
|
||||
/// <param name="exchangeHours">Exchange hours used for resolving the previous trading day</param>
|
||||
/// <param name="decimalPlaces">The number of decimal places to round the dividend's distribution to, defaulting to 2</param>
|
||||
/// <returns>All splits and dividends represented by this factor file in chronological order</returns>
|
||||
public List<BaseData> GetSplitsAndDividends(Symbol symbol, SecurityExchangeHours exchangeHours, int decimalPlaces = 2)
|
||||
{
|
||||
var dividendsAndSplits = new List<BaseData>();
|
||||
if (SortedFactorFileData.Count == 0)
|
||||
{
|
||||
Log.Trace($"{symbol} has no factors!");
|
||||
return dividendsAndSplits;
|
||||
}
|
||||
|
||||
var futureFactorFileRow = SortedFactorFileData.Last().Value.First();
|
||||
for (var i = SortedFactorFileData.Count - 2; i >= 0; i--)
|
||||
{
|
||||
var row = SortedFactorFileData.Values[i].First();
|
||||
var dividend = row.GetDividend(futureFactorFileRow, symbol, exchangeHours, decimalPlaces);
|
||||
if (dividend.Distribution != 0m)
|
||||
{
|
||||
dividendsAndSplits.Add(dividend);
|
||||
}
|
||||
|
||||
var split = row.GetSplit(futureFactorFileRow, symbol, exchangeHours);
|
||||
if (split.SplitFactor != 1m)
|
||||
{
|
||||
dividendsAndSplits.Add(split);
|
||||
}
|
||||
|
||||
futureFactorFileRow = row;
|
||||
}
|
||||
|
||||
return dividendsAndSplits.OrderBy(d => d.Time.Date).ToList();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new factor file with the specified data applied.
|
||||
/// Only <see cref="Dividend"/> and <see cref="Split"/> data types
|
||||
/// will be used.
|
||||
/// </summary>
|
||||
/// <param name="data">The data to apply</param>
|
||||
/// <param name="exchangeHours">Exchange hours used for resolving the previous trading day</param>
|
||||
/// <returns>A new factor file that incorporates the specified dividend</returns>
|
||||
public CorporateFactorProvider Apply(List<BaseData> data, SecurityExchangeHours exchangeHours)
|
||||
{
|
||||
if (data.Count == 0)
|
||||
{
|
||||
return this;
|
||||
}
|
||||
|
||||
var factorFileRows = new List<CorporateFactorRow>();
|
||||
var firstEntry = SortedFactorFileData.First().Value.First();
|
||||
var lastEntry = SortedFactorFileData.Last().Value.First();
|
||||
factorFileRows.Add(lastEntry);
|
||||
|
||||
var splitsAndDividends = GetSplitsAndDividends(data[0].Symbol, exchangeHours);
|
||||
|
||||
var combinedData = splitsAndDividends.Concat(data)
|
||||
.DistinctBy(e => $"{e.GetType().Name}{e.Time.ToStringInvariant(DateFormat.EightCharacter)}")
|
||||
.OrderByDescending(d => d.Time.Date);
|
||||
|
||||
foreach (var datum in combinedData)
|
||||
{
|
||||
CorporateFactorRow nextEntry = null;
|
||||
var split = datum as Split;
|
||||
var dividend = datum as Dividend;
|
||||
if (dividend != null)
|
||||
{
|
||||
nextEntry = lastEntry.Apply(dividend, exchangeHours);
|
||||
lastEntry = nextEntry;
|
||||
}
|
||||
else if (split != null)
|
||||
{
|
||||
nextEntry = lastEntry.Apply(split, exchangeHours);
|
||||
lastEntry = nextEntry;
|
||||
}
|
||||
|
||||
if (nextEntry != null)
|
||||
{
|
||||
// overwrite the latest entry -- this handles splits/dividends on the same date
|
||||
if (nextEntry.Date == factorFileRows.Last().Date)
|
||||
{
|
||||
factorFileRows[factorFileRows.Count - 1] = nextEntry;
|
||||
}
|
||||
else
|
||||
{
|
||||
factorFileRows.Add(nextEntry);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var firstFactorFileRow = new CorporateFactorRow(firstEntry.Date, factorFileRows.Last().PriceFactor, factorFileRows.Last().SplitFactor, firstEntry.ReferencePrice == 0 ? 0 : firstEntry.ReferencePrice);
|
||||
var existing = factorFileRows.FindIndex(row => row.Date == firstFactorFileRow.Date);
|
||||
if (existing == -1)
|
||||
{
|
||||
// only add it if not present
|
||||
factorFileRows.Add(firstFactorFileRow);
|
||||
}
|
||||
|
||||
return new CorporateFactorProvider(Permtick, factorFileRows, FactorFileMinimumDate);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,319 @@
|
||||
/*
|
||||
* 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;
|
||||
using QuantConnect.Securities;
|
||||
using QuantConnect.Data.Market;
|
||||
using System.Collections.Generic;
|
||||
using static QuantConnect.StringExtensions;
|
||||
|
||||
namespace QuantConnect.Data.Auxiliary
|
||||
{
|
||||
/// <summary>
|
||||
/// Defines a single row in a factor_factor file. This is a csv file ordered as {date, price factor, split factor, reference price}
|
||||
/// </summary>
|
||||
public class CorporateFactorRow : IFactorRow
|
||||
{
|
||||
private decimal _splitFactor;
|
||||
private decimal _priceFactor;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the date associated with this data
|
||||
/// </summary>
|
||||
public DateTime Date { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the price factor associated with this data
|
||||
/// </summary>
|
||||
public decimal PriceFactor
|
||||
{
|
||||
get
|
||||
{
|
||||
return _priceFactor;
|
||||
|
||||
}
|
||||
set
|
||||
{
|
||||
_priceFactor = value;
|
||||
UpdatePriceScaleFactor();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the split factor associated with the date
|
||||
/// </summary>
|
||||
public decimal SplitFactor
|
||||
{
|
||||
get
|
||||
{
|
||||
return _splitFactor;
|
||||
}
|
||||
set
|
||||
{
|
||||
_splitFactor = value;
|
||||
UpdatePriceScaleFactor();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the combined factor used to create adjusted prices from raw prices
|
||||
/// </summary>
|
||||
public decimal PriceScaleFactor { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the raw closing value from the trading date before the updated factor takes effect
|
||||
/// </summary>
|
||||
public decimal ReferencePrice { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="CorporateFactorRow"/> class
|
||||
/// </summary>
|
||||
public CorporateFactorRow(DateTime date, decimal priceFactor, decimal splitFactor, decimal referencePrice = 0)
|
||||
{
|
||||
Date = date;
|
||||
ReferencePrice = referencePrice;
|
||||
PriceFactor = priceFactor;
|
||||
SplitFactor = splitFactor;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Parses the lines as factor files rows while properly handling inf entries
|
||||
/// </summary>
|
||||
/// <param name="lines">The lines from the factor file to be parsed</param>
|
||||
/// <param name="factorFileMinimumDate">The minimum date from the factor file</param>
|
||||
/// <returns>An enumerable of factor file rows</returns>
|
||||
public static List<CorporateFactorRow> Parse(IEnumerable<string> lines, out DateTime? factorFileMinimumDate)
|
||||
{
|
||||
factorFileMinimumDate = null;
|
||||
|
||||
var rows = new List<CorporateFactorRow>();
|
||||
|
||||
// parse factor file lines
|
||||
foreach (var line in lines)
|
||||
{
|
||||
// Exponential notation is treated as inf is because of the loss of precision. In
|
||||
// all cases, the significant part has fewer decimals than the needed for a correct
|
||||
// representation, E.g., 1.6e+6 when the correct factor is 1562500.
|
||||
if (line.Contains("inf") || line.Contains("e+"))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var row = Parse(line);
|
||||
|
||||
// ignore zero factor rows
|
||||
if (row.PriceScaleFactor > 0)
|
||||
{
|
||||
rows.Add(row);
|
||||
}
|
||||
}
|
||||
|
||||
if (rows.Count > 0)
|
||||
{
|
||||
factorFileMinimumDate = rows.Min(ffr => ffr.Date).AddDays(-1);
|
||||
}
|
||||
|
||||
return rows;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Applies the dividend to this factor file row.
|
||||
/// This dividend date must be on or before the factor
|
||||
/// file row date
|
||||
/// </summary>
|
||||
/// <param name="dividend">The dividend to apply with reference price and distribution specified</param>
|
||||
/// <param name="exchangeHours">Exchange hours used for resolving the previous trading day</param>
|
||||
/// <returns>A new factor file row that applies the dividend to this row's factors</returns>
|
||||
public CorporateFactorRow Apply(Dividend dividend, SecurityExchangeHours exchangeHours)
|
||||
{
|
||||
if (dividend.ReferencePrice == 0m)
|
||||
{
|
||||
throw new ArgumentException("Unable to apply dividend with reference price of zero.");
|
||||
}
|
||||
|
||||
var previousTradingDay = exchangeHours.GetPreviousTradingDay(dividend.Time);
|
||||
|
||||
// this instance must be chronologically at or in front of the dividend
|
||||
// this is because the factors are defined working from current to past
|
||||
if (Date < previousTradingDay)
|
||||
{
|
||||
throw new ArgumentException(Invariant(
|
||||
$"Factor file row date '{Date:yyy-MM-dd}' is before dividend previous trading date '{previousTradingDay.Date:yyyy-MM-dd}'."
|
||||
));
|
||||
}
|
||||
|
||||
// pfi - new price factor pf(i+1) - this price factor D - distribution C - previous close
|
||||
// pfi = pf(i+1) * (C-D)/C
|
||||
var priceFactor = PriceFactor * (dividend.ReferencePrice - dividend.Distribution) / dividend.ReferencePrice;
|
||||
|
||||
return new CorporateFactorRow(
|
||||
previousTradingDay,
|
||||
priceFactor,
|
||||
SplitFactor,
|
||||
dividend.ReferencePrice
|
||||
);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Applies the split to this factor file row.
|
||||
/// This split date must be on or before the factor
|
||||
/// file row date
|
||||
/// </summary>
|
||||
/// <param name="split">The split to apply with reference price and split factor specified</param>
|
||||
/// <param name="exchangeHours">Exchange hours used for resolving the previous trading day</param>
|
||||
/// <returns>A new factor file row that applies the split to this row's factors</returns>
|
||||
public CorporateFactorRow Apply(Split split, SecurityExchangeHours exchangeHours)
|
||||
{
|
||||
if (split.Type == SplitType.Warning)
|
||||
{
|
||||
throw new ArgumentException("Unable to apply split with type warning. Only actual splits may be applied");
|
||||
}
|
||||
|
||||
if (split.ReferencePrice == 0m)
|
||||
{
|
||||
throw new ArgumentException("Unable to apply split with reference price of zero.");
|
||||
}
|
||||
|
||||
var previousTradingDay = exchangeHours.GetPreviousTradingDay(split.Time);
|
||||
|
||||
// this instance must be chronologically at or in front of the split
|
||||
// this is because the factors are defined working from current to past
|
||||
if (Date < previousTradingDay)
|
||||
{
|
||||
throw new ArgumentException(Invariant(
|
||||
$"Factor file row date '{Date:yyy-MM-dd}' is before split date '{split.Time.Date:yyyy-MM-dd}'."
|
||||
));
|
||||
}
|
||||
|
||||
return new CorporateFactorRow(
|
||||
previousTradingDay,
|
||||
PriceFactor,
|
||||
SplitFactor * split.SplitFactor,
|
||||
split.ReferencePrice
|
||||
);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new dividend from this factor file row and the one chronologically in front of it
|
||||
/// This dividend may have a distribution of zero if this row doesn't represent a dividend
|
||||
/// </summary>
|
||||
/// <param name="nextCorporateFactorRow">The next factor file row in time</param>
|
||||
/// <param name="symbol">The symbol to use for the dividend</param>
|
||||
/// <param name="exchangeHours">Exchange hours used for resolving the previous trading day</param>
|
||||
/// <param name="decimalPlaces">The number of decimal places to round the dividend's distribution to, defaulting to 2</param>
|
||||
/// <returns>A new dividend instance</returns>
|
||||
public Dividend GetDividend(CorporateFactorRow nextCorporateFactorRow, Symbol symbol, SecurityExchangeHours exchangeHours, int decimalPlaces=2)
|
||||
{
|
||||
if (nextCorporateFactorRow.PriceFactor == 0m)
|
||||
{
|
||||
throw new InvalidOperationException(Invariant(
|
||||
$"Unable to resolve dividend for '{symbol.ID}' at {Date:yyyy-MM-dd}. Price factor is zero."
|
||||
));
|
||||
}
|
||||
|
||||
// find previous trading day
|
||||
var previousTradingDay = exchangeHours.GetNextTradingDay(Date);
|
||||
|
||||
return Dividend.Create(
|
||||
symbol,
|
||||
previousTradingDay,
|
||||
ReferencePrice,
|
||||
PriceFactor / nextCorporateFactorRow.PriceFactor,
|
||||
decimalPlaces
|
||||
);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new split from this factor file row and the one chronologically in front of it
|
||||
/// This split may have a split factor of one if this row doesn't represent a split
|
||||
/// </summary>
|
||||
/// <param name="nextCorporateFactorRow">The next factor file row in time</param>
|
||||
/// <param name="symbol">The symbol to use for the split</param>
|
||||
/// <param name="exchangeHours">Exchange hours used for resolving the previous trading day</param>
|
||||
/// <returns>A new split instance</returns>
|
||||
public Split GetSplit(CorporateFactorRow nextCorporateFactorRow, Symbol symbol, SecurityExchangeHours exchangeHours)
|
||||
{
|
||||
if (nextCorporateFactorRow.SplitFactor == 0m)
|
||||
{
|
||||
throw new InvalidOperationException(Invariant(
|
||||
$"Unable to resolve split for '{symbol.ID}' at {Date:yyyy-MM-dd}. Split factor is zero."
|
||||
));
|
||||
}
|
||||
|
||||
// find previous trading day
|
||||
var previousTradingDay = exchangeHours.GetNextTradingDay(Date);
|
||||
|
||||
return new Split(
|
||||
symbol,
|
||||
previousTradingDay,
|
||||
ReferencePrice,
|
||||
SplitFactor / nextCorporateFactorRow.SplitFactor,
|
||||
SplitType.SplitOccurred
|
||||
);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Parses the specified line as a factor file row
|
||||
/// </summary>
|
||||
private static CorporateFactorRow Parse(string line)
|
||||
{
|
||||
var csv = line.Split(',');
|
||||
return new CorporateFactorRow(
|
||||
QuantConnect.Parse.DateTimeExact(csv[0], DateFormat.EightCharacter, DateTimeStyles.None),
|
||||
QuantConnect.Parse.Decimal(csv[1]),
|
||||
QuantConnect.Parse.Decimal(csv[2]),
|
||||
csv.Length > 3 ? QuantConnect.Parse.Decimal(csv[3]) : 0m
|
||||
);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes factor file row into it's file format
|
||||
/// </summary>
|
||||
/// <remarks>CSV formatted</remarks>
|
||||
public string GetFileFormat(string source = null)
|
||||
{
|
||||
source = source == null ? "" : $",{source}";
|
||||
return $"{Date.ToStringInvariant(DateFormat.EightCharacter)}," +
|
||||
Invariant($"{Math.Round(PriceFactor, 7)},") +
|
||||
Invariant($"{Math.Round(SplitFactor, 8)},") +
|
||||
Invariant($"{Math.Round(ReferencePrice, 4).Normalize()}") +
|
||||
$"{source}";
|
||||
}
|
||||
|
||||
/// <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()
|
||||
{
|
||||
return Invariant($"{Date:yyyy-MM-dd}: {PriceScaleFactor:0.0000} {SplitFactor:0.0000}");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// For performance we update <see cref="PriceScaleFactor"/> when underlying
|
||||
/// values are updated to avoid decimal multiplication on each get operation.
|
||||
/// </summary>
|
||||
private void UpdatePriceScaleFactor()
|
||||
{
|
||||
PriceScaleFactor = _priceFactor * _splitFactor;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,143 @@
|
||||
/*
|
||||
* 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.Util;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace QuantConnect.Data.Auxiliary
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents an entire factor file for a specified symbol
|
||||
/// </summary>
|
||||
public abstract class FactorFile<T> : IFactorProvider
|
||||
where T : IFactorRow
|
||||
{
|
||||
/// <summary>
|
||||
/// Keeping a reversed version is more performant that reversing it each time we need it
|
||||
/// </summary>
|
||||
protected List<DateTime> ReversedFactorFileDates { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The factor file data rows sorted by date
|
||||
/// </summary>
|
||||
public SortedList<DateTime, List<T>> SortedFactorFileData { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The minimum tradeable date for the symbol
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Some factor files have INF split values, indicating that the stock has so many splits
|
||||
/// that prices can't be calculated with correct numerical precision.
|
||||
/// To allow backtesting these symbols, we need to move the starting date
|
||||
/// forward when reading the data.
|
||||
/// Known symbols: GBSN, JUNI, NEWL
|
||||
/// </remarks>
|
||||
public DateTime? FactorFileMinimumDate { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the most recent factor change in the factor file
|
||||
/// </summary>
|
||||
public DateTime MostRecentFactorChange => ReversedFactorFileDates
|
||||
.FirstOrDefault(time => time != Time.EndOfTime);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the symbol this factor file represents
|
||||
/// </summary>
|
||||
public string Permtick { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="FactorFile{T}"/> class.
|
||||
/// </summary>
|
||||
protected FactorFile(string permtick, IEnumerable<T> data, DateTime? factorFileMinimumDate = null)
|
||||
{
|
||||
Permtick = permtick.LazyToUpper();
|
||||
|
||||
SortedFactorFileData = new SortedList<DateTime, List<T>>();
|
||||
foreach (var row in data)
|
||||
{
|
||||
if (!SortedFactorFileData.TryGetValue(row.Date, out var factorFileRows))
|
||||
{
|
||||
SortedFactorFileData[row.Date] = factorFileRows = new List<T>();
|
||||
}
|
||||
|
||||
factorFileRows.Add(row);
|
||||
}
|
||||
|
||||
ReversedFactorFileDates = new List<DateTime>(SortedFactorFileData.Count);
|
||||
foreach (var time in SortedFactorFileData.Keys.Reverse())
|
||||
{
|
||||
ReversedFactorFileDates.Add(time);
|
||||
}
|
||||
|
||||
FactorFileMinimumDate = factorFileMinimumDate;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the price scale factor for the specified search date
|
||||
/// </summary>
|
||||
public abstract decimal GetPriceFactor(
|
||||
DateTime searchDate,
|
||||
DataNormalizationMode dataNormalizationMode,
|
||||
DataMappingMode? dataMappingMode = null,
|
||||
uint contractOffset = 0
|
||||
);
|
||||
|
||||
/// <summary>
|
||||
/// Writes this factor file data to an enumerable of csv lines
|
||||
/// </summary>
|
||||
/// <returns>An enumerable of lines representing this factor file</returns>
|
||||
public IEnumerable<string> GetFileFormat()
|
||||
{
|
||||
return SortedFactorFileData.SelectMany(kvp => kvp.Value.Select(row => row.GetFileFormat()));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write the factor file to the correct place in the default Data folder
|
||||
/// </summary>
|
||||
/// <param name="symbol">The symbol this factor file represents</param>
|
||||
public void WriteToFile(Symbol symbol)
|
||||
{
|
||||
var filePath = LeanData.GenerateRelativeFactorFilePath(symbol);
|
||||
File.WriteAllLines(filePath, GetFileFormat());
|
||||
}
|
||||
|
||||
/// <summary>Returns an enumerator that iterates through the collection.</summary>
|
||||
/// <returns>A <see cref="T:System.Collections.Generic.IEnumerator`1" /> that can be used to iterate through the collection.</returns>
|
||||
/// <filterpriority>1</filterpriority>
|
||||
public IEnumerator<IFactorRow> GetEnumerator()
|
||||
{
|
||||
foreach (var kvp in SortedFactorFileData)
|
||||
{
|
||||
foreach (var factorRow in kvp.Value)
|
||||
{
|
||||
yield return factorRow;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Returns an enumerator that iterates through a collection.</summary>
|
||||
/// <returns>An <see cref="T:System.Collections.IEnumerator" /> object that can be used to iterate through the collection.</returns>
|
||||
/// <filterpriority>2</filterpriority>
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
{
|
||||
return GetEnumerator();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
/*
|
||||
* 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 System.Collections.Generic;
|
||||
using static QuantConnect.StringExtensions;
|
||||
|
||||
namespace QuantConnect.Data.Auxiliary
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides methods for reading factor file zips
|
||||
/// </summary>
|
||||
public static class FactorFileZipHelper
|
||||
{
|
||||
/// <summary>
|
||||
/// Constructs the factor file path for the specified market and security type
|
||||
/// </summary>
|
||||
/// <param name="market">The market this symbol belongs to</param>
|
||||
/// <param name="securityType">The security type</param>
|
||||
/// <returns>The relative file path</returns>
|
||||
public static string GetRelativeFactorFilePath(string market, SecurityType securityType)
|
||||
{
|
||||
return Invariant($"{securityType.SecurityTypeToLower()}/{market}/factor_files");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the factor file zip filename for the specified date
|
||||
/// </summary>
|
||||
public static string GetFactorFileZipFileName(string market, DateTime date, SecurityType securityType)
|
||||
{
|
||||
return Path.Combine(Globals.DataFolder, GetRelativeFactorFilePath(market, securityType), $"factor_files_{date:yyyyMMdd}.zip");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads the zip bytes as text and parses as FactorFileRows to create FactorFiles
|
||||
/// </summary>
|
||||
public static IEnumerable<KeyValuePair<Symbol, IFactorProvider>> ReadFactorFileZip(Stream file, MapFileResolver mapFileResolver, string market, SecurityType securityType)
|
||||
{
|
||||
if (file == null || file.Length == 0)
|
||||
{
|
||||
return new Dictionary<Symbol, IFactorProvider>();
|
||||
}
|
||||
|
||||
var keyValuePairs = (
|
||||
from kvp in Compression.Unzip(file)
|
||||
let filename = kvp.Key
|
||||
let lines = kvp.Value
|
||||
let factorFile = PriceScalingExtensions.SafeRead(Path.GetFileNameWithoutExtension(filename), lines, securityType)
|
||||
let mapFile = mapFileResolver.GetByPermtick(factorFile.Permtick)
|
||||
where mapFile != null
|
||||
select new KeyValuePair<Symbol, IFactorProvider>(GetSymbol(mapFile, market, securityType), factorFile)
|
||||
);
|
||||
|
||||
return keyValuePairs;
|
||||
}
|
||||
|
||||
private static Symbol GetSymbol(MapFile mapFile, string market, SecurityType securityType)
|
||||
{
|
||||
SecurityIdentifier sid;
|
||||
switch (securityType)
|
||||
{
|
||||
case SecurityType.Equity:
|
||||
sid = SecurityIdentifier.GenerateEquity(mapFile.FirstDate, mapFile.FirstTicker, market);
|
||||
break;
|
||||
case SecurityType.Future:
|
||||
sid = SecurityIdentifier.GenerateFuture(SecurityIdentifier.DefaultDate, mapFile.Permtick, market);
|
||||
break;
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException(nameof(securityType), securityType, null);
|
||||
}
|
||||
return new Symbol(sid, mapFile.Permtick);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* 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.Auxiliary
|
||||
{
|
||||
/// <summary>
|
||||
/// Providers price scaling factors for a permanent tick
|
||||
/// </summary>
|
||||
public interface IFactorProvider : IEnumerable<IFactorRow>
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the symbol this factor file represents
|
||||
/// </summary>
|
||||
public string Permtick { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The minimum tradeable date for the symbol
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Some factor files have INF split values, indicating that the stock has so many splits
|
||||
/// that prices can't be calculated with correct numerical precision.
|
||||
/// To allow backtesting these symbols, we need to move the starting date
|
||||
/// forward when reading the data.
|
||||
/// Known symbols: GBSN, JUNI, NEWL
|
||||
/// </remarks>
|
||||
public DateTime? FactorFileMinimumDate { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the price factor for the specified search date
|
||||
/// </summary>
|
||||
decimal GetPriceFactor(DateTime searchDate, DataNormalizationMode dataNormalizationMode, DataMappingMode? dataMappingMode = null, uint contractOffset = 0);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
namespace QuantConnect.Data.Auxiliary
|
||||
{
|
||||
/// <summary>
|
||||
/// Factor row abstraction. <see cref="IFactorProvider"/>
|
||||
/// </summary>
|
||||
public interface IFactorRow
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the date associated with this data
|
||||
/// </summary>
|
||||
DateTime Date { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Writes factor file row into it's file format
|
||||
/// </summary>
|
||||
string GetFileFormat(string source = null);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,96 @@
|
||||
/*
|
||||
* 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.IO;
|
||||
using QuantConnect.Util;
|
||||
using QuantConnect.Interfaces;
|
||||
using System.Collections.Concurrent;
|
||||
|
||||
namespace QuantConnect.Data.Auxiliary
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides an implementation of <see cref="IFactorFileProvider"/> that searches the local disk
|
||||
/// </summary>
|
||||
public class LocalDiskFactorFileProvider : IFactorFileProvider
|
||||
{
|
||||
private IMapFileProvider _mapFileProvider;
|
||||
private IDataProvider _dataProvider;
|
||||
private readonly ConcurrentDictionary<Symbol, IFactorProvider> _cache;
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new instance of the <see cref="LocalDiskFactorFileProvider"/>
|
||||
/// </summary>
|
||||
public LocalDiskFactorFileProvider()
|
||||
{
|
||||
_cache = new ConcurrentDictionary<Symbol, IFactorProvider>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes our FactorFileProvider by supplying our mapFileProvider
|
||||
/// and dataProvider
|
||||
/// </summary>
|
||||
/// <param name="mapFileProvider">MapFileProvider to use</param>
|
||||
/// <param name="dataProvider">DataProvider to use</param>
|
||||
public void Initialize(IMapFileProvider mapFileProvider, IDataProvider dataProvider)
|
||||
{
|
||||
_mapFileProvider = mapFileProvider;
|
||||
_dataProvider = dataProvider;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a <see cref="FactorFile{T}"/> instance for the specified symbol, or null if not found
|
||||
/// </summary>
|
||||
/// <param name="symbol">The security's symbol whose factor file we seek</param>
|
||||
/// <returns>The resolved factor file, or null if not found</returns>
|
||||
public IFactorProvider Get(Symbol symbol)
|
||||
{
|
||||
symbol = symbol.GetFactorFileSymbol();
|
||||
IFactorProvider factorFile;
|
||||
if (_cache.TryGetValue(symbol, out factorFile))
|
||||
{
|
||||
return factorFile;
|
||||
}
|
||||
|
||||
// we first need to resolve the map file to get a permtick, that's how the factor files are stored
|
||||
var mapFileResolver = _mapFileProvider.Get(AuxiliaryDataKey.Create(symbol));
|
||||
if (mapFileResolver == null)
|
||||
{
|
||||
return GetFactorFile(symbol, symbol.Value);
|
||||
}
|
||||
|
||||
var mapFile = mapFileResolver.ResolveMapFile(symbol);
|
||||
if (mapFile.IsNullOrEmpty())
|
||||
{
|
||||
return GetFactorFile(symbol, symbol.Value);
|
||||
}
|
||||
|
||||
return GetFactorFile(symbol, mapFile.Permtick);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks that the factor file exists on disk, and if it does, loads it into memory
|
||||
/// </summary>
|
||||
private IFactorProvider GetFactorFile(Symbol symbol, string permtick)
|
||||
{
|
||||
var basePath = Globals.GetDataFolderPath(FactorFileZipHelper.GetRelativeFactorFilePath(symbol.ID.Market, symbol.SecurityType));
|
||||
var path = Path.Combine(basePath, permtick.ToLowerInvariant() + ".csv");
|
||||
|
||||
var factorFile = PriceScalingExtensions.SafeRead(permtick, _dataProvider.ReadLines(path), symbol.SecurityType);
|
||||
_cache.AddOrUpdate(symbol, factorFile, (s, c) => factorFile);
|
||||
return factorFile;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
/*
|
||||
* 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.IO;
|
||||
using System.Threading;
|
||||
using QuantConnect.Logging;
|
||||
using QuantConnect.Interfaces;
|
||||
using System.Collections.Concurrent;
|
||||
|
||||
namespace QuantConnect.Data.Auxiliary
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides a default implementation of <see cref="IMapFileProvider"/> that reads from
|
||||
/// the local disk
|
||||
/// </summary>
|
||||
public class LocalDiskMapFileProvider : IMapFileProvider
|
||||
{
|
||||
private static int _wroteTraceStatement;
|
||||
private readonly ConcurrentDictionary<AuxiliaryDataKey, MapFileResolver> _cache;
|
||||
private IDataProvider _dataProvider;
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new instance of the <see cref="LocalDiskFactorFileProvider"/>
|
||||
/// </summary>
|
||||
public LocalDiskMapFileProvider()
|
||||
{
|
||||
_cache = new ConcurrentDictionary<AuxiliaryDataKey, MapFileResolver>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes our MapFileProvider by supplying our dataProvider
|
||||
/// </summary>
|
||||
/// <param name="dataProvider">DataProvider to use</param>
|
||||
public void Initialize(IDataProvider dataProvider)
|
||||
{
|
||||
_dataProvider = dataProvider;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a <see cref="MapFileResolver"/> representing all the map
|
||||
/// files for the specified market
|
||||
/// </summary>
|
||||
/// <param name="auxiliaryDataKey">Key used to fetch a map file resolver. Specifying market and security type</param>
|
||||
/// <returns>A <see cref="MapFileRow"/> containing all map files for the specified market</returns>
|
||||
public MapFileResolver Get(AuxiliaryDataKey auxiliaryDataKey)
|
||||
{
|
||||
return _cache.GetOrAdd(auxiliaryDataKey, GetMapFileResolver);
|
||||
}
|
||||
|
||||
private MapFileResolver GetMapFileResolver(AuxiliaryDataKey key)
|
||||
{
|
||||
var securityType = key.SecurityType;
|
||||
var market = key.Market;
|
||||
|
||||
var mapFileDirectory = Globals.GetDataFolderPath(MapFile.GetRelativeMapFilePath(market, securityType));
|
||||
if (!Directory.Exists(mapFileDirectory))
|
||||
{
|
||||
// only write this message once per application instance
|
||||
if (Interlocked.CompareExchange(ref _wroteTraceStatement, 1, 0) == 0)
|
||||
{
|
||||
Log.Error($"LocalDiskMapFileProvider.GetMapFileResolver({market}): " +
|
||||
$"The specified directory does not exist: {mapFileDirectory}"
|
||||
);
|
||||
}
|
||||
return MapFileResolver.Empty;
|
||||
}
|
||||
return new MapFileResolver(MapFile.GetMapFiles(mapFileDirectory, market, securityType, _dataProvider));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,169 @@
|
||||
/*
|
||||
* 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.Logging;
|
||||
using System.Threading.Tasks;
|
||||
using QuantConnect.Interfaces;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace QuantConnect.Data.Auxiliary
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides an implementation of <see cref="IFactorFileProvider"/> that searches the local disk for a zip file containing all factor files
|
||||
/// </summary>
|
||||
public class LocalZipFactorFileProvider : IFactorFileProvider
|
||||
{
|
||||
private readonly object _lock;
|
||||
private IDataProvider _dataProvider;
|
||||
private IMapFileProvider _mapFileProvider;
|
||||
private Dictionary<AuxiliaryDataKey, bool> _seededMarket;
|
||||
private readonly Dictionary<Symbol, IFactorProvider> _factorFiles;
|
||||
|
||||
/// <summary>
|
||||
/// The cached refresh period for the factor files
|
||||
/// </summary>
|
||||
/// <remarks>Exposed for testing</remarks>
|
||||
protected virtual TimeSpan CacheRefreshPeriod
|
||||
{
|
||||
get
|
||||
{
|
||||
var dueTime = Time.GetNextLiveAuxiliaryDataDueTime();
|
||||
if (dueTime > TimeSpan.FromMinutes(10))
|
||||
{
|
||||
// Clear the cache before the auxiliary due time to avoid race conditions with consumers
|
||||
return dueTime - TimeSpan.FromMinutes(10);
|
||||
}
|
||||
return dueTime;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new instance of the <see cref="LocalZipFactorFileProvider"/> class.
|
||||
/// </summary>
|
||||
public LocalZipFactorFileProvider()
|
||||
{
|
||||
_factorFiles = new Dictionary<Symbol, IFactorProvider>();
|
||||
_seededMarket = new Dictionary<AuxiliaryDataKey, bool>();
|
||||
_lock = new object();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes our FactorFileProvider by supplying our mapFileProvider
|
||||
/// and dataProvider
|
||||
/// </summary>
|
||||
/// <param name="mapFileProvider">MapFileProvider to use</param>
|
||||
/// <param name="dataProvider">DataProvider to use</param>
|
||||
public void Initialize(IMapFileProvider mapFileProvider, IDataProvider dataProvider)
|
||||
{
|
||||
if (_mapFileProvider != null || _dataProvider != null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_mapFileProvider = mapFileProvider;
|
||||
_dataProvider = dataProvider;
|
||||
StartExpirationTask();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a <see cref="FactorFile{T}"/> instance for the specified symbol, or null if not found
|
||||
/// </summary>
|
||||
/// <param name="symbol">The security's symbol whose factor file we seek</param>
|
||||
/// <returns>The resolved factor file, or null if not found</returns>
|
||||
public IFactorProvider Get(Symbol symbol)
|
||||
{
|
||||
symbol = symbol.GetFactorFileSymbol();
|
||||
var key = AuxiliaryDataKey.Create(symbol);
|
||||
lock (_lock)
|
||||
{
|
||||
if (!_seededMarket.ContainsKey(key))
|
||||
{
|
||||
HydrateFactorFileFromLatestZip(key);
|
||||
_seededMarket[key] = true;
|
||||
}
|
||||
|
||||
IFactorProvider factorFile;
|
||||
if (!_factorFiles.TryGetValue(symbol, out factorFile))
|
||||
{
|
||||
// Could not find factor file for symbol
|
||||
Log.Error($"LocalZipFactorFileProvider.Get({symbol}): No factor file found.");
|
||||
_factorFiles[symbol] = factorFile = symbol.GetEmptyFactorFile();
|
||||
}
|
||||
return factorFile;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Helper method that will clear any cached factor files in a daily basis, this is useful for live trading
|
||||
/// </summary>
|
||||
protected virtual void StartExpirationTask()
|
||||
{
|
||||
lock (_lock)
|
||||
{
|
||||
// we clear the seeded markets so they are reloaded
|
||||
_seededMarket = new Dictionary<AuxiliaryDataKey, bool>();
|
||||
}
|
||||
_ = Task.Delay(CacheRefreshPeriod).ContinueWith(_ => StartExpirationTask());
|
||||
}
|
||||
|
||||
/// Hydrate the <see cref="_factorFiles"/> from the latest zipped factor file on disk
|
||||
private void HydrateFactorFileFromLatestZip(AuxiliaryDataKey key)
|
||||
{
|
||||
var market = key.Market;
|
||||
// start the search with yesterday, today's file will be available tomorrow
|
||||
var todayNewYork = DateTime.UtcNow.ConvertFromUtc(TimeZones.NewYork).Date;
|
||||
var date = todayNewYork.AddDays(-1);
|
||||
|
||||
var count = 0;
|
||||
|
||||
do
|
||||
{
|
||||
var factorFilePath = FactorFileZipHelper.GetFactorFileZipFileName(market, date, key.SecurityType);
|
||||
|
||||
// Fetch a stream for our zip from our data provider
|
||||
var stream = _dataProvider.Fetch(factorFilePath);
|
||||
|
||||
// If the file was found we can read the file
|
||||
if (stream != null)
|
||||
{
|
||||
var mapFileResolver = _mapFileProvider.Get(key);
|
||||
foreach (var keyValuePair in FactorFileZipHelper.ReadFactorFileZip(stream, mapFileResolver, market, key.SecurityType))
|
||||
{
|
||||
// we merge with existing, this will allow to hold multiple markets
|
||||
_factorFiles[keyValuePair.Key] = keyValuePair.Value;
|
||||
}
|
||||
stream.DisposeSafely();
|
||||
Log.Trace($"LocalZipFactorFileProvider.Get({market}): Fetched factor files for: {date.ToShortDateString()} NY");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Otherwise we will search back another day
|
||||
Log.Debug($"LocalZipFactorFileProvider.Get({market}): No factor file found for date {date.ToShortDateString()}");
|
||||
|
||||
// prevent infinite recursion if something is wrong
|
||||
if (count++ > 7)
|
||||
{
|
||||
throw new InvalidOperationException($"LocalZipFactorFileProvider.Get(): Could not find any factor files going all the way back to {date} for {market}");
|
||||
}
|
||||
|
||||
date = date.AddDays(-1);
|
||||
}
|
||||
while (true);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,148 @@
|
||||
/*
|
||||
* 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.Configuration;
|
||||
using QuantConnect.Util;
|
||||
using QuantConnect.Logging;
|
||||
using System.Globalization;
|
||||
using System.Threading.Tasks;
|
||||
using QuantConnect.Interfaces;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace QuantConnect.Data.Auxiliary
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides an implementation of <see cref="IMapFileProvider"/> that reads from a local zip file
|
||||
/// </summary>
|
||||
public class LocalZipMapFileProvider : IMapFileProvider
|
||||
{
|
||||
private readonly DateTime? _lookupDate;
|
||||
private Dictionary<AuxiliaryDataKey, MapFileResolver> _cache;
|
||||
private IDataProvider _dataProvider;
|
||||
private object _lock;
|
||||
|
||||
/// <summary>
|
||||
/// The cached refresh period for the map files
|
||||
/// </summary>
|
||||
/// <remarks>Exposed for testing</remarks>
|
||||
protected virtual TimeSpan CacheRefreshPeriod
|
||||
{
|
||||
get
|
||||
{
|
||||
var dueTime = Time.GetNextLiveAuxiliaryDataDueTime();
|
||||
if (dueTime > TimeSpan.FromMinutes(10))
|
||||
{
|
||||
// Clear the cache before the auxiliary due time to avoid race conditions with consumers
|
||||
return dueTime - TimeSpan.FromMinutes(10);
|
||||
}
|
||||
return dueTime;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new instance of the <see cref="LocalZipMapFileProvider"/>
|
||||
/// </summary>
|
||||
public LocalZipMapFileProvider()
|
||||
{
|
||||
_lock = new object();
|
||||
_cache = new Dictionary<AuxiliaryDataKey, MapFileResolver>();
|
||||
|
||||
var lookupDateConfig = Config.Get("map-file-provider-lookup-date");
|
||||
if (DateTime.TryParseExact(lookupDateConfig, "yyyyMMdd", CultureInfo.InvariantCulture, DateTimeStyles.None, out var lookupDate))
|
||||
{
|
||||
_lookupDate = lookupDate;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes our MapFileProvider by supplying our dataProvider
|
||||
/// </summary>
|
||||
/// <param name="dataProvider">DataProvider to use</param>
|
||||
public void Initialize(IDataProvider dataProvider)
|
||||
{
|
||||
if (_dataProvider != null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_dataProvider = dataProvider;
|
||||
StartExpirationTask();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a <see cref="MapFileResolver"/> representing all the map files for the specified market
|
||||
/// </summary>
|
||||
/// <param name="auxiliaryDataKey">Key used to fetch a map file resolver. Specifying market and security type</param>
|
||||
/// <returns>A <see cref="MapFileResolver"/> containing all map files for the specified market</returns>
|
||||
public MapFileResolver Get(AuxiliaryDataKey auxiliaryDataKey)
|
||||
{
|
||||
MapFileResolver result;
|
||||
// we use a lock so that only 1 thread loads the map file resolver while the rest wait
|
||||
// else we could have multiple threads loading the map file resolver at the same time!
|
||||
lock (_lock)
|
||||
{
|
||||
if (!_cache.TryGetValue(auxiliaryDataKey, out result))
|
||||
{
|
||||
_cache[auxiliaryDataKey] = result = GetMapFileResolver(auxiliaryDataKey);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Helper method that will clear any cached factor files in a daily basis, this is useful for live trading
|
||||
/// </summary>
|
||||
protected virtual void StartExpirationTask()
|
||||
{
|
||||
lock (_lock)
|
||||
{
|
||||
// we clear the seeded markets so they are reloaded
|
||||
_cache = new Dictionary<AuxiliaryDataKey, MapFileResolver>();
|
||||
}
|
||||
_ = Task.Delay(CacheRefreshPeriod).ContinueWith(_ => StartExpirationTask());
|
||||
}
|
||||
|
||||
private MapFileResolver GetMapFileResolver(AuxiliaryDataKey auxiliaryDataKey)
|
||||
{
|
||||
var market = auxiliaryDataKey.Market;
|
||||
var timestamp = DateTime.UtcNow.ConvertFromUtc(TimeZones.NewYork);
|
||||
var todayNewYork = timestamp.Date;
|
||||
// If a lookup date was provided, use it, otherwise use yesterday as the starting point for our search
|
||||
var yesterdayNewYork = _lookupDate ?? todayNewYork.AddDays(-1);
|
||||
// To prevent infinite recursion if something is wrong with the zip files, we look back a maximum of 30 days
|
||||
var endDate = yesterdayNewYork.AddDays(_lookupDate.HasValue ? 0 : -30);
|
||||
|
||||
// start the search with yesterday, today's file will be available tomorrow
|
||||
for (var date = yesterdayNewYork; date >= endDate; date = date.AddDays(-1))
|
||||
{
|
||||
var zipFileName = MapFileZipHelper.GetMapFileZipFileName(market, date, auxiliaryDataKey.SecurityType);
|
||||
|
||||
// Fetch a stream for our zip from our data provider
|
||||
var stream = _dataProvider.Fetch(zipFileName);
|
||||
|
||||
// If we didn't find a file, continue to the next date
|
||||
if (stream == null) continue;
|
||||
|
||||
Log.Trace($"LocalZipMapFileProvider.Get({market}): Fetched map files for: {date.ToShortDateString()} NY ({(date - todayNewYork).Days} days ago).");
|
||||
var result = new MapFileResolver(MapFileZipHelper.ReadMapFileZip(stream, market, auxiliaryDataKey.SecurityType));
|
||||
stream.DisposeSafely();
|
||||
return result;
|
||||
}
|
||||
|
||||
throw new InvalidOperationException($"LocalZipMapFileProvider couldn't find any map files going all the way back to {endDate.ToShortDateString()} for {market}");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,253 @@
|
||||
/*
|
||||
* 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.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using QuantConnect.Interfaces;
|
||||
using QuantConnect.Logging;
|
||||
using static QuantConnect.StringExtensions;
|
||||
|
||||
namespace QuantConnect.Data.Auxiliary
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents an entire map file for a specified symbol
|
||||
/// </summary>
|
||||
public class MapFile : IEnumerable<MapFileRow>
|
||||
{
|
||||
private readonly List<MapFileRow> _data;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the entity's unique symbol, i.e OIH.1
|
||||
/// </summary>
|
||||
public string Permtick { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the last date in the map file which is indicative of a delisting event
|
||||
/// </summary>
|
||||
public DateTime DelistingDate { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the first date in this map file
|
||||
/// </summary>
|
||||
public DateTime FirstDate { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the first ticker for the security represented by this map file
|
||||
/// </summary>
|
||||
public string FirstTicker { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="MapFile"/> class.
|
||||
/// </summary>
|
||||
public MapFile(string permtick, IEnumerable<MapFileRow> data)
|
||||
{
|
||||
if (string.IsNullOrEmpty(permtick))
|
||||
{
|
||||
throw new ArgumentNullException(nameof(permtick), "Provided ticker is null or empty");
|
||||
}
|
||||
|
||||
Permtick = permtick.LazyToUpper();
|
||||
_data = data.Distinct().OrderBy(row => row.Date).ToList();
|
||||
|
||||
// for performance we set first and last date on ctr
|
||||
if (_data.Count == 0)
|
||||
{
|
||||
FirstDate = Time.BeginningOfTime;
|
||||
DelistingDate = Time.EndOfTime;
|
||||
}
|
||||
else
|
||||
{
|
||||
FirstDate = _data[0].Date;
|
||||
DelistingDate = _data[_data.Count - 1].Date;
|
||||
}
|
||||
|
||||
var firstTicker = GetMappedSymbol(FirstDate, Permtick);
|
||||
if (char.IsDigit(firstTicker.Last()))
|
||||
{
|
||||
var dotIndex = firstTicker.LastIndexOf(".", StringComparison.Ordinal);
|
||||
if (dotIndex > 0)
|
||||
{
|
||||
int value;
|
||||
var number = firstTicker.AsSpan(dotIndex + 1);
|
||||
if (int.TryParse(number, out value))
|
||||
{
|
||||
firstTicker = firstTicker.Substring(0, dotIndex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
FirstTicker = firstTicker;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Memory overload search method for finding the mapped symbol for this date.
|
||||
/// </summary>
|
||||
/// <param name="searchDate">date for symbol we need to find.</param>
|
||||
/// <param name="defaultReturnValue">Default return value if search was got no result.</param>
|
||||
/// <param name="dataMappingMode">The mapping mode to use if any.</param>
|
||||
/// <returns>Symbol on this date.</returns>
|
||||
public string GetMappedSymbol(DateTime searchDate, string defaultReturnValue = "", DataMappingMode? dataMappingMode = null)
|
||||
{
|
||||
var mappedSymbol = defaultReturnValue;
|
||||
//Iterate backwards to find the most recent factor:
|
||||
for (var i = 0; i < _data.Count; i++)
|
||||
{
|
||||
var row = _data[i];
|
||||
if (row.Date < searchDate || row.DataMappingMode.HasValue && row.DataMappingMode != dataMappingMode)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
mappedSymbol = row.MappedSymbol;
|
||||
break;
|
||||
}
|
||||
return mappedSymbol;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines if there's data for the requested date
|
||||
/// </summary>
|
||||
public bool HasData(DateTime date)
|
||||
{
|
||||
// handle the case where we don't have any data
|
||||
if (_data.Count == 0)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (date < FirstDate || date > DelistingDate)
|
||||
{
|
||||
// don't even bother checking the disk if the map files state we don't have the data
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads and writes each <see cref="MapFileRow"/>
|
||||
/// </summary>
|
||||
/// <returns>Enumerable of csv lines</returns>
|
||||
public IEnumerable<string> ToCsvLines()
|
||||
{
|
||||
return _data.Select(mapRow => mapRow.ToCsv());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the map file to a CSV file
|
||||
/// </summary>
|
||||
/// <param name="market">The market to save the MapFile to</param>
|
||||
/// <param name="securityType">The map file security type</param>
|
||||
public void WriteToCsv(string market, SecurityType securityType)
|
||||
{
|
||||
var filePath = Path.Combine(Globals.DataFolder, GetRelativeMapFilePath(market, securityType), Permtick.ToLowerInvariant() + ".csv");
|
||||
var fileDir = Path.GetDirectoryName(filePath);
|
||||
|
||||
if (!Directory.Exists(fileDir))
|
||||
{
|
||||
Directory.CreateDirectory(fileDir);
|
||||
Log.Trace($"Created directory for map file: {fileDir}");
|
||||
}
|
||||
|
||||
File.WriteAllLines(filePath, ToCsvLines());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructs the map file path for the specified market and symbol
|
||||
/// </summary>
|
||||
/// <param name="market">The market this symbol belongs to</param>
|
||||
/// <param name="securityType">The map file security type</param>
|
||||
/// <returns>The file path to the requested map file</returns>
|
||||
public static string GetRelativeMapFilePath(string market, SecurityType securityType)
|
||||
{
|
||||
return Invariant($"{securityType.SecurityTypeToLower()}/{market}/map_files");
|
||||
}
|
||||
|
||||
#region Implementation of IEnumerable
|
||||
|
||||
/// <summary>
|
||||
/// Returns an enumerator that iterates through the collection.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// A <see cref="T:System.Collections.Generic.IEnumerator`1"/> that can be used to iterate through the collection.
|
||||
/// </returns>
|
||||
/// <filterpriority>1</filterpriority>
|
||||
public IEnumerator<MapFileRow> GetEnumerator()
|
||||
{
|
||||
return _data.GetEnumerator();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns an enumerator that iterates through a collection.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// An <see cref="T:System.Collections.IEnumerator"/> object that can be used to iterate through the collection.
|
||||
/// </returns>
|
||||
/// <filterpriority>2</filterpriority>
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
{
|
||||
return GetEnumerator();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Reads all the map files in the specified directory
|
||||
/// </summary>
|
||||
/// <param name="mapFileDirectory">The map file directory path</param>
|
||||
/// <param name="market">The map file market</param>
|
||||
/// <param name="securityType">The map file security type</param>
|
||||
/// <param name="dataProvider">The data provider instance to use</param>
|
||||
/// <returns>An enumerable of all map files</returns>
|
||||
public static IEnumerable<MapFile> GetMapFiles(string mapFileDirectory, string market, SecurityType securityType, IDataProvider dataProvider)
|
||||
{
|
||||
var mapFiles = new List<MapFile>();
|
||||
Parallel.ForEach(Directory.EnumerateFiles(mapFileDirectory), file =>
|
||||
{
|
||||
if (file.EndsWith(".csv"))
|
||||
{
|
||||
var permtick = Path.GetFileNameWithoutExtension(file);
|
||||
var fileRead = SafeMapFileRowRead(file, market, securityType, dataProvider);
|
||||
var mapFile = new MapFile(permtick, fileRead);
|
||||
lock (mapFiles)
|
||||
{
|
||||
// just use a list + lock, not concurrent bag, avoid garbage it creates for features we don't need here. See https://github.com/dotnet/runtime/issues/23103
|
||||
mapFiles.Add(mapFile);
|
||||
}
|
||||
}
|
||||
});
|
||||
return mapFiles;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads in the map file at the specified path, returning null if any exceptions are encountered
|
||||
/// </summary>
|
||||
private static List<MapFileRow> SafeMapFileRowRead(string file, string market, SecurityType securityType, IDataProvider dataProvider)
|
||||
{
|
||||
try
|
||||
{
|
||||
return MapFileRow.Read(file, market, securityType, dataProvider).ToList();
|
||||
}
|
||||
catch (Exception err)
|
||||
{
|
||||
Log.Error(err, $"File: {file}");
|
||||
return new List<MapFileRow>();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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.Collections.Concurrent;
|
||||
using System.Linq;
|
||||
using QuantConnect.Interfaces;
|
||||
|
||||
namespace QuantConnect.Data.Auxiliary
|
||||
{
|
||||
/// <summary>
|
||||
/// Implementation of IPrimaryExchangeProvider from map files.
|
||||
/// </summary>
|
||||
public class MapFilePrimaryExchangeProvider : IPrimaryExchangeProvider
|
||||
{
|
||||
private readonly IMapFileProvider _mapFileProvider;
|
||||
private readonly ConcurrentDictionary<SecurityIdentifier, Exchange> _primaryExchangeBySid;
|
||||
|
||||
/// <summary>
|
||||
/// Constructor for Primary Exchange Provider from MapFiles
|
||||
/// </summary>
|
||||
/// <param name="mapFileProvider">MapFile to use</param>
|
||||
public MapFilePrimaryExchangeProvider(IMapFileProvider mapFileProvider)
|
||||
{
|
||||
_mapFileProvider = mapFileProvider;
|
||||
_primaryExchangeBySid = new ConcurrentDictionary<SecurityIdentifier, Exchange>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the primary exchange for a given security identifier
|
||||
/// </summary>
|
||||
/// <param name="securityIdentifier">The security identifier to get the primary exchange for</param>
|
||||
/// <returns>Returns the primary exchange or null if not found</returns>
|
||||
public Exchange GetPrimaryExchange(SecurityIdentifier securityIdentifier)
|
||||
{
|
||||
Exchange primaryExchange;
|
||||
if (!_primaryExchangeBySid.TryGetValue(securityIdentifier, out primaryExchange))
|
||||
{
|
||||
var mapFile = _mapFileProvider.Get(AuxiliaryDataKey.Create(securityIdentifier))
|
||||
.ResolveMapFile(securityIdentifier.Symbol, securityIdentifier.Date);
|
||||
if (mapFile != null && mapFile.Any())
|
||||
{
|
||||
primaryExchange = mapFile.Last().PrimaryExchange;
|
||||
}
|
||||
_primaryExchangeBySid[securityIdentifier] = primaryExchange;
|
||||
}
|
||||
|
||||
return primaryExchange;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,230 @@
|
||||
/*
|
||||
* 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.Generic;
|
||||
using System.Data;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using QuantConnect.Interfaces;
|
||||
using QuantConnect.Util;
|
||||
|
||||
namespace QuantConnect.Data.Auxiliary
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides a means of mapping a symbol at a point in time to the map file
|
||||
/// containing that share class's mapping information
|
||||
/// </summary>
|
||||
public class MapFileResolver : IEnumerable<MapFile>
|
||||
{
|
||||
private readonly Dictionary<string, MapFile> _mapFilesByPermtick;
|
||||
private readonly Dictionary<string, SortedList<DateTime, MapFileRowEntry>> _bySymbol;
|
||||
|
||||
/// <summary>
|
||||
/// Gets an empty <see cref="MapFileResolver"/>, that is an instance that contains
|
||||
/// zero mappings
|
||||
/// </summary>
|
||||
public static readonly MapFileResolver Empty = new MapFileResolver(Enumerable.Empty<MapFile>());
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="MapFileResolver"/> by reading
|
||||
/// in all files in the specified directory.
|
||||
/// </summary>
|
||||
/// <param name="mapFiles">The data used to initialize this resolver.</param>
|
||||
public MapFileResolver(IEnumerable<MapFile> mapFiles)
|
||||
{
|
||||
_mapFilesByPermtick = new Dictionary<string, MapFile>(StringComparer.InvariantCultureIgnoreCase);
|
||||
_bySymbol = new Dictionary<string, SortedList<DateTime, MapFileRowEntry>>(StringComparer.InvariantCultureIgnoreCase);
|
||||
|
||||
foreach (var mapFile in mapFiles)
|
||||
{
|
||||
// add to our by path map
|
||||
_mapFilesByPermtick.Add(mapFile.Permtick, mapFile);
|
||||
|
||||
foreach (var row in mapFile)
|
||||
{
|
||||
SortedList<DateTime, MapFileRowEntry> entries;
|
||||
var mapFileRowEntry = new MapFileRowEntry(mapFile.Permtick, row);
|
||||
|
||||
if (!_bySymbol.TryGetValue(row.MappedSymbol, out entries))
|
||||
{
|
||||
entries = new SortedList<DateTime, MapFileRowEntry>();
|
||||
_bySymbol[row.MappedSymbol] = entries;
|
||||
}
|
||||
|
||||
if (entries.ContainsKey(mapFileRowEntry.MapFileRow.Date))
|
||||
{
|
||||
// check to verify it' the same data
|
||||
if (!entries[mapFileRowEntry.MapFileRow.Date].Equals(mapFileRowEntry))
|
||||
{
|
||||
throw new DuplicateNameException("Attempted to assign different history for symbol.");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
entries.Add(mapFileRowEntry.MapFileRow.Date, mapFileRowEntry);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the map file matching the specified permtick
|
||||
/// </summary>
|
||||
/// <param name="permtick">The permtick to match on</param>
|
||||
/// <returns>The map file matching the permtick, or null if not found</returns>
|
||||
public MapFile GetByPermtick(string permtick)
|
||||
{
|
||||
MapFile mapFile;
|
||||
_mapFilesByPermtick.TryGetValue(permtick.LazyToUpper(), out mapFile);
|
||||
return mapFile;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Resolves the map file path containing the mapping information for the symbol defined at <paramref name="date"/>
|
||||
/// </summary>
|
||||
/// <param name="symbol">The symbol as of <paramref name="date"/> to be mapped</param>
|
||||
/// <param name="date">The date associated with the <paramref name="symbol"/></param>
|
||||
/// <returns>The map file responsible for mapping the symbol, if no map file is found, null is returned</returns>
|
||||
public MapFile ResolveMapFile(string symbol, DateTime date)
|
||||
{
|
||||
// lookup the symbol's history
|
||||
SortedList<DateTime, MapFileRowEntry> entries;
|
||||
if (_bySymbol.TryGetValue(symbol, out entries))
|
||||
{
|
||||
if (entries.Count == 0)
|
||||
{
|
||||
return new MapFile(symbol, Enumerable.Empty<MapFileRow>());
|
||||
}
|
||||
|
||||
// Return value of BinarySearch (from MSDN):
|
||||
// The zero-based index of item in the sorted List<T>, if item is found;
|
||||
// otherwise, a negative number that is the bitwise complement of the index of the next element that is larger than item
|
||||
// or, if there is no larger element, the bitwise complement of Count.
|
||||
var indexOf = entries.Keys.BinarySearch(date);
|
||||
if (indexOf >= 0)
|
||||
{
|
||||
symbol = entries.Values[indexOf].EntitySymbol;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (indexOf == ~entries.Keys.Count)
|
||||
{
|
||||
// the searched date is greater than the last date in the list, return the last entry
|
||||
indexOf = entries.Keys.Count - 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
// if negative, it's the bitwise complement of where it should be
|
||||
indexOf = ~indexOf;
|
||||
}
|
||||
|
||||
symbol = entries.Values[indexOf].EntitySymbol;
|
||||
}
|
||||
}
|
||||
// secondary search for exact mapping, find path than ends with symbol.csv
|
||||
MapFile mapFile;
|
||||
if (!_mapFilesByPermtick.TryGetValue(symbol, out mapFile)
|
||||
|| mapFile.FirstDate > date && date != SecurityIdentifier.DefaultDate)
|
||||
{
|
||||
return new MapFile(symbol, Enumerable.Empty<MapFileRow>());
|
||||
}
|
||||
return mapFile;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Combines the map file row with the map file path that produced the row
|
||||
/// </summary>
|
||||
class MapFileRowEntry : IEquatable<MapFileRowEntry>
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the map file row
|
||||
/// </summary>
|
||||
public MapFileRow MapFileRow { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the full path to the map file that produced this row
|
||||
/// </summary>
|
||||
public string EntitySymbol { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="MapFileRowEntry"/> class
|
||||
/// </summary>
|
||||
/// <param name="entitySymbol">The map file that produced this row</param>
|
||||
/// <param name="mapFileRow">The map file row data</param>
|
||||
public MapFileRowEntry(string entitySymbol, MapFileRow mapFileRow)
|
||||
{
|
||||
MapFileRow = mapFileRow;
|
||||
EntitySymbol = entitySymbol;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Indicates whether the current object is equal to another object of the same type.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// true if the current object is equal to the <paramref name="other"/> parameter; otherwise, false.
|
||||
/// </returns>
|
||||
/// <param name="other">An object to compare with this object.</param>
|
||||
public bool Equals(MapFileRowEntry other)
|
||||
{
|
||||
if (other == null) return false;
|
||||
return other.MapFileRow.Date == MapFileRow.Date
|
||||
&& other.MapFileRow.MappedSymbol == MapFileRow.MappedSymbol;
|
||||
}
|
||||
|
||||
/// <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()
|
||||
{
|
||||
return MapFileRow.Date + ": " + MapFileRow.MappedSymbol + ": " + EntitySymbol;
|
||||
}
|
||||
}
|
||||
|
||||
#region Implementation of IEnumerable
|
||||
|
||||
/// <summary>
|
||||
/// Returns an enumerator that iterates through the collection.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// A <see cref="T:System.Collections.Generic.IEnumerator`1"/> that can be used to iterate through the collection.
|
||||
/// </returns>
|
||||
/// <filterpriority>1</filterpriority>
|
||||
public IEnumerator<MapFile> GetEnumerator()
|
||||
{
|
||||
return _mapFilesByPermtick.Values.GetEnumerator();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns an enumerator that iterates through a collection.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// An <see cref="T:System.Collections.IEnumerator"/> object that can be used to iterate through the collection.
|
||||
/// </returns>
|
||||
/// <filterpriority>2</filterpriority>
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
{
|
||||
return GetEnumerator();
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,213 @@
|
||||
/*
|
||||
* 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 System.Collections.Generic;
|
||||
|
||||
namespace QuantConnect.Data.Auxiliary
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a single row in a map_file. This is a csv file ordered as {date, mapped symbol}
|
||||
/// </summary>
|
||||
public class MapFileRow : IEquatable<MapFileRow>
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the date associated with this data
|
||||
/// </summary>
|
||||
public DateTime Date { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the mapped symbol
|
||||
/// </summary>
|
||||
public string MappedSymbol { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the mapped symbol
|
||||
/// </summary>
|
||||
public Exchange PrimaryExchange { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the securities mapping mode associated to this mapping row
|
||||
/// </summary>
|
||||
public DataMappingMode? DataMappingMode { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="MapFileRow"/> class.
|
||||
/// </summary>
|
||||
public MapFileRow(DateTime date, string mappedSymbol, string primaryExchange,
|
||||
string market = QuantConnect.Market.USA, SecurityType securityType = SecurityType.Equity, DataMappingMode? dataMappingMode = null)
|
||||
: this(date, mappedSymbol, primaryExchange.GetPrimaryExchange(securityType, market), dataMappingMode)
|
||||
{ }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="MapFileRow"/> class.
|
||||
/// </summary>
|
||||
public MapFileRow(DateTime date, string mappedSymbol, Exchange primaryExchange = null, DataMappingMode? dataMappingMode = null)
|
||||
{
|
||||
Date = date;
|
||||
MappedSymbol = mappedSymbol.LazyToUpper();
|
||||
PrimaryExchange = primaryExchange ?? Exchange.UNKNOWN;
|
||||
DataMappingMode = dataMappingMode;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads in the map_file for the specified equity symbol
|
||||
/// </summary>
|
||||
public static IEnumerable<MapFileRow> Read(string file, string market, SecurityType securityType, IDataProvider dataProvider)
|
||||
{
|
||||
return dataProvider.ReadLines(file)
|
||||
.Where(l => !string.IsNullOrWhiteSpace(l))
|
||||
.Select(s => {
|
||||
try
|
||||
{
|
||||
return Parse(s, market, securityType);
|
||||
}
|
||||
catch (ArgumentException)
|
||||
{
|
||||
// skip unrecognized mapping modes for backwards compatibility
|
||||
return null;
|
||||
}
|
||||
})
|
||||
.Where(row => row != null);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Parses the specified line into a MapFileRow
|
||||
/// </summary>
|
||||
public static MapFileRow Parse(string line, string market, SecurityType securityType)
|
||||
{
|
||||
var csv = line.Split(',');
|
||||
var primaryExchange = Exchange.UNKNOWN;
|
||||
DataMappingMode? mappingMode = null;
|
||||
|
||||
if (csv.Length >= 3)
|
||||
{
|
||||
primaryExchange = csv[2].GetPrimaryExchange(securityType, market);
|
||||
}
|
||||
if (csv.Length >= 4)
|
||||
{
|
||||
mappingMode = csv[3].ParseDataMappingMode();
|
||||
}
|
||||
|
||||
return new MapFileRow(DateTime.ParseExact(csv[0], DateFormat.EightCharacter, null), csv[1], primaryExchange, mappingMode);
|
||||
}
|
||||
|
||||
#region Equality members
|
||||
|
||||
/// <summary>
|
||||
/// Indicates whether the current object is equal to another object of the same type.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// true if the current object is equal to the <paramref name="other"/> parameter; otherwise, false.
|
||||
/// </returns>
|
||||
/// <param name="other">An object to compare with this object.</param>
|
||||
public bool Equals(MapFileRow other)
|
||||
{
|
||||
if (ReferenceEquals(null, other)) return false;
|
||||
if (ReferenceEquals(this, other)) return true;
|
||||
return Date.Equals(other.Date) &&
|
||||
string.Equals(MappedSymbol, other.MappedSymbol) &&
|
||||
string.Equals(PrimaryExchange, other.PrimaryExchange) &&
|
||||
DataMappingMode == other.DataMappingMode;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether the specified <see cref="T:System.Object"/> is equal to the current <see cref="T:System.Object"/>.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// true if the specified object is equal to the current object; otherwise, false.
|
||||
/// </returns>
|
||||
/// <param name="obj">The object to compare with the current object. </param><filterpriority>2</filterpriority>
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
if (ReferenceEquals(null, obj)) return false;
|
||||
if (ReferenceEquals(this, obj)) return true;
|
||||
if (obj.GetType() != this.GetType()) return false;
|
||||
return Equals((MapFileRow)obj);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Serves as a hash function for a particular type.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// A hash code for the current <see cref="T:System.Object"/>.
|
||||
/// </returns>
|
||||
/// <filterpriority>2</filterpriority>
|
||||
public override int GetHashCode()
|
||||
{
|
||||
unchecked
|
||||
{
|
||||
return (Date.GetHashCode() * 397) ^
|
||||
(MappedSymbol != null ? MappedSymbol.GetHashCode() : 0) ^
|
||||
(DataMappingMode != null ? DataMappingMode.GetHashCode() : 0) ^
|
||||
(PrimaryExchange.GetHashCode());
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether or not the two instances are equal
|
||||
/// </summary>
|
||||
public static bool operator ==(MapFileRow left, MapFileRow right)
|
||||
{
|
||||
return Equals(left, right);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether or not the two instances are not equal
|
||||
/// </summary>
|
||||
public static bool operator !=(MapFileRow left, MapFileRow right)
|
||||
{
|
||||
return !Equals(left, right);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Writes this row to csv format
|
||||
/// </summary>
|
||||
public string ToCsv()
|
||||
{
|
||||
var encodedExchange = string.Empty;
|
||||
if (PrimaryExchange == Exchange.UNKNOWN)
|
||||
{
|
||||
if (DataMappingMode != null)
|
||||
{
|
||||
// be lazy, only add a comma if we have a mapping mode after
|
||||
encodedExchange = ",";
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
encodedExchange = $",{PrimaryExchange.Code}";
|
||||
}
|
||||
var mappingMode = DataMappingMode != null ? $",{(int)DataMappingMode}" : string.Empty;
|
||||
return $"{Date.ToStringInvariant(DateFormat.EightCharacter)},{MappedSymbol.ToLowerInvariant()}{encodedExchange}{mappingMode}";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Convert this row into string form
|
||||
/// </summary>
|
||||
/// <returns>resulting string</returns>
|
||||
public override string ToString()
|
||||
{
|
||||
var mainExchange = PrimaryExchange == Exchange.UNKNOWN ? string.Empty : $" - {PrimaryExchange}";
|
||||
var mappingMode = DataMappingMode != null ? $" - {DataMappingMode}" : string.Empty;
|
||||
return Date.ToShortDateString() + ": " + MappedSymbol + mainExchange + mappingMode;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
/*
|
||||
* 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 System.Collections.Generic;
|
||||
|
||||
namespace QuantConnect.Data.Auxiliary
|
||||
{
|
||||
/// <summary>
|
||||
/// Helper class for handling mapfile zip files
|
||||
/// </summary>
|
||||
public static class MapFileZipHelper
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the mapfile zip filename for the specified date
|
||||
/// </summary>
|
||||
public static string GetMapFileZipFileName(string market, DateTime date, SecurityType securityType)
|
||||
{
|
||||
return Path.Combine(Globals.DataFolder, MapFile.GetRelativeMapFilePath(market, securityType), $"map_files_{date:yyyyMMdd}.zip");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads the zip bytes as text and parses as MapFileRows to create MapFiles
|
||||
/// </summary>
|
||||
public static IEnumerable<MapFile> ReadMapFileZip(Stream file, string market, SecurityType securityType)
|
||||
{
|
||||
if (file == null || file.Length == 0)
|
||||
{
|
||||
return Enumerable.Empty<MapFile>();
|
||||
}
|
||||
|
||||
var result = from kvp in Compression.Unzip(file)
|
||||
let filename = kvp.Key
|
||||
where filename.EndsWith(".csv", StringComparison.InvariantCultureIgnoreCase)
|
||||
let lines = kvp.Value.Where(line => !string.IsNullOrEmpty(line))
|
||||
let mapFile = SafeRead(filename, lines, market, securityType)
|
||||
select mapFile;
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Parses the contents as a MapFile, if error returns a new empty map file
|
||||
/// </summary>
|
||||
private static MapFile SafeRead(string filename, IEnumerable<string> contents, string market, SecurityType securityType)
|
||||
{
|
||||
var permtick = Path.GetFileNameWithoutExtension(filename);
|
||||
try
|
||||
{
|
||||
return new MapFile(permtick, contents.Select(s => MapFileRow.Parse(s, market, securityType)));
|
||||
}
|
||||
catch
|
||||
{
|
||||
return new MapFile(permtick, Enumerable.Empty<MapFileRow>());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,99 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
namespace QuantConnect.Data.Auxiliary
|
||||
{
|
||||
/// <summary>
|
||||
/// Mapping related factor provider. Factors based on price differences on mapping dates
|
||||
/// </summary>
|
||||
public class MappingContractFactorProvider : FactorFile<MappingContractFactorRow>
|
||||
{
|
||||
/// <summary>
|
||||
///Creates a new instance
|
||||
/// </summary>
|
||||
public MappingContractFactorProvider(string permtick, IEnumerable<MappingContractFactorRow> data, DateTime? factorFileMinimumDate = null)
|
||||
: base(permtick, data, factorFileMinimumDate)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the price scale factor for the specified search date
|
||||
/// </summary>
|
||||
public override decimal GetPriceFactor(DateTime searchDate, DataNormalizationMode dataNormalizationMode, DataMappingMode? dataMappingMode = null, uint contractOffset = 0)
|
||||
{
|
||||
if (dataNormalizationMode == DataNormalizationMode.Raw)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
var factor = 1m;
|
||||
if (dataNormalizationMode is DataNormalizationMode.BackwardsPanamaCanal or DataNormalizationMode.ForwardPanamaCanal)
|
||||
{
|
||||
// default value depends on the data mode
|
||||
factor = 0;
|
||||
}
|
||||
|
||||
for (var i = 0; i < ReversedFactorFileDates.Count; i++)
|
||||
{
|
||||
var factorDate = ReversedFactorFileDates[i];
|
||||
if (factorDate.Date < searchDate.Date)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
var factorFileRow = SortedFactorFileData[factorDate];
|
||||
switch (dataNormalizationMode)
|
||||
{
|
||||
case DataNormalizationMode.BackwardsRatio:
|
||||
{
|
||||
var row = factorFileRow.FirstOrDefault(row => row.DataMappingMode == dataMappingMode);
|
||||
if (row != null && row.BackwardsRatioScale.Count > contractOffset)
|
||||
{
|
||||
factor = row.BackwardsRatioScale[(int)contractOffset];
|
||||
}
|
||||
break;
|
||||
}
|
||||
case DataNormalizationMode.BackwardsPanamaCanal:
|
||||
{
|
||||
var row = factorFileRow.FirstOrDefault(row => row.DataMappingMode == dataMappingMode);
|
||||
if (row != null && row.BackwardsPanamaCanalScale.Count > contractOffset)
|
||||
{
|
||||
factor = row.BackwardsPanamaCanalScale[(int)contractOffset];
|
||||
}
|
||||
break;
|
||||
}
|
||||
case DataNormalizationMode.ForwardPanamaCanal:
|
||||
{
|
||||
var row = factorFileRow.FirstOrDefault(row => row.DataMappingMode == dataMappingMode);
|
||||
if (row != null && row.ForwardPanamaCanalScale.Count > contractOffset)
|
||||
{
|
||||
factor = row.ForwardPanamaCanalScale[(int)contractOffset];
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException(nameof(dataNormalizationMode));
|
||||
}
|
||||
}
|
||||
|
||||
return factor;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,103 @@
|
||||
/*
|
||||
* 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 Newtonsoft.Json;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace QuantConnect.Data.Auxiliary
|
||||
{
|
||||
/// <summary>
|
||||
/// Collection of factors for continuous contracts and their back months contracts for a specific mapping mode <see cref="DataMappingMode"/> and date
|
||||
/// </summary>
|
||||
public class MappingContractFactorRow : IFactorRow
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the date associated with this data
|
||||
/// </summary>
|
||||
public DateTime Date { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Backwards ratio price scaling factors for the front month [index 0] and it's 'i' back months [index 0 + i]
|
||||
/// <see cref="DataNormalizationMode.BackwardsRatio"/>
|
||||
/// </summary>
|
||||
public IReadOnlyList<decimal> BackwardsRatioScale { get; set; } = new List<decimal>();
|
||||
|
||||
/// <summary>
|
||||
/// Backwards Panama Canal price scaling factors for the front month [index 0] and it's 'i' back months [index 0 + i]
|
||||
/// <see cref="DataNormalizationMode.BackwardsPanamaCanal"/>
|
||||
/// </summary>
|
||||
public IReadOnlyList<decimal> BackwardsPanamaCanalScale { get; set; } = new List<decimal>();
|
||||
|
||||
/// <summary>
|
||||
/// Forward Panama Canal price scaling factors for the front month [index 0] and it's 'i' back months [index 0 + i]
|
||||
/// <see cref="DataNormalizationMode.ForwardPanamaCanal"/>
|
||||
/// </summary>
|
||||
public IReadOnlyList<decimal> ForwardPanamaCanalScale { get; set; } = new List<decimal>();
|
||||
|
||||
/// <summary>
|
||||
/// Allows the consumer to specify a desired mapping mode
|
||||
/// </summary>
|
||||
public DataMappingMode? DataMappingMode { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Empty constructor for json converter
|
||||
/// </summary>
|
||||
public MappingContractFactorRow()
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes factor file row into it's file format
|
||||
/// </summary>
|
||||
/// <remarks>Json formatted</remarks>
|
||||
public string GetFileFormat(string source = null)
|
||||
{
|
||||
return JsonConvert.SerializeObject(this);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Parses the lines as factor files rows while properly handling inf entries
|
||||
/// </summary>
|
||||
/// <param name="lines">The lines from the factor file to be parsed</param>
|
||||
/// <param name="factorFileMinimumDate">The minimum date from the factor file</param>
|
||||
/// <returns>An enumerable of factor file rows</returns>
|
||||
public static List<MappingContractFactorRow> Parse(IEnumerable<string> lines, out DateTime? factorFileMinimumDate)
|
||||
{
|
||||
factorFileMinimumDate = null;
|
||||
|
||||
var rows = new List<MappingContractFactorRow>();
|
||||
|
||||
// parse factor file lines
|
||||
foreach (var line in lines)
|
||||
{
|
||||
var row = JsonConvert.DeserializeObject<MappingContractFactorRow>(line);
|
||||
if(!row.DataMappingMode.HasValue || Enum.IsDefined(typeof(DataMappingMode), row.DataMappingMode.Value))
|
||||
{
|
||||
rows.Add(row);
|
||||
}
|
||||
}
|
||||
|
||||
if (rows.Count > 0)
|
||||
{
|
||||
factorFileMinimumDate = rows.Min(ffr => ffr.Date).AddDays(-1);
|
||||
}
|
||||
|
||||
return rows;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,201 @@
|
||||
/*
|
||||
* 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 System.Collections.Generic;
|
||||
|
||||
namespace QuantConnect.Data.Auxiliary
|
||||
{
|
||||
/// <summary>
|
||||
/// Mapping extensions helper methods
|
||||
/// </summary>
|
||||
public static class MappingExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Helper method to resolve the mapping file to use.
|
||||
/// </summary>
|
||||
/// <remarks>This method is aware of the data type being added for <see cref="SecurityType.Base"/>
|
||||
/// to the <see cref="SecurityIdentifier.Symbol"/> value</remarks>
|
||||
/// <param name="mapFileProvider">The map file provider</param>
|
||||
/// <param name="dataConfig">The configuration to fetch the map file for</param>
|
||||
/// <returns>The mapping file to use</returns>
|
||||
public static MapFile ResolveMapFile(this IMapFileProvider mapFileProvider, SubscriptionDataConfig dataConfig)
|
||||
{
|
||||
var resolver = MapFileResolver.Empty;
|
||||
if (dataConfig.TickerShouldBeMapped())
|
||||
{
|
||||
resolver = mapFileProvider.Get(AuxiliaryDataKey.Create(dataConfig.Symbol));
|
||||
}
|
||||
return resolver.ResolveMapFile(dataConfig.Symbol, dataConfig.Type.Name);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Helper method to resolve the mapping file to use.
|
||||
/// </summary>
|
||||
/// <remarks>This method is aware of the data type being added for <see cref="SecurityType.Base"/>
|
||||
/// to the <see cref="SecurityIdentifier.Symbol"/> value</remarks>
|
||||
/// <param name="mapFileResolver">The map file resolver</param>
|
||||
/// <param name="symbol">The symbol that we want to map</param>
|
||||
/// <param name="dataType">The string data type name if any</param>
|
||||
/// <returns>The mapping file to use</returns>
|
||||
public static MapFile ResolveMapFile(this MapFileResolver mapFileResolver,
|
||||
Symbol symbol,
|
||||
string dataType = null)
|
||||
{
|
||||
// Load the symbol and date to complete the mapFile checks in one statement
|
||||
var symbolID = symbol.HasUnderlying ? symbol.Underlying.ID.Symbol : symbol.ID.Symbol;
|
||||
if (dataType == null && symbol.SecurityType == SecurityType.Base)
|
||||
{
|
||||
SecurityIdentifier.TryGetCustomDataType(symbol.ID.Symbol, out dataType);
|
||||
}
|
||||
symbolID = symbol.SecurityType == SecurityType.Base && dataType != null ? symbolID.RemoveFromEnd($".{dataType}") : symbolID;
|
||||
|
||||
MapFile result;
|
||||
if (ReferenceEquals(mapFileResolver, MapFileResolver.Empty))
|
||||
{
|
||||
result = mapFileResolver.ResolveMapFile(symbol.Value, Time.BeginningOfTime);
|
||||
}
|
||||
else
|
||||
{
|
||||
var date = symbol.HasUnderlying ? symbol.Underlying.ID.Date : symbol.ID.Date;
|
||||
result = mapFileResolver.ResolveMapFile(symbolID, date);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Some historical provider supports ancient data. In fact, the ticker could be restructured to new one.
|
||||
/// </summary>
|
||||
/// <param name="mapFileProvider">Provides instances of <see cref="MapFileResolver"/> at run time</param>
|
||||
/// <param name="symbol">Represents a unique security identifier</param>
|
||||
/// <param name="startDateTime">The date since we began our search for the historical name of the symbol.</param>
|
||||
/// <param name="endDateTime">The end date and time of the historical data range.</param>
|
||||
/// <returns>
|
||||
/// An enumerable collection of tuples containing symbol ticker, start date and time, and end date and time
|
||||
/// representing the historical definitions of the symbol within the specified time range.
|
||||
/// </returns>
|
||||
/// <exception cref="ArgumentNullException">Thrown when <paramref name="mapFileProvider"/> is null.</exception>
|
||||
/// <example>
|
||||
/// For instances, get "GOOGL" since 2013 to 2018:
|
||||
/// It returns: { ("GOOG", 2013, 2014), ("GOOGL", 2014, 2018) }
|
||||
/// </example>
|
||||
/// <remarks>
|
||||
/// GOOGLE: IPO: August 19, 2004 Name = GOOG then it was restructured: from "GOOG" to "GOOGL" on April 2, 2014
|
||||
/// </remarks>
|
||||
public static IEnumerable<TickerDateRange> RetrieveSymbolHistoricalDefinitionsInDateRange
|
||||
(this IMapFileProvider mapFileProvider, Symbol symbol, DateTime startDateTime, DateTime endDateTime)
|
||||
{
|
||||
if (mapFileProvider == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(mapFileProvider));
|
||||
}
|
||||
|
||||
var mapFileResolver = mapFileProvider.Get(AuxiliaryDataKey.Create(symbol));
|
||||
var symbolMapFile = mapFileResolver.ResolveMapFile(symbol);
|
||||
|
||||
if (!symbolMapFile.Any())
|
||||
{
|
||||
yield break;
|
||||
}
|
||||
|
||||
var newStartDateTime = startDateTime;
|
||||
foreach (var mappedTicker in symbolMapFile.Skip(1)) // Skip: IPO Ticker's DateTime
|
||||
{
|
||||
if (mappedTicker.Date >= newStartDateTime)
|
||||
{
|
||||
// Shifts endDateTime by one day to include all data up to and including the endDateTime.
|
||||
var newEndDateTime = mappedTicker.Date.AddDays(1);
|
||||
if (newEndDateTime > endDateTime)
|
||||
{
|
||||
yield return new(mappedTicker.MappedSymbol, newStartDateTime, endDateTime);
|
||||
// the request EndDateTime was achieved
|
||||
yield break;
|
||||
}
|
||||
|
||||
yield return new(mappedTicker.MappedSymbol, newStartDateTime, newEndDateTime);
|
||||
// the end of the current request is the start of the next
|
||||
newStartDateTime = newEndDateTime;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Retrieves all Symbol from map files based on specific Symbol.
|
||||
/// </summary>
|
||||
/// <param name="mapFileProvider">The provider for map files containing ticker data.</param>
|
||||
/// <param name="symbol">The symbol to get <see cref="MapFileResolver"/> and generate new Symbol.</param>
|
||||
/// <returns>An enumerable collection of <see cref="SymbolDateRange"/></returns>
|
||||
/// <exception cref="ArgumentException">Throw if <paramref name="mapFileProvider"/> is null.</exception>
|
||||
public static IEnumerable<SymbolDateRange> RetrieveAllMappedSymbolInDateRange(this IMapFileProvider mapFileProvider, Symbol symbol)
|
||||
{
|
||||
if (mapFileProvider == null || symbol == null)
|
||||
{
|
||||
throw new ArgumentException($"The map file provider and symbol cannot be null. {(mapFileProvider == null ? nameof(mapFileProvider) : nameof(symbol))}");
|
||||
}
|
||||
|
||||
var mapFileResolver = mapFileProvider.Get(AuxiliaryDataKey.Create(symbol));
|
||||
|
||||
var tickerUpperCase = symbol.HasUnderlying ? symbol.Underlying.Value.ToUpperInvariant() : symbol.Value.ToUpperInvariant();
|
||||
|
||||
var isOptionSymbol = symbol.SecurityType == SecurityType.Option;
|
||||
foreach (var mapFile in mapFileResolver)
|
||||
{
|
||||
// Check if 'mapFile' contains the desired ticker symbol.
|
||||
if (!mapFile.Any(mapFileRow => mapFileRow.MappedSymbol == tickerUpperCase))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
foreach (var tickerDateRange in mapFile.GetTickerDateRanges(tickerUpperCase))
|
||||
{
|
||||
var sid = SecurityIdentifier.GenerateEquity(mapFile.FirstDate, mapFile.FirstTicker, symbol?.ID.Market);
|
||||
|
||||
var newSymbol = new Symbol(sid, tickerUpperCase);
|
||||
|
||||
if (isOptionSymbol)
|
||||
{
|
||||
newSymbol = Symbol.CreateCanonicalOption(newSymbol);
|
||||
}
|
||||
|
||||
yield return new(newSymbol, tickerDateRange.StartDate, tickerDateRange.EndDate);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Retrieves the date ranges associated with a specific ticker symbol from the provided map file.
|
||||
/// </summary>
|
||||
/// <param name="mapFile">The map file containing the data ranges for various ticker.</param>
|
||||
/// <param name="ticker">The ticker for which to retrieve the date ranges.</param>
|
||||
/// <returns>An enumerable collection of tuples representing the start and end dates for each date range associated with the specified ticker symbol.</returns>
|
||||
private static IEnumerable<(DateTime StartDate, DateTime EndDate)> GetTickerDateRanges(this MapFile mapFile, string ticker)
|
||||
{
|
||||
var previousRowDate = mapFile.FirstOrDefault().Date;
|
||||
foreach (var currentRow in mapFile.Skip(1))
|
||||
{
|
||||
if (ticker == currentRow.MappedSymbol)
|
||||
{
|
||||
yield return (previousRowDate, currentRow.Date.AddDays(1));
|
||||
}
|
||||
// MapFile maintains the latest date associated with each ticker name, except first Row
|
||||
previousRowDate = currentRow.Date.AddDays(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,129 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
namespace QuantConnect.Data.Auxiliary
|
||||
{
|
||||
/// <summary>
|
||||
/// Set of helper methods for factor files and price scaling operations
|
||||
/// </summary>
|
||||
public static class PriceScalingExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Resolves the price scale for a date given a factor file and required settings
|
||||
/// </summary>
|
||||
/// <param name="factorFile">The factor file to use</param>
|
||||
/// <param name="dateTime">The date for the price scale lookup</param>
|
||||
/// <param name="normalizationMode">The price normalization mode requested</param>
|
||||
/// <param name="contractOffset">The contract offset, useful for continuous contracts</param>
|
||||
/// <param name="dataMappingMode">The data mapping mode used, useful for continuous contracts</param>
|
||||
/// <param name="endDateTime">The reference end date for scaling prices.</param>
|
||||
/// <returns>The price scale to use</returns>
|
||||
/// <exception cref="ArgumentException">
|
||||
/// If <paramref name="normalizationMode"/> is <see cref="DataNormalizationMode.ScaledRaw"/> and <paramref name="endDateTime"/> is null
|
||||
/// </exception>
|
||||
/// <remarks>
|
||||
/// For <see cref="DataNormalizationMode.ScaledRaw"/> normalization mode,
|
||||
/// the prices are scaled to the prices on the <paramref name="endDateTime"/>
|
||||
/// </remarks>
|
||||
public static decimal GetPriceScale(
|
||||
this IFactorProvider factorFile,
|
||||
DateTime dateTime,
|
||||
DataNormalizationMode normalizationMode,
|
||||
uint contractOffset = 0,
|
||||
DataMappingMode? dataMappingMode = null,
|
||||
DateTime? endDateTime = null
|
||||
)
|
||||
{
|
||||
if (factorFile == null)
|
||||
{
|
||||
if (normalizationMode is DataNormalizationMode.BackwardsPanamaCanal or DataNormalizationMode.ForwardPanamaCanal)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
var endDateTimeFactor = 1m;
|
||||
if (normalizationMode == DataNormalizationMode.ScaledRaw)
|
||||
{
|
||||
if (endDateTime == null)
|
||||
{
|
||||
throw new ArgumentException(
|
||||
$"{nameof(DataNormalizationMode.ScaledRaw)} normalization mode requires an end date for price scaling.");
|
||||
}
|
||||
|
||||
// For ScaledRaw, we need to get the price scale at the end date to adjust prices to that date instead of "today"
|
||||
endDateTimeFactor = factorFile.GetPriceFactor(endDateTime.Value, normalizationMode, dataMappingMode, contractOffset);
|
||||
}
|
||||
|
||||
return factorFile.GetPriceFactor(dateTime, normalizationMode, dataMappingMode, contractOffset) / endDateTimeFactor;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines the symbol to use to fetch it's factor file
|
||||
/// </summary>
|
||||
/// <remarks>This is useful for futures where the symbol to use is the canonical</remarks>
|
||||
public static Symbol GetFactorFileSymbol(this Symbol symbol)
|
||||
{
|
||||
return symbol.SecurityType == SecurityType.Future ? symbol.Canonical : symbol;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Helper method to return an empty factor file
|
||||
/// </summary>
|
||||
public static IFactorProvider GetEmptyFactorFile(this Symbol symbol)
|
||||
{
|
||||
if (symbol.SecurityType == SecurityType.Future)
|
||||
{
|
||||
return new MappingContractFactorProvider(symbol.ID.Symbol, Enumerable.Empty<MappingContractFactorRow>());
|
||||
}
|
||||
return new CorporateFactorProvider(symbol.ID.Symbol, Enumerable.Empty<CorporateFactorRow>());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Parses the contents as a FactorFile, if error returns a new empty factor file
|
||||
/// </summary>
|
||||
public static IFactorProvider SafeRead(string permtick, IEnumerable<string> contents, SecurityType securityType)
|
||||
{
|
||||
try
|
||||
{
|
||||
DateTime? minimumDate;
|
||||
|
||||
contents = contents.Distinct();
|
||||
|
||||
if (securityType == SecurityType.Future)
|
||||
{
|
||||
return new MappingContractFactorProvider(permtick, MappingContractFactorRow.Parse(contents, out minimumDate), minimumDate);
|
||||
}
|
||||
// FactorFileRow.Parse handles entries with 'inf' and exponential notation and provides the associated minimum tradeable date for these cases
|
||||
// previously these cases were not handled causing an exception and returning an empty factor file
|
||||
return new CorporateFactorProvider(permtick, CorporateFactorRow.Parse(contents, out minimumDate), minimumDate);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
if (securityType == SecurityType.Future)
|
||||
{
|
||||
return new MappingContractFactorProvider(permtick, Enumerable.Empty<MappingContractFactorRow>());
|
||||
}
|
||||
return new CorporateFactorProvider(permtick, Enumerable.Empty<CorporateFactorRow>());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,202 @@
|
||||
/*
|
||||
* 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.ComponentModel;
|
||||
|
||||
namespace QuantConnect.Data.Auxiliary
|
||||
{
|
||||
/// <summary>
|
||||
/// Flag system for quote conditions
|
||||
/// </summary>
|
||||
[Flags]
|
||||
public enum QuoteConditionFlags : long
|
||||
{
|
||||
/// <summary>
|
||||
/// No Condition
|
||||
/// </summary>
|
||||
None = 0,
|
||||
|
||||
/// <summary>
|
||||
/// This condition is used for the majority of quotes to indicate a normal trading environment.
|
||||
/// </summary>
|
||||
[Description("This condition is used for the majority of quotes to indicate a normal trading environment.")]
|
||||
Regular = 1L << 0,
|
||||
|
||||
/// <summary>
|
||||
/// This condition is used to indicate that the quote is a Slow Quote on both the Bid and Offer
|
||||
/// sides due to a Set Slow List that includes High Price securities.
|
||||
/// </summary>
|
||||
[Description("This condition is used to indicate that the quote is a Slow Quote on both the Bid and Offer " +
|
||||
"sides due to a Set Slow List that includes High Price securities.")]
|
||||
Slow = 1L << 1,
|
||||
|
||||
/// <summary>
|
||||
/// While in this mode, auto-execution is not eligible, the quote is then considered manual and non-firm in the Bid and Offer and
|
||||
/// either or both sides can be traded through as per Regulation NMS.
|
||||
/// </summary>
|
||||
[Description("While in this mode, auto-execution is not eligible, the quote is then considered manual and non-firm in the Bid and Offer and " +
|
||||
"either or both sides can be traded through as per Regulation NMS.")]
|
||||
Gap = 1L << 2,
|
||||
|
||||
/// <summary>
|
||||
/// This condition can be disseminated to indicate that this quote was the last quote for a security for that Participant.
|
||||
/// </summary>
|
||||
[Description("This condition can be disseminated to indicate that this quote was the last quote for a security for that Participant.")]
|
||||
Closing = 1L << 3,
|
||||
|
||||
/// <summary>
|
||||
/// This regulatory Opening Delay or Trading Halt is used when relevant news influencing the security is being disseminated.
|
||||
/// Trading is suspended until the primary market determines that an adequate publication or disclosure of information has occurred.
|
||||
/// </summary>
|
||||
[Description("This regulatory Opening Delay or Trading Halt is used when relevant news influencing the security is being disseminated." +
|
||||
"Trading is suspended until the primary market determines that an adequate publication or disclosure of information has occurred.")]
|
||||
NewsDissemination = 1L << 4,
|
||||
|
||||
/// <summary>
|
||||
/// This condition is used to indicate a regulatory Opening Delay or Trading Halt due to an expected news announcement,
|
||||
/// which may influence the security. An Opening Delay or Trading Halt may be continued once the news has been disseminated.
|
||||
/// </summary>
|
||||
[Description("This condition is used to indicate a regulatory Opening Delay or Trading Halt due to an expected news announcement, " +
|
||||
"which may influence the security. An Opening Delay or Trading Halt may be continued once the news has been disseminated.")]
|
||||
NewsPending = 1L << 5,
|
||||
|
||||
/// <summary>
|
||||
/// The condition is used to denote the probable trading range (bid and offer prices, no sizes) of a security that is not Opening Delayed or
|
||||
/// Trading Halted. The Trading Range Indication is used prior to or after the opening of a security.
|
||||
/// </summary>
|
||||
[Description("The condition is used to denote the probable trading range (bid and offer prices, no sizes) of a security that is not Opening Delayed or" +
|
||||
"Trading Halted. The Trading Range Indication is used prior to or after the opening of a security.")]
|
||||
TradingRangeIndication = 1L << 6,
|
||||
|
||||
/// <summary>
|
||||
/// This non-regulatory Opening Delay or Trading Halt is used when there is a significant imbalance of buy or sell orders.
|
||||
/// </summary>
|
||||
[Description("This non-regulatory Opening Delay or Trading Halt is used when there is a significant imbalance of buy or sell orders.")]
|
||||
OrderImbalance = 1L << 7,
|
||||
|
||||
/// <summary>
|
||||
/// This condition is disseminated by each individual FINRA Market Maker to signify either the last quote of the day or
|
||||
/// the premature close of an individual Market Maker for the day.
|
||||
/// </summary>
|
||||
[Description("This condition is disseminated by each individual FINRA Market Maker to signify either the last quote of the day or" +
|
||||
"the premature close of an individual Market Maker for the day.")]
|
||||
ClosedMarketMaker = 1L << 8,
|
||||
|
||||
/// <summary>
|
||||
/// This quote condition indicates a regulatory Opening Delay or Trading Halt due to conditions in which
|
||||
/// a security experiences a 10 % or more change in price over a five minute period.
|
||||
/// </summary>
|
||||
[Description("This quote condition indicates a regulatory Opening Delay or Trading Halt due to conditions in which " +
|
||||
"a security experiences a 10 % or more change in price over a five minute period.")]
|
||||
VolatilityTradingPause = 1L << 9,
|
||||
|
||||
/// <summary>
|
||||
/// This quote condition suspends a Participant's firm quote obligation for a quote for a security.
|
||||
/// </summary>
|
||||
[Description("This quote condition suspends a Participant's firm quote obligation for a quote for a security.")]
|
||||
NonFirmQuote = 1L << 10,
|
||||
|
||||
/// <summary>
|
||||
/// This condition can be disseminated to indicate that this quote was the opening quote for a security for that Participant.
|
||||
/// </summary>
|
||||
[Description("This condition can be disseminated to indicate that this quote was the opening quote for a security for that Participant.")]
|
||||
OpeningQuote = 1L << 11,
|
||||
|
||||
/// <summary>
|
||||
/// This non-regulatory Opening Delay or Trading Halt is used when events relating to one security will affect the price and performance of
|
||||
/// another related security. This non-regulatory Opening Delay or Trading Halt is also used when non-regulatory halt reasons such as
|
||||
/// Order Imbalance, Order Influx and Equipment Changeover are combined with Due to Related Security on CTS.
|
||||
/// </summary>
|
||||
[Description("This non-regulatory Opening Delay or Trading Halt is used when events relating to one security will affect the price and performance of " +
|
||||
"another related security. This non-regulatory Opening Delay or Trading Halt is also used when non-regulatory halt reasons such as " +
|
||||
"Order Imbalance, Order Influx and Equipment Changeover are combined with Due to Related Security on CTS.")]
|
||||
DueToRelatedSecurity = 1L << 12,
|
||||
|
||||
/// <summary>
|
||||
/// This quote condition along with zero-filled bid, offer and size fields is used to indicate that trading for a Participant is no longer
|
||||
/// suspended in a security which had been Opening Delayed or Trading Halted.
|
||||
/// </summary>
|
||||
[Description("This quote condition along with zero-filled bid, offer and size fields is used to indicate that trading for a Participant is no longer " +
|
||||
"suspended in a security which had been Opening Delayed or Trading Halted.")]
|
||||
Resume = 1L << 13,
|
||||
|
||||
/// <summary>
|
||||
/// This quote condition is used when matters affecting the common stock of a company affect the performance of the non-common
|
||||
/// associated securities, e.g., warrants, rights, preferred, classes, etc.
|
||||
/// </summary>
|
||||
[Description("This quote condition is used when matters affecting the common stock of a company affect the performance of the non-common " +
|
||||
"associated securities, e.g., warrants, rights, preferred, classes, etc.")]
|
||||
InViewOfCommon = 1L << 14,
|
||||
|
||||
/// <summary>
|
||||
/// This non-regulatory Opening Delay or Trading Halt is used when the ability to trade a security by a Participant is temporarily
|
||||
/// inhibited due to a systems, equipment or communications facility problem or for other technical reasons.
|
||||
/// </summary>
|
||||
[Description("This non-regulatory Opening Delay or Trading Halt is used when the ability to trade a security by a Participant is temporarily " +
|
||||
"inhibited due to a systems, equipment or communications facility problem or for other technical reasons.")]
|
||||
EquipmentChangeover = 1L << 15,
|
||||
|
||||
/// <summary>
|
||||
/// This non-regulatory Opening Delay or Trading Halt is used to indicate an Opening Delay or Trading Halt for a security whose price
|
||||
/// may fall below $1.05, possibly leading to a sub-penny execution.
|
||||
/// </summary>
|
||||
[Description("This non-regulatory Opening Delay or Trading Halt is used to indicate an Opening Delay or Trading Halt for a security whose price" +
|
||||
" may fall below $1.05, possibly leading to a sub-penny execution.")]
|
||||
SubPennyTrading = 1L << 16,
|
||||
|
||||
/// <summary>
|
||||
/// This quote condition is used to indicate that an Opening Delay or a Trading Halt is to be in effect for the rest
|
||||
/// of the trading day in a security for a Participant.
|
||||
/// </summary>
|
||||
[Description("This quote condition is used to indicate that an Opening Delay or a Trading Halt is to be in effect for the rest " +
|
||||
"of the trading day in a security for a Participant.")]
|
||||
NoOpenNoResume = 1L << 17,
|
||||
|
||||
/// <summary>
|
||||
/// This quote condition is used to indicate that a Limit Up-Limit Down Price Band is applicable for a security.
|
||||
/// </summary>
|
||||
[Description("This quote condition is used to indicate that a Limit Up-Limit Down Price Band is applicable for a security.")]
|
||||
LimitUpLimitDownPriceBand = 1L << 18,
|
||||
|
||||
/// <summary>
|
||||
/// This quote condition is used to indicate that a Limit Up-Limit Down Price Band that is being disseminated " +
|
||||
/// is a ‘republication’ of the latest Price Band for a security.
|
||||
/// </summary>
|
||||
[Description("This quote condition is used to indicate that a Limit Up-Limit Down Price Band that is being disseminated " +
|
||||
"is a ‘republication’ of the latest Price Band for a security.")]
|
||||
RepublishedLimitUpLimitDownPriceBand = 1L << 19,
|
||||
|
||||
/// <summary>
|
||||
/// This indicates that the market participant is in a manual mode on both the Bid and Ask. While in this mode,
|
||||
/// automated execution is not eligible on the Bid and Ask side and can be traded through pursuant to Regulation NMS requirements.
|
||||
/// </summary>
|
||||
[Description("This indicates that the market participant is in a manual mode on both the Bid and Ask. While in this mode, " +
|
||||
"automated execution is not eligible on the Bid and Ask side and can be traded through pursuant to Regulation NMS requirements.")]
|
||||
Manual = 1L << 20,
|
||||
|
||||
/// <summary>
|
||||
/// For extremely active periods of short duration. While in this mode, the UTP participant will enter quotations on a “best efforts” basis.
|
||||
/// </summary>
|
||||
[Description("For extremely active periods of short duration. While in this mode, the UTP participant will enter quotations on a “best efforts” basis.")]
|
||||
FastTrading = 1L << 21,
|
||||
|
||||
/// <summary>
|
||||
/// A halt condition used when there is a sudden order influx. To prevent a disorderly market, trading is temporarily suspended by the UTP participant.
|
||||
/// </summary>
|
||||
[Description("A halt condition used when there is a sudden order influx. To prevent a disorderly market, trading is temporarily suspended by the UTP participant.")]
|
||||
OrderInflux = 1L << 22
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
namespace QuantConnect.Data.Auxiliary
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents security identifier within a date range.
|
||||
/// </summary>
|
||||
#pragma warning disable CA1815 // Override equals and operator equals on value types
|
||||
public readonly struct SymbolDateRange
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a unique security identifier.
|
||||
/// </summary>
|
||||
public Symbol Symbol { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Ticker Start Date Time in Local
|
||||
/// </summary>
|
||||
public DateTime StartDateTimeLocal { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Ticker End Date Time in Local
|
||||
/// </summary>
|
||||
public DateTime EndDateTimeLocal { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Create the instance of <see cref="SymbolDateRange"/> struct.
|
||||
/// </summary>
|
||||
/// <param name="symbol">The unique security identifier</param>
|
||||
/// <param name="startDateTimeLocal">Start Date Time Local</param>
|
||||
/// <param name="endDateTimeLocal">End Date Time Local</param>
|
||||
public SymbolDateRange(Symbol symbol, DateTime startDateTimeLocal, DateTime endDateTimeLocal)
|
||||
{
|
||||
Symbol = symbol;
|
||||
StartDateTimeLocal = startDateTimeLocal;
|
||||
EndDateTimeLocal = endDateTimeLocal;
|
||||
}
|
||||
}
|
||||
#pragma warning restore CA1815
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
|
||||
namespace QuantConnect.Data.Auxiliary
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents stock data for a specific ticker within a date range.
|
||||
/// </summary>
|
||||
#pragma warning disable CA1815 // Override equals and operator equals on value types
|
||||
public readonly struct TickerDateRange
|
||||
{
|
||||
/// <summary>
|
||||
/// Ticker simple name of stock
|
||||
/// </summary>
|
||||
public string Ticker { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Ticker Start Date Time in Local
|
||||
/// </summary>
|
||||
public DateTime StartDateTimeLocal { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Ticker End Date Time in Local
|
||||
/// </summary>
|
||||
public DateTime EndDateTimeLocal { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Create the instance of <see cref="TickerDateRange"/> struct.
|
||||
/// </summary>
|
||||
/// <param name="ticker">Name of ticker</param>
|
||||
/// <param name="startDateTimeLocal">Start Date Time Local</param>
|
||||
/// <param name="endDateTimeLocal">End Date Time Local</param>
|
||||
public TickerDateRange(string ticker, DateTime startDateTimeLocal, DateTime endDateTimeLocal)
|
||||
{
|
||||
Ticker = ticker;
|
||||
StartDateTimeLocal = startDateTimeLocal;
|
||||
EndDateTimeLocal = endDateTimeLocal;
|
||||
}
|
||||
}
|
||||
#pragma warning restore CA1815
|
||||
}
|
||||
@@ -0,0 +1,256 @@
|
||||
/*
|
||||
* 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.ComponentModel;
|
||||
|
||||
namespace QuantConnect.Data.Auxiliary
|
||||
{
|
||||
/// <summary>
|
||||
/// Flag system for trade conditions
|
||||
/// </summary>
|
||||
[Flags]
|
||||
public enum TradeConditionFlags: long
|
||||
{
|
||||
/// <summary>
|
||||
/// No Condition
|
||||
/// </summary>
|
||||
None = 0,
|
||||
|
||||
/// <summary>
|
||||
/// A trade made without stated conditions is deemed regular way for settlement on the third business day following the transaction date.
|
||||
/// </summary>
|
||||
[Description("A trade made without stated conditions is deemed regular way for settlement on the third business day following the transaction date.")]
|
||||
Regular = 1L << 0,
|
||||
|
||||
/// <summary>
|
||||
/// A transaction which requires delivery of securities and payment on the same day the trade takes place.
|
||||
/// </summary>
|
||||
[Description("A transaction which requires delivery of securities and payment on the same day the trade takes place.")]
|
||||
Cash = 1L << 1,
|
||||
|
||||
/// <summary>
|
||||
/// A transaction that requires the delivery of securities on the first business day following the trade date.
|
||||
/// </summary>
|
||||
[Description("A transaction that requires the delivery of securities on the first business day following the trade date.")]
|
||||
NextDay = 1L << 2,
|
||||
|
||||
/// <summary>
|
||||
/// A Seller’s Option transaction gives the seller the right to deliver the security at any time within a specific period,
|
||||
/// ranging from not less than two calendar days, to not more than sixty calendar days.
|
||||
/// </summary>
|
||||
[Description("A Seller’s Option transaction gives the seller the right to deliver the security at any time within a specific period, " +
|
||||
"ranging from not less than two calendar days, to not more than sixty calendar days.")]
|
||||
Seller = 1L << 3,
|
||||
|
||||
/// <summary>
|
||||
/// Market Centers will have the ability to identify regular trades being reported during specific events as out of the ordinary
|
||||
/// by appending a new sale condition code Yellow Flag (Y) on each transaction reported to the UTP SIP.
|
||||
/// The new sale condition will be eligible to update all market center and consolidated statistics.
|
||||
/// </summary>
|
||||
[Description("Market Centers will have the ability to identify regular trades being reported during specific events as out of the ordinary " +
|
||||
"by appending a new sale condition code Yellow Flag (Y) on each transaction reported to the UTP SIP." +
|
||||
"The new sale condition will be eligible to update all market center and consolidated statistics.")]
|
||||
YellowFlag = 1L << 4,
|
||||
|
||||
/// <summary>
|
||||
/// The transaction that constituted the trade-through was the execution of an order identified as an Intermarket Sweep Order.
|
||||
/// </summary>
|
||||
[Description("The transaction that constituted the trade-through was the execution of an order identified as an Intermarket Sweep Order.")]
|
||||
IntermarketSweep = 1L << 5,
|
||||
|
||||
/// <summary>
|
||||
/// The trade that constituted the trade-through was a single priced opening transaction by the Market Center.
|
||||
/// </summary>
|
||||
[Description("The trade that constituted the trade-through was a single priced opening transaction by the Market Center.")]
|
||||
OpeningPrints = 1L << 6,
|
||||
|
||||
/// <summary>
|
||||
/// The transaction that constituted the trade-through was a single priced closing transaction by the Market Center.
|
||||
/// </summary>
|
||||
[Description("The transaction that constituted the trade-through was a single priced closing transaction by the Market Center.")]
|
||||
ClosingPrints = 1L << 7,
|
||||
|
||||
/// <summary>
|
||||
/// The trade that constituted the trade-through was a single priced reopening transaction by the Market Center.
|
||||
/// </summary>
|
||||
[Description("The trade that constituted the trade-through was a single priced reopening transaction by the Market Center.")]
|
||||
ReOpeningPrints = 1L << 8,
|
||||
|
||||
/// <summary>
|
||||
/// The transaction that constituted the trade-through was the execution of an order at a price that was not based, directly or indirectly,
|
||||
/// on the quoted price of the security at the time of execution and for which the material terms were not reasonably determinable
|
||||
/// at the time the commitment to execute the order was made.
|
||||
/// </summary>
|
||||
[Description("The transaction that constituted the trade-through was the execution of an order at a price that was not based, directly or indirectly, " +
|
||||
"on the quoted price of the security at the time of execution and for which the material terms were not reasonably determinable " +
|
||||
"at the time the commitment to execute the order was made.")]
|
||||
DerivativelyPriced = 1L << 9,
|
||||
|
||||
/// <summary>
|
||||
/// Trading in extended hours enables investors to react quickly to events that typically occur outside regular market hours, such as earnings reports.
|
||||
/// However, liquidity may be constrained during such Form T trading, resulting in wide bid-ask spreads.
|
||||
/// </summary>
|
||||
[Description("Trading in extended hours enables investors to react quickly to events that typically occur outside regular market hours, such as earnings reports." +
|
||||
"However, liquidity may be constrained during such Form T trading, resulting in wide bid-ask spreads.")]
|
||||
FormT = 1L << 10,
|
||||
|
||||
/// <summary>
|
||||
/// Sold Last is used when a trade prints in sequence but is reported late or printed in conformance to the One or Two Point Rule.
|
||||
/// </summary>
|
||||
[Description("Sold Last is used when a trade prints in sequence but is reported late or printed in conformance to the One or Two Point Rule.")]
|
||||
Sold = 1L << 11,
|
||||
|
||||
/// <summary>
|
||||
/// The transaction that constituted the trade-through was the execution by a trading center of an order for which, at the time
|
||||
/// of receipt of the order, the execution at no worse than a specified price a 'stopped order'
|
||||
/// </summary>
|
||||
[Description("The transaction that constituted the trade-through was the execution by a trading center of an order for which, at the time" +
|
||||
"of receipt of the order, the execution at no worse than a specified price a 'stopped order'")]
|
||||
Stopped = 1L << 12,
|
||||
|
||||
/// <summary>
|
||||
/// Identifies a trade that was executed outside of regular primary market hours and is reported as an extended hours trade.
|
||||
/// </summary>
|
||||
[Description("Identifies a trade that was executed outside of regular primary market hours and is reported as an extended hours trade.")]
|
||||
ExtendedHours = 1L << 13,
|
||||
|
||||
/// <summary>
|
||||
/// Identifies a trade that takes place outside of regular market hours.
|
||||
/// </summary>
|
||||
[Description("Identifies a trade that takes place outside of regular market hours.")]
|
||||
OutOfSequence = 1L << 14,
|
||||
|
||||
/// <summary>
|
||||
/// An execution in two markets when the specialist or Market Maker in the market first receiving the order agrees to execute a portion of it
|
||||
/// at whatever price is realized in another market to which the balance of the order is forwarded for execution.
|
||||
/// </summary>
|
||||
[Description("An execution in two markets when the specialist or Market Maker in the market first receiving the order agrees to execute a portion of it " +
|
||||
"at whatever price is realized in another market to which the balance of the order is forwarded for execution.")]
|
||||
Split = 1L << 15,
|
||||
|
||||
/// <summary>
|
||||
/// A transaction made on the Exchange as a result of an Exchange acquisition.
|
||||
/// </summary>
|
||||
[Description("A transaction made on the Exchange as a result of an Exchange acquisition.")]
|
||||
Acquisition = 1L << 16,
|
||||
|
||||
/// <summary>
|
||||
/// A trade representing an aggregate of two or more regular trades in a security occurring at the same price either simultaneously
|
||||
/// or within the same 60-second period, with no individual trade exceeding 10,000 shares.
|
||||
/// </summary>
|
||||
[Description("A trade representing an aggregate of two or more regular trades in a security occurring at the same price either simultaneously " +
|
||||
"or within the same 60-second period, with no individual trade exceeding 10,000 shares.")]
|
||||
Bunched = 1L << 17,
|
||||
|
||||
/// <summary>
|
||||
/// Stock-Option Trade is used to identify cash equity transactions which are related to options transactions and therefore
|
||||
/// potentially subject to cancellation if market conditions of the options leg(s) prevent the execution of the stock-option
|
||||
/// order at the price agreed upon.
|
||||
/// </summary>
|
||||
[Description("Stock-Option Trade is used to identify cash equity transactions which are related to options transactions and therefore" +
|
||||
"potentially subject to cancellation if market conditions of the options leg(s) prevent the execution of the stock-option" +
|
||||
"order at the price agreed upon.")]
|
||||
StockOption = 1L << 18,
|
||||
|
||||
/// <summary>
|
||||
/// Sale of a large block of stock in such a manner that the price is not adversely affected.
|
||||
/// </summary>
|
||||
[Description("Sale of a large block of stock in such a manner that the price is not adversely affected.")]
|
||||
Distribution = 1L << 19,
|
||||
|
||||
/// <summary>
|
||||
/// A trade where the price reported is based upon an average of the prices for transactions in a security during all or any portion of the trading day.
|
||||
/// </summary>
|
||||
[Description("A trade where the price reported is based upon an average of the prices for transactions in a security during all or any portion of the trading day.")]
|
||||
AveragePrice = 1L << 20,
|
||||
|
||||
/// <summary>
|
||||
/// Indicates that the trade resulted from a Market Center’s crossing session.
|
||||
/// </summary>
|
||||
[Description("Indicates that the trade resulted from a Market Center’s crossing session.")]
|
||||
Cross = 1L << 21,
|
||||
|
||||
/// <summary>
|
||||
/// Indicates a regular market session trade transaction that carries a price that is significantly away from the prevailing consolidated or primary market value at the time of the transaction.
|
||||
/// </summary>
|
||||
[Description("Indicates a regular market session trade transaction that carries a price that is significantly away from the prevailing consolidated or primary market value at the time of the transaction.")]
|
||||
PriceVariation = 1L << 22,
|
||||
|
||||
/// <summary>
|
||||
/// To qualify as a NYSE AMEX Rule 155
|
||||
/// </summary>
|
||||
[Description("To qualify as a NYSE AMEX Rule 155")]
|
||||
Rule155 = 1L << 23,
|
||||
|
||||
/// <summary>
|
||||
/// Indicates the ‘Official’ closing value as determined by a Market Center. This transaction report will contain the market center generated closing price.
|
||||
/// </summary>
|
||||
[Description("Indicates the ‘Official’ closing value as determined by a Market Center. This transaction report will contain the market center generated closing price.")]
|
||||
OfficialClose = 1L << 24,
|
||||
|
||||
/// <summary>
|
||||
/// A sale condition that identifies a trade based on a price at a prior point in time i.e. more than 90 seconds prior to the time of the trade report.
|
||||
/// The execution time of the trade will be the time of the prior reference price.
|
||||
/// </summary>
|
||||
[Description("A sale condition that identifies a trade based on a price at a prior point in time i.e. more than 90 seconds prior to the time of the trade report. " +
|
||||
"The execution time of the trade will be the time of the prior reference price.")]
|
||||
PriorReferencePrice = 1L << 25,
|
||||
|
||||
/// <summary>
|
||||
/// Indicates the ‘Official’ open value as determined by a Market Center. This transaction report will contain the market
|
||||
/// </summary>
|
||||
[Description("Indicates the ‘Official’ open value as determined by a Market Center. This transaction report will contain the market")]
|
||||
OfficialOpen = 1L << 26,
|
||||
|
||||
/// <summary>
|
||||
/// The CAP Election Trade highlights sales as a result of a sweep execution on the NYSE, whereby CAP orders have been elected and executed
|
||||
/// outside the best price bid or offer and the orders appear as repeat trades at subsequent execution prices.
|
||||
/// This indicator provides additional information to market participants that an automatic sweep transaction has occurred with repeat
|
||||
/// trades as one continuous electronic transaction.
|
||||
/// </summary>
|
||||
[Description("The CAP Election Trade highlights sales as a result of a sweep execution on the NYSE, whereby CAP orders have been elected and executed " +
|
||||
"outside the best price bid or offer and the orders appear as repeat trades at subsequent execution prices. " +
|
||||
"This indicator provides additional information to market participants that an automatic sweep transaction has occurred with repeat " +
|
||||
"trades as one continuous electronic transaction.")]
|
||||
CapElection = 1L << 27,
|
||||
|
||||
/// <summary>
|
||||
/// A sale condition code that identifies a NYSE trade that has been automatically executed without the potential benefit of price improvement.
|
||||
/// </summary>
|
||||
[Description("A sale condition code that identifies a NYSE trade that has been automatically executed without the potential benefit of price improvement.")]
|
||||
AutoExecution = 1L << 28,
|
||||
|
||||
/// <summary>
|
||||
/// Denotes whether or not a trade is exempt (Rule 611) and when used jointly with certain Sale Conditions,
|
||||
/// will more fully describe the characteristics of a particular trade.
|
||||
/// </summary>
|
||||
[Description("Denotes whether or not a trade is exempt (Rule 611) and when used jointly with certain Sale Conditions, " +
|
||||
"will more fully describe the characteristics of a particular trade.")]
|
||||
TradeThroughExempt = 1L << 29,
|
||||
|
||||
/// <summary>
|
||||
/// This flag is present in raw data, but AlgoSeek document does not describe it.
|
||||
/// </summary>
|
||||
[Description("This flag is present in raw data, but AlgoSeek document does not describe it.")]
|
||||
UndocumentedFlag = 1L << 30,
|
||||
|
||||
/// <summary>
|
||||
/// Denotes the trade is an odd lot less than a 100 shares.
|
||||
/// </summary>
|
||||
[Description("Denotes the trade is an odd lot less than a 100 shares.")]
|
||||
OddLot = 1L << 31,
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,434 @@
|
||||
/*
|
||||
* 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 NodaTime;
|
||||
using ProtoBuf;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using Newtonsoft.Json;
|
||||
using QuantConnect.Util;
|
||||
using QuantConnect.Data.Market;
|
||||
using System.Collections.Generic;
|
||||
using QuantConnect.Python;
|
||||
|
||||
namespace QuantConnect.Data
|
||||
{
|
||||
/// <summary>
|
||||
/// Abstract base data class of QuantConnect. It is intended to be extended to define
|
||||
/// generic user customizable data types while at the same time implementing the basics of data where possible
|
||||
/// </summary>
|
||||
[ProtoContract(SkipConstructor = true)]
|
||||
[ProtoInclude(8, typeof(Tick))]
|
||||
[ProtoInclude(100, typeof(TradeBar))]
|
||||
[ProtoInclude(200, typeof(QuoteBar))]
|
||||
[ProtoInclude(300, typeof(Dividend))]
|
||||
[ProtoInclude(400, typeof(Split))]
|
||||
[PandasIgnoreMembers]
|
||||
public abstract class BaseData : IBaseData
|
||||
{
|
||||
private decimal _value;
|
||||
|
||||
/// <summary>
|
||||
/// A list of all <see cref="Resolution"/>
|
||||
/// </summary>
|
||||
protected static readonly List<Resolution> AllResolutions =
|
||||
Enum.GetValues(typeof(Resolution)).Cast<Resolution>().ToList();
|
||||
|
||||
/// <summary>
|
||||
/// A list of <see cref="Resolution.Daily"/>
|
||||
/// </summary>
|
||||
protected static readonly List<Resolution> DailyResolution = new List<Resolution> { Resolution.Daily };
|
||||
|
||||
/// <summary>
|
||||
/// A list of <see cref="Resolution.Minute"/>
|
||||
/// </summary>
|
||||
protected static readonly List<Resolution> MinuteResolution = new List<Resolution> { Resolution.Minute };
|
||||
|
||||
/// <summary>
|
||||
/// A list of high <see cref="Resolution"/>, including minute, second, and tick.
|
||||
/// </summary>
|
||||
protected static readonly List<Resolution> HighResolution = new List<Resolution> { Resolution.Minute, Resolution.Second, Resolution.Tick };
|
||||
|
||||
/// <summary>
|
||||
/// A list of resolutions support by Options
|
||||
/// </summary>
|
||||
protected static readonly List<Resolution> OptionResolutions = new List<Resolution> { Resolution.Daily, Resolution.Hour, Resolution.Minute };
|
||||
|
||||
/// <summary>
|
||||
/// Market Data Type of this data - does it come in individual price packets or is it grouped into OHLC.
|
||||
/// </summary>
|
||||
/// <remarks>Data is classed into two categories - streams of instantaneous prices and groups of OHLC data.</remarks>
|
||||
[ProtoMember(1)]
|
||||
public MarketDataType DataType { get; set; } = MarketDataType.Base;
|
||||
|
||||
/// <summary>
|
||||
/// True if this is a fill forward piece of data
|
||||
/// </summary>
|
||||
public bool IsFillForward { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Current time marker of this data packet.
|
||||
/// </summary>
|
||||
/// <remarks>All data is timeseries based.</remarks>
|
||||
[ProtoMember(2)]
|
||||
public DateTime Time { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The end time of this data. Some data covers spans (trade bars) and as such we want
|
||||
/// to know the entire time span covered
|
||||
/// </summary>
|
||||
// NOTE: This is needed event though the class is marked with [PandasIgnoreMembers] because the property is virtual.
|
||||
// If a derived class overrides it, without [PandasIgnore], the property will not be ignored.
|
||||
[PandasIgnore]
|
||||
public virtual DateTime EndTime
|
||||
{
|
||||
get { return Time; }
|
||||
set { Time = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Symbol representation for underlying Security
|
||||
/// </summary>
|
||||
public Symbol Symbol { get; set; } = Symbol.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// Value representation of this data packet. All data requires a representative value for this moment in time.
|
||||
/// For streams of data this is the price now, for OHLC packets this is the closing price.
|
||||
/// </summary>
|
||||
[ProtoMember(4)]
|
||||
[PandasIgnore]
|
||||
public virtual decimal Value
|
||||
{
|
||||
get
|
||||
{
|
||||
return _value;
|
||||
}
|
||||
set
|
||||
{
|
||||
_value = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// As this is a backtesting platform we'll provide an alias of value as price.
|
||||
/// </summary>
|
||||
[PandasIgnore]
|
||||
public virtual decimal Price => Value;
|
||||
|
||||
/// <summary>
|
||||
/// Constructor for initialising the dase data class
|
||||
/// </summary>
|
||||
public BaseData()
|
||||
{
|
||||
//Empty constructor required for fast-reflection initialization
|
||||
}
|
||||
|
||||
/// <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. The returned object is assumed to be time stamped in the config.ExchangeTimeZone.
|
||||
/// </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 virtual BaseData Reader(SubscriptionDataConfig config, string line, DateTime date, bool isLiveMode)
|
||||
{
|
||||
// stub implementation to prevent compile errors in user algorithms
|
||||
var dataFeed = isLiveMode ? DataFeedEndpoint.LiveTrading : DataFeedEndpoint.Backtesting;
|
||||
#pragma warning disable 618 // This implementation is left here for backwards compatibility of the BaseData API
|
||||
return Reader(config, line, date, dataFeed);
|
||||
#pragma warning restore 618
|
||||
}
|
||||
|
||||
/// <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. The returned object is assumed to be time stamped in the config.ExchangeTimeZone.
|
||||
/// </summary>
|
||||
/// <param name="config">Subscription data config setup object</param>
|
||||
/// <param name="stream">The data stream</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 virtual BaseData Reader(SubscriptionDataConfig config, StreamReader stream, DateTime date, bool isLiveMode)
|
||||
{
|
||||
throw new NotImplementedException("Each data types has to implement is own Stream reader");
|
||||
}
|
||||
|
||||
/// <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 virtual SubscriptionDataSource GetSource(SubscriptionDataConfig config, DateTime date, bool isLiveMode)
|
||||
{
|
||||
// stub implementation to prevent compile errors in user algorithms
|
||||
var dataFeed = isLiveMode ? DataFeedEndpoint.LiveTrading : DataFeedEndpoint.Backtesting;
|
||||
#pragma warning disable 618 // This implementation is left here for backwards compatibility of the BaseData API
|
||||
var source = GetSource(config, date, dataFeed);
|
||||
#pragma warning restore 618
|
||||
|
||||
if (isLiveMode)
|
||||
{
|
||||
// live trading by default always gets a rest endpoint
|
||||
return new SubscriptionDataSource(source, SubscriptionTransportMedium.Rest);
|
||||
}
|
||||
|
||||
// construct a uri to determine if we have a local or remote file
|
||||
var uri = new Uri(source, UriKind.RelativeOrAbsolute);
|
||||
|
||||
if (uri.IsAbsoluteUri && !uri.IsLoopback)
|
||||
{
|
||||
return new SubscriptionDataSource(source, SubscriptionTransportMedium.RemoteFile);
|
||||
}
|
||||
|
||||
return new SubscriptionDataSource(source, SubscriptionTransportMedium.LocalFile);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Indicates if there is support for mapping
|
||||
/// </summary>
|
||||
/// <remarks>Relies on the <see cref="Symbol"/> property value</remarks>
|
||||
/// <returns>True indicates mapping should be used</returns>
|
||||
public virtual bool RequiresMapping()
|
||||
{
|
||||
return Symbol.RequiresMapping();
|
||||
}
|
||||
|
||||
/// <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 virtual bool IsSparseData()
|
||||
{
|
||||
// by default, we'll assume all custom data is sparse data
|
||||
return Symbol.SecurityType == SecurityType.Base;
|
||||
}
|
||||
|
||||
/// <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 virtual bool ShouldCacheToSecurity()
|
||||
{
|
||||
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 virtual Resolution DefaultResolution()
|
||||
{
|
||||
return Resolution.Minute;
|
||||
}
|
||||
|
||||
/// <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 virtual List<Resolution> SupportedResolutions()
|
||||
{
|
||||
if (Symbol.SecurityType.IsOption())
|
||||
{
|
||||
return OptionResolutions;
|
||||
}
|
||||
|
||||
return AllResolutions;
|
||||
}
|
||||
|
||||
/// <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 virtual DateTimeZone DataTimeZone()
|
||||
{
|
||||
if (Symbol.SecurityType != SecurityType.Base)
|
||||
{
|
||||
throw new InvalidOperationException("BaseData.DataTimeZone(): is only valid for base data types");
|
||||
}
|
||||
return TimeZones.NewYork;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Updates this base data with a new trade
|
||||
/// </summary>
|
||||
/// <param name="lastTrade">The price of the last trade</param>
|
||||
/// <param name="tradeSize">The quantity traded</param>
|
||||
public void UpdateTrade(decimal lastTrade, decimal tradeSize)
|
||||
{
|
||||
Update(lastTrade, 0, 0, tradeSize, 0, 0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Updates this base data with new quote information
|
||||
/// </summary>
|
||||
/// <param name="bidPrice">The current bid price</param>
|
||||
/// <param name="bidSize">The current bid size</param>
|
||||
/// <param name="askPrice">The current ask price</param>
|
||||
/// <param name="askSize">The current ask size</param>
|
||||
public void UpdateQuote(decimal bidPrice, decimal bidSize, decimal askPrice, decimal askSize)
|
||||
{
|
||||
Update(0, bidPrice, askPrice, 0, bidSize, askSize);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Updates this base data with the new quote bid information
|
||||
/// </summary>
|
||||
/// <param name="bidPrice">The current bid price</param>
|
||||
/// <param name="bidSize">The current bid size</param>
|
||||
public void UpdateBid(decimal bidPrice, decimal bidSize)
|
||||
{
|
||||
Update(0, bidPrice, 0, 0, bidSize, 0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Updates this base data with the new quote ask information
|
||||
/// </summary>
|
||||
/// <param name="askPrice">The current ask price</param>
|
||||
/// <param name="askSize">The current ask size</param>
|
||||
public void UpdateAsk(decimal askPrice, decimal askSize)
|
||||
{
|
||||
Update(0, 0, askPrice, 0, 0, askSize);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Update routine to build a bar/tick from a data update.
|
||||
/// </summary>
|
||||
/// <param name="lastTrade">The last trade price</param>
|
||||
/// <param name="bidPrice">Current bid price</param>
|
||||
/// <param name="askPrice">Current asking price</param>
|
||||
/// <param name="volume">Volume of this trade</param>
|
||||
/// <param name="bidSize">The size of the current bid, if available</param>
|
||||
/// <param name="askSize">The size of the current ask, if available</param>
|
||||
public virtual void Update(decimal lastTrade, decimal bidPrice, decimal askPrice, decimal volume, decimal bidSize, decimal askSize)
|
||||
{
|
||||
Value = lastTrade;
|
||||
}
|
||||
|
||||
/// <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>
|
||||
/// <param name="fillForward">True if this is a fill forward clone</param>
|
||||
/// <returns>A clone of the current object</returns>
|
||||
public virtual BaseData Clone(bool fillForward)
|
||||
{
|
||||
var clone = Clone();
|
||||
clone.IsFillForward = fillForward;
|
||||
return clone;
|
||||
}
|
||||
|
||||
/// <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 virtual BaseData Clone()
|
||||
{
|
||||
return (BaseData) ObjectActivator.Clone((object)this);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Formats a string with the symbol and value.
|
||||
/// </summary>
|
||||
/// <returns>string - a string formatted as SPY: 167.753</returns>
|
||||
public override string ToString()
|
||||
{
|
||||
return $"{Symbol}: {Value.ToStringInvariant("C")}";
|
||||
}
|
||||
|
||||
/// <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>
|
||||
/// <remarks>OBSOLETE:: This implementation is added for backward/forward compatibility purposes. This function is no longer called by the LEAN engine.</remarks>
|
||||
/// <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="dataFeed">Type of datafeed we're requesting - a live or backtest feed.</param>
|
||||
/// <returns>Instance of the T:BaseData object generated by this line of the CSV</returns>
|
||||
[Obsolete("Reader(SubscriptionDataConfig, string, DateTime, DataFeedEndpoint) method has been made obsolete, use Reader(SubscriptionDataConfig, string, DateTime, bool) instead.")]
|
||||
[StubsIgnore]
|
||||
public virtual BaseData Reader(SubscriptionDataConfig config, string line, DateTime date, DataFeedEndpoint dataFeed)
|
||||
{
|
||||
throw new InvalidOperationException(
|
||||
$"Please implement Reader(SubscriptionDataConfig, string, DateTime, bool) on your custom data type: {GetType().Name}"
|
||||
);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Return the URL string source of the file. This will be converted to a stream
|
||||
/// </summary>
|
||||
/// <remarks>OBSOLETE:: This implementation is added for backward/forward compatibility purposes. This function is no longer called by the LEAN engine.</remarks>
|
||||
/// <param name="config">Configuration object</param>
|
||||
/// <param name="date">Date of this source file</param>
|
||||
/// <param name="datafeed">Type of datafeed we're reqesting - backtest or live</param>
|
||||
/// <returns>String URL of source file.</returns>
|
||||
[Obsolete("GetSource(SubscriptionDataConfig, DateTime, DataFeedEndpoint) method has been made obsolete, use GetSource(SubscriptionDataConfig, DateTime, bool) instead.")]
|
||||
[StubsIgnore]
|
||||
public virtual string GetSource(SubscriptionDataConfig config, DateTime date, DataFeedEndpoint datafeed)
|
||||
{
|
||||
throw new InvalidOperationException(
|
||||
$"Please implement GetSource(SubscriptionDataConfig, DateTime, bool) on your custom data type: {GetType().Name}"
|
||||
);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Deserialize the message from the data server
|
||||
/// </summary>
|
||||
/// <param name="serialized">The data server's message</param>
|
||||
/// <returns>An enumerable of base data, if unsuccessful, returns an empty enumerable</returns>
|
||||
public static IEnumerable<BaseData> DeserializeMessage(string serialized)
|
||||
{
|
||||
var deserialized = JsonConvert.DeserializeObject(serialized, JsonSerializerSettings);
|
||||
|
||||
var enumerable = deserialized as IEnumerable<BaseData>;
|
||||
if (enumerable != null)
|
||||
{
|
||||
return enumerable;
|
||||
}
|
||||
|
||||
var data = deserialized as BaseData;
|
||||
if (data != null)
|
||||
{
|
||||
return new[] { data };
|
||||
}
|
||||
|
||||
return Enumerable.Empty<BaseData>();
|
||||
}
|
||||
|
||||
private static readonly JsonSerializerSettings JsonSerializerSettings = new JsonSerializerSettings
|
||||
{
|
||||
TypeNameHandling = TypeNameHandling.All
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -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 QuantConnect.Securities;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace QuantConnect.Data
|
||||
{
|
||||
/// <summary>
|
||||
/// Abstract sharing logic for data requests
|
||||
/// </summary>
|
||||
public abstract class BaseDataRequest
|
||||
{
|
||||
private readonly Lazy<DateTime> _localStartTime;
|
||||
private readonly Lazy<DateTime> _localEndTime;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the beginning of the requested time interval in UTC
|
||||
/// </summary>
|
||||
public DateTime StartTimeUtc { get; protected set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the end of the requested time interval in UTC
|
||||
/// </summary>
|
||||
public DateTime EndTimeUtc { get; protected set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the <see cref="StartTimeUtc"/> in the security's exchange time zone
|
||||
/// </summary>
|
||||
public DateTime StartTimeLocal => _localStartTime.Value;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the <see cref="EndTimeUtc"/> in the security's exchange time zone
|
||||
/// </summary>
|
||||
public DateTime EndTimeLocal => _localEndTime.Value;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the exchange hours used for processing fill forward requests
|
||||
/// </summary>
|
||||
public SecurityExchangeHours ExchangeHours { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the tradable days specified by this request, in the security's data time zone
|
||||
/// </summary>
|
||||
public abstract IEnumerable<DateTime> TradableDaysInDataTimeZone { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets true if this is a custom data request, false for normal QC data
|
||||
/// </summary>
|
||||
public bool IsCustomData { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The data type of this request
|
||||
/// </summary>
|
||||
public Type DataType { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes the base data request
|
||||
/// </summary>
|
||||
/// <param name="startTimeUtc">The start time for this request,</param>
|
||||
/// <param name="endTimeUtc">The start time for this request</param>
|
||||
/// <param name="exchangeHours">The exchange hours for this request</param>
|
||||
/// <param name="tickType">The tick type of this request</param>
|
||||
/// <param name="isCustomData">True if this subscription is for custom data</param>
|
||||
/// <param name="dataType">The data type of the output data</param>
|
||||
protected BaseDataRequest(DateTime startTimeUtc,
|
||||
DateTime endTimeUtc,
|
||||
SecurityExchangeHours exchangeHours,
|
||||
TickType tickType,
|
||||
bool isCustomData,
|
||||
Type dataType)
|
||||
{
|
||||
DataType = dataType;
|
||||
IsCustomData = isCustomData;
|
||||
StartTimeUtc = startTimeUtc;
|
||||
EndTimeUtc = endTimeUtc;
|
||||
ExchangeHours = exchangeHours;
|
||||
|
||||
// open interest data comes in once a day before market open,
|
||||
// make the subscription start from midnight and use always open exchange
|
||||
if (tickType == TickType.OpenInterest)
|
||||
{
|
||||
ExchangeHours = SecurityExchangeHours.AlwaysOpen(ExchangeHours.TimeZone);
|
||||
}
|
||||
|
||||
_localStartTime = new Lazy<DateTime>(() => StartTimeUtc.ConvertFromUtc(ExchangeHours.TimeZone));
|
||||
_localEndTime = new Lazy<DateTime>(() => EndTimeUtc.ConvertFromUtc(ExchangeHours.TimeZone));
|
||||
IsCustomData = isCustomData;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,106 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
namespace QuantConnect.Data
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// Represents a subscription channel
|
||||
/// </summary>
|
||||
public class Channel
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// Represents an internal channel name for all brokerage channels in case we don't differentiate them
|
||||
/// </summary>
|
||||
public static string Single = "common";
|
||||
|
||||
/// <summary>
|
||||
/// The name of the channel
|
||||
/// </summary>
|
||||
public string Name { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// The ticker symbol of the channel
|
||||
/// </summary>
|
||||
public Symbol Symbol { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Creates an instance of subscription channel
|
||||
/// </summary>
|
||||
/// <param name="channelName">Socket channel name</param>
|
||||
/// <param name="symbol">Associated symbol</param>
|
||||
public Channel(string channelName, Symbol symbol)
|
||||
{
|
||||
if (string.IsNullOrEmpty(channelName))
|
||||
{
|
||||
throw new ArgumentNullException(nameof(channelName), "Channel Name can't be null or empty");
|
||||
}
|
||||
|
||||
if (symbol == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(symbol), "Symbol can't be null or empty");
|
||||
}
|
||||
|
||||
Name = channelName;
|
||||
Symbol = symbol;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Indicates whether the current object is equal to another object of the same type.
|
||||
/// </summary>
|
||||
/// <param name="other">An object to compare with this object.</param>
|
||||
/// <returns>
|
||||
/// true if the current object is equal to the <paramref name="other"/> parameter; otherwise, false.
|
||||
/// </returns>
|
||||
public bool Equals(Channel other)
|
||||
{
|
||||
if (ReferenceEquals(null, other)) return false;
|
||||
if (ReferenceEquals(this, other)) return true;
|
||||
return string.Equals(Name, other?.Name) && Symbol.Equals(other.Symbol);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether the specified object is equal to the current object.
|
||||
/// </summary>
|
||||
/// <param name="obj">The object to compare with the current object. </param>
|
||||
/// <returns>
|
||||
/// true if the specified object is equal to the current object; otherwise, false.
|
||||
/// </returns>
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
return Equals(obj as Channel);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Serves as the default hash function.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// A hash code for the current object.
|
||||
/// </returns>
|
||||
public override int GetHashCode()
|
||||
{
|
||||
unchecked
|
||||
{
|
||||
int hash = (int)2166136261;
|
||||
hash = (hash * 16777619) ^ Name.GetHashCode();
|
||||
hash = (hash * 16777619) ^ Symbol.GetHashCode();
|
||||
return hash;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,175 @@
|
||||
/*
|
||||
* 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.Threading;
|
||||
using QuantConnect.Interfaces;
|
||||
using QuantConnect.Data.Consolidators;
|
||||
|
||||
namespace QuantConnect.Data
|
||||
{
|
||||
/// <summary>
|
||||
/// Helper class to wrap a consolidator and keep track of the next scan time we should trigger
|
||||
/// </summary>
|
||||
internal class ConsolidatorWrapper : IDisposable
|
||||
{
|
||||
// helps us guarantee a deterministic ordering by addition/creation
|
||||
private static long _counter;
|
||||
|
||||
private readonly IDataConsolidator _consolidator;
|
||||
private readonly LocalTimeKeeper _localTimeKeeper;
|
||||
private readonly TimeSpan _minimumIncrement;
|
||||
private readonly ITimeKeeper _timeKeeper;
|
||||
private readonly long _id;
|
||||
private TimeSpan? _barSpan;
|
||||
|
||||
/// <summary>
|
||||
/// True if this consolidator has been removed
|
||||
/// </summary>
|
||||
public bool Disposed { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// The next utc scan time
|
||||
/// </summary>
|
||||
public DateTime UtcScanTime { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Get enqueue time
|
||||
/// </summary>
|
||||
public ConsolidatorScanPriority Priority => new(UtcScanTime, _id);
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new instance
|
||||
/// </summary>
|
||||
public ConsolidatorWrapper(IDataConsolidator consolidator, TimeSpan configIncrement, ITimeKeeper timeKeeper, LocalTimeKeeper localTimeKeeper)
|
||||
{
|
||||
_id = Interlocked.Increment(ref _counter);
|
||||
|
||||
_timeKeeper = timeKeeper;
|
||||
_consolidator = consolidator;
|
||||
_localTimeKeeper = localTimeKeeper;
|
||||
|
||||
_minimumIncrement = configIncrement < Time.OneSecond ? Time.OneSecond : configIncrement;
|
||||
|
||||
_consolidator.DataConsolidated += AdvanceScanTime;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Scans the current consolidator
|
||||
/// </summary>
|
||||
public void Scan()
|
||||
{
|
||||
_consolidator.Scan(_localTimeKeeper.LocalTime);
|
||||
|
||||
// it might not of emitted at all, could happen if we got no data or it's not expected to emit like in a weekend
|
||||
// but we still need to advance the next scan time
|
||||
AdvanceScanTime();
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Disposed = true;
|
||||
_consolidator.DataConsolidated -= AdvanceScanTime;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Helper method to set the next scan time
|
||||
/// </summary>
|
||||
public void AdvanceScanTime(object _ = null, IBaseData consolidated = null)
|
||||
{
|
||||
if (consolidated == null && UtcScanTime > _timeKeeper.UtcTime)
|
||||
{
|
||||
// already set
|
||||
return;
|
||||
}
|
||||
|
||||
if (_barSpan.HasValue)
|
||||
{
|
||||
var reference = _timeKeeper.UtcTime;
|
||||
if (consolidated != null)
|
||||
{
|
||||
reference = consolidated.EndTime.ConvertToUtc(_localTimeKeeper.TimeZone);
|
||||
}
|
||||
UtcScanTime = reference + _barSpan.Value;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (consolidated != null)
|
||||
{
|
||||
_barSpan = consolidated.EndTime - consolidated.Time;
|
||||
if (_barSpan < _minimumIncrement)
|
||||
{
|
||||
_barSpan = _minimumIncrement;
|
||||
}
|
||||
|
||||
UtcScanTime = consolidated.EndTime.ConvertToUtc(_localTimeKeeper.TimeZone) + _barSpan.Value;
|
||||
}
|
||||
else if (_consolidator.WorkingData == null)
|
||||
{
|
||||
// we have no reference
|
||||
UtcScanTime = _timeKeeper.UtcTime + _minimumIncrement;
|
||||
}
|
||||
else
|
||||
{
|
||||
var pontetialEndTime = _consolidator.WorkingData.EndTime.ConvertToUtc(_localTimeKeeper.TimeZone);
|
||||
if (pontetialEndTime > _timeKeeper.UtcTime)
|
||||
{
|
||||
UtcScanTime = pontetialEndTime;
|
||||
}
|
||||
else
|
||||
{
|
||||
UtcScanTime = _timeKeeper.UtcTime + _minimumIncrement;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal class ConsolidatorScanPriority
|
||||
{
|
||||
private sealed class UtcScanTimeIdRelationalComparer : IComparer<ConsolidatorScanPriority>
|
||||
{
|
||||
public int Compare(ConsolidatorScanPriority? x, ConsolidatorScanPriority? y)
|
||||
{
|
||||
if (ReferenceEquals(x, y)) return 0;
|
||||
if (y is null) return 1;
|
||||
if (x is null) return -1;
|
||||
var utcScanTimeComparison = x.UtcScanTime.CompareTo(y.UtcScanTime);
|
||||
if (utcScanTimeComparison != 0) return utcScanTimeComparison;
|
||||
return x.Id.CompareTo(y.Id);
|
||||
}
|
||||
}
|
||||
|
||||
public static IComparer<ConsolidatorScanPriority> Comparer { get; } =
|
||||
new UtcScanTimeIdRelationalComparer();
|
||||
|
||||
/// <summary>
|
||||
/// The next utc scan time
|
||||
/// </summary>
|
||||
public DateTime UtcScanTime { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Unique Id of the associated consolidator
|
||||
/// </summary>
|
||||
public long Id { get; }
|
||||
|
||||
public ConsolidatorScanPriority(DateTime utcScanTime, long id)
|
||||
{
|
||||
Id = id;
|
||||
UtcScanTime = utcScanTime;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,115 @@
|
||||
/*
|
||||
* 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;
|
||||
using Python.Runtime;
|
||||
|
||||
namespace QuantConnect.Data.Consolidators
|
||||
{
|
||||
/// <summary>
|
||||
/// Type capable of consolidating trade bars from any base data instance
|
||||
/// </summary>
|
||||
public class BaseDataConsolidator : TradeBarConsolidatorBase<BaseData>
|
||||
{
|
||||
/// <summary>
|
||||
/// Create a new TickConsolidator for the desired resolution
|
||||
/// </summary>
|
||||
/// <param name="resolution">The resolution desired</param>
|
||||
/// <returns>A consolidator that produces data on the resolution interval</returns>
|
||||
public static BaseDataConsolidator FromResolution(Resolution resolution)
|
||||
{
|
||||
return new BaseDataConsolidator(resolution.ToTimeSpan());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a consolidator to produce a new 'TradeBar' representing the period
|
||||
/// </summary>
|
||||
/// <param name="period">The minimum span of time before emitting a consolidated bar</param>
|
||||
public BaseDataConsolidator(TimeSpan period)
|
||||
: base(period)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a consolidator to produce a new 'TradeBar' representing the last count pieces of data
|
||||
/// </summary>
|
||||
/// <param name="maxCount">The number of pieces to accept before emitting a consolidated bar</param>
|
||||
public BaseDataConsolidator(int maxCount)
|
||||
: base(maxCount)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a consolidator to produce a new 'TradeBar' representing the last count pieces of data or the period, whichever comes first
|
||||
/// </summary>
|
||||
/// <param name="maxCount">The number of pieces to accept before emitting a consolidated bar</param>
|
||||
/// <param name="period">The minimum span of time before emitting a consolidated bar</param>
|
||||
public BaseDataConsolidator(int maxCount, TimeSpan period)
|
||||
: base(maxCount, period)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="BaseDataConsolidator"/> class
|
||||
/// </summary>
|
||||
/// <param name="func">Func that defines the start time of a consolidated data</param>
|
||||
public BaseDataConsolidator(Func<DateTime, CalendarInfo> func)
|
||||
: base(func)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="BaseDataConsolidator"/> class
|
||||
/// </summary>
|
||||
/// <param name="pyfuncobj">Func that defines the start time of a consolidated data</param>
|
||||
public BaseDataConsolidator(PyObject pyfuncobj)
|
||||
: base(pyfuncobj)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Aggregates the new 'data' into the 'workingBar'. The 'workingBar' will be
|
||||
/// null following the event firing
|
||||
/// </summary>
|
||||
/// <param name="workingBar">The bar we're building, null if the event was just fired and we're starting a new trade bar</param>
|
||||
/// <param name="data">The new data</param>
|
||||
protected override void AggregateBar(ref TradeBar workingBar, BaseData data)
|
||||
{
|
||||
if (workingBar == null)
|
||||
{
|
||||
workingBar = new TradeBar
|
||||
{
|
||||
Symbol = data.Symbol,
|
||||
Time = GetRoundedBarTime(data.Time),
|
||||
Close = data.Value,
|
||||
High = data.Value,
|
||||
Low = data.Value,
|
||||
Open = data.Value,
|
||||
DataType = data.DataType,
|
||||
Value = data.Value
|
||||
};
|
||||
}
|
||||
else
|
||||
{
|
||||
//Aggregate the working bar
|
||||
workingBar.Close = data.Value;
|
||||
if (data.Value < workingBar.Low) workingBar.Low = data.Value;
|
||||
if (data.Value > workingBar.High) workingBar.High = data.Value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,194 @@
|
||||
/*
|
||||
* 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 Python.Runtime;
|
||||
using System;
|
||||
using QuantConnect.Data.Market;
|
||||
|
||||
namespace QuantConnect.Data.Consolidators
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a timeless consolidator which depends on the given values. This consolidator
|
||||
/// is meant to consolidate data into bars that do not depend on time, e.g., RangeBar's.
|
||||
/// </summary>
|
||||
public abstract class BaseTimelessConsolidator<T> : ConsolidatorBase
|
||||
where T : IBaseData
|
||||
{
|
||||
/// <summary>
|
||||
/// Extracts the value from a data instance to be formed into a <see cref="T"/>.
|
||||
/// </summary>
|
||||
protected Func<IBaseData, decimal> Selector { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Extracts the volume from a data instance. The default value is null which does
|
||||
/// not aggregate volume per bar.
|
||||
/// </summary>
|
||||
protected Func<IBaseData, decimal> VolumeSelector { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Bar being created
|
||||
/// </summary>
|
||||
protected virtual T CurrentBar { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets a clone of the data being currently consolidated
|
||||
/// </summary>
|
||||
public abstract override IBaseData WorkingData { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the type consumed by this consolidator
|
||||
/// </summary>
|
||||
public override Type InputType => typeof(IBaseData);
|
||||
|
||||
/// <summary>
|
||||
/// Gets <see cref="T"/> which is the type emitted in the <see cref="IDataConsolidator.DataConsolidated"/> event.
|
||||
/// </summary>
|
||||
public override Type OutputType => typeof(T);
|
||||
|
||||
/// <summary>
|
||||
/// Typed event handler that fires when a new piece of data is produced
|
||||
/// </summary>
|
||||
public new event EventHandler<T> DataConsolidated;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="BaseTimelessConsolidator{T}" /> class.
|
||||
/// </summary>
|
||||
/// <param name="selector">Extracts the value from a data instance to be formed into a new bar which inherits from <see cref="IBaseData"/>. The default
|
||||
/// value is (x => x.Value) the <see cref="IBaseData.Value"/> property on <see cref="IBaseData"/></param>
|
||||
/// <param name="volumeSelector">Extracts the volume from a data instance. The default value is null which does
|
||||
/// not aggregate volume per bar.</param>
|
||||
protected BaseTimelessConsolidator(Func<IBaseData, decimal> selector = null, Func<IBaseData, decimal> volumeSelector = null)
|
||||
{
|
||||
Selector = selector ?? (x => x.Value);
|
||||
VolumeSelector = volumeSelector ?? (x => x is TradeBar bar ? bar.Volume : (x is Tick tick ? tick.Quantity : 0));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="BaseTimelessConsolidator{T}" /> class.
|
||||
/// </summary>
|
||||
/// <param name="valueSelector">Extracts the value from a data instance to be formed into a new bar which inherits from <see cref="IBaseData"/>. The default
|
||||
/// value is (x => x.Value) the <see cref="IBaseData.Value"/> property on <see cref="IBaseData"/></param>
|
||||
/// <param name="volumeSelector">Extracts the volume from a data instance. The default value is null which does
|
||||
/// not aggregate volume per bar.</param>
|
||||
protected BaseTimelessConsolidator(PyObject valueSelector, PyObject volumeSelector = null)
|
||||
: this (TryToConvertSelector(valueSelector, nameof(valueSelector)), TryToConvertSelector(volumeSelector, nameof(volumeSelector)))
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tries to convert the given python selector to a C# one. If the conversion is not
|
||||
/// possible it returns null
|
||||
/// </summary>
|
||||
/// <param name="selector">The python selector to be converted</param>
|
||||
/// <param name="selectorName">The name of the selector to be used in case an exception is thrown</param>
|
||||
/// <exception cref="ArgumentException">This exception will be thrown if it's not possible to convert the
|
||||
/// given python selector to C#</exception>
|
||||
private static Func<IBaseData, decimal> TryToConvertSelector(PyObject selector, string selectorName)
|
||||
{
|
||||
using (Py.GIL())
|
||||
{
|
||||
Func<IBaseData, decimal> resultSelector;
|
||||
if (selector != null && !selector.IsNone())
|
||||
{
|
||||
if (!selector.TrySafeAs(out resultSelector))
|
||||
{
|
||||
throw new ArgumentException(
|
||||
$"Unable to convert parameter {selectorName} to delegate type Func<IBaseData, decimal>");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
resultSelector = null;
|
||||
}
|
||||
|
||||
return resultSelector;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Updates this consolidator with the specified data
|
||||
/// </summary>
|
||||
/// <param name="data">The new data for the consolidator</param>
|
||||
public override void Update(IBaseData data)
|
||||
{
|
||||
var currentValue = Selector(data);
|
||||
var volume = VolumeSelector(data);
|
||||
|
||||
// If we're already in a bar then update it
|
||||
if (CurrentBar != null)
|
||||
{
|
||||
UpdateBar(data.Time, currentValue, volume);
|
||||
}
|
||||
|
||||
// The state of the CurrentBar could have changed after UpdateBar(),
|
||||
// then we might need to create a new bar
|
||||
if (CurrentBar == null)
|
||||
{
|
||||
CreateNewBar(data, currentValue, volume);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Updates the current RangeBar being created with the given data.
|
||||
/// Additionally, if it's the case, it consolidates the current RangeBar
|
||||
/// </summary>
|
||||
/// <param name="time">Time of the given data</param>
|
||||
/// <param name="currentValue">Value of the given data</param>
|
||||
/// <param name="volume">Volume of the given data</param>
|
||||
protected abstract void UpdateBar(DateTime time, decimal currentValue, decimal volume);
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new bar with the given data
|
||||
/// </summary>
|
||||
/// <param name="data">The new data for the bar</param>
|
||||
/// <param name="currentValue">The new value for the bar</param>
|
||||
/// <param name="volume">The new volume to the bar</param>
|
||||
protected abstract void CreateNewBar(IBaseData data, decimal currentValue, decimal volume);
|
||||
|
||||
/// <summary>
|
||||
/// Raises the strongly typed DataConsolidated event
|
||||
/// </summary>
|
||||
/// <param name="consolidated">The newly consolidated data</param>
|
||||
protected override void FireDataConsolidated(IBaseData consolidated)
|
||||
{
|
||||
DataConsolidated?.Invoke(this, (T)consolidated);
|
||||
}
|
||||
|
||||
/// <summary>Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.</summary>
|
||||
/// <filterpriority>2</filterpriority>
|
||||
public override void Dispose()
|
||||
{
|
||||
DataConsolidated = null;
|
||||
base.Dispose();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Resets the consolidator
|
||||
/// </summary>
|
||||
public override void Reset()
|
||||
{
|
||||
CurrentBar = default(T);
|
||||
base.Reset();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Scans this consolidator to see if it should emit a bar due to time passing
|
||||
/// </summary>
|
||||
/// <param name="currentLocalTime">The current time in the local time zone (same as <see cref="BaseData.Time"/>)</param>
|
||||
public override void Scan(DateTime currentLocalTime)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,173 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
namespace QuantConnect.Data.Consolidators
|
||||
{
|
||||
/// <summary>
|
||||
/// Helper class that provides <see cref="Func{DateTime,CalendarInfo}"/> used to define consolidation calendar
|
||||
/// </summary>
|
||||
public static class Calendar
|
||||
{
|
||||
/// <summary>
|
||||
/// Computes the start of week (previous Monday) of given date/time
|
||||
/// </summary>
|
||||
public static Func<DateTime, CalendarInfo> Weekly
|
||||
{
|
||||
get
|
||||
{
|
||||
return dt =>
|
||||
{
|
||||
var start = Expiry.EndOfWeek(dt).AddDays(-7);
|
||||
return new CalendarInfo(start, TimeSpan.FromDays(7));
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Computes the start of month (1st of the current month) of given date/time
|
||||
/// </summary>
|
||||
public static Func<DateTime, CalendarInfo> Monthly
|
||||
{
|
||||
get
|
||||
{
|
||||
return dt =>
|
||||
{
|
||||
var start = dt.AddDays(1 - dt.Day).Date;
|
||||
var end = Expiry.EndOfMonth(dt);
|
||||
return new CalendarInfo(start, end - start);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Computes the start of quarter (1st of the starting month of current quarter) of given date/time
|
||||
/// </summary>
|
||||
public static Func<DateTime, CalendarInfo> Quarterly
|
||||
{
|
||||
get
|
||||
{
|
||||
return dt =>
|
||||
{
|
||||
var nthQuarter = (dt.Month - 1) / 3;
|
||||
var firstMonthOfQuarter = nthQuarter * 3 + 1;
|
||||
var start = new DateTime(dt.Year, firstMonthOfQuarter, 1);
|
||||
var end = Expiry.EndOfQuarter(dt);
|
||||
return new CalendarInfo(start, end - start);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Computes the start of year (1st of the current year) of given date/time
|
||||
/// </summary>
|
||||
public static Func<DateTime, CalendarInfo> Yearly
|
||||
{
|
||||
get
|
||||
{
|
||||
return dt =>
|
||||
{
|
||||
var start = dt.AddDays(1 - dt.DayOfYear).Date;
|
||||
var end = Expiry.EndOfYear(dt);
|
||||
return new CalendarInfo(start, end - start);
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Calendar Info for storing information related to the start and period of a consolidator
|
||||
/// </summary>
|
||||
public readonly struct CalendarInfo
|
||||
{
|
||||
/// <summary>
|
||||
/// Calendar Start
|
||||
/// </summary>
|
||||
public DateTime Start { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Consolidation Period
|
||||
/// </summary>
|
||||
public TimeSpan Period { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Calendar End
|
||||
/// </summary>
|
||||
public readonly DateTime End => Start + Period;
|
||||
|
||||
/// <summary>
|
||||
/// Constructor for CalendarInfo; used for consolidation calendar
|
||||
/// </summary>
|
||||
/// <param name="start">Calendar Start</param>
|
||||
/// <param name="period">Consolidation Period</param>
|
||||
public CalendarInfo(DateTime start, TimeSpan period)
|
||||
{
|
||||
Start = start;
|
||||
Period = period;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a string containing the Calendar start and the consolidation period
|
||||
/// </summary>
|
||||
public override string ToString()
|
||||
{
|
||||
return $"{Start} {Period}";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Indicates whether the given object is equal to this object, this is, the Calendar start
|
||||
/// and consolidation period is the same for both
|
||||
/// </summary>
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
if (obj is not CalendarInfo other)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return Start == other.Start && Period == other.Period;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the hash code for this object as an integer
|
||||
/// </summary>
|
||||
public override int GetHashCode()
|
||||
{
|
||||
unchecked
|
||||
{
|
||||
var hashCode = Start.GetHashCode();
|
||||
return (hashCode * 397) ^ Period.GetHashCode();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Indicates whether the given object is equal to this object, this is, the Calendar start
|
||||
/// and consolidation period is the same for both
|
||||
/// </summary>
|
||||
public static bool operator ==(CalendarInfo left, CalendarInfo right)
|
||||
{
|
||||
return left.Equals(right);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Indicates whether the given object is equal to this object, this is, the Calendar start
|
||||
/// and consolidation period is the same for both
|
||||
/// </summary>
|
||||
public static bool operator !=(CalendarInfo left, CalendarInfo right)
|
||||
{
|
||||
return !(left == right);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
namespace QuantConnect.Data.Consolidators
|
||||
{
|
||||
/// <summary>
|
||||
/// Calendar Type Class; now obsolete routes functions to <see cref="Calendar"/>
|
||||
/// </summary>
|
||||
[Obsolete("CalendarType is obsolete, please use Calendar instead")]
|
||||
public static class CalendarType
|
||||
{
|
||||
/// <summary>
|
||||
/// Computes the start of week (previous Monday) of given date/time
|
||||
/// </summary>
|
||||
public static Func<DateTime, CalendarInfo> Weekly => Calendar.Weekly;
|
||||
|
||||
/// <summary>
|
||||
/// Computes the start of month (1st of the current month) of given date/time
|
||||
/// </summary>
|
||||
public static Func<DateTime, CalendarInfo> Monthly => Calendar.Monthly;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
/*
|
||||
* 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;
|
||||
using Python.Runtime;
|
||||
|
||||
namespace QuantConnect.Data.Consolidators
|
||||
{
|
||||
/// <summary>
|
||||
/// This consolidator can transform a stream of <see cref="IBaseData"/> instances into a stream of <see cref="RangeBar"/>.
|
||||
/// The difference between this consolidator and <see cref="RangeConsolidator"/>, is that this last one creates intermediate/
|
||||
/// phantom RangeBar's (RangeBar's with zero volume) if the price rises up or falls down by above/below two times the range
|
||||
/// size. Therefore, <see cref="RangeConsolidator"/> leaves no space between two adyacent RangeBar's since it always start
|
||||
/// a new RangeBar one range above the last RangeBar's High value or one range below the last RangeBar's Low value, where
|
||||
/// one range equals to one minimum price change.
|
||||
/// </summary>
|
||||
public class ClassicRangeConsolidator : RangeConsolidator
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ClassicRangeConsolidator" /> class.
|
||||
/// </summary>
|
||||
/// <param name="range">The Range interval sets the range in which the price moves, which in turn initiates the formation of a new bar.
|
||||
/// One range equals to one minimum price change, where this last value is defined depending of the RangeBar's symbol</param>
|
||||
/// <param name="selector">Extracts the value from a data instance to be formed into a <see cref="RangeBar"/>. The default
|
||||
/// value is (x => x.Value) the <see cref="IBaseData.Value"/> property on <see cref="IBaseData"/></param>
|
||||
/// <param name="volumeSelector">Extracts the volume from a data instance. The default value is null which does
|
||||
/// not aggregate volume per bar, except if the input is a TradeBar.</param>
|
||||
public ClassicRangeConsolidator(
|
||||
int range,
|
||||
Func<IBaseData, decimal> selector = null,
|
||||
Func<IBaseData, decimal> volumeSelector = null)
|
||||
: base(range, selector, volumeSelector)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="RangeConsolidator" /> class.
|
||||
/// </summary>
|
||||
/// <param name="range">The Range interval sets the range in which the price moves, which in turn initiates the formation of a new bar.
|
||||
/// One range equals to one minimum price change, where this last value is defined depending of the RangeBar's symbol</param>
|
||||
/// <param name="selector">Extracts the value from a data instance to be formed into a <see cref="RangeBar"/>. The default
|
||||
/// value is (x => x.Value) the <see cref="IBaseData.Value"/> property on <see cref="IBaseData"/></param>
|
||||
/// <param name="volumeSelector">Extracts the volume from a data instance. The default value is null which does
|
||||
/// not aggregate volume per bar.</param>
|
||||
public ClassicRangeConsolidator(int range,
|
||||
PyObject selector,
|
||||
PyObject volumeSelector = null)
|
||||
: base(range, selector, volumeSelector)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Updates the current RangeBar being created with the given data.
|
||||
/// Additionally, if it's the case, it consolidates the current RangeBar
|
||||
/// </summary>
|
||||
/// <param name="time">Time of the given data</param>
|
||||
/// <param name="currentValue">Value of the given data</param>
|
||||
/// <param name="volume">Volume of the given data</param>
|
||||
protected override void UpdateBar(DateTime time, decimal currentValue, decimal volume)
|
||||
{
|
||||
CurrentBar.Update(time, currentValue, volume);
|
||||
|
||||
if (CurrentBar.IsClosed)
|
||||
{
|
||||
OnDataConsolidated(CurrentBar);
|
||||
CurrentBar = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,241 @@
|
||||
/*
|
||||
* 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 QuantConnect.Data.Market;
|
||||
|
||||
namespace QuantConnect.Data.Consolidators
|
||||
{
|
||||
/// <summary>
|
||||
/// This consolidator can transform a stream of <see cref="IBaseData"/> instances into a stream of <see cref="RenkoBar"/>
|
||||
/// </summary>
|
||||
public class ClassicRenkoConsolidator : BaseTimelessConsolidator<RenkoBar>
|
||||
{
|
||||
private decimal _barSize;
|
||||
private bool _evenBars;
|
||||
private decimal? _lastCloseValue;
|
||||
|
||||
/// <summary>
|
||||
/// Bar being created
|
||||
/// </summary>
|
||||
protected override RenkoBar CurrentBar { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the kind of the bar
|
||||
/// </summary>
|
||||
public RenkoType Type => RenkoType.Classic;
|
||||
|
||||
/// <summary>
|
||||
/// Gets a clone of the data being currently consolidated
|
||||
/// </summary>
|
||||
public override IBaseData WorkingData => CurrentBar?.Clone();
|
||||
|
||||
/// <summary>
|
||||
/// Gets <see cref="RenkoBar"/> which is the type emitted in the <see cref="IDataConsolidator.DataConsolidated"/> event.
|
||||
/// </summary>
|
||||
public override Type OutputType => typeof(RenkoBar);
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ClassicRenkoConsolidator"/> class using the specified <paramref name="barSize"/>.
|
||||
/// The value selector will by default select <see cref="IBaseData.Value"/>
|
||||
/// The volume selector will by default select zero.
|
||||
/// </summary>
|
||||
/// <param name="barSize">The constant value size of each bar</param>
|
||||
/// <param name="evenBars">When true bar open/close will be a multiple of the barSize</param>
|
||||
public ClassicRenkoConsolidator(decimal barSize, bool evenBars = true)
|
||||
: base()
|
||||
{
|
||||
EpsilonCheck(barSize);
|
||||
_barSize = barSize;
|
||||
_evenBars = evenBars;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ClassicRenkoConsolidator" /> class.
|
||||
/// </summary>
|
||||
/// <param name="barSize">The size of each bar in units of the value produced by <paramref name="selector"/></param>
|
||||
/// <param name="selector">Extracts the value from a data instance to be formed into a <see cref="RenkoBar"/>. The default
|
||||
/// value is (x => x.Value) the <see cref="IBaseData.Value"/> property on <see cref="IBaseData"/></param>
|
||||
/// <param name="volumeSelector">Extracts the volume from a data instance. The default value is null which does
|
||||
/// not aggregate volume per bar.</param>
|
||||
/// <param name="evenBars">When true bar open/close will be a multiple of the barSize</param>
|
||||
public ClassicRenkoConsolidator(
|
||||
decimal barSize,
|
||||
Func<IBaseData, decimal> selector,
|
||||
Func<IBaseData, decimal> volumeSelector = null,
|
||||
bool evenBars = true)
|
||||
: base(selector, volumeSelector)
|
||||
{
|
||||
EpsilonCheck(barSize);
|
||||
_barSize = barSize;
|
||||
_evenBars = evenBars;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///Initializes a new instance of the <see cref="ClassicRenkoConsolidator" /> class.
|
||||
/// </summary>
|
||||
/// <param name="barSize">The constant value size of each bar</param>
|
||||
/// <param name="type">The RenkoType of the bar</param>
|
||||
[Obsolete("Please use the new RenkoConsolidator if RenkoType is not Classic")]
|
||||
public ClassicRenkoConsolidator(decimal barSize, RenkoType type)
|
||||
: this(barSize, true)
|
||||
{
|
||||
if (type != RenkoType.Classic)
|
||||
{
|
||||
throw new ArgumentException("Please use the new RenkoConsolidator type if RenkoType is not Classic");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ClassicRenkoConsolidator" /> class.
|
||||
/// </summary>
|
||||
/// <param name="barSize">The size of each bar in units of the value produced by <paramref name="selector"/></param>
|
||||
/// <param name="selector">Extracts the value from a data instance to be formed into a <see cref="RenkoBar"/>. The default
|
||||
/// value is (x => x.Value) the <see cref="IBaseData.Value"/> property on <see cref="IBaseData"/></param>
|
||||
/// <param name="volumeSelector">Extracts the volume from a data instance. The default value is null which does
|
||||
/// not aggregate volume per bar.</param>
|
||||
/// <param name="evenBars">When true bar open/close will be a multiple of the barSize</param>
|
||||
public ClassicRenkoConsolidator(decimal barSize,
|
||||
PyObject selector,
|
||||
PyObject volumeSelector = null,
|
||||
bool evenBars = true)
|
||||
: base(selector, volumeSelector)
|
||||
{
|
||||
EpsilonCheck(barSize);
|
||||
_barSize = barSize;
|
||||
_evenBars = evenBars;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Resets the ClassicRenkoConsolidator
|
||||
/// </summary>
|
||||
public override void Reset()
|
||||
{
|
||||
base.Reset();
|
||||
_lastCloseValue = null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Updates the current RangeBar being created with the given data.
|
||||
/// Additionally, if it's the case, it consolidates the current RangeBar
|
||||
/// </summary>
|
||||
/// <param name="time">Time of the given data</param>
|
||||
/// <param name="currentValue">Value of the given data</param>
|
||||
/// <param name="volume">Volume of the given data</param>
|
||||
protected override void UpdateBar(DateTime time, decimal currentValue, decimal volume)
|
||||
{
|
||||
CurrentBar.Update(time, currentValue, volume);
|
||||
|
||||
if (CurrentBar.IsClosed)
|
||||
{
|
||||
_lastCloseValue = CurrentBar.Close;
|
||||
OnDataConsolidated(CurrentBar);
|
||||
CurrentBar = null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new bar with the given data
|
||||
/// </summary>
|
||||
/// <param name="data">The new data for the bar</param>
|
||||
/// <param name="currentValue">The new value for the bar</param>
|
||||
/// <param name="volume">The new volume to the bar</param>
|
||||
protected override void CreateNewBar(IBaseData data, decimal currentValue, decimal volume)
|
||||
{
|
||||
var open = _lastCloseValue ?? currentValue;
|
||||
if (_evenBars && !_lastCloseValue.HasValue)
|
||||
{
|
||||
open = Math.Ceiling(open / _barSize) * _barSize;
|
||||
}
|
||||
|
||||
CurrentBar = new RenkoBar(data.Symbol, data.Time, _barSize, open, volume);
|
||||
}
|
||||
|
||||
private static void EpsilonCheck(decimal barSize)
|
||||
{
|
||||
if (barSize < Extensions.GetDecimalEpsilon())
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(barSize),
|
||||
"RenkoConsolidator bar size must be positve and greater than 1e-28");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Provides a type safe wrapper on the RenkoConsolidator class. This just allows us to define our selector functions with the real type they'll be receiving
|
||||
/// </summary>
|
||||
/// <typeparam name="TInput"></typeparam>
|
||||
public class ClassicRenkoConsolidator<TInput> : ClassicRenkoConsolidator
|
||||
where TInput : IBaseData
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ClassicRenkoConsolidator" /> class.
|
||||
/// </summary>
|
||||
/// <param name="barSize">The size of each bar in units of the value produced by <paramref name="selector"/></param>
|
||||
/// <param name="selector">Extracts the value from a data instance to be formed into a <see cref="RenkoBar"/>. The default
|
||||
/// value is (x => x.Value) the <see cref="IBaseData.Value"/> property on <see cref="IBaseData"/></param>
|
||||
/// <param name="volumeSelector">Extracts the volume from a data instance. The default value is null which does
|
||||
/// not aggregate volume per bar.</param>
|
||||
/// <param name="evenBars">When true bar open/close will be a multiple of the barSize</param>
|
||||
public ClassicRenkoConsolidator(
|
||||
decimal barSize,
|
||||
Func<TInput, decimal> selector,
|
||||
Func<TInput, decimal> volumeSelector = null,
|
||||
bool evenBars = true
|
||||
)
|
||||
: base(barSize, x => selector((TInput) x),
|
||||
volumeSelector == null ? (Func<IBaseData, decimal>) null : x => volumeSelector((TInput) x), evenBars)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ClassicRenkoConsolidator"/> class using the specified <paramref name="barSize"/>.
|
||||
/// The value selector will by default select <see cref="IBaseData.Value"/>
|
||||
/// The volume selector will by default select zero.
|
||||
/// </summary>
|
||||
/// <param name="barSize">The constant value size of each bar</param>
|
||||
/// <param name="evenBars">When true bar open/close will be a multiple of the barSize</param>
|
||||
public ClassicRenkoConsolidator(decimal barSize, bool evenBars = true)
|
||||
: this(barSize, x => x.Value, x => 0, evenBars)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ClassicRenkoConsolidator"/> class using the specified <paramref name="barSize"/>.
|
||||
/// The value selector will by default select <see cref="IBaseData.Value"/>
|
||||
/// The volume selector will by default select zero.
|
||||
/// </summary>
|
||||
/// <param name="barSize">The constant value size of each bar</param>
|
||||
/// <param name="type">The RenkoType of the bar</param>
|
||||
[Obsolete("Please use the WickedRenkoConsolidator if RenkoType is not Classic")]
|
||||
public ClassicRenkoConsolidator(decimal barSize, RenkoType type)
|
||||
: base(barSize, type)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Updates this consolidator with the specified data.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Type safe shim method.
|
||||
/// </remarks>
|
||||
/// <param name="data">The new data for the consolidator</param>
|
||||
public void Update(TInput data)
|
||||
{
|
||||
base.Update(data);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,132 @@
|
||||
/*
|
||||
* 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.Indicators;
|
||||
|
||||
namespace QuantConnect.Data.Consolidators
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides a base implementation for consolidators, including a built-in rolling window
|
||||
/// that stores the history of consolidated bars.
|
||||
/// </summary>
|
||||
public abstract class ConsolidatorBase : WindowBase<IBaseData>, IDataConsolidator
|
||||
{
|
||||
private IBaseData _consolidated;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the most recently consolidated piece of data. This will be null if this consolidator
|
||||
/// has not produced any data yet.
|
||||
/// </summary>
|
||||
public IBaseData Consolidated
|
||||
{
|
||||
get
|
||||
{
|
||||
return _consolidated;
|
||||
}
|
||||
protected set
|
||||
{
|
||||
_consolidated = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a clone of the data being currently consolidated
|
||||
/// </summary>
|
||||
public abstract IBaseData WorkingData { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the type consumed by this consolidator
|
||||
/// </summary>
|
||||
public abstract Type InputType { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the type produced by this consolidator
|
||||
/// </summary>
|
||||
public abstract Type OutputType { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Updates this consolidator with the specified data
|
||||
/// </summary>
|
||||
/// <param name="data">The new data for the consolidator</param>
|
||||
public abstract void Update(IBaseData data);
|
||||
|
||||
/// <summary>
|
||||
/// Scans this consolidator to see if it should emit a bar due to time passing
|
||||
/// </summary>
|
||||
/// <param name="currentLocalTime">The current time in the local time zone (same as <see cref="BaseData.Time"/>)</param>
|
||||
public abstract void Scan(DateTime currentLocalTime);
|
||||
|
||||
/// <summary>
|
||||
/// Event handler that fires when a new piece of data is produced. This is the single subscription
|
||||
/// point, shared by the <see cref="IDataConsolidator"/> interface and by derived consolidators whose
|
||||
/// output is a base data bar, so subscribing and unsubscribing always target the same handler list.
|
||||
/// </summary>
|
||||
public event DataConsolidatedHandler DataConsolidated;
|
||||
|
||||
/// <summary>
|
||||
/// Event invocator for the DataConsolidated event. Populates the rolling window, raises the
|
||||
/// strongly typed and interface events, and finally updates the <see cref="Consolidated"/> property.
|
||||
/// </summary>
|
||||
protected virtual void OnDataConsolidated(IBaseData consolidated)
|
||||
{
|
||||
// populate the rolling window before firing any event so that, inside a DataConsolidated
|
||||
// handler, consolidator[0] is the bar that was just produced. Skip null bars, an out of order
|
||||
// data point can produce a null bar in count mode, so we never push null nor wipe the history
|
||||
if (consolidated != null)
|
||||
{
|
||||
Current = consolidated;
|
||||
}
|
||||
|
||||
// let derived consolidators raise their strongly typed DataConsolidated event
|
||||
FireDataConsolidated(consolidated);
|
||||
|
||||
DataConsolidated?.Invoke(this, consolidated);
|
||||
|
||||
// assign the Consolidated property after the event handlers are fired,
|
||||
// this allows the event handlers to look at the new consolidated data
|
||||
// and the previous consolidated data at the same time without extra bookkeeping
|
||||
Consolidated = consolidated;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Raises the strongly typed DataConsolidated event exposed by derived consolidators that produce a
|
||||
/// more specific bar type. Invoked after the rolling window is populated and before the shared event
|
||||
/// so every handler sees the same window. Consolidators whose output is a base data bar do not need
|
||||
/// to override this, the shared <see cref="DataConsolidated"/> event already carries their bar.
|
||||
/// </summary>
|
||||
/// <param name="consolidated">The newly consolidated data</param>
|
||||
protected virtual void FireDataConsolidated(IBaseData consolidated)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
|
||||
/// </summary>
|
||||
public virtual void Dispose()
|
||||
{
|
||||
DataConsolidated = null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Resets this consolidator, clearing consolidated data and the rolling window.
|
||||
/// </summary>
|
||||
public virtual void Reset()
|
||||
{
|
||||
Consolidated = null;
|
||||
ResetWindow();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
namespace QuantConnect.Data.Consolidators
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a type that consumes BaseData instances and fires an event with consolidated
|
||||
/// and/or aggregated data.
|
||||
/// </summary>
|
||||
/// <typeparam name="TInput">The type consumed by the consolidator</typeparam>
|
||||
public abstract class DataConsolidator<TInput> : ConsolidatorBase
|
||||
where TInput : IBaseData
|
||||
{
|
||||
/// <summary>
|
||||
/// Updates this consolidator with the specified data
|
||||
/// </summary>
|
||||
/// <param name="data">The new data for the consolidator</param>
|
||||
public override void Update(IBaseData data)
|
||||
{
|
||||
if (!(data is TInput))
|
||||
{
|
||||
throw new ArgumentNullException(nameof(data),
|
||||
$"Received type of {data.GetType().Name} but expected {typeof(TInput).Name}"
|
||||
);
|
||||
}
|
||||
Update((TInput)data);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Scans this consolidator to see if it should emit a bar due to time passing
|
||||
/// </summary>
|
||||
/// <param name="currentLocalTime">The current time in the local time zone (same as <see cref="BaseData.Time"/>)</param>
|
||||
public abstract override void Scan(DateTime currentLocalTime);
|
||||
|
||||
/// <summary>
|
||||
/// Gets a clone of the data being currently consolidated
|
||||
/// </summary>
|
||||
public abstract override IBaseData WorkingData { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the type consumed by this consolidator
|
||||
/// </summary>
|
||||
public override Type InputType => typeof(TInput);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the type produced by this consolidator
|
||||
/// </summary>
|
||||
public abstract override Type OutputType { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Updates this consolidator with the specified data. This method is
|
||||
/// responsible for raising the DataConsolidated event
|
||||
/// </summary>
|
||||
/// <param name="data">The new data for the consolidator</param>
|
||||
public abstract void Update(TInput data);
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* 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 QuantConnect.Data.Market;
|
||||
using QuantConnect.Data.Consolidators;
|
||||
using QuantConnect.Data;
|
||||
|
||||
namespace Common.Data.Consolidators
|
||||
{
|
||||
/// <summary>
|
||||
/// This consolidator transforms a stream of <see cref="BaseData"/> instances into a stream of <see cref="RenkoBar"/>
|
||||
/// with a constant dollar volume for each bar.
|
||||
/// </summary>
|
||||
public class DollarVolumeRenkoConsolidator : VolumeRenkoConsolidator
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="DollarVolumeRenkoConsolidator"/> class using the specified <paramref name="barSize"/>.
|
||||
/// </summary>
|
||||
/// <param name="barSize">The constant dollar volume size of each bar</param>
|
||||
public DollarVolumeRenkoConsolidator(decimal barSize)
|
||||
: base(barSize)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts raw volume into dollar volume by multiplying it with the trade price.
|
||||
/// </summary>
|
||||
/// <param name="volume">The raw trade volume</param>
|
||||
/// <param name="price">The trade price</param>
|
||||
/// <returns>The dollar volume</returns>
|
||||
protected override decimal AdjustVolume(decimal volume, decimal price)
|
||||
{
|
||||
return volume * price;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,115 @@
|
||||
/*
|
||||
* 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.Consolidators
|
||||
{
|
||||
/// <summary>
|
||||
/// A data csolidator that can make trade bars from DynamicData derived types. This is useful for
|
||||
/// aggregating Quandl and other highly flexible dynamic custom data types.
|
||||
/// </summary>
|
||||
public class DynamicDataConsolidator : TradeBarConsolidatorBase<DynamicData>
|
||||
{
|
||||
/// <summary>
|
||||
/// Creates a consolidator to produce a new 'TradeBar' representing the period.
|
||||
/// </summary>
|
||||
/// <param name="period">The minimum span of time before emitting a consolidated bar</param>
|
||||
public DynamicDataConsolidator(TimeSpan period)
|
||||
: base(period)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a consolidator to produce a new 'TradeBar' representing the last count pieces of data.
|
||||
/// </summary>
|
||||
/// <param name="maxCount">The number of pieces to accept before emiting a consolidated bar</param>
|
||||
public DynamicDataConsolidator(int maxCount)
|
||||
: base(maxCount)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a consolidator to produce a new 'TradeBar' representing the last count pieces of data or the period, whichever comes first.
|
||||
/// </summary>
|
||||
/// <param name="maxCount">The number of pieces to accept before emiting a consolidated bar</param>
|
||||
/// <param name="period">The minimum span of time before emitting a consolidated bar</param>
|
||||
public DynamicDataConsolidator(int maxCount, TimeSpan period)
|
||||
: base(maxCount, period)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a consolidator to produce a new 'TradeBar' representing the last count pieces of data or the period, whichever comes first.
|
||||
/// </summary>
|
||||
/// <param name="func">Func that defines the start time of a consolidated data</param>
|
||||
public DynamicDataConsolidator(Func<DateTime, CalendarInfo> func)
|
||||
: base(func)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Aggregates the new 'data' into the 'workingBar'. The 'workingBar' will be
|
||||
/// null following the event firing
|
||||
/// </summary>
|
||||
/// <param name="workingBar">The bar we're building, null if the event was just fired and we're starting a new trade bar</param>
|
||||
/// <param name="data">The new data</param>
|
||||
protected override void AggregateBar(ref TradeBar workingBar, DynamicData data)
|
||||
{
|
||||
// grab the properties, if they don't exist just use the .Value property
|
||||
var open = GetNamedPropertyOrValueProperty(data, "Open");
|
||||
var high = GetNamedPropertyOrValueProperty(data, "High");
|
||||
var low = GetNamedPropertyOrValueProperty(data, "Low");
|
||||
var close = GetNamedPropertyOrValueProperty(data, "Close");
|
||||
|
||||
// if we have volume, use it, otherwise just use zero
|
||||
var volume = data.HasProperty("Volume")
|
||||
? data.GetProperty("Volume").ConvertInvariant<long>()
|
||||
: 0L;
|
||||
|
||||
if (workingBar == null)
|
||||
{
|
||||
workingBar = new TradeBar
|
||||
{
|
||||
Symbol = data.Symbol,
|
||||
Time = GetRoundedBarTime(data),
|
||||
Open = open,
|
||||
High = high,
|
||||
Low = low,
|
||||
Close = close,
|
||||
Volume = volume
|
||||
};
|
||||
}
|
||||
else
|
||||
{
|
||||
//Aggregate the working bar
|
||||
workingBar.Close = close;
|
||||
workingBar.Volume += volume;
|
||||
if (low < workingBar.Low) workingBar.Low = low;
|
||||
if (high > workingBar.High) workingBar.High = high;
|
||||
}
|
||||
}
|
||||
|
||||
private static decimal GetNamedPropertyOrValueProperty(DynamicData data, string propertyName)
|
||||
{
|
||||
if (!data.HasProperty(propertyName))
|
||||
{
|
||||
return data.Value;
|
||||
}
|
||||
return data.GetProperty(propertyName).ConvertInvariant<decimal>();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
/*
|
||||
* 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.Consolidators
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides an implementation of <see cref="IDataConsolidator"/> that preserve the input
|
||||
/// data unmodified. The input data is filtering by the specified predicate function
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type of data</typeparam>
|
||||
public class FilteredIdentityDataConsolidator<T> : IdentityDataConsolidator<T>
|
||||
where T : IBaseData
|
||||
{
|
||||
private readonly Func<T, bool> _predicate;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="FilteredIdentityDataConsolidator{T}"/> class
|
||||
/// </summary>
|
||||
/// <param name="predicate">The predicate function, returning true to accept data and false to reject data</param>
|
||||
public FilteredIdentityDataConsolidator(Func<T, bool> predicate)
|
||||
{
|
||||
this._predicate = predicate;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Updates this consolidator with the specified data
|
||||
/// </summary>
|
||||
/// <param name="data">The new data for the consolidator</param>
|
||||
public override void Update(T data)
|
||||
{
|
||||
// only permit data that passes our predicate function to be passed through
|
||||
if (_predicate(data))
|
||||
{
|
||||
base.Update(data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Provides factory methods for creating instances of <see cref="FilteredIdentityDataConsolidator{T}"/>
|
||||
/// </summary>
|
||||
public static class FilteredIdentityDataConsolidator
|
||||
{
|
||||
/// <summary>
|
||||
/// Creates a new instance of <see cref="FilteredIdentityDataConsolidator{T}"/> that filters ticks
|
||||
/// based on the specified <see cref="TickType"/>
|
||||
/// </summary>
|
||||
/// <param name="tickType">The tick type of data to accept</param>
|
||||
/// <returns>A new <see cref="FilteredIdentityDataConsolidator{T}"/> that filters based on the provided tick type</returns>
|
||||
public static FilteredIdentityDataConsolidator<Tick> ForTickType(TickType tickType)
|
||||
{
|
||||
return new FilteredIdentityDataConsolidator<Tick>(tick => tick.TickType == tickType);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
namespace QuantConnect.Data.Consolidators
|
||||
{
|
||||
/// <summary>
|
||||
/// Event handler type for the IDataConsolidator.DataConsolidated event
|
||||
/// </summary>
|
||||
/// <param name="sender">The consolidator that fired the event</param>
|
||||
/// <param name="consolidated">The consolidated piece of data</param>
|
||||
public delegate void DataConsolidatedHandler(object sender, IBaseData consolidated);
|
||||
|
||||
/// <summary>
|
||||
/// Represents a type capable of taking BaseData updates and firing events containing new
|
||||
/// 'consolidated' data. These types can be used to produce larger bars, or even be used to
|
||||
/// transform the data before being sent to another component. The most common usage of these
|
||||
/// types is with indicators.
|
||||
/// </summary>
|
||||
public interface IDataConsolidator : IDisposable
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the most recently consolidated piece of data. This will be null if this consolidator
|
||||
/// has not produced any data yet.
|
||||
/// </summary>
|
||||
IBaseData Consolidated { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets a clone of the data being currently consolidated
|
||||
/// </summary>
|
||||
IBaseData WorkingData { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the type consumed by this consolidator
|
||||
/// </summary>
|
||||
Type InputType { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the type produced by this consolidator
|
||||
/// </summary>
|
||||
Type OutputType { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Updates this consolidator with the specified data
|
||||
/// </summary>
|
||||
/// <param name="data">The new data for the consolidator</param>
|
||||
void Update(IBaseData data);
|
||||
|
||||
/// <summary>
|
||||
/// Scans this consolidator to see if it should emit a bar due to time passing
|
||||
/// </summary>
|
||||
/// <param name="currentLocalTime">The current time in the local time zone (same as <see cref="BaseData.Time"/>)</param>
|
||||
void Scan(DateTime currentLocalTime);
|
||||
|
||||
/// <summary>
|
||||
/// Resets the consolidator
|
||||
/// </summary>
|
||||
void Reset();
|
||||
|
||||
/// <summary>
|
||||
/// Event handler that fires when a new piece of data is produced
|
||||
/// </summary>
|
||||
event DataConsolidatedHandler DataConsolidated;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
/*
|
||||
* 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.Consolidators
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents the simplest DataConsolidator implementation, one that is defined
|
||||
/// by a straight pass through of the data. No projection or aggregation is performed.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type of data</typeparam>
|
||||
public class IdentityDataConsolidator<T> : DataConsolidator<T>
|
||||
where T : IBaseData
|
||||
{
|
||||
private static readonly bool IsTick = typeof(T) == typeof(Tick);
|
||||
|
||||
private T _last;
|
||||
|
||||
/// <summary>
|
||||
/// Stores the timestamp of the last processed data item.
|
||||
/// </summary>
|
||||
private DateTime _lastTime;
|
||||
|
||||
/// <summary>
|
||||
/// Gets a clone of the data being currently consolidated
|
||||
/// </summary>
|
||||
public override IBaseData WorkingData
|
||||
{
|
||||
get { return _last == null ? null : _last.Clone(); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the type produced by this consolidator
|
||||
/// </summary>
|
||||
public override Type OutputType
|
||||
{
|
||||
get { return typeof(T); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Updates this consolidator with the specified data
|
||||
/// </summary>
|
||||
/// <param name="data">The new data for the consolidator</param>
|
||||
public override void Update(T data)
|
||||
{
|
||||
if (IsTick || _last == null || data.EndTime != _lastTime)
|
||||
{
|
||||
OnDataConsolidated(data);
|
||||
_last = data;
|
||||
_lastTime = data.EndTime;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Scans this consolidator to see if it should emit a bar due to time passing
|
||||
/// </summary>
|
||||
/// <param name="currentLocalTime">The current time in the local time zone (same as <see cref="BaseData.Time"/>)</param>
|
||||
public override void Scan(DateTime currentLocalTime)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Resets the consolidator
|
||||
/// </summary>
|
||||
public override void Reset()
|
||||
{
|
||||
base.Reset();
|
||||
_last = default(T);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,278 @@
|
||||
/*
|
||||
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
|
||||
* Lean Algorithmic Trading Engine v2.0. Copyright 2024 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 NodaTime;
|
||||
using QuantConnect.Util;
|
||||
using QuantConnect.Securities;
|
||||
using QuantConnect.Data.Market;
|
||||
|
||||
namespace QuantConnect.Data.Consolidators
|
||||
{
|
||||
/// <summary>
|
||||
/// Consolidator for open markets bar only, extended hours bar are not consolidated.
|
||||
/// </summary>
|
||||
public class MarketHourAwareConsolidator : ConsolidatorBase
|
||||
{
|
||||
private readonly bool _dailyStrictEndTimeEnabled;
|
||||
private readonly bool _extendedMarketHours;
|
||||
private bool _useStrictEndTime;
|
||||
|
||||
/// <summary>
|
||||
/// The consolidation period requested
|
||||
/// </summary>
|
||||
protected TimeSpan Period { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The consolidator instance
|
||||
/// </summary>
|
||||
protected IDataConsolidator Consolidator { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The associated security exchange hours instance
|
||||
/// </summary>
|
||||
protected SecurityExchangeHours ExchangeHours { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The associated data time zone
|
||||
/// </summary>
|
||||
protected DateTimeZone DataTimeZone { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the type consumed by this consolidator
|
||||
/// </summary>
|
||||
public override Type InputType => Consolidator.InputType;
|
||||
|
||||
/// <summary>
|
||||
/// Gets a clone of the data being currently consolidated
|
||||
/// </summary>
|
||||
public override IBaseData WorkingData => Consolidator.WorkingData;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the type produced by this consolidator
|
||||
/// </summary>
|
||||
public override Type OutputType => Consolidator.OutputType;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="MarketHourAwareConsolidator"/> class.
|
||||
/// </summary>
|
||||
/// <param name="resolution">The resolution.</param>
|
||||
/// <param name="dataType">The target data type</param>
|
||||
/// <param name="tickType">The target tick type</param>
|
||||
/// <param name="extendedMarketHours">True if extended market hours should be consolidated</param>
|
||||
public MarketHourAwareConsolidator(bool dailyStrictEndTimeEnabled, Resolution resolution, Type dataType, TickType tickType, bool extendedMarketHours)
|
||||
{
|
||||
_dailyStrictEndTimeEnabled = dailyStrictEndTimeEnabled;
|
||||
Period = resolution.ToTimeSpan();
|
||||
_extendedMarketHours = extendedMarketHours;
|
||||
|
||||
Consolidator = CreateConsolidator(resolution, dataType, tickType);
|
||||
Consolidator.DataConsolidated += ForwardConsolidatedBar;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="MarketHourAwareConsolidator"/> class for an arbitrary period.
|
||||
/// Intraday periods are anchored to the market open without extending past the close.
|
||||
/// </summary>
|
||||
/// <param name="dailyStrictEndTimeEnabled">True if daily strict end times should be enabled</param>
|
||||
/// <param name="period">The consolidation period</param>
|
||||
/// <param name="dataType">The target data type</param>
|
||||
/// <param name="tickType">The target tick type</param>
|
||||
/// <param name="extendedMarketHours">True if extended market hours should be consolidated</param>
|
||||
public MarketHourAwareConsolidator(bool dailyStrictEndTimeEnabled, TimeSpan period, Type dataType, TickType tickType, bool extendedMarketHours)
|
||||
{
|
||||
_dailyStrictEndTimeEnabled = dailyStrictEndTimeEnabled;
|
||||
Period = period;
|
||||
_extendedMarketHours = extendedMarketHours;
|
||||
|
||||
// when the period exactly matches a standard resolution, reuse the resolution based consolidation so its
|
||||
// well-tested behavior is preserved; only arbitrary periods need the market-open anchored intraday calendar
|
||||
var resolution = period.ToHigherResolutionEquivalent(false);
|
||||
if (resolution.ToTimeSpan() == period)
|
||||
{
|
||||
Consolidator = CreateConsolidator(resolution, dataType, tickType);
|
||||
}
|
||||
else
|
||||
{
|
||||
Func<DateTime, CalendarInfo> calendar = period < Time.OneDay ? IntradayCalendar : DailyStrictEndTime;
|
||||
Consolidator = CreateConsolidator(calendar, dataType, tickType);
|
||||
}
|
||||
Consolidator.DataConsolidated += ForwardConsolidatedBar;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates the inner consolidator that produces the requested <paramref name="dataType"/> output.
|
||||
/// </summary>
|
||||
protected virtual IDataConsolidator CreateConsolidator(Resolution resolution, Type dataType, TickType tickType)
|
||||
{
|
||||
if (dataType == typeof(Tick))
|
||||
{
|
||||
if (tickType == TickType.Trade)
|
||||
{
|
||||
return resolution == Resolution.Daily
|
||||
? new TickConsolidator(DailyStrictEndTime)
|
||||
: new TickConsolidator(Period);
|
||||
}
|
||||
return resolution == Resolution.Daily
|
||||
? new TickQuoteBarConsolidator(DailyStrictEndTime)
|
||||
: new TickQuoteBarConsolidator(Period);
|
||||
}
|
||||
if (dataType == typeof(TradeBar))
|
||||
{
|
||||
return resolution == Resolution.Daily
|
||||
? new TradeBarConsolidator(DailyStrictEndTime)
|
||||
: new TradeBarConsolidator(Period);
|
||||
}
|
||||
if (dataType == typeof(QuoteBar))
|
||||
{
|
||||
return resolution == Resolution.Daily
|
||||
? new QuoteBarConsolidator(DailyStrictEndTime)
|
||||
: new QuoteBarConsolidator(Period);
|
||||
}
|
||||
throw new ArgumentNullException(nameof(dataType), $"{dataType.Name} not supported");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates the underlying calendar based consolidator for the given data type, used for arbitrary periods
|
||||
/// </summary>
|
||||
protected virtual IDataConsolidator CreateConsolidator(Func<DateTime, CalendarInfo> calendar, Type dataType, TickType tickType)
|
||||
{
|
||||
if (dataType == typeof(Tick))
|
||||
{
|
||||
return tickType == TickType.Trade
|
||||
? new TickConsolidator(calendar)
|
||||
: new TickQuoteBarConsolidator(calendar);
|
||||
}
|
||||
if (dataType == typeof(TradeBar))
|
||||
{
|
||||
return new TradeBarConsolidator(calendar);
|
||||
}
|
||||
if (dataType == typeof(QuoteBar))
|
||||
{
|
||||
return new QuoteBarConsolidator(calendar);
|
||||
}
|
||||
throw new ArgumentNullException(nameof(dataType), $"{dataType.Name} not supported");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Updates this consolidator with the specified data
|
||||
/// </summary>
|
||||
/// <param name="data">The new data for the consolidator</param>
|
||||
public override void Update(IBaseData data)
|
||||
{
|
||||
Initialize(data);
|
||||
|
||||
// US equity hour data from the database starts at 9am but the exchange opens at 9:30am. Thus, we need to handle
|
||||
// this case specifically to avoid skipping the first hourly bar. To avoid this, we assert the period is daily,
|
||||
// the data resolution is hour and the exchange opens at any point in time over the data.Time to data.EndTime interval
|
||||
if (_extendedMarketHours ||
|
||||
ExchangeHours.IsOpen(data.Time, false) ||
|
||||
(Period == Time.OneDay && (data.EndTime - data.Time >= Time.OneHour) && ExchangeHours.IsOpen(data.Time, data.EndTime, false)))
|
||||
{
|
||||
Consolidator.Update(data);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Scans this consolidator to see if it should emit a bar due to time passing
|
||||
/// </summary>
|
||||
/// <param name="currentLocalTime">The current time in the local time zone (same as <see cref="P:QuantConnect.Data.BaseData.Time" />)</param>
|
||||
public override void Scan(DateTime currentLocalTime)
|
||||
{
|
||||
Consolidator.Scan(currentLocalTime);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
|
||||
/// </summary>
|
||||
public override void Dispose()
|
||||
{
|
||||
Consolidator.DataConsolidated -= ForwardConsolidatedBar;
|
||||
Consolidator.Dispose();
|
||||
base.Dispose();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Resets the consolidator
|
||||
/// </summary>
|
||||
public override void Reset()
|
||||
{
|
||||
_useStrictEndTime = false;
|
||||
ExchangeHours = null;
|
||||
DataTimeZone = null;
|
||||
Consolidator.Reset();
|
||||
base.Reset();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Perform late initialization based on the datas symbol
|
||||
/// </summary>
|
||||
protected void Initialize(IBaseData data)
|
||||
{
|
||||
if (ExchangeHours == null)
|
||||
{
|
||||
var symbol = data.Symbol;
|
||||
var marketHoursDatabase = MarketHoursDatabase.FromDataFolder();
|
||||
ExchangeHours = marketHoursDatabase.GetExchangeHours(symbol.ID.Market, symbol, symbol.SecurityType);
|
||||
DataTimeZone = marketHoursDatabase.GetDataTimeZone(symbol.ID.Market, symbol, symbol.SecurityType);
|
||||
|
||||
_useStrictEndTime = UseStrictEndTime(data.Symbol);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines a bar start time and period
|
||||
/// </summary>
|
||||
protected virtual CalendarInfo DailyStrictEndTime(DateTime dateTime)
|
||||
{
|
||||
// strict end times describe a single daily bar, so periods larger than a day fall back to standard period consolidation
|
||||
if (!_useStrictEndTime || Period > Time.OneDay)
|
||||
{
|
||||
return new(Period > Time.OneDay ? dateTime : dateTime.RoundDown(Period), Period);
|
||||
}
|
||||
return LeanData.GetDailyCalendar(dateTime, ExchangeHours, _extendedMarketHours);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines a bar start time and period for intraday consolidation, anchored to the market open
|
||||
/// without extending past the market close so a bar never spans across closed market hours
|
||||
/// </summary>
|
||||
protected virtual CalendarInfo IntradayCalendar(DateTime dateTime)
|
||||
{
|
||||
if (ExchangeHours == null || ExchangeHours.IsMarketAlwaysOpen)
|
||||
{
|
||||
return new(dateTime.RoundDown(Period), Period);
|
||||
}
|
||||
return LeanData.GetIntradayCalendar(dateTime, Period, ExchangeHours, _extendedMarketHours);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Useful for testing
|
||||
/// </summary>
|
||||
protected virtual bool UseStrictEndTime(Symbol symbol)
|
||||
{
|
||||
return LeanData.UseStrictEndTime(_dailyStrictEndTimeEnabled, symbol, Period, ExchangeHours);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Will forward the underlying consolidated bar to consumers on this object.
|
||||
/// This wrapper keeps its own rolling window in addition to the inner consolidator's window.
|
||||
/// </summary>
|
||||
protected virtual void ForwardConsolidatedBar(object sender, IBaseData consolidated)
|
||||
{
|
||||
OnDataConsolidated(consolidated);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,155 @@
|
||||
/*
|
||||
* 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;
|
||||
using Python.Runtime;
|
||||
|
||||
namespace QuantConnect.Data.Consolidators
|
||||
{
|
||||
/// <summary>
|
||||
/// Type capable of consolidating open interest
|
||||
/// </summary>
|
||||
public class OpenInterestConsolidator : PeriodCountConsolidatorBase<Tick, OpenInterest>
|
||||
{
|
||||
private bool _hourOrDailyConsolidation;
|
||||
// Keep track of the last input to detect hour or date change
|
||||
private Tick _lastInput;
|
||||
|
||||
/// <summary>
|
||||
/// Create a new OpenInterestConsolidator for the desired resolution
|
||||
/// </summary>
|
||||
/// <param name="resolution">The resolution desired</param>
|
||||
/// <returns>A consolidator that produces data on the resolution interval</returns>
|
||||
public static OpenInterestConsolidator FromResolution(Resolution resolution)
|
||||
{
|
||||
return new OpenInterestConsolidator(resolution.ToTimeSpan());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a consolidator to produce a new 'OpenInterest' representing the period
|
||||
/// </summary>
|
||||
/// <param name="period">The minimum span of time before emitting a consolidated bar</param>
|
||||
/// <param name="startTime">Optionally the bar start time anchor to use</param>
|
||||
public OpenInterestConsolidator(TimeSpan period, TimeSpan? startTime = null)
|
||||
: base(period, startTime)
|
||||
{
|
||||
_hourOrDailyConsolidation = period >= Time.OneHour;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a consolidator to produce a new 'OpenInterest' representing the last count pieces of data
|
||||
/// </summary>
|
||||
/// <param name="maxCount">The number of pieces to accept before emitting a consolidated bar</param>
|
||||
public OpenInterestConsolidator(int maxCount)
|
||||
: base(maxCount)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a consolidator to produce a new 'OpenInterest' representing the last count pieces of data or the period, whichever comes first
|
||||
/// </summary>
|
||||
/// <param name="maxCount">The number of pieces to accept before emitting a consolidated bar</param>
|
||||
/// <param name="period">The minimum span of time before emitting a consolidated bar</param>
|
||||
public OpenInterestConsolidator(int maxCount, TimeSpan period)
|
||||
: base(maxCount, period)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a consolidator to produce a new 'OpenInterest'
|
||||
/// </summary>
|
||||
/// <param name="func">Func that defines the start time of a consolidated data</param>
|
||||
public OpenInterestConsolidator(Func<DateTime, CalendarInfo> func)
|
||||
: base(func)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a consolidator to produce a new 'OpenInterest'
|
||||
/// </summary>
|
||||
/// <param name="pyfuncobj">Python function object that defines the start time of a consolidated data</param>
|
||||
public OpenInterestConsolidator(PyObject pyfuncobj)
|
||||
: base(pyfuncobj)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether or not the specified data should be processed
|
||||
/// </summary>
|
||||
/// <param name="data">The data to check</param>
|
||||
/// <returns>True if the consolidator should process this data, false otherwise</returns>
|
||||
protected override bool ShouldProcess(Tick data)
|
||||
{
|
||||
return data.TickType == TickType.OpenInterest;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Aggregates the new 'data' into the 'workingBar'. The 'workingBar' will be
|
||||
/// null following the event firing
|
||||
/// </summary>
|
||||
/// <param name="workingBar">The bar we're building, null if the event was just fired and we're starting a new OI bar</param>
|
||||
/// <param name="data">The new data</param>
|
||||
protected override void AggregateBar(ref OpenInterest workingBar, Tick data)
|
||||
{
|
||||
if (workingBar == null)
|
||||
{
|
||||
workingBar = new OpenInterest
|
||||
{
|
||||
Symbol = data.Symbol,
|
||||
Time = _hourOrDailyConsolidation ? data.EndTime : GetRoundedBarTime(data),
|
||||
Value = data.Value
|
||||
};
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
//Update the working bar
|
||||
workingBar.Value = data.Value;
|
||||
|
||||
// If we are consolidating hourly or daily, we need to update the time of the working bar
|
||||
// for the end time to match the last data point time
|
||||
if (_hourOrDailyConsolidation)
|
||||
{
|
||||
workingBar.Time = data.EndTime;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Updates this consolidator with the specified data. This method is
|
||||
/// responsible for raising the DataConsolidated event.
|
||||
/// It will check for date or hour change and force consolidation if needed.
|
||||
/// </summary>
|
||||
/// <param name="data">The new data for the consolidator</param>
|
||||
public override void Update(Tick data)
|
||||
{
|
||||
if (_lastInput != null &&
|
||||
_hourOrDailyConsolidation &&
|
||||
// Detect hour or date change
|
||||
((Period == Time.OneHour && data.EndTime.Hour != _lastInput.EndTime.Hour) ||
|
||||
(Period == Time.OneDay && data.EndTime.Date != _lastInput.EndTime.Date)))
|
||||
{
|
||||
// Date or hour change, force consolidation, no need to wait for the whole period to pass.
|
||||
// Force consolidation by scanning at a time after the end of the period
|
||||
Scan(_lastInput.EndTime.Add(Period.Value + Time.OneSecond));
|
||||
}
|
||||
|
||||
base.Update(data);
|
||||
_lastInput = data;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,474 @@
|
||||
/*
|
||||
* 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 QuantConnect.Util;
|
||||
using QuantConnect.Data.Market;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace QuantConnect.Data.Consolidators
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides a base class for consolidators that emit data based on the passing of a period of time
|
||||
/// or after seeing a max count of data points.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The input type of the consolidator</typeparam>
|
||||
/// <typeparam name="TConsolidated">The output type of the consolidator</typeparam>
|
||||
public abstract class PeriodCountConsolidatorBase<T, TConsolidated> : DataConsolidator<T>
|
||||
where T : IBaseData
|
||||
where TConsolidated : BaseData
|
||||
{
|
||||
// The SecurityIdentifier that we are consolidating for.
|
||||
private SecurityIdentifier _securityIdentifier;
|
||||
private bool _securityIdentifierIsSet;
|
||||
//The number of data updates between creating new bars.
|
||||
private int? _maxCount;
|
||||
//
|
||||
private IPeriodSpecification _periodSpecification;
|
||||
//The minimum timespan between creating new bars.
|
||||
private TimeSpan? _period;
|
||||
//The number of pieces of data we've accumulated since our last emit
|
||||
private int _currentCount;
|
||||
//The working bar used for aggregating the data
|
||||
protected TConsolidated _workingBar;
|
||||
//The last time we emitted a consolidated bar
|
||||
private DateTime? _lastEmit;
|
||||
private bool _validateTimeSpan;
|
||||
|
||||
private PeriodCountConsolidatorBase(IPeriodSpecification periodSpecification)
|
||||
{
|
||||
_periodSpecification = periodSpecification;
|
||||
_period = _periodSpecification.Period;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a consolidator to produce a new <typeparamref name="TConsolidated"/> instance representing the period
|
||||
/// </summary>
|
||||
/// <param name="period">The minimum span of time before emitting a consolidated bar</param>
|
||||
/// <param name="startTime">Optionally the bar start time anchor to use</param>
|
||||
protected PeriodCountConsolidatorBase(TimeSpan period, TimeSpan? startTime = null)
|
||||
: this(new TimeSpanPeriodSpecification(period, startTime))
|
||||
{
|
||||
_period = _periodSpecification.Period;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a consolidator to produce a new <typeparamref name="TConsolidated"/> instance representing the last count pieces of data
|
||||
/// </summary>
|
||||
/// <param name="maxCount">The number of pieces to accept before emiting a consolidated bar</param>
|
||||
protected PeriodCountConsolidatorBase(int maxCount)
|
||||
: this(new BarCountPeriodSpecification())
|
||||
{
|
||||
_maxCount = maxCount;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a consolidator to produce a new <typeparamref name="TConsolidated"/> instance representing the last count pieces of data or the period, whichever comes first
|
||||
/// </summary>
|
||||
/// <param name="maxCount">The number of pieces to accept before emiting a consolidated bar</param>
|
||||
/// <param name="period">The minimum span of time before emitting a consolidated bar</param>
|
||||
protected PeriodCountConsolidatorBase(int maxCount, TimeSpan period)
|
||||
: this(new MixedModePeriodSpecification(period))
|
||||
{
|
||||
_maxCount = maxCount;
|
||||
_period = _periodSpecification.Period;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a consolidator to produce a new <typeparamref name="TConsolidated"/> instance representing the last count pieces of data or the period, whichever comes first
|
||||
/// </summary>
|
||||
/// <param name="func">Func that defines the start time of a consolidated data</param>
|
||||
protected PeriodCountConsolidatorBase(Func<DateTime, CalendarInfo> func)
|
||||
: this(new FuncPeriodSpecification(func))
|
||||
{
|
||||
_period = Time.OneSecond;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a consolidator to produce a new <typeparamref name="TConsolidated"/> instance representing the last count pieces of data or the period, whichever comes first
|
||||
/// </summary>
|
||||
/// <param name="pyObject">Python object that defines either a function object that defines the start time of a consolidated data or a timespan</param>
|
||||
protected PeriodCountConsolidatorBase(PyObject pyObject)
|
||||
: this(GetPeriodSpecificationFromPyObject(pyObject))
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the type produced by this consolidator
|
||||
/// </summary>
|
||||
public override Type OutputType => typeof(TConsolidated);
|
||||
|
||||
/// <summary>
|
||||
/// Gets a clone of the data being currently consolidated
|
||||
/// </summary>
|
||||
public override IBaseData WorkingData => _workingBar?.Clone();
|
||||
|
||||
/// <summary>
|
||||
/// Event handler that fires when a new piece of data is produced. We define this as a 'new'
|
||||
/// event so we can expose it as a <typeparamref name="TConsolidated"/> instead of a <see cref="BaseData"/> instance
|
||||
/// </summary>
|
||||
public new event EventHandler<TConsolidated> DataConsolidated;
|
||||
|
||||
/// <summary>
|
||||
/// Updates this consolidator with the specified data. This method is
|
||||
/// responsible for raising the DataConsolidated event
|
||||
/// In time span mode, the bar range is closed on the left and open on the right: [T, T+TimeSpan).
|
||||
/// For example, if time span is 1 minute, we have [10:00, 10:01): so data at 10:01 is not
|
||||
/// included in the bar starting at 10:00.
|
||||
/// </summary>
|
||||
/// <exception cref="InvalidOperationException">Thrown when multiple symbols are being consolidated.</exception>
|
||||
/// <param name="data">The new data for the consolidator</param>
|
||||
public override void Update(T data)
|
||||
{
|
||||
if (!_securityIdentifierIsSet)
|
||||
{
|
||||
_securityIdentifierIsSet = true;
|
||||
_securityIdentifier = data.Symbol.ID;
|
||||
}
|
||||
else if (!data.Symbol.ID.Equals(_securityIdentifier))
|
||||
{
|
||||
throw new InvalidOperationException($"Consolidators can only be used with a single symbol. The previous consolidated SecurityIdentifier ({_securityIdentifier}) is not the same as in the current data ({data.Symbol.ID}).");
|
||||
}
|
||||
|
||||
if (!ShouldProcess(data))
|
||||
{
|
||||
// first allow the base class a chance to filter out data it doesn't want
|
||||
// before we start incrementing counts and what not
|
||||
return;
|
||||
}
|
||||
|
||||
if (!_validateTimeSpan && _period.HasValue && _periodSpecification is TimeSpanPeriodSpecification)
|
||||
{
|
||||
// only do this check once
|
||||
_validateTimeSpan = true;
|
||||
var dataLength = data.EndTime - data.Time;
|
||||
if (dataLength > _period)
|
||||
{
|
||||
throw new ArgumentException($"For Symbol {data.Symbol} can not consolidate bars of period: {_period}, using data of the same or higher period: {data.EndTime - data.Time}");
|
||||
}
|
||||
}
|
||||
|
||||
//Decide to fire the event
|
||||
var fireDataConsolidated = false;
|
||||
|
||||
// decide to aggregate data before or after firing OnDataConsolidated event
|
||||
// always aggregate before firing in counting mode
|
||||
bool aggregateBeforeFire = _maxCount.HasValue;
|
||||
|
||||
if (_maxCount.HasValue)
|
||||
{
|
||||
// we're in count mode
|
||||
_currentCount++;
|
||||
if (_currentCount >= _maxCount.Value)
|
||||
{
|
||||
_currentCount = 0;
|
||||
fireDataConsolidated = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!_lastEmit.HasValue)
|
||||
{
|
||||
// initialize this value for period computations
|
||||
_lastEmit = IsTimeBased ? DateTime.MinValue : data.Time;
|
||||
}
|
||||
|
||||
if (_period.HasValue)
|
||||
{
|
||||
// we're in time span mode and initialized
|
||||
if (_workingBar != null && data.Time - _workingBar.Time >= _period.Value && GetRoundedBarTime(data) > _lastEmit)
|
||||
{
|
||||
fireDataConsolidated = true;
|
||||
}
|
||||
|
||||
// special case: always aggregate before event trigger when TimeSpan is zero
|
||||
if (_period.Value == TimeSpan.Zero)
|
||||
{
|
||||
fireDataConsolidated = true;
|
||||
aggregateBeforeFire = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (aggregateBeforeFire)
|
||||
{
|
||||
if (data.Time >= _lastEmit)
|
||||
{
|
||||
AggregateBar(ref _workingBar, data);
|
||||
|
||||
if (_maxCount.HasValue)
|
||||
{
|
||||
// When using count-based consolidation, set EndTime to the last input's EndTime
|
||||
_workingBar.EndTime = data.EndTime;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//Fire the event
|
||||
if (fireDataConsolidated)
|
||||
{
|
||||
var workingTradeBar = _workingBar as TradeBar;
|
||||
if (workingTradeBar != null)
|
||||
{
|
||||
// we kind of are cheating here...
|
||||
if (_period.HasValue)
|
||||
{
|
||||
workingTradeBar.Period = _period.Value;
|
||||
}
|
||||
}
|
||||
|
||||
// Set _lastEmit first because OnDataConsolidated will set _workingBar to null
|
||||
_lastEmit = IsTimeBased && _workingBar != null ? _workingBar.EndTime : data.Time;
|
||||
OnDataConsolidated(_workingBar);
|
||||
}
|
||||
|
||||
if (!aggregateBeforeFire)
|
||||
{
|
||||
if (data.Time >= _lastEmit)
|
||||
{
|
||||
AggregateBar(ref _workingBar, data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Scans this consolidator to see if it should emit a bar due to time passing
|
||||
/// </summary>
|
||||
/// <param name="currentLocalTime">The current time in the local time zone (same as <see cref="BaseData.Time"/>)</param>
|
||||
public override void Scan(DateTime currentLocalTime)
|
||||
{
|
||||
if (_workingBar != null && _period.HasValue && _period.Value != TimeSpan.Zero
|
||||
&& currentLocalTime - _workingBar.Time >= _period.Value && GetRoundedBarTime(currentLocalTime) > _lastEmit)
|
||||
{
|
||||
_lastEmit = _workingBar.EndTime;
|
||||
OnDataConsolidated(_workingBar);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Resets the consolidator
|
||||
/// </summary>
|
||||
public override void Reset()
|
||||
{
|
||||
base.Reset();
|
||||
_securityIdentifier = null;
|
||||
_securityIdentifierIsSet = false;
|
||||
_currentCount = 0;
|
||||
_workingBar = null;
|
||||
_lastEmit = null;
|
||||
_validateTimeSpan = false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if this consolidator is time-based, false otherwise
|
||||
/// </summary>
|
||||
protected bool IsTimeBased => !_maxCount.HasValue;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the time period for this consolidator
|
||||
/// </summary>
|
||||
protected TimeSpan? Period => _period;
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether or not the specified data should be processed
|
||||
/// </summary>
|
||||
/// <param name="data">The data to check</param>
|
||||
/// <returns>True if the consolidator should process this data, false otherwise</returns>
|
||||
protected virtual bool ShouldProcess(T data) => true;
|
||||
|
||||
/// <summary>
|
||||
/// Aggregates the new 'data' into the 'workingBar'. The 'workingBar' will be
|
||||
/// null following the event firing
|
||||
/// </summary>
|
||||
/// <param name="workingBar">The bar we're building, null if the event was just fired and we're starting a new consolidated bar</param>
|
||||
/// <param name="data">The new data</param>
|
||||
protected abstract void AggregateBar(ref TConsolidated workingBar, T data);
|
||||
|
||||
/// <summary>
|
||||
/// Gets a rounded-down bar time. Called by AggregateBar in derived classes.
|
||||
/// </summary>
|
||||
/// <param name="time">The bar time to be rounded down</param>
|
||||
/// <returns>The rounded bar time</returns>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
protected DateTime GetRoundedBarTime(DateTime time)
|
||||
{
|
||||
var startTime = _periodSpecification.GetRoundedBarTime(time);
|
||||
|
||||
// In the case of a new bar, define the period defined at opening time
|
||||
if (_workingBar == null)
|
||||
{
|
||||
_period = _periodSpecification.Period;
|
||||
}
|
||||
|
||||
return startTime;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a rounded-down bar start time. Called by AggregateBar in derived classes.
|
||||
/// </summary>
|
||||
/// <param name="inputData">The input data point</param>
|
||||
/// <returns>The rounded bar start time</returns>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
protected DateTime GetRoundedBarTime(IBaseData inputData)
|
||||
{
|
||||
var potentialStartTime = GetRoundedBarTime(inputData.Time);
|
||||
if (_period.HasValue && potentialStartTime + _period < inputData.EndTime)
|
||||
{
|
||||
// US equity hour bars from the database starts at 9am but the exchange opens at 9:30am. Thus, the method
|
||||
// GetRoundedBarTime(inputData.Time) returns the market open of the previous day, which is not consistent
|
||||
// with the given end time. For that reason we need to handle this case specifically, by calling
|
||||
// GetRoundedBarTime(inputData.EndTime) as it will return our expected start time: 9:30am
|
||||
if (inputData.EndTime - inputData.Time == Time.OneHour && potentialStartTime.Date < inputData.Time.Date)
|
||||
{
|
||||
potentialStartTime = GetRoundedBarTime(inputData.EndTime);
|
||||
}
|
||||
else
|
||||
{
|
||||
// whops! the end time we were giving is beyond our potential end time, so let's use the giving bars star time instead
|
||||
potentialStartTime = inputData.Time;
|
||||
}
|
||||
}
|
||||
|
||||
return potentialStartTime;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Event invocator for the <see cref="DataConsolidated"/> event
|
||||
/// </summary>
|
||||
/// <param name="e">The consolidated data</param>
|
||||
protected virtual void OnDataConsolidated(TConsolidated e)
|
||||
{
|
||||
base.OnDataConsolidated(e);
|
||||
DataConsolidated?.Invoke(this, e);
|
||||
|
||||
ResetWorkingBar();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Resets the working bar
|
||||
/// </summary>
|
||||
protected virtual void ResetWorkingBar()
|
||||
{
|
||||
_workingBar = null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the period specification from the PyObject that can either represent a function object that defines the start time of a consolidated data or a timespan.
|
||||
/// </summary>
|
||||
/// <param name="pyObject">Python object that defines either a function object that defines the start time of a consolidated data or a timespan</param>
|
||||
/// <returns>IPeriodSpecification that represents the PyObject</returns>
|
||||
private static IPeriodSpecification GetPeriodSpecificationFromPyObject(PyObject pyObject)
|
||||
{
|
||||
Func<DateTime, CalendarInfo> expiryFunc;
|
||||
if (pyObject.TrySafeAs(out expiryFunc))
|
||||
{
|
||||
return new FuncPeriodSpecification(expiryFunc);
|
||||
}
|
||||
|
||||
using (Py.GIL())
|
||||
{
|
||||
return new TimeSpanPeriodSpecification(pyObject.As<TimeSpan>());
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Distinguishes between the different ways a consolidated data start time can be specified
|
||||
/// </summary>
|
||||
private interface IPeriodSpecification
|
||||
{
|
||||
TimeSpan? Period { get; }
|
||||
DateTime GetRoundedBarTime(DateTime time);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// User defined the bars period using a counter
|
||||
/// </summary>
|
||||
private class BarCountPeriodSpecification : IPeriodSpecification
|
||||
{
|
||||
public TimeSpan? Period { get; } = null;
|
||||
|
||||
public DateTime GetRoundedBarTime(DateTime time) => time;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// User defined the bars period using a counter and a period (mixed mode)
|
||||
/// </summary>
|
||||
private class MixedModePeriodSpecification : IPeriodSpecification
|
||||
{
|
||||
public TimeSpan? Period { get; }
|
||||
|
||||
public MixedModePeriodSpecification(TimeSpan period)
|
||||
{
|
||||
Period = period;
|
||||
}
|
||||
|
||||
public DateTime GetRoundedBarTime(DateTime time) => time;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// User defined the bars period using a time span
|
||||
/// </summary>
|
||||
private class TimeSpanPeriodSpecification : IPeriodSpecification
|
||||
{
|
||||
public TimeSpan? StartTime { get; }
|
||||
public TimeSpan? Period { get; }
|
||||
|
||||
public TimeSpanPeriodSpecification(TimeSpan period, TimeSpan? startTime = null)
|
||||
{
|
||||
Period = period;
|
||||
StartTime = startTime;
|
||||
}
|
||||
|
||||
public DateTime GetRoundedBarTime(DateTime time)
|
||||
{
|
||||
if (StartTime.HasValue)
|
||||
{
|
||||
return LeanData.GetConsolidatorStartTime(Period.Value, StartTime.Value, time);
|
||||
}
|
||||
return Period.Value > Time.OneDay
|
||||
? time // #4915 For periods larger than a day, don't use a rounding schedule.
|
||||
: time.RoundDown(Period.Value);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Special case for bars where the open time is defined by a function.
|
||||
/// We assert on construction that the function returns a date time in the past or equal to the given time instant.
|
||||
/// </summary>
|
||||
private class FuncPeriodSpecification : IPeriodSpecification
|
||||
{
|
||||
private static readonly DateTime _verificationDate = new DateTime(2022, 01, 03, 10, 10, 10);
|
||||
public TimeSpan? Period { get; private set; }
|
||||
|
||||
public readonly Func<DateTime, CalendarInfo> _calendarInfoFunc;
|
||||
|
||||
public FuncPeriodSpecification(Func<DateTime, CalendarInfo> expiryFunc)
|
||||
{
|
||||
if (expiryFunc(_verificationDate).Start > _verificationDate)
|
||||
{
|
||||
throw new ArgumentException($"{nameof(FuncPeriodSpecification)}: Please use a function that computes the start of the bar associated with the given date time. Should never return a time later than the one passed in.");
|
||||
}
|
||||
_calendarInfoFunc = expiryFunc;
|
||||
}
|
||||
|
||||
public DateTime GetRoundedBarTime(DateTime time)
|
||||
{
|
||||
var calendarInfo = _calendarInfoFunc(time);
|
||||
Period = calendarInfo.Period;
|
||||
return calendarInfo.Start;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,132 @@
|
||||
/*
|
||||
* 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 QuantConnect.Data.Market;
|
||||
|
||||
namespace QuantConnect.Data.Consolidators
|
||||
{
|
||||
/// <summary>
|
||||
/// Consolidates QuoteBars into larger QuoteBars
|
||||
/// </summary>
|
||||
public class QuoteBarConsolidator : PeriodCountConsolidatorBase<QuoteBar, QuoteBar>
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="QuoteBarConsolidator"/> class
|
||||
/// </summary>
|
||||
/// <param name="period">The minimum span of time before emitting a consolidated bar</param>
|
||||
/// <param name="startTime">Optionally the bar start time anchor to use</param>
|
||||
public QuoteBarConsolidator(TimeSpan period, TimeSpan? startTime = null)
|
||||
: base(period, startTime)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="QuoteBarConsolidator"/> class
|
||||
/// </summary>
|
||||
/// <param name="maxCount">The number of pieces to accept before emitting a consolidated bar</param>
|
||||
public QuoteBarConsolidator(int maxCount)
|
||||
: base(maxCount)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="QuoteBarConsolidator"/> class
|
||||
/// </summary>
|
||||
/// <param name="maxCount">The number of pieces to accept before emitting a consolidated bar</param>
|
||||
/// <param name="period">The minimum span of time before emitting a consolidated bar</param>
|
||||
public QuoteBarConsolidator(int maxCount, TimeSpan period)
|
||||
: base(maxCount, period)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a consolidator to produce a new 'QuoteBar' representing the last count pieces of data or the period, whichever comes first
|
||||
/// </summary>
|
||||
/// <param name="func">Func that defines the start time of a consolidated data</param>
|
||||
public QuoteBarConsolidator(Func<DateTime, CalendarInfo> func)
|
||||
: base(func)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a consolidator to produce a new 'QuoteBar' representing the last count pieces of data or the period, whichever comes first
|
||||
/// </summary>
|
||||
/// <param name="pyfuncobj">Python function object that defines the start time of a consolidated data</param>
|
||||
public QuoteBarConsolidator(PyObject pyfuncobj)
|
||||
: base(pyfuncobj)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Aggregates the new 'data' into the 'workingBar'. The 'workingBar' will be
|
||||
/// null following the event firing
|
||||
/// </summary>
|
||||
/// <param name="workingBar">The bar we're building, null if the event was just fired and we're starting a new consolidated bar</param>
|
||||
/// <param name="data">The new data</param>
|
||||
protected override void AggregateBar(ref QuoteBar workingBar, QuoteBar data)
|
||||
{
|
||||
var bid = data.Bid;
|
||||
var ask = data.Ask;
|
||||
|
||||
if (workingBar == null)
|
||||
{
|
||||
workingBar = new QuoteBar(GetRoundedBarTime(data), data.Symbol, null, 0, null, 0, IsTimeBased && Period.HasValue ? Period : data.Period);
|
||||
|
||||
// open ask and bid should match previous close ask and bid
|
||||
if (Consolidated != null)
|
||||
{
|
||||
// note that we will only fill forward previous close ask and bid when a new data point comes in and we generate a new working bar which is not a fill forward bar
|
||||
var previous = Consolidated as QuoteBar;
|
||||
workingBar.Update(0, previous.Bid?.Close ?? 0, previous.Ask?.Close ?? 0, 0, previous.LastBidSize, previous.LastAskSize);
|
||||
}
|
||||
}
|
||||
|
||||
// update the bid and ask
|
||||
if (bid != null)
|
||||
{
|
||||
workingBar.LastBidSize = data.LastBidSize;
|
||||
if (workingBar.Bid == null)
|
||||
{
|
||||
workingBar.Bid = new Bar(bid.Open, bid.High, bid.Low, bid.Close);
|
||||
}
|
||||
else
|
||||
{
|
||||
workingBar.Bid.Close = bid.Close;
|
||||
if (workingBar.Bid.High < bid.High) workingBar.Bid.High = bid.High;
|
||||
if (workingBar.Bid.Low > bid.Low) workingBar.Bid.Low = bid.Low;
|
||||
}
|
||||
}
|
||||
if (ask != null)
|
||||
{
|
||||
workingBar.LastAskSize = data.LastAskSize;
|
||||
if (workingBar.Ask == null)
|
||||
{
|
||||
workingBar.Ask = new Bar(ask.Open, ask.High, ask.Low, ask.Close);
|
||||
}
|
||||
else
|
||||
{
|
||||
workingBar.Ask.Close = ask.Close;
|
||||
if (workingBar.Ask.High < ask.High) workingBar.Ask.High = ask.High;
|
||||
if (workingBar.Ask.Low > ask.Low) workingBar.Ask.Low = ask.Low;
|
||||
}
|
||||
}
|
||||
|
||||
workingBar.Value = data.Value;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,159 @@
|
||||
/*
|
||||
* 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 Python.Runtime;
|
||||
using QuantConnect.Data.Market;
|
||||
using QuantConnect.Securities;
|
||||
using System;
|
||||
|
||||
namespace QuantConnect.Data.Consolidators
|
||||
{
|
||||
/// <summary>
|
||||
/// This consolidator can transform a stream of <see cref="IBaseData"/> instances into a stream of <see cref="RangeBar"/>
|
||||
/// </summary>
|
||||
public class RangeConsolidator : BaseTimelessConsolidator<RangeBar>
|
||||
{
|
||||
private bool _firstTick;
|
||||
private decimal _minimumPriceVariation;
|
||||
|
||||
/// <summary>
|
||||
/// Symbol properties database to use to get the minimum price variation of certain symbol
|
||||
/// </summary>
|
||||
private static SymbolPropertiesDatabase _symbolPropertiesDatabase = SymbolPropertiesDatabase.FromDataFolder();
|
||||
|
||||
/// <summary>
|
||||
/// Bar being created
|
||||
/// </summary>
|
||||
protected override RangeBar CurrentBar { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Range for each RangeBar, this is, the difference between the High and Low for each
|
||||
/// RangeBar
|
||||
/// </summary>
|
||||
public decimal RangeSize { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Number of MinimumPriceVariation units
|
||||
/// </summary>
|
||||
public int Range { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets <see cref="RangeBar"/> which is the type emitted in the <see cref="IDataConsolidator.DataConsolidated"/> event.
|
||||
/// </summary>
|
||||
public override Type OutputType => typeof(RangeBar);
|
||||
|
||||
/// <summary>
|
||||
/// Gets a clone of the data being currently consolidated
|
||||
/// </summary>
|
||||
public override IBaseData WorkingData => CurrentBar?.Clone();
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="RangeConsolidator" /> class.
|
||||
/// </summary>
|
||||
/// <param name="range">The Range interval sets the range in which the price moves, which in turn initiates the formation of a new bar.
|
||||
/// One range equals to one minimum price change, where this last value is defined depending of the RangeBar's symbol</param>
|
||||
/// <param name="selector">Extracts the value from a data instance to be formed into a <see cref="RangeBar"/>. The default
|
||||
/// value is (x => x.Value) the <see cref="IBaseData.Value"/> property on <see cref="IBaseData"/></param>
|
||||
/// <param name="volumeSelector">Extracts the volume from a data instance. The default value is null which does
|
||||
/// not aggregate volume per bar, except if the input is a TradeBar.</param>
|
||||
public RangeConsolidator(
|
||||
int range,
|
||||
Func<IBaseData, decimal> selector = null,
|
||||
Func<IBaseData, decimal> volumeSelector = null)
|
||||
: base(selector, volumeSelector)
|
||||
{
|
||||
Range = range;
|
||||
_firstTick = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="RangeConsolidator" /> class.
|
||||
/// </summary>
|
||||
/// <param name="range">The Range interval sets the range in which the price moves, which in turn initiates the formation of a new bar.
|
||||
/// One range equals to one minimum price change, where this last value is defined depending of the RangeBar's symbol</param>
|
||||
/// <param name="selector">Extracts the value from a data instance to be formed into a <see cref="RangeBar"/>. The default
|
||||
/// value is (x => x.Value) the <see cref="IBaseData.Value"/> property on <see cref="IBaseData"/></param>
|
||||
/// <param name="volumeSelector">Extracts the volume from a data instance. The default value is null which does
|
||||
/// not aggregate volume per bar.</param>
|
||||
public RangeConsolidator(int range,
|
||||
PyObject selector,
|
||||
PyObject volumeSelector = null)
|
||||
: base(selector, volumeSelector)
|
||||
{
|
||||
Range = range;
|
||||
_firstTick = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Resets the consolidator
|
||||
/// </summary>
|
||||
public override void Reset()
|
||||
{
|
||||
base.Reset();
|
||||
_firstTick = true;
|
||||
_minimumPriceVariation = 0m;
|
||||
RangeSize = 0m;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Updates the current RangeBar being created with the given data.
|
||||
/// Additionally, if it's the case, it consolidates the current RangeBar
|
||||
/// </summary>
|
||||
/// <param name="time">Time of the given data</param>
|
||||
/// <param name="currentValue">Value of the given data</param>
|
||||
/// <param name="volume">Volume of the given data</param>
|
||||
protected override void UpdateBar(DateTime time, decimal currentValue, decimal volume)
|
||||
{
|
||||
bool isRising = default;
|
||||
if (currentValue > CurrentBar.High)
|
||||
{
|
||||
isRising = true;
|
||||
}
|
||||
else if (currentValue < CurrentBar.Low)
|
||||
{
|
||||
isRising = false;
|
||||
}
|
||||
|
||||
CurrentBar.Update(time, currentValue, volume);
|
||||
while (CurrentBar.IsClosed)
|
||||
{
|
||||
OnDataConsolidated(CurrentBar);
|
||||
CurrentBar = new RangeBar(CurrentBar.Symbol, CurrentBar.EndTime, RangeSize, isRising ? CurrentBar.High + _minimumPriceVariation : CurrentBar.Low - _minimumPriceVariation);
|
||||
CurrentBar.Update(time, currentValue, Math.Abs(CurrentBar.Low - currentValue) > RangeSize ? 0 : volume); // Intermediate/phantom RangeBar's have zero volume
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new bar with the given data
|
||||
/// </summary>
|
||||
/// <param name="data">The new data for the bar</param>
|
||||
/// <param name="currentValue">The new value for the bar</param>
|
||||
/// <param name="volume">The new volume for the bar</param>
|
||||
protected override void CreateNewBar(IBaseData data, decimal currentValue, decimal volume)
|
||||
{
|
||||
var open = currentValue;
|
||||
|
||||
if (_firstTick)
|
||||
{
|
||||
_minimumPriceVariation = _symbolPropertiesDatabase.GetSymbolProperties(data.Symbol.ID.Market, data.Symbol, data.Symbol.ID.SecurityType, "USD").MinimumPriceVariation;
|
||||
RangeSize = _minimumPriceVariation * Range;
|
||||
open = Math.Ceiling(open / RangeSize) * RangeSize;
|
||||
_firstTick = false;
|
||||
}
|
||||
|
||||
CurrentBar = new RangeBar(data.Symbol, data.Time, RangeSize, open, volume: volume);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,373 @@
|
||||
/*
|
||||
* 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.Consolidators
|
||||
{
|
||||
/// <summary>
|
||||
/// This consolidator can transform a stream of <see cref="BaseData"/> instances into a stream of <see cref="RenkoBar"/>
|
||||
/// with Renko type <see cref="RenkoType.Wicked"/>.
|
||||
/// </summary>
|
||||
/// <remarks>This implementation replaced the original implementation that was shown to have inaccuracies in its representation
|
||||
/// of Renko charts. The original implementation has been moved to <see cref="ClassicRenkoConsolidator"/>.</remarks>
|
||||
public class RenkoConsolidator : ConsolidatorBase
|
||||
{
|
||||
private bool _firstTick = true;
|
||||
private RenkoBar _lastWicko;
|
||||
private RenkoBar _currentBar;
|
||||
|
||||
/// <summary>
|
||||
/// Time of consolidated close.
|
||||
/// </summary>
|
||||
/// <remarks>Protected for testing</remarks>
|
||||
protected DateTime CloseOn { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Value of consolidated close.
|
||||
/// </summary>
|
||||
/// <remarks>Protected for testing</remarks>
|
||||
protected decimal CloseRate { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Value of consolidated high.
|
||||
/// </summary>
|
||||
/// <remarks>Protected for testing</remarks>
|
||||
protected decimal HighRate { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Value of consolidated low.
|
||||
/// </summary>
|
||||
/// <remarks>Protected for testing</remarks>
|
||||
protected decimal LowRate { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Time of consolidated open.
|
||||
/// </summary>
|
||||
/// <remarks>Protected for testing</remarks>
|
||||
protected DateTime OpenOn { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Value of consolidate open.
|
||||
/// </summary>
|
||||
/// <remarks>Protected for testing</remarks>
|
||||
protected decimal OpenRate { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Size of the consolidated bar.
|
||||
/// </summary>
|
||||
/// <remarks>Protected for testing</remarks>
|
||||
protected decimal BarSize { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the kind of the bar
|
||||
/// </summary>
|
||||
public RenkoType Type => RenkoType.Wicked;
|
||||
|
||||
/// <summary>
|
||||
/// Gets a clone of the data being currently consolidated
|
||||
/// </summary>
|
||||
public override IBaseData WorkingData => _currentBar?.Clone();
|
||||
|
||||
/// <summary>
|
||||
/// Gets the type consumed by this consolidator
|
||||
/// </summary>
|
||||
public override Type InputType => typeof(IBaseData);
|
||||
|
||||
/// <summary>
|
||||
/// Gets <see cref="RenkoBar"/> which is the type emitted in the <see cref="IDataConsolidator.DataConsolidated"/> event.
|
||||
/// </summary>
|
||||
public override Type OutputType => typeof(RenkoBar);
|
||||
|
||||
/// <summary>
|
||||
/// Typed event handler that fires when a new piece of data is produced
|
||||
/// </summary>
|
||||
public new event EventHandler<RenkoBar> DataConsolidated;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="RenkoConsolidator"/> class using the specified <paramref name="barSize"/>.
|
||||
/// </summary>
|
||||
/// <param name="barSize">The constant value size of each bar</param>
|
||||
public RenkoConsolidator(decimal barSize)
|
||||
{
|
||||
if (barSize <= 0)
|
||||
{
|
||||
throw new ArgumentException("Renko consolidator BarSize must be strictly greater than zero");
|
||||
}
|
||||
|
||||
BarSize = barSize;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Updates this consolidator with the specified data
|
||||
/// </summary>
|
||||
/// <param name="data">The new data for the consolidator</param>
|
||||
public override void Update(IBaseData data)
|
||||
{
|
||||
var rate = data.Price;
|
||||
|
||||
if (_firstTick)
|
||||
{
|
||||
_firstTick = false;
|
||||
|
||||
// Round our first rate to the same length as BarSize
|
||||
rate = GetClosestMultiple(rate, BarSize);
|
||||
|
||||
OpenOn = data.Time;
|
||||
CloseOn = data.Time;
|
||||
OpenRate = rate;
|
||||
HighRate = rate;
|
||||
LowRate = rate;
|
||||
CloseRate = rate;
|
||||
}
|
||||
else
|
||||
{
|
||||
CloseOn = data.Time;
|
||||
|
||||
if (rate > HighRate)
|
||||
{
|
||||
HighRate = rate;
|
||||
}
|
||||
|
||||
if (rate < LowRate)
|
||||
{
|
||||
LowRate = rate;
|
||||
}
|
||||
|
||||
CloseRate = rate;
|
||||
|
||||
if (CloseRate > OpenRate)
|
||||
{
|
||||
if (_lastWicko == null || _lastWicko.Direction == BarDirection.Rising)
|
||||
{
|
||||
Rising(data);
|
||||
return;
|
||||
}
|
||||
|
||||
var limit = _lastWicko.Open + BarSize;
|
||||
|
||||
if (CloseRate > limit)
|
||||
{
|
||||
var wicko = new RenkoBar(data.Symbol, OpenOn, CloseOn, BarSize, _lastWicko.Open, limit,
|
||||
LowRate, limit);
|
||||
|
||||
_lastWicko = wicko;
|
||||
|
||||
OnDataConsolidated(wicko);
|
||||
|
||||
OpenOn = CloseOn;
|
||||
OpenRate = limit;
|
||||
LowRate = limit;
|
||||
|
||||
Rising(data);
|
||||
}
|
||||
}
|
||||
else if (CloseRate < OpenRate)
|
||||
{
|
||||
if (_lastWicko == null || _lastWicko.Direction == BarDirection.Falling)
|
||||
{
|
||||
Falling(data);
|
||||
return;
|
||||
}
|
||||
|
||||
var limit = _lastWicko.Open - BarSize;
|
||||
|
||||
if (CloseRate < limit)
|
||||
{
|
||||
var wicko = new RenkoBar(data.Symbol, OpenOn, CloseOn, BarSize, _lastWicko.Open, HighRate,
|
||||
limit, limit);
|
||||
|
||||
_lastWicko = wicko;
|
||||
|
||||
OnDataConsolidated(wicko);
|
||||
|
||||
OpenOn = CloseOn;
|
||||
OpenRate = limit;
|
||||
HighRate = limit;
|
||||
|
||||
Falling(data);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Scans this consolidator to see if it should emit a bar due to time passing
|
||||
/// </summary>
|
||||
/// <param name="currentLocalTime">The current time in the local time zone (same as <see cref="BaseData.Time"/>)</param>
|
||||
public override void Scan(DateTime currentLocalTime)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.</summary>
|
||||
/// <filterpriority>2</filterpriority>
|
||||
public override void Dispose()
|
||||
{
|
||||
DataConsolidated = null;
|
||||
base.Dispose();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Resets the consolidator
|
||||
/// </summary>
|
||||
public override void Reset()
|
||||
{
|
||||
_firstTick = true;
|
||||
_lastWicko = null;
|
||||
_currentBar = null;
|
||||
CloseOn = default;
|
||||
CloseRate = default;
|
||||
HighRate = default;
|
||||
LowRate = default;
|
||||
OpenOn = default;
|
||||
OpenRate = default;
|
||||
base.Reset();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Raises the strongly typed DataConsolidated event
|
||||
/// </summary>
|
||||
/// <param name="consolidated">The newly consolidated data</param>
|
||||
protected override void FireDataConsolidated(IBaseData consolidated)
|
||||
{
|
||||
var bar = (RenkoBar)consolidated;
|
||||
// fire the typed event before updating the current bar so handlers reading
|
||||
// WorkingData still see the previous bar, as they did before the rolling window
|
||||
DataConsolidated?.Invoke(this, bar);
|
||||
_currentBar = bar;
|
||||
}
|
||||
|
||||
private void Rising(IBaseData data)
|
||||
{
|
||||
decimal limit;
|
||||
|
||||
while (CloseRate > (limit = OpenRate + BarSize))
|
||||
{
|
||||
var wicko = new RenkoBar(data.Symbol, OpenOn, CloseOn, BarSize, OpenRate, limit, LowRate, limit);
|
||||
|
||||
_lastWicko = wicko;
|
||||
|
||||
OnDataConsolidated(wicko);
|
||||
|
||||
OpenOn = CloseOn;
|
||||
OpenRate = limit;
|
||||
LowRate = limit;
|
||||
}
|
||||
}
|
||||
|
||||
private void Falling(IBaseData data)
|
||||
{
|
||||
decimal limit;
|
||||
|
||||
while (CloseRate < (limit = OpenRate - BarSize))
|
||||
{
|
||||
var wicko = new RenkoBar(data.Symbol, OpenOn, CloseOn, BarSize, OpenRate, HighRate, limit, limit);
|
||||
|
||||
_lastWicko = wicko;
|
||||
|
||||
OnDataConsolidated(wicko);
|
||||
|
||||
OpenOn = CloseOn;
|
||||
OpenRate = limit;
|
||||
HighRate = limit;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the closest BarSize-Multiple to the price.
|
||||
/// </summary>
|
||||
/// <remarks>Based on: The Art of Computer Programming, Vol I, pag 39. Donald E. Knuth</remarks>
|
||||
/// <param name="price">Price to be rounded to the closest BarSize-Multiple</param>
|
||||
/// <param name="barSize">The size of the Renko bar</param>
|
||||
/// <returns>The closest BarSize-Multiple to the price</returns>
|
||||
public static decimal GetClosestMultiple(decimal price, decimal barSize)
|
||||
{
|
||||
if (barSize <= 0)
|
||||
{
|
||||
throw new ArgumentException("BarSize must be strictly greater than zero");
|
||||
}
|
||||
|
||||
var modulus = price - barSize * Math.Floor(price / barSize);
|
||||
var round = Math.Round(modulus / barSize);
|
||||
return barSize * (Math.Floor(price / barSize) + round);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Provides a type safe wrapper on the RenkoConsolidator class. This just allows us to define our selector functions with the real type they'll be receiving
|
||||
/// </summary>
|
||||
/// <typeparam name="TInput"></typeparam>
|
||||
public class RenkoConsolidator<TInput> : RenkoConsolidator
|
||||
where TInput : IBaseData
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="RenkoConsolidator"/> class using the specified <paramref name="barSize"/>.
|
||||
/// </summary>
|
||||
/// <param name="barSize">The constant value size of each bar</param>
|
||||
public RenkoConsolidator(decimal barSize)
|
||||
: base(barSize)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Updates this consolidator with the specified data.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Type safe shim method.
|
||||
/// </remarks>
|
||||
/// <param name="data">The new data for the consolidator</param>
|
||||
public void Update(TInput data)
|
||||
{
|
||||
base.Update(data);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This consolidator can transform a stream of <see cref="BaseData"/> instances into a stream of <see cref="RenkoBar"/>
|
||||
/// with Renko type <see cref="RenkoType.Wicked"/>.
|
||||
/// /// </summary>
|
||||
/// <remarks>For backwards compatibility now that WickedRenkoConsolidators -> RenkoConsolidator</remarks>
|
||||
public class WickedRenkoConsolidator : RenkoConsolidator
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="RenkoConsolidator"/> class using the specified <paramref name="barSize"/>.
|
||||
/// </summary>
|
||||
/// <param name="barSize">The constant value size of each bar</param>
|
||||
public WickedRenkoConsolidator(decimal barSize)
|
||||
: base(barSize)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This consolidator can transform a stream of <see cref="BaseData"/> instances into a stream of <see cref="RenkoBar"/>
|
||||
/// with Renko type <see cref="RenkoType.Wicked"/>.
|
||||
/// Provides a type safe wrapper on the WickedRenkoConsolidator class. This just allows us to define our selector functions with the real type they'll be receiving
|
||||
/// /// </summary>
|
||||
/// <remarks>For backwards compatibility now that WickedRenkoConsolidators -> RenkoConsolidator</remarks>
|
||||
public class WickedRenkoConsolidator<T> : RenkoConsolidator<T>
|
||||
where T : IBaseData
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="RenkoConsolidator"/> class using the specified <paramref name="barSize"/>.
|
||||
/// </summary>
|
||||
/// <param name="barSize">The constant value size of each bar</param>
|
||||
public WickedRenkoConsolidator(decimal barSize)
|
||||
: base(barSize)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,128 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
namespace QuantConnect.Data.Consolidators
|
||||
{
|
||||
/// <summary>
|
||||
/// This consolidator wires up the events on its First and Second consolidators
|
||||
/// such that data flows from the First to Second consolidator. It's output comes
|
||||
/// from the Second.
|
||||
/// </summary>
|
||||
public class SequentialConsolidator : ConsolidatorBase
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the first consolidator to receive data
|
||||
/// </summary>
|
||||
public IDataConsolidator First
|
||||
{
|
||||
get; private set;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the second consolidator that ends up receiving data produced
|
||||
/// by the first
|
||||
/// </summary>
|
||||
public IDataConsolidator Second
|
||||
{
|
||||
get; private set;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a clone of the data being currently consolidated
|
||||
/// </summary>
|
||||
public override IBaseData WorkingData
|
||||
{
|
||||
get { return Second.WorkingData; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the type consumed by this consolidator
|
||||
/// </summary>
|
||||
public override Type InputType
|
||||
{
|
||||
get { return First.InputType; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the type produced by this consolidator
|
||||
/// </summary>
|
||||
public override Type OutputType
|
||||
{
|
||||
get { return Second.OutputType; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Updates this consolidator with the specified data
|
||||
/// </summary>
|
||||
/// <param name="data">The new data for the consolidator</param>
|
||||
public override void Update(IBaseData data)
|
||||
{
|
||||
First.Update(data);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Scans this consolidator to see if it should emit a bar due to time passing
|
||||
/// </summary>
|
||||
/// <param name="currentLocalTime">The current time in the local time zone (same as <see cref="BaseData.Time"/>)</param>
|
||||
public override void Scan(DateTime currentLocalTime)
|
||||
{
|
||||
First.Scan(currentLocalTime);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new consolidator that will pump date through the first, and then the output
|
||||
/// of the first into the second. This enables 'wrapping' or 'composing' of consolidators
|
||||
/// </summary>
|
||||
/// <param name="first">The first consolidator to receive data</param>
|
||||
/// <param name="second">The consolidator to receive first's output</param>
|
||||
public SequentialConsolidator(IDataConsolidator first, IDataConsolidator second)
|
||||
{
|
||||
if (!second.InputType.IsAssignableFrom(first.OutputType))
|
||||
{
|
||||
throw new ArgumentException("first.OutputType must equal second.OutputType!");
|
||||
}
|
||||
First = first;
|
||||
Second = second;
|
||||
|
||||
// wire up the second one to get data from the first
|
||||
first.DataConsolidated += (sender, consolidated) => second.Update(consolidated);
|
||||
|
||||
// wire up the second one's events to also fire this consolidator's event so consumers
|
||||
// can attach. This wrapper also keeps its own window
|
||||
second.DataConsolidated += (sender, consolidated) => OnDataConsolidated(consolidated);
|
||||
}
|
||||
|
||||
/// <summary>Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.</summary>
|
||||
/// <filterpriority>2</filterpriority>
|
||||
public override void Dispose()
|
||||
{
|
||||
First.Dispose();
|
||||
Second.Dispose();
|
||||
base.Dispose();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Resets the consolidator
|
||||
/// </summary>
|
||||
public override void Reset()
|
||||
{
|
||||
First.Reset();
|
||||
Second.Reset();
|
||||
base.Reset();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,153 @@
|
||||
/*
|
||||
* 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;
|
||||
using QuantConnect.Data;
|
||||
using QuantConnect.Securities;
|
||||
using QuantConnect.Data.Market;
|
||||
using QuantConnect.Data.Consolidators;
|
||||
using QuantConnect.Util;
|
||||
|
||||
namespace Common.Data.Consolidators
|
||||
{
|
||||
/// <summary>
|
||||
/// Consolidates intraday market data into a single daily <see cref="SessionBar"/> (OHLCV + OpenInterest).
|
||||
/// </summary>
|
||||
public class SessionConsolidator : PeriodCountConsolidatorBase<BaseData, SessionBar>
|
||||
{
|
||||
private readonly SecurityExchangeHours _exchangeHours;
|
||||
private readonly TickType _sourceTickType;
|
||||
private readonly Symbol _symbol;
|
||||
private bool _initialized;
|
||||
internal SessionBar WorkingInstance
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_workingBar == null)
|
||||
{
|
||||
InitializeWorkingBar();
|
||||
}
|
||||
return _workingBar;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="SessionConsolidator"/> class.
|
||||
/// </summary>
|
||||
/// <param name="exchangeHours">The exchange hours</param>
|
||||
/// <param name="sourceTickType">Type of the source tick</param>
|
||||
/// <param name="symbol">The symbol</param>
|
||||
public SessionConsolidator(SecurityExchangeHours exchangeHours, TickType sourceTickType, Symbol symbol) : base(Time.OneDay)
|
||||
{
|
||||
_symbol = symbol;
|
||||
_exchangeHours = exchangeHours;
|
||||
_sourceTickType = sourceTickType;
|
||||
InitializeWorkingBar();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Aggregates the new 'data' into the 'workingBar'
|
||||
/// </summary>
|
||||
/// <param name="workingBar">The bar we're building, null if the event was just fired and we're starting a new trade bar</param>
|
||||
/// <param name="data">The new data</param>
|
||||
protected override void AggregateBar(ref SessionBar workingBar, BaseData data)
|
||||
{
|
||||
if (!_initialized)
|
||||
{
|
||||
if (workingBar.Time == DateTime.MaxValue || data.Time.Date > workingBar.Time.Date)
|
||||
{
|
||||
workingBar.Time = data.Time.Date;
|
||||
}
|
||||
_initialized = true;
|
||||
}
|
||||
|
||||
// Handle open interest
|
||||
if (data.DataType == MarketDataType.Tick && data is Tick oiTick && oiTick.TickType == TickType.OpenInterest)
|
||||
{
|
||||
// Update the working session bar with the latest open interest
|
||||
workingBar.OpenInterest = oiTick.Value;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!_exchangeHours.IsOpen(data.Time, data.EndTime, false))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Update the working session bar
|
||||
workingBar.Update(data, Consolidated);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Validates the current local time and triggers Scan() if a new day is detected.
|
||||
/// </summary>
|
||||
/// <param name="currentLocalTime">The current local time.</param>
|
||||
public void ValidateAndScan(DateTime currentLocalTime)
|
||||
{
|
||||
if (!_initialized)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (currentLocalTime.Date != WorkingInstance.Time.Date)
|
||||
{
|
||||
Scan(currentLocalTime);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Event handler that fires when a new piece of data is produced
|
||||
/// </summary>
|
||||
//public event DataConsolidatedHandler DataConsolidated;
|
||||
|
||||
protected override void OnDataConsolidated(SessionBar e)
|
||||
{
|
||||
_workingBar = null;
|
||||
base.OnDataConsolidated(e);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Resets the working bar
|
||||
/// </summary>
|
||||
protected override void ResetWorkingBar()
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Resets the consolidator
|
||||
/// </summary>
|
||||
public override void Reset()
|
||||
{
|
||||
base.Reset();
|
||||
InitializeWorkingBar();
|
||||
}
|
||||
|
||||
private void InitializeWorkingBar()
|
||||
{
|
||||
var time = DateTime.MaxValue;
|
||||
if (Consolidated != null)
|
||||
{
|
||||
time = _exchangeHours.GetNextTradingDay(Consolidated.Time).Date;
|
||||
}
|
||||
_workingBar = new SessionBar(_sourceTickType)
|
||||
{
|
||||
Time = time,
|
||||
Symbol = _symbol
|
||||
};
|
||||
_initialized = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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 QuantConnect.Data.Market;
|
||||
using Python.Runtime;
|
||||
|
||||
namespace QuantConnect.Data.Consolidators
|
||||
{
|
||||
/// <summary>
|
||||
/// A data consolidator that can make bigger bars from ticks over a given
|
||||
/// time span or a count of pieces of data.
|
||||
/// </summary>
|
||||
public class TickConsolidator : TradeBarConsolidatorBase<Tick>
|
||||
{
|
||||
/// <summary>
|
||||
/// Creates a consolidator to produce a new 'TradeBar' representing the period
|
||||
/// </summary>
|
||||
/// <param name="period">The minimum span of time before emitting a consolidated bar</param>
|
||||
public TickConsolidator(TimeSpan period)
|
||||
: base(period)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a consolidator to produce a new 'TradeBar' representing the last count pieces of data
|
||||
/// </summary>
|
||||
/// <param name="maxCount">The number of pieces to accept before emitting a consolidated bar</param>
|
||||
public TickConsolidator(int maxCount)
|
||||
: base(maxCount)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a consolidator to produce a new 'TradeBar' representing the last count pieces of data or the period, whichever comes first
|
||||
/// </summary>
|
||||
/// <param name="maxCount">The number of pieces to accept before emitting a consolidated bar</param>
|
||||
/// <param name="period">The minimum span of time before emitting a consolidated bar</param>
|
||||
public TickConsolidator(int maxCount, TimeSpan period)
|
||||
: base(maxCount, period)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="TickQuoteBarConsolidator"/> class
|
||||
/// </summary>
|
||||
/// <param name="func">Func that defines the start time of a consolidated data</param>
|
||||
public TickConsolidator(Func<DateTime, CalendarInfo> func)
|
||||
: base(func)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a consolidator to produce a new 'TradeBar' representing the last count pieces of data or the period, whichever comes first
|
||||
/// </summary>
|
||||
/// <param name="pyfuncobj">Python function object that defines the start time of a consolidated data</param>
|
||||
public TickConsolidator(PyObject pyfuncobj)
|
||||
: base(pyfuncobj)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether or not the specified data should be processed
|
||||
/// </summary>
|
||||
/// <param name="data">The data to check</param>
|
||||
/// <returns>True if the consolidator should process this data, false otherwise</returns>
|
||||
protected override bool ShouldProcess(Tick data)
|
||||
{
|
||||
return data.TickType == TickType.Trade;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Aggregates the new 'data' into the 'workingBar'. The 'workingBar' will be
|
||||
/// null following the event firing
|
||||
/// </summary>
|
||||
/// <param name="workingBar">The bar we're building</param>
|
||||
/// <param name="data">The new data</param>
|
||||
protected override void AggregateBar(ref TradeBar workingBar, Tick data)
|
||||
{
|
||||
if (workingBar == null)
|
||||
{
|
||||
workingBar = new TradeBar(GetRoundedBarTime(data),
|
||||
data.Symbol,
|
||||
data.Value,
|
||||
data.Value,
|
||||
data.Value,
|
||||
data.Value,
|
||||
data.Quantity,
|
||||
Period);
|
||||
}
|
||||
else
|
||||
{
|
||||
//Aggregate the working bar
|
||||
workingBar.Close = data.Value;
|
||||
workingBar.Volume += data.Quantity;
|
||||
if (data.Value < workingBar.Low) workingBar.Low = data.Value;
|
||||
if (data.Value > workingBar.High) workingBar.High = data.Value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,111 @@
|
||||
/*
|
||||
* 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;
|
||||
using Python.Runtime;
|
||||
|
||||
namespace QuantConnect.Data.Consolidators
|
||||
{
|
||||
/// <summary>
|
||||
/// Consolidates ticks into quote bars. This consolidator ignores trade ticks
|
||||
/// </summary>
|
||||
public class TickQuoteBarConsolidator : PeriodCountConsolidatorBase<Tick, QuoteBar>
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="TickQuoteBarConsolidator"/> class
|
||||
/// </summary>
|
||||
/// <param name="period">The minimum span of time before emitting a consolidated bar</param>
|
||||
/// <param name="startTime">Optionally the bar start time anchor to use</param>
|
||||
public TickQuoteBarConsolidator(TimeSpan period, TimeSpan? startTime = null)
|
||||
: base(period, startTime)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="TickQuoteBarConsolidator"/> class
|
||||
/// </summary>
|
||||
/// <param name="maxCount">The number of pieces to accept before emitting a consolidated bar</param>
|
||||
public TickQuoteBarConsolidator(int maxCount)
|
||||
: base(maxCount)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="TickQuoteBarConsolidator"/> class
|
||||
/// </summary>
|
||||
/// <param name="maxCount">The number of pieces to accept before emitting a consolidated bar</param>
|
||||
/// <param name="period">The minimum span of time before emitting a consolidated bar</param>
|
||||
public TickQuoteBarConsolidator(int maxCount, TimeSpan period)
|
||||
: base(maxCount, period)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="TickQuoteBarConsolidator"/> class
|
||||
/// </summary>
|
||||
/// <param name="func">Func that defines the start time of a consolidated data</param>
|
||||
public TickQuoteBarConsolidator(Func<DateTime, CalendarInfo> func)
|
||||
: base(func)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="TickQuoteBarConsolidator"/> class
|
||||
/// </summary>
|
||||
/// <param name="pyfuncobj">Python function object that defines the start time of a consolidated data</param>
|
||||
public TickQuoteBarConsolidator(PyObject pyfuncobj)
|
||||
: base(pyfuncobj)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether or not the specified data should be processed
|
||||
/// </summary>
|
||||
/// <param name="data">The data to check</param>
|
||||
/// <returns>True if the consolidator should process this data, false otherwise</returns>
|
||||
protected override bool ShouldProcess(Tick data)
|
||||
{
|
||||
return data.TickType == TickType.Quote;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Aggregates the new 'data' into the 'workingBar'. The 'workingBar' will be
|
||||
/// null following the event firing
|
||||
/// </summary>
|
||||
/// <param name="workingBar">The bar we're building, null if the event was just fired and we're starting a new consolidated bar</param>
|
||||
/// <param name="data">The new data</param>
|
||||
protected override void AggregateBar(ref QuoteBar workingBar, Tick data)
|
||||
{
|
||||
if (workingBar == null)
|
||||
{
|
||||
workingBar = new QuoteBar(GetRoundedBarTime(data), data.Symbol, null, decimal.Zero, null, decimal.Zero, Period);
|
||||
|
||||
// open ask and bid should match previous close ask and bid
|
||||
if (Consolidated != null)
|
||||
{
|
||||
// note that we will only fill forward previous close ask and bid when a new data point comes in and we generate a new working bar which is not a fill forward bar
|
||||
var previous = Consolidated as QuoteBar;
|
||||
workingBar.Update(decimal.Zero, previous.Bid?.Close ?? decimal.Zero, previous.Ask?.Close ?? decimal.Zero, decimal.Zero, previous.LastBidSize, previous.LastAskSize);
|
||||
}
|
||||
}
|
||||
|
||||
// update the bid and ask
|
||||
workingBar.Update(decimal.Zero, data.BidPrice, data.AskPrice, decimal.Zero, data.BidSize, data.AskSize);
|
||||
if (!Period.HasValue) workingBar.EndTime = GetRoundedBarTime(data.EndTime);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
using Python.Runtime;
|
||||
|
||||
namespace QuantConnect.Data.Consolidators
|
||||
{
|
||||
/// <summary>
|
||||
/// A data consolidator that can make bigger bars from smaller ones over a given
|
||||
/// time span or a count of pieces of data.
|
||||
///
|
||||
/// Use this consolidator to turn data of a lower resolution into data of a higher resolution,
|
||||
/// for example, if you subscribe to minute data but want to have a 15 minute bar.
|
||||
/// </summary>
|
||||
public class TradeBarConsolidator : TradeBarConsolidatorBase<TradeBar>
|
||||
{
|
||||
/// <summary>
|
||||
/// Create a new TradeBarConsolidator for the desired resolution
|
||||
/// </summary>
|
||||
/// <param name="resolution">The resolution desired</param>
|
||||
/// <returns>A consolidator that produces data on the resolution interval</returns>
|
||||
public static TradeBarConsolidator FromResolution(Resolution resolution)
|
||||
{
|
||||
return new TradeBarConsolidator(resolution.ToTimeSpan());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a consolidator to produce a new 'TradeBar' representing the period
|
||||
/// </summary>
|
||||
/// <param name="period">The minimum span of time before emitting a consolidated bar</param>
|
||||
/// <param name="startTime">Optionally the bar start time anchor to use</param>
|
||||
public TradeBarConsolidator(TimeSpan period, TimeSpan? startTime = null)
|
||||
: base(period, startTime)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a consolidator to produce a new 'TradeBar' representing the last count pieces of data
|
||||
/// </summary>
|
||||
/// <param name="maxCount">The number of pieces to accept before emitting a consolidated bar</param>
|
||||
public TradeBarConsolidator(int maxCount)
|
||||
: base(maxCount)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a consolidator to produce a new 'TradeBar' representing the last count pieces of data or the period, whichever comes first
|
||||
/// </summary>
|
||||
/// <param name="maxCount">The number of pieces to accept before emitting a consolidated bar</param>
|
||||
/// <param name="period">The minimum span of time before emitting a consolidated bar</param>
|
||||
public TradeBarConsolidator(int maxCount, TimeSpan period)
|
||||
: base(maxCount, period)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a consolidator to produce a new 'TradeBar' representing the last count pieces of data or the period, whichever comes first
|
||||
/// </summary>
|
||||
/// <param name="func">Func that defines the start time of a consolidated data</param>
|
||||
public TradeBarConsolidator(Func<DateTime, CalendarInfo> func)
|
||||
: base(func)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a consolidator to produce a new 'TradeBar' representing the last count pieces of data or the period, whichever comes first
|
||||
/// </summary>
|
||||
/// <param name="pyfuncobj">Python function object that defines the start time of a consolidated data</param>
|
||||
public TradeBarConsolidator(PyObject pyfuncobj)
|
||||
: base(pyfuncobj)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Aggregates the new 'data' into the 'workingBar'. The 'workingBar' will be
|
||||
/// null following the event firing
|
||||
/// </summary>
|
||||
/// <param name="workingBar">The bar we're building, null if the event was just fired and we're starting a new trade bar</param>
|
||||
/// <param name="data">The new data</param>
|
||||
protected override void AggregateBar(ref TradeBar workingBar, TradeBar data)
|
||||
{
|
||||
if (workingBar == null)
|
||||
{
|
||||
workingBar = new TradeBar
|
||||
{
|
||||
Time = GetRoundedBarTime(data),
|
||||
Symbol = data.Symbol,
|
||||
Open = data.Open,
|
||||
High = data.High,
|
||||
Low = data.Low,
|
||||
Close = data.Close,
|
||||
Volume = data.Volume,
|
||||
DataType = MarketDataType.TradeBar,
|
||||
Period = IsTimeBased && Period.HasValue ? (TimeSpan)Period : data.Period
|
||||
};
|
||||
}
|
||||
else
|
||||
{
|
||||
//Aggregate the working bar
|
||||
workingBar.Close = data.Close;
|
||||
workingBar.Volume += data.Volume;
|
||||
if (data.Low < workingBar.Low) workingBar.Low = data.Low;
|
||||
if (data.High > workingBar.High) workingBar.High = data.High;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
/*
|
||||
* 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;
|
||||
using Python.Runtime;
|
||||
|
||||
namespace QuantConnect.Data.Consolidators
|
||||
{
|
||||
/// <summary>
|
||||
/// A data consolidator that can make bigger bars from any base data
|
||||
///
|
||||
/// This type acts as the base for other consolidators that produce bars on a given time step or for a count of data.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The input type into the consolidator's Update method</typeparam>
|
||||
public abstract class TradeBarConsolidatorBase<T> : PeriodCountConsolidatorBase<T, TradeBar>
|
||||
where T : IBaseData
|
||||
{
|
||||
/// <summary>
|
||||
/// Creates a consolidator to produce a new 'TradeBar' representing the period
|
||||
/// </summary>
|
||||
/// <param name="period">The minimum span of time before emitting a consolidated bar</param>
|
||||
/// <param name="startTime">Optionally the bar start time anchor to use</param>
|
||||
protected TradeBarConsolidatorBase(TimeSpan period, TimeSpan? startTime = null)
|
||||
: base(period, startTime)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a consolidator to produce a new 'TradeBar' representing the last count pieces of data
|
||||
/// </summary>
|
||||
/// <param name="maxCount">The number of pieces to accept before emiting a consolidated bar</param>
|
||||
protected TradeBarConsolidatorBase(int maxCount)
|
||||
: base(maxCount)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a consolidator to produce a new 'TradeBar' representing the last count pieces of data or the period, whichever comes first
|
||||
/// </summary>
|
||||
/// <param name="maxCount">The number of pieces to accept before emiting a consolidated bar</param>
|
||||
/// <param name="period">The minimum span of time before emitting a consolidated bar</param>
|
||||
protected TradeBarConsolidatorBase(int maxCount, TimeSpan period)
|
||||
: base(maxCount, period)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a consolidator to produce a new 'TradeBar' representing the last count pieces of data or the period, whichever comes first
|
||||
/// </summary>
|
||||
/// <param name="func">Func that defines the start time of a consolidated data</param>
|
||||
protected TradeBarConsolidatorBase(Func<DateTime, CalendarInfo> func)
|
||||
: base(func)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a consolidator to produce a new 'TradeBar' representing the last count pieces of data or the period, whichever comes first
|
||||
/// </summary>
|
||||
/// <param name="pyfuncobj">Python function object that defines the start time of a consolidated data</param>
|
||||
protected TradeBarConsolidatorBase(PyObject pyfuncobj)
|
||||
: base(pyfuncobj)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a copy of the current 'workingBar'.
|
||||
/// </summary>
|
||||
public TradeBar WorkingBar => (TradeBar) WorkingData;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,149 @@
|
||||
/*
|
||||
* 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.Consolidators
|
||||
{
|
||||
/// <summary>
|
||||
/// This consolidator can transform a stream of <see cref="BaseData"/> instances into a stream of <see cref="RenkoBar"/>
|
||||
/// with a constant volume for each bar.
|
||||
/// </summary>
|
||||
public class VolumeRenkoConsolidator : DataConsolidator<BaseData>
|
||||
{
|
||||
private VolumeRenkoBar _currentBar;
|
||||
private decimal _barSize;
|
||||
|
||||
/// <summary>
|
||||
/// Gets a clone of the data being currently consolidated
|
||||
/// </summary>
|
||||
public override IBaseData WorkingData => _currentBar;
|
||||
|
||||
/// <summary>
|
||||
/// Gets <see cref="VolumeRenkoBar"/> which is the type emitted in the <see cref="IDataConsolidator.DataConsolidated"/> event.
|
||||
/// </summary>
|
||||
public override Type OutputType => typeof(VolumeRenkoBar);
|
||||
|
||||
/// <summary>
|
||||
/// Event handler that fires when a new piece of data is produced
|
||||
/// </summary>
|
||||
public new event EventHandler<VolumeRenkoBar> DataConsolidated;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="VolumeRenkoConsolidator"/> class using the specified <paramref name="barSize"/>.
|
||||
/// </summary>
|
||||
/// <param name="barSize">The constant volume size of each bar</param>
|
||||
public VolumeRenkoConsolidator(decimal barSize)
|
||||
{
|
||||
_barSize = barSize;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Updates this consolidator with the specified data
|
||||
/// </summary>
|
||||
/// <param name="data">The new data for the consolidator</param>
|
||||
public override void Update(BaseData data)
|
||||
{
|
||||
var close = data.Price;
|
||||
var dataType = data.GetType();
|
||||
|
||||
decimal volume;
|
||||
decimal open;
|
||||
decimal high;
|
||||
decimal low;
|
||||
|
||||
if (dataType == typeof(TradeBar))
|
||||
{
|
||||
var tradeBar = (TradeBar)data;
|
||||
volume = tradeBar.Volume;
|
||||
open = tradeBar.Open;
|
||||
high = tradeBar.High;
|
||||
low = tradeBar.Low;
|
||||
}
|
||||
else if (dataType == typeof(Tick))
|
||||
{
|
||||
var tick = (Tick)data;
|
||||
// Only include actual trade information
|
||||
if (tick.TickType != TickType.Trade)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
volume = tick.Quantity;
|
||||
open = close;
|
||||
high = close;
|
||||
low = close;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new ArgumentException($"{GetType().Name} must be used with TradeBar or Tick data.");
|
||||
}
|
||||
|
||||
var adjustedVolume = AdjustVolume(volume, close);
|
||||
|
||||
if (_currentBar == null)
|
||||
{
|
||||
_currentBar = new VolumeRenkoBar(data.Symbol, data.Time, data.EndTime, _barSize, open, high, low, close, 0);
|
||||
}
|
||||
var volumeLeftOver = _currentBar.Update(data.EndTime, high, low, close, adjustedVolume);
|
||||
while (volumeLeftOver >= 0)
|
||||
{
|
||||
OnDataConsolidated(_currentBar);
|
||||
_currentBar = _currentBar.Rollover();
|
||||
volumeLeftOver = _currentBar.Update(data.EndTime, high, low, close, volumeLeftOver);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the raw volume without any adjustment.
|
||||
/// </summary>
|
||||
/// <param name="volume">The volume</param>
|
||||
/// <param name="price">The price</param>
|
||||
/// <returns>The unmodified volume</returns>
|
||||
protected virtual decimal AdjustVolume(decimal volume, decimal price)
|
||||
{
|
||||
return volume;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Scans this consolidator to see if it should emit a bar due to time passing
|
||||
/// </summary>
|
||||
/// <param name="currentLocalTime">The current time in the local time zone (same as <see cref="BaseData.Time"/>)</param>
|
||||
public override void Scan(DateTime currentLocalTime)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Resets the consolidator
|
||||
/// </summary>
|
||||
public override void Reset()
|
||||
{
|
||||
base.Reset();
|
||||
_currentBar = null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Event invocator for the DataConsolidated event. This should be invoked
|
||||
/// by derived classes when they have consolidated a new piece of data.
|
||||
/// </summary>
|
||||
/// <param name="consolidated">The newly consolidated data</param>
|
||||
protected void OnDataConsolidated(VolumeRenkoBar consolidated)
|
||||
{
|
||||
base.OnDataConsolidated(consolidated);
|
||||
DataConsolidated?.Invoke(this, consolidated);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
namespace QuantConnect.Data
|
||||
{
|
||||
/// <summary>
|
||||
/// Constant dividend yield model
|
||||
/// </summary>
|
||||
public class ConstantDividendYieldModel : IDividendYieldModel
|
||||
{
|
||||
private readonly decimal _dividendYield;
|
||||
|
||||
/// <summary>
|
||||
/// Instantiates a <see cref="ConstantDividendYieldModel"/> with the specified dividend yield
|
||||
/// </summary>
|
||||
public ConstantDividendYieldModel(decimal dividendYield)
|
||||
{
|
||||
_dividendYield = dividendYield;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get dividend yield by a given date of a given symbol
|
||||
/// </summary>
|
||||
/// <param name="date">The date</param>
|
||||
/// <returns>Dividend yield on the given date of the given symbol</returns>
|
||||
public decimal GetDividendYield(DateTime date)
|
||||
{
|
||||
return _dividendYield;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get dividend yield at given date and security price
|
||||
/// </summary>
|
||||
/// <param name="date">The date</param>
|
||||
/// <param name="securityPrice">The security price at the given date</param>
|
||||
/// <returns>Dividend yield on the given date of the given symbol</returns>
|
||||
public decimal GetDividendYield(DateTime date, decimal securityPrice)
|
||||
{
|
||||
return _dividendYield;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
namespace QuantConnect.Data
|
||||
{
|
||||
/// <summary>
|
||||
/// Constant risk free rate interest rate model
|
||||
/// </summary>
|
||||
public class ConstantRiskFreeRateInterestRateModel : IRiskFreeInterestRateModel
|
||||
{
|
||||
private readonly decimal _riskFreeRate;
|
||||
|
||||
/// <summary>
|
||||
/// Instantiates a <see cref="ConstantRiskFreeRateInterestRateModel"/> with the specified risk free rate
|
||||
/// </summary>
|
||||
public ConstantRiskFreeRateInterestRateModel(decimal riskFreeRate)
|
||||
{
|
||||
_riskFreeRate = riskFreeRate;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get interest rate by a given date
|
||||
/// </summary>
|
||||
/// <param name="date">The date</param>
|
||||
/// <returns>Interest rate on the given date</returns>
|
||||
public decimal GetInterestRate(DateTime date)
|
||||
{
|
||||
return _riskFreeRate;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
namespace QuantConnect.Data.Custom.AlphaStreams
|
||||
{
|
||||
/// <summary>
|
||||
/// Static class for place holder
|
||||
/// </summary>
|
||||
[Obsolete("'QuantConnect.Data.Custom.Alphas' namespace is obsolete")]
|
||||
public static class PlaceHolder
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,246 @@
|
||||
/*
|
||||
* 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 System.IO;
|
||||
using System.Linq;
|
||||
using static QuantConnect.StringExtensions;
|
||||
|
||||
namespace QuantConnect.Data.Custom
|
||||
{
|
||||
/// <summary>
|
||||
/// FXCM Real FOREX Volume and Transaction data from its clients base, available for the following pairs:
|
||||
/// - EURUSD, USDJPY, GBPUSD, USDCHF, EURCHF, AUDUSD, USDCAD,
|
||||
/// NZDUSD, EURGBP, EURJPY, GBPJPY, EURAUD, EURCAD, AUDJPY
|
||||
/// FXCM only provides support for FX symbols which produced over 110 million average daily volume (ADV) during 2013.
|
||||
/// This limit is imposed to ensure we do not highlight low volume/low ticket symbols in addition to other financial
|
||||
/// reporting concerns.
|
||||
/// </summary>
|
||||
/// <seealso cref="QuantConnect.Data.BaseData" />
|
||||
public class FxcmVolume : BaseData
|
||||
{
|
||||
/// <summary>
|
||||
/// Auxiliary enum used to map the pair symbol into FXCM request code.
|
||||
/// </summary>
|
||||
private enum FxcmSymbolId
|
||||
{
|
||||
EURUSD = 1,
|
||||
USDJPY = 2,
|
||||
GBPUSD = 3,
|
||||
USDCHF = 4,
|
||||
EURCHF = 5,
|
||||
AUDUSD = 6,
|
||||
USDCAD = 7,
|
||||
NZDUSD = 8,
|
||||
EURGBP = 9,
|
||||
EURJPY = 10,
|
||||
GBPJPY = 11,
|
||||
EURAUD = 14,
|
||||
EURCAD = 15,
|
||||
AUDJPY = 17
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The request base URL.
|
||||
/// </summary>
|
||||
private readonly string _baseUrl = " http://marketsummary2.fxcorporate.com/ssisa/servlet?RT=SSI";
|
||||
|
||||
/// <summary>
|
||||
/// FXCM session id.
|
||||
/// </summary>
|
||||
private readonly string _sid = "quantconnect";
|
||||
|
||||
/// <summary>
|
||||
/// The columns index which should be added to obtain the transactions.
|
||||
/// </summary>
|
||||
private readonly long[] _transactionsIdx = { 27, 29, 31, 33 };
|
||||
|
||||
/// <summary>
|
||||
/// Integer representing client version.
|
||||
/// </summary>
|
||||
private readonly int _ver = 1;
|
||||
|
||||
/// <summary>
|
||||
/// The columns index which should be added to obtain the volume.
|
||||
/// </summary>
|
||||
private readonly int[] _volumeIdx = { 26, 28, 30, 32 };
|
||||
|
||||
/// <summary>
|
||||
/// Sum of opening and closing Transactions for the entire time interval.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// The transactions.
|
||||
/// </value>
|
||||
public int Transactions { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Sum of opening and closing Volume for the entire time interval.
|
||||
/// The volume measured in the QUOTE CURRENCY.
|
||||
/// </summary>
|
||||
/// <remarks>Please remember to convert this data to a common currency before making comparison between different pairs.</remarks>
|
||||
public long Volume { get; set; }
|
||||
|
||||
/// <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>
|
||||
/// <exception cref="System.NotImplementedException">FOREX Volume data is not available in live mode, yet.</exception>
|
||||
public override SubscriptionDataSource GetSource(SubscriptionDataConfig config, DateTime date, bool isLiveMode)
|
||||
{
|
||||
var interval = GetIntervalFromResolution(config.Resolution);
|
||||
var symbolId = GetFxcmIDFromSymbol(config.Symbol.Value.Split('_').First());
|
||||
|
||||
if (isLiveMode)
|
||||
{
|
||||
var source = Invariant($"{_baseUrl}&ver={_ver}&sid={_sid}&interval={interval}&offerID={symbolId}");
|
||||
return new SubscriptionDataSource(source, SubscriptionTransportMedium.Rest, FileFormat.Csv);
|
||||
}
|
||||
else
|
||||
{
|
||||
var source = GenerateZipFilePath(config, date);
|
||||
return new SubscriptionDataSource(source, SubscriptionTransportMedium.LocalFile);
|
||||
}
|
||||
}
|
||||
|
||||
/// <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. The returned object is assumed to be time stamped in the config.ExchangeTimeZone.
|
||||
/// </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)
|
||||
{
|
||||
var fxcmVolume = new FxcmVolume { DataType = MarketDataType.Base, Symbol = config.Symbol };
|
||||
if (isLiveMode)
|
||||
{
|
||||
try
|
||||
{
|
||||
var obs = line.Split('\n')[2].Split(';');
|
||||
var stringDate = obs[0].Substring(startIndex: 3);
|
||||
fxcmVolume.Time = DateTime.ParseExact(stringDate, "yyyyMMddHHmm", DateTimeFormatInfo.InvariantInfo);
|
||||
fxcmVolume.Volume = _volumeIdx.Select(x => Parse.Long(obs[x])).Sum();
|
||||
fxcmVolume.Transactions = _transactionsIdx.Select(x => Parse.Int(obs[x])).Sum();
|
||||
fxcmVolume.Value = fxcmVolume.Volume;
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
Logging.Log.Error($"Invalid data. Line: {line}. Exception: {exception.Message}");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
var obs = line.Split(',');
|
||||
if (config.Resolution == Resolution.Minute)
|
||||
{
|
||||
fxcmVolume.Time = date.Date.AddMilliseconds(Parse.Int(obs[0]));
|
||||
}
|
||||
else
|
||||
{
|
||||
fxcmVolume.Time = DateTime.ParseExact(obs[0], "yyyyMMdd HH:mm", CultureInfo.InvariantCulture);
|
||||
}
|
||||
fxcmVolume.Volume = Parse.Long(obs[1]);
|
||||
fxcmVolume.Transactions = obs[2].ConvertInvariant<int>();
|
||||
fxcmVolume.Value = fxcmVolume.Volume;
|
||||
}
|
||||
return fxcmVolume;
|
||||
}
|
||||
|
||||
private static string GenerateZipFilePath(SubscriptionDataConfig config, DateTime date)
|
||||
{
|
||||
var source = Path.Combine(new[] { Globals.DataFolder, "forex", "fxcm", config.Resolution.ToLower() });
|
||||
string filename;
|
||||
|
||||
var symbol = config.Symbol.Value.Split('_').First().ToLowerInvariant();
|
||||
if (config.Resolution == Resolution.Minute)
|
||||
{
|
||||
filename = Invariant($"{date:yyyyMMdd}_volume.zip");
|
||||
source = Path.Combine(source, symbol, filename);
|
||||
}
|
||||
else
|
||||
{
|
||||
filename = $"{symbol}_volume.zip";
|
||||
source = Path.Combine(source, filename);
|
||||
}
|
||||
return source;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the FXCM identifier from a FOREX pair ticker.
|
||||
/// </summary>
|
||||
/// <param name="ticker">The pair ticker.</param>
|
||||
/// <returns></returns>
|
||||
/// <exception cref="System.ArgumentException">Volume data is not available for the selected ticker. - ticker</exception>
|
||||
private int GetFxcmIDFromSymbol(string ticker)
|
||||
{
|
||||
int symbolId;
|
||||
try
|
||||
{
|
||||
symbolId = (int)Enum.Parse(typeof(FxcmSymbolId), ticker);
|
||||
}
|
||||
catch (ArgumentException)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(ticker), ticker,
|
||||
"Volume data is not available for the selected ticker.");
|
||||
}
|
||||
return symbolId;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the string interval representation from the resolution.
|
||||
/// </summary>
|
||||
/// <param name="resolution">The requested resolution.</param>
|
||||
/// <returns></returns>
|
||||
/// <exception cref="System.ArgumentOutOfRangeException">
|
||||
/// resolution - tick or second resolution are not supported for Forex
|
||||
/// Volume.
|
||||
/// </exception>
|
||||
private string GetIntervalFromResolution(Resolution resolution)
|
||||
{
|
||||
string interval;
|
||||
switch (resolution)
|
||||
{
|
||||
case Resolution.Minute:
|
||||
interval = "M1";
|
||||
break;
|
||||
|
||||
case Resolution.Hour:
|
||||
interval = "H1";
|
||||
break;
|
||||
|
||||
case Resolution.Daily:
|
||||
interval = "D1";
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException(nameof(resolution), resolution,
|
||||
"Tick or second resolution are not supported for Forex Volume. Available resolutions are Minute, Hour and Daily.");
|
||||
}
|
||||
return interval;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,144 @@
|
||||
/*
|
||||
* 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 QuantConnect.Data;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using ProtoBuf;
|
||||
|
||||
namespace QuantConnect.Data.Custom.IconicTypes
|
||||
{
|
||||
/// <summary>
|
||||
/// Data type that is indexed, i.e. a file that points to another file containing the contents
|
||||
/// we're looking for in a Symbol.
|
||||
/// </summary>
|
||||
[ProtoContract(SkipConstructor = true)]
|
||||
public class IndexedLinkedData : IndexedBaseData
|
||||
{
|
||||
/// <summary>
|
||||
/// Example data property
|
||||
/// </summary>
|
||||
[ProtoMember(55)]
|
||||
public int Count { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Determines the actual source from an index contained within a ticker folder
|
||||
/// </summary>
|
||||
/// <param name="config">Subscription configuration</param>
|
||||
/// <param name="date">Date</param>
|
||||
/// <param name="index">File to load data from</param>
|
||||
/// <param name="isLiveMode">Is live mode</param>
|
||||
/// <returns>SubscriptionDataSource pointing to the article</returns>
|
||||
public override SubscriptionDataSource GetSourceForAnIndex(SubscriptionDataConfig config, DateTime date, string index, bool isLiveMode)
|
||||
{
|
||||
return new SubscriptionDataSource(
|
||||
Path.Combine("TestData",
|
||||
"indexlinked",
|
||||
"content",
|
||||
$"{date.ToStringInvariant(DateFormat.EightCharacter)}.zip#{index}"
|
||||
),
|
||||
SubscriptionTransportMedium.LocalFile,
|
||||
FileFormat.Csv
|
||||
);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the source of the index file
|
||||
/// </summary>
|
||||
/// <param name="config">Configuration object</param>
|
||||
/// <param name="date">Date of this source file</param>
|
||||
/// <param name="isLiveMode">Is live mode</param>
|
||||
/// <returns>SubscriptionDataSource indicating where data is located and how it's stored</returns>
|
||||
public override SubscriptionDataSource GetSource(SubscriptionDataConfig config, DateTime date, bool isLiveMode)
|
||||
{
|
||||
return new SubscriptionDataSource(
|
||||
Path.Combine(
|
||||
"TestData",
|
||||
"indexlinked",
|
||||
config.Symbol.Value.ToLowerInvariant(),
|
||||
$"{date.ToStringInvariant(DateFormat.EightCharacter)}.csv"
|
||||
),
|
||||
SubscriptionTransportMedium.LocalFile,
|
||||
FileFormat.Index
|
||||
);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates an instance from a line of JSON containing article information read from the `content` directory
|
||||
/// </summary>
|
||||
/// <param name="config">Subscription configuration</param>
|
||||
/// <param name="line">Line of data</param>
|
||||
/// <param name="date">Date</param>
|
||||
/// <param name="isLiveMode">Is live mode</param>
|
||||
public override BaseData Reader(SubscriptionDataConfig config, string line, DateTime date, bool isLiveMode)
|
||||
{
|
||||
return new IndexedLinkedData
|
||||
{
|
||||
Count = 10,
|
||||
Symbol = config.Symbol,
|
||||
EndTime = date
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Indicates whether the data source is sparse.
|
||||
/// If false, it will disable missing file logging.
|
||||
/// </summary>
|
||||
/// <returns>true</returns>
|
||||
public override bool IsSparseData()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Indicates whether the data source can undergo
|
||||
/// rename events/is tied to equities.
|
||||
/// </summary>
|
||||
/// <returns>true</returns>
|
||||
public override bool RequiresMapping()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Set the data time zone to UTC
|
||||
/// </summary>
|
||||
/// <returns>Time zone as UTC</returns>
|
||||
public override DateTimeZone DataTimeZone()
|
||||
{
|
||||
return TimeZones.Utc;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the default resolution to Second
|
||||
/// </summary>
|
||||
/// <returns>Resolution.Second</returns>
|
||||
public override Resolution DefaultResolution()
|
||||
{
|
||||
return Resolution.Daily;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a list of all the supported Resolutions
|
||||
/// </summary>
|
||||
/// <returns>All resolutions</returns>
|
||||
public override List<Resolution> SupportedResolutions()
|
||||
{
|
||||
return DailyResolution;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,149 @@
|
||||
/*
|
||||
* 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 QuantConnect.Data;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using ProtoBuf;
|
||||
|
||||
namespace QuantConnect.Data.Custom.IconicTypes
|
||||
{
|
||||
/// <summary>
|
||||
/// Data type that is indexed, i.e. a file that points to another file containing the contents
|
||||
/// we're looking for in a Symbol.
|
||||
/// </summary>
|
||||
[ProtoContract(SkipConstructor = true)]
|
||||
public class IndexedLinkedData2 : IndexedBaseData
|
||||
{
|
||||
/// <summary>
|
||||
/// Example data property
|
||||
/// </summary>
|
||||
[ProtoMember(55)]
|
||||
public int Count { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Determines the actual source from an index contained within a ticker folder
|
||||
/// </summary>
|
||||
/// <param name="config">Subscription configuration</param>
|
||||
/// <param name="date">Date</param>
|
||||
/// <param name="index">File to load data from</param>
|
||||
/// <param name="isLiveMode">Is live mode</param>
|
||||
/// <returns>SubscriptionDataSource pointing to the article</returns>
|
||||
public override SubscriptionDataSource GetSourceForAnIndex(SubscriptionDataConfig config, DateTime date, string index, bool isLiveMode)
|
||||
{
|
||||
return new SubscriptionDataSource(
|
||||
Path.Combine("TestData",
|
||||
"indexlinked2",
|
||||
"content",
|
||||
$"{date.ToStringInvariant(DateFormat.EightCharacter)}.zip#{index}"
|
||||
),
|
||||
SubscriptionTransportMedium.LocalFile,
|
||||
FileFormat.Csv
|
||||
);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the source of the index file
|
||||
/// </summary>
|
||||
/// <param name="config">Configuration object</param>
|
||||
/// <param name="date">Date of this source file</param>
|
||||
/// <param name="isLiveMode">Is live mode</param>
|
||||
/// <returns>SubscriptionDataSource indicating where data is located and how it's stored</returns>
|
||||
public override SubscriptionDataSource GetSource(SubscriptionDataConfig config, DateTime date, bool isLiveMode)
|
||||
{
|
||||
if (isLiveMode)
|
||||
{
|
||||
throw new NotImplementedException("Live mode not supported");
|
||||
}
|
||||
|
||||
return new SubscriptionDataSource(
|
||||
Path.Combine(
|
||||
"TestData",
|
||||
"indexlinked2",
|
||||
config.Symbol.Value.ToLowerInvariant(),
|
||||
$"{date.ToStringInvariant(DateFormat.EightCharacter)}.csv"
|
||||
),
|
||||
SubscriptionTransportMedium.LocalFile,
|
||||
FileFormat.Index
|
||||
);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates an instance from a line of JSON containing article information read from the `content` directory
|
||||
/// </summary>
|
||||
/// <param name="config">Subscription configuration</param>
|
||||
/// <param name="line">Line of data</param>
|
||||
/// <param name="date">Date</param>
|
||||
/// <param name="isLiveMode">Is live mode</param>
|
||||
public override BaseData Reader(SubscriptionDataConfig config, string line, DateTime date, bool isLiveMode)
|
||||
{
|
||||
return new IndexedLinkedData2
|
||||
{
|
||||
Count = 10,
|
||||
Symbol = config.Symbol,
|
||||
EndTime = date
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Indicates whether the data source is sparse.
|
||||
/// If false, it will disable missing file logging.
|
||||
/// </summary>
|
||||
/// <returns>true</returns>
|
||||
public override bool IsSparseData()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Indicates whether the data source can undergo
|
||||
/// rename events/is tied to equities.
|
||||
/// </summary>
|
||||
/// <returns>true</returns>
|
||||
public override bool RequiresMapping()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Set the data time zone to UTC
|
||||
/// </summary>
|
||||
/// <returns>Time zone as UTC</returns>
|
||||
public override DateTimeZone DataTimeZone()
|
||||
{
|
||||
return TimeZones.Utc;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the default resolution to Second
|
||||
/// </summary>
|
||||
/// <returns>Resolution.Second</returns>
|
||||
public override Resolution DefaultResolution()
|
||||
{
|
||||
return Resolution.Daily;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a list of all the supported Resolutions
|
||||
/// </summary>
|
||||
/// <returns>All resolutions</returns>
|
||||
public override List<Resolution> SupportedResolutions()
|
||||
{
|
||||
return DailyResolution;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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 NodaTime;
|
||||
using QuantConnect.Data;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using ProtoBuf;
|
||||
|
||||
namespace QuantConnect.Data.Custom.IconicTypes
|
||||
{
|
||||
/// <summary>
|
||||
/// Data source that is linked (tickers that can have renames or be delisted)
|
||||
/// </summary>
|
||||
[ProtoContract(SkipConstructor = true)]
|
||||
public class LinkedData : BaseData
|
||||
{
|
||||
/// <summary>
|
||||
/// Example data
|
||||
/// </summary>
|
||||
[ProtoMember(55)]
|
||||
public int Count { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Return the URL string source of the file. This will be converted to a stream
|
||||
/// </summary>
|
||||
public override SubscriptionDataSource GetSource(SubscriptionDataConfig config, DateTime date, bool isLiveMode)
|
||||
{
|
||||
return new SubscriptionDataSource(
|
||||
Path.Combine(
|
||||
"TestData",
|
||||
"linked",
|
||||
$"{config.Symbol.Underlying.Value.ToLowerInvariant()}.csv"
|
||||
),
|
||||
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. The returned object is assumed to be time stamped in the config.ExchangeTimeZone.
|
||||
/// </summary>
|
||||
public override BaseData Reader(SubscriptionDataConfig config, string line, DateTime date, bool isLiveMode)
|
||||
{
|
||||
return new LinkedData
|
||||
{
|
||||
Count = 10,
|
||||
Symbol = config.Symbol,
|
||||
EndTime = date
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Indicates whether the data source is sparse.
|
||||
/// If false, it will disable missing file logging.
|
||||
/// </summary>
|
||||
/// <returns>true</returns>
|
||||
public override bool IsSparseData()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Indicates whether the data source can undergo
|
||||
/// rename events/is tied to equities.
|
||||
/// </summary>
|
||||
/// <returns>true</returns>
|
||||
public override bool RequiresMapping()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Set the data time zone to UTC
|
||||
/// </summary>
|
||||
/// <returns>Time zone as UTC</returns>
|
||||
public override DateTimeZone DataTimeZone()
|
||||
{
|
||||
return TimeZones.Utc;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the default resolution to Second
|
||||
/// </summary>
|
||||
/// <returns>Resolution.Second</returns>
|
||||
public override Resolution DefaultResolution()
|
||||
{
|
||||
return Resolution.Daily;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a list of all the supported Resolutions
|
||||
/// </summary>
|
||||
/// <returns>All resolutions</returns>
|
||||
public override List<Resolution> SupportedResolutions()
|
||||
{
|
||||
return DailyResolution;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,126 @@
|
||||
/*
|
||||
* 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 QuantConnect.Data;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using ProtoBuf;
|
||||
|
||||
namespace QuantConnect.Data.Custom.IconicTypes
|
||||
{
|
||||
/// <summary>
|
||||
/// Data source that is unlinked (no mapping) and takes any ticker when calling AddData
|
||||
/// </summary>
|
||||
[ProtoContract(SkipConstructor = true)]
|
||||
public class UnlinkedData : BaseData
|
||||
{
|
||||
/// <summary>
|
||||
/// If true, we accept any ticker from the AddData call
|
||||
/// </summary>
|
||||
public static bool AnyTicker { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Example data
|
||||
/// </summary>
|
||||
[ProtoMember(55)]
|
||||
public string Ticker { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Return the path 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 path of source file.</returns>
|
||||
public override SubscriptionDataSource GetSource(SubscriptionDataConfig config, DateTime date, bool isLiveMode)
|
||||
{
|
||||
return new SubscriptionDataSource(
|
||||
Path.Combine(
|
||||
"TestData",
|
||||
"unlinked",
|
||||
AnyTicker ? "data.csv" : $"{config.Symbol.Value.ToLowerInvariant()}.csv"
|
||||
),
|
||||
SubscriptionTransportMedium.LocalFile,
|
||||
FileFormat.Csv);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates UnlinkedData objects using the subscription data config setup as well as the date.
|
||||
/// </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 UnlinkedData object generated by this line of the CSV</returns>
|
||||
public override BaseData Reader(SubscriptionDataConfig config, string line, DateTime date, bool isLiveMode)
|
||||
{
|
||||
return new UnlinkedData
|
||||
{
|
||||
Ticker = AnyTicker ? "ANY" : $"{config.Symbol.Value}",
|
||||
Symbol = config.Symbol,
|
||||
EndTime = date
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Indicates whether the data source is sparse.
|
||||
/// If false, it will disable missing file logging.
|
||||
/// </summary>
|
||||
/// <returns>true</returns>
|
||||
public override bool IsSparseData()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Indicates whether the data source can undergo
|
||||
/// rename events/is tied to equities.
|
||||
/// </summary>
|
||||
/// <returns>true</returns>
|
||||
public override bool RequiresMapping()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Set the data time zone to UTC
|
||||
/// </summary>
|
||||
/// <returns>Time zone as UTC</returns>
|
||||
public override DateTimeZone DataTimeZone()
|
||||
{
|
||||
return TimeZones.Utc;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the default resolution to Second
|
||||
/// </summary>
|
||||
/// <returns>Resolution.Second</returns>
|
||||
public override Resolution DefaultResolution()
|
||||
{
|
||||
return Resolution.Daily;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a list of all the supported Resolutions
|
||||
/// </summary>
|
||||
/// <returns>All resolutions</returns>
|
||||
public override List<Resolution> SupportedResolutions()
|
||||
{
|
||||
return DailyResolution;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,136 @@
|
||||
/*
|
||||
* 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 QuantConnect.Data;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using ProtoBuf;
|
||||
using QuantConnect.Data.Market;
|
||||
|
||||
namespace QuantConnect.Data.Custom.IconicTypes
|
||||
{
|
||||
/// <summary>
|
||||
/// Data source that is unlinked (no mapping) and takes any ticker when calling AddData
|
||||
/// </summary>
|
||||
[ProtoContract(SkipConstructor = true)]
|
||||
public class UnlinkedDataTradeBar : TradeBar
|
||||
{
|
||||
/// <summary>
|
||||
/// If true, we accept any ticker from the AddData call
|
||||
/// </summary>
|
||||
public static bool AnyTicker { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new instance of an UnlinkedTradeBar
|
||||
/// </summary>
|
||||
public UnlinkedDataTradeBar()
|
||||
{
|
||||
DataType = MarketDataType.Base;
|
||||
Period = TimeSpan.FromDays(1);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get Source for Custom Data File
|
||||
/// >> What source file location would you prefer for each type of usage:
|
||||
/// </summary>
|
||||
/// <param name="config">Configuration object</param>
|
||||
/// <param name="date">Date of this source request if source spread across multiple files</param>
|
||||
/// <param name="isLiveMode">true if we're in live mode, false for backtesting mode</param>
|
||||
/// <returns>String source location of the file</returns>
|
||||
public override SubscriptionDataSource GetSource(SubscriptionDataConfig config, DateTime date, bool isLiveMode)
|
||||
{
|
||||
return new SubscriptionDataSource(
|
||||
Path.Combine(
|
||||
"TestData",
|
||||
"unlinkedtradebar",
|
||||
AnyTicker ? "data.csv" : $"{config.Symbol.Value.ToLowerInvariant()}.csv"
|
||||
),
|
||||
SubscriptionTransportMedium.LocalFile,
|
||||
FileFormat.Csv);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Fetch the data from the storage and feed it line by line into the engine.
|
||||
/// </summary>
|
||||
/// <param name="config">Symbols, Resolution, DataType, </param>
|
||||
/// <param name="line">Line from the data file requested</param>
|
||||
/// <param name="date">Date of this reader request</param>
|
||||
/// <param name="isLiveMode">true if we're in live mode, false for backtesting mode</param>
|
||||
/// <returns>Enumerable iterator for returning each line of the required data.</returns>
|
||||
public override BaseData Reader(SubscriptionDataConfig config, string line, DateTime date, bool isLiveMode)
|
||||
{
|
||||
return new UnlinkedDataTradeBar
|
||||
{
|
||||
Open = 1m,
|
||||
High = 2m,
|
||||
Low = 1m,
|
||||
Close = 1.5m,
|
||||
Volume = 0m,
|
||||
|
||||
Symbol = config.Symbol,
|
||||
EndTime = date
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Indicates whether the data source is sparse.
|
||||
/// If false, it will disable missing file logging.
|
||||
/// </summary>
|
||||
/// <returns>true</returns>
|
||||
public override bool IsSparseData()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Indicates whether the data source can undergo
|
||||
/// rename events/is tied to equities.
|
||||
/// </summary>
|
||||
/// <returns>true</returns>
|
||||
public override bool RequiresMapping()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Set the data time zone to UTC
|
||||
/// </summary>
|
||||
/// <returns>Time zone as UTC</returns>
|
||||
public override DateTimeZone DataTimeZone()
|
||||
{
|
||||
return TimeZones.Utc;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the default resolution to Second
|
||||
/// </summary>
|
||||
/// <returns>Resolution.Second</returns>
|
||||
public override Resolution DefaultResolution()
|
||||
{
|
||||
return Resolution.Daily;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a list of all the supported Resolutions
|
||||
/// </summary>
|
||||
/// <returns>All resolutions</returns>
|
||||
public override List<Resolution> SupportedResolutions()
|
||||
{
|
||||
return DailyResolution;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,498 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
namespace QuantConnect.Data.Custom.Intrinio
|
||||
{
|
||||
/// <summary>
|
||||
/// Intrinio Data Source
|
||||
/// </summary>
|
||||
public static class IntrinioEconomicDataSources
|
||||
{
|
||||
/// <summary>
|
||||
/// Bank of America Merrill Lynch
|
||||
/// </summary>
|
||||
public static class BofAMerrillLynch
|
||||
{
|
||||
/// <summary>
|
||||
/// This data represents the effective yield of the BofA Merrill Lynch US Corporate BBB Index, a subset of the BofA
|
||||
/// Merrill Lynch US Corporate Master Index tracking the performance of US dollar denominated investment grade rated
|
||||
/// corporate debt publically issued in the US domestic market.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Source: https://fred.stlouisfed.org/series/BAMLC0A4CBBBEY
|
||||
/// </remarks>
|
||||
public const string USCorporateBBBEffectiveYield = "$BAMLC0A4CBBBEY";
|
||||
|
||||
/// <summary>
|
||||
/// This data represents the Option-Adjusted Spread (OAS) of the BofA Merrill Lynch US Corporate BBB Index, a subset of
|
||||
/// the BofA Merrill Lynch US Corporate Master Index tracking the performance of US dollar denominated investment grade
|
||||
/// rated corporate debt publically issued in the US domestic market.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Source: https://fred.stlouisfed.org/series/BAMLC0A4CBBB
|
||||
/// </remarks>
|
||||
public const string USCorporateBBBOptionAdjustedSpread = "$BAMLC0A4CBBB";
|
||||
|
||||
/// <summary>
|
||||
/// The BofA Merrill Lynch Option-Adjusted Spreads (OASs) are the calculated spreads between a computed OAS index of
|
||||
/// all bonds in a given rating category and a spot Treasury curve. An OAS index is constructed using each constituent
|
||||
/// bond’s OAS, weighted by market capitalization.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Source: https://fred.stlouisfed.org/series/BAMLC0A0CM
|
||||
/// </remarks>
|
||||
public const string USCorporateMasterOptionAdjustedSpread = "$BAMLC0A0CM";
|
||||
|
||||
/// <summary>
|
||||
/// This data represents the Option-Adjusted Spread (OAS) of the BofA Merrill Lynch US Corporate BB Index, a subset of
|
||||
/// the BofA Merrill Lynch US High Yield Master II Index tracking the performance of US dollar denominated below
|
||||
/// investment grade rated corporate debt publically issued in the US domestic market.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Source: https://fred.stlouisfed.org/series/BAMLH0A1HYBB
|
||||
/// </remarks>
|
||||
public const string USHighYieldBBOptionAdjustedSpread = "$BAMLH0A1HYBB";
|
||||
|
||||
/// <summary>
|
||||
/// This data represents the Option-Adjusted Spread (OAS) of the BofA Merrill Lynch US Corporate B Index, a subset of
|
||||
/// the BofA Merrill Lynch US High Yield Master II Index tracking the performance of US dollar denominated below
|
||||
/// investment grade rated corporate debt publically issued in the US domestic market. This subset includes all
|
||||
/// securities with a given investment grade rating B.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Source: https://fred.stlouisfed.org/series/BAMLH0A2HYB
|
||||
/// </remarks>
|
||||
public const string USHighYieldBOptionAdjustedSpread = "$BAMLH0A2HYB";
|
||||
|
||||
/// <summary>
|
||||
/// This data represents the Option-Adjusted Spread (OAS) of the BofA Merrill Lynch US Corporate C Index, a subset of
|
||||
/// the BofA Merrill Lynch US High Yield Master II Index tracking the performance of US dollar denominated below
|
||||
/// investment grade rated corporate debt publically issued in the US domestic market.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Source: https://fred.stlouisfed.org/series/BAMLH0A3HYC
|
||||
/// </remarks>
|
||||
public const string USHighYieldCCCorBelowOptionAdjustedSpread = "$BAMLH0A3HYC";
|
||||
|
||||
/// <summary>
|
||||
/// This data represents the effective yield of the BofA Merrill Lynch US High Yield Master II Index, which tracks the
|
||||
/// performance of US dollar denominated below investment grade rated corporate debt publically issued in the US
|
||||
/// domestic market.
|
||||
/// Source: https://fred.stlouisfed.org/series/BAMLH0A0HYM2EY
|
||||
/// </summary>
|
||||
public const string USHighYieldEffectiveYield = "$BAMLH0A0HYM2EY";
|
||||
|
||||
/// <summary>
|
||||
/// This data represents the BofA Merrill Lynch US High Yield Master II Index value, which tracks the performance of US
|
||||
/// dollar denominated below investment grade rated corporate debt publically issued in the US domestic market.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Source: https://fred.stlouisfed.org/series/BAMLHYH0A0HYM2TRIV
|
||||
/// </remarks>
|
||||
public const string USHighYieldMasterIITotalReturnIndexValue = "$BAMLHYH0A0HYM2TRIV";
|
||||
|
||||
/// <summary>
|
||||
/// The BofA Merrill Lynch Option-Adjusted Spreads (OASs) are the calculated spreads between a computed OAS index of
|
||||
/// all bonds in a given rating category and a spot Treasury curve. An OAS index is constructed using each constituent
|
||||
/// bond’s OAS, weighted by market capitalization.
|
||||
/// Source: https://fred.stlouisfed.org/series/BAMLH0A0HYM2
|
||||
/// </summary>
|
||||
public const string USHighYieldOptionAdjustedSpread = "$BAMLH0A0HYM2";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Chicago Board Options Exchange
|
||||
/// </summary>
|
||||
public static class CBOE
|
||||
{
|
||||
/// <summary>
|
||||
/// CBOE China ETF Volatility Index
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Source: https://fred.stlouisfed.org/series/VXFXICLS
|
||||
/// </remarks>
|
||||
public const string ChinaETFVolatilityIndex = "$VXFXICLS";
|
||||
|
||||
/// <summary>
|
||||
/// CBOE Crude Oil ETF Volatility Index
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Source: https://fred.stlouisfed.org/series/OVXCLS
|
||||
/// </remarks>
|
||||
public const string CrudeOilETFVolatilityIndex = "$OVXCLS";
|
||||
|
||||
/// <summary>
|
||||
/// CBOE Emerging Markets ETF Volatility Index
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Source: https://fred.stlouisfed.org/series/VXEEMCLS
|
||||
/// </remarks>
|
||||
public const string EmergingMarketsETFVolatilityIndex = "$VXEEMCLS";
|
||||
|
||||
/// <summary>
|
||||
/// CBOE Gold ETF Volatility Index
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Source: https://fred.stlouisfed.org/series/GVZCLS
|
||||
/// </remarks>
|
||||
public const string GoldETFVolatilityIndex = "$GVZCLS";
|
||||
|
||||
/// <summary>
|
||||
/// CBOE 10-Year Treasury Note Volatility Futures
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Source: https://fred.stlouisfed.org/series/VXTYN
|
||||
/// </remarks>
|
||||
public const string TenYearTreasuryNoteVolatilityFutures = "$VXTYN";
|
||||
|
||||
/// <summary>
|
||||
/// CBOE Volatility Index: VIX
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Source: https://fred.stlouisfed.org/series/VIXCLS
|
||||
/// </remarks>
|
||||
public const string VIX = "$VIXCLS";
|
||||
|
||||
/// <summary>
|
||||
/// CBOE S&P 100 Volatility Index: VXO
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Source: https://fred.stlouisfed.org/series/VXOCLS
|
||||
/// </remarks>
|
||||
public const string VXO = "$VXOCLS";
|
||||
|
||||
/// <summary>
|
||||
/// CBOE S&P 500 3-Month Volatility Index
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Source: https://fred.stlouisfed.org/series/VXVCLS
|
||||
/// </remarks>
|
||||
public const string VXV = "$VXVCLS";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Commodities
|
||||
/// </summary>
|
||||
public static class Commodities
|
||||
{
|
||||
/// <summary>
|
||||
/// Crude Oil Prices: Brent - Europe
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Source: https://fred.stlouisfed.org/series/DCOILBRENTEU
|
||||
/// </remarks>
|
||||
public const string CrudeOilBrent = "$DCOILBRENTEU";
|
||||
|
||||
/// <summary>
|
||||
/// Crude Oil Prices: West Texas Intermediate (WTI) - Cushing, Oklahoma
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Source: https://fred.stlouisfed.org/series/DCOILWTICO
|
||||
/// </remarks>
|
||||
public const string CrudeOilWTI = "$DCOILWTICO";
|
||||
|
||||
/// <summary>
|
||||
/// Conventional Gasoline Prices: U.S. Gulf Coast, Regular
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Source: https://fred.stlouisfed.org/series/DGASUSGULF
|
||||
/// </remarks>
|
||||
public const string GasolineUSGulfCoast = "$DGASUSGULF";
|
||||
|
||||
/// <summary>
|
||||
/// Gold Fixing Price 10:30 A.M. (London time) in London Bullion Market, based in U.S. Dollars
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Source: https://fred.stlouisfed.org/series/GOLDAMGBD228NLBM
|
||||
/// </remarks>
|
||||
public const string GoldFixingPrice1030amLondon = "$GOLDAMGBD228NLBM";
|
||||
|
||||
/// <summary>
|
||||
/// Gold Fixing Price 3:00 P.M. (London time) in London Bullion Market, based in U.S. Dollars
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Source: https://fred.stlouisfed.org/series/GOLDPMGBD228NLBM
|
||||
/// </remarks>
|
||||
public const string GoldFixingPrice1500amLondon = "$GOLDPMGBD228NLBM";
|
||||
|
||||
/// <summary>
|
||||
/// Henry Hub Natural Gas Spot Price
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Source: https://fred.stlouisfed.org/series/DHHNGSP
|
||||
/// </remarks>
|
||||
public const string NaturalGas = "$DHHNGSP";
|
||||
|
||||
/// <summary>
|
||||
/// Propane Prices: Mont Belvieu, Texas
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Source: https://fred.stlouisfed.org/series/DPROPANEMBTX
|
||||
/// </remarks>
|
||||
public const string Propane = "$DPROPANEMBTX";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Exchange Rates
|
||||
/// </summary>
|
||||
public static class ExchangeRates
|
||||
{
|
||||
/// <summary>
|
||||
/// Brazilian Reals to One U.S. Dollar
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Source: Board of Governors of the Federal Reserve System https://www.federalreserve.gov/releases/h10/
|
||||
/// </remarks>
|
||||
public const string Brazil_USA = "$DEXBZUS";
|
||||
|
||||
/// <summary>
|
||||
/// Canadian Dollars to One U.S. Dollar
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Source: Board of Governors of the Federal Reserve System https://www.federalreserve.gov/releases/h10/
|
||||
/// </remarks>
|
||||
public const string Canada_USA = "$DEXCAUS";
|
||||
|
||||
/// <summary>
|
||||
/// Chinese Yuan to One U.S. Dollar
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Source: Board of Governors of the Federal Reserve System https://www.federalreserve.gov/releases/h10/
|
||||
/// </remarks>
|
||||
public const string China_USA = "$DEXCHUS";
|
||||
|
||||
/// <summary>
|
||||
/// Hong Kong Dollars to One U.S. Dollar
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Source: Board of Governors of the Federal Reserve System https://www.federalreserve.gov/releases/h10/
|
||||
/// </remarks>
|
||||
public const string HongKong_USA = "$DEXHKUS";
|
||||
|
||||
/// <summary>
|
||||
/// Indian Rupees to One U.S. Dollar
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Source: Board of Governors of the Federal Reserve System https://www.federalreserve.gov/releases/h10/
|
||||
/// </remarks>
|
||||
public const string India_USA = "$DEXINUS";
|
||||
|
||||
/// <summary>
|
||||
/// Japanese Yen to One U.S. Dollar
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Source: Board of Governors of the Federal Reserve System https://www.federalreserve.gov/releases/h10/
|
||||
/// </remarks>
|
||||
public const string Japan_USA = "$DEXJPUS";
|
||||
|
||||
/// <summary>
|
||||
/// Malaysian Ringgit to One U.S. Dollar
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Source: Board of Governors of the Federal Reserve System https://www.federalreserve.gov/releases/h10/
|
||||
/// </remarks>
|
||||
public const string Malaysia_USA = "$DEXMAUS";
|
||||
|
||||
/// <summary>
|
||||
/// Mexican New Pesos to One U.S. Dollar
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Source: Board of Governors of the Federal Reserve System https://www.federalreserve.gov/releases/h10/
|
||||
/// </remarks>
|
||||
public const string Mexico_USA = "$DEXMXUS";
|
||||
|
||||
/// <summary>
|
||||
/// Norwegian Kroner to One U.S. Dollar
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Source: Board of Governors of the Federal Reserve System https://www.federalreserve.gov/releases/h10/
|
||||
/// </remarks>
|
||||
public const string Norway_USA = "$DEXNOUS";
|
||||
|
||||
/// <summary>
|
||||
/// Singapore Dollars to One U.S. Dollar
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Source: Board of Governors of the Federal Reserve System https://www.federalreserve.gov/releases/h10/
|
||||
/// </remarks>
|
||||
public const string Singapore_USA = "$DEXSIUS";
|
||||
|
||||
/// <summary>
|
||||
/// South African Rand to One U.S. Dollar
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Source: Board of Governors of the Federal Reserve System https://www.federalreserve.gov/releases/h10/
|
||||
/// </remarks>
|
||||
public const string SouthAfrica_USA = "$DEXSFUS";
|
||||
|
||||
/// <summary>
|
||||
/// South Korean Won to One U.S. Dollar
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Source: Board of Governors of the Federal Reserve System https://www.federalreserve.gov/releases/h10/
|
||||
/// </remarks>
|
||||
public const string SouthKorea_USA = "$DEXKOUS";
|
||||
|
||||
/// <summary>
|
||||
/// Sri Lankan Rupees to One U.S. Dollar
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Source: Board of Governors of the Federal Reserve System https://www.federalreserve.gov/releases/h10/
|
||||
/// </remarks>
|
||||
public const string SriLanka_USA = "$DEXSLUS";
|
||||
|
||||
/// <summary>
|
||||
/// Swiss Francs to One U.S. Dollar
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Source: Board of Governors of the Federal Reserve System https://www.federalreserve.gov/releases/h10/
|
||||
/// </remarks>
|
||||
public const string Switzerland_USA = "$DEXSZUS";
|
||||
|
||||
/// <summary>
|
||||
/// New Taiwan Dollars to One U.S. Dollar
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Source: Board of Governors of the Federal Reserve System https://www.federalreserve.gov/releases/h10/
|
||||
/// </remarks>
|
||||
public const string Taiwan_USA = "$DEXTAUS";
|
||||
|
||||
/// <summary>
|
||||
/// Thai Baht to One U.S. Dollar
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Source: Board of Governors of the Federal Reserve System https://www.federalreserve.gov/releases/h10/
|
||||
/// </remarks>
|
||||
public const string Thailand_USA = "$DEXTHUS";
|
||||
|
||||
/// <summary>
|
||||
/// U.S. Dollars to One Australian Dollar
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Source: Board of Governors of the Federal Reserve System https://www.federalreserve.gov/releases/h10/
|
||||
/// </remarks>
|
||||
public const string USA_Australia = "$DEXUSAL";
|
||||
|
||||
/// <summary>
|
||||
/// U.S. Dollars to One Euro
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Source: Board of Governors of the Federal Reserve System https://www.federalreserve.gov/releases/h10/
|
||||
/// </remarks>
|
||||
public const string USA_Euro = "$DEXUSEU";
|
||||
|
||||
/// <summary>
|
||||
/// U.S. Dollars to One New Zealand Dollar
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Source: Board of Governors of the Federal Reserve System https://www.federalreserve.gov/releases/h10/
|
||||
/// </remarks>
|
||||
public const string USA_NewZealand = "$DEXUSNZ";
|
||||
|
||||
/// <summary>
|
||||
/// U.S. Dollars to One British Pound
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Source: Board of Governors of the Federal Reserve System https://www.federalreserve.gov/releases/h10/
|
||||
/// </remarks>
|
||||
public const string USA_UK = "$DEXUSUK";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Moody's Investors Service
|
||||
/// </summary>
|
||||
public static class Moodys
|
||||
{
|
||||
/// <summary>
|
||||
/// Moody's Seasoned Aaa Corporate Bond© and 10-Year Treasury Constant Maturity.
|
||||
/// These instruments are based on bonds with maturities 20 years and above.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Source: https://fred.stlouisfed.org/series/DAAA
|
||||
/// </remarks>
|
||||
public const string SeasonedAaaCorporateBondYield = "$DAAA";
|
||||
|
||||
/// <summary>
|
||||
/// Series is calculated as the spread between Moody's Seasoned Aaa Corporate Bond© and 10-Year Treasury Constant
|
||||
/// Maturity
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Source: https://fred.stlouisfed.org/series/AAA10Y
|
||||
/// </remarks>
|
||||
public const string SeasonedAaaCorporateBondYieldRelativeTo10YearTreasuryConstantMaturity = "$AAA10Y";
|
||||
|
||||
/// <summary>
|
||||
/// Moody's Seasoned Baa Corporate Bond© and 10-Year Treasury Constant Maturity.
|
||||
/// These instruments are based on bonds with maturities 20 years and above.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Source: https://fred.stlouisfed.org/series/DBAA
|
||||
/// </remarks>
|
||||
public const string SeasonedBaaCorporateBondYield = "$DBAA";
|
||||
|
||||
/// <summary>
|
||||
/// Series is calculated as the spread between Moody's Seasoned Baa Corporate Bond© and 10-Year Treasury Constant Maturity
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Source: https://fred.stlouisfed.org/series/BAA10Y
|
||||
/// </remarks>
|
||||
public const string SeasonedBaaCorporateBondYieldRelativeTo10YearTreasuryConstantMaturity = "$BAA10Y";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Trade Weighted US Dollar Index
|
||||
/// </summary>
|
||||
public static class TradeWeightedUsDollarIndex
|
||||
{
|
||||
/// <summary>
|
||||
/// A weighted average of the foreign exchange value of the U.S. dollar against the currencies of a broad group of
|
||||
/// major U.S. trading partners. Broad currency index includes the Euro Area, Canada, Japan, Mexico, China, United
|
||||
/// Kingdom, Taiwan, Korea, Singapore, Hong Kong, Malaysia, Brazil, Switzerland, Thailand, Philippines, Australia,
|
||||
/// Indonesia, India, Israel, Saudi Arabia, Russia, Sweden, Argentina, Venezuela, Chile and Colombia.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Source: https://fred.stlouisfed.org/series/DTWEXB
|
||||
/// For more information about trade-weighted indexes see
|
||||
/// http://www.federalreserve.gov/pubs/bulletin/2005/winter05_index.pdf.
|
||||
/// </remarks>
|
||||
public const string Broad = "$DTWEXB";
|
||||
|
||||
/// <summary>
|
||||
/// A weighted average of the foreign exchange value of the U.S. dollar against a subset of the broad index currencies
|
||||
/// that circulate widely outside the country of issue. Major currencies index includes the Euro Area, Canada, Japan,
|
||||
/// United Kingdom, Switzerland, Australia, and Sweden.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Source: https://fred.stlouisfed.org/series/DTWEXM
|
||||
/// For more information about trade-weighted indexes see
|
||||
/// http://www.federalreserve.gov/pubs/bulletin/2005/winter05_index.pdf.
|
||||
/// </remarks>
|
||||
public const string MajorCurrencies = "$DTWEXM";
|
||||
|
||||
/// <summary>
|
||||
/// A weighted average of the foreign exchange value of the U.S. dollar against a subset of the broad index currencies
|
||||
/// that do not circulate widely outside the country of issue. Countries whose currencies are included in the other
|
||||
/// important trading partners index are Mexico, China, Taiwan, Korea, Singapore, Hong Kong, Malaysia, Brazil,
|
||||
/// Thailand, Philippines, Indonesia, India, Israel, Saudi Arabia, Russia, Argentina, Venezuela, Chile and Colombia.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Source: https://fred.stlouisfed.org/series/DTWEXO
|
||||
/// For more information about trade-weighted indexes see
|
||||
/// http://www.federalreserve.gov/pubs/bulletin/2005/winter05_index.pdf.
|
||||
/// </remarks>
|
||||
public const string OtherImportantTradingPartners = "$DTWEXO";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
namespace QuantConnect.Data.Custom.Intrinio
|
||||
{
|
||||
/// <summary>
|
||||
/// Auxiliary class to access all Intrinio API data.
|
||||
/// </summary>
|
||||
public static class IntrinioConfig
|
||||
{
|
||||
/// <summary>
|
||||
/// </summary>
|
||||
public static RateGate RateGate =
|
||||
new RateGate(1, TimeSpan.FromMilliseconds(5000));
|
||||
|
||||
/// <summary>
|
||||
/// Check if Intrinio API user and password are not empty or null.
|
||||
/// </summary>
|
||||
public static bool IsInitialized => !string.IsNullOrWhiteSpace(User) && !string.IsNullOrWhiteSpace(Password);
|
||||
|
||||
/// <summary>
|
||||
/// Intrinio API password
|
||||
/// </summary>
|
||||
public static string Password = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// Intrinio API user
|
||||
/// </summary>
|
||||
public static string User = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// Sets the time interval between calls.
|
||||
/// For more information, please refer to: https://intrinio.com/documentation/api#limits
|
||||
/// </summary>
|
||||
/// <param name="timeSpan">Time interval between to consecutive calls.</param>
|
||||
/// <remarks>
|
||||
/// Paid subscription has limits of 1 call per second.
|
||||
/// Free subscription has limits of 1 call per minute.
|
||||
/// </remarks>
|
||||
public static void SetTimeIntervalBetweenCalls(TimeSpan timeSpan)
|
||||
{
|
||||
RateGate = new RateGate(1, timeSpan);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Set the Intrinio API user and password.
|
||||
/// </summary>
|
||||
public static void SetUserAndPassword(string user, string password)
|
||||
{
|
||||
User = user;
|
||||
Password = password;
|
||||
|
||||
if (!IsInitialized)
|
||||
{
|
||||
throw new InvalidOperationException("Please set a valid Intrinio user and password.");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,229 @@
|
||||
/*
|
||||
* 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.Text;
|
||||
|
||||
namespace QuantConnect.Data.Custom.Intrinio
|
||||
{
|
||||
/// <summary>
|
||||
/// TRanformation available for the Economic data.
|
||||
/// </summary>
|
||||
public enum IntrinioDataTransformation
|
||||
{
|
||||
/// <summary>
|
||||
/// The rate of change
|
||||
/// </summary>
|
||||
Roc,
|
||||
|
||||
/// <summary>
|
||||
/// Rate of change from Year Ago
|
||||
/// </summary>
|
||||
AnnualyRoc,
|
||||
|
||||
/// <summary>
|
||||
/// The compounded annual rate of change
|
||||
/// </summary>
|
||||
CompoundedAnnualRoc,
|
||||
|
||||
/// <summary>
|
||||
/// The continuously compounded annual rate of change
|
||||
/// </summary>
|
||||
AnnualyCCRoc,
|
||||
|
||||
/// <summary>
|
||||
/// The continuously compounded rateof change
|
||||
/// </summary>
|
||||
CCRoc,
|
||||
|
||||
/// <summary>
|
||||
/// The level, no transformation.
|
||||
/// </summary>
|
||||
Level,
|
||||
|
||||
/// <summary>
|
||||
/// The natural log
|
||||
/// </summary>
|
||||
Ln,
|
||||
|
||||
/// <summary>
|
||||
/// The percent change
|
||||
/// </summary>
|
||||
Pc,
|
||||
|
||||
/// <summary>
|
||||
/// The percent change from year ago
|
||||
/// </summary>
|
||||
AnnualyPc
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Access the massive repository of economic data from the Federal Reserve Economic Data system via the Intrinio API.
|
||||
/// </summary>
|
||||
/// <seealso cref="QuantConnect.Data.BaseData" />
|
||||
public class IntrinioEconomicData : BaseData
|
||||
{
|
||||
private readonly string _baseUrl = @"https://api.intrinio.com/historical_data.csv?";
|
||||
|
||||
private readonly IntrinioDataTransformation _dataTransformation;
|
||||
|
||||
|
||||
private bool _backtestingFirstTimeCallOrLiveMode = true;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="IntrinioEconomicData" /> class.
|
||||
/// </summary>
|
||||
public IntrinioEconomicData() : this(IntrinioDataTransformation.Level)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="IntrinioEconomicData" /> class.
|
||||
/// </summary>
|
||||
/// <param name="dataTransformation">The item.</param>
|
||||
public IntrinioEconomicData(IntrinioDataTransformation dataTransformation)
|
||||
{
|
||||
_dataTransformation = dataTransformation;
|
||||
|
||||
// If the user and the password is not set then then throw error.
|
||||
if (!IntrinioConfig.IsInitialized)
|
||||
{
|
||||
throw new
|
||||
InvalidOperationException("Please set a valid Intrinio user and password using the 'IntrinioEconomicData.SetUserAndPassword' static method. " +
|
||||
"For local backtesting, the user and password can be set in the 'parameters' fields from the 'config.json' file.");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <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>
|
||||
/// <remarks>
|
||||
/// Given Intrinio's API limits, we cannot make more than one CSV request per second. That's why in backtesting mode
|
||||
/// we make sure we make just one call to retrieve all the data needed. Also, to avoid the problem of many sources
|
||||
/// asking the data at the beginning of the algorithm, a pause of a second is added.
|
||||
/// </remarks>
|
||||
public override SubscriptionDataSource GetSource(SubscriptionDataConfig config, DateTime date, bool isLiveMode)
|
||||
{
|
||||
SubscriptionDataSource subscription;
|
||||
|
||||
// We want to make just one call with all the data in backtesting mode.
|
||||
// Also we want to make one call per second becasue of the API limit.
|
||||
if (_backtestingFirstTimeCallOrLiveMode)
|
||||
{
|
||||
// Force the engine to wait at least 1000 ms between API calls.
|
||||
IntrinioConfig.RateGate.WaitToProceed();
|
||||
|
||||
// In backtesting mode, there is only one call at the beggining with all the data
|
||||
_backtestingFirstTimeCallOrLiveMode = false || isLiveMode;
|
||||
subscription = GetIntrinioSubscription(config, isLiveMode);
|
||||
}
|
||||
else
|
||||
{
|
||||
subscription = new SubscriptionDataSource("", SubscriptionTransportMedium.LocalFile);
|
||||
}
|
||||
return subscription;
|
||||
}
|
||||
|
||||
/// <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. The returned object is assumed to be time stamped in the config.ExchangeTimeZone.
|
||||
/// </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)
|
||||
{
|
||||
var obs = line.Split(',');
|
||||
var time = DateTime.MinValue;
|
||||
if (!DateTime.TryParseExact(obs[0], "yyyy-MM-dd", CultureInfo.InvariantCulture, DateTimeStyles.None,
|
||||
out time)) return null;
|
||||
var value = obs[1].ToDecimal();
|
||||
return new IntrinioEconomicData
|
||||
{
|
||||
Symbol = config.Symbol,
|
||||
Time = time,
|
||||
EndTime = time + QuantConnect.Time.OneDay,
|
||||
Value = value
|
||||
};
|
||||
}
|
||||
|
||||
private static string GetStringForDataTransformation(IntrinioDataTransformation dataTransformation)
|
||||
{
|
||||
var item = "level";
|
||||
switch (dataTransformation)
|
||||
{
|
||||
case IntrinioDataTransformation.Roc:
|
||||
item = "change";
|
||||
break;
|
||||
case IntrinioDataTransformation.AnnualyRoc:
|
||||
item = "yr_change";
|
||||
break;
|
||||
case IntrinioDataTransformation.CompoundedAnnualRoc:
|
||||
item = "c_annual_roc";
|
||||
break;
|
||||
case IntrinioDataTransformation.AnnualyCCRoc:
|
||||
item = "cc_annual_roc";
|
||||
break;
|
||||
case IntrinioDataTransformation.CCRoc:
|
||||
item = "cc_roc";
|
||||
break;
|
||||
case IntrinioDataTransformation.Level:
|
||||
item = "level";
|
||||
break;
|
||||
case IntrinioDataTransformation.Ln:
|
||||
item = "log";
|
||||
break;
|
||||
case IntrinioDataTransformation.Pc:
|
||||
item = "percent_change";
|
||||
break;
|
||||
case IntrinioDataTransformation.AnnualyPc:
|
||||
item = "yr_percent_change";
|
||||
break;
|
||||
}
|
||||
return item;
|
||||
}
|
||||
|
||||
private SubscriptionDataSource GetIntrinioSubscription(SubscriptionDataConfig config, bool isLiveMode)
|
||||
{
|
||||
// In Live mode, we only want the last observation, in backtesitng we need the data in ascending order.
|
||||
var order = isLiveMode ? "desc" : "asc";
|
||||
var item = GetStringForDataTransformation(_dataTransformation);
|
||||
var url = $"{_baseUrl}identifier={config.Symbol.Value}&item={item}&sort_order={order}";
|
||||
var byteKey = Encoding.ASCII.GetBytes($"{IntrinioConfig.User}:{IntrinioConfig.Password}");
|
||||
var authorizationHeaders = new List<KeyValuePair<string, string>>
|
||||
{
|
||||
new KeyValuePair<string, string>("Authorization",
|
||||
$"Basic ({Convert.ToBase64String(byteKey)})")
|
||||
};
|
||||
|
||||
return new SubscriptionDataSource(url, SubscriptionTransportMedium.RemoteFile, FileFormat.Csv,
|
||||
authorizationHeaders);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
* 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 QuantConnect.Data;
|
||||
|
||||
namespace QuantConnect.DataSource
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a custom data type place holder
|
||||
/// </summary>
|
||||
public class NullData : BaseData
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
namespace QuantConnect.Data.Custom.Tiingo
|
||||
{
|
||||
/// <summary>
|
||||
/// Helper class for Tiingo configuration
|
||||
/// </summary>
|
||||
public static class Tiingo
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the Tiingo API token.
|
||||
/// </summary>
|
||||
public static string AuthCode { get; private set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if the Tiingo API token has been set.
|
||||
/// </summary>
|
||||
public static bool IsAuthCodeSet { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Sets the Tiingo API token.
|
||||
/// </summary>
|
||||
/// <param name="authCode">The Tiingo API token</param>
|
||||
public static void SetAuthCode(string authCode)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(authCode)) return;
|
||||
|
||||
AuthCode = authCode;
|
||||
IsAuthCodeSet = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
namespace QuantConnect.Data.Custom.Tiingo
|
||||
{
|
||||
/// <summary>
|
||||
/// Tiingo daily price data
|
||||
/// https://api.tiingo.com/docs/tiingo/daily
|
||||
/// </summary>
|
||||
/// <remarks>Requires setting <see cref="Tiingo.AuthCode"/></remarks>
|
||||
[Obsolete("This is kept for backwards compatibility, please use TiingoPrice")]
|
||||
public class TiingoDailyData : TiingoPrice
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,220 @@
|
||||
/*
|
||||
* 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 Newtonsoft.Json;
|
||||
using NodaTime;
|
||||
using QuantConnect.Data.Market;
|
||||
using QuantConnect.Data.UniverseSelection;
|
||||
using static QuantConnect.StringExtensions;
|
||||
|
||||
namespace QuantConnect.Data.Custom.Tiingo
|
||||
{
|
||||
/// <summary>
|
||||
/// Tiingo daily price data
|
||||
/// https://api.tiingo.com/docs/tiingo/daily
|
||||
/// </summary>
|
||||
/// <remarks>Requires setting <see cref="Tiingo.AuthCode"/></remarks>
|
||||
public class TiingoPrice : TradeBar
|
||||
{
|
||||
private readonly ConcurrentDictionary<string, DateTime> _startDates = new ConcurrentDictionary<string, DateTime>();
|
||||
|
||||
/// <summary>
|
||||
/// The end time of this data. Some data covers spans (trade bars) and as such we want
|
||||
/// to know the entire time span covered
|
||||
/// </summary>
|
||||
public override DateTime EndTime
|
||||
{
|
||||
get { return Time + Period; }
|
||||
set { Time = value - Period; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The period of this trade bar, (second, minute, daily, ect...)
|
||||
/// </summary>
|
||||
public override TimeSpan Period => QuantConnect.Time.OneDay;
|
||||
|
||||
/// <summary>
|
||||
/// The date this data pertains to
|
||||
/// </summary>
|
||||
[JsonProperty("date")]
|
||||
public DateTime Date { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The actual (not adjusted) open price of the asset on the specific date
|
||||
/// </summary>
|
||||
[JsonProperty("open")]
|
||||
public override decimal Open { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The actual (not adjusted) high price of the asset on the specific date
|
||||
/// </summary>
|
||||
[JsonProperty("high")]
|
||||
public override decimal High { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The actual (not adjusted) low price of the asset on the specific date
|
||||
/// </summary>
|
||||
[JsonProperty("low")]
|
||||
public override decimal Low { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The actual (not adjusted) closing price of the asset on the specific date
|
||||
/// </summary>
|
||||
[JsonProperty("close")]
|
||||
public override decimal Close { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The actual (not adjusted) number of shares traded during the day
|
||||
/// </summary>
|
||||
[JsonProperty("volume")]
|
||||
public override decimal Volume { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The adjusted opening price of the asset on the specific date. Returns null if not available.
|
||||
/// </summary>
|
||||
[JsonProperty("adjOpen")]
|
||||
public decimal AdjustedOpen { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The adjusted high price of the asset on the specific date. Returns null if not available.
|
||||
/// </summary>
|
||||
[JsonProperty("adjHigh")]
|
||||
public decimal AdjustedHigh { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The adjusted low price of the asset on the specific date. Returns null if not available.
|
||||
/// </summary>
|
||||
[JsonProperty("adjLow")]
|
||||
public decimal AdjustedLow { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The adjusted close price of the asset on the specific date. Returns null if not available.
|
||||
/// </summary>
|
||||
[JsonProperty("adjClose")]
|
||||
public decimal AdjustedClose { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The adjusted number of shares traded during the day - adjusted for splits. Returns null if not available
|
||||
/// </summary>
|
||||
[JsonProperty("adjVolume")]
|
||||
public long AdjustedVolume { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The dividend paid out on "date" (note that "date" will be the "exDate" for the dividend)
|
||||
/// </summary>
|
||||
[JsonProperty("divCash")]
|
||||
public decimal Dividend { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// A factor used when a company splits or reverse splits. On days where there is ONLY a split (no dividend payment),
|
||||
/// you can calculate the adjusted close as follows: adjClose = "Previous Close"/splitFactor
|
||||
/// </summary>
|
||||
[JsonProperty("splitFactor")]
|
||||
public decimal SplitFactor { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes an instance of the <see cref="TiingoPrice"/> class.
|
||||
/// </summary>
|
||||
public TiingoPrice()
|
||||
{
|
||||
Symbol = Symbol.Empty;
|
||||
DataType = MarketDataType.Base;
|
||||
}
|
||||
|
||||
/// <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)
|
||||
{
|
||||
DateTime startDate;
|
||||
if (!_startDates.TryGetValue(config.Symbol.Value, out startDate))
|
||||
{
|
||||
startDate = date;
|
||||
_startDates.TryAdd(config.Symbol.Value, startDate);
|
||||
}
|
||||
|
||||
var tiingoTicker = TiingoSymbolMapper.GetTiingoTicker(config.Symbol);
|
||||
var source = Invariant($"https://api.tiingo.com/tiingo/daily/{tiingoTicker}/prices?startDate={startDate:yyyy-MM-dd}&token={Tiingo.AuthCode}");
|
||||
return new SubscriptionDataSource(source, SubscriptionTransportMedium.RemoteFile, FileFormat.UnfoldingCollection);
|
||||
}
|
||||
|
||||
/// <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. The returned object is assumed to be time stamped in the config.ExchangeTimeZone.
|
||||
/// </summary>
|
||||
/// <param name="config">Subscription data config setup object</param>
|
||||
/// <param name="line">Content 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)
|
||||
{
|
||||
var list = JsonConvert.DeserializeObject<List<TiingoPrice>>(line);
|
||||
|
||||
foreach (var item in list)
|
||||
{
|
||||
item.Symbol = config.Symbol;
|
||||
item.Time = item.Date;
|
||||
item.Value = item.Close;
|
||||
}
|
||||
|
||||
return new BaseDataCollection(date, config.Symbol, list);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Indicates if there is support for mapping
|
||||
/// </summary>
|
||||
/// <returns>True indicates mapping should be used</returns>
|
||||
public override bool RequiresMapping()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Specifies the data time zone for this data type. This is useful for custom data types
|
||||
/// </summary>
|
||||
/// <returns>The <see cref="DateTimeZone"/> of this data type</returns>
|
||||
public override DateTimeZone DataTimeZone()
|
||||
{
|
||||
return TimeZones.Utc;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the default resolution for this data and security type
|
||||
/// </summary>
|
||||
public override Resolution DefaultResolution()
|
||||
{
|
||||
return Resolution.Daily;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the supported resolution for this data and security type
|
||||
/// </summary>
|
||||
public override List<Resolution> SupportedResolutions()
|
||||
{
|
||||
return DailyResolution;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
namespace QuantConnect.Data.Custom.Tiingo
|
||||
{
|
||||
/// <summary>
|
||||
/// Helper class to map a Lean format ticker to Tiingo format
|
||||
/// </summary>
|
||||
/// <remarks>To be used when performing direct queries to Tiingo API</remarks>
|
||||
/// <remarks>https://api.tiingo.com/documentation/appendix/symbology</remarks>
|
||||
public static class TiingoSymbolMapper
|
||||
{
|
||||
/// <summary>
|
||||
/// Maps a given <see cref="Symbol"/> instance to it's Tiingo equivalent
|
||||
/// </summary>
|
||||
public static string GetTiingoTicker(Symbol symbol)
|
||||
{
|
||||
return symbol.Value.Replace(".", "-");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Maps a given Tiingo ticker to Lean equivalent
|
||||
/// </summary>
|
||||
public static string GetLeanTicker(string ticker)
|
||||
{
|
||||
return ticker.Replace("-", ".");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* 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 QuantConnect.Interfaces;
|
||||
|
||||
namespace QuantConnect.Data
|
||||
{
|
||||
/// <summary>
|
||||
/// The <see cref="IDataAggregator"/> parameters initialize dto
|
||||
/// </summary>
|
||||
public class DataAggregatorInitializeParameters
|
||||
{
|
||||
/// <summary>
|
||||
/// The algorithm settings instance to use
|
||||
/// </summary>
|
||||
public IAlgorithmSettings AlgorithmSettings { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -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 System.Text;
|
||||
using System.Linq;
|
||||
using Python.Runtime;
|
||||
using QuantConnect.Util;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace QuantConnect.Data
|
||||
{
|
||||
/// <summary>
|
||||
/// Historical data abstraction
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The data this collection can enumerate</typeparam>
|
||||
public class DataHistory<T> : IEnumerable<T>
|
||||
{
|
||||
private readonly Lazy<int> _count;
|
||||
private readonly Lazy<PyObject> _dataframe;
|
||||
|
||||
/// <summary>
|
||||
/// The data we hold
|
||||
/// </summary>
|
||||
protected IEnumerable<T> Data { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The current data point count
|
||||
/// </summary>
|
||||
public int Count => _count.Value;
|
||||
|
||||
/// <summary>
|
||||
/// This data pandas data frame
|
||||
/// </summary>
|
||||
public PyObject DataFrame => _dataframe.Value;
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new instance
|
||||
/// </summary>
|
||||
public DataHistory(IEnumerable<T> data, Lazy<PyObject> dataframe)
|
||||
{
|
||||
Data = data.Memoize();
|
||||
_dataframe = dataframe;
|
||||
// let's be lazy
|
||||
_count = new(() => Data.Count());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Default to string implementation
|
||||
/// </summary>
|
||||
public override string ToString()
|
||||
{
|
||||
var builder = new StringBuilder();
|
||||
foreach (var dataPoint in Data)
|
||||
{
|
||||
builder.AppendLine(dataPoint.ToString());
|
||||
}
|
||||
return builder.ToString();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns an enumerator for the data
|
||||
/// </summary>
|
||||
public IEnumerator<T> GetEnumerator()
|
||||
{
|
||||
return Data.GetEnumerator();
|
||||
}
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
{
|
||||
return GetEnumerator();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,276 @@
|
||||
/*
|
||||
* 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.Threading;
|
||||
using Newtonsoft.Json;
|
||||
using QuantConnect.Interfaces;
|
||||
using QuantConnect.Logging;
|
||||
using QuantConnect.Util;
|
||||
|
||||
namespace QuantConnect.Data
|
||||
{
|
||||
/// <summary>
|
||||
/// Monitors data requests and reports on missing data
|
||||
/// </summary>
|
||||
public class DataMonitor : IDataMonitor
|
||||
{
|
||||
private bool _exited;
|
||||
|
||||
private TextWriter _succeededDataRequestsWriter;
|
||||
private TextWriter _failedDataRequestsWriter;
|
||||
|
||||
private long _succeededDataRequestsCount;
|
||||
private long _failedDataRequestsCount;
|
||||
|
||||
private long _succeededUniverseDataRequestsCount;
|
||||
private long _failedUniverseDataRequestsCount;
|
||||
|
||||
private readonly List<double> _requestRates = new();
|
||||
private long _prevRequestsCount;
|
||||
private DateTime _lastRequestRateCalculationTime;
|
||||
|
||||
private Thread _requestRateCalculationThread;
|
||||
private CancellationTokenSource _cancellationTokenSource;
|
||||
|
||||
private readonly string _succeededDataRequestsFileName;
|
||||
private readonly string _failedDataRequestsFileName;
|
||||
private readonly string _resultsDestinationFolder;
|
||||
|
||||
private readonly object _threadLock = new();
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="DataMonitor"/> class
|
||||
/// </summary>
|
||||
public DataMonitor()
|
||||
{
|
||||
_resultsDestinationFolder = Globals.ResultsDestinationFolder;
|
||||
_succeededDataRequestsFileName = GetFilePath("succeeded-data-requests.txt");
|
||||
_failedDataRequestsFileName = GetFilePath("failed-data-requests.txt");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Event handler for the <see cref="IDataProvider.NewDataRequest"/> event
|
||||
/// </summary>
|
||||
public void OnNewDataRequest(object sender, DataProviderNewDataRequestEventArgs e)
|
||||
{
|
||||
if (_exited)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Initialize();
|
||||
|
||||
if (e.Path.Contains("map_files", StringComparison.OrdinalIgnoreCase) ||
|
||||
e.Path.Contains("factor_files", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var path = StripDataFolder(e.Path);
|
||||
var isUniverseData = path.Contains("coarse", StringComparison.OrdinalIgnoreCase) ||
|
||||
path.Contains("universe", StringComparison.OrdinalIgnoreCase);
|
||||
|
||||
if (e.Succeeded)
|
||||
{
|
||||
WriteLineToFile(_succeededDataRequestsWriter, path, _succeededDataRequestsFileName);
|
||||
Interlocked.Increment(ref _succeededDataRequestsCount);
|
||||
if (isUniverseData)
|
||||
{
|
||||
Interlocked.Increment(ref _succeededUniverseDataRequestsCount);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
WriteLineToFile(_failedDataRequestsWriter, path, _failedDataRequestsFileName);
|
||||
Interlocked.Increment(ref _failedDataRequestsCount);
|
||||
if (isUniverseData)
|
||||
{
|
||||
Interlocked.Increment(ref _failedUniverseDataRequestsCount);
|
||||
}
|
||||
|
||||
if (Logging.Log.DebuggingEnabled)
|
||||
{
|
||||
Logging.Log.Debug($"DataMonitor.OnNewDataRequest(): Data from {path} could not be fetched, error: {e.ErrorMessage}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Terminates the data monitor generating a final report
|
||||
/// </summary>
|
||||
public void Exit()
|
||||
{
|
||||
if (_exited || _requestRateCalculationThread == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
_exited = true;
|
||||
Log.Trace("DataMonitor.Exit(): start...");
|
||||
|
||||
_requestRateCalculationThread.StopSafely(TimeSpan.FromSeconds(5), _cancellationTokenSource);
|
||||
_succeededDataRequestsWriter?.Close();
|
||||
_failedDataRequestsWriter?.Close();
|
||||
|
||||
StoreDataMonitorReport(GenerateReport());
|
||||
|
||||
_succeededDataRequestsWriter.DisposeSafely();
|
||||
_failedDataRequestsWriter.DisposeSafely();
|
||||
_cancellationTokenSource.DisposeSafely();
|
||||
Log.Trace("DataMonitor.Exit(): end");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Disposes this object
|
||||
/// </summary>
|
||||
public void Dispose()
|
||||
{
|
||||
Exit();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Strips the given data folder path
|
||||
/// </summary>
|
||||
protected virtual string StripDataFolder(string path)
|
||||
{
|
||||
if (path.StartsWith(Globals.DataFolder, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return path.Substring(Globals.DataFolder.Length);
|
||||
}
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes the <see cref="DataMonitor"/> instance
|
||||
/// </summary>
|
||||
private void Initialize()
|
||||
{
|
||||
if (_requestRateCalculationThread != null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
lock (_threadLock)
|
||||
{
|
||||
if (_requestRateCalculationThread != null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
// we create the files on demand
|
||||
_succeededDataRequestsWriter = OpenStream(_succeededDataRequestsFileName);
|
||||
_failedDataRequestsWriter = OpenStream(_failedDataRequestsFileName);
|
||||
|
||||
_cancellationTokenSource = new CancellationTokenSource();
|
||||
|
||||
_requestRateCalculationThread = new Thread(() =>
|
||||
{
|
||||
while (!_cancellationTokenSource.Token.WaitHandle.WaitOne(3000))
|
||||
{
|
||||
ComputeFileRequestFrequency();
|
||||
}
|
||||
})
|
||||
{ IsBackground = true };
|
||||
_requestRateCalculationThread.Start();
|
||||
}
|
||||
}
|
||||
|
||||
private DataMonitorReport GenerateReport()
|
||||
{
|
||||
var report = new DataMonitorReport(_succeededDataRequestsCount,
|
||||
_failedDataRequestsCount,
|
||||
_succeededUniverseDataRequestsCount,
|
||||
_failedUniverseDataRequestsCount,
|
||||
_requestRates);
|
||||
|
||||
Logging.Log.Trace($"DataMonitor.GenerateReport():{Environment.NewLine}" +
|
||||
$"DATA USAGE:: Total data requests {report.TotalRequestsCount}{Environment.NewLine}" +
|
||||
$"DATA USAGE:: Succeeded data requests {report.SucceededDataRequestsCount}{Environment.NewLine}" +
|
||||
$"DATA USAGE:: Failed data requests {report.FailedDataRequestsCount}{Environment.NewLine}" +
|
||||
$"DATA USAGE:: Failed data requests percentage {report.FailedDataRequestsPercentage}%{Environment.NewLine}" +
|
||||
$"DATA USAGE:: Total universe data requests {report.TotalUniverseDataRequestsCount}{Environment.NewLine}" +
|
||||
$"DATA USAGE:: Succeeded universe data requests {report.SucceededUniverseDataRequestsCount}{Environment.NewLine}" +
|
||||
$"DATA USAGE:: Failed universe data requests {report.FailedUniverseDataRequestsCount}{Environment.NewLine}" +
|
||||
$"DATA USAGE:: Failed universe data requests percentage {report.FailedUniverseDataRequestsPercentage}%");
|
||||
|
||||
return report;
|
||||
}
|
||||
|
||||
private void ComputeFileRequestFrequency()
|
||||
{
|
||||
var requestsCount = _succeededDataRequestsCount + _failedDataRequestsCount;
|
||||
|
||||
if (_lastRequestRateCalculationTime == default)
|
||||
{
|
||||
// First time we calculate the request rate.
|
||||
// We don't have a previous value to compare to so we just store the current value.
|
||||
_lastRequestRateCalculationTime = DateTime.UtcNow;
|
||||
_prevRequestsCount = requestsCount;
|
||||
return;
|
||||
}
|
||||
|
||||
var requestsCountDelta = requestsCount - _prevRequestsCount;
|
||||
var now = DateTime.UtcNow;
|
||||
var timeDelta = now - _lastRequestRateCalculationTime;
|
||||
|
||||
_requestRates.Add(Math.Round(requestsCountDelta / timeDelta.TotalSeconds));
|
||||
_prevRequestsCount = requestsCount;
|
||||
_lastRequestRateCalculationTime = now;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Stores the data monitor report
|
||||
/// </summary>
|
||||
/// <param name="report">The data monitor report to be stored</param>
|
||||
private void StoreDataMonitorReport(DataMonitorReport report)
|
||||
{
|
||||
if (report == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var path = GetFilePath("data-monitor-report.json");
|
||||
var data = JsonConvert.SerializeObject(report, Formatting.None);
|
||||
File.WriteAllText(path, data);
|
||||
}
|
||||
|
||||
private string GetFilePath(string filename)
|
||||
{
|
||||
var baseFilename = Path.GetFileNameWithoutExtension(filename);
|
||||
var timestamp = DateTime.UtcNow.ToStringInvariant("yyyyMMddHHmmssfff");
|
||||
var extension = Path.GetExtension(filename);
|
||||
return Path.Combine(_resultsDestinationFolder, $"{baseFilename}-{timestamp}{extension}");
|
||||
}
|
||||
|
||||
private static TextWriter OpenStream(string filename)
|
||||
{
|
||||
var writer = new StreamWriter(filename);
|
||||
return TextWriter.Synchronized(writer);
|
||||
}
|
||||
|
||||
private static void WriteLineToFile(TextWriter writer, string line, string filename)
|
||||
{
|
||||
try
|
||||
{
|
||||
writer.WriteLine(line);
|
||||
}
|
||||
catch (IOException exception)
|
||||
{
|
||||
Logging.Log.Error($"DataMonitor.OnNewDataRequest(): Failed to write to file {filename}: {exception.Message}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,172 @@
|
||||
/*
|
||||
* 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 QuantConnect.Interfaces;
|
||||
using QuantConnect.Logging;
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace QuantConnect.Data
|
||||
{
|
||||
/// <summary>
|
||||
/// Count number of subscribers for each channel (Symbol, Socket) pair
|
||||
/// </summary>
|
||||
public abstract class DataQueueHandlerSubscriptionManager : IDisposable
|
||||
{
|
||||
/// <summary>
|
||||
/// Counter
|
||||
/// </summary>
|
||||
protected ConcurrentDictionary<Channel, int> SubscribersByChannel { get; init; } = new ConcurrentDictionary<Channel, int>();
|
||||
|
||||
/// <summary>
|
||||
/// Increment number of subscribers for current <see cref="TickType"/>
|
||||
/// </summary>
|
||||
/// <param name="dataConfig">defines the subscription configuration data.</param>
|
||||
public virtual void Subscribe(SubscriptionDataConfig dataConfig)
|
||||
{
|
||||
try
|
||||
{
|
||||
var channel = GetChannel(dataConfig);
|
||||
int count;
|
||||
if (SubscribersByChannel.TryGetValue(channel, out count))
|
||||
{
|
||||
SubscribersByChannel.TryUpdate(channel, count + 1, count);
|
||||
return;
|
||||
}
|
||||
|
||||
if (Subscribe(new[] { dataConfig.Symbol }, dataConfig.TickType))
|
||||
{
|
||||
SubscribersByChannel.AddOrUpdate(channel, 1);
|
||||
}
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
Log.Error(exception);
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Decrement number of subscribers for current <see cref="TickType"/>
|
||||
/// </summary>
|
||||
/// <param name="dataConfig">defines the subscription configuration data.</param>
|
||||
public void Unsubscribe(SubscriptionDataConfig dataConfig)
|
||||
{
|
||||
try
|
||||
{
|
||||
var channel = GetChannel(dataConfig);
|
||||
int count;
|
||||
if (SubscribersByChannel.TryGetValue(channel, out count))
|
||||
{
|
||||
if (count > 1)
|
||||
{
|
||||
SubscribersByChannel.TryUpdate(channel, count - 1, count);
|
||||
return;
|
||||
}
|
||||
|
||||
if (Unsubscribe(new[] { dataConfig.Symbol }, dataConfig.TickType))
|
||||
{
|
||||
SubscribersByChannel.TryRemove(channel, out count);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
Log.Error(exception);
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns subscribed symbols
|
||||
/// </summary>
|
||||
/// <returns>list of <see cref="Symbol"/> currently subscribed</returns>
|
||||
public IEnumerable<Symbol> GetSubscribedSymbols()
|
||||
{
|
||||
return SubscribersByChannel.Keys
|
||||
.Select(c => c.Symbol)
|
||||
.Distinct();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Retrieves the list of unique <see cref="Symbol"/> instances that are currently subscribed for a specific <see cref="TickType"/>.
|
||||
/// </summary>
|
||||
/// <param name="tickType">The type of tick data to filter subscriptions by.</param>
|
||||
/// <returns>A collection of unique <see cref="Symbol"/> objects that match the specified <paramref name="tickType"/>.</returns>
|
||||
public IEnumerable<Symbol> GetSubscribedSymbols(TickType tickType)
|
||||
{
|
||||
var channelName = ChannelNameFromTickType(tickType);
|
||||
#pragma warning disable CA1309
|
||||
return SubscribersByChannel.Keys.Where(x => x.Name.Equals(channelName, StringComparison.InvariantCultureIgnoreCase))
|
||||
#pragma warning restore CA1309
|
||||
.Select(c => c.Symbol)
|
||||
.Distinct();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks if there is existing subscriber for current channel
|
||||
/// </summary>
|
||||
/// <param name="symbol">Symbol</param>
|
||||
/// <param name="tickType">Type of tick data</param>
|
||||
/// <returns>return true if there is one subscriber at least; otherwise false</returns>
|
||||
public bool IsSubscribed(Symbol symbol, TickType tickType)
|
||||
{
|
||||
return SubscribersByChannel.ContainsKey(GetChannel(
|
||||
symbol,
|
||||
tickType));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
|
||||
/// </summary>
|
||||
public virtual void Dispose()
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Describes the way <see cref="IDataQueueHandler"/> implements subscription
|
||||
/// </summary>
|
||||
/// <param name="symbols">Symbols to subscribe</param>
|
||||
/// <param name="tickType">Type of tick data</param>
|
||||
/// <returns>Returns true if subsribed; otherwise false</returns>
|
||||
protected abstract bool Subscribe(IEnumerable<Symbol> symbols, TickType tickType);
|
||||
|
||||
/// <summary>
|
||||
/// Describes the way <see cref="IDataQueueHandler"/> implements unsubscription
|
||||
/// </summary>
|
||||
/// <param name="symbols">Symbols to unsubscribe</param>
|
||||
/// <param name="tickType">Type of tick data</param>
|
||||
/// <returns>Returns true if unsubsribed; otherwise false</returns>
|
||||
protected abstract bool Unsubscribe(IEnumerable<Symbol> symbols, TickType tickType);
|
||||
|
||||
/// <summary>
|
||||
/// Brokerage maps <see cref="TickType"/> to real socket/api channel
|
||||
/// </summary>
|
||||
/// <param name="tickType">Type of tick data</param>
|
||||
/// <returns></returns>
|
||||
protected abstract string ChannelNameFromTickType(TickType tickType);
|
||||
|
||||
private Channel GetChannel(SubscriptionDataConfig dataConfig) => GetChannel(dataConfig.Symbol, dataConfig.TickType);
|
||||
|
||||
private Channel GetChannel(Symbol symbol, TickType tickType)
|
||||
{
|
||||
return new Channel(
|
||||
ChannelNameFromTickType(tickType),
|
||||
symbol);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,143 @@
|
||||
/*
|
||||
* 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.IO;
|
||||
using Ionic.Zip;
|
||||
using System.Linq;
|
||||
using QuantConnect.Util;
|
||||
using QuantConnect.Logging;
|
||||
using QuantConnect.Interfaces;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace QuantConnect.Data
|
||||
{
|
||||
/// <summary>
|
||||
/// Simple data cache provider, writes and reads directly from disk
|
||||
/// Used as default for <see cref="LeanDataWriter"/>
|
||||
/// </summary>
|
||||
public class DiskDataCacheProvider : IDataCacheProvider
|
||||
{
|
||||
private readonly KeyStringSynchronizer _synchronizer;
|
||||
|
||||
/// <summary>
|
||||
/// Property indicating the data is temporary in nature and should not be cached.
|
||||
/// </summary>
|
||||
public bool IsDataEphemeral => false;
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new instance
|
||||
/// </summary>
|
||||
public DiskDataCacheProvider() : this(new KeyStringSynchronizer())
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new instance using the given synchronizer
|
||||
/// </summary>
|
||||
/// <param name="locker">The synchronizer instance to use</param>
|
||||
public DiskDataCacheProvider(KeyStringSynchronizer locker)
|
||||
{
|
||||
_synchronizer = locker;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Fetch data from the cache
|
||||
/// </summary>
|
||||
/// <param name="key">A string representing the key of the cached data</param>
|
||||
/// <returns>An <see cref="Stream"/> of the cached data</returns>
|
||||
public Stream Fetch(string key)
|
||||
{
|
||||
LeanData.ParseKey(key, out var filePath, out var entryName);
|
||||
|
||||
return _synchronizer.Execute(filePath, () =>
|
||||
{
|
||||
if (!File.Exists(filePath))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
using (var zip = ZipFile.Read(filePath))
|
||||
{
|
||||
ZipEntry entry;
|
||||
if (entryName.IsNullOrEmpty())
|
||||
{
|
||||
// Return the first entry
|
||||
entry = zip[0];
|
||||
}
|
||||
else
|
||||
{
|
||||
// Attempt to find our specific entry
|
||||
if (!zip.ContainsEntry(entryName))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
entry = zip[entryName];
|
||||
}
|
||||
|
||||
// Extract our entry and return it
|
||||
var stream = new MemoryStream();
|
||||
entry.Extract(stream);
|
||||
stream.Position = 0;
|
||||
return stream;
|
||||
}
|
||||
}
|
||||
catch (ZipException exception)
|
||||
{
|
||||
Log.Error("DiskDataCacheProvider.Fetch(): Corrupt file: " + key + " Error: " + exception);
|
||||
return null;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Store the data in the cache. Not implemented in this instance of the IDataCacheProvider
|
||||
/// </summary>
|
||||
/// <param name="key">The source of the data, used as a key to retrieve data in the cache</param>
|
||||
/// <param name="data">The data as a byte array</param>
|
||||
public void Store(string key, byte[] data)
|
||||
{
|
||||
LeanData.ParseKey(key, out var filePath, out var entryName);
|
||||
|
||||
_synchronizer.Execute(filePath, singleExecution: false, () =>
|
||||
{
|
||||
Compression.ZipCreateAppendData(filePath, entryName, data, true);
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a list of zip entries in a provided zip file
|
||||
/// </summary>
|
||||
public List<string> GetZipEntries(string zipFile)
|
||||
{
|
||||
return _synchronizer.Execute(zipFile, () =>
|
||||
{
|
||||
using var stream = new FileStream(FileExtension.ToNormalizedPath(zipFile), FileMode.Open, FileAccess.Read);
|
||||
return Compression.GetZipEntryFileNames(stream).ToList();
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Dispose for this class
|
||||
/// </summary>
|
||||
public void Dispose()
|
||||
{
|
||||
//NOP
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,320 @@
|
||||
/*
|
||||
* 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 System.Threading.Tasks;
|
||||
using QuantConnect.Interfaces;
|
||||
using System.Collections.Generic;
|
||||
using QuantConnect.Data.Auxiliary;
|
||||
using QuantConnect.Securities;
|
||||
using QuantConnect.Data.Market;
|
||||
|
||||
namespace QuantConnect.Data
|
||||
{
|
||||
/// <summary>
|
||||
/// Estimated annualized continuous dividend yield at given date
|
||||
/// </summary>
|
||||
public class DividendYieldProvider : IDividendYieldModel
|
||||
{
|
||||
private static MarketHoursDatabase _marketHoursDatabase = MarketHoursDatabase.FromDataFolder();
|
||||
|
||||
/// <summary>
|
||||
/// The default symbol to use as a dividend yield provider
|
||||
/// </summary>
|
||||
/// <remarks>This is useful for index and future options which do not have an underlying that yields dividends.
|
||||
/// Defaults to SPY</remarks>
|
||||
public static Symbol DefaultSymbol { get; set; } = Symbol.Create("SPY", SecurityType.Equity, QuantConnect.Market.USA);
|
||||
|
||||
/// <summary>
|
||||
/// The dividends by symbol
|
||||
/// </summary>
|
||||
protected static Dictionary<Symbol, List<BaseData>> _corporateEventsCache;
|
||||
|
||||
/// <summary>
|
||||
/// Task to clear the cache
|
||||
/// </summary>
|
||||
protected static Task _cacheClearTask;
|
||||
private static readonly object _lock = new();
|
||||
|
||||
private readonly Symbol _symbol;
|
||||
private readonly SecurityExchangeHours _exchangeHours;
|
||||
|
||||
/// <summary>
|
||||
/// Default no dividend payout
|
||||
/// </summary>
|
||||
public static readonly decimal DefaultDividendYieldRate = 0.0m;
|
||||
|
||||
/// <summary>
|
||||
/// The cached refresh period for the dividend yield rate
|
||||
/// </summary>
|
||||
/// <remarks>Exposed for testing</remarks>
|
||||
protected virtual TimeSpan CacheRefreshPeriod
|
||||
{
|
||||
get
|
||||
{
|
||||
var dueTime = Time.GetNextLiveAuxiliaryDataDueTime();
|
||||
if (dueTime > TimeSpan.FromMinutes(10))
|
||||
{
|
||||
// Clear the cache before the auxiliary due time to avoid race conditions with consumers
|
||||
return dueTime - TimeSpan.FromMinutes(10);
|
||||
}
|
||||
return dueTime;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new instance using the default symbol
|
||||
/// </summary>
|
||||
public DividendYieldProvider() : this(DefaultSymbol)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Instantiates a <see cref="DividendYieldProvider"/> with the specified Symbol
|
||||
/// </summary>
|
||||
public DividendYieldProvider(Symbol symbol)
|
||||
{
|
||||
_symbol = symbol;
|
||||
_exchangeHours = _marketHoursDatabase.GetExchangeHours(symbol.ID.Market, symbol, symbol.ID.SecurityType);
|
||||
|
||||
if (_cacheClearTask == null)
|
||||
{
|
||||
lock (_lock)
|
||||
{
|
||||
// only the first triggers the expiration task check
|
||||
if (_cacheClearTask == null)
|
||||
{
|
||||
StartExpirationTask(CacheRefreshPeriod);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new instance for the given option symbol
|
||||
/// </summary>
|
||||
public static IDividendYieldModel CreateForOption(Symbol optionSymbol)
|
||||
{
|
||||
if (optionSymbol.SecurityType == SecurityType.Option)
|
||||
{
|
||||
return new DividendYieldProvider(optionSymbol.Underlying);
|
||||
}
|
||||
|
||||
if (optionSymbol.SecurityType == SecurityType.IndexOption)
|
||||
{
|
||||
return optionSymbol.Value switch
|
||||
{
|
||||
"SPX" => new DividendYieldProvider(Symbol.Create("SPY", SecurityType.Equity, QuantConnect.Market.USA)),
|
||||
"NDX" => new DividendYieldProvider(Symbol.Create("QQQ", SecurityType.Equity, QuantConnect.Market.USA)),
|
||||
"VIX" => new ConstantDividendYieldModel(0),
|
||||
_ => new DividendYieldProvider()
|
||||
};
|
||||
}
|
||||
|
||||
return new ConstantDividendYieldModel(0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Helper method that will clear any cached dividend rate in a daily basis, this is useful for live trading
|
||||
/// </summary>
|
||||
private static void StartExpirationTask(TimeSpan cacheRefreshPeriod)
|
||||
{
|
||||
lock (_lock)
|
||||
{
|
||||
// we clear the dividend yield rate cache so they are reloaded
|
||||
_corporateEventsCache = new();
|
||||
}
|
||||
_cacheClearTask = Task.Delay(cacheRefreshPeriod).ContinueWith(_ => StartExpirationTask(cacheRefreshPeriod));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get dividend yield by a given date of a given symbol.
|
||||
/// It will get the dividend yield at the time of the most recent dividend since no price is provided.
|
||||
/// In order to get more accurate dividend yield, provide the security price at the given date to
|
||||
/// the <see cref="GetDividendYield(DateTime, decimal)"/> or <see cref="GetDividendYield(IBaseData)"/> methods.
|
||||
/// </summary>
|
||||
/// <param name="date">The date</param>
|
||||
/// <returns>Dividend yield on the given date of the given symbol</returns>
|
||||
public decimal GetDividendYield(DateTime date)
|
||||
{
|
||||
return GetDividendYieldImpl(date, null);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the dividend yield at the date of the specified data, using the data price as the security price
|
||||
/// </summary>
|
||||
/// <param name="priceData">Price data instance</param>
|
||||
/// <returns>Dividend yield on the given date of the given symbol</returns>
|
||||
/// <remarks>Price data must be raw (<see cref="DataNormalizationMode.Raw"/>)</remarks>
|
||||
public decimal GetDividendYield(IBaseData priceData)
|
||||
{
|
||||
if (priceData.Symbol != _symbol)
|
||||
{
|
||||
throw new ArgumentException($"Trying to get {priceData.Symbol} dividend yield using the {_symbol} dividend yield provider.");
|
||||
}
|
||||
|
||||
return GetDividendYield(priceData.EndTime, priceData.Value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get dividend yield at given date and security price
|
||||
/// </summary>
|
||||
/// <param name="date">The date</param>
|
||||
/// <param name="securityPrice">The security price at the given date</param>
|
||||
/// <returns>Dividend yield on the given date of the given symbol</returns>
|
||||
/// <remarks>Price data must be raw (<see cref="DataNormalizationMode.Raw"/>)</remarks>
|
||||
public decimal GetDividendYield(DateTime date, decimal securityPrice)
|
||||
{
|
||||
return GetDividendYieldImpl(date, securityPrice);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get dividend yield at given date and security price.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <paramref name="securityPrice"/> is nullable for backwards compatibility, so <see cref="GetDividendYield(DateTime)"/> is usable.
|
||||
/// If dividend yield is requested at a given date without a price, the dividend yield at the time of the most recent dividend is returned.
|
||||
/// Price data must be raw (<see cref="DataNormalizationMode.Raw"/>).
|
||||
/// </remarks>
|
||||
private decimal GetDividendYieldImpl(DateTime date, decimal? securityPrice)
|
||||
{
|
||||
List<BaseData> symbolCorporateEvents;
|
||||
lock (_lock)
|
||||
{
|
||||
if (!_corporateEventsCache.TryGetValue(_symbol, out symbolCorporateEvents))
|
||||
{
|
||||
// load the symbol factor if it is the first encounter
|
||||
symbolCorporateEvents = _corporateEventsCache[_symbol] = LoadCorporateEvents(_symbol);
|
||||
}
|
||||
}
|
||||
|
||||
if (symbolCorporateEvents == null)
|
||||
{
|
||||
return DefaultDividendYieldRate;
|
||||
}
|
||||
|
||||
// We need both corporate event types, so we get the most recent one, either dividend or split
|
||||
var mostRecentCorporateEventIndex = symbolCorporateEvents.FindLastIndex(x => x.EndTime <= date.Date);
|
||||
if (mostRecentCorporateEventIndex == -1)
|
||||
{
|
||||
return DefaultDividendYieldRate;
|
||||
}
|
||||
|
||||
// Now we get the most recent dividend in order to get the end of the trailing twelve months period for the dividend yield
|
||||
var mostRecentCorporateEvent = symbolCorporateEvents[mostRecentCorporateEventIndex];
|
||||
var mostRecentDividend = mostRecentCorporateEvent as Dividend;
|
||||
if (mostRecentDividend == null)
|
||||
{
|
||||
for (var i = mostRecentCorporateEventIndex - 1; i >= 0; i--)
|
||||
{
|
||||
if (symbolCorporateEvents[i] is Dividend dividend)
|
||||
{
|
||||
mostRecentDividend = dividend;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If there is no dividend in the past year, we return the default dividend yield rate
|
||||
if (mostRecentDividend == null)
|
||||
{
|
||||
return DefaultDividendYieldRate;
|
||||
}
|
||||
|
||||
securityPrice ??= mostRecentDividend.ReferencePrice;
|
||||
if (securityPrice == 0)
|
||||
{
|
||||
throw new ArgumentException("Security price cannot be zero.");
|
||||
}
|
||||
|
||||
// The dividend yield is the sum of the dividends in the past year (ending in the most recent dividend date,
|
||||
// not on the price quote date) divided by the last close price:
|
||||
|
||||
// 15 days window from 1y to avoid overestimation from last year value
|
||||
var trailingYearStartDate = mostRecentDividend.EndTime.AddDays(-350);
|
||||
|
||||
var yearlyDividend = 0m;
|
||||
var currentSplitFactor = 1m;
|
||||
for (var i = mostRecentCorporateEventIndex; i >= 0; i--)
|
||||
{
|
||||
var corporateEvent = symbolCorporateEvents[i];
|
||||
if (corporateEvent.EndTime < trailingYearStartDate)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if (corporateEvent is Dividend dividend)
|
||||
{
|
||||
yearlyDividend += dividend.Distribution * currentSplitFactor;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Update the split factor to adjust the dividend value per share
|
||||
currentSplitFactor *= ((Split)corporateEvent).SplitFactor;
|
||||
}
|
||||
}
|
||||
|
||||
return yearlyDividend / securityPrice.Value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Generate the corporate events from the corporate factor file for the specified symbol
|
||||
/// </summary>
|
||||
/// <remarks>Exposed for testing</remarks>
|
||||
protected virtual List<BaseData> LoadCorporateEvents(Symbol symbol)
|
||||
{
|
||||
var factorFileProvider = Composer.Instance.GetPart<IFactorFileProvider>();
|
||||
var corporateFactors = factorFileProvider
|
||||
.Get(symbol)
|
||||
.Select(factorRow => factorRow as CorporateFactorRow)
|
||||
.Where(corporateFactor => corporateFactor != null);
|
||||
|
||||
var symbolCorporateEvents = FromCorporateFactorRows(corporateFactors, symbol).ToList();
|
||||
if (symbolCorporateEvents.Count == 0)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return symbolCorporateEvents;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Generates the splits and dividends from the corporate factor rows
|
||||
/// </summary>
|
||||
private IEnumerable<BaseData> FromCorporateFactorRows(IEnumerable<CorporateFactorRow> corporateFactors, Symbol symbol)
|
||||
{
|
||||
var dividends = new List<Dividend>();
|
||||
|
||||
// Get all dividends from the corporate actions
|
||||
var rows = corporateFactors.OrderBy(corporateFactor => corporateFactor.Date).ToArray();
|
||||
for (var i = 0; i < rows.Length - 1; i++)
|
||||
{
|
||||
var row = rows[i];
|
||||
var nextRow = rows[i + 1];
|
||||
if (row.PriceFactor != nextRow.PriceFactor)
|
||||
{
|
||||
yield return row.GetDividend(nextRow, symbol, _exchangeHours, decimalPlaces: 3);
|
||||
}
|
||||
else
|
||||
{
|
||||
yield return row.GetSplit(nextRow, symbol, _exchangeHours);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,99 @@
|
||||
/*
|
||||
* 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.Interfaces;
|
||||
using System.Collections.Generic;
|
||||
using QuantConnect.Data.Auxiliary;
|
||||
using NodaTime;
|
||||
|
||||
namespace QuantConnect.Data
|
||||
{
|
||||
/// <summary>
|
||||
/// Contains extension methods for the Downloader functionality.
|
||||
/// </summary>
|
||||
public static class DownloaderExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Get <see cref="DataDownloaderGetParameters"/> for all mapped <seealso cref="Symbol"/> with appropriate ticker name in specific date time range.
|
||||
/// </summary>
|
||||
/// <param name="dataDownloaderParameter">Generated class in "Lean.Engine.DataFeeds.DownloaderDataProvider"</param>
|
||||
/// <param name="mapFileProvider">Provides instances of <see cref="MapFileResolver"/> at run time</param>
|
||||
/// <param name="exchangeTimeZone">Provides the time zone this exchange</param>
|
||||
/// <returns>
|
||||
/// Return DataDownloaderGetParameters with different
|
||||
/// <see cref="DataDownloaderGetParameters.StartUtc"/> - <seealso cref="DataDownloaderGetParameters.EndUtc"/> range
|
||||
/// and <seealso cref="Symbol"/>
|
||||
/// </returns>
|
||||
/// <exception cref="ArgumentNullException">Thrown when <paramref name="dataDownloaderParameter"/> is null.</exception>
|
||||
public static IEnumerable<DataDownloaderGetParameters> GetDataDownloaderParameterForAllMappedSymbols(
|
||||
this DataDownloaderGetParameters dataDownloaderParameter,
|
||||
IMapFileProvider mapFileProvider,
|
||||
DateTimeZone exchangeTimeZone)
|
||||
{
|
||||
if (dataDownloaderParameter == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(dataDownloaderParameter));
|
||||
}
|
||||
|
||||
if (dataDownloaderParameter.Symbol.SecurityType != SecurityType.Future
|
||||
&& dataDownloaderParameter.Symbol.RequiresMapping()
|
||||
&& dataDownloaderParameter.Resolution >= Resolution.Hour)
|
||||
{
|
||||
var yieldMappedSymbol = default(bool);
|
||||
foreach (var symbolDateRange in mapFileProvider.RetrieveAllMappedSymbolInDateRange(dataDownloaderParameter.Symbol))
|
||||
{
|
||||
var startDateTimeUtc = symbolDateRange.StartDateTimeLocal.ConvertToUtc(exchangeTimeZone);
|
||||
var endDateTimeUtc = symbolDateRange.EndDateTimeLocal.ConvertToUtc(exchangeTimeZone);
|
||||
|
||||
// The first start date returns from mapFile like IPO (DateTime) and can not be greater then request StartTime
|
||||
// The Downloader doesn't know start DateTime exactly, it always download all data, except for options and index options
|
||||
if (dataDownloaderParameter.Symbol.SecurityType == SecurityType.Option ||
|
||||
dataDownloaderParameter.Symbol.SecurityType == SecurityType.IndexOption)
|
||||
{
|
||||
// The symbol was delisted before the request start time
|
||||
if (endDateTimeUtc < dataDownloaderParameter.StartUtc)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (startDateTimeUtc < dataDownloaderParameter.StartUtc)
|
||||
{
|
||||
startDateTimeUtc = dataDownloaderParameter.StartUtc;
|
||||
}
|
||||
}
|
||||
|
||||
if (endDateTimeUtc > dataDownloaderParameter.EndUtc)
|
||||
{
|
||||
endDateTimeUtc = dataDownloaderParameter.EndUtc;
|
||||
}
|
||||
|
||||
yield return new DataDownloaderGetParameters(
|
||||
symbolDateRange.Symbol, dataDownloaderParameter.Resolution, startDateTimeUtc, endDateTimeUtc, dataDownloaderParameter.TickType);
|
||||
yieldMappedSymbol = true;
|
||||
}
|
||||
|
||||
if (!yieldMappedSymbol)
|
||||
{
|
||||
yield return dataDownloaderParameter;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
yield return dataDownloaderParameter;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,200 @@
|
||||
/*
|
||||
* 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.Dynamic;
|
||||
using System.Linq.Expressions;
|
||||
using System.Reflection;
|
||||
using Python.Runtime;
|
||||
using QuantConnect.Util;
|
||||
|
||||
namespace QuantConnect.Data
|
||||
{
|
||||
/// <summary>
|
||||
/// Dynamic Data Class: Accept flexible data, adapting to the columns provided by source.
|
||||
/// </summary>
|
||||
/// <remarks>Intended for use with Quandl class.</remarks>
|
||||
public abstract class DynamicData : BaseData, IDynamicMetaObjectProvider
|
||||
{
|
||||
private static readonly MethodInfo SetPropertyMethodInfo = typeof(DynamicData).GetMethod("SetProperty");
|
||||
private static readonly MethodInfo GetPropertyMethodInfo = typeof(DynamicData).GetMethod("GetProperty");
|
||||
|
||||
private readonly IDictionary<string, object> _snakeNameStorage = new Dictionary<string, object>();
|
||||
private readonly IDictionary<string, object> _storage = new Dictionary<string, object>();
|
||||
|
||||
/// <summary>
|
||||
/// Get the metaObject required for Dynamism.
|
||||
/// </summary>
|
||||
public DynamicMetaObject GetMetaObject(Expression parameter)
|
||||
{
|
||||
return new GetSetPropertyDynamicMetaObject(parameter, this, SetPropertyMethodInfo, GetPropertyMethodInfo);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the property with the specified name to the value. This is a case-insensitve search.
|
||||
/// </summary>
|
||||
/// <param name="name">The property name to set</param>
|
||||
/// <param name="value">The new property value</param>
|
||||
/// <returns>Returns the input value back to the caller</returns>
|
||||
public object SetProperty(string name, object value)
|
||||
{
|
||||
// let's be polite and support snake name access for the given object value too
|
||||
var snakeName = name.ToSnakeCase();
|
||||
name = name.LazyToLower();
|
||||
|
||||
if (name == "time")
|
||||
{
|
||||
if (value is PyObject pyobject)
|
||||
{
|
||||
Time = pyobject.As<DateTime>();
|
||||
}
|
||||
else
|
||||
{
|
||||
Time = (DateTime)value;
|
||||
}
|
||||
}
|
||||
else if (name == "endtime" || name == "end_time")
|
||||
{
|
||||
if (value is PyObject pyobject)
|
||||
{
|
||||
EndTime = pyobject.As<DateTime>();
|
||||
}
|
||||
else
|
||||
{
|
||||
EndTime = (DateTime)value;
|
||||
}
|
||||
}
|
||||
else if (name == "value")
|
||||
{
|
||||
if (value is PyObject pyobject)
|
||||
{
|
||||
Value = pyobject.As<decimal>();
|
||||
}
|
||||
else
|
||||
{
|
||||
Value = (decimal)value;
|
||||
}
|
||||
}
|
||||
else if (name == "symbol")
|
||||
{
|
||||
if (value is string)
|
||||
{
|
||||
Symbol = SymbolCache.GetSymbol((string) value);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (value is PyObject pyobject)
|
||||
{
|
||||
Symbol = pyobject.As<Symbol>();
|
||||
}
|
||||
else
|
||||
{
|
||||
Symbol = (Symbol)value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_storage[name] = value;
|
||||
if (snakeName != name)
|
||||
{
|
||||
_snakeNameStorage[snakeName] = value;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the property's value with the specified name. This is a case-insensitve search.
|
||||
/// </summary>
|
||||
/// <param name="name">The property name to access</param>
|
||||
/// <returns>object value of BaseData</returns>
|
||||
public object GetProperty(string name)
|
||||
{
|
||||
name = name.ToLowerInvariant();
|
||||
|
||||
// redirect these calls to the base types properties
|
||||
if (name == "time")
|
||||
{
|
||||
return Time;
|
||||
}
|
||||
if (name == "endtime")
|
||||
{
|
||||
return EndTime;
|
||||
}
|
||||
if (name == "value")
|
||||
{
|
||||
return Value;
|
||||
}
|
||||
if (name == "symbol")
|
||||
{
|
||||
return Symbol;
|
||||
}
|
||||
if (name == "price")
|
||||
{
|
||||
return Price;
|
||||
}
|
||||
|
||||
object value;
|
||||
if (!_storage.TryGetValue(name, out value) && !_snakeNameStorage.TryGetValue(name, out value))
|
||||
{
|
||||
// let the user know the property name that we couldn't find
|
||||
throw new KeyNotFoundException(
|
||||
$"Property with name \'{name}\' does not exist. Properties: Time, Symbol, Value {string.Join(", ", _storage.Keys)}"
|
||||
);
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets whether or not this dynamic data instance has a property with the specified name.
|
||||
/// This is a case-insensitve search.
|
||||
/// </summary>
|
||||
/// <param name="name">The property name to check for</param>
|
||||
/// <returns>True if the property exists, false otherwise</returns>
|
||||
public bool HasProperty(string name)
|
||||
{
|
||||
return _storage.ContainsKey(name.ToLowerInvariant());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the storage dictionary
|
||||
/// Python algorithms need this information since DynamicMetaObject does not work
|
||||
/// </summary>
|
||||
/// <returns>Dictionary that stores the paramenters names and values</returns>
|
||||
public IDictionary<string, object> GetStorageDictionary()
|
||||
{
|
||||
return _storage;
|
||||
}
|
||||
|
||||
/// <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()
|
||||
{
|
||||
var clone = ObjectActivator.Clone(this);
|
||||
foreach (var kvp in _storage)
|
||||
{
|
||||
// don't forget to add the dynamic members!
|
||||
clone._storage.Add(kvp);
|
||||
}
|
||||
return clone;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,92 @@
|
||||
/*
|
||||
* 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.Logging;
|
||||
|
||||
namespace QuantConnect.Data
|
||||
{
|
||||
/// <summary>
|
||||
/// Overrides <see cref="DataQueueHandlerSubscriptionManager"/> methods using events
|
||||
/// </summary>
|
||||
public class EventBasedDataQueueHandlerSubscriptionManager : DataQueueHandlerSubscriptionManager
|
||||
{
|
||||
/// <summary>
|
||||
/// Creates an instance of <see cref="EventBasedDataQueueHandlerSubscriptionManager"/> with a single channel name
|
||||
/// </summary>
|
||||
public EventBasedDataQueueHandlerSubscriptionManager() : this(t => Channel.Single) {}
|
||||
|
||||
/// <summary>
|
||||
/// Creates an instance of <see cref="EventBasedDataQueueHandlerSubscriptionManager"/>
|
||||
/// </summary>
|
||||
/// <param name="getChannelName">Convert TickType into string</param>
|
||||
public EventBasedDataQueueHandlerSubscriptionManager(Func<TickType, string> getChannelName)
|
||||
{
|
||||
_getChannelName = getChannelName;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Subscription method implementation
|
||||
/// </summary>
|
||||
public Func<IEnumerable<Symbol>, TickType, bool> SubscribeImpl { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Unsubscription method implementation
|
||||
/// </summary>
|
||||
public Func<IEnumerable<Symbol>, TickType, bool> UnsubscribeImpl { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Socket channel name
|
||||
/// </summary>
|
||||
private Func<TickType, string> _getChannelName;
|
||||
|
||||
/// <summary>
|
||||
/// The way Brokerage subscribes to symbol tickers
|
||||
/// </summary>
|
||||
/// <param name="symbols">Symbols to subscribe</param>
|
||||
/// <param name="tickType">Type of tick data</param>
|
||||
/// <returns></returns>
|
||||
protected override bool Subscribe(IEnumerable<Symbol> symbols, TickType tickType)
|
||||
{
|
||||
Log.Trace("EventBasedDataQueueHandlerSubscriptionManager.Subscribe(): {0}", string.Join(",", symbols.Select(x => x.Value)));
|
||||
return SubscribeImpl?.Invoke(symbols, tickType) == true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The way Brokerage unsubscribes from symbol tickers
|
||||
/// </summary>
|
||||
/// <param name="symbols">Symbols to unsubscribe</param>
|
||||
/// <param name="tickType">Type of tick data</param>
|
||||
/// <returns></returns>
|
||||
protected override bool Unsubscribe(IEnumerable<Symbol> symbols, TickType tickType)
|
||||
{
|
||||
Log.Trace("EventBasedDataQueueHandlerSubscriptionManager.Unsubscribe(): {0}", string.Join(",", symbols.Select(x => x.Value)));
|
||||
return UnsubscribeImpl?.Invoke(symbols, tickType) == true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Channel name
|
||||
/// </summary>
|
||||
/// <param name="tickType">Type of tick data</param>
|
||||
/// <returns>Returns Socket channel name corresponding <paramref name="tickType"/></returns>
|
||||
protected override string ChannelNameFromTickType(TickType tickType)
|
||||
{
|
||||
return _getChannelName?.Invoke(tickType);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
namespace QuantConnect.Data
|
||||
{
|
||||
/// <summary>
|
||||
/// Specifies the format of data in a subscription
|
||||
/// </summary>
|
||||
public enum FileFormat
|
||||
{
|
||||
/// <summary>
|
||||
/// Comma separated values (0)
|
||||
/// </summary>
|
||||
Csv,
|
||||
|
||||
/// <summary>
|
||||
/// Binary file data (1)
|
||||
/// </summary>
|
||||
Binary,
|
||||
|
||||
/// <summary>
|
||||
/// Only the zip entry names are read in as symbols (2)
|
||||
/// </summary>
|
||||
ZipEntryName,
|
||||
|
||||
/// <summary>
|
||||
/// Reader returns a BaseDataCollection object (3)
|
||||
/// </summary>
|
||||
/// <remarks>Lean will unfold the collection and consume it as individual data points</remarks>
|
||||
UnfoldingCollection,
|
||||
|
||||
/// <summary>
|
||||
/// Data stored using an intermediate index source (4)
|
||||
/// </summary>
|
||||
Index,
|
||||
|
||||
/// <summary>
|
||||
/// Data type inherits from BaseDataCollection.
|
||||
/// Reader method can return a non BaseDataCollection type which will be folded, based on unique time,
|
||||
/// into an instance of the data type (5)
|
||||
/// </summary>
|
||||
FoldingCollection
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* 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 Python.Runtime;
|
||||
using System;
|
||||
|
||||
namespace QuantConnect.Data
|
||||
{
|
||||
/// <summary>
|
||||
/// Constant risk free rate interest rate model
|
||||
/// </summary>
|
||||
public class FuncRiskFreeRateInterestRateModel : IRiskFreeInterestRateModel
|
||||
{
|
||||
private readonly Func<DateTime, decimal> _getInterestRateFunc;
|
||||
|
||||
/// <summary>
|
||||
/// Create class instance of interest rate provider
|
||||
/// </summary>
|
||||
public FuncRiskFreeRateInterestRateModel(Func<DateTime, decimal> getInterestRateFunc)
|
||||
{
|
||||
_getInterestRateFunc = getInterestRateFunc;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create class instance of interest rate provider with given PyObject
|
||||
/// </summary>
|
||||
public FuncRiskFreeRateInterestRateModel(PyObject getInterestRateFunc)
|
||||
{
|
||||
using (Py.GIL())
|
||||
{
|
||||
_getInterestRateFunc = getInterestRateFunc.SafeAs<Func<DateTime, decimal>>();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get interest rate by a given date
|
||||
/// </summary>
|
||||
/// <param name="date">The date</param>
|
||||
/// <returns>Interest rate on the given date</returns>
|
||||
public decimal GetInterestRate(DateTime date)
|
||||
{
|
||||
return _getInterestRateFunc(date);
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -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 Newtonsoft.Json;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace QuantConnect.Data.Fundamental
|
||||
{
|
||||
/// <summary>
|
||||
/// Definition of the FineFundamental class
|
||||
/// </summary>
|
||||
public partial class FineFundamental
|
||||
{
|
||||
/// <summary>
|
||||
/// The end time of this data.
|
||||
/// </summary>
|
||||
[JsonIgnore]
|
||||
public override DateTime EndTime
|
||||
{
|
||||
get { return Time + QuantConnect.Time.OneDay; }
|
||||
set { Time = value - QuantConnect.Time.OneDay; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Price * Total SharesOutstanding.
|
||||
/// The most current market cap for example, would be the most recent closing price x the most recent reported shares outstanding.
|
||||
/// For ADR share classes, market cap is price * (ordinary shares outstanding / adr ratio).
|
||||
/// </summary>
|
||||
[JsonIgnore]
|
||||
public long MarketCap => CompanyProfile.MarketCap;
|
||||
|
||||
/// <summary>
|
||||
/// Return the URL string source of the file. This will be converted to a stream
|
||||
/// </summary>
|
||||
public override SubscriptionDataSource GetSource(SubscriptionDataConfig config, DateTime date, bool isLiveMode)
|
||||
{
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
|
||||
/// <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. The returned object is assumed to be time stamped in the config.ExchangeTimeZone.
|
||||
/// </summary>
|
||||
public override BaseData Reader(SubscriptionDataConfig config, string line, DateTime date, bool isLiveMode)
|
||||
{
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Clones this fine data instance
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public override BaseData Clone()
|
||||
{
|
||||
return new FineFundamental(Time, Symbol, _fundamentalInstanceProvider);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This is a daily data set
|
||||
/// </summary>
|
||||
public override List<Resolution> SupportedResolutions()
|
||||
{
|
||||
return DailyResolution;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This is a daily data set
|
||||
/// </summary>
|
||||
public override Resolution DefaultResolution()
|
||||
{
|
||||
return Resolution.Daily;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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 System.IO;
|
||||
using QuantConnect.Data.UniverseSelection;
|
||||
|
||||
namespace QuantConnect.Data.Fundamental
|
||||
{
|
||||
/// <summary>
|
||||
/// Lean fundamental data class
|
||||
/// </summary>
|
||||
public class Fundamental : FineFundamental
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the day's dollar volume for this symbol
|
||||
/// </summary>
|
||||
public override double DollarVolume => FundamentalService.Get<double>(Time, Symbol.ID, FundamentalProperty.DollarVolume);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the day's total volume
|
||||
/// </summary>
|
||||
public override long Volume => FundamentalService.Get<long>(Time, Symbol.ID, FundamentalProperty.Volume);
|
||||
|
||||
/// <summary>
|
||||
/// Returns whether the symbol has fundamental data for the given date
|
||||
/// </summary>
|
||||
public override bool HasFundamentalData => FundamentalService.Get<bool>(Time, Symbol.ID, FundamentalProperty.HasFundamentalData);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the price factor for the given date
|
||||
/// </summary>
|
||||
public override decimal PriceFactor => FundamentalService.Get<decimal>(Time, Symbol.ID, FundamentalProperty.PriceFactor);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the split factor for the given date
|
||||
/// </summary>
|
||||
public override decimal SplitFactor => FundamentalService.Get<decimal>(Time, Symbol.ID, FundamentalProperty.SplitFactor);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the raw price
|
||||
/// </summary>
|
||||
public override decimal Value => FundamentalService.Get<decimal>(Time, Symbol.ID, FundamentalProperty.Value);
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new empty instance
|
||||
/// </summary>
|
||||
public Fundamental()
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new instance
|
||||
/// </summary>
|
||||
/// <param name="time">The current time</param>
|
||||
/// <param name="symbol">The associated symbol</param>
|
||||
public Fundamental(DateTime time, Symbol symbol)
|
||||
: base(time, symbol)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new instance
|
||||
/// </summary>
|
||||
/// <param name="time">The current time</param>
|
||||
/// <param name="symbol">The associated symbol</param>
|
||||
public static Fundamental ForDate(DateTime time, Symbol symbol)
|
||||
{
|
||||
// Important: set EndTime to time so that time is previous day midnight, if we just set time, EndTime would be NEXT day midnight.
|
||||
// Note: data for T date is available on T+1 date, fundamental selection also handles this, see BaseDataCollectionSubscriptionEnumeratorFactory
|
||||
return new Fundamental(time, symbol) { EndTime = time };
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Return the URL string source of the file. This will be converted to a stream
|
||||
/// </summary>
|
||||
public override SubscriptionDataSource GetSource(SubscriptionDataConfig config, DateTime date, bool isLiveMode)
|
||||
{
|
||||
var path = Path.Combine(Globals.DataFolder, "equity", config.Market, "fundamental", "coarse", $"{date:yyyyMMdd}.csv");
|
||||
return new SubscriptionDataSource(path, SubscriptionTransportMedium.LocalFile, FileFormat.Csv);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Will read a new instance from the given line
|
||||
/// </summary>
|
||||
/// <param name="config">The associated requested configuration</param>
|
||||
/// <param name="line">The line to parse</param>
|
||||
/// <param name="date">The current time</param>
|
||||
/// <param name="isLiveMode">True if live mode</param>
|
||||
/// <returns>A new instance or null</returns>
|
||||
public override BaseData Reader(SubscriptionDataConfig config, string line, DateTime date, bool isLiveMode)
|
||||
{
|
||||
try
|
||||
{
|
||||
var csv = line.Split(',');
|
||||
var sid = SecurityIdentifier.Parse(csv[0]);
|
||||
// This use case/Reader implementation is only for history, where the user requests specific symbols only
|
||||
// and because we use the same source file as the universe Fundamentals we need to filter out other symbols
|
||||
if (sid == config.Symbol.ID)
|
||||
{
|
||||
return new Fundamental(date, new Symbol(sid, csv[1]));
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
// pass
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Will clone the current instance
|
||||
/// </summary>
|
||||
/// <returns>The cloned instance</returns>
|
||||
public override BaseData Clone()
|
||||
{
|
||||
return new Fundamental(Time, Symbol);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the default resolution for this data and security type
|
||||
/// </summary>
|
||||
public override Resolution DefaultResolution()
|
||||
{
|
||||
return Resolution.Daily;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,184 @@
|
||||
/*
|
||||
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
|
||||
* Lean Algorithmic Trading Engine v2.0. Copyright 2023 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.Runtime.CompilerServices;
|
||||
|
||||
namespace QuantConnect.Data.Fundamental
|
||||
{
|
||||
/// <summary>
|
||||
/// Per symbol we will have a fundamental class provider so the instances can be reused
|
||||
/// </summary>
|
||||
public class FundamentalInstanceProvider
|
||||
{
|
||||
private static readonly Dictionary<SecurityIdentifier, FundamentalInstanceProvider> _cache = new();
|
||||
|
||||
private readonly FundamentalTimeProvider _timeProvider;
|
||||
private readonly FinancialStatements _financialStatements;
|
||||
private readonly OperationRatios _operationRatios;
|
||||
private readonly SecurityReference _securityReference;
|
||||
private readonly CompanyReference _companyReference;
|
||||
private readonly CompanyProfile _companyProfile;
|
||||
private readonly AssetClassification _assetClassification;
|
||||
private readonly ValuationRatios _valuationRatios;
|
||||
private readonly EarningRatios _earningRatios;
|
||||
private readonly EarningReports _earningReports;
|
||||
|
||||
/// <summary>
|
||||
/// Get's the fundamental instance provider for the requested symbol
|
||||
/// </summary>
|
||||
/// <param name="symbol">The requested symbol</param>
|
||||
/// <returns>The unique instance provider</returns>
|
||||
public static FundamentalInstanceProvider Get(Symbol symbol)
|
||||
{
|
||||
FundamentalInstanceProvider result = null;
|
||||
lock (_cache)
|
||||
{
|
||||
_cache.TryGetValue(symbol.ID, out result);
|
||||
}
|
||||
|
||||
if (result == null)
|
||||
{
|
||||
// we create the fundamental instance provider without holding the cache lock, this is because it uses the pygil
|
||||
// Deadlock case: if the main thread has PyGil and wants to take lock on cache (security.Fundamentals use case) and the data
|
||||
// stack thread takes the lock on the cache (creating new fundamentals) and next wants the pygil deadlock!
|
||||
result = new FundamentalInstanceProvider(symbol);
|
||||
lock (_cache)
|
||||
{
|
||||
_cache[symbol.ID] = result;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new fundamental instance provider
|
||||
/// </summary>
|
||||
/// <param name="symbol">The target symbol</param>
|
||||
private FundamentalInstanceProvider(Symbol symbol)
|
||||
{
|
||||
_timeProvider = new();
|
||||
_financialStatements = new(_timeProvider, symbol.ID);
|
||||
_operationRatios = new(_timeProvider, symbol.ID);
|
||||
_securityReference = new(_timeProvider, symbol.ID);
|
||||
_companyReference = new(_timeProvider, symbol.ID);
|
||||
_companyProfile = new(_timeProvider, symbol.ID);
|
||||
_assetClassification = new(_timeProvider, symbol.ID);
|
||||
_valuationRatios = new(_timeProvider, symbol.ID);
|
||||
_earningRatios = new(_timeProvider, symbol.ID);
|
||||
_earningReports = new(_timeProvider, symbol.ID);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the ValuationRatios instance
|
||||
/// </summary>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public ValuationRatios GetValuationRatios(DateTime time)
|
||||
{
|
||||
_timeProvider.Time = time;
|
||||
return _valuationRatios;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the EarningRatios instance
|
||||
/// </summary>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public EarningRatios GetEarningRatios(DateTime time)
|
||||
{
|
||||
_timeProvider.Time = time;
|
||||
return _earningRatios;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the EarningReports instance
|
||||
/// </summary>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public EarningReports GetEarningReports(DateTime time)
|
||||
{
|
||||
_timeProvider.Time = time;
|
||||
return _earningReports;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the OperationRatios instance
|
||||
/// </summary>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public OperationRatios GetOperationRatios(DateTime time)
|
||||
{
|
||||
_timeProvider.Time = time;
|
||||
return _operationRatios;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the FinancialStatements instance
|
||||
/// </summary>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public FinancialStatements GetFinancialStatements(DateTime time)
|
||||
{
|
||||
_timeProvider.Time = time;
|
||||
return _financialStatements;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the SecurityReference instance
|
||||
/// </summary>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public SecurityReference GetSecurityReference(DateTime time)
|
||||
{
|
||||
_timeProvider.Time = time;
|
||||
return _securityReference;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the CompanyReference instance
|
||||
/// </summary>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public CompanyReference GetCompanyReference(DateTime time)
|
||||
{
|
||||
_timeProvider.Time = time;
|
||||
return _companyReference;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the CompanyProfile instance
|
||||
/// </summary>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public CompanyProfile GetCompanyProfile(DateTime time)
|
||||
{
|
||||
_timeProvider.Time = time;
|
||||
return _companyProfile;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the AssetClassification instance
|
||||
/// </summary>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public AssetClassification GetAssetClassification(DateTime time)
|
||||
{
|
||||
_timeProvider.Time = time;
|
||||
return _assetClassification;
|
||||
}
|
||||
|
||||
private class FundamentalTimeProvider : ITimeProvider
|
||||
{
|
||||
public DateTime Time;
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public DateTime GetUtcNow() => Time;
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
|
||||
* Lean Algorithmic Trading Engine v2.0. Copyright 2023 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 Python.Runtime;
|
||||
|
||||
namespace QuantConnect.Data.Fundamental
|
||||
{
|
||||
/// <summary>
|
||||
/// Simple base class shared by top layer fundamental properties which depend on a time provider
|
||||
/// </summary>
|
||||
public abstract class FundamentalTimeDependentProperty : ReusuableCLRObject
|
||||
{
|
||||
/// <summary>
|
||||
/// The time provider instance to use
|
||||
/// </summary>
|
||||
protected ITimeProvider _timeProvider { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The SID instance to use
|
||||
/// </summary>
|
||||
protected SecurityIdentifier _securityIdentifier { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new instance for the given time and security
|
||||
/// </summary>
|
||||
public FundamentalTimeDependentProperty(ITimeProvider timeProvider, SecurityIdentifier securityIdentifier)
|
||||
{
|
||||
_timeProvider = timeProvider;
|
||||
_securityIdentifier = securityIdentifier;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Clones this instance
|
||||
/// </summary>
|
||||
public abstract FundamentalTimeDependentProperty Clone(ITimeProvider timeProvider);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,148 @@
|
||||
/*
|
||||
* 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.Threading;
|
||||
using Python.Runtime;
|
||||
using QuantConnect.Data.UniverseSelection;
|
||||
|
||||
namespace QuantConnect.Data.Fundamental
|
||||
{
|
||||
/// <summary>
|
||||
/// Lean fundamentals universe data class
|
||||
/// </summary>
|
||||
[Obsolete("'Fundamentals' was renamed to 'FundamentalUniverse'")]
|
||||
public class Fundamentals : FundamentalUniverse { }
|
||||
|
||||
/// <summary>
|
||||
/// Lean fundamentals universe data class
|
||||
/// </summary>
|
||||
public class FundamentalUniverse : BaseDataCollection
|
||||
{
|
||||
private static int _universeCount;
|
||||
private static readonly Fundamental _factory = new();
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new instance
|
||||
/// </summary>
|
||||
public FundamentalUniverse()
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new instance
|
||||
/// </summary>
|
||||
/// <param name="time">The current time</param>
|
||||
/// <param name="symbol">The associated symbol</param>
|
||||
public FundamentalUniverse(DateTime time, Symbol symbol) : base(time, symbol)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Return the URL string source of the file. This will be converted to a stream
|
||||
/// </summary>
|
||||
public override SubscriptionDataSource GetSource(SubscriptionDataConfig config, DateTime date, bool isLiveMode)
|
||||
{
|
||||
var path = _factory.GetSource(config, date, isLiveMode).Source;
|
||||
return new SubscriptionDataSource(path, SubscriptionTransportMedium.LocalFile, FileFormat.FoldingCollection);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Will read a new instance from the given line
|
||||
/// </summary>
|
||||
/// <param name="config">The associated requested configuration</param>
|
||||
/// <param name="line">The line to parse</param>
|
||||
/// <param name="date">The current time</param>
|
||||
/// <param name="isLiveMode">True if live mode</param>
|
||||
/// <returns>A new instance or null</returns>
|
||||
public override BaseData Reader(SubscriptionDataConfig config, string line, DateTime date, bool isLiveMode)
|
||||
{
|
||||
try
|
||||
{
|
||||
var csv = line.Split(',');
|
||||
var symbol = new Symbol(SecurityIdentifier.Parse(csv[0]), csv[1]);
|
||||
return new Fundamental(date, symbol);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Will clone the current instance
|
||||
/// </summary>
|
||||
/// <returns>The cloned instance</returns>
|
||||
public override BaseData Clone()
|
||||
{
|
||||
return new FundamentalUniverse(Time, Symbol) { Data = Data, EndTime = EndTime };
|
||||
}
|
||||
|
||||
/// <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>
|
||||
/// Creates the universe symbol for the target market
|
||||
/// </summary>
|
||||
/// <returns>The universe symbol to use</returns>
|
||||
public override 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.Equity, market, baseDataType: GetType());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new fundamental universe for the USA market
|
||||
/// </summary>
|
||||
/// <param name="selector">The selector function</param>
|
||||
/// <param name="universeSettings">The universe settings to use, will default to algorithms if not provided</param>
|
||||
/// <returns>A configured new universe instance</returns>
|
||||
public static FundamentalUniverseFactory USA(Func<IEnumerable<Fundamental>, IEnumerable<Symbol>> selector, UniverseSettings universeSettings = null)
|
||||
{
|
||||
return new FundamentalUniverseFactory(QuantConnect.Market.USA, universeSettings, selector);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new fundamental universe for the USA market
|
||||
/// </summary>
|
||||
/// <param name="selector">The selector function</param>
|
||||
/// <param name="universeSettings">The universe settings to use, will default to algorithms if not provided</param>
|
||||
/// <returns>A configured new universe instance</returns>
|
||||
public static FundamentalUniverseFactory USA(PyObject selector, UniverseSettings universeSettings = null)
|
||||
{
|
||||
return new FundamentalUniverseFactory(QuantConnect.Market.USA, universeSettings, selector);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new fundamental universe for the USA market
|
||||
/// </summary>
|
||||
/// <param name="selector">The selector function</param>
|
||||
/// <param name="universeSettings">The universe settings to use, will default to algorithms if not provided</param>
|
||||
/// <returns>A configured new universe instance</returns>
|
||||
public static FundamentalUniverseFactory USA(Func<IEnumerable<Fundamental>, object> selector, UniverseSettings universeSettings = null)
|
||||
{
|
||||
return new FundamentalUniverseFactory(QuantConnect.Market.USA, universeSettings, selector);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,101 @@
|
||||
/*
|
||||
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
|
||||
* Lean Algorithmic Trading Engine v2.0. Copyright 2023 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 Newtonsoft.Json;
|
||||
using System.Collections.Generic;
|
||||
using QuantConnect.Data.UniverseSelection;
|
||||
|
||||
namespace QuantConnect.Data.Fundamental
|
||||
{
|
||||
/// <summary>
|
||||
/// This is the simple average of the company's ROIC over the last 5 years. Return on invested capital is calculated by taking net operating profit after taxes and dividends and dividing by the total amount of capital invested and expressing the result as a percentage.
|
||||
/// </summary>
|
||||
public class AVG5YrsROIC : MultiPeriodField
|
||||
{
|
||||
/// <summary>
|
||||
/// The default period
|
||||
/// </summary>
|
||||
protected override string DefaultPeriod => "FiveYears";
|
||||
|
||||
/// <summary>
|
||||
/// Gets/sets the FiveYears period value for the field
|
||||
/// </summary>
|
||||
[JsonProperty("5Y")]
|
||||
public double FiveYears => FundamentalService.Get<double>(TimeProvider.GetUtcNow(), SecurityIdentifier, FundamentalProperty.OperationRatios_AVG5YrsROIC_FiveYears);
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if the field contains a value for the default period
|
||||
/// </summary>
|
||||
public override bool HasValue => !BaseFundamentalDataProvider.IsNone(typeof(double), FundamentalService.Get<double>(TimeProvider.GetUtcNow(), SecurityIdentifier, FundamentalProperty.OperationRatios_AVG5YrsROIC_FiveYears));
|
||||
|
||||
/// <summary>
|
||||
/// Returns the default value for the field
|
||||
/// </summary>
|
||||
public override double Value
|
||||
{
|
||||
get
|
||||
{
|
||||
var defaultValue = FundamentalService.Get<double>(TimeProvider.GetUtcNow(), SecurityIdentifier, FundamentalProperty.OperationRatios_AVG5YrsROIC_FiveYears);
|
||||
if (!BaseFundamentalDataProvider.IsNone(typeof(double), defaultValue))
|
||||
{
|
||||
return defaultValue;
|
||||
}
|
||||
return base.Value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a dictionary of period names and values for the field
|
||||
/// </summary>
|
||||
/// <returns>The dictionary of period names and values</returns>
|
||||
public override IReadOnlyDictionary<string, double> GetPeriodValues()
|
||||
{
|
||||
var result = new Dictionary<string, double>();
|
||||
foreach (var kvp in new[] { new Tuple<string, double>("5Y",FiveYears) })
|
||||
{
|
||||
if(!BaseFundamentalDataProvider.IsNone(typeof(double), kvp.Item2))
|
||||
{
|
||||
result[kvp.Item1] = kvp.Item2;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the value of the field for the requested period
|
||||
/// </summary>
|
||||
/// <param name="period">The requested period</param>
|
||||
/// <returns>The value for the period</returns>
|
||||
public override double GetPeriodValue(string period) => FundamentalService.Get<double>(TimeProvider.GetUtcNow(), SecurityIdentifier, Enum.Parse<FundamentalProperty>($"OperationRatios_AVG5YrsROIC_{ConvertPeriod(period)}"));
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new empty instance
|
||||
/// </summary>
|
||||
public AVG5YrsROIC()
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new instance for the given time and security
|
||||
/// </summary>
|
||||
public AVG5YrsROIC(ITimeProvider timeProvider, SecurityIdentifier securityIdentifier) : base(timeProvider, securityIdentifier)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,131 @@
|
||||
/*
|
||||
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
|
||||
* Lean Algorithmic Trading Engine v2.0. Copyright 2023 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 Newtonsoft.Json;
|
||||
using System.Collections.Generic;
|
||||
using QuantConnect.Data.UniverseSelection;
|
||||
|
||||
namespace QuantConnect.Data.Fundamental
|
||||
{
|
||||
/// <summary>
|
||||
/// Any money that a company owes its suppliers for goods and services purchased on credit and is expected to pay within the next year or operating cycle.
|
||||
/// </summary>
|
||||
public class AccountsPayableBalanceSheet : MultiPeriodField
|
||||
{
|
||||
/// <summary>
|
||||
/// The default period
|
||||
/// </summary>
|
||||
protected override string DefaultPeriod => "TwelveMonths";
|
||||
|
||||
/// <summary>
|
||||
/// Gets/sets the OneMonth period value for the field
|
||||
/// </summary>
|
||||
[JsonProperty("1M")]
|
||||
public double OneMonth => FundamentalService.Get<double>(TimeProvider.GetUtcNow(), SecurityIdentifier, FundamentalProperty.FinancialStatements_BalanceSheet_AccountsPayable_OneMonth);
|
||||
|
||||
/// <summary>
|
||||
/// Gets/sets the TwoMonths period value for the field
|
||||
/// </summary>
|
||||
[JsonProperty("2M")]
|
||||
public double TwoMonths => FundamentalService.Get<double>(TimeProvider.GetUtcNow(), SecurityIdentifier, FundamentalProperty.FinancialStatements_BalanceSheet_AccountsPayable_TwoMonths);
|
||||
|
||||
/// <summary>
|
||||
/// Gets/sets the ThreeMonths period value for the field
|
||||
/// </summary>
|
||||
[JsonProperty("3M")]
|
||||
public double ThreeMonths => FundamentalService.Get<double>(TimeProvider.GetUtcNow(), SecurityIdentifier, FundamentalProperty.FinancialStatements_BalanceSheet_AccountsPayable_ThreeMonths);
|
||||
|
||||
/// <summary>
|
||||
/// Gets/sets the SixMonths period value for the field
|
||||
/// </summary>
|
||||
[JsonProperty("6M")]
|
||||
public double SixMonths => FundamentalService.Get<double>(TimeProvider.GetUtcNow(), SecurityIdentifier, FundamentalProperty.FinancialStatements_BalanceSheet_AccountsPayable_SixMonths);
|
||||
|
||||
/// <summary>
|
||||
/// Gets/sets the NineMonths period value for the field
|
||||
/// </summary>
|
||||
[JsonProperty("9M")]
|
||||
public double NineMonths => FundamentalService.Get<double>(TimeProvider.GetUtcNow(), SecurityIdentifier, FundamentalProperty.FinancialStatements_BalanceSheet_AccountsPayable_NineMonths);
|
||||
|
||||
/// <summary>
|
||||
/// Gets/sets the TwelveMonths period value for the field
|
||||
/// </summary>
|
||||
[JsonProperty("12M")]
|
||||
public double TwelveMonths => FundamentalService.Get<double>(TimeProvider.GetUtcNow(), SecurityIdentifier, FundamentalProperty.FinancialStatements_BalanceSheet_AccountsPayable_TwelveMonths);
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if the field contains a value for the default period
|
||||
/// </summary>
|
||||
public override bool HasValue => !BaseFundamentalDataProvider.IsNone(typeof(double), FundamentalService.Get<double>(TimeProvider.GetUtcNow(), SecurityIdentifier, FundamentalProperty.FinancialStatements_BalanceSheet_AccountsPayable_TwelveMonths));
|
||||
|
||||
/// <summary>
|
||||
/// Returns the default value for the field
|
||||
/// </summary>
|
||||
public override double Value
|
||||
{
|
||||
get
|
||||
{
|
||||
var defaultValue = FundamentalService.Get<double>(TimeProvider.GetUtcNow(), SecurityIdentifier, FundamentalProperty.FinancialStatements_BalanceSheet_AccountsPayable_TwelveMonths);
|
||||
if (!BaseFundamentalDataProvider.IsNone(typeof(double), defaultValue))
|
||||
{
|
||||
return defaultValue;
|
||||
}
|
||||
return base.Value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a dictionary of period names and values for the field
|
||||
/// </summary>
|
||||
/// <returns>The dictionary of period names and values</returns>
|
||||
public override IReadOnlyDictionary<string, double> GetPeriodValues()
|
||||
{
|
||||
var result = new Dictionary<string, double>();
|
||||
foreach (var kvp in new[] { new Tuple<string, double>("1M",OneMonth), new Tuple<string, double>("2M",TwoMonths), new Tuple<string, double>("3M",ThreeMonths), new Tuple<string, double>("6M",SixMonths), new Tuple<string, double>("9M",NineMonths), new Tuple<string, double>("12M",TwelveMonths) })
|
||||
{
|
||||
if(!BaseFundamentalDataProvider.IsNone(typeof(double), kvp.Item2))
|
||||
{
|
||||
result[kvp.Item1] = kvp.Item2;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the value of the field for the requested period
|
||||
/// </summary>
|
||||
/// <param name="period">The requested period</param>
|
||||
/// <returns>The value for the period</returns>
|
||||
public override double GetPeriodValue(string period) => FundamentalService.Get<double>(TimeProvider.GetUtcNow(), SecurityIdentifier, Enum.Parse<FundamentalProperty>($"FinancialStatements_BalanceSheet_AccountsPayable_{ConvertPeriod(period)}"));
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new empty instance
|
||||
/// </summary>
|
||||
public AccountsPayableBalanceSheet()
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new instance for the given time and security
|
||||
/// </summary>
|
||||
public AccountsPayableBalanceSheet(ITimeProvider timeProvider, SecurityIdentifier securityIdentifier) : base(timeProvider, securityIdentifier)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,131 @@
|
||||
/*
|
||||
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
|
||||
* Lean Algorithmic Trading Engine v2.0. Copyright 2023 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 Newtonsoft.Json;
|
||||
using System.Collections.Generic;
|
||||
using QuantConnect.Data.UniverseSelection;
|
||||
|
||||
namespace QuantConnect.Data.Fundamental
|
||||
{
|
||||
/// <summary>
|
||||
/// Accounts owed to a company by customers within a year as a result of exchanging goods or services on credit.
|
||||
/// </summary>
|
||||
public class AccountsReceivableBalanceSheet : MultiPeriodField
|
||||
{
|
||||
/// <summary>
|
||||
/// The default period
|
||||
/// </summary>
|
||||
protected override string DefaultPeriod => "TwelveMonths";
|
||||
|
||||
/// <summary>
|
||||
/// Gets/sets the OneMonth period value for the field
|
||||
/// </summary>
|
||||
[JsonProperty("1M")]
|
||||
public double OneMonth => FundamentalService.Get<double>(TimeProvider.GetUtcNow(), SecurityIdentifier, FundamentalProperty.FinancialStatements_BalanceSheet_AccountsReceivable_OneMonth);
|
||||
|
||||
/// <summary>
|
||||
/// Gets/sets the TwoMonths period value for the field
|
||||
/// </summary>
|
||||
[JsonProperty("2M")]
|
||||
public double TwoMonths => FundamentalService.Get<double>(TimeProvider.GetUtcNow(), SecurityIdentifier, FundamentalProperty.FinancialStatements_BalanceSheet_AccountsReceivable_TwoMonths);
|
||||
|
||||
/// <summary>
|
||||
/// Gets/sets the ThreeMonths period value for the field
|
||||
/// </summary>
|
||||
[JsonProperty("3M")]
|
||||
public double ThreeMonths => FundamentalService.Get<double>(TimeProvider.GetUtcNow(), SecurityIdentifier, FundamentalProperty.FinancialStatements_BalanceSheet_AccountsReceivable_ThreeMonths);
|
||||
|
||||
/// <summary>
|
||||
/// Gets/sets the SixMonths period value for the field
|
||||
/// </summary>
|
||||
[JsonProperty("6M")]
|
||||
public double SixMonths => FundamentalService.Get<double>(TimeProvider.GetUtcNow(), SecurityIdentifier, FundamentalProperty.FinancialStatements_BalanceSheet_AccountsReceivable_SixMonths);
|
||||
|
||||
/// <summary>
|
||||
/// Gets/sets the NineMonths period value for the field
|
||||
/// </summary>
|
||||
[JsonProperty("9M")]
|
||||
public double NineMonths => FundamentalService.Get<double>(TimeProvider.GetUtcNow(), SecurityIdentifier, FundamentalProperty.FinancialStatements_BalanceSheet_AccountsReceivable_NineMonths);
|
||||
|
||||
/// <summary>
|
||||
/// Gets/sets the TwelveMonths period value for the field
|
||||
/// </summary>
|
||||
[JsonProperty("12M")]
|
||||
public double TwelveMonths => FundamentalService.Get<double>(TimeProvider.GetUtcNow(), SecurityIdentifier, FundamentalProperty.FinancialStatements_BalanceSheet_AccountsReceivable_TwelveMonths);
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if the field contains a value for the default period
|
||||
/// </summary>
|
||||
public override bool HasValue => !BaseFundamentalDataProvider.IsNone(typeof(double), FundamentalService.Get<double>(TimeProvider.GetUtcNow(), SecurityIdentifier, FundamentalProperty.FinancialStatements_BalanceSheet_AccountsReceivable_TwelveMonths));
|
||||
|
||||
/// <summary>
|
||||
/// Returns the default value for the field
|
||||
/// </summary>
|
||||
public override double Value
|
||||
{
|
||||
get
|
||||
{
|
||||
var defaultValue = FundamentalService.Get<double>(TimeProvider.GetUtcNow(), SecurityIdentifier, FundamentalProperty.FinancialStatements_BalanceSheet_AccountsReceivable_TwelveMonths);
|
||||
if (!BaseFundamentalDataProvider.IsNone(typeof(double), defaultValue))
|
||||
{
|
||||
return defaultValue;
|
||||
}
|
||||
return base.Value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a dictionary of period names and values for the field
|
||||
/// </summary>
|
||||
/// <returns>The dictionary of period names and values</returns>
|
||||
public override IReadOnlyDictionary<string, double> GetPeriodValues()
|
||||
{
|
||||
var result = new Dictionary<string, double>();
|
||||
foreach (var kvp in new[] { new Tuple<string, double>("1M",OneMonth), new Tuple<string, double>("2M",TwoMonths), new Tuple<string, double>("3M",ThreeMonths), new Tuple<string, double>("6M",SixMonths), new Tuple<string, double>("9M",NineMonths), new Tuple<string, double>("12M",TwelveMonths) })
|
||||
{
|
||||
if(!BaseFundamentalDataProvider.IsNone(typeof(double), kvp.Item2))
|
||||
{
|
||||
result[kvp.Item1] = kvp.Item2;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the value of the field for the requested period
|
||||
/// </summary>
|
||||
/// <param name="period">The requested period</param>
|
||||
/// <returns>The value for the period</returns>
|
||||
public override double GetPeriodValue(string period) => FundamentalService.Get<double>(TimeProvider.GetUtcNow(), SecurityIdentifier, Enum.Parse<FundamentalProperty>($"FinancialStatements_BalanceSheet_AccountsReceivable_{ConvertPeriod(period)}"));
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new empty instance
|
||||
/// </summary>
|
||||
public AccountsReceivableBalanceSheet()
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new instance for the given time and security
|
||||
/// </summary>
|
||||
public AccountsReceivableBalanceSheet(ITimeProvider timeProvider, SecurityIdentifier securityIdentifier) : base(timeProvider, securityIdentifier)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,125 @@
|
||||
/*
|
||||
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
|
||||
* Lean Algorithmic Trading Engine v2.0. Copyright 2023 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 Newtonsoft.Json;
|
||||
using System.Collections.Generic;
|
||||
using QuantConnect.Data.UniverseSelection;
|
||||
|
||||
namespace QuantConnect.Data.Fundamental
|
||||
{
|
||||
/// <summary>
|
||||
/// This account shows the amount of unpaid interest accrued to the date of purchase and included in the purchase price of securities purchased between interest dates.
|
||||
/// </summary>
|
||||
public class AccruedInterestReceivableBalanceSheet : MultiPeriodField
|
||||
{
|
||||
/// <summary>
|
||||
/// The default period
|
||||
/// </summary>
|
||||
protected override string DefaultPeriod => "TwelveMonths";
|
||||
|
||||
/// <summary>
|
||||
/// Gets/sets the TwoMonths period value for the field
|
||||
/// </summary>
|
||||
[JsonProperty("2M")]
|
||||
public double TwoMonths => FundamentalService.Get<double>(TimeProvider.GetUtcNow(), SecurityIdentifier, FundamentalProperty.FinancialStatements_BalanceSheet_AccruedInterestReceivable_TwoMonths);
|
||||
|
||||
/// <summary>
|
||||
/// Gets/sets the ThreeMonths period value for the field
|
||||
/// </summary>
|
||||
[JsonProperty("3M")]
|
||||
public double ThreeMonths => FundamentalService.Get<double>(TimeProvider.GetUtcNow(), SecurityIdentifier, FundamentalProperty.FinancialStatements_BalanceSheet_AccruedInterestReceivable_ThreeMonths);
|
||||
|
||||
/// <summary>
|
||||
/// Gets/sets the SixMonths period value for the field
|
||||
/// </summary>
|
||||
[JsonProperty("6M")]
|
||||
public double SixMonths => FundamentalService.Get<double>(TimeProvider.GetUtcNow(), SecurityIdentifier, FundamentalProperty.FinancialStatements_BalanceSheet_AccruedInterestReceivable_SixMonths);
|
||||
|
||||
/// <summary>
|
||||
/// Gets/sets the NineMonths period value for the field
|
||||
/// </summary>
|
||||
[JsonProperty("9M")]
|
||||
public double NineMonths => FundamentalService.Get<double>(TimeProvider.GetUtcNow(), SecurityIdentifier, FundamentalProperty.FinancialStatements_BalanceSheet_AccruedInterestReceivable_NineMonths);
|
||||
|
||||
/// <summary>
|
||||
/// Gets/sets the TwelveMonths period value for the field
|
||||
/// </summary>
|
||||
[JsonProperty("12M")]
|
||||
public double TwelveMonths => FundamentalService.Get<double>(TimeProvider.GetUtcNow(), SecurityIdentifier, FundamentalProperty.FinancialStatements_BalanceSheet_AccruedInterestReceivable_TwelveMonths);
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if the field contains a value for the default period
|
||||
/// </summary>
|
||||
public override bool HasValue => !BaseFundamentalDataProvider.IsNone(typeof(double), FundamentalService.Get<double>(TimeProvider.GetUtcNow(), SecurityIdentifier, FundamentalProperty.FinancialStatements_BalanceSheet_AccruedInterestReceivable_TwelveMonths));
|
||||
|
||||
/// <summary>
|
||||
/// Returns the default value for the field
|
||||
/// </summary>
|
||||
public override double Value
|
||||
{
|
||||
get
|
||||
{
|
||||
var defaultValue = FundamentalService.Get<double>(TimeProvider.GetUtcNow(), SecurityIdentifier, FundamentalProperty.FinancialStatements_BalanceSheet_AccruedInterestReceivable_TwelveMonths);
|
||||
if (!BaseFundamentalDataProvider.IsNone(typeof(double), defaultValue))
|
||||
{
|
||||
return defaultValue;
|
||||
}
|
||||
return base.Value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a dictionary of period names and values for the field
|
||||
/// </summary>
|
||||
/// <returns>The dictionary of period names and values</returns>
|
||||
public override IReadOnlyDictionary<string, double> GetPeriodValues()
|
||||
{
|
||||
var result = new Dictionary<string, double>();
|
||||
foreach (var kvp in new[] { new Tuple<string, double>("2M",TwoMonths), new Tuple<string, double>("3M",ThreeMonths), new Tuple<string, double>("6M",SixMonths), new Tuple<string, double>("9M",NineMonths), new Tuple<string, double>("12M",TwelveMonths) })
|
||||
{
|
||||
if(!BaseFundamentalDataProvider.IsNone(typeof(double), kvp.Item2))
|
||||
{
|
||||
result[kvp.Item1] = kvp.Item2;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the value of the field for the requested period
|
||||
/// </summary>
|
||||
/// <param name="period">The requested period</param>
|
||||
/// <returns>The value for the period</returns>
|
||||
public override double GetPeriodValue(string period) => FundamentalService.Get<double>(TimeProvider.GetUtcNow(), SecurityIdentifier, Enum.Parse<FundamentalProperty>($"FinancialStatements_BalanceSheet_AccruedInterestReceivable_{ConvertPeriod(period)}"));
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new empty instance
|
||||
/// </summary>
|
||||
public AccruedInterestReceivableBalanceSheet()
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new instance for the given time and security
|
||||
/// </summary>
|
||||
public AccruedInterestReceivableBalanceSheet(ITimeProvider timeProvider, SecurityIdentifier securityIdentifier) : base(timeProvider, securityIdentifier)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,113 @@
|
||||
/*
|
||||
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
|
||||
* Lean Algorithmic Trading Engine v2.0. Copyright 2023 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 Newtonsoft.Json;
|
||||
using System.Collections.Generic;
|
||||
using QuantConnect.Data.UniverseSelection;
|
||||
|
||||
namespace QuantConnect.Data.Fundamental
|
||||
{
|
||||
/// <summary>
|
||||
/// Interest, dividends, rents, ancillary and other revenues earned but not yet received by the entity on its investments.
|
||||
/// </summary>
|
||||
public class AccruedInvestmentIncomeBalanceSheet : MultiPeriodField
|
||||
{
|
||||
/// <summary>
|
||||
/// The default period
|
||||
/// </summary>
|
||||
protected override string DefaultPeriod => "TwelveMonths";
|
||||
|
||||
/// <summary>
|
||||
/// Gets/sets the ThreeMonths period value for the field
|
||||
/// </summary>
|
||||
[JsonProperty("3M")]
|
||||
public double ThreeMonths => FundamentalService.Get<double>(TimeProvider.GetUtcNow(), SecurityIdentifier, FundamentalProperty.FinancialStatements_BalanceSheet_AccruedInvestmentIncome_ThreeMonths);
|
||||
|
||||
/// <summary>
|
||||
/// Gets/sets the NineMonths period value for the field
|
||||
/// </summary>
|
||||
[JsonProperty("6M")]
|
||||
public double SixMonths => FundamentalService.Get<double>(TimeProvider.GetUtcNow(), SecurityIdentifier, FundamentalProperty.FinancialStatements_BalanceSheet_AccruedInvestmentIncome_SixMonths);
|
||||
|
||||
/// <summary>
|
||||
/// Gets/sets the TwelveMonths period value for the field
|
||||
/// </summary>
|
||||
[JsonProperty("12M")]
|
||||
public double TwelveMonths => FundamentalService.Get<double>(TimeProvider.GetUtcNow(), SecurityIdentifier, FundamentalProperty.FinancialStatements_BalanceSheet_AccruedInvestmentIncome_TwelveMonths);
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if the field contains a value for the default period
|
||||
/// </summary>
|
||||
public override bool HasValue => !BaseFundamentalDataProvider.IsNone(typeof(double), FundamentalService.Get<double>(TimeProvider.GetUtcNow(), SecurityIdentifier, FundamentalProperty.FinancialStatements_BalanceSheet_AccruedInvestmentIncome_TwelveMonths));
|
||||
|
||||
/// <summary>
|
||||
/// Returns the default value for the field
|
||||
/// </summary>
|
||||
public override double Value
|
||||
{
|
||||
get
|
||||
{
|
||||
var defaultValue = FundamentalService.Get<double>(TimeProvider.GetUtcNow(), SecurityIdentifier, FundamentalProperty.FinancialStatements_BalanceSheet_AccruedInvestmentIncome_TwelveMonths);
|
||||
if (!BaseFundamentalDataProvider.IsNone(typeof(double), defaultValue))
|
||||
{
|
||||
return defaultValue;
|
||||
}
|
||||
return base.Value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a dictionary of period names and values for the field
|
||||
/// </summary>
|
||||
/// <returns>The dictionary of period names and values</returns>
|
||||
public override IReadOnlyDictionary<string, double> GetPeriodValues()
|
||||
{
|
||||
var result = new Dictionary<string, double>();
|
||||
foreach (var kvp in new[] { new Tuple<string, double>("3M",ThreeMonths), new Tuple<string, double>("6M",SixMonths), new Tuple<string, double>("12M",TwelveMonths) })
|
||||
{
|
||||
if(!BaseFundamentalDataProvider.IsNone(typeof(double), kvp.Item2))
|
||||
{
|
||||
result[kvp.Item1] = kvp.Item2;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the value of the field for the requested period
|
||||
/// </summary>
|
||||
/// <param name="period">The requested period</param>
|
||||
/// <returns>The value for the period</returns>
|
||||
public override double GetPeriodValue(string period) => FundamentalService.Get<double>(TimeProvider.GetUtcNow(), SecurityIdentifier, Enum.Parse<FundamentalProperty>($"FinancialStatements_BalanceSheet_AccruedInvestmentIncome_{ConvertPeriod(period)}"));
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new empty instance
|
||||
/// </summary>
|
||||
public AccruedInvestmentIncomeBalanceSheet()
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new instance for the given time and security
|
||||
/// </summary>
|
||||
public AccruedInvestmentIncomeBalanceSheet(ITimeProvider timeProvider, SecurityIdentifier securityIdentifier) : base(timeProvider, securityIdentifier)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,113 @@
|
||||
/*
|
||||
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
|
||||
* Lean Algorithmic Trading Engine v2.0. Copyright 2023 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 Newtonsoft.Json;
|
||||
using System.Collections.Generic;
|
||||
using QuantConnect.Data.UniverseSelection;
|
||||
|
||||
namespace QuantConnect.Data.Fundamental
|
||||
{
|
||||
/// <summary>
|
||||
/// Liabilities which have occurred, but have not been paid or logged under accounts payable during an accounting PeriodAsByte. In other words, obligations for goods and services provided to a company for which invoices have not yet been received; on a Non- Differentiated Balance Sheet.
|
||||
/// </summary>
|
||||
public class AccruedLiabilitiesTotalBalanceSheet : MultiPeriodField
|
||||
{
|
||||
/// <summary>
|
||||
/// The default period
|
||||
/// </summary>
|
||||
protected override string DefaultPeriod => "TwelveMonths";
|
||||
|
||||
/// <summary>
|
||||
/// Gets/sets the TwoMonths period value for the field
|
||||
/// </summary>
|
||||
[JsonProperty("2M")]
|
||||
public double TwoMonths => FundamentalService.Get<double>(TimeProvider.GetUtcNow(), SecurityIdentifier, FundamentalProperty.FinancialStatements_BalanceSheet_AccruedLiabilitiesTotal_TwoMonths);
|
||||
|
||||
/// <summary>
|
||||
/// Gets/sets the ThreeMonths period value for the field
|
||||
/// </summary>
|
||||
[JsonProperty("3M")]
|
||||
public double ThreeMonths => FundamentalService.Get<double>(TimeProvider.GetUtcNow(), SecurityIdentifier, FundamentalProperty.FinancialStatements_BalanceSheet_AccruedLiabilitiesTotal_ThreeMonths);
|
||||
|
||||
/// <summary>
|
||||
/// Gets/sets the TwelveMonths period value for the field
|
||||
/// </summary>
|
||||
[JsonProperty("12M")]
|
||||
public double TwelveMonths => FundamentalService.Get<double>(TimeProvider.GetUtcNow(), SecurityIdentifier, FundamentalProperty.FinancialStatements_BalanceSheet_AccruedLiabilitiesTotal_TwelveMonths);
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if the field contains a value for the default period
|
||||
/// </summary>
|
||||
public override bool HasValue => !BaseFundamentalDataProvider.IsNone(typeof(double), FundamentalService.Get<double>(TimeProvider.GetUtcNow(), SecurityIdentifier, FundamentalProperty.FinancialStatements_BalanceSheet_AccruedLiabilitiesTotal_TwelveMonths));
|
||||
|
||||
/// <summary>
|
||||
/// Returns the default value for the field
|
||||
/// </summary>
|
||||
public override double Value
|
||||
{
|
||||
get
|
||||
{
|
||||
var defaultValue = FundamentalService.Get<double>(TimeProvider.GetUtcNow(), SecurityIdentifier, FundamentalProperty.FinancialStatements_BalanceSheet_AccruedLiabilitiesTotal_TwelveMonths);
|
||||
if (!BaseFundamentalDataProvider.IsNone(typeof(double), defaultValue))
|
||||
{
|
||||
return defaultValue;
|
||||
}
|
||||
return base.Value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a dictionary of period names and values for the field
|
||||
/// </summary>
|
||||
/// <returns>The dictionary of period names and values</returns>
|
||||
public override IReadOnlyDictionary<string, double> GetPeriodValues()
|
||||
{
|
||||
var result = new Dictionary<string, double>();
|
||||
foreach (var kvp in new[] { new Tuple<string, double>("2M",TwoMonths), new Tuple<string, double>("3M",ThreeMonths), new Tuple<string, double>("12M",TwelveMonths) })
|
||||
{
|
||||
if(!BaseFundamentalDataProvider.IsNone(typeof(double), kvp.Item2))
|
||||
{
|
||||
result[kvp.Item1] = kvp.Item2;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the value of the field for the requested period
|
||||
/// </summary>
|
||||
/// <param name="period">The requested period</param>
|
||||
/// <returns>The value for the period</returns>
|
||||
public override double GetPeriodValue(string period) => FundamentalService.Get<double>(TimeProvider.GetUtcNow(), SecurityIdentifier, Enum.Parse<FundamentalProperty>($"FinancialStatements_BalanceSheet_AccruedLiabilitiesTotal_{ConvertPeriod(period)}"));
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new empty instance
|
||||
/// </summary>
|
||||
public AccruedLiabilitiesTotalBalanceSheet()
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new instance for the given time and security
|
||||
/// </summary>
|
||||
public AccruedLiabilitiesTotalBalanceSheet(ITimeProvider timeProvider, SecurityIdentifier securityIdentifier) : base(timeProvider, securityIdentifier)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,107 @@
|
||||
/*
|
||||
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
|
||||
* Lean Algorithmic Trading Engine v2.0. Copyright 2023 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 Newtonsoft.Json;
|
||||
using System.Collections.Generic;
|
||||
using QuantConnect.Data.UniverseSelection;
|
||||
|
||||
namespace QuantConnect.Data.Fundamental
|
||||
{
|
||||
/// <summary>
|
||||
/// Sum of accrued liabilities and deferred income (amount received in advance but the services are not provided in respect of amount).
|
||||
/// </summary>
|
||||
public class AccruedandDeferredIncomeBalanceSheet : MultiPeriodField
|
||||
{
|
||||
/// <summary>
|
||||
/// The default period
|
||||
/// </summary>
|
||||
protected override string DefaultPeriod => "TwelveMonths";
|
||||
|
||||
/// <summary>
|
||||
/// Gets/sets the ThreeMonths period value for the field
|
||||
/// </summary>
|
||||
[JsonProperty("3M")]
|
||||
public double ThreeMonths => FundamentalService.Get<double>(TimeProvider.GetUtcNow(), SecurityIdentifier, FundamentalProperty.FinancialStatements_BalanceSheet_AccruedandDeferredIncome_ThreeMonths);
|
||||
|
||||
/// <summary>
|
||||
/// Gets/sets the TwelveMonths period value for the field
|
||||
/// </summary>
|
||||
[JsonProperty("12M")]
|
||||
public double TwelveMonths => FundamentalService.Get<double>(TimeProvider.GetUtcNow(), SecurityIdentifier, FundamentalProperty.FinancialStatements_BalanceSheet_AccruedandDeferredIncome_TwelveMonths);
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if the field contains a value for the default period
|
||||
/// </summary>
|
||||
public override bool HasValue => !BaseFundamentalDataProvider.IsNone(typeof(double), FundamentalService.Get<double>(TimeProvider.GetUtcNow(), SecurityIdentifier, FundamentalProperty.FinancialStatements_BalanceSheet_AccruedandDeferredIncome_TwelveMonths));
|
||||
|
||||
/// <summary>
|
||||
/// Returns the default value for the field
|
||||
/// </summary>
|
||||
public override double Value
|
||||
{
|
||||
get
|
||||
{
|
||||
var defaultValue = FundamentalService.Get<double>(TimeProvider.GetUtcNow(), SecurityIdentifier, FundamentalProperty.FinancialStatements_BalanceSheet_AccruedandDeferredIncome_TwelveMonths);
|
||||
if (!BaseFundamentalDataProvider.IsNone(typeof(double), defaultValue))
|
||||
{
|
||||
return defaultValue;
|
||||
}
|
||||
return base.Value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a dictionary of period names and values for the field
|
||||
/// </summary>
|
||||
/// <returns>The dictionary of period names and values</returns>
|
||||
public override IReadOnlyDictionary<string, double> GetPeriodValues()
|
||||
{
|
||||
var result = new Dictionary<string, double>();
|
||||
foreach (var kvp in new[] { new Tuple<string, double>("3M",ThreeMonths), new Tuple<string, double>("12M",TwelveMonths) })
|
||||
{
|
||||
if(!BaseFundamentalDataProvider.IsNone(typeof(double), kvp.Item2))
|
||||
{
|
||||
result[kvp.Item1] = kvp.Item2;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the value of the field for the requested period
|
||||
/// </summary>
|
||||
/// <param name="period">The requested period</param>
|
||||
/// <returns>The value for the period</returns>
|
||||
public override double GetPeriodValue(string period) => FundamentalService.Get<double>(TimeProvider.GetUtcNow(), SecurityIdentifier, Enum.Parse<FundamentalProperty>($"FinancialStatements_BalanceSheet_AccruedandDeferredIncome_{ConvertPeriod(period)}"));
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new empty instance
|
||||
/// </summary>
|
||||
public AccruedandDeferredIncomeBalanceSheet()
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new instance for the given time and security
|
||||
/// </summary>
|
||||
public AccruedandDeferredIncomeBalanceSheet(ITimeProvider timeProvider, SecurityIdentifier securityIdentifier) : base(timeProvider, securityIdentifier)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,107 @@
|
||||
/*
|
||||
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
|
||||
* Lean Algorithmic Trading Engine v2.0. Copyright 2023 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 Newtonsoft.Json;
|
||||
using System.Collections.Generic;
|
||||
using QuantConnect.Data.UniverseSelection;
|
||||
|
||||
namespace QuantConnect.Data.Fundamental
|
||||
{
|
||||
/// <summary>
|
||||
/// Sum of Accrued Liabilities and Deferred Income (amount received in advance but the services are not provided in respect of amount) due within 1 year.
|
||||
/// </summary>
|
||||
public class AccruedandDeferredIncomeCurrentBalanceSheet : MultiPeriodField
|
||||
{
|
||||
/// <summary>
|
||||
/// The default period
|
||||
/// </summary>
|
||||
protected override string DefaultPeriod => "TwelveMonths";
|
||||
|
||||
/// <summary>
|
||||
/// Gets/sets the ThreeMonths period value for the field
|
||||
/// </summary>
|
||||
[JsonProperty("3M")]
|
||||
public double ThreeMonths => FundamentalService.Get<double>(TimeProvider.GetUtcNow(), SecurityIdentifier, FundamentalProperty.FinancialStatements_BalanceSheet_AccruedandDeferredIncomeCurrent_ThreeMonths);
|
||||
|
||||
/// <summary>
|
||||
/// Gets/sets the TwelveMonths period value for the field
|
||||
/// </summary>
|
||||
[JsonProperty("12M")]
|
||||
public double TwelveMonths => FundamentalService.Get<double>(TimeProvider.GetUtcNow(), SecurityIdentifier, FundamentalProperty.FinancialStatements_BalanceSheet_AccruedandDeferredIncomeCurrent_TwelveMonths);
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if the field contains a value for the default period
|
||||
/// </summary>
|
||||
public override bool HasValue => !BaseFundamentalDataProvider.IsNone(typeof(double), FundamentalService.Get<double>(TimeProvider.GetUtcNow(), SecurityIdentifier, FundamentalProperty.FinancialStatements_BalanceSheet_AccruedandDeferredIncomeCurrent_TwelveMonths));
|
||||
|
||||
/// <summary>
|
||||
/// Returns the default value for the field
|
||||
/// </summary>
|
||||
public override double Value
|
||||
{
|
||||
get
|
||||
{
|
||||
var defaultValue = FundamentalService.Get<double>(TimeProvider.GetUtcNow(), SecurityIdentifier, FundamentalProperty.FinancialStatements_BalanceSheet_AccruedandDeferredIncomeCurrent_TwelveMonths);
|
||||
if (!BaseFundamentalDataProvider.IsNone(typeof(double), defaultValue))
|
||||
{
|
||||
return defaultValue;
|
||||
}
|
||||
return base.Value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a dictionary of period names and values for the field
|
||||
/// </summary>
|
||||
/// <returns>The dictionary of period names and values</returns>
|
||||
public override IReadOnlyDictionary<string, double> GetPeriodValues()
|
||||
{
|
||||
var result = new Dictionary<string, double>();
|
||||
foreach (var kvp in new[] { new Tuple<string, double>("3M",ThreeMonths), new Tuple<string, double>("12M",TwelveMonths) })
|
||||
{
|
||||
if(!BaseFundamentalDataProvider.IsNone(typeof(double), kvp.Item2))
|
||||
{
|
||||
result[kvp.Item1] = kvp.Item2;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the value of the field for the requested period
|
||||
/// </summary>
|
||||
/// <param name="period">The requested period</param>
|
||||
/// <returns>The value for the period</returns>
|
||||
public override double GetPeriodValue(string period) => FundamentalService.Get<double>(TimeProvider.GetUtcNow(), SecurityIdentifier, Enum.Parse<FundamentalProperty>($"FinancialStatements_BalanceSheet_AccruedandDeferredIncomeCurrent_{ConvertPeriod(period)}"));
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new empty instance
|
||||
/// </summary>
|
||||
public AccruedandDeferredIncomeCurrentBalanceSheet()
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new instance for the given time and security
|
||||
/// </summary>
|
||||
public AccruedandDeferredIncomeCurrentBalanceSheet(ITimeProvider timeProvider, SecurityIdentifier securityIdentifier) : base(timeProvider, securityIdentifier)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,107 @@
|
||||
/*
|
||||
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
|
||||
* Lean Algorithmic Trading Engine v2.0. Copyright 2023 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 Newtonsoft.Json;
|
||||
using System.Collections.Generic;
|
||||
using QuantConnect.Data.UniverseSelection;
|
||||
|
||||
namespace QuantConnect.Data.Fundamental
|
||||
{
|
||||
/// <summary>
|
||||
/// Sum of Accrued Liabilities and Deferred Income (amount received in advance but the services are not provided in respect of amount) due after 1 year.
|
||||
/// </summary>
|
||||
public class AccruedandDeferredIncomeNonCurrentBalanceSheet : MultiPeriodField
|
||||
{
|
||||
/// <summary>
|
||||
/// The default period
|
||||
/// </summary>
|
||||
protected override string DefaultPeriod => "TwelveMonths";
|
||||
|
||||
/// <summary>
|
||||
/// Gets/sets the ThreeMonths period value for the field
|
||||
/// </summary>
|
||||
[JsonProperty("3M")]
|
||||
public double ThreeMonths => FundamentalService.Get<double>(TimeProvider.GetUtcNow(), SecurityIdentifier, FundamentalProperty.FinancialStatements_BalanceSheet_AccruedandDeferredIncomeNonCurrent_ThreeMonths);
|
||||
|
||||
/// <summary>
|
||||
/// Gets/sets the TwelveMonths period value for the field
|
||||
/// </summary>
|
||||
[JsonProperty("12M")]
|
||||
public double TwelveMonths => FundamentalService.Get<double>(TimeProvider.GetUtcNow(), SecurityIdentifier, FundamentalProperty.FinancialStatements_BalanceSheet_AccruedandDeferredIncomeNonCurrent_TwelveMonths);
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if the field contains a value for the default period
|
||||
/// </summary>
|
||||
public override bool HasValue => !BaseFundamentalDataProvider.IsNone(typeof(double), FundamentalService.Get<double>(TimeProvider.GetUtcNow(), SecurityIdentifier, FundamentalProperty.FinancialStatements_BalanceSheet_AccruedandDeferredIncomeNonCurrent_TwelveMonths));
|
||||
|
||||
/// <summary>
|
||||
/// Returns the default value for the field
|
||||
/// </summary>
|
||||
public override double Value
|
||||
{
|
||||
get
|
||||
{
|
||||
var defaultValue = FundamentalService.Get<double>(TimeProvider.GetUtcNow(), SecurityIdentifier, FundamentalProperty.FinancialStatements_BalanceSheet_AccruedandDeferredIncomeNonCurrent_TwelveMonths);
|
||||
if (!BaseFundamentalDataProvider.IsNone(typeof(double), defaultValue))
|
||||
{
|
||||
return defaultValue;
|
||||
}
|
||||
return base.Value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a dictionary of period names and values for the field
|
||||
/// </summary>
|
||||
/// <returns>The dictionary of period names and values</returns>
|
||||
public override IReadOnlyDictionary<string, double> GetPeriodValues()
|
||||
{
|
||||
var result = new Dictionary<string, double>();
|
||||
foreach (var kvp in new[] { new Tuple<string, double>("3M",ThreeMonths), new Tuple<string, double>("12M",TwelveMonths) })
|
||||
{
|
||||
if(!BaseFundamentalDataProvider.IsNone(typeof(double), kvp.Item2))
|
||||
{
|
||||
result[kvp.Item1] = kvp.Item2;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the value of the field for the requested period
|
||||
/// </summary>
|
||||
/// <param name="period">The requested period</param>
|
||||
/// <returns>The value for the period</returns>
|
||||
public override double GetPeriodValue(string period) => FundamentalService.Get<double>(TimeProvider.GetUtcNow(), SecurityIdentifier, Enum.Parse<FundamentalProperty>($"FinancialStatements_BalanceSheet_AccruedandDeferredIncomeNonCurrent_{ConvertPeriod(period)}"));
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new empty instance
|
||||
/// </summary>
|
||||
public AccruedandDeferredIncomeNonCurrentBalanceSheet()
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new instance for the given time and security
|
||||
/// </summary>
|
||||
public AccruedandDeferredIncomeNonCurrentBalanceSheet(ITimeProvider timeProvider, SecurityIdentifier securityIdentifier) : base(timeProvider, securityIdentifier)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,131 @@
|
||||
/*
|
||||
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
|
||||
* Lean Algorithmic Trading Engine v2.0. Copyright 2023 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 Newtonsoft.Json;
|
||||
using System.Collections.Generic;
|
||||
using QuantConnect.Data.UniverseSelection;
|
||||
|
||||
namespace QuantConnect.Data.Fundamental
|
||||
{
|
||||
/// <summary>
|
||||
/// The cumulative amount of wear and tear or obsolescence charged against the fixed assets of a company.
|
||||
/// </summary>
|
||||
public class AccumulatedDepreciationBalanceSheet : MultiPeriodField
|
||||
{
|
||||
/// <summary>
|
||||
/// The default period
|
||||
/// </summary>
|
||||
protected override string DefaultPeriod => "TwelveMonths";
|
||||
|
||||
/// <summary>
|
||||
/// Gets/sets the OneMonth period value for the field
|
||||
/// </summary>
|
||||
[JsonProperty("1M")]
|
||||
public double OneMonth => FundamentalService.Get<double>(TimeProvider.GetUtcNow(), SecurityIdentifier, FundamentalProperty.FinancialStatements_BalanceSheet_AccumulatedDepreciation_OneMonth);
|
||||
|
||||
/// <summary>
|
||||
/// Gets/sets the TwoMonths period value for the field
|
||||
/// </summary>
|
||||
[JsonProperty("2M")]
|
||||
public double TwoMonths => FundamentalService.Get<double>(TimeProvider.GetUtcNow(), SecurityIdentifier, FundamentalProperty.FinancialStatements_BalanceSheet_AccumulatedDepreciation_TwoMonths);
|
||||
|
||||
/// <summary>
|
||||
/// Gets/sets the ThreeMonths period value for the field
|
||||
/// </summary>
|
||||
[JsonProperty("3M")]
|
||||
public double ThreeMonths => FundamentalService.Get<double>(TimeProvider.GetUtcNow(), SecurityIdentifier, FundamentalProperty.FinancialStatements_BalanceSheet_AccumulatedDepreciation_ThreeMonths);
|
||||
|
||||
/// <summary>
|
||||
/// Gets/sets the SixMonths period value for the field
|
||||
/// </summary>
|
||||
[JsonProperty("6M")]
|
||||
public double SixMonths => FundamentalService.Get<double>(TimeProvider.GetUtcNow(), SecurityIdentifier, FundamentalProperty.FinancialStatements_BalanceSheet_AccumulatedDepreciation_SixMonths);
|
||||
|
||||
/// <summary>
|
||||
/// Gets/sets the NineMonths period value for the field
|
||||
/// </summary>
|
||||
[JsonProperty("9M")]
|
||||
public double NineMonths => FundamentalService.Get<double>(TimeProvider.GetUtcNow(), SecurityIdentifier, FundamentalProperty.FinancialStatements_BalanceSheet_AccumulatedDepreciation_NineMonths);
|
||||
|
||||
/// <summary>
|
||||
/// Gets/sets the TwelveMonths period value for the field
|
||||
/// </summary>
|
||||
[JsonProperty("12M")]
|
||||
public double TwelveMonths => FundamentalService.Get<double>(TimeProvider.GetUtcNow(), SecurityIdentifier, FundamentalProperty.FinancialStatements_BalanceSheet_AccumulatedDepreciation_TwelveMonths);
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if the field contains a value for the default period
|
||||
/// </summary>
|
||||
public override bool HasValue => !BaseFundamentalDataProvider.IsNone(typeof(double), FundamentalService.Get<double>(TimeProvider.GetUtcNow(), SecurityIdentifier, FundamentalProperty.FinancialStatements_BalanceSheet_AccumulatedDepreciation_TwelveMonths));
|
||||
|
||||
/// <summary>
|
||||
/// Returns the default value for the field
|
||||
/// </summary>
|
||||
public override double Value
|
||||
{
|
||||
get
|
||||
{
|
||||
var defaultValue = FundamentalService.Get<double>(TimeProvider.GetUtcNow(), SecurityIdentifier, FundamentalProperty.FinancialStatements_BalanceSheet_AccumulatedDepreciation_TwelveMonths);
|
||||
if (!BaseFundamentalDataProvider.IsNone(typeof(double), defaultValue))
|
||||
{
|
||||
return defaultValue;
|
||||
}
|
||||
return base.Value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a dictionary of period names and values for the field
|
||||
/// </summary>
|
||||
/// <returns>The dictionary of period names and values</returns>
|
||||
public override IReadOnlyDictionary<string, double> GetPeriodValues()
|
||||
{
|
||||
var result = new Dictionary<string, double>();
|
||||
foreach (var kvp in new[] { new Tuple<string, double>("1M",OneMonth), new Tuple<string, double>("2M",TwoMonths), new Tuple<string, double>("3M",ThreeMonths), new Tuple<string, double>("6M",SixMonths), new Tuple<string, double>("9M",NineMonths), new Tuple<string, double>("12M",TwelveMonths) })
|
||||
{
|
||||
if(!BaseFundamentalDataProvider.IsNone(typeof(double), kvp.Item2))
|
||||
{
|
||||
result[kvp.Item1] = kvp.Item2;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the value of the field for the requested period
|
||||
/// </summary>
|
||||
/// <param name="period">The requested period</param>
|
||||
/// <returns>The value for the period</returns>
|
||||
public override double GetPeriodValue(string period) => FundamentalService.Get<double>(TimeProvider.GetUtcNow(), SecurityIdentifier, Enum.Parse<FundamentalProperty>($"FinancialStatements_BalanceSheet_AccumulatedDepreciation_{ConvertPeriod(period)}"));
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new empty instance
|
||||
/// </summary>
|
||||
public AccumulatedDepreciationBalanceSheet()
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new instance for the given time and security
|
||||
/// </summary>
|
||||
public AccumulatedDepreciationBalanceSheet(ITimeProvider timeProvider, SecurityIdentifier securityIdentifier) : base(timeProvider, securityIdentifier)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,131 @@
|
||||
/*
|
||||
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
|
||||
* Lean Algorithmic Trading Engine v2.0. Copyright 2023 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 Newtonsoft.Json;
|
||||
using System.Collections.Generic;
|
||||
using QuantConnect.Data.UniverseSelection;
|
||||
|
||||
namespace QuantConnect.Data.Fundamental
|
||||
{
|
||||
/// <summary>
|
||||
/// Excess of issue price over par or stated value of the entity's capital stock and amounts received from other transactions involving the entity's stock or stockholders. Includes adjustments to additional paid in capital. There are two major categories of additional paid in capital: 1) Paid in capital in excess of par/stated value, which is the difference between the actual issue price of the shares and the shares' par/stated value. 2) Paid in capital from other transactions which includes treasury stock, retirement of stock, stock dividends recorded at market, lapse of stock purchase warrants, conversion of convertible bonds in excess of the par value of the stock, and any other additional capital from the company's own stock transactions.
|
||||
/// </summary>
|
||||
public class AdditionalPaidInCapitalBalanceSheet : MultiPeriodField
|
||||
{
|
||||
/// <summary>
|
||||
/// The default period
|
||||
/// </summary>
|
||||
protected override string DefaultPeriod => "TwelveMonths";
|
||||
|
||||
/// <summary>
|
||||
/// Gets/sets the OneMonth period value for the field
|
||||
/// </summary>
|
||||
[JsonProperty("1M")]
|
||||
public double OneMonth => FundamentalService.Get<double>(TimeProvider.GetUtcNow(), SecurityIdentifier, FundamentalProperty.FinancialStatements_BalanceSheet_AdditionalPaidInCapital_OneMonth);
|
||||
|
||||
/// <summary>
|
||||
/// Gets/sets the TwoMonths period value for the field
|
||||
/// </summary>
|
||||
[JsonProperty("2M")]
|
||||
public double TwoMonths => FundamentalService.Get<double>(TimeProvider.GetUtcNow(), SecurityIdentifier, FundamentalProperty.FinancialStatements_BalanceSheet_AdditionalPaidInCapital_TwoMonths);
|
||||
|
||||
/// <summary>
|
||||
/// Gets/sets the ThreeMonths period value for the field
|
||||
/// </summary>
|
||||
[JsonProperty("3M")]
|
||||
public double ThreeMonths => FundamentalService.Get<double>(TimeProvider.GetUtcNow(), SecurityIdentifier, FundamentalProperty.FinancialStatements_BalanceSheet_AdditionalPaidInCapital_ThreeMonths);
|
||||
|
||||
/// <summary>
|
||||
/// Gets/sets the SixMonths period value for the field
|
||||
/// </summary>
|
||||
[JsonProperty("6M")]
|
||||
public double SixMonths => FundamentalService.Get<double>(TimeProvider.GetUtcNow(), SecurityIdentifier, FundamentalProperty.FinancialStatements_BalanceSheet_AdditionalPaidInCapital_SixMonths);
|
||||
|
||||
/// <summary>
|
||||
/// Gets/sets the NineMonths period value for the field
|
||||
/// </summary>
|
||||
[JsonProperty("9M")]
|
||||
public double NineMonths => FundamentalService.Get<double>(TimeProvider.GetUtcNow(), SecurityIdentifier, FundamentalProperty.FinancialStatements_BalanceSheet_AdditionalPaidInCapital_NineMonths);
|
||||
|
||||
/// <summary>
|
||||
/// Gets/sets the TwelveMonths period value for the field
|
||||
/// </summary>
|
||||
[JsonProperty("12M")]
|
||||
public double TwelveMonths => FundamentalService.Get<double>(TimeProvider.GetUtcNow(), SecurityIdentifier, FundamentalProperty.FinancialStatements_BalanceSheet_AdditionalPaidInCapital_TwelveMonths);
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if the field contains a value for the default period
|
||||
/// </summary>
|
||||
public override bool HasValue => !BaseFundamentalDataProvider.IsNone(typeof(double), FundamentalService.Get<double>(TimeProvider.GetUtcNow(), SecurityIdentifier, FundamentalProperty.FinancialStatements_BalanceSheet_AdditionalPaidInCapital_TwelveMonths));
|
||||
|
||||
/// <summary>
|
||||
/// Returns the default value for the field
|
||||
/// </summary>
|
||||
public override double Value
|
||||
{
|
||||
get
|
||||
{
|
||||
var defaultValue = FundamentalService.Get<double>(TimeProvider.GetUtcNow(), SecurityIdentifier, FundamentalProperty.FinancialStatements_BalanceSheet_AdditionalPaidInCapital_TwelveMonths);
|
||||
if (!BaseFundamentalDataProvider.IsNone(typeof(double), defaultValue))
|
||||
{
|
||||
return defaultValue;
|
||||
}
|
||||
return base.Value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a dictionary of period names and values for the field
|
||||
/// </summary>
|
||||
/// <returns>The dictionary of period names and values</returns>
|
||||
public override IReadOnlyDictionary<string, double> GetPeriodValues()
|
||||
{
|
||||
var result = new Dictionary<string, double>();
|
||||
foreach (var kvp in new[] { new Tuple<string, double>("1M",OneMonth), new Tuple<string, double>("2M",TwoMonths), new Tuple<string, double>("3M",ThreeMonths), new Tuple<string, double>("6M",SixMonths), new Tuple<string, double>("9M",NineMonths), new Tuple<string, double>("12M",TwelveMonths) })
|
||||
{
|
||||
if(!BaseFundamentalDataProvider.IsNone(typeof(double), kvp.Item2))
|
||||
{
|
||||
result[kvp.Item1] = kvp.Item2;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the value of the field for the requested period
|
||||
/// </summary>
|
||||
/// <param name="period">The requested period</param>
|
||||
/// <returns>The value for the period</returns>
|
||||
public override double GetPeriodValue(string period) => FundamentalService.Get<double>(TimeProvider.GetUtcNow(), SecurityIdentifier, Enum.Parse<FundamentalProperty>($"FinancialStatements_BalanceSheet_AdditionalPaidInCapital_{ConvertPeriod(period)}"));
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new empty instance
|
||||
/// </summary>
|
||||
public AdditionalPaidInCapitalBalanceSheet()
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new instance for the given time and security
|
||||
/// </summary>
|
||||
public AdditionalPaidInCapitalBalanceSheet(ITimeProvider timeProvider, SecurityIdentifier securityIdentifier) : base(timeProvider, securityIdentifier)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user