Skip to content

FEDEV-3973: WebSocket price + candle streaming (UI + SDK)#2611

Open
divhead wants to merge 1 commit into
masterfrom
phase-2-ws-prices
Open

FEDEV-3973: WebSocket price + candle streaming (UI + SDK)#2611
divhead wants to merge 1 commit into
masterfrom
phase-2-ws-prices

Conversation

@divhead

@divhead divhead commented Jul 2, 2026

Copy link
Copy Markdown
Collaborator

Phase 2 — Prices & candles over WebSocket (UI + SDK)

Streams normalized prices and live candles into the trading UI and the @gmx-io/sdk v2 client, behind off-by-default flags with the existing REST/poll as the fallback. Consumes the gmx-api WS gateway (gmx-io/gmx-api#102).

Linear: https://linear.app/gmx-io/issue/FEDEV-3973

SDK (@gmx-io/sdk v2)

  • WsStreamClient transport in utils/stream — isomorphic-ws, reconnect with backoff, snapshot-then-stream, ref-counted single connection.
  • v2 watchTokenPrices() / watchCandles() — raw Subscriptions; fetchTokenPrices() — REST snapshot companion. All serve normalized TokenPricesData.

UI

  • Prices: useTokenRecentPricesRequest overlays the WS set behind the abWebsocket flag, throttled (~250ms), with an originTs staleness fallback to the REST poll (which never stops polling). useWsPriceOverlay emits freshness metrics.
  • Candles: DataFeed streams the forming bar into TradingView behind wsCandles; the 1s poll stays the backstop, and a monotonic onTick guard prevents series rewrites at a period rollover.
  • Fixes: weekly/monthly CHART_PERIODS NaN; guard empty stream frames.

Tests

Unit (conversion, staleness, DataFeed overlay) + in-process SDK e2e (real socket).

Notes

  • All behind abWebsocket / wsPrices / wsCandles (off by default).
  • The e2e CI step (pr-tests.yml) is omitted from this push (token lacks the workflow scope) — to be added separately.

Phase 2 (FEDEV-3973): stream prices and live candles into the UI and SDK,
behind off-by-default flags with the existing REST/poll as fallback.

- sdk: WsStreamClient transport (isomorphic-ws, reconnect+backoff, snapshot-
  then-stream); v2 watchTokenPrices / watchCandles raw Subscriptions and a
  fetchTokenPrices REST snapshot, all serving normalized TokenPricesData over
  one shared connection
- prices: useTokenRecentPricesRequest overlays the WS set behind the abWebsocket
  flag, throttled, with an originTs staleness fallback to the REST poll;
  useWsPriceOverlay emits freshness metrics
- candles: DataFeed streams the forming bar into TradingView behind wsCandles;
  the poll stays the backstop and a monotonic onTick guard prevents rollover
  rewrites
- fix weekly/monthly CHART_PERIODS NaN and guard empty stream frames; unit +
  e2e tests
@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Jul 2, 2026

Copy link
Copy Markdown

Deploying gmx-interface-home with  Cloudflare Pages  Cloudflare Pages

Latest commit: 1ca4a55
Status: ✅  Deploy successful!
Preview URL: https://1158ba88.gmx-interface-home.pages.dev
Branch Preview URL: https://phase-2-ws-prices-2.gmx-interface-home.pages.dev

View logs

@cursor cursor Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes and found 3 potential issues.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 1ca4a55. Configure here.

wsStatus === "live" &&
wsPrices !== undefined &&
wsOriginTs !== undefined &&
Date.now() - wsOriginTs < WS_PRICES_STALE_MS;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Stale WS prices without rerenders

Medium Severity

The WebSocket freshness gate uses Date.now() - wsOriginTs only during render, so when frames stop and nothing else updates state, wsFresh can stay true long after the 10s threshold. On leaderboard/competition routes the REST poll runs every 60s, so stale streamed prices may keep displaying for up to roughly a minute.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 1ca4a55. Configure here.

pricesData: data?.pricesData,
updatedAt: data?.updatedAt,
pricesData: wsFresh ? wsPrices : data?.pricesData,
updatedAt: wsFresh ? wsOriginTs : data?.updatedAt,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Loading flag ignores WebSocket prices

Medium Severity

When wsFresh is true and pricesData comes from the WebSocket overlay, isPriceDataLoading still mirrors the REST/SWR isLoading flag only. UI that waits on isPriceDataLoading can stay blocked even though live ticker data is already available from the stream.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 1ca4a55. Configure here.

pricesData: data?.pricesData,
updatedAt: data?.updatedAt,
pricesData: wsFresh ? wsPrices : data?.pricesData,
updatedAt: wsFresh ? wsOriginTs : data?.updatedAt,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

WS prices skip native alias

Medium Severity

Fresh WebSocket ticker maps are returned directly as pricesData, but the REST fetcher always copies wrapped-token prices onto NATIVE_TOKEN_ADDRESS. If the stream/API map lacks that zero-address entry, native-token rows in useTokensDataRequest lose prices whenever the WS overlay is active.

Additional Locations (1)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 1ca4a55. Configure here.

@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Jul 2, 2026

Copy link
Copy Markdown

Deploying gmx-interface with  Cloudflare Pages  Cloudflare Pages

Latest commit: 1ca4a55
Status: ✅  Deploy successful!
Preview URL: https://50ddfe96.gmx-interface.pages.dev
Branch Preview URL: https://phase-2-ws-prices-2.gmx-interface.pages.dev

View logs

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.

1 participant