示例#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
        // callback (from controller) to indicate no more contracts
        private void SearchContractReady()
        {
            try
            {
                // limit result list
                if (securityDatas.Count > maxDisplayedContract)
                {
                    securityDatas.RemoveRange(maxDisplayedContract, securityDatas.Count - maxDisplayedContract);
                }

                // InvokeRequired did not always work! May be called back on UI thread as well.
                // However, there can be a lengthy operation to do it on background thread.
                sorting = true;

                if (securityDatas.Count > 1)
                {
                    securityDatas.Sort(new SecurityDataComparer(SecurityDataField.LocalSymbol, SortOrder.Ascending));
                }

                // if window is not shown, we cannot invoke a method through window message loop
                if (IsHandleCreated)
                {
                    BeginInvoke(new MethodInvoker(ShowContracts));
                }
            }
            catch (Exception ex)
            {
                LogAndMessage.Log(MessageType.Error, "Search form could not collect contracts: " + ex);
                MessageBox.Show("Error while retrieving contracts:" + ex, "Search form error", MessageBoxButtons.OK, MessageBoxIcon.Stop);
            }
        }
        internal void HeadTimestampReceived(string headTimestamp)
        {
            DateTime date;
            bool     result = DateTime.TryParseExact(headTimestamp, "yyyyMMdd  HH:mm:ss", CultureInfo.InvariantCulture, DateTimeStyles.None, out date);

            lock (TickerData)  // event handling
            {
                if (result)
                {
                    TickerData.EarliestDataPoint   = date;
                    TickerData.HeadTimestampStatus = HeadTimestampStatus.Ok;
                }
                else
                {
                    TickerData.EarliestDataPoint   = DateTime.MinValue;
                    TickerData.HeadTimestampStatus = HeadTimestampStatus.Failed;
                }
            }

            if (result)
            {
                LogAndMessage.Log(TickerData, MessageType.Info, "Earliest data point value is updated. " + ToString(true, LogAndMessage.VerboseLog));
            }
            else
            {
                LogAndMessage.Log(TickerData, MessageType.Error, "Invalid earliest data point value received: " + headTimestamp + " " + ToString(true, LogAndMessage.VerboseLog));
            }
        }
示例#4
0
        private void buttonAdd_Click(object sender, EventArgs e)
        {
            if (dataGridViewResult.SelectedRows.Count == 0)
            {
                return;
            }

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

                object abStocks   = appType.InvokeMember("Stocks", System.Reflection.BindingFlags.GetProperty, null, abApp, null);
                Type   stocksType = abStocks.GetType();

                for (int i = 0; i < dataGridViewResult.SelectedRows.Count; i++)
                {
                    SecurityData sd = (SecurityData)dataGridViewResult.SelectedRows[i].DataBoundItem;;

                    SymbolParts ibTicker = new SymbolParts(sd.LocalSymbol, sd.Exchange, sd.SecType, sd.Currency, "");

                    object stock = stocksType.InvokeMember("Add", System.Reflection.BindingFlags.InvokeMethod, null,
                                                           abStocks, new object[] { ibTicker.Ticker });
                    if (stock != null)
                    {
                        Type stockType = stock.GetType();
                        stockType.InvokeMember("Alias", System.Reflection.BindingFlags.SetProperty, null, stock,
                                               new object[] { sd.Symbol });
                        stockType.InvokeMember("Currency", System.Reflection.BindingFlags.SetProperty, null, stock,
                                               new object[] { sd.Currency });
                        stockType.InvokeMember("FullName", System.Reflection.BindingFlags.SetProperty, null, stock,
                                               new object[] { sd.LongName });
                        stockType.InvokeMember("PointValue", System.Reflection.BindingFlags.SetProperty, null, stock,
                                               new object[] { sd.PriceMagnifier });
                        stockType.InvokeMember("TickSize", System.Reflection.BindingFlags.SetProperty, null, stock,
                                               new object[] { sd.MinTick });
                        stockType.InvokeMember("WebID", System.Reflection.BindingFlags.SetProperty, null, stock,
                                               new object[] { sd.ContractId });
                    }

                    if (checkBoxAddContinuous.Checked && sd.SecType.ToUpper() == "FUT")
                    {
                        string      localNamePart = sd.LocalSymbol.Substring(0, sd.LocalSymbol.Length - 2);
                        SymbolParts contTicker    = new SymbolParts(localNamePart + "~/" + sd.Symbol, sd.Exchange, sd.SecType, sd.Currency, "");

                        stock = stocksType.InvokeMember("Add", System.Reflection.BindingFlags.InvokeMethod, null,
                                                        abStocks, new object[] { contTicker.Ticker });
                    }
                }
            }
            catch (Exception ex)
            {
                LogAndMessage.Log(MessageType.Error, "Search form could not add tickers: " + ex);
                MessageBox.Show("Error while adding tickers: " + ex, "Search form error", MessageBoxButtons.OK, MessageBoxIcon.Stop);
            }
        }
