Skip to content

fix(connectors): stamp order books with the venue's event timestamp; … - #73

Merged
silahian merged 1 commit into
masterfrom
fix/mkt-lat-exchange-timestamps
Aug 25, 2026
Merged

fix(connectors): stamp order books with the venue's event timestamp; …#73
silahian merged 1 commit into
masterfrom
fix/mkt-lat-exchange-timestamps

Conversation

@silahian

Copy link
Copy Markdown
Collaborator

…add {{metric}} webhook placeholder

The five exchange libraries all deliver a genuine venue event timestamp on the book stream (Binance E, Coinbase per-entry event_time, Kraken book-v2 timestamp, KuCoin time, Bitfinex DataTime) and every connector discarded it, stamping LastUpdated from local socket receive time. Each connector gains one ResolveBookTimestamp decision point: venue event time in local kind, or null when the frame carries none -- a default(DateTime) stamp would fabricate a colossal latency spike, and receive time must never masquerade as exchange time. Binance's EventTime clobber is deleted and its freshness warn keys on ReceiveTime.

TriggerEngine: the {{metric}} placeholder the RestApiAction docs promised now substitutes with the firing metric; {{plugin}} keeps its historical output so saved templates render unchanged; help text and the seeded template updated.

…add {{metric}} webhook placeholder

The five exchange libraries all deliver a genuine venue event timestamp on
the book stream (Binance E, Coinbase per-entry event_time, Kraken book-v2
timestamp, KuCoin time, Bitfinex DataTime) and every connector discarded
it, stamping LastUpdated from local socket receive time. Each connector
gains one ResolveBookTimestamp decision point: venue event time in local
kind, or null when the frame carries none -- a default(DateTime) stamp
would fabricate a colossal latency spike, and receive time must never
masquerade as exchange time. Binance's EventTime clobber is deleted and
its freshness warn keys on ReceiveTime.

TriggerEngine: the {{metric}} placeholder the RestApiAction docs promised
now substitutes with the firing metric; {{plugin}} keeps its historical
output so saved templates render unchanged; help text and the seeded
template updated.
Copilot AI lite review requested due to automatic review settings August 25, 2026 13:02
@silahian
silahian merged commit e5d8ab6 into master Aug 25, 2026
1 check passed

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR updates multiple market connector plugins to stamp order books using the exchange-provided event timestamp (when available) instead of local receive time, and extends TriggerEngine webhook templating to support a documented {{metric}} placeholder while preserving legacy {{plugin}} behavior.

Changes:

  • Market connectors: propagate venue event timestamps into the order book LastUpdated field (nullable when the feed frame provides no usable timestamp).
  • TriggerEngine: add/seed {{metric}} in webhook body templates and keep {{plugin}} substitution compatible with existing saved templates.

Reviewed changes

Copilot reviewed 8 out of 8 changed files in this pull request and generated 6 comments.

Show a summary per file
File Description
VisualHFT.Plugins/MarketConnectors.KuCoin/KuCoinPlugin.cs Buffer and book update pipeline now carries nullable venue timestamps and resolves KuCoin frame time.
VisualHFT.Plugins/MarketConnectors.Kraken/KrakenPlugin.cs Uses Kraken book-v2 frame timestamp as the book stamp (nullable when absent) while keeping freshness checks on receive time.
VisualHFT.Plugins/MarketConnectors.Coinbase/CoinbasePlugin.cs Resolves Coinbase per-entry event_time into a nullable frame timestamp for stamping.
VisualHFT.Plugins/MarketConnectors.Bitfinex/BitfinexPlugin.cs Uses Bitfinex wrapper DataTime (when present) as the venue timestamp for book updates.
VisualHFT.Plugins/MarketConnectors.Binance/BinancePlugin.cs Stops overwriting EventTime, adds a single timestamp decision point, and stamps LastUpdated with venue time (nullable).
TriggerEngine/View/TriggerSettingAddOrUpdate.xaml Updates UI help text to document the available webhook placeholders including {{metric}}.
TriggerEngine/View/AddAPISetting.xaml.cs Seeds the default webhook body template to use {{metric}}.
TriggerEngine/TriggerEngineService.cs Implements {{metric}} substitution while keeping {{plugin}} output stable for older templates.
Suppressed comments (5)

VisualHFT.Plugins/MarketConnectors.Coinbase/CoinbasePlugin.cs:609

  • Same issue as above: ServerTimeStamp = ts ?? DateTime.Now introduces a second wall-clock read inside the same frame. Prefer ts ?? now for consistency and to reduce overhead.
                        IsBid = true,
                        LocalTimeStamp = now,
                        ServerTimeStamp = ts ?? DateTime.Now,
                        Symbol = symbol
                    });

