BlogDeveloper

How to Build a Hyperliquid TWAP Execution Tool

Build a TWAP execution tool on Hyperliquid: native TWAP orders vs your own slicing, tracking slice fills, and seeing every active TWAP in a market.

HydromancerTeam
How to Build a Hyperliquid TWAP Execution Tool

TWAP stands for time-weighted average price. Instead of buying $500,000 of BTC at once and pushing the price against yourself, you split it into small pieces spread over hours. Funds, treasuries and anyone moving size use it to get a price close to the market's average over that time.

Why traders split big orders this way:

• To avoid moving the price against themselves. One large market order eats through the book and fills at worse and worse prices.
• To get a fair average price over hours, instead of betting everything on one moment.
• To hide size. Small, steady slices draw less attention than one big order.
• To show a fair execution. Funds and treasuries can point to the average price as their benchmark.

Why should you choose to build a TWAP execution tool on Hyperliquid?

• Plenty of size moves this way. We counted 44 TWAPs running on BTC alone, 33 of them buying.
• The built-in TWAP is fixed once it starts. You choose the size and the time (5 minutes to 7 days, $100 minimum), and after that you can only cancel it.
• A tool adds what it leaves out. Pause when the spread widens, stop at a price limit, report how the fill compared with the market.
• It can show the whole market. Users see what everyone else's TWAPs in a market are doing before they start their own.
• Execution tools pay for themselves. Tread.fi, which runs TWAP and other execution algorithms across several exchanges, is sitting on $2.39M in Hyperliquid builder fees as of Flowscan's 2 October 2026 count (top builders by revenue).

You can build one two ways on Hyperliquid, and the choice decides most of the design. We tried both on 31 October 2026. The one feature where the APIs differ, a live count of everyone's TWAPs in a market, we built and timed on each. Skip the code if it's not your thing.

Option 1: Use Hyperliquid's built-in TWAP

Hyperliquid runs TWAP orders on-chain. You send one twapOrder action with the size and the duration in minutes, and Hyperliquid places the suborders for you. Per its order types docs, suborders go out at regular intervals of at least 30 seconds, and each has a maximum slippage of 3%. A TWAP runs from 5 minutes to 7 days, with a $100 minimum total. If slices fall behind, later ones grow (up to 3 times the normal size) to catch up.

Three settings make it more useful than a plain timer: randomize varies each slice by up to 20% so it's harder to spot, a trigger price starts the TWAP only when the mark price gets there, and a max/min price stops slices filling beyond a limit. As an example from the docs, $10,000 over one hour becomes about 121 slices of $83, one every 30 seconds.

Your tool then reports progress. userTwapSliceFills lists the pieces that filled (2,000 is the most this request returns):

code
import requests

URL = "https://api.hyperliquid.xyz/info"
USER = "0x0405b6fe11f41ea3f28cbba3fd3015be402bfba9"
fills = requests.post(URL, json={"type": "userTwapSliceFills",
                                 "user": USER}).json()
f = fills[0]["fill"]
print(len(fills), "slice fills; latest:", f["coin"], f["side"], f["sz"],
      "@", f["px"], "TWAP id", fills[0]["twapId"])
code
2000 slice fills; latest: BTC B 0.00016 @ 77421.0 TWAP id 2451531

That user's BTC TWAP had been running for about 31 hours of a seven-day schedule when we checked, and was about 19% done. The twapStates stream and userTwapHistory give live status and finished TWAPs for one user.

Good for: a simple "buy X over Y hours" button. Less good for: custom logic, such as pausing when the spread widens or speeding up when the price dips, because you can't change a running TWAP, only cancel it. The catch for a business: a twapOrder has no builder field, so a built-in TWAP earns you no builder fee.

Option 2: Slice the order yourself

Your tool places each child order itself: a limit or IOC order every N seconds, sized from what's left. That gives you full control: randomized timing, price limits that follow the book, pausing on wide spreads.

It also means your tool handles what Hyperliquid otherwise does for you: each child order is a normal signed order on /exchange, counts against the account's request budget, and has to meet the $10 minimum order value. The upside: every slice is an order your builder code earns on, so a seven-day TWAP pays out slice by slice.

To pace child orders well, you need to know what a slice of a given size costs. Hydromancer's slippageHistory gives you that cost through the day, not just right now (the funding arbitrage guide runs it), so pick the slice size whose worst hour you can live with.

See every TWAP running in a market

This is the part only market-wide data can do. A big TWAP buying BTC for seven days is information: it tells you there's a steady buyer, and it competes with your own slices. We built a "how many TWAPs are buying or selling BTC right now" counter on both APIs and ran them back to back.

Hyperliquid API

Hyperliquid has no request that lists every user's TWAPs, but you can find them. TWAP slices show up in the public trade feed with an all-zero transaction hash, so step one listens to BTC trades for two minutes and saves the wallets behind those trades to a file, one address per line:

code
import json, time
from websockets.sync.client import connect