示例#5
0
        private void mUpdateSymbolInfo_Click(object sender, EventArgs e)
        {
            if (currentSI == null)
            {
                return;
            }

            LogAndMessage.Log(MessageType.Info, currentTicker + ": Symbol info manually updated.");
            controller.UpdateSymbolInfo(currentTicker);
        }
示例#6
0
 private void Listener_MessageReceived(object sender, XDMessageEventArgs e)
 {
     if (e.DataGram.Message == "reconnect")
     {
         LogAndMessage.Log(MessageType.Info, "Reconencting...");
         //manuallyDisconnected = true;
         //if (controller.IsIbConnected)
         controller.Disconnect();
         controller.Connect(false);
     }
 }
示例#7
0
        private void SaveQuote(Quotation quote)
        {
            DateTime quoteDate = (DateTime)quote.DateTime;

            // get the trading day
            //DateTime tradingDay = DateTime.MinValue;
            //tradingDay = tickerData.LiquidHours.GetTradeDate(quoteDate);
            //if (!IBDataSource.RthOnly && tradingDay == DateTime.MinValue)
            //tradingDay = tickerData.TradingDays.GetTradeDate(quoteDate);

            // if no trading day found and RTH only
            //if (tradingDay == DateTime.MinValue)
            //    if (IBDataSource.RthOnly)
            //        return;
            //    else
            //        tradingDay = DateTime.Now.Date;

            DateTime tradingDay = tickerData.TradingDays.GetTradeDate(quoteDate);

            if (tradingDay == DateTime.MinValue)
            {
                tradingDay = DateTime.Now.Date;
            }

            try
            {
                lock (tickerData.Quotes)
                {
                    // Merge quote into last intraday quote in QuotationList
                    if (tickerData.Quotes.Periodicity != Periodicity.EndOfDay)
                    {
                        tickerData.Quotes.Merge(quote);
                    }

                    // Merge quote into last EOD quote in QuotationList
                    if (tickerData.Quotes.Periodicity == Periodicity.EndOfDay || FTDataSource.AllowMixedEODIntra)
                    {
                        tickerData.Quotes.MergeEod(quote, (AmiDate)tradingDay);
                    }
                }
            }
            catch (Exception ex)
            {
                LogAndMessage.Log(tickerData, MessageType.Error, "Error while merging received quote: " + ex);
            }
        }
示例#8
0
        internal virtual bool ProcessQueuedRequests(FTController ibController, bool allowNewRequest, bool writeLog)
        {
            int cntAtStart;
            int cntAtEnd;

            bool savedAllowNewRequest = allowNewRequest;

            lock (requestList)
            {
                cntAtStart = requestList.Count;

                for (int i = cntAtStart - 1; i >= 0; i--)
                {
                    noTimeOuts &= requestList.Values[i].RequestTimeouts == 0;

                    if (requestList.Values[i].IsFinished)
                    {
                        requestList.RemoveAt(i);
                    }
                }

                cntAtEnd = requestList.Count;
            }

            // we must limit the open requests to 5
            for (int i = 0; i < cntAtEnd && i < 5; i++)
            {
                allowNewRequest &= requestList.Values[i].Process(ibController, allowNewRequest);
            }

            if (cntAtEnd == 0)
            {
                noTimeOuts = true;
            }
#if DEBUG
            if (writeLog)
            {
                LogAndMessage.Log(MessageType.Trace, queueName + ": Allow new request: " + (savedAllowNewRequest ? "1" : "0") + "/" + (allowNewRequest ? "1" : "0") + "  Requests: " + cntAtStart.ToString("#0") + "/" + cntAtEnd.ToString("#0"));
            }
#endif
            return(allowNewRequest);
        }
示例#9
0
        /// <summary>
        /// Start processing the list of contract details in the event of ContractDetailsEnd
        /// </summary>
        internal void ContractDetailsReceived(List <ContractDetails> list)
        {
            bool result = false;

            lock (TickerData)   // event handling
            {
                result = ProcessContractDetailsList(list);

                TickerData.ContractStatus = result ? ContractStatus.Ok : ContractStatus.Failed;
            }

            if (result)
            {
                LogAndMessage.Log(TickerData, MessageType.Info, "Contract is updated. " + ToString(true, LogAndMessage.VerboseLog));
            }
            else
            {
                LogAndMessage.Log(TickerData, MessageType.Error, "Failed to update contract. " + ToString(true, LogAndMessage.VerboseLog));
            }
        }
示例#10
0
        public static FTConfiguration GetConfigObject(string config)
        {
            // if no config string, set default values
            if (string.IsNullOrEmpty(config) || config.Trim().Length == 0)
            {
                return(GetDefaultConfigObject());
            }

            try
            {
                XmlSerializer serializer = new XmlSerializer(typeof(FTConfiguration));
                Stream        stream     = new MemoryStream(ASCIIEncoding.Default.GetBytes(config));

                return((FTConfiguration)serializer.Deserialize(stream));
            }
            catch (Exception ex)
            {
                LogAndMessage.Log(MessageType.Error, "Configuration error:" + ex);
                return(GetDefaultConfigObject());
            }
        }
