Skip to content

[Hyperliquid] Expose public WebSocket allMids as CustomData source #3980

@graceyangfan

Description

@graceyangfan

Feature Request

Summary

Hyperliquid provides a public WebSocket channel allMids that returns a snapshot of the mid-price for every tradable coin in a single message. The underlying WebSocket infrastructure in the Hyperliquid adapter already supports this channel (HyperliquidWsChannel::AllMids, SubscriptionRequest::AllMids, and handler parsing are all in place), but the LiveDataClient does not expose a subscription interface. Strategies therefore cannot consume this unique full-market data source through the standard Nautilus framework.

Current State

  • HyperliquidWsChannel::AllMids is fully defined in crates/adapters/hyperliquid/src/websocket/enums.rs.
  • SubscriptionRequest::AllMids { dex } and its topic formatting exist in websocket/handler.rs.
  • The WebSocket codec already deserializes allMids messages into AllMidsData { mids: AHashMap<String, String> }.
  • However, HyperliquidDataClient has no subscribe_all_mids() method, so there is no path for a strategy or actor to request this stream.
  • Because allMids is an instrument-agnostic, full-market snapshot (not a per-instrument stream), it does not fit the standard SubscribeQuotes / SubscribeMarkPrices pattern and needs a dedicated SubscribeCustomData path.

Proposed Change

Expose the existing allMids stream as a CustomData source, keeping all changes inside the Hyperliquid adapter crate.

  1. Adapter data type
    Define a new struct implementing CustomDataTrait:

    pub struct HyperliquidAllMids {
        pub mids: HashMap<InstrumentId, Price>,   // coin → mid price
        pub ts_event: UnixNanos,
        pub ts_init: UnixNanos,
    }

    The handler should use the existing instruments_cache to map raw coin symbols (e.g. "BTC") to InstrumentIds so that Python strategies receive familiar identifiers.

  2. WebSocket handler
    In the handler’s AllMids branch (currently the parsed data is likely unused or returned raw), convert AllMidsData into HyperliquidAllMids and emit it as NautilusWsMessage::Data(vec![Data::Custom(...)]).

  3. Data client
    Add subscribe_all_mids(&mut self) to HyperliquidDataClient, issuing a SubscribeCustomData command with DataType::new("HyperliquidAllMids", None, None). The unsubscribe path should send the corresponding UnsubscribeCustomData.

  4. Python bindings
    Expose HyperliquidAllMids through PyO3 so it can be imported and down-casted in on_data.

Why This Matters

  • allMids is a unique exchange feature: very few venues offer a single message containing every tradable mid-price. It is extremely bandwidth-efficient for market-scanning logic.
  • Cross-coin analytics: strategies can compute real-time correlation matrices, market-breadth indicators, or identify relative-value deviations without maintaining hundreds of individual quote subscriptions.
  • Scanner / stat-arb strategies: a single allMids message every second can drive a universe-selection model that then subscribes to L2 books for only the most promising pairs.
  • Since the WebSocket plumbing is already complete, the remaining work is primarily surfacing the data into the Nautilus event framework via CustomData.

Example Usage (Python)

from nautilus_trader.adapters.hyperliquid.data import HyperliquidAllMids

class MarketScanner(Actor):
    def on_data(self, data):
        if isinstance(data, HyperliquidAllMids):
            # Compute market median deviation in a single shot
            for inst_id, mid in data.mids.items():
                self.log.debug(f"{inst_id}: {mid}")

References

  • Hyperliquid WebSocket docs: allMids subscription
    https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/websocket
  • Existing AllMids enum, request, and data structures:
    crates/adapters/hyperliquid/src/websocket/enums.rs:45
    crates/adapters/hyperliquid/src/websocket/messages.rs:378
    crates/adapters/hyperliquid/src/websocket/handler.rs:805
  • Nautilus CustomData / CustomDataTrait extension mechanism:
    crates/model/src/data/custom.rs

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions