/* * 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 { /// /// Tiingo daily price data /// https://api.tiingo.com/docs/tiingo/daily /// /// Requires setting public class TiingoPrice : TradeBar { private readonly ConcurrentDictionary _startDates = new ConcurrentDictionary(); /// /// The end time of this data. Some data covers spans (trade bars) and as such we want /// to know the entire time span covered /// public override DateTime EndTime { get { return Time + Period; } set { Time = value - Period; } } /// /// The period of this trade bar, (second, minute, daily, ect...) /// public override TimeSpan Period => QuantConnect.Time.OneDay; /// /// The date this data pertains to /// [JsonProperty("date")] public DateTime Date { get; set; } /// /// The actual (not adjusted) open price of the asset on the specific date /// [JsonProperty("open")] public override decimal Open { get; set; } /// /// The actual (not adjusted) high price of the asset on the specific date /// [JsonProperty("high")] public override decimal High { get; set; } /// /// The actual (not adjusted) low price of the asset on the specific date /// [JsonProperty("low")] public override decimal Low { get; set; } /// /// The actual (not adjusted) closing price of the asset on the specific date /// [JsonProperty("close")] public override decimal Close { get; set; } /// /// The actual (not adjusted) number of shares traded during the day /// [JsonProperty("volume")] public override decimal Volume { get; set; } /// /// The adjusted opening price of the asset on the specific date. Returns null if not available. /// [JsonProperty("adjOpen")] public decimal AdjustedOpen { get; set; } /// /// The adjusted high price of the asset on the specific date. Returns null if not available. /// [JsonProperty("adjHigh")] public decimal AdjustedHigh { get; set; } /// /// The adjusted low price of the asset on the specific date. Returns null if not available. /// [JsonProperty("adjLow")] public decimal AdjustedLow { get; set; } /// /// The adjusted close price of the asset on the specific date. Returns null if not available. /// [JsonProperty("adjClose")] public decimal AdjustedClose { get; set; } /// /// The adjusted number of shares traded during the day - adjusted for splits. Returns null if not available /// [JsonProperty("adjVolume")] public long AdjustedVolume { get; set; } /// /// The dividend paid out on "date" (note that "date" will be the "exDate" for the dividend) /// [JsonProperty("divCash")] public decimal Dividend { get; set; } /// /// 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 /// [JsonProperty("splitFactor")] public decimal SplitFactor { get; set; } /// /// Initializes an instance of the class. /// public TiingoPrice() { Symbol = Symbol.Empty; DataType = MarketDataType.Base; } /// /// Return the URL string source of the file. This will be converted to a stream /// /// Configuration object /// Date of this source file /// true if we're in live mode, false for backtesting mode /// String URL of source file. 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); } /// /// 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. /// /// Subscription data config setup object /// Content of the source document /// Date of the requested data /// true if we're in live mode, false for backtesting mode /// /// Instance of the T:BaseData object generated by this line of the CSV /// public override BaseData Reader(SubscriptionDataConfig config, string line, DateTime date, bool isLiveMode) { var list = JsonConvert.DeserializeObject>(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); } /// /// Indicates if there is support for mapping /// /// True indicates mapping should be used public override bool RequiresMapping() { return true; } /// /// Specifies the data time zone for this data type. This is useful for custom data types /// /// The of this data type public override DateTimeZone DataTimeZone() { return TimeZones.Utc; } /// /// Gets the default resolution for this data and security type /// public override Resolution DefaultResolution() { return Resolution.Daily; } /// /// Gets the supported resolution for this data and security type /// public override List SupportedResolutions() { return DailyResolution; } } }