Create Trade
POST /api/v1/tradesScope: trades:write
Submit a new spread trade. Returns immediately with a trade_id; execution
happens asynchronously.
Request
{
"market": "HYPE",
"long_exchange": "lighter",
"long_wallet": "0xYourWalletAddressHere",
"short_exchange": "extended",
"short_wallet": "0xYourWalletAddressHere",
"target_spread": "0",
"spread_condition": "gte",
"target_size": "2",
"execution_type": "maker_taker",
"maker_leg": "long",
"max_slippage": "0.1",
"size_type": "base",
"spread_type": "absolute"
}Required fields
| Field | Type | Description |
|---|---|---|
market | string | Trading pair symbol (e.g. HYPE, BTC, ETH) |
long_exchange | string | Exchange for the long leg |
long_wallet | string | Wallet address for the long leg |
short_exchange | string | Exchange for the short leg (must differ from long_exchange) |
short_wallet | string | Wallet address for the short leg |
target_spread | string | Target spread value (decimal string, in units of spread_type) |
spread_condition | string | One of gte, gt, lte, lt, eq |
target_size | string | Total size to fill (positive decimal) |
execution_type | string | maker_taker |
maker_leg | string | long or short |
max_slippage | string | Maximum allowed slippage (non-negative decimal) |
Optional fields
| Field | Type | Default | Description |
|---|---|---|---|
size_type | string | base | base (token amount) or notional (USD amount) |
spread_type | string | absolute | absolute (raw USD price difference), percentage (% of hedge reference price), bps (basis points of hedge reference price), or ticks (multiples of the coarser leg's tick size) |
idempotency_key | string | — | See idempotency below — required via header or body |
Idempotency (required)
Every create request must carry an idempotency key — either the
X-Idempotency-Key header (preferred; takes precedence) or the
idempotency_key body field. Missing key → 400. Keys must match
^[a-zA-Z0-9_-]{1,128}$ (a UUID works).
Replaying a key returns 200 OK with the original trade and
"idempotent": true — no new trade is created:
{
"trade_id": "00000000-0000-0000-0000-000000000000",
"status": "active",
"rate_budget": 20,
"idempotent": true
}Response
202 Accepted
{
"trade_id": "00000000-0000-0000-0000-000000000000",
"status": "pending",
"rate_budget": 20
}The rate_budget is the per-second request budget Spreadr has allocated to
this trade against the maker exchange's per-account rate limit.
When the hedge exchange enforces a per-account limit that other legs of yours
share, the response also carries hedge_rate_budget: the per-second budget
allocated to this trade's hedge leg. Both budgets are re-divided live as your
trades on those accounts start and finish.
Aggressive quoting and the fast-move guard
quote_mode: "aggressive" (maker-taker only) pegs the maker up to, or across,
the touch to fill now, bounded by worst_spread (same units as
target_spread; omitted = peg to the touch). Because an aggressive order rests
inside the spread, a fast move of the hedge reference can run it over before a
re-quote lands. The fast-move guard watches for that:
| Field | Values | Default |
|---|---|---|
fast_move_guard | shadow (evaluate and record only), on (cancel the resting order when the hedge reference moves against it by the threshold inside the window, then hold quoting until the book settles), off | shadow for aggressive trades |
fast_move_guard_bps | explicit trigger threshold, 0 < x <= 1000 | the resting order's distance to the hedge reference (its quote cushion), floored at 10 bps |
fast_move_window_ms | 50–5000 | 250 |
fast_move_settle_ms | 50–10000 | 500 (a hold is capped at 3 s while the book stays fast) |
Every trigger appears in GET /trades/{id}/events as a fast_move_guard
event (move, threshold, references, action), hedge_outcome events carry
guard_fill_class (after_trigger: a fill inside the settle window of a
trigger; adverse: a fill whose move met the threshold with no trigger), and
fast_move_guard_stats is written on the trade when it ends.
Validations
The server enforces these before accepting the trade:
- Both exchanges must have active credentials linked for the specified
wallets, and the wallets must belong to your account (
403otherwise). - System and both exchanges must not be in maintenance mode (
503). - The global kill switch must not be active (
503). long_exchangeandshort_exchangemust differ.marketmust be recognized on both exchanges — not tradeable on one or both, or ambiguous between the two, returns400(use the canonical symbol fromGET /api/v1/markets).- Concurrent maker-trade cap per (wallet, maker exchange), counting only
trades where the wallet is on the maker leg. The cap varies by venue
(currently: Lighter 1; Hyperliquid, Orderly, Aster 2; Extended 3;
trade[xyz] shares Hyperliquid's cap — all subject to change). Exceeding it
returns
409("max N concurrent maker trades on {exchange} — already has M active"). - Sufficient account-level rate budget on the maker exchange (
429).
Example
curl -X POST https://api.spreadr.xyz/api/v1/trades \
-H "X-API-Key: sprdr_..." \
-H "X-Idempotency-Key: my-bot-001" \
-H "Content-Type: application/json" \
-d '{
"market": "HYPE",
"long_exchange": "lighter",
"long_wallet": "0xYourWalletAddressHere",
"short_exchange": "extended",
"short_wallet": "0xYourWalletAddressHere",
"target_spread": "0",
"spread_condition": "gte",
"target_size": "2",
"execution_type": "maker_taker",
"maker_leg": "long",
"max_slippage": "0.1"
}'