コード例 #1
0
        /// <summary>
        /// Get the contract for the historical data request for a specified start date
        /// </summary>
        /// <param name="startDate"></param>
        ///
        /// <returns></returns>
        private Contract GetCurrentContract(DateTime startDate)
        {
            Contract contract;

            if (TickerData.SymbolParts.IsContinuous)
            {
                string exStr = startDate.ToString("yyyyMMdd");
                int    i     = 0;
                for (; i < TickerData.contractDetailsList.Count - 1; i++)
                {
                    if (TickerData.contractDetailsList[i].Contract.LastTradeDateOrContractMonth.CompareTo(exStr) >= 0)
                    {
                        break;
                    }
                }

                contract = TickerData.contractDetailsList[i].Contract;
            }
            else
            {
                contract = TickerData.ContractDetails.Contract;
            }

            contract.IncludeExpired = IBClientHelper.IsContractExpired(contract);

            // TODO: Do we need it? Does not hurt...
            if (string.IsNullOrEmpty(contract.LocalSymbol))
            {
                LogAndMessage.Log(MessageType.Trace, "No valid security for continuous contract.");
                return(null);
            }

            return(contract);
        }
コード例 #2
0
        /// <summary>
        /// Writes an error message sent by TWS to the log file and queues it for the plugin notification area
        /// </summary>
        /// <param name="tickerData"></param>
        /// <param name="context"></param>
        /// <param name="e"></param>
        internal static void LogAndQueue(TickerData tickerData, string context, int id, int errorCode, string errorMsg)
        {
            MessageType messageType = IBClientHelper.GetMessageType(errorCode);

            if (IsLoggable(messageType))
            {
                LogMessage(messageType, GetTwsMessageForLog(tickerData, context, id, errorCode, errorMsg));
                QueueMessage(messageType, GetTwsMessageForUser(tickerData, context, id, errorCode, errorMsg));
            }
        }
コード例 #3
0
        /// <summary>
        /// Writes a message sent by TWS to the log file
        /// </summary>
        /// <param name="tickerData"></param>
        /// <param name="context"></param>
        /// <param name="e"></param>
        internal static void Log(TickerData tickerData, string context, int id, int errorCode, string errorMsg)
        {
            MessageType messageType = IBClientHelper.GetMessageType(errorCode);

            if (IsLoggable(messageType))
            {
                string message = GetTwsMessageForLog(tickerData, context, id, errorCode, errorMsg);

                LogMessage(messageType, message);
            }
        }
コード例 #4
0
        internal bool IsFinished;                       // Response/Timeout/Error closed this request

        internal Request(TickerData tickerData)
        {
            if (tickerData == null)
            {
                throw new ArgumentNullException();
            }

            Id = IBClientHelper.GetNextReqId(); // this Id is used (instead of collections key) in case of HistoricalDataRequest and HeadTimestampRequest
                                                // because the same logical request may result in more actual request (e.g timeouts and multiple download periods)
            TickerData      = tickerData;
            IsFinished      = false;
            RequestTimeouts = 0;
        }
