TWAP algos
Native TWAP order status and execution progress, as it fills.
Status events for Hyperliquid's native TWAP orders: who is running them, total and executed size, executed notional (giving average fill price), duration, and lifecycle status. Useful for large-order detection and flow analysis.
- Method
- hyperliquid.Streaming/StreamData (stream_type: TWAP)
- Endpoint
- stream.hyperliquidrpc.com:443 · gRPC over TLS (HTTP/2)
- Auth
- API key in x-api-key metadata
- Volume
- Low volume relative to fills, since only institutional TWAPs appear here. Cheap to subscribe to platform-wide.
When to use it
Native TWAPs are how size moves quietly on Hyperliquid. This stream announces them: who started a TWAP, in which market, how big, over how many minutes, and, as progress events arrive, how much has executed at what notional. Use it for large-order detection, flow-aware execution (trade around a TWAP, not into it), and studying how algorithmic sell/buy programs move markets.
Volume is low (institutional TWAPs only), so a platform-wide, unfiltered subscription is cheap. The individual child fills are not here; they arrive on the trades stream tagged with the same twap_id.
Method
// stream.hyperliquidrpc.com:443 — gRPC over TLS (HTTP/2)// auth: API key in x-api-key metadata · server reflection enabledpackage hyperliquid; service Streaming { // Bidirectional: send one subscription, then read updates. // Subscribe with stream_type: TWAP. rpc StreamData (stream SubscribeRequest) returns (stream SubscribeUpdate);}QuickNode-compatible StreamData with stream_type: TWAP. Each update carries the block number and the TWAP event payload as JSON.
Subscribe
# StreamData is bidirectional; grpcurl sends the subscription for you.grpcurl -H 'x-api-key: YOUR_KEY' \ -d '{"subscribe":{"stream_type":"TWAP"}}' \ stream.hyperliquidrpc.com:443 \ hyperliquid.Streaming/StreamDataThe example subscribes platform-wide. Add coin or user filters to narrow to one market or one wallet's algos.
Message fields
Fields typed string that carry numbers are byte-exact decimal strings, verbatim from the node. Compare and store them as strings or arbitrary-precision decimals. Never parseFloat a price you intend to reconcile.
Server-side filters
- coins[]
- wallets[]
- replay from a block height
Filters are applied on the server, so filtered-out messages never leave our edge. You only pay for what you subscribe to. Request shapes for every stream family are on Filtering; backfill semantics on Replay & backfill.
Semantics & gotchas
Event stream: one message per TWAP status change or progress update, in block order.
- One TWAP, many messages. You receive a message per status change and progress update. Key your state on
twap_idand treat each message as the latest view of that parent order. - Average fill price is a division away.
executed_ntl / executed_szgives the running average fill price. Both are byte-exact decimal strings; divide as decimals, not floats. - Lifecycle has four terminal-ish states.
activatedstarts the clock;finished,canceled, andterminatedend it. A canceled TWAP keeps whatever it executed. - Child fills live on the trades stream. Fills belonging to a TWAP carry its
twap_idon the trades/swaps feed. Join the two streams for slice-by-slice execution detail.
Sample message
{ "block_height": 612408201, "twap_id": 48112, "coin": "HYPE", "user": "0xa4f17bd09e26c3158c0b7341fa882ce05d97b264", "side": "B", "sz": "25000.00", "executed_sz": "9412.36", "executed_ntl": "116214.872340", "minutes": 60, "randomize": true, "status": "activated"}Low volume relative to fills, since only institutional TWAPs appear here. Cheap to subscribe to platform-wide.
Recipes
Alert on large TWAPs as they start
Watch activated events and flag programs whose total size matters in their market. A 60-minute sell program announced at activation is actionable information for the entire window.
from decimal import Decimal for update in stub.StreamData(iter([subscribe]), metadata=meta): ev = json.loads(update.data.data) if ev["status"] == "activated" and Decimal(ev["sz"]) > Decimal("10000"): alert(ev["coin"], ev["user"], ev["sz"], ev["minutes"])Track execution progress and slippage
On each progress update, compute the running average fill price and compare it to the mark at activation. This measures what the program is paying for its patience.
from decimal import Decimal ev = json.loads(update.data.data)if Decimal(ev["executed_sz"]) > 0: avg_px = Decimal(ev["executed_ntl"]) / Decimal(ev["executed_sz"]) done = Decimal(ev["executed_sz"]) / Decimal(ev["sz"]) # fraction completeJoin child fills by twap_id
Subscribe to trades for the same market and group fills by twap_id. You get each slice's exact price, size, and timing: the full execution trace of someone else's algo.