Add real Hyperliquid WS feed, reconnect/stall detection, and fallback… - #59
Conversation
…-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.
There was a problem hiding this comment.
💡 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".
|
|
||
| const PRICE_PUBLISH_INTERVAL_MS = 1_000; | ||
| setInterval(() => { | ||
| const mids = hyperliquidWs.getMids(); |
There was a problem hiding this comment.
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 👍 / 👎.
| ws.on('message', (raw) => { | ||
| lastMessageAt = new Date(); | ||
| resetStallTimer(); |
There was a problem hiding this comment.
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 👍 / 👎.
…-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.
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.