Skip to main content

Monaco Protocol SDK v1.0.46

This release adds two things: a post-execution transaction cost analysis (TCA) report for TWAP parent orders — realized average price scored against the arrival price and a window-TWAP benchmark, with signed basis points for both — and a typed sdk.ws.instruments() subscription for the public instrument WebSocket channel that shipped server-side in v1.0.45, which until now was reachable only over the raw WebSocket protocol. Both surfaces are additive; nothing existing changes shape, so the upgrade is drop-in with no action required.

Added

TWAP transaction cost analysis (getTwapOrderTca)

sdk.trading.getTwapOrderTca(twapOrderId) (GET /api/v1/orders/twap/{twapOrderId}/tca; gRPC OrdersService.GetTwapOrderTca) returns a post-execution TCA report for a terminal TWAP parent — available once the parent is COMPLETED or CANCELLED; a non-terminal parent returns 400. The report scores the parent’s realized average price against two references over its active window (windowStartAt to windowTerminalAt — the actual start-to-terminal span, never the planned end): the arrival price (the reference series’ latest minute bucket closing at or before the window start) and the window-TWAP benchmark (the average reference price over the window’s sealed minute buckets). benchmarkSource names the one series both references came from — risk_mark_1m for marked pairs, with ohlcv_1m_close as the spot fallback. The two derived scores, slippageVsArrivalBps and performanceVsBenchmarkBps, are signed basis points at 4 decimal places, and positive always means the execution beat the reference — a BUY filled below it, a SELL above it. Two things to read carefully:
  • realizedAvgPrice is executedNotional / executedQuantity, gross of fees — the price the fills traded at, deliberately excluding taker fees and maker rebates so it compares cleanly against price benchmarks.
  • The six analytics fields (realizedAvgPrice, arrivalPrice, benchmarkTwapPrice, benchmarkSource, and both bps fields) are optional and omitted from the response body — the key is absent, not sent as null — whenever that field cannot be computed honestly, and each has its own condition. realizedAvgPrice comes straight from the fills and is absent only when nothing executed. The three reference fields are absent when no reference series qualified: an arrival bucket staler than 5 minutes is rejected, the benchmark requires at least 90% coverage of the window’s sealed minute buckets, and a window too short to seal a single bucket is not scoreable. Each bps field is absent when either of its inputs is — so a parent that filled but had no qualifying reference series still reports realizedAvgPrice, just no scores. The structural fields (twapOrderId, tradingPairId, state, side, totalQuantity, executedQuantity, shortfallQuantity, and the window bounds) are always present, so a report is self-describing and closes the fill-rate arithmetic without a second lookup.
Owner scoping matches the rest of the TWAP surface: another user’s parent returns a 404 byte-identical to an unknown ID, and delegated-agent sessions are rejected. @0xmonaco/types ships the GetTwapOrderTcaResponse interface. See Trading and TWAP Orders.

Typed sdk.ws.instruments() WebSocket subscription

sdk.ws.instruments(handler, tradingPairId?) is a typed subscription for the public instrument channel: market lifecycle and configuration changes — listings, delistings, and edits to tick size, quantity step, order-size bounds, or category. The perp-only leverage/margin-rate bounds are carried in every frame’s full config but are payload only: an edit to those margin parameters alone does not emit a frame. Omit tradingPairId for all markets or pass one to filter. Handlers receive the typed InstrumentEvent from @0xmonaco/types; every frame carries the market’s full current configuration as a terminal-state snapshot — never an additive delta — with changedFields naming what the mutation touched, and the subscribe-time snapshot of the active-pair list is fanned out to the handler as one event per market before the live diffs. A subscriber joining a channel the client already holds is replayed the current baseline from a local cache (the server snapshots only genuinely new wire subscriptions), so every subscriber gets the baseline regardless of ordering. The channel itself shipped server-side in v1.0.45 and was previously reachable only over a raw WebSocket connection with hand-mapped snake_case keys. See WebSockets.

Upgrade

The MCP server ships at 1.0.46 too; it runs via npx -y @0xmonaco/mcp-server, so restarting your assistant picks up the new version. Every SDK bump is a patch release. Both new surfaces are additive — a new TCA endpoint and a typed helper for an existing channel — so existing request and wire shapes are unchanged and the upgrade is drop-in; adopt them only if you want them. When you do read a TCA report, handle the absent-key case for the six analytics fields — a report with only the structural fields is a valid answer, not an error.