コード例 #5
0
        private void SendBackfillRequest(FTController ibController)
        {
            if (downloadContract != null
                // && (string.IsNullOrEmpty(contract.LastTradeDateOrContractMonth) || histStart.ToString("yyyyMMdd").CompareTo(contract.LastTradeDateOrContractMonth) <= 0)
                && (downloadStep > 24 * 60 || IBClientHelper.IsBankingHour(downloadStart) || IBClientHelper.IsBankingHour(downloadEnd))) //check if we need to queue a requests
            {
                //try to avoid intraday request for saturday-sunday
                Id = IBClientHelper.GetNextReqId();

                // add quotelist of subcontracts of continuous contract
                if (TickerData.SymbolParts.IsContinuous)
                {
                    if (!TickerData.ContinuousQuotesDictionary.ContainsKey(downloadContract.LocalSymbol))
                    {
                        TickerData.ContinuousQuotesDictionary.Add(downloadContract.LocalSymbol, new QuotationList(FTDataSource.Periodicity));
                    }
                }

                if (downloadPeriodicity <= Periodicity.FifteenSeconds)      // download step is smaller than a day
                {
                    LogAndMessage.LogAndQueue(MessageType.Info, TickerData.ToString(downloadContract) + ": Requesting data from " + downloadStart.ToShortDateString() + " " + downloadStart.ToShortTimeString() + " to " + downloadEnd.ToShortDateString() + " " + downloadEnd.ToShortTimeString() + " " + ToString(false, LogAndMessage.VerboseLog));
                }
                else
                {
                    LogAndMessage.LogAndQueue(MessageType.Info, TickerData.ToString(downloadContract) + ": Requesting data from " + downloadStart.ToShortDateString() + " to " + downloadEnd.ToShortDateString() + " " + ToString(false, LogAndMessage.VerboseLog));
                }

                WaitingForResponse = true;
                RequestTime        = DateTime.Now;

                ibController.SendHistoricalDataRequest(Id, downloadContract, downloadEnd, downloadStart, downloadPeriodicity, TickerData.SymbolParts.DataType);
            }
            else
            {
                // calc next download period
                if (CalcNextBackfillRequest())
                {
                    SendBackfillRequest(ibController);
                }
            }
        }
コード例 #6
0
        private bool CalcNextBackfillRequest()
        {
            downloadStart = downloadStart.AddMinutes(downloadStep);

            // if contiguous contract is being backfilled
            if (TickerData.SymbolParts.IsContinuous)
            {
                DateTime currExp = IBClientHelper.GetContractExpiryDateTime(downloadContract);

                if (currExp < downloadStart)
                {
                    downloadContract = GetCurrentContract(currExp.AddDays(1));
                    downloadStart    = currExp.AddMinutes(-downloadStep);
                    downloadStart    = IBClientHelper.GetAdjustedStartDate(downloadStart, downloadPeriodicity, GetEarliestDownloadDate(), true);
                }
            }

            // if no more to download
            if (downloadPeriodicity < Periodicity.EndOfDay && downloadStart > DateTime.Now ||
                downloadPeriodicity == Periodicity.EndOfDay && downloadStart.Date >= DateTime.Now.Date)
            {
                if (TickerData.QuoteDataStatus == QuotationStatus.DownloadingIntra)
                {
                    TickerData.QuoteDataStatus = QuotationStatus.DownloadedIntra;
                }
                if (TickerData.QuoteDataStatus == QuotationStatus.DownloadingEod)
                {
                    TickerData.QuoteDataStatus = QuotationStatus.DownloadedEod;
                }

                return(false);
            }

            // set the end of the download period
            downloadEnd = downloadStart.AddMinutes(downloadInterval);

            // indicate that more request is needed
            return(true);
        }
コード例 #7
0
        private void mBackfill_Click(object sender, EventArgs e)
        {
            if (firstGetQuotesExCall)                   // db periodicity not known yet
            {
                return;
            }

            if (string.IsNullOrEmpty(currentTicker))    // no selected ticker
            {
                return;
            }

            DateTime refreshStartDate = GetRefreshStartDate(sender);

            refreshStartDate = IBClientHelper.GetAdjustedStartDate(refreshStartDate, Periodicity, DateTime.MinValue, false);

            LogAndMessage.Log(MessageType.Info, currentTicker + ": Manual backfill from " + refreshStartDate.ToShortDateString() + ".");

            StringCollection tickerToBackfill = new StringCollection();

            tickerToBackfill.Add(currentTicker);

            StartBackfills(refreshStartDate, tickerToBackfill);
        }
