- ago
Hi there,

currently i am working at a custom implementation of the streamingproviderbase.
i am using the update.... methods to inject data i receive from my provider.
the provider delivers up to several hundread ticks per second.
plumbing the output directly to the Update methods lead to an application freeze.
I limited the rate to one tick per second only using this line from either the backgroundthread and main thread, but it always stucks at the method.

UpdateTick(symbolName, DateTime.Now, Random.Shared.Next(10, 100), Random.Shared.Next(1000, 10000), 0);

What is the threshold to invoke data into the chart?
What is your suggestion?

Kind regards
Mike

[Edit 1]
i found out what i did wrong.
i did not call the updateheartbeat frequently.
for anyone else running into this issue look here:

https://www.wealth-lab.com/Discussion/Strategy-Monitor-with-my-custom-Alor-SDP-does-not-trigger-execution-on-UpdateHeartbeat-6667

[Edit 2]
Unfortunatley i got the problem again.
i initialize an updateheartbeat thread once to refresh the view every second when initializing the streamingprovider.

var isHeartbeatActive = true;
ThreadPool.QueueUserWorkItem(state =>
{
while (isHeartbeatActive)
{
UpdateHeartbeat(DateTime.Now);
Thread.Sleep(1000);
}
});

in my providers tick handler i just map the data with this method:

