/*
* 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;
}
}
}