コード例 #8
0
        internal override bool Process(FTController ibController, bool allowNewRequest)
        {
            const int requestTimeoutPeriod = 20;

            // if no contract received yet
            if (TickerData.ContractStatus == ContractStatus.SendRequest || TickerData.ContractStatus == ContractStatus.WaitForResponse)
            {
                return(allowNewRequest);
            }

            // if no contract found
            if (TickerData.ContractStatus != ContractStatus.Ok)
            {
                TickerData.HeadTimestampStatus = HeadTimestampStatus.Failed;
                IsFinished = true;
                return(allowNewRequest);
            }

            lock (TickerData)  // request handling
            {
                // if not waiting for response
                switch (TickerData.HeadTimestampStatus)
                {
                // if marked to get headtimestamp
                case HeadTimestampStatus.SendRequest:

                    if (allowNewRequest)
                    {
                        LogAndMessage.Log(TickerData, MessageType.Trace, "Requesting earliest data point. " + ToString(false, LogAndMessage.VerboseLog));

                        TickerData.HeadTimestampStatus = HeadTimestampStatus.WaitForResponse;
                        RequestTime = DateTime.Now;

                        ibController.SendHeadTimestampRequest(Id, TickerData);
                    }

                    return(false);

                // if request is sent, but response has not arrived yet
                // see ibClient_HeadTimestamp event handler
                case HeadTimestampStatus.WaitForResponse:

                    // if no answer in time
                    if (RequestTime.AddSeconds(requestTimeoutPeriod) < DateTime.Now)
                    {
                        if (RequestTimeouts == 0)
                        {
                            LogAndMessage.LogAndQueue(TickerData, MessageType.Error, "Request of earliest data point timed out. Retrying. " + ToString(true, LogAndMessage.VerboseLog));

                            RequestTimeouts++;
                            TickerData.HeadTimestampStatus = HeadTimestampStatus.SendRequest;
                            Id = IBClientHelper.GetNextReqId();
                            goto case HeadTimestampStatus.SendRequest;
                        }

                        LogAndMessage.LogAndQueue(TickerData, MessageType.Error, "Request of earliest data point timed out. " + ToString(true, LogAndMessage.VerboseLog));

                        TickerData.HeadTimestampStatus = HeadTimestampStatus.Failed;

                        goto case HeadTimestampStatus.Failed;
                    }

                    return(allowNewRequest);

                // if new, offline ticker
                case HeadTimestampStatus.Offline:
                // ticker's HeadTimestamp is updated
                case HeadTimestampStatus.Ok:
                // ticker's HeadTimestamp is NOT updated (we do not mark ticker as failed. it still may work!)
                case HeadTimestampStatus.Failed:

                    IsFinished = true;
                    return(allowNewRequest);

                // this is program error
                default:

                    TickerData.HeadTimestampStatus = HeadTimestampStatus.Failed;
                    IsFinished = true;
                    return(allowNewRequest);
                }
            }
        }
コード例 #9
0
        private void mBackfillAll_Click(object sender, EventArgs e)
        {
            if (firstGetQuotesExCall)                   // db periodicity not known yet
            {
                return;
            }

            if (string.IsNullOrEmpty(currentTicker))    // no selected ticker
            {
                return;
            }

            DateTime refreshStartDate = GetRefreshStartDate(sender);

            refreshStartDate = IBClientHelper.GetAdjustedStartDate(refreshStartDate, Periodicity, DateTime.MinValue, false);

            //
            // collecting all tickers
            //

            int stockCount = 0;
            StringCollection tickersInDatabase = new StringCollection();

            LogAndMessage.Log(MessageType.Info, "Manual backfill of all tickers from " + refreshStartDate.ToShortDateString() + ".");

            try
            {
                Type   abAppType = Type.GetTypeFromProgID("Broker.Application");
                object abApp     = Activator.CreateInstance(abAppType);

                // access AB COM interface to get current ticker
                if (abAppType != null && abApp != null)
                {
                    object abStocks     = abAppType.InvokeMember("Stocks", BindingFlags.GetProperty, null, abApp, null);
                    Type   abStocksType = abStocks.GetType();

                    // get the number of stocks in the db
                    stockCount = (int)abStocksType.InvokeMember("Count", BindingFlags.GetProperty, null, abStocks, null);

                    if (stockCount > 0)
                    {
                        Type abStockType = abStocksType.InvokeMember("Item", BindingFlags.GetProperty, null, abStocks, new object[] { 0 }).GetType();

                        for (int i = 0; i < stockCount; i++)
                        {
                            object abStock = abStocksType.InvokeMember("Item", BindingFlags.GetProperty, null, abStocks, new object[] { i });
                            if (abStock != null)
                            {
                                string ticker = (string)abStockType.InvokeMember("Ticker", BindingFlags.GetProperty, null, abStock, null);
                                if (!tickersInDatabase.Contains(ticker))
                                {
                                    tickersInDatabase.Add(ticker);
                                }
                            }
                        }
                    }
                    else
                    {
                        LogAndMessage.Log(MessageType.Trace, "Manual backfill of all symbols failed. Database has no symbols.");
                    }
                }
                else
                {
                    LogAndMessage.Log(MessageType.Warning, "Manual backfill of all symbols failed. ActiveX interface error.");
                }
            }
            catch (Exception ex)
            {
                LogAndMessage.LogAndQueue(MessageType.Error, "Manual backfill of all symbols failed. Exception: " + ex);
            }

            StartBackfills(refreshStartDate, tickersInDatabase);
        }
