bmello4688 / TDAmeritradeApi

Unofficial TD Ameritrade CSharp API Library
Apache License 2.0
12 stars 5 forks source link

Issues with streaming data disconnecting and stale data #8

Closed StevenFischerWI closed 2 years ago

StevenFischerWI commented 2 years ago

Hi there - first off, thank you for your continued work. I've built my bot around your project and am having success using the TDA data feed for about 1200 tickers.

I'm experiencing some frustrating issues with the streaming of live chart data (likely due to TDA API glitchiness). Streaming chart minute data seems to be duplicated and stale, and I get occasional app-killing disconnects. I'm curious if you've seen these issues or have any guidance on troubleshooting.

The issues

image

My setup:

if (mdt == MarketDataType.Charts) {

                        _lastCandleTime = _clockService.Now;

                        if (_recentCandles == null)
                            _recentCandles = new List<(string, DateTime, DateTime)>();

                        lock (_recentCandles)
                            _recentCandles = Enumerable.TakeLast(_recentCandles, 5000).ToList();

                        foreach (var key in marketData[MarketDataType.Charts].Keys)
                        {
                            try
                            {
                                MinuteChartData[] minutes = marketData[MarketDataType.Charts][key].Data.ToArray();
                                List<MinuteChartData> minuteList = new List<MinuteChartData>(minutes);

                                // echo out every minute returned
                                foreach (var min in minuteList)
                                {
                                    await SaveStreamLog($"{ _clockService.Timestamp() },{ min.Symbol },ALL-MIN,{ min.ChartTime.ToShortTimeString() }");
                                }

                                var minute = minuteList.OrderBy(m => m.ChartTime).LastOrDefault();

                                var diff = Math.Abs(DateTime.Now.AddHours(TIMEZONE_HOURS_OFFSET * -1).Subtract(minute.ChartTime).TotalSeconds);

                                if (diff < 100)
                                {
                                    quoteCount++;
                                    Console.ForegroundColor = ConsoleColor.Green;
                                }

                                if (_zenService.ExtendedLogging)
                                    Console.WriteLine(quoteCount + " " + minute.Symbol + "- " + minute.ChartTime.ToShortDateString() + " " + minute.ChartTime.ToLongTimeString() + " " + minute.ClosePrice + " " + diff);

                                Console.ForegroundColor = ConsoleColor.White;

                                var candle = new Shared.Candle()
                                {
                                    Close = (decimal)minute.ClosePrice,
                                    Open = (decimal)minute.OpenPrice,
                                    DateTime = minute.ChartTime,
                                    High = (decimal)minute.HighPrice,
                                    Low = (decimal)minute.LowPrice,
                                    Volume = (long)minute.Volume
                                };

                                await SaveStreamLog($"{ _clockService.Timestamp() },{ minute.Symbol },MIN,{ minute.ChartTime.ToShortTimeString() }");

                                _recentCandles.Add((minute.Symbol, minute.ChartTime, _clockService.Now));

                                var ticker = _zenService.LiveTickers.Where(t => t.Name == minute.Symbol).LastOrDefault();

                                if (ticker != null)
                                {

                                    // is this a new candle?
                                    if (candle.DateTime > ticker.LastCandleSeen)
                                    {
                                        lock (ticker)
                                            ticker.LastCandleSeen = candle.DateTime;

                                        // add to in-memory database
                                        AddMinuteCandle(minute.Symbol, candle, false).Wait();

                                        CalculateMostRecentCandles(minute.Symbol).Wait();

                                        // immediately process the ticker
                                        if (Math.Abs(_clockService.Now.Subtract(candle.DateTime.AddHours(TIMEZONE_HOURS_OFFSET)).TotalMinutes) <= 2)
                                        {
                                            Thread newThread = new Thread(ProcessTicker);
                                            newThread.IsBackground = true;
                                            newThread.Start(ticker);
                                        }
                                    }

                                }

                            }
                            catch (Exception ex)
                            {
                                Console.WriteLine("STREAMING ERROR");
                                Console.WriteLine(ex);
                            }
                        }
                    }`
bmello4688 commented 2 years ago

Hi Steve,

So I have found that the tda api is very buggy and glitchy. The stale data could be because no trades are happening if you are outside of market hours. I’m looking into a better solution such as getting the thinkorswim api, but it will be some time.

I have created a plug-in for QuantConnect’s Lean Engine. It may help fix some of your problems.

Brian

Brian


From: Steven Fischer @.> Sent: Tuesday, February 1, 2022 12:14:12 PM To: bmello4688/TDAmeritradeApi @.> Cc: Subscribed @.***> Subject: [bmello4688/TDAmeritradeApi] Issues with streaming data disconnecting and stale data (Issue #8)

Hi there - first off, thank you for your continued work. I've built my bot around your project and am having success using the TDA data feed for about 1200 tickers.

I'm experiencing some frustrating issues with the streaming of live chart data (likely due to TDA API glitchiness). Streaming chart minute data seems to be duplicated and stale, and I get occasional app-killing disconnects. I'm curious if you've seen these issues or have any guidance on troubleshooting.

The issues

[image]https://user-images.githubusercontent.com/4407258/152004369-487146df-99de-436a-8430-daef76c7d835.png

[image]https://user-images.githubusercontent.com/4407258/152014550-e75459d2-363a-446c-90d9-754d7803cb75.png

My setup:

if (mdt == MarketDataType.Charts) {

                    _lastCandleTime = _clockService.Now;

                    if (_recentCandles == null)
                        _recentCandles = new List<(string, DateTime, DateTime)>();

                    lock (_recentCandles)
                        _recentCandles = Enumerable.TakeLast(_recentCandles, 5000).ToList();

                    foreach (var key in marketData[MarketDataType.Charts].Keys)
                    {
                        try
                        {
                            MinuteChartData[] minutes = marketData[MarketDataType.Charts][key].Data.ToArray();
                            List<MinuteChartData> minuteList = new List<MinuteChartData>(minutes);

                            // echo out every minute returned
                            foreach (var min in minuteList)
                            {
                                await SaveStreamLog($"{ _clockService.Timestamp() },{ min.Symbol },ALL-MIN,{ min.ChartTime.ToShortTimeString() }");
                            }

                            var minute = minuteList.OrderBy(m => m.ChartTime).LastOrDefault();

                            var diff = Math.Abs(DateTime.Now.AddHours(TIMEZONE_HOURS_OFFSET * -1).Subtract(minute.ChartTime).TotalSeconds);

                            if (diff < 100)
                            {
                                quoteCount++;
                                Console.ForegroundColor = ConsoleColor.Green;
                            }

                            if (_zenService.ExtendedLogging)
                                Console.WriteLine(quoteCount + " " + minute.Symbol + "- " + minute.ChartTime.ToShortDateString() + " " + minute.ChartTime.ToLongTimeString() + " " + minute.ClosePrice + " " + diff);

                            Console.ForegroundColor = ConsoleColor.White;

                            var candle = new Shared.Candle()
                            {
                                Close = (decimal)minute.ClosePrice,
                                Open = (decimal)minute.OpenPrice,
                                DateTime = minute.ChartTime,
                                High = (decimal)minute.HighPrice,
                                Low = (decimal)minute.LowPrice,
                                Volume = (long)minute.Volume
                            };

                            await SaveStreamLog($"{ _clockService.Timestamp() },{ minute.Symbol },MIN,{ minute.ChartTime.ToShortTimeString() }");

                            _recentCandles.Add((minute.Symbol, minute.ChartTime, _clockService.Now));

                            var ticker = _zenService.LiveTickers.Where(t => t.Name == minute.Symbol).LastOrDefault();

                            if (ticker != null)
                            {

                                // is this a new candle?
                                if (candle.DateTime > ticker.LastCandleSeen)
                                {
                                    lock (ticker)
                                        ticker.LastCandleSeen = candle.DateTime;

                                    // add to in-memory database
                                    AddMinuteCandle(minute.Symbol, candle, false).Wait();

                                    CalculateMostRecentCandles(minute.Symbol).Wait();

                                    // immediately process the ticker
                                    if (Math.Abs(_clockService.Now.Subtract(candle.DateTime.AddHours(TIMEZONE_HOURS_OFFSET)).TotalMinutes) <= 2)
                                    {
                                        Thread newThread = new Thread(ProcessTicker);
                                        newThread.IsBackground = true;
                                        newThread.Start(ticker);
                                    }
                                }

                            }

                        }
                        catch (Exception ex)
                        {
                            Console.WriteLine("STREAMING ERROR");
                            Console.WriteLine(ex);
                        }
                    }
                }`

— Reply to this email directly, view it on GitHubhttps://github.com/bmello4688/TDAmeritradeApi/issues/8, or unsubscribehttps://github.com/notifications/unsubscribe-auth/AB3WTQSIZU6SKXGZ22RKBWTUZAIGJANCNFSM5NJYCG5A. Triage notifications on the go with GitHub Mobile for iOShttps://apps.apple.com/app/apple-store/id1477376905?ct=notification-email&mt=8&pt=524675 or Androidhttps://play.google.com/store/apps/details?id=com.github.android&referrer=utm_campaign%3Dnotification-email%26utm_medium%3Demail%26utm_source%3Dgithub. You are receiving this because you are subscribed to this thread.Message ID: @.***>

StevenFischerWI commented 2 years ago

Ah, I'm glad it's not just me then. I might explore using a different API for streaming candle data. I've modified your code for my purposes, some of it might be worth a pull request. I'll submit one when I have it.