Skip to content

Releases

v0.7.2

Choose a tag to compare

@aiiven aiiven released this 05 Nov 23:41
6b15a6e

Package version: 0.7.2. Git tag: v0.7.2. Released 2026-11-06.

  • REST errors that say an order or trigger outcome is unknown now use the
    same non-retryable API error as Connect. Read the order or trigger back
    before retrying: the first request may still apply. A gateway timeout
    without a recognised outcome code remains a retryable transport/server
    failure with an unknown outcome; reconcile before retrying a mutation.

v0.7.1

Choose a tag to compare

@aiiven aiiven released this 05 Nov 22:52
15154c9

Package version: 0.7.1. Git tag: v0.7.1. Released 2026-11-06.

  • Service-unavailable responses now raise retryable server errors on Connect
    for orders, withdrawals and internal transfers, matching REST. This includes
    policy and fee lookups, backlogs, operations in progress and temporarily
    unavailable dependencies. Policy denials and permanent precondition failures
    remain non-retryable. Rate-limit errors keep their retry delay, and unknown
    mutation outcomes remain non-retryable even on an unavailable response.
  • These failures now use the existing server error, which does not expose
    the structured service code previously available on API errors.

v0.7.0

Choose a tag to compare

@aiiven aiiven released this 05 Nov 14:00
7c9972d

Built on public contract 748066a, the contract of backend 9.2.5. Breaking changes are marked Breaking below; read them before upgrading.

Package version: 0.7.0. Git tag: v0.7.0. Released 2026-11-05. Built on
public contract 748066a.

  • Breaking: a trailing stop created with an activation price already
    reached now ends FAILED with
    TRIGGER_FAILURE_REASON_TRIGGER_WOULD_TRIGGER_IMMEDIATELY (244).
    ModifyTrigger and order modifies that would make a trailing stop act at
    once are refused with ERROR_CODE_TRIGGER_WOULD_TRIGGER_IMMEDIATELY (302),
    leaving the existing state unchanged. To start trailing from the market,
    clear the activation price with a present zero.
  • Breaking: remove the public holds-list method, hold models and decoders.
    Read aggregate held trading funds from each asset's reserved balance in
    the balances API. Individual hold IDs and expiry times have no replacement.
  • Breaking: listing events for an unreadable trigger now returns the same
    not-found error as reading that trigger, instead of an empty history.
    Events reads retry a catching-up UNAVAILABLE with the trigger-read policy.
  • Breaking: SpotFeeRate gains public fields, so exhaustive struct literals
    must initialize them. SpotFeeRate and SpotFeeRatesList no longer implement Eq.
  • Expose reserve fee rates, the next scheduled change and the full fee
    breakdown. Omitted optional components remain absent and omitted account
    discounts decode as an empty list.
  • Breaking: Error::PermissionDenied, Error::ApiKeyRejected,
    Error::TimestampSkew and Error::SessionRequired gain
    optional problem metadata. Include .. in variant patterns when ignoring it.
  • Preserve REST problem status, code, detail and canonical type on realtime
    authorization and early gateway authentication errors.
  • Pin execution-history continuation pages to the returned exchange order ID
    so reuse of a client order ID cannot change generations between pages.

Attached-exit self-trade prevention, sub-account balances (contract
54dc59d).
Breaking for code that builds Order, GetSubaccountResult or
GetSubaccountOpts with a struct literal naming every field.

  • GetSubaccountOpts::include_balances asks a sub-account read for the
    sub-account's balances, and GetSubaccountResult.balances returns them as a
    BalancesList, the shape of balances.list. None unless asked for; an
    empty list when the sub-account holds none. It needs the READ_BALANCES
    action on the sub-account, or the read fails with PermissionDenied; a
    root-scoped API key cannot read a sub-account's balances. A read that
    cannot reach the balances right now fails with the retryable
    AUTH_TEMPORARILY_UNAVAILABLE.
  • Order.self_trade_prevention_mode reports the order's mode
    (expire_taker, expire_maker, expire_both, UNKNOWN(<n>) for a newer
    one). The order's attached take-profit, stop-loss and trailing-stop exits
    use it; set it with CreateOrderParams.self_trade_prevention.
  • An attached exit never trades with the order it protects. When it fires
    while that order still rests, the order's unfilled rest is canceled first
    and the order ends with cancel_reason CANCEL_REASON_ATTACHED_EXIT_FIRED
    (on reads and on the private order stream).
  • A self-trade prevention block of an attached exit is a refused fire, not an
    end: a fire_refused trigger event with fire_refusal_reason
    self_trade_prevented, whose child_seq names the child order self-trade
    prevention expired. The leg stays armed. Reject reason
    ERROR_CODE_SELF_TRADE_PREVENTED decodes too; no request is answered with
    it.
  • A trigger a halted market refuses now reads market_halted as its
    failure_reason or fire_refusal_reason, never the unnamed
    UNKNOWN_TRIGGER_FAILURE_REASON(212). Unknown reasons still decode with
    their number.
  • A buy sized by a quote amount can carry attached exits; the server checks
    the legs against the pair's minimums.
  • Docs: Order.cum_notional, cum_quote() and quote_used() are exactly the
    settled quote when the pair's base_quantity_scale is at most 9; above
    that they can exceed it by less than 1e-18 per fill.

