/* * 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 { /// /// Provides a means of mapping a symbol at a point in time to the map file /// containing that share class's mapping information /// public class MapFileResolver : IEnumerable { private readonly Dictionary _mapFilesByPermtick; private readonly Dictionary> _bySymbol; /// /// Gets an empty , that is an instance that contains /// zero mappings /// public static readonly MapFileResolver Empty = new MapFileResolver(Enumerable.Empty()); /// /// Initializes a new instance of the by reading /// in all files in the specified directory. /// /// The data used to initialize this resolver. public MapFileResolver(IEnumerable mapFiles) { _mapFilesByPermtick = new Dictionary(StringComparer.InvariantCultureIgnoreCase); _bySymbol = new Dictionary>(StringComparer.InvariantCultureIgnoreCase); foreach (var mapFile in mapFiles) { // add to our by path map _mapFilesByPermtick.Add(mapFile.Permtick, mapFile); foreach (var row in mapFile) { SortedList entries; var mapFileRowEntry = new MapFileRowEntry(mapFile.Permtick, row); if (!_bySymbol.TryGetValue(row.MappedSymbol, out entries)) { entries = new SortedList(); _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); } } } } /// /// Gets the map file matching the specified permtick /// /// The permtick to match on /// The map file matching the permtick, or null if not found public MapFile GetByPermtick(string permtick) { MapFile mapFile; _mapFilesByPermtick.TryGetValue(permtick.LazyToUpper(), out mapFile); return mapFile; } /// /// Resolves the map file path containing the mapping information for the symbol defined at /// /// The symbol as of to be mapped /// The date associated with the /// The map file responsible for mapping the symbol, if no map file is found, null is returned public MapFile ResolveMapFile(string symbol, DateTime date) { // lookup the symbol's history SortedList entries; if (_bySymbol.TryGetValue(symbol, out entries)) { if (entries.Count == 0) { return new MapFile(symbol, Enumerable.Empty()); } // Return value of BinarySearch (from MSDN): // The zero-based index of item in the sorted List, 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()); } return mapFile; } /// /// Combines the map file row with the map file path that produced the row /// class MapFileRowEntry : IEquatable { /// /// Gets the map file row /// public MapFileRow MapFileRow { get; private set; } /// /// Gets the full path to the map file that produced this row /// public string EntitySymbol { get; private set; } /// /// Initializes a new instance of the class /// /// The map file that produced this row /// The map file row data public MapFileRowEntry(string entitySymbol, MapFileRow mapFileRow) { MapFileRow = mapFileRow; EntitySymbol = entitySymbol; } /// /// Indicates whether the current object is equal to another object of the same type. /// /// /// true if the current object is equal to the parameter; otherwise, false. /// /// An object to compare with this object. public bool Equals(MapFileRowEntry other) { if (other == null) return false; return other.MapFileRow.Date == MapFileRow.Date && other.MapFileRow.MappedSymbol == MapFileRow.MappedSymbol; } /// /// Returns a string that represents the current object. /// /// /// A string that represents the current object. /// /// 2 public override string ToString() { return MapFileRow.Date + ": " + MapFileRow.MappedSymbol + ": " + EntitySymbol; } } #region Implementation of IEnumerable /// /// Returns an enumerator that iterates through the collection. /// /// /// A that can be used to iterate through the collection. /// /// 1 public IEnumerator GetEnumerator() { return _mapFilesByPermtick.Values.GetEnumerator(); } /// /// 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(); } #endregion } }