VisualHFT.Plugins/MarketConnectors.Coinbase/CoinbasePlugin.cs:626

  • Same issue as above: use the already-cached now value when ts is null so timestamps are consistent within the frame and you avoid multiple DateTime.Now calls.
                        IsBid = false,
                        LocalTimeStamp = now,
                        ServerTimeStamp = ts ?? DateTime.Now,
                        Symbol = symbol
                    });

VisualHFT.Plugins/MarketConnectors.Coinbase/CoinbasePlugin.cs:638

  • Same issue as above: ServerTimeStamp should use the cached now when ts is null to avoid inconsistent timestamps and extra wall-clock reads.
                        IsBid = false,
                        LocalTimeStamp = now,
                        ServerTimeStamp = ts ?? DateTime.Now,
                        Symbol = symbol
                    });

VisualHFT.Plugins/MarketConnectors.KuCoin/KuCoinPlugin.cs:779

  • Same as above: avoid multiple DateTime.Now reads for a single ask-level update by caching now and using ts ?? now. This keeps timestamps within the same frame consistent and reduces overhead.
                        else
                            local_lob.AddOrUpdateLevel(false, string.Empty, (double)item.Price, (double)item.Quantity, DateTime.Now, ts ?? DateTime.Now);
                    }

VisualHFT.Plugins/MarketConnectors.Bitfinex/BitfinexPlugin.cs:715

  • Same issue as the delete path: cache one now per delta so LocalTimeStamp and ts-null fallback for ServerTimeStamp are consistent, and avoid duplicate DateTime.Now calls.
                    var delta = new DeltaBookItem()
                    {
                        Price = (double)lob_update.Price,
                        Size = (double)Math.Abs(lob_update.Quantity),
                        IsBid = isBid,
                        LocalTimeStamp = DateTime.Now,
                        ServerTimeStamp = ts ?? DateTime.Now,
                        Symbol = local_lob.Symbol,

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

else
{
restApiAction.BodyTemplate = "{\r\n\r\n\"plugin\":\"{{plugin}}\",\r\n\"value\":\"{{value}}\",\r\n\"timestamp\":\"{{timestamp}}\", \r\n}";
restApiAction.BodyTemplate = "{\r\n\r\n\"metric\":\"{{metric}}\",\r\n\"value\":\"{{value}}\",\r\n\"timestamp\":\"{{timestamp}}\", \r\n}";
Comment on lines 593 to 597
IsBid = true,
LocalTimeStamp = now,
ServerTimeStamp = ts,
ServerTimeStamp = ts ?? DateTime.Now,
Symbol = symbol
});
Comment on lines +142 to 144
new HelperCustomQueue<Tuple<DateTime?, string, CoinbaseOrderBookUpdate>>(
$"<Tuple<DateTime, string, CoinbaseStreamOrderBookChanged>>_{this.Name.Replace(" Plugin", "")}",
eventBuffers_onReadAction, eventBuffers_onErrorAction));
Comment on lines 174 to 177
_eventBuffers.Add(symbol,
new HelperCustomQueue<Tuple<DateTime, string, KucoinStreamOrderBook>>(
new HelperCustomQueue<Tuple<DateTime?, string, KucoinStreamOrderBook>>(
$"<Tuple<DateTime, string, KucoinStreamOrderBookChanged>>_{this.Name.Replace(" Plugin", "")}",
eventBuffers_onReadAction, eventBuffers_onErrorAction));
Comment on lines 766 to 768
else
local_lob.AddOrUpdateLevel(true, string.Empty, (double)item.Price, (double)item.Quantity, DateTime.Now, ts);
local_lob.AddOrUpdateLevel(true, string.Empty, (double)item.Price, (double)item.Quantity, DateTime.Now, ts ?? DateTime.Now);
}
Comment on lines 694 to 701
var delta = new DeltaBookItem()
{
Price = (double)lob_update.Price,
Size = (double)Math.Abs(lob_update.Quantity),
IsBid = isBid,
LocalTimeStamp = DateTime.Now,
ServerTimeStamp = ts,
ServerTimeStamp = ts ?? DateTime.Now,
Symbol = local_lob.Symbol,
@silahian
silahian deleted the fix/mkt-lat-exchange-timestamps branch August 25, 2026 13:09
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants