Skip to content

Releases: pmxt-dev/pmxt

v2.54.0

Choose a tag to compare

@github-actions github-actions released this 18 Jul 01:47

Added

  • feat(probable): unified Web3 authentication lifecycle (#1614). Adds getAuthNonce, loginWithSignature, logout, isSessionActive, and verifyL1/verifyL2 to the Probable exchange, with in-memory session storage on the base class, exposed through both SDKs.

Security

  • Session credentials are never exposed over the network. #1614 as submitted exposed getSession as an HTTP/RPC endpoint that returned the full session credential set (apiKey/apiSecret/passphrase) keyed by a public wallet address — on a shared/hosted deployment any caller could retrieve another user's trading secrets. Before landing, getSession was added to EXCLUDED_METHODS in generate-openapi.js, so it is omitted from method-verbs.json, the OpenAPI spec, and the generated SDK clients; it remains an in-process helper only. The signature-gated loginWithSignature (which returns the caller's own freshly minted credentials, only after they prove wallet ownership) and the boolean isSessionActive remain available.

Installation

npm:

npm install pmxtjs@2.54.0
npm install -g @pmxt/cli@2.54.0

PyPI:

pip install pmxt==2.54.0

Links

Full Changelog: v2.53.1f...v2.54.0f

v2.53.1

Choose a tag to compare

@github-actions github-actions released this 18 Jul 01:32

Fixed

  • fix(core): type compareMarketPrices with CompareMarketPricesParams (#1419). Introduce a precise CompareMarketPricesParams type and use it for the base compareMarketPrices signature instead of the loose FetchMatchesParams. Type-only refinement — the base method is a stub and the concrete Router.ts behavior is unchanged. Only the buildable core of #1419 was applied; its broken SDK-generator import and a private_key=wallet_address bug were dropped.

Installation

npm:

npm install pmxtjs@2.53.1
npm install -g @pmxt/cli@2.53.1

PyPI:

pip install pmxt==2.53.1

Links

Full Changelog: v2.53.0f...v2.53.1f

v2.53.0

Choose a tag to compare

@github-actions github-actions released this 18 Jul 01:25

Second wave of community PR triage. Each of these was reworked before landing — the original branches carried stale reverts, file-encoding corruption, or compile errors, so only the intended net change was applied on top of current main, then re-verified. All Core (816), Python SDK (267), and TypeScript SDK (93) tests pass. Minor bump for the new opt-in Router and WebSocket capabilities.

Added

  • feat(sdk): Router.sql(query) (#1129). Both SDKs gain a Router.sql() / Router.sql() method that POSTs a query to the server's existing /v0/sql endpoint (read-only ClickHouse, error-scrubbed) with the SDK's normal auth headers, returning a typed SqlResult (SqlMeta/SqlColumn) exported from each package root. The original PR's UTF-16 file corruption and unrelated reverts were dropped.
  • feat(sdk): cross-venue Router.fetchOrderBook(outcomeId) (#1670). Both SDKs expose a Router-level order-book fetch that routes through the existing core Router.fetchOrderBook surface and returns a single merged OrderBook. Reimplemented as a proper Router class method (the original defined it at module level, which gutted the Python Router class).
  • feat(sdk): expose WebSocket configuration for Polymarket and Kalshi (#1126). A websocket options object (reconnect interval, max reconnect attempts, ping interval, connect timeout) is threaded through the SDK exchange constructors into the WebSocket clients in both SDKs. Reconciled with the #1659 handshake-timeout/retry work already on main, and the fast default reconnect backoff is preserved (no 5s-default regression).

Fixed

  • fix(baozi): correct program error-code mappings (#1118). Remap 6018/6040/6020/60416013/6014/6023/6024 to match the current on-chain IDL. Applied without the stale hosted-trading reverts the original branch carried.
  • fix(limitless): paginate all markets (#1119). Replace fixed-page parallel fetching with sequential pagination driven by totalMarketsCount (with a 50-page safety cap) plus a token-filter over-fetch factor, so large limit requests return the full set. Applied without the stale reverts.
  • fix(ts-sdk): align MatchResult / PriceComparison nullable fields (#1578). Widen reasoning, bestBid, bestAsk to T | null to match openapi.yaml (nullable: true). The half-wired parity CI from that PR was intentionally not included.

Not merged

  • #1614 (feat(probable)) was rejected: it exposed session credentials (apiKey/apiSecret/passphrase) over an HTTP endpoint keyed by a public wallet address. Held out pending a fix that stops returning secrets over the server surface.
  • #1419 (replace any with proper types) was superseded: the remaining any usages are raw wire-JSON in converter helpers with no genuine importable type to substitute; the public Router signatures are already typed.

Installation

npm:

npm install pmxtjs@2.53.0
npm install -g @pmxt/cli@2.53.0

PyPI:

pip install pmxt==2.53.0

Links

Full Changelog: v2.52.0f...v2.53.0f

v2.52.0

Choose a tag to compare

@github-actions github-actions released this 18 Jul 00:55

Maintenance release rolling up the community and internal fixes accumulated since 2.51.4, plus two additive venue capabilities. All Core (816), Python SDK (260), and TypeScript SDK (86) tests pass. Backward-compatible; minor bump for the new opt-in features.

Added

  • feat(rain): fetchOrderBooks batch order-book fetch (#1693). RainExchange now implements the batch fetchOrderBooks(outcomeIds) surface (emulated by fanning out to the existing single-outcome fetchOrderBook) and declares the emulated capability, so Rain participates in the cross-venue batch order-book path.
  • feat(python): SuiBets wallet options (#1657). The Python SDK gains a SuiBetsOptions typed dict and threads wallet_address through the SuiBets constructor into the sidecar credential dict, matching the wallet-option pattern used by other venues.

Fixed

  • fix(hyperliquid): builder order attribution (#1658). createOrder accepts optional builder/builderFee params, appended to the signed payload in the correct key order (after grouping) with address/fee validation. Purely opt-in; existing order flows are unchanged.
  • fix(typescript): WS client connection timeout and retry (#1659). The TS SDK WebSocket client now applies a 10s handshake timeout and a 3-attempt retry loop with backoff, bringing it to parity with the Python client.
  • fix(limitless): wire unwatchOrderBook to WebSocket unsubscribe (#1692). unwatchOrderBook now forwards to LimitlessWebSocket.unsubscribe, mirroring the watchOrderBook override and the Polymarket pattern.
  • fix(kalshi): expose event metadata endpoint (#1611); sync Trade schema with v2 API drift (#1187, #1282); OHLCV normalizer + docs outcomeId param (#1429).
  • fix(suibets): model onchainState to restore accurate order-book liquidity (#1583).
  • fix(polymarket-us): prevent WebSocket connect hangs from a garbage-collected timeout (#1580).
  • fix(limitless): throw on watchOrderBook failure instead of silently swallowing it (#1581).
  • fix(gemini-titan): add terms-acceptance flow before order submission (#1326).
  • fix(smarkets): resolutionDate fallback (#1367).
  • fix(sdk): compute detailed execution prices locally (#1308); expose venue filters in fetch params (#1325); align order book field types (#1417).
  • fix(ts-sdk): export Polymarket_us alias (#1290); raise hosted embedded errors (#1307); require wallet for hosted build orders (#1314); forward apiSecret credentials (#1375); make hosted errors catchable by the base class (#1416); export public SDK option types (#1453); export ExchangeOptions from the package root (#1493); add documented event helper methods (#1492); make Position fields nullable to match Core (#1418); export version constant (#1579).
  • fix(python-sdk): route order-book unwatch via HTTP (#1324); accept wallet address in the Hunch client (#1376); route Myriad wallet address correctly (#1452); type api_secret in exchange options (#1511); export filter function types (#1546).

Installation

npm:

npm install pmxtjs@2.52.0
npm install -g @pmxt/cli@2.52.0

PyPI:

pip install pmxt==2.52.0

Links

What's Changed

New Contributors

Full Changelog: v2.51.4f...v2.52.0f

v2.51.4

Choose a tag to compare

@github-actions github-actions released this 24 Jun 09:51

Fixed

  • Hyperliquid normalizer now extracts resolutionDate from question prose when no expiry: tag is present. Hyperliquid's outcomeMeta payload exposes no structured end-time on either the Outcome or Question objects. Price-bracket markets get a clean expiry:YYYYMMDD-HHmm in the outcome description (parsed); everything else (World Cup teams/matches, Fed funds decisions, CPI prints) puts the deadline only in the question description's legalese, e.g. "by October 14, 2026 at 23:59 UTC". The normalizer now scans the question description for <Month> <DD>[,] <YYYY> [at HH:MM UTC] matches and takes the latest — which is always the resolution deadline (questions often mention an event date and a later cutoff). Defaults to 23:59 UTC when no time is given. Verified against all 28 live HL questions: 27 resolve to the correct deadline (World Cup matches → 2026-07-19, World Cup champion → 2026-10-14, Fed funds → 2026-09-16, CPI → 2026-08-12); the one miss is the Recurring price-bracket parent, which still falls through to the existing outcome-level expiry: tag.

Installation

npm:

npm install pmxtjs@2.51.4
npm install -g @pmxt/cli@2.51.4

PyPI:

pip install pmxt==2.51.4

Links

Full Changelog: v2.51.3f...v2.51.4f

v2.51.3

Choose a tag to compare

@github-actions github-actions released this 24 Jun 09:19

Fixed

  • Hyperliquid normalizer no longer stamps resolutionDate with the Unix epoch when expiry is unknown. core/src/exchanges/hyperliquid/normalizer.ts used expiryDate ?? new Date(0) for the Outcome Markets path, which caused HL markets without a parseable expiry:YYYYMMDD-HHmm metadata tag (e.g., World Cup team markets) to be serialized with resolutionDate = 1970-01-01T00:00:00Z. Downstream consumers that gate on "is this market still tradable?" via resolutionDate <= now() (hosted-pmxt's ingest sweep is one) would then mass-close otherwise-live markets. The field is already optional in UnifiedMarket, so the fallback is now plain undefined — consumers decide policy.

Installation

npm:

npm install pmxtjs@2.51.3
npm install -g @pmxt/cli@2.51.3

PyPI:

pip install pmxt==2.51.3

Links

What's Changed

Full Changelog: v2.51.2f...v2.51.3f

v2.51.2

Choose a tag to compare

@github-actions github-actions released this 23 Jun 09:53

Fixed

  • Hunch list ingestion now surfaces live binary prices instead of zero-priced markets. The Hunch list/catalog item now carries raw.odds; the normalizer uses those YES/NO cents on the bare list path while still letting explicit detail/quote odds win. This unblocks Hunch markets from price-gated cross-venue features such as compare, arbitrage, hedge, and matched-prices.
  • Hunch volume24h now passes through raw.volume24hUsd. The previous hard-zero made the recency/ranking signal unusable for Hunch even when the venue provided a trailing-24h figure.
  • Hunch category and tags now map into PMXT taxonomy. Native Hunch categories roll up to top-level PMXT categories (Crypto by default, eventCulture) and add granular tags such as Market Cap, Price, and the token symbol so ?category= filters and market matching work with higher confidence.
  • Hunch catalog crawls now follow nextCursor. fetchRawMarkets() drains the full paginated catalogue when no explicit limit is supplied, with a 50-page safety backstop; explicit limit calls still fetch a single page.
  • Consumer SDK/generated surfaces were synced for Hunch. Added Hunch to the Python and TypeScript SDK exports and made the client-method generators preserve existing hosted-mode overrides while codegen catches up, so the generated-sync checks stay green without regressing hosted routing.

Installation

npm:

npm install pmxtjs@2.51.2
npm install -g @pmxt/cli@2.51.2

PyPI:

pip install pmxt==2.51.2

Links

What's Changed

  • feat(hunch): surface live odds + 24h volume + Crypto taxonomy + cursor draining by @rajkaria in #1293

Full Changelog: v2.51.1f...v2.51.2f

v2.51.1

Choose a tag to compare

@github-actions github-actions released this 23 Jun 06:13

Followup to the Hunch venue ship in 2.51.0: the adapter was wired into the runtime (factory, registry, exports) but hunch was missing from the ExchangeParam enum in core/scripts/generate-openapi.js. That enum is the source of truth for docs/concepts/venues.mdx (auto-generated), the OpenAPI path enum, and COMPLIANCE.md, so Hunch was invisible on pmxt.dev/docs/concepts/venues and absent from the compliance matrix.

Fixed

  • core/scripts/generate-openapi.js — added hunch to the ExchangeParam enum. Regenerated core/src/server/openapi.yaml, docs/api-reference/openapi.json, and docs/concepts/venues.mdx (now 18 venues).
  • core/scripts/generate-compliance.js — added hunch to EXCHANGE_ORDER. Regenerated core/COMPLIANCE.md (Hunch: 15/20 methods supported).
  • README.md — added Hunch to the supported-exchanges row.

Installation

npm:

npm install pmxtjs@2.51.1
npm install -g @pmxt/cli@2.51.1

PyPI:

pip install pmxt==2.51.1

Links

Full Changelog: v2.51.0f...v2.51.1f

v2.51.0

Choose a tag to compare

@github-actions github-actions released this 22 Jun 13:12

New venue: Hunch (parimutuel prediction market on Base, x402 settlement). And a full assertion-based audit of the Hyperliquid SDK surface (both Python + TS) caught ten silent bugs that prior "did the call throw?" smoke tests had hidden — several since the venue was added. Read paths now have behavioral assertions on shape AND values; trading paths are verified end-to-end against a live mainnet wallet. Final HL state: every no-creds method behaviorally green in both SDKs (43/43 assertions), credentialed reads cross-checked vs HL raw API (open orders: 7/7 exact match; user trades: 2000/2000 match; synthesized closed orders: 104/104 match), and the full createOrder → openOrders → cancelOrder → openOrders-empty lifecycle proven live.

Added — Hunch venue (#1150)

  • core/src/exchanges/hunch/ — new adapter for playhunch.xyz, a parimutuel (pool-based, not CLOB/AMM) prediction market on Base settling in USDC via x402 / EIP-3009. Inventory is crypto-native: token market-cap ladders, up/down, launchpad, date-window markets. Modeled on the Myriad adapter — market-orders only, fetchOrderBook: 'emulated' (single level synthesized from implied price + pool), cancelOrder / limit / sell unsupported.
  • Surface: fetchMarkets / fetchEvents (single-market wrap — Hunch has no event tier) / fetchOHLCV (flat candles from the odds tape) / fetchOrderBook (emulated) / fetchTrades / fetchPositions / fetchBalance. Binary markets → YES/NO outcomes; N-way (mcap ladders, date windows) → one outcome per bucket key. outcomeId encodes ${marketId}:${side} and round-trips back to a Hunch trade side.
  • createOrder runs Hunch's x402 loop: POST /trade → 402 → sign EIP-3009 TransferWithAuthorization (viem) → re-POST with X-PAYMENT → 200 receipt. Orders > $10 fetch a price-locked quote first. Verified end-to-end against the live 402 challenge (no funds moved).
  • Registration: core/src/index.ts (export + registry + Hunch), core/src/server/exchange-factory.ts (case "hunch"), core/src/server/openapi.yaml (ExchangeParam enum), COMPLIANCE.md.
  • Self-hosted creds: HUNCH_PRIVATE_KEY / HUNCH_WALLET_ADDRESS (Base). Hosted-mode trading (Polygon escrow) is out of scope — Hunch settles on Base via x402 — so it lists as read-only hosted / tradeable self-hosted, like Kalshi.
  • Tests: core/test/normalizers/hunch-normalizer.test.ts — 47 tests covering binary + N-way mapping, the money-critical outcomeIdside round-trip, position/balance/OHLCV/emulated-orderbook. tsc --noEmit clean.
  • Known gap: volume24h is 0 (Hunch reports no 24h split; total volume is the pool size). Fast-follow on our side can add it.

Fixed — Hyperliquid

  • core/src/exchanges/hyperliquid/index.tsfetchOHLCV params was typed as required but server dispatch passes a single merged object as args[0], leaving args[1] undefined. Result: any MCP/HTTP call to HL fetchOHLCV crashed with Cannot read properties of undefined (reading 'start'). Default to { resolution: '1h' } so the type-check passes (resolution is required on OHLCVParams) and the call survives even without explicit params. (#1161, #1162)
  • sdks/python/pmxt/client.py + sdks/typescript/pmxt/client.ts — SDKs sent ?id=... for GET reads, but server method-verbs.json spec for fetchOHLCV / fetchTrades declares the first arg as outcomeId. GET dispatcher (queryToArgs in core/src/server/app.ts) peels primitives by spec name, then bundles remaining query keys into the object arg — so outcomeId arrived undefined and the raw id ended up inside params. Downstream fromMarketId(undefined) crashed with Cannot read properties of undefined (reading 'match'). POST was unaffected (positional args). Fixed both SDKs. (#1162)
  • core/src/exchanges/hyperliquid/normalizer.tsvolume24h was hardcoded to 0 for every HL market and event. Fixed by pulling dayNtlVlm from spotMetaAndAssetCtxs (outcome legs appear as coin: '#NNNN'), summing Yes + No notional per outcome, and threading the map through fetchRawMarkets / fetchEventsImpl. One extra batched call, no N+1; fallback to 0 if spotMetaAndAssetCtxs is unreachable. (#1219)
  • core/src/exchanges/hyperliquid/utils.tsfromMarketId only matched hl-outcome-{N}. Passing an actual outcome token (e.g. 100002000, as returned by UnifiedMarket.outcomes[].outcomeId) threw Invalid Hyperliquid market ID. Now accepts either form via decodeAssetId. Affects fetchOrderBook / fetchOHLCV / fetchTrades. (#1252)
  • core/src/exchanges/hyperliquid/fetcher.tsfetchRawMarkets ignored params.marketId, and fetchRawEvents ignored params.eventId. fetchMarket(marketId=X) returned the first market in the venue list instead of X; fetchEvent(eventId=X) always returned the first question. Both filters now applied via fromMarketId and direct id match. (#1254)
  • core/src/exchanges/hyperliquid/fetcher.tsfetchRawOHLCV and fetchRawTrades ignored params.limit. OHLCV returned the entire window regardless; trades returned a fixed page. Now slices client-side after the venue call returns (HL's candleSnapshot / recentTrades have no native limit param). (#1254)
  • core/src/exchanges/hyperliquid/normalizer.tsnormalizeUserTrade left marketId / outcomeId / fee undefined on every fill. Consumers couldn't tell which market a fill was on. Now populated via the existing coinToMarketId / coinToOutcomeId helpers and the raw fee field. Widened UnifiedUserTrade with optional marketId, fee. Verified 2000/2000 trades fully populated on an active wallet. (#1255)
  • core/src/exchanges/hyperliquid/normalizer.tsnormalizeBalance read crossMarginSummary (perp margin) and hardcoded the currency label as 'USDH'. Outcome markets quote against USDC on the spot account, so users with deposited funds saw USDH: 0 and assumed empty. Now reads spotClearinghouseState alongside the perp account; spot balances surface with their real coin label (USDC, USDH, etc.); funded perp surfaces as USDC_PERP so callers can tell it apart. Verified $14.90 USDC deposit now correctly returns USDC: 14.9. (#1280)
  • core/src/exchanges/hyperliquid/index.tssubmitOrder silently swallowed HL rejections. When HL returned statuses[0].error (e.g. "Order must have minimum value of 10 USDC"), the SDK reported status='filled', id='unknown' — fake success with no way for the caller to know the order wasn't placed. Now raises a typed PmxtError carrying HL's message; also correctly populates price / oid on the filled branch (was checked but never read). (#1281)
  • core/src/exchanges/hyperliquid/index.tscancelOrder hardcoded a: 0 (asset id). HL rejected every cancel with User or API Wallet 0xfaf6... does not exist because the action hash with the wrong asset recovers a different signer address. Now looks up the open order to derive the real asset id via encodeAssetId. Throws a typed "Order not found" when the supplied oid isn't open. (#1281)
  • core/src/exchanges/hyperliquid/auth.tsmsgpackr encoded positive BigInts as int64 (0xd3), HL's server (Python msgpack) encodes the same values as uint64 (0xcf). Identical bit pattern, different type byte → action hash mismatch → signature recovers to wrong address. Only manifested on cancel because order actions don't carry BigInt fields; cancel does (oid). Added fixInt64ToUint64 post-processor: HL actions never carry negative ints (oids, nonces, asset ids are all ≥ 0), so flipping d3 → cf when the following byte is < 0x80 is safe and produces byte-identical encoding to Python msgpack. (#1281)

Fixed — Python SDK (cross-venue)

  • sdks/python/pmxt/errors.pyNetworkError / ExchangeNotAvailable rejected the code / retryable kwargs that from_server_error always sets. Any 503 from Kalshi or another venue raised TypeError: ExchangeNotAvailable.__init__() got an unexpected keyword argument 'code' instead of a typed PmxtError. Both classes now accept **kwargs and default-fill their hardcoded values. Caught by the cross-venue Trump search test where Kalshi briefly errored. (#1219)

Added — Hyperliquid

  • fetchEventsPaginated wrappers in both SDKs. BaseExchange.fetchEventsPaginated existed but neither client.py nor client.ts exposed it. Added fetch_events_paginated / fetchEventsPaginated mirroring the existing fetchMarketsPaginated pattern. (#1252)
  • fetchOrderBooks on Hyperliquid. HL has no native batch order-book endpoint. Implemented as Promise.all over fetchOrderBook; inherits the outcome-token-or-marketId resolution from the single-fetch path. has.fetchOrderBooks auto-flips because BaseExchange._deriveCapabilities introspects overrides. ponytail: comment marks the unbounded concurrency for future capping. (#1253)
  • fetchClosedOrders + fetchAllOrders on Hyperliquid. HL exposes no closed-orders endpoint. Synthesize by grouping userFills by oid and excluding currently-open oids — VWAP price, summed size, summed fee, earliest fill time. fetchAllOrders = openOrders ∪ closedOrders. ponytail: comment marks the limitation: cancelled-with-no-fills orders aren't reconstructable from the public info API. Verified against an active wallet: 7 open + 104 derived closed = 111 all, exact-count match. (#1255)

Changed — types

  • core/src/types.tsUnifiedUserTrade widened with optional marketId and fee fields. Existing consumers continue to work unchanged. (#1255)

Fixed — Python SDK (test-suite rot caught at version cut)

Running the full npm test before tagging surfaced six pre-existing failures untouched by the HL audit. Two were the SDK silently broken since the 2.50.11–14 hosted-routing series; the rest were stale test fixtures from earlier intentional behavior changes.

  • **`sdks/python/pmxt/client....
Read more

v2.50.16

Choose a tag to compare

@github-actions github-actions released this 18 Jun 14:40

Fixed

  • sdks/python/pmxt/client.py + sdks/typescript/pmxt/client.tsfetch_open_orders / fetchOpenOrders missing hosted-mode routing branch. Same class of bug as the 2.50.11-14 fixes for fetch_balance / fetch_positions / fetch_order / fetch_my_trades / cancel_order: hosted callers received Trading operations require authentication. Initialize LimitlessExchange with credentials: ... because the SDK fell through to the sidecar /api/{exchange}/fetchOpenOrders path instead of routing to the hosted GET /v0/orders/open?address=... endpoint. Added an is_hosted branch in both SDKs that resolves the wallet address, calls _hosted_request("fetch_open_orders", params={"address": ...}), and maps the response through order_from_v0 / orderFromV0. The self-hosted/sidecar branch is preserved unchanged. Verified live against hosted Limitless: fetch_open_orders() returns [] cleanly and no longer raises.

Installation

npm:

npm install pmxtjs@2.50.16
npm install -g @pmxt/cli@2.50.16

PyPI:

pip install pmxt==2.50.16

Links

Full Changelog: v2.50.15f...v2.50.16f