/* * 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 { /// /// Represents an entire factor file for a specified symbol /// public abstract class FactorFile : IFactorProvider where T : IFactorRow { /// /// Keeping a reversed version is more performant that reversing it each time we need it /// protected List ReversedFactorFileDates { get; } /// /// The factor file data rows sorted by date /// public SortedList> SortedFactorFileData { get; set; } /// /// The minimum tradeable date for the symbol /// /// /// 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 /// public DateTime? FactorFileMinimumDate { get; set; } /// /// Gets the most recent factor change in the factor file /// public DateTime MostRecentFactorChange => ReversedFactorFileDates .FirstOrDefault(time => time != Time.EndOfTime); /// /// Gets the symbol this factor file represents /// public string Permtick { get; } /// /// Initializes a new instance of the class. /// protected FactorFile(string permtick, IEnumerable data, DateTime? factorFileMinimumDate = null) { Permtick = permtick.LazyToUpper(); SortedFactorFileData = new SortedList>(); foreach (var row in data) { if (!SortedFactorFileData.TryGetValue(row.Date, out var factorFileRows)) { SortedFactorFileData[row.Date] = factorFileRows = new List(); } factorFileRows.Add(row); } ReversedFactorFileDates = new List(SortedFactorFileData.Count); foreach (var time in SortedFactorFileData.Keys.Reverse()) { ReversedFactorFileDates.Add(time); } FactorFileMinimumDate = factorFileMinimumDate; } /// /// Gets the price scale factor for the specified search date /// public abstract decimal GetPriceFactor( DateTime searchDate, DataNormalizationMode dataNormalizationMode, DataMappingMode? dataMappingMode = null, uint contractOffset = 0 ); /// /// Writes this factor file data to an enumerable of csv lines /// /// An enumerable of lines representing this factor file public IEnumerable GetFileFormat() { return SortedFactorFileData.SelectMany(kvp => kvp.Value.Select(row => row.GetFileFormat())); } /// /// Write the factor file to the correct place in the default Data folder /// /// The symbol this factor file represents public void WriteToFile(Symbol symbol) { var filePath = LeanData.GenerateRelativeFactorFilePath(symbol); File.WriteAllLines(filePath, GetFileFormat()); } /// Returns an enumerator that iterates through the collection. /// A that can be used to iterate through the collection. /// 1 public IEnumerator GetEnumerator() { foreach (var kvp in SortedFactorFileData) { foreach (var factorRow in kvp.Value) { yield return factorRow; } } } /// Returns an enumerator that iterates through a collection. /// An object that can be used to iterate through the collection. /// 2 IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } } }