Skip to content

Add real Hyperliquid WS feed, reconnect/stall detection, and fallback… - #59

Merged
jamalfrnk merged 1 commit into
mainfrom
feat/market-feed-recovery
Aug 1, 2026
Merged

Add real Hyperliquid WS feed, reconnect/stall detection, and fallback…#59
jamalfrnk merged 1 commit into
mainfrom
feat/market-feed-recovery

Conversation

@jamalfrnk

Copy link
Copy Markdown
Owner

…-source execution gating

DATA-RECOVERY-001 (issue #35) closes the gap DATA-HL-001 explicitly deferred: a genuinely live Hyperliquid price feed, resilient reconnection, and a hard block on new paper orders executing against a stale/fallback price.

  • hyperliquidWs.ts: real WS client for wss://api.hyperliquid.xyz/ws (allMids), with exponential backoff + jitter reconnection and silent-stall detection (a message-reset timer independent of the socket's own close event).
  • marketHealth.ts: pure computeMarketDataMode() combining WS + REST ingestion health into live | degraded | fallback | unavailable, exposed on GET /api/market-data/health alongside raw WS health.
  • risk/limits.ts: new checkTrustworthySource check wired into both new-order placement and the resting-limit-order sweep in paperEngine.ts, rejecting any order priced off a CoinGecko-fallback row.
  • server.ts: instantiates the shared WS client and a 1s per-symbol broadcast loop, merging live mid prices with last-known change24h/volume/source from the existing REST ingestion cycle (ingestion.ts's new getLastKnownMarketMeta), since the WS channel doesn't carry those fields.

Verified against live Hyperliquid mainnet end-to-end (not just unit tests): connected the real WS client, confirmed /api/market-data/health reports mode: "live", measured ~1 update/sec/symbol via a real client socket, and confirmed a real guest-session paper order still fills correctly with no regression from the new gating. Full server suite: 191/191 passing.

Closes #35.

…-source execution gating

DATA-RECOVERY-001 (issue #35) closes the gap DATA-HL-001 explicitly deferred:
a genuinely live Hyperliquid price feed, resilient reconnection, and a hard
block on new paper orders executing against a stale/fallback price.

- hyperliquidWs.ts: real WS client for wss://api.hyperliquid.xyz/ws (allMids),
  with exponential backoff + jitter reconnection and silent-stall detection
  (a message-reset timer independent of the socket's own close event).
- marketHealth.ts: pure computeMarketDataMode() combining WS + REST ingestion
  health into live | degraded | fallback | unavailable, exposed on
  GET /api/market-data/health alongside raw WS health.
- risk/limits.ts: new checkTrustworthySource check wired into both new-order
  placement and the resting-limit-order sweep in paperEngine.ts, rejecting
  any order priced off a CoinGecko-fallback row.
- server.ts: instantiates the shared WS client and a 1s per-symbol broadcast
  loop, merging live mid prices with last-known change24h/volume/source from
  the existing REST ingestion cycle (ingestion.ts's new
  getLastKnownMarketMeta), since the WS channel doesn't carry those fields.

Verified against live Hyperliquid mainnet end-to-end (not just unit tests):
connected the real WS client, confirmed /api/market-data/health reports
mode: "live", measured ~1 update/sec/symbol via a real client socket, and
confirmed a real guest-session paper order still fills correctly with no
regression from the new gating. Full server suite: 191/191 passing.

Closes #35.
@jamalfrnk
jamalfrnk merged commit 4088caf into main Aug 1, 2026
3 checks passed

@chatgpt-codex-connector chatgpt-codex-connector Bot 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 6a26af1526

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread server/src/server.ts

const PRICE_PUBLISH_INTERVAL_MS = 1_000;
setInterval(() => {
const mids = hyperliquidWs.getMids();

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Stop republishing disconnected WS prices as fresh

When the upstream socket closes or stalls after delivering at least one snapshot, getMids() retains that snapshot and this interval continues broadcasting it indefinitely without checking getHealth(). Each broadcast assigns a new timestamp and labels the cached value as Hyperliquid-sourced, so client/src/features/realtime/useMarketDataSocket.ts marks it stale: false; it also overwrites a correctly labeled CoinGecko fallback update within one second. Publish only while the WS has a recent valid message, or preserve the snapshot's original receipt time so stale/disconnected data cannot masquerade as live.

Useful? React with 👍 / 👎.

Comment on lines +100 to +102
ws.on('message', (raw) => {
lastMessageAt = new Date();
resetStallTimer();

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Record feed freshness only after validating allMids

If Hyperliquid sends a subscription acknowledgement, wrong-channel frame, malformed JSON, or an allMids payload that fails schema validation, these lines still refresh lastMessageAt and reset the stall timer before the frame is rejected. Repeated unusable frames therefore keep /api/market-data/health in live mode and prevent stall recovery even though no price can be consumed; track valid-data freshness separately and update it only after a successful AllMidsResponseSchema parse.

Useful? React with 👍 / 👎.

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.

DATA-RECOVERY-001: Add feed recovery, stale handling, fallback, and provider health

1 participant