Exact order totals, refused trigger fires, API-key refusal reasons
(contract e96897c).
Breaking for code that builds these types with struct
literals or matches Error exhaustively.

  • Order::avg_price() is the exact average execution price from the new
    Order.avg_price_e18 (18 decimals; avg_px stays rounded down to 1e-9).
    Order.cum_notional / Order::cum_quote(base_quantity_scale) is the exact
    quote amount of the fills before fees, and Order.fee_total
    (OrderFeeTotal: amount_e18 / amount(), is_rebate, qty) their fee
    net of rebates. Order::quote_used(base_scale) and
    Order::quote_unspent(base_scale, quote_scale) tell how much of a
    quote-sized buy's amount the fills used; None until the fee total covers
    every fill. All exact Decimals, zero with no fills, and None rather
    than a rounded value when a result needs more digits than a Decimal
    holds.
  • Trigger events: fire_refused (also a list_events filter) for a fire
    refused while the trigger stays live, with the new
    TriggerEvent.fire_refusal_reason (rate_limited, account_repairing,
    market_halted, min_notional, ...). It is not terminal. The failure reason
    account_repairing is named. Unknown event types and reasons still read as
    UNKNOWN(<n>) / UNKNOWN_TRIGGER_FAILURE_REASON(<n>).
  • Error::auth_code() returns the typed auth.v1.AuthErrorCode of a refusal
    on ConnectRPC (AuthErrorDetail) and REST (code with AUTH_ added,
    UNAUTHENTICATED as AUTH_AUTHENTICATION_REQUIRED);
    errors::auth_codes::from_rest_code maps a REST code, and auth_codes names
    the seven new values (SIGNATURE_INVALID, MISSING_HEADERS, KEY_EXPIRED,
    KEY_DISABLED, IP_NOT_ALLOWED, API_KEY_NOT_ACCEPTED, plus the existing
    TIMESTAMP_SKEW).
  • Changed: a ConnectRPC AUTH_TIMESTAMP_SKEW detail is the retryable
    Error::TimestampSkew, and the other API-key reasons are
    Error::ApiKeyRejected with the REST form of the code (SIGNATURE_INVALID),
    the same errors the API gateway's answers map to. They were Error::Api.
  • New Error::SessionRequired (is_session_required()) for
    AUTH_SESSION_KIND_NOT_ALLOWED: a session-only method called with an
    account API key, read from the Connect permission_denied detail and the
    REST 403 code alike. It was Error::Api on Connect and
    Error::ApiKeyRejected on REST.
  • Error::Api gains violations (Error::violations()): the request fields
    an order refusal names, with ConnectRPC field paths. A missing or wrong
    attached trailing-stop maximum on create, preview or batch create is now
    refused before sending with the server's code, rule ID and field path
    (ERROR_CODE_BAD_PRICE / sell_unset or buy_at_least_activation,
    ERROR_CODE_TRIGGER_BUY_REQUIRES_LIMIT / buy_required) as Error::Api
    instead of Error::Validation; a modify names new_attached_risk... and
    a batch replace item items[N].new_attached_risk....
  • Error::is_order_already_terminal() and
    order_codes::ORDER_ALREADY_TERMINAL / ORDER_UNKNOWN: a cancel of an order
    that has already ended, a repeat of the cancel that ended it included, is
    now always refused with ERROR_CODE_ORDER_ALREADY_TERMINAL. Treat it as
    "already done".
  • client.stop_all_trading(scope) cancels every live trigger, then every open
    order. Cancel-all and the dead-man switch cancel orders only, never
    triggers; cancel_all, cancel_all_after and cancel document it.
  • Fixed: with WireFormat::Json, a response naming an enum value newer than
    this SDK (a new changelog surface, for example) failed the whole call with
    a retryable Error::Server. The value now reads as unset (and is dropped
    from a repeated field), as protojson's DiscardUnknown does; binary
    responses keep the value's number.
  • Changelog: surface labels market_data, quickswap and rewards;
    ChangelogSection.surface names the product area a section covers;
    list_changes refuses more than 10 surfaces before sending.
  • Docs: an API key's permission_denied message names the missing policy
    action and reaches the caller as is; a quote-sized buy that spent its amount
    ends filled; a ladder whose levels were all canceled before any filled
    ends cancelled.

