drasi-source-hyperliquid 0.1.2

Hyperliquid market data source plugin for Drasi
Documentation

Hyperliquid Source

A Drasi source that connects to Hyperliquid's public APIs to stream real-time DeFi perpetual and spot market data as a continuously-queryable graph. No API keys required.

What You Can Build

  • Price alert bots — trigger when BTC crosses $100k or ETH drops 5% in a minute
  • Whale watchers — detect trades over $1M in real time
  • Spread monitors — alert when bid-ask spread widens beyond a threshold
  • Funding rate dashboards — track which coins have extreme funding
  • Liquidation feeds — monitor liquidation cascades across assets
  • Cross-asset correlation — join trades, prices, and funding through graph traversal

Quick Start

use drasi_lib::{DrasiLib, Query};
use drasi_reaction_log::LogReaction;
use drasi_source_hyperliquid::{HyperliquidSource, HyperliquidNetwork};
use std::sync::Arc;

#[tokio::main]
async fn main() -> anyhow::Result<()> {
    env_logger::init();

    // Create a source streaming BTC and ETH data
    let source = HyperliquidSource::builder("hl")
        .with_network(HyperliquidNetwork::Mainnet)
        .with_coins(vec!["BTC", "ETH"])
        .with_mid_prices(true)
        .with_trades(true)
        .start_from_now()
        .build()?;

    // Alert when BTC price changes
    let query = Query::cypher("btc-price")
        .query(r#"
            MATCH (m:MidPrice)-[:PRICE_OF]->(c:Coin {name: "BTC"})
            RETURN c.name AS coin, m.price AS price
        "#)
        .from_source("hl")
        .auto_start(true)
        .enable_bootstrap(true)
        .build();

    let reaction = LogReaction::builder("log")
        .from_query("btc-price")
        .build()?;

    let core = Arc::new(
        DrasiLib::builder()
            .with_source(source)
            .with_query(query)
            .with_reaction(reaction)
            .build().await?,
    );

    core.start().await?;
    println!("Streaming... press Ctrl+C to stop");
    tokio::signal::ctrl_c().await?;
    core.stop().await?;
    Ok(())
}

Graph Model

All data flows through a Coin-centric graph. Every market data entity connects back to a Coin node, enabling graph traversal queries that correlate across data types.

                          ┌───────────┐
                          │   Coin    │
                          │ (anchor)  │
                          └─────┬─────┘
                 ┌────────┬─────┼─────┬──────────┐
                 │        │     │     │           │
                 ▼        ▼     ▼     ▼           ▼
              Trade   MidPrice  │  Liquidation  FundingRate
                          OrderBook

See GRAPH_SCHEMA.md for complete property tables, ID formats, and relationship details.

Example Queries

🐋 Whale Detection — Large Trades in Real Time

Continuously alert on trades over $100k notional value:

MATCH (t:Trade)-[:TRADED_ON]->(c:Coin)
WHERE t.price * t.size > 100000
RETURN c.name AS coin, t.side AS side,
       t.price AS price, t.size AS size,
       t.price * t.size AS notional

Every time a whale trade lands, your reaction fires with the coin, direction, and size.

📊 Spread Monitor — Bid-Ask Spread Alert

Alert when any coin's spread widens beyond 0.1%:

MATCH (ob:OrderBook)-[:BOOK_OF]->(c:Coin),
      (m:MidPrice)-[:PRICE_OF]->(c)
WHERE (ob.best_ask_price - ob.best_bid_price) / m.price > 0.001
RETURN c.name AS coin,
       ob.best_bid_price AS bid, ob.best_ask_price AS ask,
       ob.best_ask_price - ob.best_bid_price AS spread,
       m.price AS mid_price

💰 Funding Arbitrage Scanner

Find coins with extreme funding rates (potential arbitrage opportunity):

MATCH (f:FundingRate)-[:FUNDING_OF]->(c:Coin),
      (m:MidPrice)-[:PRICE_OF]->(c)
WHERE f.rate > 0.01 OR f.rate < -0.01
RETURN c.name AS coin, f.rate AS funding_rate,
       f.mark_price AS mark, m.price AS mid,
       f.mark_price - m.price AS basis,
       f.open_interest AS oi

🔥 Liquidation Cascade Detector

Monitor liquidation events alongside funding rates to spot cascades:

MATCH (l:Liquidation)-[:LIQUIDATED_ON]->(c:Coin),
      (f:FundingRate)-[:FUNDING_OF]->(c)
RETURN c.name AS coin, l.side AS liq_side,
       l.price AS liq_price, l.size AS liq_size,
       f.rate AS funding, f.open_interest AS oi

📈 Multi-Asset Price Dashboard

Track real-time prices for your watchlist with leverage info:

MATCH (m:MidPrice)-[:PRICE_OF]->(c:Coin)
RETURN c.name AS coin, c.max_leverage AS leverage,
       c.market_type AS type, m.price AS price

🔗 Cross-Entity Correlation — Price vs Mark vs Funding

Join mid-price, order book, and funding through the Coin node in one query:

MATCH (m:MidPrice)-[:PRICE_OF]->(c:Coin {name: "ETH"}),
      (ob:OrderBook)-[:BOOK_OF]->(c),
      (f:FundingRate)-[:FUNDING_OF]->(c)
RETURN m.price AS mid_price,
       ob.best_bid_price AS bid, ob.best_ask_price AS ask,
       f.mark_price AS mark, f.rate AS funding,
       f.open_interest AS open_interest

🏦 Open Interest Monitor

Alert when a coin's open interest crosses a threshold:

MATCH (f:FundingRate)-[:FUNDING_OF]->(c:Coin)
WHERE f.open_interest > 10000000
RETURN c.name AS coin, f.open_interest AS oi, f.volume_24h AS vol_24h

⚡ High-Leverage Coin Scan

Find all coins offering 50x+ leverage with their current metrics:

MATCH (f:FundingRate)-[:FUNDING_OF]->(c:Coin),
      (m:MidPrice)-[:PRICE_OF]->(c)
WHERE c.max_leverage >= 50
RETURN c.name AS coin, c.max_leverage AS leverage,
       m.price AS price, f.rate AS funding, f.volume_24h AS volume

Configuration

let source = HyperliquidSource::builder("my-source")
    .with_network(HyperliquidNetwork::Mainnet)    // or Testnet, or Custom { rest_url, ws_url }
    .with_coins(vec!["BTC", "ETH", "SOL"])         // or .with_all_coins()
    .with_trades(true)                             // trade events (high volume)
    .with_order_book(true)                         // L2 book snapshots (high volume)
    .with_mid_prices(true)                         // mid-market prices (moderate)
    .with_funding_rates(true)                      // funding rate polling (low volume)
    .with_liquidations(true)                       // liquidation events (sporadic)
    .with_funding_poll_interval_secs(30)           // poll every 30s instead of default 60s
    .start_from_beginning()                        // or .start_from_now() / .start_from_timestamp(ms)
    .build()?;

Config Reference

Field Type Default Description
network HyperliquidNetwork Mainnet API environment
coins CoinSelection All Specific { coins } or All
enable_trades bool false Trade event stream
enable_order_book bool false L2 order book stream
enable_mid_prices bool true Mid-price stream
enable_funding_rates bool false Funding rate polling
enable_liquidations bool false Liquidation event stream
funding_poll_interval_secs u64 60 Funding poll interval
initial_cursor InitialCursor StartFromNow Where to start streaming

Bootstrap & Streaming

Bootstrap (REST): When a query subscribes with enable_bootstrap, the source fetches a snapshot of the relevant current data via Hyperliquid's /info REST endpoints. Coin and SpotPair nodes are always included. MidPrice, FundingRate, and OrderBook are bootstrapped only when their respective streams are enabled.

Streaming (WebSocket + REST polling): The source opens a WebSocket connection and subscribes to enabled channels. Funding rates are polled via REST at the configured interval.

Data Bootstrap Streaming Update Pattern
Coin ✅ Always Insert once, never updated
SpotPair ✅ Always Insert once, never updated
MidPrice ✅ If enabled WebSocket allMids Insert first, then update
OrderBook ✅ If enabled WebSocket l2Book Insert first, then update
FundingRate ✅ If enabled REST poll Insert first, then update
Trade WebSocket trades Insert per event (append-only)
Liquidation WebSocket liquidations Insert per event (append-only)

State Persistence

When a StateStoreProvider is available:

  • Trade deduplication — persists last seen tid per coin; prevents duplicates on WebSocket reconnect
  • Funding snapshots — persists last funding state; skips redundant updates when data hasn't changed

Testing

# Unit tests (no network)
cargo test -p drasi-source-hyperliquid

# Integration test against live mainnet (requires internet)
cargo test -p drasi-source-hyperliquid -- --ignored --nocapture

Troubleshooting

Symptom Check
REST API unreachable Verify connectivity to https://api.hyperliquid.xyz/info
WebSocket errors wscat -c wss://api.hyperliquid.xyz/ws
No changes detected Set RUST_LOG=debug, confirm channels are enabled
Too much data Reduce coin list or disable high-volume streams (trades, l2Book)
Duplicate events on restart Ensure a StateStoreProvider is configured

Limitations

  • No historical replay — WebSocket starts from current data
  • Funding rates are polled, not pushed in real time
  • Subscribing to all trades + order books for all coins is very high volume
  • SpotPair nodes have no relationships (standalone metadata)