コード例 #10
0
        private void mBackfillWL_Click(object sender, EventArgs e)
        {
            if (firstGetQuotesExCall)                   // db periodicity not known yet
            {
                return;
            }

            if (string.IsNullOrEmpty(currentTicker))    // no selected ticker
            {
                return;
            }

            DateTime refreshStartDate = GetRefreshStartDate(sender);

            refreshStartDate = IBClientHelper.GetAdjustedStartDate(refreshStartDate, Periodicity, DateTime.MinValue, false);

            WatchlistForm watchlistForm = new WatchlistForm(DatabasePath);

            if (DialogResult.OK != watchlistForm.ShowDialog() || watchlistForm.SelectedWatchlistIndices == null)
            {
                return;
            }

            int[] selectedWatchlistIndices = watchlistForm.SelectedWatchlistIndices;

            watchlistForm.Dispose();

            StringCollection tickersInWatchlists = new StringCollection();

            ulong watchlistBits = 0;

            foreach (int watchlistId in selectedWatchlistIndices)
            {
                watchlistBits |= (ulong)1 << watchlistId;
            }

            LogAndMessage.Log(MessageType.Info, "Manual backfill of watchlists (" + watchlistBits.ToString("0x") + ") from " + refreshStartDate.ToShortDateString() + ".");

            try
            {
                Type   abAppType = Type.GetTypeFromProgID("Broker.Application");
                object abApp     = Activator.CreateInstance(abAppType);

                // access AB COM interface to get current ticker
                if (abAppType != null && abApp != null)
                {
                    object abStocks     = abAppType.InvokeMember("Stocks", BindingFlags.GetProperty, null, abApp, null);
                    Type   abStocksType = abStocks.GetType();

                    // get the number of stocks in the db
                    int stockCount = (int)abStocksType.InvokeMember("Count", BindingFlags.GetProperty, null, abStocks, null);

                    if (stockCount > 0)
                    {
                        Type abStockType = abStocksType.InvokeMember("Item", BindingFlags.GetProperty, null, abStocks, new object[] { 0 }).GetType();

                        for (int i = 0; i < stockCount; i++)
                        {
                            object abStock = abStocksType.InvokeMember("Item", BindingFlags.GetProperty, null, abStocks, new object[] { i });
                            if (abStock != null)
                            {
                                string ticker                = (string)abStockType.InvokeMember("Ticker", BindingFlags.GetProperty, null, abStock, null);
                                uint   watchlistBits1        = (uint)(int)abStockType.InvokeMember("WatchListBits", BindingFlags.GetProperty, null, abStock, null);
                                uint   watchlistBits2        = (uint)(int)abStockType.InvokeMember("WatchListBits2", BindingFlags.GetProperty, null, abStock, null);
                                ulong  watchlistBitsCombined = (watchlistBits2 << 32) + watchlistBits1;

                                if ((watchlistBitsCombined & watchlistBits) != 0)
                                {
                                    if (!tickersInWatchlists.Contains(ticker))
                                    {
                                        tickersInWatchlists.Add(ticker);
                                    }
                                }
                            }
                        }
                    }
                    else
                    {
                        LogAndMessage.Log(MessageType.Trace, "Manual backfill of watchlists failed. Database has no symbols.");
                    }
                }
                else
                {
                    LogAndMessage.Log(MessageType.Warning, "Manual backfill of watchlists failed. ActiveX interface error.");
                }
            }
            catch (Exception ex)
            {
                LogAndMessage.LogAndQueue(MessageType.Error, "Manual backfill of watchlists failed. Exception: " + ex);
            }

            if (tickersInWatchlists.Count == 0)
            {
                LogAndMessage.Log(MessageType.Trace, "Manual backfill of watchlists failed. Selected watchlists have no symbols.");
            }
            else
            {
                StartBackfills(refreshStartDate, tickersInWatchlists);
            }
        }