New: public product changelog (client.changelog). Read the changelog of
the environment you call without an API key. It is available on
devnet now and on testnet with its next release.

  • list_posts, get_post and list_changes wrap
    changelog.v1.ChangelogService; posts and changes stream every page.
  • breaking_changes_since(t) and action_required_since(t) collect the
    matching changes published since t.
  • Typed models ChangelogPostSummary, ChangelogPost, ChangelogSection,
    ChangelogChange and ChangelogChangeEntry. Enums are lowercase labels and
    unknown values read as unknown(<n>); change ids are base58.
  • The generated module tree now compiles changelog.v1.

Batch replace refusals, trigger read-your-writes, owner role lock.

  • orders.wait_batch_replace(batch_request_id, subaccount_id, timeout) polls
    get_batch_replace_status with a short backoff until no item is
    admitted, polling through the not_found and unavailable answers of the
    first seconds after admission. It stops at the 60-second status window (or
    an earlier timeout) with Error::Transport: reconcile through the orders
    then.
  • BatchReplaceStatusItem::error_code() turns an item's code
    (POST_ONLY_CROSS) into the orders error code (ERROR_CODE_POST_ONLY_CROSS),
    keeping a code this SDK does not know unchanged;
    errors::order_codes::from_status_code does the same for any string.
  • Fixed: get_batch_replace_status failed with `Error::ResponseContrac...
Read more

v0.6.0

Choose a tag to compare

@aiiven aiiven released this 02 Nov 14:41
19df13a

Package version: 0.6.0. Git tag: v0.6.0. Released 2026-11-02.

What a trading bot gains. A sell order can carry an attached trailing stop
again. That trailing stop buys back, and the server now requires the most its
exit pays; 0.5.0 could not send it, so every sell order with an attached
trailing stop was rejected. Set it with TrailingStop::with_limit_price.

This is a minor release because input structs changed shape. The order and
trigger inputs that grow optional fields are now #[non_exhaustive] with
constructors, so future optional fields arrive in compatible releases. The Go
and Python SDKs ship the same fix as 0.5.1, without breaking changes.

An environment requires the limit price once it runs the 0.5.0 contract:
devnet first, then testnet after its next upgrade.

Breaking changes

  • CreateOrderParams, PreviewOrderParams, CreateTriggerParams, RiskLeg
    and TrailingStop are #[non_exhaustive]: code outside the crate can no
    longer build them with a struct literal. Use CreateOrderParams::new(symbol, side, order_type), PreviewOrderParams::new(symbol, side, order_type),
    CreateTriggerParams::new(symbol, trigger_type, side, order_type, qty),
    RiskLeg::market(trigger_price) / RiskLeg::limit(trigger_price, limit_price) or TrailingStop::new(distance), then set optional fields
    (params.price = Some(..)) or chain the leg setters
    (.with_activation_price(..), .with_limit_price(..),
    .with_trigger_price_source(..), .with_max_slippage(..)).
    OrdersService::create_params is unchanged. Inputs that derive Default
    (AttachedRisk and the list and read options) are unchanged: keep
    ..Default::default().
  • TrailingStop has a new public field, limit_price: Option<Price>.
  • Creating a sell order whose attached trailing stop has no limit_price now
    fails locally with Error::Validation; the server rejected it already.

Fixed

  • Attached trailing stops send TrailingStop::limit_price (or
    TrailingStop::with_limit_price) as the trailing stop's maximum buy-back
    price. On order create, preview and batch create, a sell order's trailing
    stop requires it and a buy order's trailing stop rejects it. On every path
    it must be positive and at least activation_price when that is set. A
    modify or batch replace does not carry the order's side, so the server
    checks the side rule there. Order reads do not return the limit price yet.

v0.5.0

Choose a tag to compare

@aiiven aiiven released this 02 Nov 13:56
62a1bfa

Package version: 0.5.0. Git tag: v0.5.0. Released 2026-11-02.

What a trading bot gains. An attached take-profit, stop-loss or trailing
stop now says when it starts protecting the position: its trigger events
include armed, once, when the parent order's first fill makes the leg live.
A bot can wait for it instead of polling the leg's status. Three new error
codes are final refusals: the request did not apply, so do not resend it
unchanged.

An environment reports armed events and the new codes once it runs this
contract: devnet first, then testnet after its next upgrade.

Breaking changes

  • None in the SDK API.

Added

  • Trigger events decode the new armed event type: an attached take-profit,
    stop-loss or trailing-stop leg reports it once, when its parent order's
    first fill makes the leg live (or when a leg paused before that fill
    resumes). It is not terminal. trigger_event_type_from_label accepts
    "armed" for the event filter. Attached trailing stops still report
    activated when they start tracking.
  • Error codes AUTH_SUBACCOUNT_OWNER_ROLE_LOCKED (the sub-account's owner
    cannot be invited, re-roled or removed),
    ERROR_CODE_TRIGGER_SYMBOL_MISMATCH (modify, pause or resume named a listed
    pair other than the trigger's own; name the trigger's pair or omit it) and
    the balance reads' ERROR_CODE_INVALID_SUBACCOUNT_ID (a zero or malformed
    sub-account ID).
  • Generated messages add Subaccount.removed (real-time sub-account updates
    only: the caller lost access, so drop the sub-account),
    TrailingStopPolicy.limit_price_ticks, Checkpoint.opening_value_usd,
    ListMyRewardAwardsResponse.awards_may_change and the Swap reason
    MAX_ORDER_QUANTITY, and the trade WebSocket protobufs follow binary schema
    34.

Server behaviour on this contract

  • Batch replace amends an order in place, keeping its order ID and queue
    priority, when an item keeps the price, does not raise the total quantity
    and keeps the client order ID. Otherwise it replaces the order under a new
    order ID.
  • An attached trailing stop on a selling order buys back, and the server now
    requires its maximum buy-back price. This SDK's
    AttachedRisk::trailing_stop does not send that price yet, so place a
    selling order with only take-profit and stop-loss legs until a later release
    adds it. A buying order's attached trailing stop is unchanged.
  • Ladder outcomes: a ladder is completed once no child order remains open and
    at least one reached the book; it is failed only when every child order was
    rejected before reaching the book.

v0.4.0

Choose a tag to compare

@aiiven aiiven released this 02 Nov 10:07
935ee93

Package version: 0.4.0. Git tag: v0.4.0. Released 2026-11-02.

What a trading bot gains. An order now says why it ended, in the same
words everywhere. A rejected order's reject_reason is the error code the
Orders API returns for the same refusal, and a canceled order's
cancel_reason says why it was canceled, on order reads and on the private
order stream alike. Before, the numeric reason used the matching engine's own
numbering, which clashed with the API's error codes. OrderbookData::available
tells a bot when a book's levels are unknown rather than empty, so it does not
quote into a book that is being rebuilt. Trigger::version picks out the
newest copy of a trigger, and nine new error codes are final refusals: the
request did not apply, so do not resend it unchanged.

This release works on devnet now, and on testnet after testnet's next upgrade.

Reason labels in this SDK. Both reasons are full proto enum names.
reject_reason is the orders.v1.ErrorCode name, the same string as
Error::Api's code, for example ERROR_CODE_POST_ONLY_CROSS.
cancel_reason is the orders.v1.CancelReason name, for example
CANCEL_REASON_USER_REQUEST. The Go and Python SDKs format these labels
differently.

Breaking changes

  • Client::whiteboard, Client::polychart and Client::layout are removed.
  • The generated orders.v1.Order loses terminal_reason_code and
    terminal_reason, and the private order stream's OrderEvent loses
    reason_code. Read reject_reason and cancel_reason instead.
  • OrderStreamEvent::reason_code is replaced by reject_reason and
    cancel_reason, both Option<String>.
  • GetSubaccountOpts::include_balances is removed.
  • orderbook::build_orderbook_data takes the book's availability as a new
    last argument.

Breaking

  • Client::whiteboard, Client::polychart and Client::layout are removed,
    because those APIs are no longer part of the public API.
  • The order terminal reason fields are removed: the generated
    orders.v1.Order no longer has terminal_reason_code or terminal_reason,
    and the private order stream's OrderEvent no longer has reason_code.
    Read the typed reject_reason and cancel_reason instead, and replace any
    matching on terminal_reason text with them.
  • OrderStreamEvent::reason_code is replaced by reject_reason and
    cancel_reason, both Option<String>. A rejected order's event names its
    refusal with the order error code the Orders API returns (for example
    ERROR_CODE_POST_ONLY_CROSS). A canceled order's event names why it ended
    (for example CANCEL_REASON_USER_REQUEST), and so does the replaced event
    of the order a replace ended (CANCEL_REASON_REPLACED). Both are None
    otherwise.
  • GetSubaccountOpts::include_balances is removed: a sub-account read no
    longer returns balances. Read them with the balances service for the
    sub-account.
  • orderbook::build_orderbook_data takes the book's availability as a new
    last argument.

Added

  • Order::reject_reason and Order::cancel_reason on order reads and on the
    orders of the private order stream's snapshots and units. A rejected order's
    reject reason is formatted like Error::Api's code for the same refusal;
    a canceled order's cancel reason is a CancelReason proto name. Both are
    None for every other status, and a value this SDK does not know keeps its
    number (UNKNOWN_ERROR_CODE(<n>), UNKNOWN(<n>)).
  • OrderbookData::available: false while the book is being built or after it
    was invalidated, when its levels are unknown rather than empty. It is the
    server's value as sent, never inferred from the levels; a managed order book
    subscription carries the value of its last snapshot. A server that predates
    the field reports false.
  • Trigger::version: 1 for the first state, higher for every later state
    change. Keep the copy with the highest version.
  • Order error codes ERROR_CODE_ATTACHED_LEGS_EXCEEDED,
    ERROR_CODE_FEE_ASSET_INVALID, ERROR_CODE_FEE_CEILING_INVALID,
    ERROR_CODE_UNSUPPORTED_FIELD_SET, ERROR_CODE_TRIGGER_FIRE_LIMIT_REACHED,
    ERROR_CODE_CONDITION_FLAGS_INVALID, ERROR_CODE_CONDITION_PARAMETER_SET,
    ERROR_CODE_TWAP_CAPACITY_REACHED and ERROR_CODE_CHILD_ORDER_INCONSISTENT
    surface as Error::Api codes. Their outcome is known: they are not
    retryable and mutation_outcome_unknown() is false.

v0.3.0

Choose a tag to compare

@aiiven aiiven released this 31 Oct 06:21
b6a9190

Package version: 0.3.0. Git tag: v0.3.0. Released 2026-10-31.

What a trading bot gains. Public trade, fill, ledger transfer and
trigger-event subscriptions now deliver every event; before, all but one
event of each batch was lost. SpotConfig and the catalog expose each pair's
order limits as typed values, including the new cap on one market order's
notional, so a bot can size orders before it sends them. A clock-skew
rejection from the API gateway is the retryable Error::TimestampSkew and no
longer ends a private order stream for good; other API-key rejections keep
their code. A duplicate client order ID names the order that already holds
it, replacement orders report the quantity they inherited, and slippage caps
and trigger inputs are checked before sending the way the API checks them.

This release works on devnet today, and on testnet after testnet's next
upgrade, which brings the new private order stream.

Breaking changes

  • Batched subscriptions yield every event, and the single-event decoders
    (market_trade_from_bytes, user_trade_from_bytes,
    ledger_transfer_from_bytes, trigger_event_from_bytes) are replaced by
    their ..._batch_from_bytes versions, which return one result per event.
  • spot_config_from_proto returns Result.
  • Connect unimplemented and a bare HTTP 501 are Error::NotImplemented
    instead of Error::RouteNotFound or Error::Api.
  • max_slippage_bps is at most 9999 for a market order that sells, every
    trailing stop and triggers.modify.
  • The mark trigger price source is rejected locally.
  • A buy trailing stop's limit_price must be at least its
    activation_price.
  • Public structs gain fields, so code that builds them with a struct literal
    must set them.

Breaking

  • Batched realtime publications deliver every event. Public trades,
    user fills, ledger transfers and trigger events arrive as batches; before,
    each batch was decoded as one event and the rest were lost. The
    subscriptions now yield every event in order. The single-event decoders
    market_trade_from_bytes, user_trade_from_bytes,
    ledger_transfer_from_bytes and trigger_event_from_bytes are replaced by
    market_trade_batch_from_bytes, user_trade_batch_from_bytes,
    ledger_transfer_batch_from_bytes and trigger_event_batch_from_bytes,
    which return one result per event.
  • spot_config_from_proto returns Result: a malformed order limit is an
    error instead of an untyped value.
  • Connect unimplemented and a bare HTTP 501 are Error::NotImplemented
    instead of Error::RouteNotFound or Error::Api. A bare HTTP 404 is still
    Error::RouteNotFound; Error::is_not_implemented() is true for both.
  • Slippage caps match the API. A market order that sells, every trailing
    stop (standalone or attached, buy or sell) and triggers.modify take at
    most 9999 bps; they accepted 10000, which the API rejects. A buy market
    order, a buy stop-loss or take-profit market child and a TWAP slice still
    take 10000.
  • The mark trigger price source is rejected locally (standalone triggers
    and attached legs): spot markets have no mark price.
  • A buy trailing stop's limit_price must be at least its
    activation_price.
  • Public structs gain fields (see Added), so code that builds them with a
    struct literal must set them.

Fixed

  • API-gateway rejections keep their code. The gateway rejects API-key
    requests with a plain JSON body such as 401 {"code":"TIMESTAMP_SKEW"}.
    It was reported as a generic Error::Auth with no code, so a clock-skew
    rejection was not retryable and ended a private order stream for good. Now
    TIMESTAMP_SKEW is the retryable Error::TimestampSkew, and any other
    code (SIGNATURE_INVALID, KEY_DISABLED, IP_NOT_ALLOWED, ...) is the
    non-retryable Error::ApiKeyRejected with its code and HTTP status. This
    covers Connect calls and the realtime token requests.
  • A market overview subscription created with symbols keeps only those
    markets in buffered and live updates, not only in its first snapshot.

Added

  • Typed spot-config order limits: SpotConfig.pair_order_limits
    (PairOrderLimits with max_limit_qty_base, max_market_qty_base,
    max_order_notional_quote, max_market_notional_quote and
    max_open_orders_per_pair) and SpotConfig.max_open_orders_total. The
    decimal limits are None when the pair has no maximum. The catalog
    exposes the same values: catalogs.pair_order_limits_for_symbol(),
    pair_order_limits_for_symbol_id() and max_open_orders_total().
  • Order.inherited_cum_qty: the filled quantity a replacement inherited
    from its predecessors.
  • action_taken on BatchReplaceAdmissionItem and BatchReplaceStatusItem:
    replaced, or amended for a cancel-only outcome with no successor.
  • A duplicate client order ID rejection names the order that already holds
    the ID, when the server knows it: Error::existing_order_id() for single
    creates and BatchCreateResultItem.existing_order_id for batch creates.
  • LedgerTransfer.transfer_id, shared by both legs of a transfer.
  • triggers.modify and triggers.resume_with / resume_by_id no longer
    need a symbol; without one they target the trigger's own market.
  • TriggerTrailingDetails.trigger_price: a trailing stop's current
    threshold.
  • VIPStatus.settled_volume_quality and average_aop_quality
    (VIPMetricQuality: status and incomplete_hours). When the volume's
    status is price_unavailable, settled_volume_30d_usd is a lower bound.
  • realtime::Client::subscribe_proto_batch for batched channels. An event
    that fails to decode is reported through the subscription's error
    callback, and the rest of its batch is still delivered.
  • auth_codes::TIMESTAMP_SKEW; Error::auth_error_code() also returns the
    gateway code of Error::TimestampSkew and Error::ApiKeyRejected.

Internal

  • sdk-capabilities.json no longer carries publicDescriptorSha256 or generatedAt, so a proto publication that only changes src/gen/ and manifest.json no longer makes it stale; manifest.json stays the single source of the descriptor hash.

v0.2.0

Choose a tag to compare

@aiiven aiiven released this 31 Oct 02:53
6e52008

Package version: 0.2.0. Git tag: v0.2.0.

This release replaces 0.1.0-alpha.49 and covers every change since it.
From 0.2.0 on, the Go, Python and Rust SDKs share one version number and
are released together. Versions are plain SemVer (0.2.0, 0.2.1, ...) and
git tags are vX.Y.Z; the alpha pre-release suffixes (0.1.0-alpha.N, tag
v0.1.0aN) are retired. Upgrade from any 0.1.0-alpha.* release: those
releases use hosts that no longer exist and a price scale 1,000 times off
against the current API.

Breaking

  • Trading prices now use the published fixed scale of 9 decimals: one
    price tick is 0.000000001 quote units.
    PRICE_TICK_SCALE is 9, so
    Price::from_decimal_str, Price::as_decimal, Price::format, order,
    trigger, trade, orderbook, market-overview and primary candle prices
    encode and decode at 1e-9. Earlier releases used 1e-6 and are 1,000
    times off against the current API. Code that builds Price::from_ticks
    values by hand must multiply its old tick values by 1,000.
  • OrdersService::subscribe streams account orders over the private
    WebSocket (/v1/ws/private) and returns a PrivateOrdersSubscription
    of PrivateOrdersEvents (Connected, Snapshot, Unit, Ready,
    Stale, Disconnected, Error) instead of a TypedSubscription<Order>. The
    realtime order channels it used are retired and no longer issue
    subscribe tokens. Snapshot and unit orders use the same Order model as
    the order reads; units also carry removed order IDs and order events.
    The call returns at once: the handshake result arrives as Connected or
    Error. The stream resumes from its last position after a gap or a
    reconnect, and calls for the same account share one server subscription.
    Ready arrives once per server subscription when the stream reaches the
    account's read boundary; wait for it before relying on the stream. A
    consumer that joins a ready stream gets it right after its catch-up
    snapshot. Stale carries an OrdersStale with stale, the lowercase
    reason (view_behind, order_unavailable, ...) and order_ids: with
    order_unavailable only those orders are not current, the rest of the
    view is and units keep arriving. A later report replaces the earlier one,
    and a consumer that joins a stale stream gets the current report.
  • Removed codecs::decode::order_from_bytes, the decoder for the retired
    order channel's publications.
  • ModifyTriggerParams.limit_price is removed: a trigger's child limit
    price is fixed at create, and the API rejects any modify that sets it.
  • CancelAllOrdersResult, CancelAllAfterResult, GetOrderResult,
    LifecycleFlowSummary, MarketTradesResult, GetTradesOpts and
    Trigger gain fields (below). These structs are not #[non_exhaustive],
    so code that builds them with struct literals must add them.

Fixed

  • POLYESTER_TESTNET_ENVIRONMENT and environment_from_name("testnet") now
    use https://api.testnet.polyester.com and wss://api.testnet.polyester.com.
    Earlier versions pointed at api-testnet.polyester.com, which does not
    exist, so every testnet call failed with a DNS error. The devnet preset and
    DEFAULT_API_URL / DEFAULT_WS_URL now use the documented
    api.devnet.polyester.com host.
  • An order create, trigger create, order cancel or order modify that was sent
    but not confirmed in time (ERROR_CODE_ORDER_CREATE_OUTCOME_UNKNOWN,
    ERROR_CODE_TRIGGER_CREATE_OUTCOME_UNKNOWN,
    ERROR_CODE_ORDER_CANCEL_OUTCOME_UNKNOWN,
    ERROR_CODE_ORDER_MODIFY_OUTCOME_UNKNOWN) now reports
    mutation_outcome_unknown() and is_retryable() true. It may still apply:
    read the order or trigger back before retrying. Earlier versions reported
    it as a definite failure. errors::order_codes lists these codes.
  • AUTH_TEMPORARILY_UNAVAILABLE is now retryable: the account request
    changed nothing, so send the same request again.
  • Stop-loss and take-profit triggers with a market child now send their
    slippage cap.
    max_slippage_ticks / max_slippage_bps were dropped on
    create, so the child used the pair's default market slippage instead of
    the requested cap. At most one of them is accepted, a sell child takes
    fewer than 10000 bps, and a limit child rejects them.
  • Order reads no longer report an attached-risk leg whose state is
    not_configured; the server sends that state for a leg the order does
    not have.
  • An API error whose order, auth, withdraw or transfer code is newer than
    this SDK version now reports code = "UNKNOWN_ERROR_CODE(<n>)" instead
    of ERROR_CODE_UNSPECIFIED or AUTH_UNSPECIFIED, so the server's code is
    never lost.

Added

  • Index-price triggers and attached legs: CreateTriggerParams.trigger_price_source
    (last, index or mark, the labels trigger reads use) is sent for
    stop-loss, take-profit and trailing-stop triggers, and
    RiskLeg.trigger_price_source / TrailingStop.trigger_price_source are
    sent on order create and modify. None watches the last trade price.
    Order reads now fill these leg fields, which are no longer deprecated, so
    a read leg can be sent back unchanged. An unknown label is a validation
    error, and TWAP and ladder triggers reject a price source.
  • CancelAllOrdersResult.listing_status: included, or
    not_retained_read_open_orders when a retry with the same request_id
    returns the original counts with an empty cancelled_orders. An empty
    retried list does not mean nothing was canceled.
  • CancelAllAfterResult.effective_scope: the account, symbol and side the
    armed switch cancels (DeadManSwitchScope); None when disabled.
  • GetOrderResult.executions_complete: true when the order's trades across
    every page add up to its filled quantity.
  • LifecycleFlowSummary.is_delayed: an open flow that has made no progress
    for well beyond its expected step time. Lifecycle reason
    deposit_source_not_confirmed.
  • Trigger reads name the cancel reasons account_repair,
    pair_drain_trigger, pair_drain_twap, pair_drain_ladder and
    pair_drain_attached_leg, and the failure reasons
    index_price_unavailable and trigger_would_trigger_immediately. Spot
    config reports halted pairs as PAIR_STATUS_HALTED.
  • Standalone BUY trailing stops: CreateTriggerParams.limit_price is the
    required maximum price of a BUY trailing stop (limit_price_ticks), and
    must be None for a SELL one. Trigger reads show a BUY trailing stop
    as an IOC limit child (order_type limit, time_in_force ioc) with
    the maximum price as Trigger.limit_price; the trailing details carry the
    trough price.
  • Trigger.max_slippage: the slippage cap of a stop-loss or take-profit
    market child, or of a trailing stop.
  • CancelAllOrdersResult.cancelled_orders (order ID and client order ID,
    oldest first, at most 200), total_cancelled and truncated.
  • Gap-free trade backfill: GetTradesOpts.after_trade_id (not combinable
    with start, end or page_token), and
    MarketTradesResult.complete_through_trade_id, next_after_trade_id and
    epoch_ends. Zero is a valid cursor and watermark.
  • OrderMutationResult (order create), ModifyOrderResult and accepted
    BatchCreateResultItems carry take_profit_trigger_id,
    stop_loss_trigger_id and trailing_stop_trigger_id: the public ID of
    each attached-risk leg's trigger, and None for a leg the order does not
    have. These structs are not #[non_exhaustive], so code that builds them
    with struct literals or destructures them exhaustively must add the new
    fields.
  • realtime::Client::subscribe_private_orders(account_id) and
    proto::privatews (the private WebSocket contract).
  • Trigger events report event_type = "activated" when a standalone
    trailing trigger's activation condition is met and tracking begins.
    trigger_event_type_from_label("activated") filters for them.
  • The generated proto and connect modules now include checkpoints::v1,
    claims::v1, rewards::v1, swap::v1 and swap::quickswap::v1. Their
    code was already in the package but was not compiled into the crate.
    These services have no Client wrappers: they need an interactive
    session or a broker key, which this API-key SDK does not use.

Changed

  • MaxSlippage::Ticks and the trigger create/modify max_slippage_ticks
    are now i64 absolute price ticks, matching the 64-bit contract fields.
  • Candle and market-overview base volume now use the base asset
    market_data_volume_scale from get_spot_config. Primary candle prices
    use the fixed price scale of 9.
  • Composite reference-candle OHLC uses the pair reference_price_scale.
    GetCandlesOpts.include_reference requests that series.
    MarketOverviewEntry.volume_24h_base is the decoded decimal when the
    catalog scale is known; volume_24h_base_scaled stays the integer.
  • The crate documentation link and the README links to the SDK capability
    matrix and market order price protection point at the public docs on
    polyester.com.

v0.1.0a49

Choose a tag to compare

@AnthonyArena AnthonyArena released this 21 Sep 15:27
852c63b

Fixed

  • Limit-order create now rejects market_max_slippage instead of dropping the supplied protection.

v0.1.0a48

Choose a tag to compare

@AnthonyArena AnthonyArena released this 16 Sep 16:54
9af56a4

Added

  • Limit GTD orders: CreateTimeInForce::Gtd plus required expire_at encode OrderIntent.limit_gtd (price, optional post_only, 1s–30d expiry)
  • Order reads expose expire_at for GTD and omit it otherwise

Changed

  • Generated Connect/protobuf bindings now include ClaimsService.GetDailyClaimStatus and ClaimDailyReward. Those RPCs stay JWT/session-only and are not wrapped in this API-key SDK.