示例#11
0
        internal override bool ProcessQueuedRequests(FTController ibController, bool allowNewRequest, bool writeLog)
        {
            int cntAtStart;
            int cntAtEnd;

            bool savedAllowNewRequest = allowNewRequest;

            //
            // we must limit the open requests to 1
            //

            lock (requestList)
            {
                cntAtStart = requestList.Count;

                if (cntAtStart > 0)
                {
                    if (requestList.Values[0].IsFinished)
                    {
                        requestList.RemoveAt(0);
                    }
                }

                cntAtEnd = requestList.Count;
            }

            if (cntAtEnd > 0)
            {
                allowNewRequest &= requestList.Values[0].Process(ibController, allowNewRequest);
            }

#if DEBUG
            if (writeLog)
            {
                LogAndMessage.Log(MessageType.Trace, queueName + ": Allow new request: " + (savedAllowNewRequest ? "1" : "0") + "/" + (allowNewRequest ? "1" : "0") + "  Requests: " + cntAtStart.ToString("#0") + "/" + cntAtEnd.ToString("#0"));
            }
#endif
            return(allowNewRequest);
        }
示例#12
0
        private void mFindIBContract_Click(object sender, EventArgs e)
        {
            try
            {
                if (searchForm == null)
                {
                    searchForm = new SearchForm(controller);
                }
                searchForm.ShowDialog();

                PostMessage(MainWindowHandle, 0x001C, new IntPtr(1), new IntPtr(0));     // WM_ACTIVATEAPP = 0x001C
                PostMessage(MainWindowHandle, 0x0086, new IntPtr(1), new IntPtr(0));     // WM_NCACTIVATE = 0x0086
                PostMessage(MainWindowHandle, 0x0006, new IntPtr(1), new IntPtr(0));     // WM_ACTIVATE = 0x0006
                PostMessage(MainWindowHandle, 0x36E, new IntPtr(1), new IntPtr(0));      // WM_ACTIVATETOPLEVEL = 0x36E
                PostMessage(MainWindowHandle, 0x2862, new IntPtr(0xb6d), new IntPtr(0)); //WM_USER + 9314
                PostMessage(MainWindowHandle, 0x0111, new IntPtr(0xb6d), new IntPtr(0)); //WM_COMMAND = 0x0111;
            }
            catch (Exception ex)
            {
                LogAndMessage.Log(MessageType.Error, "Error while opening Search window:" + ex);
            }
        }
示例#13
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);
        }
示例#14
0
        internal override bool Process(FTController ibController, bool allowNewRequest)
        {
            // if no contract received yet
            if (TickerData.ContractStatus == ContractStatus.SendRequest || TickerData.ContractStatus == ContractStatus.WaitForResponse)
            {
                return(allowNewRequest);
            }

            // if GetQuotesEx was not yet called (stockInfo is not ready yet), symbol data cannot be updated
            if (TickerData.StockInfo == null)
            {
                IsFinished = true;
                return(allowNewRequest);
            }

            // if not waiting for response
            switch (TickerData.SymbolStatus)
            {
            // if marked to update AB symbol's data
            case SymbolStatus.WaitForContractUpdate:

                // if no contract found
                if (TickerData.ContractStatus != ContractStatus.Ok)
                {
                    LogAndMessage.LogAndQueue(TickerData, MessageType.Error, "Getting contract info failed, AmiBroker symbol data cannot be updated.");

                    TickerData.SymbolStatus = SymbolStatus.Failed;

                    goto case SymbolStatus.Failed;
                }

                // plugin may call it when StockInfo is not available (E.g. start watchlist backfill)
                if (TickerData.StockInfo == null)
                {
                    LogAndMessage.Log(TickerData, MessageType.Trace, "StockInfo data is not available. AmiBroker symbol data is not updated.");
                    return(false);
                }

                try
                {
                    // update AB's information
                    TickerData.StockInfo.AliasName  = TickerData.ContractDetails.Contract.LocalSymbol + '/' + TickerData.ContractDetails.Contract.Symbol;
                    TickerData.StockInfo.FullName   = TickerData.ContractDetails.LongName;
                    TickerData.StockInfo.PointValue = TickerData.ContractDetails.PriceMagnifier;
                    TickerData.StockInfo.TickSize   = (float)TickerData.ContractDetails.MinTick;
                    TickerData.StockInfo.WebId      = TickerData.ContractDetails.Contract.ConId.ToString();
                    TickerData.StockInfo.Currency   = TickerData.ContractDetails.Contract.Currency;

                    TickerData.SymbolStatus = SymbolStatus.Ok;

                    LogAndMessage.LogAndQueue(TickerData, MessageType.Info, "AmiBroker symbol data is updated.");
                }
                catch (Exception ex)
                {
                    TickerData.SymbolStatus = SymbolStatus.Failed;

                    LogAndMessage.LogAndQueue(TickerData, MessageType.Error, "AmiBroker symbol data update failed:" + ex);
                    return(false);
                }

                goto case SymbolStatus.Ok;

            // if new ticker
            case SymbolStatus.Offline:
            // AB symbol's data are updated
            case SymbolStatus.Ok:
            // AB symbol's data NOT updated, e.g: no contract found
            case SymbolStatus.Failed:

                IsFinished = true;
                return(allowNewRequest);

            default:

                TickerData.SymbolStatus = SymbolStatus.Failed;

                IsFinished = true;
                return(allowNewRequest);
            }
        }
