From c959c3d99297490eea6e477dbab3a8cb09204c4c Mon Sep 17 00:00:00 2001 From: "Samuel EF. Tinnerholm" Date: Sun, 21 Jun 2026 19:16:15 +0200 Subject: [PATCH] fix(hyperliquid): honor marketId/eventId filters and OHLCV/trades limit MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit HL fetcher silently ignored four filters that the unified API contract promises: - fetchRawMarkets ignored params.marketId — fetchMarket(marketId=X) returned the first market in the venue list instead of X - fetchRawMarkets / fetchRawEvents ignored params.eventId — fetchEvent always returned the first question - fetchRawOHLCV ignored params.limit — returned the entire window - fetchRawTrades ignored params.limit — returned a fixed page These all passed the prior smoke matrix because it only checked 'did the call throw'. The new assertion-based verify suite catches each one (45/45 pass after fix, both SDKs). marketId filter uses fromMarketId so it accepts either canonical hl-outcome-{N} or a raw outcome token, matching the resolution we added for fetchOrderBook / fetchOHLCV / fetchTrades single-fetch. Limit slicing is client-side after the venue call returns, since HL's candleSnapshot and recentTrades both return a fixed window/page. --- core/src/exchanges/hyperliquid/fetcher.ts | 32 ++++++++++++++++++++--- 1 file changed, 29 insertions(+), 3 deletions(-) diff --git a/core/src/exchanges/hyperliquid/fetcher.ts b/core/src/exchanges/hyperliquid/fetcher.ts index a53aab7a..036952b2 100644 --- a/core/src/exchanges/hyperliquid/fetcher.ts +++ b/core/src/exchanges/hyperliquid/fetcher.ts @@ -226,6 +226,22 @@ export class HyperliquidFetcher implements IExchangeFetcher r.outcome.outcome === targetOutcomeId); + } catch { + results = []; + } + } + + // Filter by parent eventId (HL question number) + if ((params as any)?.eventId !== undefined && (params as any).eventId !== null) { + const targetEventId = String((params as any).eventId); + results = results.filter(r => r.question && String(r.question.question) === targetEventId); + } + // Limit const limit = params?.limit || 250000; const offset = params?.offset || 0; @@ -239,6 +255,12 @@ export class HyperliquidFetcher implements IExchangeFetcher String(q.question) === targetEventId); + } + // Filter by query if (params?.query) { const lowerQuery = params.query.toLowerCase(); @@ -278,18 +300,22 @@ export class HyperliquidFetcher implements IExchangeFetcher({ + const raw = await this.postInfo({ type: 'candleSnapshot', req: { coin, interval: params.resolution || '1h', startTime, endTime }, }); + // ponytail: HL returns the full window; honor caller's limit by trimming to the most recent N + return params.limit && raw.length > params.limit ? raw.slice(-params.limit) : raw; } // -- Trades ---------------------------------------------------------------- - async fetchRawTrades(marketId: string, _params: TradesParams): Promise { + async fetchRawTrades(marketId: string, params: TradesParams): Promise { const outcomeId = fromMarketId(marketId); const coin = toCoinNotation(outcomeId, 'yes'); - return this.postInfo({ type: 'recentTrades', coin }); + const raw = await this.postInfo({ type: 'recentTrades', coin }); + // ponytail: HL recentTrades returns a fixed page; honor caller's limit (most recent N) + return params?.limit && raw.length > params.limit ? raw.slice(0, params.limit) : raw; } // -- User data -------------------------------------------------------------