private void PushFeedMessageHandler(TPRPushFeedMessage message)
{
Debug.WriteLine($"{message.MessageType} - {message}");

if (message is TPRQuoteTickMessage quoteMsg)
{
var symbolName = LPSymbolMapper.GetById(quoteMsg.SymbolNo);
switch (quoteMsg.QuoteType)
{
case TPRQuoteTypes.Last:
-> UpdateTick(symbolName, quoteMsg.QuoteTick.Time, quoteMsg.QuoteTick.Quote, quoteMsg.QuoteTick.Volume, 0);
break;
case TPRQuoteTypes.Ask:
UpdateBidAsk(symbolName, 0, quoteMsg.QuoteTick.Quote);
break;
case TPRQuoteTypes.Bid:
UpdateBidAsk(symbolName, quoteMsg.QuoteTick.Quote, 0);
break;
default:
Debugger.Break();
break;
}
}

but despite the thread updating the "heartbeat", the executing thread stops in the marked line (->).
0
221
6 Replies

Reply

Bookmark

Sort
Cone8
 ( 7.88% )
- ago
#1
Last I checked, using IQFeed (a tick to tick provider) WealthLab can pretty easily keep up with the S&P 500. So hundreds of ticks per second isn't the problem.

We've got about a dozen streaming providers, so you probably need to look more closely at your implementation.
0
- ago
#2
Hi community,

i am stuck for days on the same problems i have mentioned here:
https://www.wealth-lab.com/Discussion/Custom-streaming-provider-locks-up-at-UpdateTick-11315

the thread locks in the execution of the updatetick method and i have no clue why.
in addition to the information from the other post.
it seemst to stuck in accessing the index of a list from member 'IsOpenNow()'
ive added a stack screenshot.
0
- ago
#3
QUOTE:
i am stuck for days on the same problems i have mentioned here:

Nonetheless, which is not a reason for creating the (duplicate) thread which has been merged with this topic. 🤷‍♂️
0
- ago
#4
QUOTE:
it seemst to stuck in accessing the index of a list from member 'IsOpenNow()'

Probably IsOpenNow is operating internally with a type that isn't thread safe. Can you adjust your code to this?
0
- ago
#5
i have not implemented any of these types and MarketDetails is on of the framework types. i have no idea how to elaborate that problem.
0
- ago
#6
maybe the problem occurs because i have not implemented enough.
i have implmeneted these types:

CODE:
public class LPDataSet : DataSet { public LPDataSet() { PreferredDataProviderName = LPGlobals.ExtensionName; ReadOnlySymbols = true; } } public class LPDataSetProvider : DataSetProviderBase { private List<DataSet> _dataSets = []; public override string Name => LPGlobals.ExtensionName; public LPDataSetProvider() { Instance = this; } public static LPDataSetProvider Instance { get; private set; } public override void Initialize() { if (_dataSets.Any()) { foreach (var ds in _dataSets) WLHost.Instance.DataSets.Remove(ds); _dataSets.Clear(); UpdateView(); } if (!LPAdapter.Instance.IsConnected()) return; var catalogDatas = LPAdapter.Instance.GetCatalogDatas(LPGlobals.DefaultCatalogIds); _dataSets = catalogDatas.Select(cd => { var ds = new LPDataSet { Name = cd.Catalog.Name, IsDynamicEnabled = false, IsUserCreated = false, ReadOnlySymbols = true, Symbols = cd.Symbols.Select(i => i.SymbolString).ToList(), }; ds.SymbolString = string.Join(' ', ds.Symbols); return ds; }).OfType<DataSet>().ToList(); UpdateView(); } public override List<DataSet> DataSets => _dataSets; private void UpdateView() => EventRouter.FireEvent("DataSetProviderReloaded", this); } internal class LPHistoryProvider : DataProviderBase { public override string Name => LPGlobals.ExtensionName; public override bool IsGeneralPurposeProvider => true; protected override BarHistory GetHistoryInternal(string symbol, HistoryScale scale, DateTime startDate, DateTime endDate, int maxBars) => LPAdapter.Instance.GetHistoryData(symbol, scale, startDate, endDate, maxBars, null); public override bool SupportsScale(HistoryScale scale) => true; public override bool SupportsParallelRequests => false; } public class LPStreamingProvider : StreamingProviderBase { private System.Timers.Timer _hbUpdate; public override string Name => LPGlobals.ExtensionName; public LPStreamingProvider() { FilterPrePost = false; } protected override bool Connect() { if (LPAdapter.Instance.IsConnected()) { _hbUpdate = new System.Timers.Timer(1000); _hbUpdate.Elapsed += (s, e) => UpdateHeartbeat(DateTime.Now); _hbUpdate.Start(); LPAdapter.Instance.ConnectPushFeed(PushFeedMessageHandler); return true; } return false; } protected override void SubscribeTo(string symbol) => LPAdapter.Instance.Subscribe(symbol); protected override void UnsubscribeFrom(string symbol) => LPAdapter.Instance.Unsubscribe(symbol); private void PushFeedMessageHandler(TPRPushFeedMessage message) { if (message is TPRQuoteTickMessage quoteMsg) { Debug.WriteLine($"MT:{message.MessageType} - QT:{quoteMsg.QuoteType} - T:{quoteMsg.QuoteTick.Time} - Q:{quoteMsg.QuoteTick.Quote} - V:{quoteMsg.QuoteTick.Volume}"); var symbolName = LPSymbolMapper.GetById(quoteMsg.SymbolNo); switch (quoteMsg.QuoteType) { case TPRQuoteTypes.Last: UpdateTick(symbolName, quoteMsg.QuoteTick.Time, quoteMsg.QuoteTick.Quote, quoteMsg.QuoteTick.Volume, double.NaN); break; case TPRQuoteTypes.Ask: UpdateBidAsk(symbolName, double.NaN, quoteMsg.QuoteTick.Quote); break; case TPRQuoteTypes.Bid: UpdateBidAsk(symbolName, quoteMsg.QuoteTick.Quote, double.NaN); break; default: Debugger.Break(); break; } } else if (message is TPRMarketDepthMessage mptickMessage) { if (mptickMessage.Position + 1 > 0) { Debug.WriteLine($"MT:{message.MessageType} - QT:{mptickMessage.QuoteType} - T:{mptickMessage.QuoteTick.Time} - Q:{mptickMessage.QuoteTick.Quote} - V:{mptickMessage.QuoteTick.Volume}"); var symbolName = LPSymbolMapper.GetById(mptickMessage.SymbolNo); UpdateTick(symbolName, mptickMessage.QuoteTick.Time, mptickMessage.QuoteTick.Quote, mptickMessage.QuoteTick.Volume, double.NaN); } } else if (message is TPRPingMessage pm) { Debug.WriteLine("Ping"); } else if (message is TPRPushFeedConnectionMessage pfcm) { Debug.WriteLine("CMessage: " + pfcm.Status); } else Debugger.Break(); } }


i also implemented a childwindow which is only used for login process.
after successfull login the LPAdapter is functional.
0

Reply

Bookmark

Sort