示例#15
0
        /// <summary>
        /// Timer event handler
        /// </summary>
        /// <param name="sender"></param>
        /// <remarks>
        /// If connection is broken, it tries to reconnect in every 30 secs.
        /// If it reconnects, it starts a backfill of all tickers
        /// If status is ready and autorefresh is configured, it starts the scheduled refresh
        /// </remarks>
        private void timer_Tick(object sender)
        {
            if (controller == null)
            {
                return;
            }

            // check and indicate thread entry
            if (Interlocked.CompareExchange(ref inTimerTick, 1, 0) != 0)
            {
                return;
            }

            IBPluginState currPluginState = IBPluginState.Disconnected;

            try
            {
                currPluginState = controller.GetIBPluginState();

                if (currPluginState != prevPluginState)
                {
                    LogAndMessage.Log(MessageType.Info, "Plugin status: " + currPluginState);
                }

                // if no connection between the data plugin and the TWS client
                if (currPluginState == IBPluginState.Disconnected)
                {
                    // if not manually disconnected, try to reconnect
                    if (manuallyDisconnected == false)
                    {
                        // if retry period has elapsed
                        if (connectionRetryTime < DateTime.Now)
                        {
                            // if connection has just got broken (prevent repeated log entries)
                            if (prevPluginState != IBPluginState.Disconnected)
                            {
                                LogAndMessage.LogAndQueue(MessageType.Warning, "Data plugin has been disconnected from TWS. Trying to reconnect in every " + ConnectionRetryInterval + " sec.");
                            }

                            // set new retry time and increase interval up to 30 secs
                            connectionRetryTime = DateTime.Now.AddSeconds(ConnectionRetryInterval);

                            // try to reconnect
                            controller.Connect(true);
                        }
                    }
                }

                // data plugin is connected to TWS
                else
                {
                    // reset connection retrying
                    connectionRetryTime = DateTime.MinValue;

                    // if an existing connection  was disconnected
                    if (prevPluginState == IBPluginState.Disconnected && !firstConnection || controller.RestartStreaming)
                    {
                        LogAndMessage.LogAndQueue(MessageType.Warning, "TWS has been reconnected. Starting database refresh.");

                        // request refresh of all tickers, restart subscriptions, etc.
                        controller.RestartAfterReconnect(lastUptodateTime);

                        return;
                    }

                    // clear flag of first connection
                    firstConnection = false;

                    // check if it's time to run AutoRefresh
                    if (prevPluginState == IBPluginState.Ready)             // Plugin works with up to date data
                    {
                        lastUptodateTime = DateTime.Now;

                        if (IBConfiguration != null && IBConfiguration.AutoRefreshEnabled && // Auto refresh is enabled
                            nextAutoRefreshTime < DateTime.Now)                              // The time of auto refresh has passed
                        {
                            DateTime refreshStartDate = DateTime.Now.Date.AddDays(-IBConfiguration.AutoRefreshDays);
                            LogAndMessage.LogAndQueue(MessageType.Warning, "Starting automatic database refresh (" + refreshStartDate.ToShortDateString() + ").");

                            controller.RefreshAllUsed(refreshStartDate);

                            CalcNextAutoRefreshTime();
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                LogAndMessage.Log(MessageType.Error, "Error in data source timer event handler: " + ex);
            }
            finally
            {
                // update plugin state
                prevPluginState = currPluginState;

                // indicate thread exit
                Interlocked.Exchange(ref inTimerTick, 0);
            }
        }
示例#16
0
        /// <summary>
        /// Event handler called when all bar are collected for a request
        /// </summary>
        /// <param name="bars"></param>
        internal void QuoteReceived(List <Bar> bars)
        {
            lock (TickerData)    // event handling
            {
                foreach (Bar bar in bars)
                {
                    DateTime date;

                    if (bar.Time.Length == 8)
                    {
                        date = DateTime.ParseExact(bar.Time, "yyyyMMdd", CultureInfo.InvariantCulture);
                    }
                    else
                    {
                        date = DateTime.ParseExact(bar.Time, "yyyyMMdd  HH:mm:ss", CultureInfo.InvariantCulture);
                    }

                    if (downloadStart.CompareTo(date) <= 0)  // if newer data (may overlap w/ prev request)
                    {
                        Quotation quoteData = new Quotation();
                        quoteData.DateTime = (AmiDate)date;
                        quoteData.Open     = (float)bar.Open;
                        quoteData.High     = (float)bar.High;
                        quoteData.Low      = (float)bar.Low;
                        quoteData.Price    = (float)bar.Close;
                        quoteData.Volume   = bar.Volume;

                        if (TickerData.SymbolParts.IsContinuous)
                        {
                            if (FTDataSource.Periodicity == Periodicity.EndOfDay || TickerData.QuoteDataStatus == QuotationStatus.DownloadingEod)
                            {
                                TickerData.ContinuousQuotesDictionary[downloadContract.LocalSymbol].MergeEod(quoteData, quoteData.DateTime);
                            }
                            else
                            {
                                TickerData.ContinuousQuotesDictionary[downloadContract.LocalSymbol].Merge(quoteData);
                            }
                        }
                        else
                        {
                            lock (TickerData.Quotes)
                            {     // store in the list directly only for non contiguous contracts
                                if (FTDataSource.Periodicity == Periodicity.EndOfDay || TickerData.QuoteDataStatus == QuotationStatus.DownloadingEod)
                                {
                                    TickerData.Quotes.MergeEod(quoteData, quoteData.DateTime);
                                }
                                else
                                {
                                    TickerData.Quotes.Merge(quoteData);
                                }
                            }
                        }
                    }
                }

                // it is finished with succes
                WaitingForResponse = false;

                LogAndMessage.Log(TickerData, MessageType.Info, "Received " + bars.Count + " bars. " + ToString(true, LogAndMessage.VerboseLog));
            }
        }
示例#17
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);
        }
示例#18
0
        private void mCancel_Click(object sender, EventArgs e)
        {
            LogAndMessage.Log(MessageType.Info, "All backfill operations are manually cancelled.");

            controller.CancelAllRefreshes();
        }
示例#19
0
 internal void RegisterHstPacingViolation()
 {
     ibHstThrottlingEndTime = DateTime.Now.AddSeconds(30);
     LogAndMessage.Log(MessageType.Warning, "Throttling historical data requests until " + ibHstThrottlingEndTime.ToShortTimeString() + ".");
 }
示例#20
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);
            }
        }
        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);
                }
            }
        }
