Open
Upside markets route automatically. Upside pairs (formerly “zero-fee”/ZFP)
are separate markets suffixed
_UPSIDE — e.g. BTC_UPSIDE/USD next to
BTC/USD. Opening one sends the PnL (Upside) order type by itself: no
open/close fee, a tiered profit share on gains instead. There is no flag to
pass — the pair determines the order type (the contract rejects any
mismatch). Upside pairs are market-only: no limit/stop opens and no TWAP.
See Markets for discovering them.Open sized in coin units
market_open_coin targets a coin exposure (e.g. 0.5 ETH) instead of a leverage-derived notional. The fill leverage floats within [min_leverage, max_leverage].
market_open_coin also accepts open_price, with the same semantics as market_open.
Close
Close by collateral (partial or full) or by coin exposure:
Closes route from the pair too: a position on an Upside pair closes with the
PnL close type automatically (
Position.is_upside is informational — you
don’t pass it anywhere).
Track the order lifecycle
Market orders route through the batched-market service, which streams the lifecycle back:MarketOrderAccepted → MarketOrderInitiated (on-chain
order id + tx hash) → MarketOrderExecuted, with zero or more non-terminal
AttemptFailed events in between when an attempt hits a retryable condition
(see the batched-market reference). With
the default wait=True the receipt already reflects the executed fill:
slippage_percent)
raises RelayError instead of returning a receipt; on a terminal Error
event the exception’s .code carries the machine-readable reason (a
contract error name like WrongSl, or a service code like
ATTEMPTS_EXHAUSTED).
Watch the journey while the SDK settles
Want the SDK’s settle logic and live visibility of the journey — e.g. to logAttemptFailed diagnostics for later debugging? Pass on_event= (all
market open/close/increase methods take it). The hook is called once per
lifecycle event, in stream order, while the call still blocks until settled:
MarketOrderAccepted, each retryable
AttemptFailed ({attempt, code, message, willRetry}), unknown
informational types the server may add, the initiation event, and the
terminal — including when the terminal makes the call raise, so a
journey log is complete on failures. If the stream view times out, the hook
also sees the connection-scoped STREAM_TIMEOUT Error and then each event
recovered via status polling, every event exactly once.
Notes:
- Relayer route only (the direct RPC route has no lifecycle stream).
- Sync and async callables both work; keep the hook fast — it runs inline on the client’s event loop.
- Exceptions from the hook propagate and abort the local wait; the order
keeps executing server-side (settle with
client.engine.batched_market.wait(tracking_id)).
wait=False the call returns at MarketOrderAccepted. At that point
tx_hash is still None and you settle later from the tracking_id:
client.engine.batched_market.status(tracking_id, after_seq=n) is the
non-blocking single poll. Every event carries a seq, so you can resume
replay after a crash without missing or double-processing events. wait()
also takes on_event= and delivers each newly replayed event to it live.
The executed fill payload
The terminalMarketOrderExecuted event carries the final trade as it
executed on-chain — no follow-up positions query is needed to learn the
fill. It’s available as outcome.terminal.data (and as receipt.raw with
the default wait=True):
Every numeric field is a string in raw on-chain units (several exceed
float precision); convert with
from_usdc / from_1e10 from
avantis_trader_sdk.types.
Size increases terminate with PositionSizeIncreased instead, which is
deliberately a different shape: there is no fill price /
percentProfit / usdcSentToTrader; it reports coinExposureAdded plus
t = the blended resulting position (open price, leverage and
collateral recomputed on-chain across the old and new size).
For position-level confirmation, client.account.positions() reflects the
fill after execution; see Core concepts.