nautechsystems/nautilus_trader · error · PyValueError

Hyperliquid does not provide historical market trades via HT

Error message

Hyperliquid does not provide historical market trades via HTTP API

What it means

Hyperliquid's HTTP API does not expose historical market trade ticks, so the Python HTTP client's request_trade_ticks is intentionally a stub that always returns an error through a rejected future. Like the quote stub, this is a permanent capability gap in the adapter rather than a transient or configuration error. Recent trade snapshots are available instead via the dedicated snapshot request method, and live trades via the WebSocket subscription.

Source

Thrown at crates/adapters/hyperliquid/src/python/http.rs:272

        pyo3_async_runtimes::tokio::future_into_py(py, async move {
            Err::<Vec<u8>, _>(to_pyvalue_err(anyhow::anyhow!(
                "Hyperliquid does not provide historical quotes via HTTP API"
            )))
        })
    }

    #[pyo3(name = "request_trade_ticks", signature = (instrument_id, start=None, end=None, limit=None))]
    fn py_request_trade_ticks<'py>(
        &self,
        py: Python<'py>,
        instrument_id: InstrumentId,
        start: Option<jiff::Timestamp>,
        end: Option<jiff::Timestamp>,
        limit: Option<u32>,
    ) -> PyResult<Bound<'py, PyAny>> {
        let _ = (instrument_id, start, end, limit);
        pyo3_async_runtimes::tokio::future_into_py(py, async move {
            Err::<Vec<u8>, _>(to_pyvalue_err(anyhow::anyhow!(
                "Hyperliquid does not provide historical market trades via HTTP API"
            )))
        })
    }

    /// Request the recent public trade snapshot for an instrument.
    ///
    /// Hyperliquid's `recentTrades` endpoint is a bounded newest-first snapshot,
    /// rather than a range-query endpoint. The returned trades are normalized to
    /// ascending event time and then constrained to the requested window.
    ///
    /// A self-hosted node without the indexer responds with HTTP 422. This is
    /// treated as no available coverage so requests can still complete.
    #[pyo3(name = "request_public_trades", signature = (instrument_id, start=None, end=None, limit=None))]
    #[gen_stub(override_return_type(type_repr = "typing.Any", imports = ("typing",)))]
    fn py_request_public_trades<'py>(
        &self,
        py: Python<'py>,

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Use the recent public trade snapshot request method for current trades instead of historical ranges
  2. Subscribe to the trades WebSocket stream and persist trades locally to build history
  3. Route historical trade-tick requests to an adapter/venue that supports them
  4. Use Hyperliquid candle/OHLCV endpoints if bar-level history suffices

Example fix

// before
trades = client.request_trade_ticks(instrument_id, start, end)  # always errors
// after
snapshot = client.request_trade_snapshot(instrument_id)  # supported recent snapshot
client.subscribe_trade_ticks(instrument_id)              # live stream; persist for history
Defensive patterns

Strategy: fallback

Validate before calling

# Python: check capability before requesting historical trades
if isinstance(data_client, HyperliquidDataClient):
    use_trade_snapshot_or_candles()

Type guard

def supports_historical_trades(client) -> bool:
    return not type(client).__name__.startswith("Hyperliquid")

Try / catch

try:
    trades = client.request_trade_ticks(instrument_id, start, end)
except ValueError as e:
    if "historical market trades" in str(e):
        snapshot = client.request_trade_snapshot(instrument_id)  # fallback
    else:
        raise

Prevention

When it happens

Trigger: Calling the Hyperliquid HTTP data client's request_trade_ticks from Python (or via the DataEngine's historical trade-tick request path routed to it), with any arguments.

Common situations: Backfilling trade history through a Hyperliquid data client; porting code from adapters with HTTP trade history; wiring catalog/backtest data loading against Hyperliquid.

Understand the failure class

Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.

Related errors


AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08). Data as JSON: /api/errors/e624070c8f789fed. Report an issue: GitHub.