示例#22
0
        /// <summary>
        /// Process the list of contract details received from TWS, and selects the current front month contract
        /// </summary>
        /// <param name="TickerData"></param>
        /// <returns></returns>
        private bool ProcessContractDetailsList(List <ContractDetails> list)
        {
            try
            {
                TickerData.contractDetailsList = list;

                // if no contract found
                if (TickerData.contractDetailsList.Count == 0)
                {
                    return(false);
                }

                // not a continuos contract there must be exactly 1 found contract
                if (TickerData.contractDetailsList.Count == 1 && !TickerData.SymbolParts.IsContinuous)
                {
                    TickerData.ContractDetails = TickerData.contractDetailsList[0];
                    return(true);
                }

                // continuos contract
                if (TickerData.SymbolParts.IsContinuous)
                {
                    //
                    // only expired and the nearest expiration may remain in the list
                    //

                    // sort contract details on expiry
                    TickerData.contractDetailsList.Sort(new ContractDetailsComparer());

                    // current date in the format of contract expiry
                    string frontMonthExpiry = DateTime.Now.ToString("yyyyMMdd");

                    // this may be an already expired contract or a contract that will expire in the far future
                    ContractDetails temp = TickerData.contractDetailsList[0];

                    // find the contract that ...
                    for (int i = 1; i < TickerData.contractDetailsList.Count; i++)
                    {
                        if (TickerData.contractDetailsList[i].Contract.LastTradeDateOrContractMonth.CompareTo(frontMonthExpiry) >= 0)       // expires in the future or today
                        {
                            temp = TickerData.contractDetailsList[i];
                            break;
                        }
                    }

                    // setting the found CURRENT (front month) contract as the contractdetails
                    TickerData.ContractDetails = temp;

                    frontMonthExpiry = temp.Contract.LastTradeDateOrContractMonth;

                    // remove all future contract with later expiry then current front month
                    for (int i = TickerData.contractDetailsList.Count - 1; i >= 0; i--)
                    {
                        if (TickerData.contractDetailsList[i].Contract.LastTradeDateOrContractMonth.CompareTo(frontMonthExpiry) > 0)
                        {
                            TickerData.contractDetailsList.RemoveAt(i);
                        }
                    }

                    return(true);
                }

                return(false);
            }
            finally
            {
                try
                {
                    // update trading days using current contract details
                    if (TickerData.ContractDetails != null)
                    {
                        //tickerData.LiquidHours = new TradingDayList(tickerData.ContractDetails.LiquidHours, true);
                        //if (IBDataSource.RthOnly && string.IsNullOrEmpty(tickerData.ContractDetails.LiquidHours))
                        //    LogAndMessage.LogAndQueue(tickerData, MessageType.Warning, "No liquid hours data is available.");
                        //else
                        //    LogAndMessage.Log(tickerData, MessageType.Trace, "Liquid hour:" + tickerData.ContractDetails.LiquidHours);

                        TickerData.TradingDays = new TradingDayList(TickerData.ContractDetails.TradingHours, false);
                        if ((FTDataSource.AllowMixedEODIntra || FTDataSource.Periodicity == Periodicity.EndOfDay) && string.IsNullOrEmpty(TickerData.ContractDetails.TradingHours))
                        {
                            LogAndMessage.Log(TickerData, MessageType.Warning, "No trading hours data is available. Daily quotation data may not be correct.");
                        }
                        //else
                        //    LogAndMessage.Log(tickerData, MessageType.Trace, "Trading hour:" + tickerData.ContractDetails.TradingHours);
                    }
                    else
                    {
                        //tickerData.LiquidHours = new TradingDayList(null, true);
                        TickerData.TradingDays = new TradingDayList(null, false);
                    }
                }
                catch (Exception e)
                {
                    LogAndMessage.Log(TickerData, MessageType.Error, "Failed to parse (" + TickerData.ContractDetails.TradingHours + ") and update trading hours:" + e.ToString());
                }
            }
        }
