/// <summary> /// Stream IQFeed TickMessages from disk to Lean Tick /// </summary> /// <param name="filename"></param> /// <param name="request"></param> /// <param name="tickFunc"></param> /// <param name="delete"></param> /// <returns>Converted Tick</returns> private IEnumerable <BaseData> GetDataFromTickMessages(string filename, HistoryRequest request, Func <DateTime, Symbol, TickMessage, Tick> tickFunc, bool delete) { var dataTimeZone = _marketHoursDatabase.GetDataTimeZone(request.Symbol.ID.Market, request.Symbol, request.Symbol.SecurityType); // We need to discard ticks which are not impacting the price, i.e those having BasisForLast = O // To get a better understanding how IQFeed is resampling ticks, have a look to this algorithm: // https://github.com/mathpaquette/IQFeed.CSharpApiClient/blob/1b33250e057dfd6cd77e5ee35fa16aebfc8fbe79/src/IQFeed.CSharpApiClient.Extensions/Lookup/Historical/Resample/TickMessageExtensions.cs#L41 foreach (var tick in TickMessage.ParseFromFile(filename).Where(t => t.BasisForLast != 'O')) { var timestamp = tick.Timestamp.ConvertTo(TimeZones.NewYork, dataTimeZone); yield return(tickFunc(timestamp, request.Symbol, tick)); } if (delete) { File.Delete(filename); } }
/// <summary> /// Stream IQFeed TickMessages from disk to Lean Tick /// </summary> /// <param name="filename"></param> /// <param name="request"></param> /// <param name="isEquity"></param> /// <returns>Converted Tick</returns> private IEnumerable <BaseData> GetDataFromTickMessages(string filename, HistoryRequest request) { var dataTimeZone = _marketHoursDatabase.GetDataTimeZone(request.Symbol.ID.Market, request.Symbol, request.Symbol.SecurityType); // We need to discard ticks which are not impacting the price, i.e those having BasisForLast = O // To get a better understanding how IQFeed is resampling ticks, have a look to this algorithm: // https://github.com/mathpaquette/IQFeed.CSharpApiClient/blob/1b33250e057dfd6cd77e5ee35fa16aebfc8fbe79/src/IQFeed.CSharpApiClient.Extensions/Lookup/Historical/Resample/TickMessageExtensions.cs#L41 foreach (var tick in TickMessage.ParseFromFile(filename).Where(t => t.BasisForLast != 'O')) { var timestamp = tick.Timestamp.ConvertTo(TimeZones.NewYork, dataTimeZone); // trade yield return(new Tick( timestamp, request.Symbol, tick.TradeConditions, tick.TradeMarketCenter.ToStringInvariant(), tick.LastSize, (decimal)tick.Last )); // quote yield return(new Tick( timestamp, request.Symbol, tick.TradeConditions, tick.TradeMarketCenter.ToStringInvariant(), 0, // not provided by IQFeed on history (decimal)tick.Bid, 0, // not provided by IQFeed on history (decimal)tick.Ask )); } File.Delete(filename); }
/// <summary> /// Get the last known price using the history provider. /// Useful for seeding securities with the correct price /// </summary> /// <param name="security"><see cref="Security"/> object for which to retrieve historical data</param> /// <returns>A single <see cref="BaseData"/> object with the last known price</returns> public BaseData GetLastKnownPrice(Security security) { if (security.Symbol.IsCanonical() || HistoryProvider == null) { return(null); } var configs = SubscriptionManager.SubscriptionDataConfigService .GetSubscriptionDataConfigs(security.Symbol); var dataTimeZone = MarketHoursDatabase .GetDataTimeZone(security.Symbol.ID.Market, security.Symbol, security.Symbol.SecurityType); // For speed and memory usage, use Resolution.Minute as the minimum resolution var resolution = (Resolution)Math.Max((int)Resolution.Minute, (int)configs.GetHighestResolution()); var isExtendedMarketHours = configs.IsExtendedMarketHours(); // request QuoteBar for Options and Futures var dataType = typeof(BaseData); if (security.Type == SecurityType.Option || security.Type == SecurityType.Future) { dataType = LeanData.GetDataType(resolution, TickType.Quote); } // Get the config with the largest resolution var subscriptionDataConfig = GetMatchingSubscription(security.Symbol, dataType); TickType tickType; if (subscriptionDataConfig == null) { dataType = typeof(TradeBar); tickType = LeanData.GetCommonTickTypeForCommonDataTypes(dataType, security.Type); } else { // if subscription resolution is Tick, we also need to update the data type from Tick to TradeBar/QuoteBar if (subscriptionDataConfig.Resolution == Resolution.Tick) { dataType = LeanData.GetDataType(resolution, subscriptionDataConfig.TickType); subscriptionDataConfig = new SubscriptionDataConfig(subscriptionDataConfig, dataType, resolution: resolution); } dataType = subscriptionDataConfig.Type; tickType = subscriptionDataConfig.TickType; } Func <int, BaseData> getLastKnownPriceForPeriods = backwardsPeriods => { var startTimeUtc = _historyRequestFactory .GetStartTimeAlgoTz(security.Symbol, backwardsPeriods, resolution, security.Exchange.Hours, dataTimeZone) .ConvertToUtc(_localTimeKeeper.TimeZone); var request = new HistoryRequest( startTimeUtc, UtcTime, dataType, security.Symbol, resolution, security.Exchange.Hours, dataTimeZone, resolution, isExtendedMarketHours, configs.IsCustomData(), configs.DataNormalizationMode(), tickType ); BaseData result = null; History(new List <HistoryRequest> { request }) .PushThrough(bar => { if (!bar.IsFillForward) { result = bar; } }); return(result); }; var lastKnownPrice = getLastKnownPriceForPeriods(1); if (lastKnownPrice != null) { return(lastKnownPrice); } // If the first attempt to get the last know price returns null, it maybe the case of an illiquid security. // We increase the look-back period for this case accordingly to the resolution to cover 3 trading days var periods = resolution == Resolution.Daily ? 3 : resolution == Resolution.Hour ? 24 : 1440; return(getLastKnownPriceForPeriods(periods)); }