ZERO, wallets, end = "0x" + "0" * 64, set(), time.time() + 120
with connect("wss://api.hyperliquid.xyz/ws") as ws:
    ws.send(json.dumps({"method": "subscribe", "subscription":
                        {"type": "trades", "coin": "BTC"}}))
    while time.time() < end:
        m = json.loads(ws.recv())
        for t in m["data"] if m["channel"] == "trades" else []:
            if t["hash"] == ZERO:              # TWAP slices have no hash
                wallets.add(t["users"][t["side"] == "A"])   # the taker
open("twap_wallets.txt", "w").write("\n".join(wallets))
print(len(wallets), "wallets traded a TWAP slice in 2 minutes")
code
18 wallets traded a TWAP slice in 2 minutes

Step two asks twapHistory for each of those wallets and keeps the TWAPs still running:

code
import time, requests

URL, twaps = "https://api.hyperliquid.xyz/info", {}
for u in open("twap_wallets.txt").read().split():
    rows = requests.post(URL, json={"type": "twapHistory", "user": u})
    for h in rows.json():                     # newest first
        twaps.setdefault((u, h.get("twapId"), h["state"]["timestamp"]), h)
    time.sleep(7)                             # stay under 1,200 a minute
live = [h for h in twaps.values() if h["status"]["status"] == "activated"
        and h["state"]["coin"] == "BTC"]
buys = sum(h["state"]["side"] == "B" for h in live)
print(len(live), "active BTC TWAPs:", buys, "buying,", len(live) - buys,
      "selling")
code
19 active BTC TWAPs: 14 buying, 5 selling

An all-zero hash isn't only TWAPs: in a sample of 410 such fills, half had no TWAP id, so the lookup step is what confirms each one. And this only finds TWAPs that happened to place a slice while you were listening.

Long, slow TWAPs place a slice every few minutes, so a two-minute listen misses many of them. The complete route on Hyperliquid alone is your own node with --write-fills, which also writes every TWAP's status to disk.

Hydromancer API

perpTwapSnapshots returns every active TWAP in the markets you ask for, with address, side, total size, how much has filled and when the next slice is due. The reply is compressed, so this one also needs pip install msgpack zstandard:

code
import os, msgpack, requests

H = {"Authorization": "Bearer " + os.environ["HYDROMANCER_API_KEY"]}
r = requests.post("https://api.hydromancer.xyz/info", headers=H,
                  json={"type": "perpTwapSnapshots", "market_names": ["BTC"]})
twaps = msgpack.unpackb(r.content)[2]     # every active BTC TWAP
buys = sum(1 for t in twaps if t[3])
print(len(twaps), "active BTC TWAPs:", buys, "buying,", len(twaps) - buys,
      "selling")
code
44 active BTC TWAPs: 33 buying, 11 selling

Side by side

Hyperliquid API Hydromancer API
Active BTC TWAPs found1944
Worked1 of 1 runs1 of 1 runs
Time to finish (median)251 s (listens live by design)0.2 s
Requests181
Rate-limit cost1,179 weight (limit: 1,200 a minute per IP)1 download of the 5 allowed every 10 minutes
Data received over REST (uncompressed)5.3 MBunder 0.1 MB

The Hyperliquid route sees fewer than half the TWAPs that are actually running, which is a different market picture, not just a slower one. An execution tool can show users "33 TWAPs are buying BTC right now" next to their own order, or delay its own slices away from a large one. The snapshot is limited to 5 requests every 10 minutes, so poll it, don't stream it; allTwapStatusUpdates streams changes in between.

Picking between the two

Built-in TWAP Your own slicing
Placing piecesHyperliquid does itYour code does it
Custom rulesFixed once startedAnything you can code
Requests from your appOne to start, one to cancelOne per slice
ProgressuserTwapSliceFills, twapStatesYour own order records
Builder feeNot possible (no builder field)On every slice

Either way, Hyperliquid's free API runs the execution. Hydromancer helps you size and time it: slippage history for slice size, and the market-wide TWAP view.

FAQ

Can you place a TWAP on Hyperliquid?

Yes. Hyperliquid runs TWAP orders natively: you send one twapOrder with size and duration, and suborders go out at regular intervals of at least 30 seconds, each with a maximum slippage of 3%.

How do I see other traders' TWAP orders on Hyperliquid?

On the official API, per wallet: find wallets placing TWAP slices in the trade feed (they have an all-zero hash), then read each one's twapHistory. In our test that found 19 of 44 active BTC TWAPs in four minutes. Hydromancer's perpTwapSnapshots returns every active TWAP in a market in one request.

How do TWAP orders work on Hyperliquid?

You choose a size and a running time, from 5 minutes to 7 days, with a $100 minimum. Hyperliquid splits the order into suborders sent at a fixed interval, as often as every 30 seconds, aiming to have filled elapsed time divided by total time of the size at each point. Once it starts, you can cancel it but not change it.

Why use a TWAP instead of a market order?

For large orders, because each small slice moves the price less, so you pay less market impact than one big order eating through the book. For small orders, a single limit order is simpler and cheaper.

• How to build a Hyperliquid trading bot
• Hyperliquid fees and revenue
• Hyperliquid rate limits explained
• Hyperliquid tick size and lot size

Sources

- Hyperliquid docs: Order types, Exchange endpoint, Builder codes
- Hydromancer docs: perpTwapSnapshots, slippageHistory

Continue