示例#23
0
        public override bool Notify(ref PluginNotification notifyData)
        {
            bool result = true;

            switch (notifyData.Reason)
            {
            case Reason.DatabaseLoaded:

                // if database is loaded
                if (controller != null)
                {
                    // disconnect from TWS and reset all data
                    controller.Disconnect();
                    ((IDisposable)controller).Dispose();
                    controller = null;
                }

                Workspace          = notifyData.Workspace;
                DatabasePath       = notifyData.DatabasePath;
                MainWindowHandle   = notifyData.MainWnd;
                AllowMixedEODIntra = Workspace.AllowMixedEODIntra != 0;

                // start logging the opening of the database
                LogAndMessage.Log(MessageType.Info, "Database: " + DatabasePath);
                LogAndMessage.Log(MessageType.Info, "Mixed EOD/Intra: " + (Workspace.AllowMixedEODIntra != 0));
                LogAndMessage.Log(MessageType.Info, "Number of bars: " + Workspace.NumBars);
                LogAndMessage.Log(MessageType.Info, "Database config: " + Settings);

                // create the config object
                IBConfiguration          = FTConfiguration.GetConfigObject(Settings);
                LogAndMessage.VerboseLog = IBConfiguration.VerboseLog;
                RthOnly = IBConfiguration.RthOnly;
                CalcNextAutoRefreshTime();

                // create new controller
                connectionRetryTime = DateTime.Now.AddSeconds(ConnectionRetryInterval);
                prevPluginState     = IBPluginState.Disconnected;
                firstConnection     = true;
                controller          = new FTController();

                // connect database to tws
                controller.Connect(false);

                if (rtWindowTickersBck.Count > 0)
                {
                    for (int i = 0; i < rtWindowTickersBck.Count; i++)
                    {
                        controller.GetRecentInfo(rtWindowTickersBck[i]);
                    }
                }

                break;

            // user changed the db
            case Reason.DatabaseUnloaded:

                // disconnect from TWS
                if (controller != null)
                {
                    controller.Disconnect();
                    ((IDisposable)controller).Dispose();
                    controller = null;
                }

                // clean up
                Workspace        = new Workspace();
                DatabasePath     = null;
                MainWindowHandle = IntPtr.Zero;
                searchForm       = null;

                break;

            // seams to be obsolete
            case Reason.SettingsChanged:

                break;

            // user right clicks data plugin area in AB
            case Reason.RightMouseClick:

                if (controller != null)
                {
                    currentSI = notifyData.CurrentSI;
                    if (currentSI != null)
                    {
                        currentTicker = currentSI.ShortName;
                        if (currentTicker.Length > 10)
                        {
                            currentTickerShortend = currentTicker.Substring(0, 7) + "...";
                        }
                        else
                        {
                            currentTickerShortend = currentTicker;
                        }
                    }
                    else
                    {
                        currentTicker         = null;
                        currentTickerShortend = null;
                    }
                }

                SetContextMenuState();

                ShowContextMenu(mContextMenu);

                break;

            default:
                result = false;

                break;
            }
            return(result);
        }