コード例 #11
0
        private void StartBackfills(DateTime refreshStartDate, StringCollection tickersToBackfill)
        {
            if (tickersToBackfill.Count == 0)
            {
                return;
            }

            //
            // checking if long download is accepted
            //

            int      stepSize   = IBClientHelper.GetDownloadStep(Periodicity);
            TimeSpan ts         = DateTime.Now.Subtract(refreshStartDate);
            int      requestsNo = (int)Math.Ceiling(ts.TotalMinutes / stepSize * tickersToBackfill.Count);

            // if mixed database, add number of EOD requests
            requestsNo = (Periodicity != Periodicity.EndOfDay && Workspace.AllowMixedEODIntra != 0) ? requestsNo + tickersToBackfill.Count : requestsNo;

            //
            // checking if database can accomodate the data
            //

            // quoteNum is aproximate value
            int quoteNum = (int)(ts.TotalSeconds / (int)Periodicity);       // total number of bars if traded 24 hours

            if (Periodicity != Periodicity.EndOfDay)
            {
                if (IBConfiguration.RthOnly)
                {
                    quoteNum /= 3;
                }
            }

            //
            // building and showing warning
            //

            bool tooManyRequest = requestsNo > 3;
            bool tooManyQuotes  = quoteNum / 1.2 > Workspace.NumBars;

            if (tooManyRequest || tooManyQuotes)
            {
                TimeSpan mts = new TimeSpan(0, 0, requestsNo * 10);

                StringBuilder msg = new StringBuilder(500);

                msg.Append("The requested data refresh");

                if (tooManyRequest)
                {
                    msg.Append(" may download more bar data (~");
                    msg.Append((quoteNum / 1.2).ToString("N0"));
                    msg.Append(") than your database can accomodate (");
                    msg.Append(Workspace.NumBars.ToString());
                    msg.Append(")");
                }
                if (tooManyRequest)
                {
                    if (tooManyRequest)
                    {
                        msg.Append(" and it");
                    }

                    msg.Append(" may start a long data download operation (~");
                    msg.Append(mts);
                    msg.Append(")");
                }

                msg.AppendLine(".");
                msg.AppendLine("Do you still want it?");

                if (MessageBox.Show(msg.ToString(),
                                    "Warning", MessageBoxButtons.YesNo, MessageBoxIcon.Warning) == DialogResult.No)
                {
                    return;
                }
            }

            //
            // start backfills of selected length
            //

            foreach (var ticker in tickersToBackfill)
            {
                if (!controller.RefreshTicker(ticker, refreshStartDate))
                {
                    LogAndMessage.LogAndQueue(MessageType.Warning, ticker + ": Cannot start manual backfill because ticker is being backfilled.");
                }
            }
        }
