Skip to main content

Monaco Protocol SDK v1.0.29

This release adds a public market pulse feed, an all-markets funding-history endpoint, and cursor pagination for full order and trade history. It also widens the market-order price band, re-enables entry-attached TP/SL, and makes several portfolio and position figures more accurate. It rolls up the consumer-facing changes since v1.0.26 across every client (TypeScript, Rust REST, and Rust gRPC), so upgrading is recommended and there are a few action items worth reviewing before you deploy.

Added

Market pulse feed

New sdk.pulse.getPulse() (GET /api/v1/pulse, public — no auth) returns a cached market news and sentiment feed: generatedAt (ISO 8601 UTC, also the response ETag), watchlist, and items[] — each an asset ticker (or "MARKET" for a cross-asset story) with a sentiment of "Bullish", "Neutral", or "Bearish", a summary (≤240 chars), updatedAt, and sources[] (url, author, source, createdAt, relevance 1–5). The snapshot refreshes hourly; responses carry an ETag and support If-None-Match/304, and return 503 until the cache warms. Also on gRPC PulseService.GetPulse.

All-markets funding history

New sdk.market.listAllFundingHistory(params?) (GET /api/v1/market/funding/history, public) returns settled funding across every perp market in one call, so you no longer fan out one listFundingHistory request per pair. Optional startTime/endTime (ms-epoch strings, inclusive on settledAt), page, pageSize (max 100), and orderBy ("ASC"/"DESC", default DESC); the response is { records, total, page, pageSize } and each FundingRecord carries its own tradingPairId. Also on gRPC MarketService.ListAllFundingHistory.

Cursor pagination for orders and trades

sdk.trading.getPaginatedOrders and sdk.profile.getUserTrades (gRPC ListOrders, GetUserTrades, ListUserTrades) accept a pageToken cursor and return a nextPageToken:
  • Omit pageToken for legacy page-number pagination — the recent hot window only.
  • Pass pageToken: "" (empty string) to start a cursor walk over full history (hot and archived rows merged), newest first — or oldest first with orderBy: "ASC".
  • Pass a previous nextPageToken to resume the walk.
nextPageToken is non-empty whenever a page returns any rows; a zero-row page with an empty token means the walk is exhausted. In cursor mode the exact total/page/totalPages counts are omitted (returned as 0).

Funding data on records and the screener

  • FundingRecord gains a carried flag — true when the window settled at the carried last rate under the sparse-sample rule — and listFundingHistory accepts orderBy ("ASC"/"DESC").
  • Screener rows (sdk.market.getScreener, ScreenerItem) gain latestFundingRate (the latest capped settled rate, a decimal fraction per window) and lastFundingTime (window close, ms epoch). Both are null for spot pairs and for perps with no settled window yet.

Terminal position lifetime figures

Terminal position rows (CLOSED/LIQUIDATED/EXPIRED) now report lifetime totals instead of the sliver left before the final closing fill: size is the total quantity closed over the position’s life and isolatedMargin is the total initial margin allocated across its reducing executions. Two optional fields are added — netRealizedPnl (lifetime realized PnL net of trading fees and funding) and realizedRoe (that figure as a percentage of the total allocated initial margin, i.e. leverage-aware realized return). Both are absent, and the stored row values served instead, when a position’s reducing executions do not cover its whole lifetime. Open rows are unchanged.

Changed

Market-order price band widened to 1,000 bps

The mandatory server-side protective band around the reference price is now 1,000 bps (10%) — widened from 500 bps — and triggered TP/SL market legs use a wider 1,200 bps (12%) band. Market orders execute immediately-or-cancel: the quantity available inside the band fills and the remainder is cancelled; a zero-fill order still rejects as insufficient liquidity, and a market on a market with no usable reference price is still rejected as unavailable. A client slippageToleranceBps can only tighten the band, never widen it. The fee-simulation endpoint’s default market slippage buffer follows the band to 1,000 bps, so preflight lock estimates match what placement reserves. No wire types changed.

Entry-attached TP/SL re-enabled

Passing takeProfit/stopLoss on placeLimitOrder/placeMarketOrder is accepted again for margin entry orders under one-way semantics — the child direction follows the order side. The legs activate when the order fills and cancel if it is cancelled or expires unfilled. (This reverses the v1.0.26 rejection; spot and reduce-only orders still reject entry-attached TP/SL.)

Position-based closed-trade win rate

Closed-trade win statistics now classify each position (one flat→open→flat round-trip) once by its net realized PnL after all fees, rather than per closing fill. sdk.portfolio.getRealizedPnl().closedTrades adds a positions total (winners + losers + breakEven), and sdk.profile.getPortfolioStats().winLossRatio is position-based; count stays fill-based.

Batch orders reject time-in-force on market items

Batch order creation now rejects timeInForce on MARKET items, matching the single-order endpoint — market orders take no time-in-force and always execute IOC-style inside the protective band. The SDK rejects this client-side before the request is sent.

Funding-state cadence

getFundingState().nextFundingTime now reflects a market’s actual settlement cadence, and estimatedNextFundingRate refreshes as new samples arrive.

Staging WebSocket ingress

The staging network preset now connects WebSockets to wss://ws-staging.apimonaco.xyz/ws (the development preset moved to wss://ws-develop.apimonaco.xyz/ws in v1.0.26). The previous wss://staging.apimonaco.xyz/ws path remains supported during the migration window, so custom wsUrl overrides and older SDK versions keep working unchanged.

Trade settlement status

On trade records (the settlementStatus field on GetUserTrades/ListUserTrades in the REST and gRPC wire), the SETTLED_ON_CHAIN value is retired — the valid values are now PENDING, SETTLED (terminal), and FAILED. This is the trade-level settlement status only; the order lifecycle OrderStatus is unchanged and still includes SETTLED_ON_CHAIN.

Scoped maintenance mode

During a maintenance window the API keeps sign-in, order cancels, position closes, risk simulations, and delegated-session creation available, and rejects mutating operations (new and replace orders, TP/SL, margin changes, collateral transfers, deposits, withdrawals, faucet mint, delegated-agent config, and reward transfers). Rejected requests return REST 503 with a stable OPERATIONS_BLOCKED code (gRPC UNAVAILABLE with x-maintenance-blocked metadata), so a deliberate maintenance block is distinguishable from a generic outage.

Fixed

Retryable 503 on matching-engine unavailability

POST /api/v1/positions/{positionId}/close, POST /api/v1/positions/{positionId}/tp-sl, POST /api/v1/pitpass/rewards/transfer, and GET /api/v1/orderbook/{tradingPairId} now return 503 (retryable) instead of 500 when the matching engine is momentarily unreachable or restarting. Requests and responses are unchanged; non-transient engine faults still return 500.

Upgrade

Action items to review:
  1. Market band is now 1,000 bps. A market order can partially fill with the remainder cancelled; slippageToleranceBps only tightens the band. Fee-simulation now defaults to a 1,000 bps market buffer.
  2. Trade settlement status dropped SETTLED_ON_CHAIN. If you read the trade-level settlementStatus over the wire, handle only PENDING, SETTLED, and FAILED — the order status enum is unaffected.
  3. Walk full history with a cursor. To read beyond the recent window, start with pageToken: "" and follow nextPageToken until a zero-row page.
  4. Entry-attached TP/SL works again for margin entries — attach takeProfit/stopLoss at placement instead of after the position opens if you prefer.
  5. Treat maintenance 503s as retryable. A REST 503 with OPERATIONS_BLOCKED, and the matching-engine 503s above, are safe to retry.