示例#24
0
        /// <summary>
        /// Processing all queues/request
        /// </summary>
        /// <returns>true, if any request was sent</returns>
        private bool ProcessQueues()
        {
            try
            {
#if DEBUG
                bool traceMode = backfillQueue.IsBusy || subscriptionQueue.IsBusy ||
                                 symbolQueue.IsBusy || headTimestampQueue.IsBusy || contractQueue.IsBusy;

                traceMode = false;

                if (traceMode)
                {
                    LogAndMessage.Log(MessageType.Trace, "Start of ProcessAllQueues");
                }
#else
                bool traceMode = false;
#endif
                //
                // sending notificaton to AB to get quotes from the plugin (GetQuotesEx will be called)
                //
                SendQuoteNotificationToAB();

                if (!ibController.IsIbConnected())
                {
                    return(true);
                }

                // remove timed out entries from request throlling queue and check  if any request can be sent
                bool throttling = ibAllRequestTimeQueue.IsThrottled();
                if (throttling)
                {
                    LogAndMessage.LogAndQueue(MessageType.Info, "Throttling all requests.");
                }

                // remove timed out entries from hist request throlling queue and check if historical request can be sent
                bool histThrottling = ibHstRequestTimeQueue.IsThrottled() || ibHstThrottlingEndTime >= DateTime.Now;

                //
                // main queue processing logic
                //

                // check if general request can be sent
                bool allowNewRequest = !throttling;

                if (!histThrottling)
                {
                    allowNewRequest &= backfillQueue.ProcessQueuedRequests(ibController, allowNewRequest, traceMode);
                }

                allowNewRequest &= subscriptionQueue.ProcessQueuedRequests(ibController, allowNewRequest, traceMode);

                allowNewRequest &= headTimestampQueue.ProcessQueuedRequests(ibController, allowNewRequest, traceMode);

                allowNewRequest &= contractQueue.ProcessQueuedRequests(ibController, allowNewRequest, traceMode);

                allowNewRequest &= symbolQueue.ProcessQueuedRequests(ibController, allowNewRequest, traceMode);

                if (allowNewRequest)
                {
                    allowNewRequest &= ibController.SendCurrentTimeRequest();
                }

#if DEBUG
                if (traceMode)
                {
                    LogAndMessage.Log(MessageType.Trace, "End of ProcessAllQueues");
                }
#endif

                // other scheduled jobs
                ibController.StartContractRefresh();

                ibController.UpdateFailedTickers();

                return(!allowNewRequest);                // indicate newly sent request -> longer wait time
            }
            catch (Exception ex)
            {
                LogAndMessage.LogAndQueue(MessageType.Error, "Program error. ProcessQueues exception: " + ex);
                return(true);
            }
        }
示例#25
0
        internal void MergePrice(int tickerId, int field, float price, DateTime time)
        {
            //
            // if price is 0 or less (no live data)
            //
            if (price <= 0.0f)
            {
                return;
            }

            decimal p = (decimal)price;

            //
            // save BID and ASK prices
            //
            if (field == TickType.ASK)
            {
                lastAsk = p;
            }

            else if (field == TickType.BID)
            {
                lastBid = p;
            }

            //
            // calc MID price if data is available
            //
            if (lastAsk > 0m && lastBid > 0m)
            {
                lastMid = (lastAsk + lastBid) / 2m;
            }

            //
            // check if we need to use this price tick or it is irrelevant
            //
            if (tickerData.SymbolParts.DataType == IBHistoricalDataType.Midpoint || tickerData.SymbolParts.DataType == IBHistoricalDataType.BidAsk)
            {
                if (field != TickType.BID && field != TickType.ASK && field != TickType.LAST)
                {
                    return;
                }
            }
            else if (tickerData.SymbolParts.DataType == IBHistoricalDataType.Trades || tickerData.SymbolParts.DataType == IBHistoricalDataType.Adjusted)
            {
                if (field != TickType.LAST)
                {
                    return;
                }
            }
            else if (tickerData.SymbolParts.DataType == IBHistoricalDataType.Bid)
            {
                if (field != TickType.BID)
                {
                    return;
                }
            }
            else if (tickerData.SymbolParts.DataType == IBHistoricalDataType.Ask)
            {
                if (field != TickType.ASK)
                {
                    return;
                }
            }
            else if (tickerData.SymbolParts.DataType == IBHistoricalDataType.HistoricalVolatility)
            {
                if (field != TickType.OPTION_HISTORICAL_VOL)
                {
                    return;
                }
            }
            else if (tickerData.SymbolParts.DataType == IBHistoricalDataType.ImpliedVolatility)
            {
                if (field != TickType.OPTION_IMPLIED_VOL)
                {
                    return;
                }
            }
            else
            {
                return;
            }

            //
            // check if tick is in acceptable range
            //
            if (filter)
            {
                //
                // filter #1
                //

                // it is a simple filter to remove bad price ticks
                // it works only during high volume, continuously traded period, fell free to improve it
                if (lastMid != 0.0m &&                                                 // there is a midpoint price already
                    (DateTime.Now.Ticks - date.Ticks) / TimeSpan.TicksPerSecond < 5 && // time elapsed since last tick event is less then 5 second
                    Math.Abs(p - lastMid) / lastMid > 0.03m)                           // price change is greater then 3 %
                {
                    // This may impose 5 sec delay and loss of some ticks in higly volatily and thin market (not in Forex)
                    LogAndMessage.Log(tickerData, MessageType.Trace, "Bad tick has been rejected. Price:" + price.ToString() + " MidPoint:" + lastMid.ToString());
                    return;
                }

                //
                // filter #2
                //

                //
                //
                //

                // it is a "round robin" array store
                // check if index points behind last element of the array
                if (sampleIdx == MaxSampleNo)
                {
                    sampleIdx = 0;
                    sampleOk  = true;
                }

                // if there is enough data yet
                if (sampleOk)
                {
                    // calc avg prior to this tick
                    decimal avg = 0;
                    for (int i = 0; i < MaxSampleNo; i++)
                    {
                        avg += sample[i];
                    }

                    // calc price move compared to avg price
                    decimal rate = avg / MaxSampleNo / p;

                    // if to big, reject tick
                    if (rate > 1.02M || rate < 0.98M)
                    {
                        LogAndMessage.Log(tickerData, MessageType.Trace, "Bad tick has been rejected. Price:" + price.ToString() + " Avg of last " + MaxSampleNo + " ticks:" + (avg / MaxSampleNo).ToString());
                        return;
                    }

                    // store current price in sample array
                    sample[sampleIdx] = p;
                    sampleIdx++;
                }
                // if there is NOT enough data yet
                else
                {
                    // store current price in sample array
                    sample[sampleIdx] = p;
                    sampleIdx++;
                }
            }

            // storing the tick into a Quote to merge
            if (tickerData.SymbolParts.DataType == IBHistoricalDataType.Midpoint)
            {
                if (lastMid == 0.0m)
                {
                    return;
                }
                lastPrice = (float)lastMid;
            }
            else
            {
                lastPrice = price;
            }

            date = time;

            Quotation quote = new Quotation();

            quote.DateTime = (AmiDate)date;
            quote.Price    = lastPrice;
            quote.Low      = lastPrice;
            quote.High     = lastPrice;
            quote.Open     = prevPrice != 0 ? prevPrice : lastPrice;
            quote.Volume   = 0;

            prevPrice = lastPrice;

            SaveQuote(quote);
        }