コード例 #12
0
        internal override bool Process(FTController ibController, bool allowNewRequest)
        {
            int requestTimeoutPeriod = 75;

            // if contract of the ticker is still being retrieved or headtimestamp of the ticker is needed (not Offline) AND not yet retrieved
            if (TickerData.ContractStatus <= ContractStatus.WaitForResponse ||
                ((FTDataSource.Periodicity == Periodicity.EndOfDay || FTDataSource.AllowMixedEODIntra) && TickerData.HeadTimestampStatus <= HeadTimestampStatus.WaitForResponse))
            {
                return(allowNewRequest);
            }

            if (TickerData.ContractStatus == ContractStatus.Failed || TickerData.ContractStatus == ContractStatus.Offline ||
                TickerData.HeadTimestampStatus == HeadTimestampStatus.Failed || (TickerData.HeadTimestampStatus == HeadTimestampStatus.Offline && (FTDataSource.Periodicity == Periodicity.EndOfDay || FTDataSource.AllowMixedEODIntra)))
            {
                TickerData.QuoteDataStatus = QuotationStatus.Failed;

                IsFinished = true;
                return(allowNewRequest);
            }

            lock (TickerData)   // request handling
            {
                // if reqHistoricalData is send to IB and we are waiting for answer
                if (WaitingForResponse)
                {
                    // request is not yet timed out...
                    if (RequestTime.AddSeconds(requestTimeoutPeriod) > DateTime.Now)
                    {
                        return(allowNewRequest);
                    }

                    // no response arrived in time, request is timed out...
                    LogAndMessage.LogAndQueue(TickerData, MessageType.Info, "Historical data request has timed out. " + ToString(true, LogAndMessage.VerboseLog));

                    RequestTimeouts++;
                    WaitingForResponse = false;

                    // if there were too many reqHistoricalData timeouts
                    if (RequestTimeouts > 2)
                    {
                        // drop this ticker...
                        TickerData.QuoteDataStatus = QuotationStatus.Failed;

                        IsFinished = true;
                        return(allowNewRequest);
                    }
                }

                // if no new request can be sent (request pacing)
                bool histThrottling = !allowNewRequest || TickerData.QuoteDataStatus > QuotationStatus.New && RequestTime.AddSeconds(6.5) > DateTime.Now;

                // process the ticker depending on its state
                switch (TickerData.QuoteDataStatus)
                {
                case QuotationStatus.Offline:

                    LogAndMessage.Log(MessageType.Error, "Program error. Offline ticker cannot get historical update.");

                    IsFinished = true;
                    return(allowNewRequest);

                // All historical data requests are processed for the ticker
                // (the last CalcNextHistoricalDataRequest call sets this state)
                case QuotationStatus.DownloadedEod:

                    #region Merging and backadjusting downloaded quotes of different contracts/expiry into a simgle QuotationList of the continuous contract

                    if (TickerData.SymbolParts.IsContinuous)
                    {
                        QuotationList mergedQuotes = new QuotationList(FTDataSource.Periodicity);

                        int newQuoteIndex;

                        foreach (ContractDetails cd in TickerData.contractDetailsList)
                        {
                            // if there were no quotes receiced for this contract...
                            if (!TickerData.ContinuousQuotesDictionary.ContainsKey(cd.Contract.LocalSymbol))
                            {
                                continue;
                            }

                            newQuoteIndex = 0;

                            if (mergedQuotes.Count > 0)
                            {
                                int     mergedQuoteIndex    = mergedQuotes.Count - 1;
                                AmiDate mergedQuoteDateTime = mergedQuotes[mergedQuoteIndex].DateTime;

                                // move forward to the first quote not overlqapping with prev contract
                                while (newQuoteIndex < TickerData.ContinuousQuotesDictionary[cd.Contract.LocalSymbol].Count - 1 && TickerData.ContinuousQuotesDictionary[cd.Contract.LocalSymbol][newQuoteIndex].DateTime.Date < mergedQuoteDateTime.Date)
                                {
                                    newQuoteIndex++;
                                }

                                // at this point newQuoteIndex points to a quote of the "same" date as mergedQuoteDateTime (if there are quotes for the same day, if not, then the next day)

                                // if daily database then we look for a day where volume on older contract is greater (switch over day)
                                if (FTDataSource.Periodicity == Periodicity.EndOfDay)
                                {
                                    // find the quote that has a lower volume
                                    while (newQuoteIndex > 0 && mergedQuoteIndex > 0 &&
                                           TickerData.ContinuousQuotesDictionary[cd.Contract.LocalSymbol][newQuoteIndex].DateTime.Date == mergedQuotes[mergedQuoteIndex].DateTime.Date &&        // quotes are of same date
                                           TickerData.ContinuousQuotesDictionary[cd.Contract.LocalSymbol][newQuoteIndex].Volume > mergedQuotes[mergedQuoteIndex].Volume)                         // new contract's volume is higher then old contract's volume
                                    {
                                        newQuoteIndex--;
                                        mergedQuoteIndex--;
                                    }
                                    // at this point newQuoteIndex and lastQuoteDateTime point to quote at which contract is replaced
                                }

                                if (TickerData.ContinuousQuotesDictionary[cd.Contract.LocalSymbol][newQuoteIndex].DateTime.Date != mergedQuotes[mergedQuoteIndex].DateTime.Date)
                                {
                                    LogAndMessage.Log(MessageType.Info, TickerData.ToString(cd.Contract) + ": No overlapping quote found. Used dates to change contracts: " + mergedQuotes[mergedQuoteIndex].DateTime + " and " + TickerData.ContinuousQuotesDictionary[cd.Contract.LocalSymbol][newQuoteIndex].DateTime + ".");
                                }
                                else
                                {
                                    LogAndMessage.Log(MessageType.Info, TickerData.ToString(cd.Contract) + ": Switching to new contract on " + mergedQuotes[mergedQuoteIndex].DateTime + ".");
                                }

                                // get "closing prices" of the contract on the same day
                                float  closeOfNewer = TickerData.ContinuousQuotesDictionary[cd.Contract.LocalSymbol][newQuoteIndex].Price;
                                float  closeOfOlder = mergedQuotes[mergedQuoteIndex].Price;
                                double priceMult    = closeOfNewer / closeOfOlder;

                                // back-adjust prev contracts' prices
                                QuotationList tempList = new QuotationList(FTDataSource.Periodicity);
                                for (int i = 0; i < mergedQuoteIndex; i++)
                                {
                                    Quotation quote = mergedQuotes[i];
                                    quote.Open  = (float)(quote.Open * priceMult);
                                    quote.High  = (float)(quote.High * priceMult);
                                    quote.Low   = (float)(quote.Low * priceMult);
                                    quote.Price = (float)(quote.Price * priceMult);
                                    tempList.Merge(quote);
                                }
                                mergedQuotes.Clear();
                                mergedQuotes = tempList;
                            }

                            // add quotes of newer contract
                            for (; newQuoteIndex < TickerData.ContinuousQuotesDictionary[cd.Contract.LocalSymbol].Count; newQuoteIndex++)
                            {
                                mergedQuotes.Merge(TickerData.ContinuousQuotesDictionary[cd.Contract.LocalSymbol][newQuoteIndex]);
                            }
                        }

                        TickerData.Quotes = mergedQuotes;
                    }

                    #endregion

                    // this is not THROTTLED, but counted in general throttling queue
                    ibController.SendSubscriptionRequest(0, TickerData, false);

                    TickerData.QuoteDataStatus = QuotationStatus.Online;

                    return(allowNewRequest);

                // this should never happen (ticker with online status should not be in the queue...)
                case QuotationStatus.Online:

                    LogAndMessage.LogAndQueue(TickerData, MessageType.Info, "Backfill finished, symbol is ready. ");

                    IsFinished = true;
                    return(allowNewRequest);

                // if any error happend
                case QuotationStatus.Failed:

                    // if intraday download received no data response
                    if (errorCode == 162 && FTDataSource.Periodicity < Periodicity.EndOfDay && FTDataSource.Periodicity > Periodicity.FifteenSeconds)
                    {
                        errorCode = 0;

                        // move forward 4 periods to speed up download/find first valid period with available data
                        CalcNextBackfillRequest();
                        CalcNextBackfillRequest();
                        CalcNextBackfillRequest();
                        LogAndMessage.Log(TickerData, MessageType.Trace, "No data returned, fast forward download period.");

                        // start next download
                        TickerData.QuoteDataStatus = QuotationStatus.DownloadingIntra;

                        return(allowNewRequest);
                    }
                    else
                    {
                        LogAndMessage.LogAndQueue(TickerData, MessageType.Info, "Backfill failed, symbol is offline.");

                        IsFinished = true;
                        return(allowNewRequest);
                    }

                // start historical data refresh
                case QuotationStatus.New:

                    if (histThrottling)
                    {
                        return(false);
                    }

                    // calc download properties
                    downloadPeriodicity = FTDataSource.Periodicity;
                    downloadStep        = IBClientHelper.GetDownloadStep(FTDataSource.Periodicity);
                    downloadInterval    = IBClientHelper.GetDownloadInterval(FTDataSource.Periodicity);
                    downloadStart       = IBClientHelper.GetAdjustedStartDate(TickerData.RefreshStartDate, FTDataSource.Periodicity, GetEarliestDownloadDate(), true);
                    downloadEnd         = downloadStart.AddMinutes(downloadInterval);
                    downloadContract    = GetCurrentContract(downloadStart);

                    // remove quotes already stored
                    TickerData.Quotes.Clear();

                    // set next state
                    if (FTDataSource.Periodicity == Periodicity.EndOfDay)
                    {
                        TickerData.QuoteDataStatus = QuotationStatus.DownloadingEod;
                    }
                    else
                    {
                        TickerData.QuoteDataStatus = QuotationStatus.DownloadingIntra;
                    }

                    // not to wait to send next request
                    RequestTime = DateTime.MinValue;

                    // download historical data
                    SendBackfillRequest(ibController);

                    return(false);

                case QuotationStatus.DownloadingEod:
                case QuotationStatus.DownloadingIntra:

                    if (histThrottling)
                    {
                        return(false);
                    }

                    // if previous request timed out
                    if (RequestTimeouts != 0)
                    {
                        SendBackfillRequest(ibController);
                    }

                    // download historical data
                    else if (CalcNextBackfillRequest())
                    {
                        SendBackfillRequest(ibController);
                    }

                    return(false);

                // last CalcNextHistoricalDataRequest call for intraday bars should have set this state
                case QuotationStatus.DownloadedIntra:

                    // if we need EOD data as well
                    if (FTDataSource.AllowMixedEODIntra)
                    {
                        if (histThrottling)
                        {
                            return(false);
                        }

                        // calc download properties for EOD
                        downloadPeriodicity = Periodicity.EndOfDay;
                        downloadStep        = IBClientHelper.GetDownloadStep(Periodicity.EndOfDay);
                        downloadInterval    = IBClientHelper.GetDownloadInterval(Periodicity.EndOfDay);
                        downloadStart       = IBClientHelper.GetAdjustedStartDate(TickerData.RefreshStartDate, Periodicity.EndOfDay, GetEarliestDownloadDate(), true);
                        downloadEnd         = downloadStart.AddMinutes(downloadInterval);
                        downloadContract    = GetCurrentContract(downloadStart);

                        SendBackfillRequest(ibController);

                        TickerData.QuoteDataStatus = QuotationStatus.DownloadingEod;
                    }
                    else
                    {
                        TickerData.QuoteDataStatus = QuotationStatus.DownloadedEod;
                    }

                    return(false);

                default:

                    LogAndMessage.LogAndQueue(TickerData, MessageType.Info, "Program error in backfill logic.");

                    IsFinished = true;
                    return(true);
                }
            }
        }