示例#26
0
        internal override bool Process(FTController ibController, bool allowNewRequest)
        {
            const int requestTimeoutPeriod = 10;

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

                    if (allowNewRequest)
                    {
                        LogAndMessage.Log(TickerData, MessageType.Trace, "Getting contract. " + ToString(false, LogAndMessage.VerboseLog));

                        Contract contract = new Contract();

                        contract.Exchange       = TickerData.SymbolParts.Exchange;
                        contract.SecType        = TickerData.SymbolParts.SecurityType;
                        contract.Currency       = TickerData.SymbolParts.Currency;
                        contract.IncludeExpired = true;

                        if (TickerData.SymbolParts.IsContinuous)
                        {
                            if (!string.IsNullOrEmpty(TickerData.SymbolParts.Underlying))
                            {
                                contract.Symbol = TickerData.SymbolParts.Underlying;
                            }
                            else
                            {
                                contract.Symbol = TickerData.SymbolParts.Symbol;
                            }
                        }
                        else
                        {
                            contract.LocalSymbol = TickerData.SymbolParts.Symbol;
                        }

                        TickerData.contractDetailsList.Clear();
                        TickerData.ContractStatus = ContractStatus.WaitForResponse;
                        RequestTime = DateTime.Now;

                        ibController.SendContractDetailsRequest(Id, contract);
                    }

                    return(false);

                // if request is sent, but response has not arrived yet
                // see ibclient_ContractDetails and ibclient_ContractDetailsEnd event handlers
                case ContractStatus.WaitForResponse:

                    // if no answer in Time
                    if (RequestTime.AddSeconds(requestTimeoutPeriod) < DateTime.Now)
                    {
                        LogAndMessage.LogAndQueue(TickerData, MessageType.Error, "Getting contract info timed out, symbol is offline. " + ToString(true, LogAndMessage.VerboseLog));

                        TickerData.ContractStatus = ContractStatus.Failed;

                        goto case ContractStatus.Failed;
                    }

                    return(allowNewRequest);

                // if new, offline ticker
                case ContractStatus.Offline:
                    goto case ContractStatus.Failed;

                // contract found
                case ContractStatus.Ok:
                    goto case ContractStatus.Failed;

                // no contract found
                case ContractStatus.Failed:

                    IsFinished = true;
                    return(allowNewRequest);

                default:
                    throw new ArgumentOutOfRangeException();
                }
            }
        }
示例#27
0
 private void mDisconnect_Click(object sender, EventArgs e)
 {
     LogAndMessage.Log(MessageType.Info, "TWS is manually disconnected.");
     manuallyDisconnected = true;
     controller.Disconnect();
 }
示例#28
0
 private void mReconnect_Click(object sender, EventArgs e)
 {
     LogAndMessage.Log(MessageType.Info, "TWS is manually reconnected.");
     manuallyDisconnected = false;
     controller.Connect(false);
 }
示例#29
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);
                }
            }
        }