Skip to content

History / Exchange Markets

Revisions

  • [Automated changes] wiki @ e764960

    @github-actions github-actions[bot] committed Sep 21, 2026
  • [Automated changes] wiki @ e802092

    @github-actions github-actions[bot] committed Sep 9, 2026
  • [Automated changes] wiki @ 7629205

    @github-actions github-actions[bot] committed Sep 1, 2026
  • [Automated changes] wiki @ 9b33381

    @github-actions github-actions[bot] committed Aug 21, 2026
  • [Automated changes] feat(nado): new exchange (#28800) * feat(nado): new exchange, add fetchMarkets fetchCurrencies * feat(nado): add fetchStatus * feat(nado): add fetchTickers & fetchTicker * feat(nado): add fetchOHLCV * feat(nado): add fetchOrderBook * feat(nado): add fetchTrades * feat(nado): add fetchFundingRate & fetchFundingRates * feat(nado): add fetchOpenInterest & fetchOpenInterests * feat(nado): add fetchTime * feat(nado): add createOrder * feat(nado): add cancelOrder & cancelOrders * feat(nado): add fetchOrder & fetchOpenOrders * feat(nado): add error code * feat(nado): add fetchBalance * feat(nado): add cancelAllOrders & editOrder * feat(nado): add fetchClosedOrders & fetchMyTrades * feat(nado): add fetchDeposits fetchWithdrawals fetchFundingHistory fetchPositions * feat(nado): add ws, watchTrades, watchOrderBook, watchBidsAsks * feat(nado): update watchBidsAsks * feat(nado): add watchTicker, watchTickers, watchOrderBookForSymbols, watchTradesForSymbols * feat(nado): add watchOHLCV, add unwatch * feat(nado): add watchOHLCVForSymbols * feat(nado): add watchOrders * feat(nado): add watchMyTrades, watchPositions * feat(nado): update * feat(nado): update * feat(nado): update * feat(nado): update * feat(nado): add builder * feat(nado): update * nado: tp/sl order * nado: fetch open trigger orders * nado: fetch closed trigger orders * nado: add fetch canceled / closed orders * nado: add cancel all trigger orders * nado: add cancel trigger orders * nado: update * nado: add tests * nado: update test * nado: update * nado: update * nado: add builder id * feat(nado): update * feat(nado): update * feat(nado): update * feat(nado): update * add logo * add tests * retrigger * export ts * fix trade * fix build --------- Co-authored-by: carlosmiei <43336371+carlosmiei@users.noreply.github.com>

    @github-actions github-actions[bot] committed Jul 28, 2026
  • [Automated changes] feat(mexc): update (#29205) * docs(mexc): add apis, update @see, update docs * feat(mexc): update cancelAllOrders * feat(mexc): update closeAllPositions

    @github-actions github-actions[bot] committed Jul 16, 2026
  • [Automated changes] fix(build): retrigger

    @github-actions github-actions[bot] committed Jul 15, 2026
  • [Automated changes] docs(toobit): add apis, update @see, update docs (#29213)

    @github-actions github-actions[bot] committed Jul 15, 2026
  • [Automated changes] feat: Prediction on ccxt (#28752) * restore eslintrc * fix liniting * add missing tpyes * missing config file * rm js folder * rm file * polymarket static tests * fix request tests * fix(pro): make ArrayCacheBySymbolById keyField non-enumerable keyField was set via a plain assignment, which on an Array subclass creates an enumerable own property. It then leaked into array equality/iteration, breaking the base WS cache test (assert equals(cache, [object2, object3])) once the JS was freshly transpiled. Define it via Object.defineProperty like the other internal cache fields so it stays invisible; ArrayCacheByOutcomeById still overrides the value via its writable reassignment. * fix(examples): use comma args in prediction-common-fed-event console.log The example transpiler rejects console.log with + concatenation (breaks the Python/PHP/C#/Go example transpile step); switch to comma-separated args. * remove symbol from prediction types * add more filtering options to prediction * use sort and other params * add example * update example * update types.py * remove loadMarkets calls and marketSymbol refs * rm loadMarkets and others * remove symbol > outcome * rm more symbol * rename symbol to event * update example * fix precision * some kalshi fixes (still not working signing) * some hL fixes * some fixes and HL example * fix limitless order placement using eoa * kalshi signature fix * fix markets kalshi * add example * feat(prediction): outcome convention, native PredictionOrderBook + types, cross-lang fixes Source + transpiler contribution on top of the prediction-on-ccxt base (generated per-exchange files intentionally omitted — they regenerate from this source). - prediction methods use the `outcomes`/`outcome` handle, not `symbols` (industry convention): fetchTickers/fetchPositions take `outcomes` across all 5 exchanges - safePredictionOrderBook base helper; fetchOrderBook returns PredictionOrderBook (outcome/outcomeId/market, no symbol) consistently in all 5 exchanges - native dedicated structs PredictionOrderBook / PredictionTradingFee / PredictionOpenInterest in C#/Go/Java (+ transpiler type mappings) — they were referenced by generated wrappers but never defined, so prediction didn't compile - fetchEvents typed with fetchEventsParams; mapped per language - base filterByValueSinceLimit uses safeValue(entry,field) so a missing field is a non-match, not a python/php KeyError on outcome-keyed structures - Go transpiler: prediction methods that rename a base option param emit a prediction-local options struct (FetchTickersOptionsStruct{ Outcomes }); generate go/v4/prediction/exchange_dynamic.go; map fetchEventsParams - myriad populateOutcomes normalizes legacy symbol/id/marketSymbol keys (Go/C#/Java don't dispatch the prediction setMarkets override) - Java EIP-712 signing (ethEncodeStructuredData root type, encode, ethAbiEncode) - test framework + cli: prediction is async-only (ccxt.prediction.<id>); java cli loads optional credentials and respects real args - regenerate prediction kalshi abstract (PortfolioEventsOrders) Static response tests pass for polymarket/kalshi/limitless/myriad in all six languages when regenerated from this source. (myriad watchTickers stays `symbols`: WS options live in the pro package — outcome rename there is a follow-up.) * refactor(prediction): WS methods use outcome(s); drop symbol aliases - all prediction watch* methods take outcome/outcomes (matching REST + the base PredictionExchange declarations): myriad watchTickers/watchPositions/watchTicker/ watchOrderBook/watchTrades/watchMyTrades/watchOHLCV/watchOrders, polymarket watch* — no more `symbols` - use outcome/outcomes directly in the method bodies instead of a `const symbol = outcome` alias (cleaner; same for the REST fetchTickers/ fetchPositions) - Go transpiler: copy the cached extractTypeAndFuncNames Set before deleting the prediction-local option-struct names — mutating the shared cache de-qualified WatchTickersOptions/WatchPositionsOptions in other exchanges' base delegations WS list methods that rename a base option param (watchTickers `outcomes` vs base `symbols`) now emit a prediction-local options struct with Outcomes, like the REST fetchTickers fix. * fix(kalshi): parseOrder reads V2 order fields (live-verified on demo) The V2 order objects (GET /portfolio/orders, fetchOpenOrders) return yes_price_dollars/no_price_dollars (already dollars), initial_count_fp, fill_count_fp and remaining_count_fp — parseOrder only read the legacy yes_price/no_price (cents), count and filled_count, so fetched orders came back with price/amount/remaining undefined. Now read the V2 fields (price by the outcome's own YES/NO leg) with legacy fallbacks. Verified live on the demo environment (demo-api.kalshi.co): RSA-PSS signing, fetchBalance, createOrder (resting limit), fetchOpenOrders, fetchOrder and cancelOrder all work; fetched orders now report price/amount/remaining correctly. * feat(prediction): RSA-PSS signing in all 6 langs + outcome convention cleanup - RSA-PSS support in PHP (manual EMSA-PSS via openssl NO_PADDING since ext-openssl has no native PSS), C#, Go and Java base crypto, so kalshi's RSASSA-PSS request signing works in every language - kalshi fetchMarkets: hoist .length to locals + use arraySlice so the PHP regex transpiler emits count()/array_slice() not strlen()/mb_substr() - base parseOrders / parseTrades / filterByValueSinceLimit: use safeValue/safeString so prediction structures keyed on outcome (no symbol) don't KeyError in python/php - goTranspiler: prediction-local option structs for outcome-renamed params - drop doubled "outcome outcome" docstring artifacts across all 5 exchanges Live-tested kalshi create/fetch/cancel on the demo env in TS, JS, Python, PHP, C#, Go and Java. * fix(kalshi): cancelAllOrders uses the real batched-cancel endpoint cancelAllOrders hit DELETE /portfolio/orders which 404s — kalshi V2 has no "cancel all" endpoint. Now it fetches the resting orders and batch-cancels them by id via DELETE /portfolio/orders/batched, chunked to 20 ids/call with arraySlice (transpiler-safe — no variable-step for loop). Dropped the phantom portfolio/orders DELETE from the api block. Live-verified on the kalshi demo: swept 32 leftover resting orders -> 0 (JS), and create->cancelAllOrders->0 (Python). Builds clean in all 6 langs. * fix(base): Go ethEncodeStructuredData infers nested EIP-712 root type toTypedDataTypes hardcoded the primary (root) type as OrderWithBuilderFee→ Order→first-key, so nested typed data like the ERC-7739 TypedDataSign(Order contents,…) wrapper picked "Order" and hashed the wrong struct (the go-ethereum apitypes "doesn't match type 'address'" panic). Now the root is inferred as the struct no other struct references as a field type — matching ethers' TypedDataEncoder. Unblocks polymarket deposit-wallet (signatureType 3) createOrder signing in Go. Live-verified on the real polymarket CLOB: deposit-wallet createOrder → open → cancel in Go; signClobOrder byte-identical to JS/Python/Java/C#/PHP. hyperliquid/derive/paradex Go static request tests still pass (no regression). * fix(polymarket): make createOrder signing transpile correctly to PHP Five php-regex-transpiler issues that blocked deposit-wallet createOrder in PHP (the other 5 languages were already correct): - sign(): 'auth/derive-api-key' built by concatenation so the `api` param name does not leak into the literal as '$api' (broke the L1-auth routing) - signClobOrder: param renamed signatureType→sigType and local chainId→ chainIdValue so neither leaks into the 'Order(...)' / 'EIP712Domain(...)' type-string literals (which feed the EIP-712 type hashes) - signClobOrder: compare parseToInt(sigType) !== 3 — php types the number param as float and 3.0 !== 3 (strict) always took the wrong (EOA) branch - signClobOrder: orderTypeString.length used inline so php emits strlen(), not count() (the `const n = str.length;` form wrongly assumes an array) - L2 HMAC: unchained the .replaceAll calls (php converts only the outermost) - buildClobOrderBody: made synchronous (no I/O) — a no-await async method transpiles to a php promise-typed wrapper returning a plain array, throwing Live-verified deposit-wallet createOrder → open → cancel on the real polymarket CLOB in ALL 6 languages; signClobOrder byte-identical across all. * fix(base): Go auto-loads prediction outcomes after loadMarkets Go has no virtual dispatch, so base loadMarketsHelper's this.SetMarkets() bypassed the PredictionExchange.SetMarkets override that builds the outcome lookup — leaving this.Outcomes nil after LoadMarkets, so every outcome-resolving method (fetchTicker/fetchOrderBook/createOrder/…) panicked "outcomes not loaded" in Go for ALL prediction exchanges. loadMarketsHelper now invokes setOutcomesFromMarkets() on the concrete instance via a type assertion when it implements it (non-prediction exchanges do not, so they are unaffected). Mirrors the TS override that runs inside setMarkets. Live-verified: limitless createOrder → open → cancel works in Go with no explicit SetOutcomesFromMarkets() call (Outcomes auto-populates, count 820). * fix(base): Java omits Content-Type on body-less requests The Java HTTP client forced Content-Type: application/json on every non-GET request even when the body was empty, diverging from the other languages. Some APIs reject that — limitless DELETE /orders/{id} returns 400 "Body cannot be empty when content-type is set to 'application/json'". Now Content-Type is sent only when the exchange set one explicitly, or there is an actual request body. Live-verified: limitless createOrder -> open -> cancelOrder now works in Java. * chore(prediction): regenerate generated files across all 6 langs after the master merge The upstream merge auto-merged committed generated files, leaving the prediction base classes, abstracts and per-exchange files stale/inconsistent — and it corrupted go/v4/exchange_generated.go (duplicated content → syntax error, Go package wouldn't build). Regenerated from the merged source: - prediction base classes: PredictionExchange.{cs,java}, exchange_prediction.go, prediction_exchange.py, PredictionExchange.php - kalshi abstract (the new portfolio/events/orders endpoint) across langs - per-exchange prediction generated files (Go/C#/Java/Python/PHP) - go/v4/exchange_generated.go rebuilt (removes the merge's duplicated funcs) All six languages now build/transpile clean: TS (tsBuild), JS, Python, PHP, C# (0 errors), Go, Java (compileJava). Non-prediction *_api.go whitespace churn from the abstract regen was reverted to keep the diff scoped; C# Exchange.BaseMethods.cs left as merged (builds fine). * docs(prediction): build per-exchange docs + prediction sections in wiki, website, skills - jsdoc2md.js: render the prediction exchanges (js/src/prediction) to wiki/exchanges/prediction/<id>.md and index them in the sidebar, so the jsdoc→md docs build now covers prediction exchanges (own subdir avoids the hyperliquid name collision with the regular exchange) - build/wiki-to-fumadocs.ts: emit a "Prediction Markets" sub-group under Exchanges on the website (website/content/docs/exchanges/prediction/ with its own meta.json, referenced from the parent meta) - wiki/Manual.md: fix the Prediction Markets section — async-only Python/PHP namespaces (no async_support / async\ sub-namespace) and the outcome convention (outcome/outcomeId, not symbol/id); add a createOrder example - .claude/skills/ccxt-{typescript,python,php,csharp,go,java}: add a Prediction Markets section (namespace access, outcome convention, create/cancel example) * docs(prediction): list prediction exchanges in Supported Exchanges, by-country & examples - build/export-exchanges.js: inject the prediction-exchange table into wiki/Exchange-Markets.md (+ README) via the prediction-list markers, and include prediction exchanges in the Exchange-Markets-By-Country listing (polymarket/kalshi declare US; the country-less DEX-style ones don't group, same as other country-less exchanges) - wiki/Exchange-Markets.md + README.md: add the "Prediction Market Exchanges" section + markers the generator fills - wiki/examples: prediction example docs (via examples2md.js) now generated for ts/py/php/cs/go, so they show in the website Examples section Verified on the rebuilt fumadocs site: /docs/exchange-markets shows the 5 prediction exchanges, /docs/exchange-markets-by-country lists polymarket+kalshi under United States, and the prediction example pages serve under /docs/examples. * docs(prediction): animated data-model diagram, sortable exchanges table, unified-methods catalogue - new Prediction Markets guide (wiki/Prediction-Markets.md) as the /docs/prediction tab index, with a bespoke animated Event -> Market -> Outcome -> methods diagram (PredictionDataModel) and a grouped catalogue of every unified PredictionExchange method, replacing the thin fetchEvents/fetchEvent-only overview - add a "Prediction" top-nav link (-> /docs/prediction/polymarket, mirroring Exchanges -> binance) since the sidebar root-switcher is disabled - merge the 5 prediction exchanges into the main Supported Exchanges table via a sortable/filterable ExchangesTable component (search, type/certified/pro filters, column sort, logo fallback); wiki-to-fumadocs parses the markdown tables into its data - wire ```prediction-diagram / ```exchanges-table fences to components via a rehype step - Manual.md points to the new guide; home page card -> /docs/prediction * docs(prediction): fail the build if the Supported Exchanges table parses to empty parseExchangeMarkets is coupled to export-exchanges.js's markdown (column order + the <!--- init list -->/<!--- init prediction list --> markers). Throw with an actionable message when crypto or prediction rows parse to 0, instead of silently shipping a blank <ExchangesTable/>. * test(prediction): live-test harness for prediction exchanges across all languages Make run-tests.js exercise every prediction-market method (public, private, and order placement) live in all six languages, and capture the gaps that geo-blocking and TLS fingerprinting leave for static fixtures. Harness (transpiles to JS/Py/PHP/C#/Go/Java): - tests.ts: runPredictionTests resolves the outcome handle from typed markets and drives prediction-specific + trading methods via dynamic dispatch (each wrapped in try/catch for Java's checked exceptions); --fundedTests gates a non-marketable place-then-cancel order (0.10 USD); createOrder honors a getSkips() skip so geo-blocked CI does not attempt placement - tests.helpers.ts: resolve ids present in both namespaces to ccxt.prediction only under --prediction (hyperliquid collision) - base validators guard prediction shapes (market/ticker/trade/orderBook/ position/tradingFee), afterConstruct reads options via safeDict, and fetchTickers tests by outcome handle instead of the no-arg "all" path Runner + per-language infra: - run-tests.js concatenates ids+prediction and adds --prediction/--fundedTests - utils/check_modified_files.sh detects ts/src/prediction/*.ts changes - python argparse learns --prediction/--fundedTests; php memory_limit 2048M for kalshi's ~1000 markets Exchange fixes surfaced by live testing: - kalshi: migrate cancelOrder/cancelAllOrders to the V2 endpoint (DELETE /portfolio/events/orders/{order_id}; v1 is 410 Gone) and sanitize negative bid/ask sizes in parseTicker - PredictionExchange: fix strlen-on-array transpile of queries.length Static + skips: - skip-tests.json: route kalshi + polymarket through the CI proxy and skip polymarket createOrder live (geo-blocked); signing stays covered by the request fixtures - add polymarket createOrder/cancelOrder response fixtures (pass JS/C#/Go; Python/PHP prediction static tests are a pre-existing async-harness gap) * ignore transpiling for now * require query search inside fetch events * pretty print events in cli.ts * -p support in CLI * fix CLi and HL * fix(base): apply credentials in Go SetProperty and accept any slice in ArrayConcat Two Go base bugs surfaced while live-testing prediction exchanges, both affecting all exchanges (not just prediction): - SetProperty only set a field when the value was already assignable to it, but it did not guard the reflect.Set, so a plain map passed for a typed field (e.g. Options *sync.Map) would panic. Now it skips when the value is not AssignableTo the field type. - ArrayConcat did a hard aa.([]any) assertion and panicked on []string (which ObjectKeys returns in Go — the balance validator feeds it exactly that). It now copies elements through reflection so any slice type works, and drops a dead duplicate branch. * test(prediction): force the prediction namespace under --prediction in every language Live-verify prediction trading (create→cancel + private reads) across all six languages, which required the test harness to actually build the prediction class. - For ids present in both namespaces (only hyperliquid), every non-JS init helper fell back to prediction only when the id was ABSENT from crypto, so --prediction was ignored and it built the crypto class — Go's "pass" was a false positive (no prediction outcome line). Now python/php/cs/go/java honor --prediction; C#/Java add a forcePrediction param to the lib DynamicallyCreateInstance and the test BaseTest passes getCliArgValue("--prediction"). - Go SetExchangeProp passed the value as the property NAME (so creds were never set) and FieldByName is case-sensitive — fixed to capitalize and pass the name. - Harness reads skip-tests.json preferredPredictionOutcome (some venues list many resolved/halted markets whose first outcome can't be traded) and fundedAmount/ fundedPrice (hyperliquid testnet has a 10 USD min vs the default 0.10 USD). - Validator prediction guards: test.order skips symbol; test.position skips the derivatives-only fields a share-holding lacks; test.sharedMethods assertType accepts a dict against an empty-array format marker (PHP's is_dictionary([]) is false, so an empty {} format failed — no-op in JS, binance response tests pass). * make search easier and more flexible * fix(hyperliquid): transpile prediction createOrder/fetchEvents to PHP and typed langs Surfaced when the cross-language harness finally ran the prediction hyperliquid: - fetchEvents and initializeClient were async with no await, so the PHP/typed transpilers emit a non-promise the caller's await then chokes on. Both now await loadMarkets() at the top, which is also correct — fetchEvents builds events from the loaded markets client-side and createOrder needs them to resolve the outcome handle. - signHash did signature['r'].padStart(...) on a subscript, which leaks an undefined padStart() call in PHP — assigned to a bare local first. * feat(polymarket): send the PING heartbeat required by the CLOB websocket Polymarket's market and user ws channels have no protocol-level ping-pong and require a plain-text "PING" every 10s (the server replies "PONG", already skipped as a string frame). The implementation handled incoming PONG but never sent PING, so idle connections would drop. Added a streaming block (ping + keepAlive 10000) and a ping() returning "PING". Verified live in JS: watchOrderBook streams and watchOrders receives the open/canceled events for a placed-then-cancelled order. * test(prediction): scope fetchEvents with a query where the venue requires one The prediction fetchEvents implementations now call requireEventQuery (added on this branch), which throws unless the call is scoped by query/queries/tags/eventId/ slug — so the harness's unscoped fetchEvents([]) broke for every prediction exchange. runPredictionTests now passes a skip-tests.json preferredEventQuery as {query} when set. Added matching queries (verified to return events): polymarket trump, myriad/limitless bitcoin, hyperliquid WORLD, kalshi trump. * fix trades/mytrades * fix(base): send the first ws ping after one keepAlive interval, not on connect The Python aiohttp ws client's ping_loop sent the first ping immediately on connect, before the subscribe frame. Some servers (e.g. Polymarket's CLOB ws) close the connection (1006) if a ping arrives before the subscribe. The JS client already waits one interval (setInterval fires after keepAlive), so this aligns Python with it by sleeping before the first ping. * fix(polymarket): use safe dict access in the ws order-book and trade handlers handleOrderBookSnapshot/Delta and handleTrade read this.orderbooks[outcome] and this.trades[outcome] directly, which raises KeyError in Python (JS returns undefined). Use `outcome in this.orderbooks` and safeValue for the existence checks, matching the standard pro exchanges (okx/binance). Fixes the Python ws KeyError once the connection stays open. * test(prediction): route prediction WS to the prediction class in every language The harness instantiated ccxt.pro.<id> for any --ws run, but prediction exchanges have no ccxt.pro variant — their watch* methods live on the main prediction class (no separate pro namespace), so this errored with "ccxt.pro[id] is not a constructor". The init helpers now resolve the prediction namespace before the ws/pro branch in all six languages (JS/Python/PHP route to the prediction class; C#/Go/Java keep the bare id and let forcePrediction pick the non-pro prediction package). The watch* tests now run for prediction exchanges in every language. * fix fetchPositions * fix(polymarket): orderBook({}) for empty book + ws keepalive on text PONG this.orderBook([]) builds an empty book from an empty *list*, which the typed languages reject: C#/Go cast the snapshot to a dict, an empty list becomes null, and the dict constructor dereferences nil (this was the C# watchTicker NPE). Use {} (the standard pro pattern) so the empty book is a dict in every language. Polymarket keeps the ws alive with text PING/PONG (not protocol frames), so the client's onPong never fires; refresh client.lastPong on the "PONG" reply so the Go keepalive does not drop the connection after maxPingPongMisses. Add wsProxy for polymarket so C#/Go can reach the ws endpoint (their TLS fingerprint is rejected directly by Cloudflare; mirrors the existing httpsProxy). * fix(go): unblock prediction test harness build The prediction Go test harness failed to compile (blocking every Go test, including ws): - ICoreExchange was missing FetchTransfers, which the generated test.fetchTransfers.go references on the exchange interface. - test.fetchTransfers declared an unused `now`; Go rejects unused variables. * fix(tests): null-safe C# dump() on null args C# dump() called value.ToString() with no null guard and crashed on a null argument, unlike the JS/Python/PHP dumps which stringify null. The prediction ws tests dump exchange.json(eventId), and eventId is null in C# (ws tests carry no eventId). * fix(polymarket): avoid KeyError in tokenIdToSymbol on the ws trade path The markets_by_id fallback used bare marketsById[tokenId] and market['symbol']; both are undefined in JS but raise KeyError in Python when the token is not a market id, which crashed watch_trades when a trade arrived. Use safeDict/ safeString so the lookup degrades to undefined in every language. * fix(pro): ArrayCache.append tolerates items without a 'symbol' (python) The Python ArrayCache.append read item['symbol'] directly, which raises KeyError for items that carry 'outcome' instead of 'symbol' (prediction ws trades, whose 'symbol' is stripped by safePredictionTrade). JS yields undefined for the same access, so this is a Python-only port gap. Use item.get('symbol'). Blast radius: every Python async watch* using ArrayCache. No behavior change for items that have 'symbol' (regression-checked); symbol-less items no longer crash. Verified live: polymarket watch_trades now returns trades with zero KeyError. * feat(prediction): prediction types for all unified methods, WS book identity, PredictionOrderRequest - promote the unified methods onto PredictionExchange with Prediction* return types (fetchOrderTrades, fetchMyTrades, fetchPosition, createOrders, cancelOrders, watchOrders, watchMyTrades, watchPositions, watchTickers, fetchOpenInterest, fetchTradingFee, createMarket*OrderWithCost, ...) so venues that don't override a method still expose prediction-typed signatures instead of the crypto Exchange fallback; Go/C# wrappers source from the prediction base for inherited methods - watchOrderBook returns PredictionOrderBook in the Go/C# typed bindings, and the live WS OrderBook cache carries outcome/outcomeId/market in all 6 languages (added conditionally so crypto order books are unchanged) - add PredictionOrderRequest (outcome instead of symbol) for createOrders - fix Go implicit-api casing (callEndpointAsync -> CallEndpointAsync) - fix Python prediction base type import * test(polymarket): createOrders static fixture uses outcome (PredictionOrderRequest) The createOrders request fixture still passed each order as { symbol: ... }; since createOrders now reads `outcome` (PredictionOrderRequest), update the fixture key so the static request test passes in JS/C#/Go. * docs(prediction): JSDoc for the PredictionExchange base unified methods Add JSDoc blocks to the unified methods promoted onto PredictionExchange (fetchOrderTrades, fetchMyTrades, fetchPosition, createOrders, cancelOrders, watch*, fetchOpenInterest, fetchTradingFee, createMarket*OrderWithCost, the retyped fetch*/create*/cancel*/watch* single-outcome methods, ...). These drive the generated Python/PHP/C#/Go docstrings. * fix(prediction): resolve cross-language user-test bugs + regenerate stale outputs Source fixes: - limitless: hoist allRaw.length to a named local (was mis-transpiled to strlen() on an array, fataling fetchMarkets in PHP/Python) and route the six "pad hex to even" sites through a padHexToEven helper (inline `.length % 2` became a broken 1-arg fmod() in PHP, breaking EVM signing) - polymarket: seed the WS order book via a hoisted local so `orderBook({})` transpiles to a map/Dictionary, not a list/slice (was a deterministic WatchTicker NullReferenceException in C# and a process panic in Go); add the missing `market` field to fetchOpenInterest and fetchTradingFee for shape parity with every other prediction structure - PredictionExchange: an unknown outcome now throws BadSymbol (was ArgumentsRequired) - php/pro/ArrayCache: fall back to the `outcome` handle when an item has no `symbol` (prediction trades flooded watchTrades with undefined-key warnings) - transpile.ts: detect PredictionOrderRequest in Python param annotations so venue files import it (createOrders) instead of NameError-ing at import Regenerate the prediction package across all six languages (the committed generated code was stale: kalshi/limitless called a renamed checkEvents, exchange_generated.go was missing CleanWsData/CleanRestData so a fresh checkout didn't compile Go, and the watchOrderBook/typed-base fixes hadn't propagated). Builds/transpiles + static request/response + WS base tests pass in all six languages; kalshi/limitless verified live in Python/PHP and the WatchTicker crash verified fixed in C#. * fix(prediction): drop unused `symbol` key from WS order books (REST/WS parity) The live WS OrderBook cache always seeded a `symbol` key, so watchOrderBook returned `{ symbol: undefined, ... }` while REST fetchOrderBook (via safePredictionOrderBook) omits it — `'symbol' in book` diverged between WS and REST for the dict-based languages (JS/Python/PHP) and Java's toMap. Prediction books are keyed by `outcome`; drop `symbol` in reset()/toMap when an outcome is present (crypto books keep `symbol` unchanged). Verified live: REST and WS now agree (no `symbol`, has `outcome`); WS base tests still pass. * fix(kalshi): resolve market search via events endpoint; tidy fetch-limit options fetchMarkets({query}) sent only limit/cursor to the API and filtered every open market client-side, paging ~25 x 2.6MB and hanging. It now resolves the query against the events endpoint (bounded, multi-query, server-scoped) and returns the matched events' markets; the events scan drops nested markets so matched events fetch their own (4x faster, ~100s -> ~23s). Also: wire the previously-dead defaultFetchEventsLimit option, drop the phantom fetchMarketsLimit (read but never defined) in favour of maxFetchMarketsLimit, fix the maxPages JSDoc (5 -> 50), and regenerate the stale TS abstract (kalshiPrivateDeletePortfolioEventsOrdersOrderId). * fix(examples): correct prediction example imports, fetchEvents scoping, and outcome fields The prediction examples under examples/ts/prediction/ couldn't run: - import path was one level too shallow (../../ts -> ../../../ts) - fetchEvents(['x']) used an array shorthand the API never supported; use fetchEvents({ queries: ['x'] }) - read .outcomeId for the unified outcome id (.id/.symbol are undefined on polymarket/limitless) - unscoped fetchEvents() now throws (requireEventQuery); use loadMarkets() to prime outcomes, or a scoped query - hyperliquid fetchOHLCV needs loadMarkets() first - prediction-fetch-events-options scopes each case with a query All public read examples verified live; the private templates now reach the auth step (still need real credentials). * feat(prediction): auto-load & cache outcomes like loadMarkets Outcome-addressed methods now auto-load on first use and serve from cache, mirroring loadMarkets()+market() — no more "fetch events first" throws. Base PredictionExchange: - loadOutcomes(reload, params): bulk loader (loadMarkets + populateOutcomes), idempotent, mirrors loadMarkets reload/params - loadOutcome(id): per-call resolver — cache hit, else bulk-warm (options.loadAllOutcomes, default true) or single-fetch via fetchOutcome - fetchOutcome(id): "fetch one" — base bulk-fallback; exchanges override - populateOutcomes(): rebuild caches from markets (renamed from setOutcomesFromMarkets; myriad's duplicate removed); checkEvents() removed Single outcome → loadOutcome(id), full set → loadOutcomes(); fetchOrder resolves cache-only (1 request). kalshi has too many markets to bulk-load, so it sets loadAllOutcomes=false and overrides fetchOutcome to fetch one market by ticker and cache it. Both unified handle and native outcomeId resolve once loaded (dual index). Pattern documented in .claude/rules/prediction-outcomes.md. Verified live on all 5 exchanges; builds across all 6 languages. * fix(kalshi): classify not-found 404 as BadSymbol; clearer cold fetchOutcome error kalshi's missing-market 404 ({"error":{"code":"not_found"}}) was mapped by the base to ExchangeNotAvailable — indistinguishable from an outage. Add handleErrors + an exceptions block mapping not_found -> BadSymbol, and have fetchOutcome re-throw it with a hint ("pass an outcomeId, or call fetchEvents()/loadOutcomes() first") for a cold unified handle, while letting genuine network errors propagate. * fix(prediction): export prediction namespace from the built js/ccxt.js bundle The tracked js/ccxt.js was stale — it never re-exported the prediction namespace after the prediction exchanges were added, so `ccxt.prediction` was undefined from the built bundle (breaking the canonical JS/TS examples and normal `import ccxt from 'ccxt'; ccxt.prediction.*` usage). Regenerate the bundle + its .d.ts so `prediction` is exported. * Revert "fix(prediction): export prediction namespace from the built js/ccxt.js bundle" This reverts commit 669a983e8c59d7da8c1413a8326841fba9ecb512. * fix(examples): make python prediction example self-contained examples/py/prediction_markets.py did a bare `import ccxt.prediction`, which picks up a pip-installed ccxt (no prediction) instead of this repo. Prepend the repo's python/ to sys.path so it runs directly with `python3 examples/py/ prediction_markets.py` (matching the PHP example, which self-includes ccxt.php). * fix(examples): close(True) to tear down REST session in python prediction example * fix(prediction): outcome-aware parsing fixes + parsePrediction* base aggregators - PredictionExchange: add parsePredictionTrades/Orders/Positions - the base parseTrades/parseOrders/parsePositions post-filter by the market 'symbol' key (or resolve symbols), silently dropping prediction structures; all call sites in the five exchanges converted - limitless: fetchTrades always returned []; optional-outcome methods (fetchMyTrades/fetchOrder/fetchOrdersByIds/cancelOrder/cancelOrders/ cancelAllOrders) threw BadSymbol when outcome was omitted - kalshi: fetchPositions outcomes filter never matched; fetchOpenOrders dropped every row in python; parseOrder now derives the leg from the raw side ('no' -> ticker + '-NO') instead of always resolving the YES leg - polymarket: parsePosition raw ['event'] access crashed python; empty params serialized to a "[]" body in php (empty array is also an empty dict there) - hyperliquid: restore userFills/userFillsByTime in fetchMyTrades (it delegated to the public recentTrades tape) - all: import error classes from base/errors.js, not the ccxt.js bundle (circular import crashed deep imports of prediction modules) - cs: rsa() PEM parsing drops header/footer by content, tolerating the trailing newline openssl writes (kalshi RSA-PSS keys) - fixtures: first kalshi private fixtures (committed throwaway PKCS#1 RSA key; C#/Go rsa are PKCS#1-only), fetchPositions/fetchOpenOrders/fetchMyTrades coverage, refreshed stale fetchTrades captures that had enshrined the bugs * fix(tests): prediction CI paths — async-only sync skip + namespace-aware scoped tooling - static fixtures declare asyncOnly; the python/php sync harnesses skip them (prediction is async-only there by design) — full python sync sweep passes 4448 tests instead of crashing on the first prediction id - transpile.ts/csharpTranspiler/goTranspiler/javaTranspiler auto-route bare prediction-only ids (e.g. 'transpile.ts kalshi') to ts/src/prediction/, so the scoped CI transpile steps work unchanged - goTranspiler always emits the full prediction set (a single-exchange run truncated the shared exchange_wrapper_structs.go) - js.yml scoped lint resolves ts/src/prediction/ paths - regenerated test harnesses (cs generated tests were stale vs ts/src/test) * fix(prediction): export the prediction namespace from the built js bundle js/src/prediction modules were committed but js/ccxt.js never regenerated, so ccxt.prediction was undefined for every ESM/CJS/browser consumer; also brings the committed prediction js modules and the js test harness current with ts * fix(prediction): remove broken python async_support/pro stub subpackages ccxt.prediction is flattened async-only in python; the stubs imported modules that don't exist and shipped in the wheel as instant ModuleNotFoundError; align the prediction __init__ version and drop the stubs from vss * chore: remove committed scratch/debug debris probe scripts (lmtsprobe/, cs/lmtsprobe/), design-doc drafts (prediction-types-proposal.*, prediction-types.ts) and an unreferenced 145 KB sample payload (ts/src/base/polyMarketEvent.json) * docs(examples): polymarket spain-world-cup prediction example * fix(prediction): unify the market field + outcome auto-load stragglers - myriad (9 sites) and hyperliquid (6 sites) reported the outcome handle in the 'market' field instead of the parent market symbol; myriad parseOrder read outcomeId from the legacy 'id' key; hyperliquid parseTicker day-volume now resolves the parent market so quoteVolume is populated - polymarket watch* auto-load the outcome cache instead of throwing on a cold instance (watchOrderBook/watchTrades/watchTicker/watchOrders/watchMyTrades) - hyperliquid fetchTickers()/fetchPositions() warm the outcome set on a cold instance instead of silently returning nothing - kalshi fetchBalance/fetchOrder/cancelOrder/cancelAllOrders no longer force a full market-listing scan for label-only lookups (1 request instead of 30+) * docs(prediction): JSDoc for the parsePrediction* base helpers * fix(build): make the full CI transpile/test matrix pass end-to-end - csharpTranspiler/goTranspiler: the prediction pass inside transpileEverything reused the CLI's regular-exchange ids and tried to transpile them from ts/src/prediction/ — every --multi worker crashed (this broke CI's transpileCS); scoped runs with no prediction work now skip the pass - goTranspiler: safeOptionsStructFile's non-prediction tail referenced phantom locals (isPrediction/isWs/needsCcxtImport/structsContent) — restored the upstream loop; csharpTranspiler: createCSharpClass passed an undefined restNamespace arg in the ws pass - transpile.ts: the prediction WS-import block also fired for regular pro files, duplicating the ArrayCache import in every python/ccxt/pro/*.py (ruff F811) - cs base: convertToBigInt passes hex strings through (extended's stark chain parses hex itself; decimal strings still become BigInteger for eip-712), numberToString/intToBase16 handle BigInteger (not IConvertible) - prediction sources: ruff-clean comments (E265) and truthiness instead of '!== null' (E711); drop the unused asyncio import and kalshi's comment-induced unused error import - export the prediction namespace from dist/cjs and the browser bundles - spain-world-cup example: PredictionMarket has no 'symbol' (tsBuildExamples) * docs(examples): regenerate prediction example docs * fix(merge): post-merge reconciliation with upstream master - go/v4/exchange_interface.go: both sides added FetchTransfers (branch harness fix + upstream #29012); dedupe the auto-merged duplicate - wiki/Exchange-Markets.md: restore the prediction-table markers upstream's side didn't carry, regenerate the table - regenerate the js/dist bundles on top of the merged sources * chore: mark dist/js and prediction generated outputs linguist-generated * fix(prediction): review-round bug fixes, live event cache, prediction CLIs everywhere - kalshi: fetchOHLCV(since) without limit sets end_ts; parseMarket reads the current volume_fp/liquidity_dollars/open_interest_fp keys; cancelOrder backfills id/status (the delete response carries neither) - polymarket: parseEvent maps the real gamma keys (createdAt/endDate/image/ updatedAt/closed) and carries 'active' so the client-side status filter works - limitless: missing privateKey throws ArgumentsRequired instead of a raw TypeError; feeRateBps defaults to 0; search honors params.limit (capped at the API max of 50); fetchAccounts/approve has-flags; myriad declares pro:true - PredictionExchange: event cache is live - applyEventFetchParams merges every fetched event into this.events/events_by_slug, setEvents accumulates, getEvent() resolves cache-only ('event' is a C# keyword, hence the name); dropped the never-usable reloadingEvents/eventsLoading members - CLIs: python/php/go/c# route prediction ids to the prediction namespace (regular ids win for duals, --prediction forces); go gets a generated prediction exchange_metadata.go wired into export-exchanges/vss live-verified: kalshi DEMO full trading lifecycle (create->fetch->open->cancel ->refetch) in js and python, demo fetchBalance through all four CLIs, plus polymarket events/cache, limitless limits and the privateKey guard * fix(prediction): full-matrix live-test fixes across all six languages - limitless: fetchOHLCV buckets raw price points into timeframe-aligned candles (single points carried unaligned timestamps; inline bucketing - buildOHLCVC transpiles to a mangled name; php needs the value-copy write-back) - hyperliquid: fetchEvents reuses the cached market load so advertised handles always match the outcome cache; venues can rotate outcome ids, so the base loadOutcome retries once with a forced reload when a warm cache misses - kalshi: 5 req/s throttle (the demo host 429s at 10 req/s) - polymarket: handleErrors + exceptions map (dead CLOB book 404 -> BadSymbol instead of retryable ExchangeNotAvailable; balance/allowance/geo mappings) - go: fetchEvents/fetchOutcome registered for virtual dispatch (kalshi's on-demand fetchOutcome and loadEvents overrides were unreachable from the base in go); IDerivedExchange + base stub extended - test harness: preferredPredictionOutcome pins are validated against the live listing and fall back to the market scan when stale; pin polymarket to a liquid 2028 market (C#/Go/Java dict ordering scans onto placeholder markets with no CLOB book); refresh the stale hyperliquid pin path live-verified: all 5 prediction exchanges x all 6 languages, public+private (kalshi on the demo host), full run-tests --prediction --private green * refactor(prediction): architecture/perf/DX improvements from review Architecture (PredictionExchange base): - extract indexMarketOutcomes(market) — kalshi on-demand fetchOutcome indexes one market instead of a full O(markets x outcomes) rebuild per outcome - shortenSlug collision handling: same handle + different outcomeId now disambiguates (append id suffix) instead of silently overwriting - setEvents keys events by the unified event handle too; eventsList() helper; deleted the 3 inline populateOutcomes copies + limitless rebuildOutcomes + the per-exchange manual event-cache writes - cold-instance guards: populateOutcomes no-ops when markets are unloaded; the no-query fetchEvents branch serves from the cache without crashing - loadOutcome indexes already-loaded markets for free before any network call, so cold-cache resolution is consistent across languages (removed the over-eager forced-reload that clobbered offline markets and masked live typos) - filterEventsByTags implemented (tags was accepted but filtered nothing); actionable outcome/getEvent errors; safeOutcome stub carries an event key Performance: - polymarket pagination was silently broken (page size 500 vs gamma's 100 cap, so the >=pageSize check never fired) — fixed to 100, default fetchMarketsLimit 200 to bound the ~90 KB/event cold start - kalshi fetchMarkets requests min(maxMarkets, pageLimit), not always 1000 - myriad ethRpc returns safeValue not safeString (a receipt object was coerced to "[object Object]") Types/docs: - fetchEventsParams gains queries + tags - wiki + language skills: fetchEvents({ query }) not fetchEvents([...]) (the old form throws), cold caches auto-load (not "throws, fetch first"), outcome-cache + CLI sections, event structure symbol->event, prediction checklist in the new-exchange skill Verified: all 6 languages regen + build + offline static tests green; live public+private smoke green for all 5 exchanges (kalshi on the demo host). * refactor(prediction): extract EVM toolkit, fix event types, add fetchEvent coverage Architecture: - move the shared EVM helpers (padHexToEven/padHexAddress/rlpEncode*/intToRlpHex/ hexToRlpBytes/ethRpc/sendEvmTransaction/waitForTransactionReceipt) from limitless+myriad onto PredictionExchange — they're used by zero crypto exchanges, so the base Exchange (transpiled into ~100 exchanges) is the wrong home. signEvmTransaction stays per-exchange (needs the noble crypto imports the prediction base skeletons don't carry); the base sendEvmTransaction dispatches to it. Net -65 source lines and the ethRpc receipt-object drift can't recur. go: signEvmTransaction registered for (sync) virtual dispatch + IDerivedExchange method + base stub - PredictionEvent.markets: PredictionMarket[] -> Market[] (venues put ccxt market rows in it; the wrong type gave typed-language users empty structs) - polymarket fetchEvents now delegates to the shared applyEventFetchParams (injecting its fuzzy-search defaults status=active/searchIn=title as explicit params), so all five venues filter identically and sort/eventId/slug/tags now work on polymarket (sort was silently ignored) - remove dead slugToMarketId; createMarketBuy/SellOrderWithCost use safeBool, not a raw options[...] access that KeyErrors in Python/PHP Tests: - strengthen the prediction-event validator (id + event handle + each market's outcomes list + typed active/tags/info), wired into the live fetchEvents and fetchEvent paths so it runs in all six languages - add a myriad fetchEvent static fixture (limitless's dropped — its 6-decimal 1e-6 precision serialises as 1.0E-6 in PHP vs 1.0e-6 elsewhere, an unavoidable float-format divergence; covered live instead) Verified: all 6 languages regen + build + offline static green; live prediction tests green for limitless (py/php/cs) and myriad (js/go/java). * fix(prediction): search-based kalshi fetchEvents + fix cold-cache event scopes kalshi: - point trade-api at external-api.kalshi.com; add the elections search host - fetchEvents resolves each scope server-side then fetches canonically, no client scan: query -> ranked /v1/search/series; tags/category -> /series; series_ticker verbatim; eventId is the event_ticker (direct). limit now bounds fetching, not just output - createOrder requires a price (kalshi has only limit orders) limitless / myriad: - no-query scopes (eventId/slug/tags) fetch from the API instead of serving an empty cold cache, which silently returned [] hyperliquid: - cache events through setEvents so getEvent resolves by id/slug/handle tests: - runPredictionTests exercises each fetchEvents scope (eventId round-trip, limit bound, and configured preferredEventScopes) so a broken parameter path fails loudly * static tests * hl tests * move static tests * adapt cli * run static tests * add hl events * fix import * feat(prediction): settlement + resolution reads across all venues Adds a read-side settlement/resolution surface to the prediction exchanges: - PredictionSettlement type (ts/src/base/types.ts) + Go/C# native structs - base PredictionExchange.fetchSettlements (NotSupported stub) - kalshi: fetchSettlements + parseSettlement (yes/no leg the user held, won, amount, price, cost, payout, pnl); has['fetchSettlements'] = true - resolution fields on every parseMarket/outcome: market.resolved + market.resolvedOutcome, and per-outcome winner + settleFraction - kalshi: status==settled / result - polymarket outcomePrices (0/1) + umaResolutionStatus/closed - myriad: resolvedOutcomeId (-1 until resolved) + voided - limitless: winningOutcomeIndex Transpiler: - regex transpiler (build/transpile.ts) skips comment-only method chunks and strips leading //-comment/blank lines before signature detection. Fixes a pre-existing crash on the prediction base's EVM section-divider comment that silently truncated the Python/PHP prediction base (dropping the EVM helpers). Provably a no-op for the main Exchange base (it has no such chunks). - kalshi parseSettlement: hoisted a compound ternary condition (broke the Py ternary rewrite) and reworded a comment whose " in " triggered the PHP in->array_key_exists rewrite. Verified: TS build + lint clean; Py/PHP syntax; C#/Go build; offline request/response green in JS/C#/Go across kalshi/polymarket/myriad/limitless; resolution + settlement parsing verified offline with mocks. * fix(polymarket): return a fully-populated order from createOrder The CLOB create response only echoes {orderID, status, success}, so createOrder/createOrders returned orders with undefined side/price/amount. buildClobOrderBody now also returns a `request` echo (keyed as the fetchOrder response fields parseOrder reads); createOrder/createOrders merge it before parsing and reset `info` to the raw response so it stays clean. Live-verified against the polymarket CLOB: a limit buy round-trip now returns side=buy price=0.03 amount=5 timeInForce=GTC (previously all undefined), created status=open then canceled (0 open orders after). Signed order body unchanged (request tests 12/12); createOrder response fixture regenerated; offline response green in JS/C#/Go. * fix(polymarket): map a killed FAK/FOK order to OrderNotFillable A FAK/FOK order that finds no match is killed by the CLOB (HTTP 400) — a normal order outcome, not a transport failure. It fell through handleErrors to the base default and surfaced as ExchangeNotAvailable, so a caller would retry as if the exchange were down. Map "no orders found to match" and "could not be fully filled" to OrderNotFillable. Live-verified: a non-marketable FAK buy now throws OrderNotFillable (was ExchangeNotAvailable). Offline request/response green in JS/C#/Go. * feat(kalshi): fetchMyTrades + fix PredictionSettlement Python import fetchMyTrades: fetch the authenticated user's fills via GET /portfolio/fills, parsed per-leg (yes -> <ticker>, no -> <ticker>-NO) into unified trades with side (from action), price (yes/no_price_dollars), amount (count_fp), cost, fee (fee_cost), takerOrMaker (is_taker), order (order_id) + outcome filter. has flag set. Live-verified on kalshi demo in JS and Python (identical output: KXBTCMAX100-26-DEC buy 0.25 x10 cost 2.5 fee $0.13 taker). Also fixes a latent Python-only NameError in the settlement feature: the `PredictionSettlement` return type was never defined in python/ccxt/base/types.py nor registered in the transpiler's import-detection list, so importing any prediction module raised NameError at load (Python static tests don't run and py_compile only checks syntax, so it slipped through). Add the TypedDict, the transpiler import regex, and the PHP array-return regex entry. Verified all 5 prediction modules now import in Python. Offline request/response green JS/C#/Go. * feat(kalshi): fetchOrders + fetchClosedOrders fetchOrders returns every order (resting/executed/canceled) via GET /portfolio/orders with no status filter; fetchClosedOrders fetches all and keeps the executed+canceled ones client-side (kalshi's status filter takes a single value, so "closed" — which spans executed and canceled — can't be one query). Both reuse the existing parsePredictionOrders path + outcome filter. has flags set. Live-verified on kalshi demo in JS and Python (identical): fetchOrders=6 (1 executed + 5 canceled), fetchOpenOrders=0, fetchClosedOrders=6, every closed row status in {closed,canceled}, every open row status open. Offline request/response green JS/C#/Go. * feat(kalshi): editOrder via cancel + recreate kalshi's live amend endpoint is deprecated (V1 /portfolio/orders/{id}/amend returns 410 Gone, no V2 replacement), so editOrder cancels the resting order via the V2 DELETE path then places a fresh order with the updated terms — the same pattern myriad.editOrder uses. has flag set. Live-verified on kalshi demo in JS and Python: create (0.02 x1) -> edit (0.03 x2) returns a new order id, old order no longer open, cleanup canceled. Offline request/response green JS/C#/Go. * fix(polymarket): honor the unified postOnly param buildClobOrderBody omitted postOnly from the passthrough params but hardcoded postOnly:false in the signed order body, so a unified postOnly:true was silently dropped. Read params.postOnly and set it on the order body + carry it in the request echo; parseOrder now reflects it. Live-verified in JS and Python: a far-from-market postOnly buy rests as maker and the returned order shows postOnly=true, then cancels. Offline request/response green JS/C#/Go. * feat(limitless): redeem a resolved position by conditionId redeem(outcome, params) POSTs the market's CTF conditionId to /portfolio/redeem (gasless — the operator settles on-chain). The conditionId resolves from the outcome's market (now carried in the per-outcome info) or params.conditionId directly; ArgumentsRequired if neither is available. has flag set. Live-verified in JS and Python: the request is accepted by the real endpoint (returns "market not resolved" for an unresolved market — I have no winning position to fully redeem, but the request path + conditionId resolution + guard are confirmed). Static request fixture locks the body across JS/C#/Go; offline request/response green. * fix(limitless): map unmatched 400 to BadRequest not ExchangeNotAvailable An unmatched 400 (bad params, or a business rule like "market not resolved") returned undefined from handleErrors and fell through to the base default, surfacing as ExchangeNotAvailable — so a caller would retry as if the exchange were down. Throw BadRequest for a bare 400 after the specific exact/broad matches (which still win). Live-verified: the redeem "market not resolved" response now throws BadRequest. Offline request/response green JS/C#/Go. * fix(kalshi): map unmatched 400 to BadRequest not ExchangeNotAvailable An unmapped kalshi error code on a 400 (e.g. invalid_order) fell through handleErrors to the base default and surfaced as ExchangeNotAvailable, so a caller would retry as if the exchange were down. Throw BadRequest for a bare 400 after the specific code matches (which still win). Live-verified on demo: an invalid-price createOrder now throws BadRequest (was ExchangeNotAvailable). Offline request/response green JS/C#/Go. * docs(examples): kalshi end-to-end example + fix spain-world-cup type error Adds prediction-kalshi-end-to-end.ts — the only prediction venue without an end-to-end example. It demonstrates the full surface completed this session: fetchEvents scoped by tag + resolution winners, an outcome's ticker/order book, a create -> editOrder -> cancel round-trip, and fetchOrders / fetchMyTrades / fetchSettlements. Defaults to the kalshi demo (KALSHI_SANDBOX=false for prod); run-verified live end-to-end on demo. Also fixes a pre-existing type error in prediction-polymarket-spain-world-cup.ts (title/market not on MarketInterface) that failed tsBuildExamples — cast to any. * chore(go): gofmt the regenerated prediction + base Go files The goTranspiler runs this session emitted un-gofmt'd Go (spaces, stray semicolons) that was committed as-is — CI runs `go fmt` and would flag it. gofmt the 14 Go files in this branch's diff. No content change (the FilterByKey / SafeValue-for-prediction deltas in the main base are correct syncs from Exchange.ts, which the committed Go base had gone stale against). Full Go build (v4 + pro + prediction) passes. * fix(prediction): address review findings (Go winner determinism + 3 more) From a cross-language review of this session's changes: - limitless: the resolved-market winner was `i === winningOutcomeIndex` where i iterates Object.keys(tokens) — Go/Java randomize map iteration, so ~50% of the time the wrong outcome was flagged winner (JS/Python are insertion-ordered so it passed live). Map the leg to its canonical index by label (yes=0, no=1) instead of loop position. Now deterministic across all languages. - polymarket: a market that is closed-for-trading but not yet UMA-resolved has fractional outcomePrices; the code reported settleFraction = the mid (e.g. 0.5) as if final. Only set winner/settleFraction when a decisive price exists (>=0.99 or <=0.01); leave undefined otherwise. - kalshi editOrder: validate price + amount BEFORE cancelling the old order, so a bad edit (kalshi is limit-only) doesn't leave the user with the order cancelled and an exception instead of a replacement. - C# PredictionSettlement.timestamp: Int64? not double?, matching every sibling struct + Go (*int64) / Python (Int) / TS (Int). Verified: limitless (winningOutcomeIndex=1 -> NO winner) + polymarket (closed- unsettled -> no winner/settleFraction) via mocks; live re-check confirms Trump- 2024 (prices 1/0) still winner=true/settleFraction=1 and myriad categorical intact; kalshi editOrder throws before cancel on missing price. Full offline matrix green JS/C#/Go; C#/Go build; gofmt clean. * fix(kalshi): map FOK to fill_or_kill + killed-FOK to OrderNotFillable Review follow-up. kalshi has a native fill_or_kill primitive (distinct from immediate_or_cancel), confirmed live — so collapsing unified FOK into IOC was wrong (FOK is all-or-nothing; IOC allows a partial fill). Map timeInForce 'FOK' -> 'fill_or_kill' and 'IOC' -> 'immediate_or_cancel' separately. A killed FOK returns 409 fill_or_kill_insufficient_resting_volume (a normal order outcome) which fell through to ExchangeNotAvailable; map it to OrderNotFillable, matching the polymarket FAK/FOK fix. Live-verified on demo: unified timeInForce:'FOK' now submits fill_or_kill and a non-matchable FOK throws OrderNotFillable (was ExchangeNotAvailable). Offline request/response green JS/C#/Go. * fix(kalshi): map the invalid_order error code to InvalidOrder Review follow-up: the invalid_order code (bad price/size, verified live) fell to the generic 400->BadRequest fallback; map it explicitly to InvalidOrder so callers get the precise class. The bare-400->BadRequest fallback now only catches genuinely-unclassified client errors. Offline green JS/C#/Go. * fix(prediction): make the resolution fields compile in Java + wire Java support Running the full Java build (a CI target) caught a real cross-language bug the JS/C#/Go offline tests could not: the resolution-field locals (winner / settleFraction / resolvedOutcome) are reassigned `let`s captured in the outcome and market object literals, which Java emits as anonymous inner classes that cannot capture a reassigned local ("must be final or effectively final") — PolymarketCore.java failed to compile. Copy each to an effectively-final const before the literal, across kalshi/polymarket/myriad/limitless. Behaviour- preserving (verified via mocks + the offline matrix); transpiles harmlessly to every language. Java support: add PredictionSettlement.java (the native type, like Go/C#) + register it in the Java wrapper generator's known-types. The full Java build (lib + tests module) now compiles. Note: fetchSettlements/redeem are prediction- specific methods that don't fit Java's shared-wrapper model (built from base Exchange.ts), so their typed wrappers aren't generated — the impls live in *Core.java and CI compile is green. Re-transpiled + verified all 6 languages: offline request/response matrix green JS/C#/Go, C#/Go build, Py/PHP syntax, Java assemble (BUILD SUCCESSFUL), gofmt clean. * fix(java): generate typed wrappers for prediction-only methods Close the Java wrapper gap flagged in review. generateJavaWrappers built the prediction method list only from base Exchange.ts, so prediction-only methods had no typed wrapper (impl was in *Core.java, callable only dynamically): - fetchSettlements lives on PredictionExchange.ts — parse the prediction base and add its methods that aren't already on Exchange.ts to the shared list. Every prediction Core extends PredictionExchange so super.fetchSettlements() resolves; all 5 venues now get a typed List<PredictionSettlement> wrapper. - redeem is limitless-specific and returns a plain dict — add a per-exchange method map so only Limitless.java gets it (Object return); genReturnExpr / genAsyncReturnExpr now handle Object (identity, not `new Object(res)`). Verified: Kalshi.fetchSettlements() -> List<PredictionSettlement>, Limitless.redeem() -> Object present only on limitless; full Java build (assemble) SUCCESSFUL; zero change to the ~100 non-prediction wrappers. * move static data to events/ * chore: regenerate base + prediction after merging carlos + upstream tsBuild + base (--baseClass) + prediction transpile across all langs on the merged source. Small delta (js/go/cs base+prediction) — Py/PHP/Java auto-merged identically. Go builds; JS prediction static tests green (polymarket 12/7, myriad 8/6, limitless 5/4, kalshi 5/7). * fix(kalshi): initialize positionSide so Python fetchPositions doesn't UnboundLocalError Live testing found kalshi fetchPositions threw UnboundLocalError in Python when a position has no 'position' field (yesContracts undefined): positionSide was declared 'let positionSide: Str;' and only assigned inside the if, so Python referenced an unassigned local. Initialize to undefined. Also fixes the malformed .gitignore line that failed to ignore the go/main build binary. * fix(prediction): cross-language transpiler correctness for kalshi/myriad Bugs surfaced by live-testing the prediction exchanges in all six languages (public + private endpoints): - kalshi.parseTrade: initialize `side` to undefined — a trade whose taker_side is neither "yes" nor "no" left it unassigned, raising UnboundLocalError in Python (same class as the earlier positionSide fix). - kalshi.fetchEvents: hoist rawEvents.length into a named local at the three `>= limit` comparison sites so the PHP regex transpiler emits count() instead of strlen() — fetchEvents was a fatal TypeError in PHP. Same hoist applied to queries/tags in base requireEventQuery. - base slugToMarketSymbol/slugToOutcomeSymbol/shortenSlug: accept a nullable (Str) eventSlug. The bodies already collapse an absent event to just the market part, but the strict `string` parameter made PHP throw on null, breaking every myriad market load (fetchEvents/fetchBalance/fetchPositions). - myriad.fetchPositions: derive the owner from the configured privateKey via walletAddressOrUndefined() (matching fetchBalance) so a privateKey-only config resolves the wallet for both methods. Verified public + private live in JS, Python, PHP, C#, Go and Java; all five compiled targets build clean. * fix(kalshi): skip unresolvable events in fetchEvents({query}) loop The series search can rank an event_ticker whose /events/{ticker} endpoint 404s (a series-only ticker, or one absent on the demo host). A single 404 threw BadSymbol and failed the entire fetchEvents call; catch it and skip that event instead. Repro on demo: fetchEvents({query:'BTC'}) hit KXBTCHALF -> not_found -> whole call died. Now returns the resolvable events (45). * refactor(base): BaseExchange tier — PredictionExchange independent of Exchange Extract all shared infrastructure into a new BaseExchange base class. Exchange becomes a thin concrete subclass (regular venues extend it, unchanged), and PredictionExchange extends BaseExchange as an independent sibling — a prediction instance is no longer an Exchange (instanceof/embed check is false in every language) while still reusing every base helper via BaseExchange. Across all 6 languages: - TS: class BaseExchange + thin `Exchange extends BaseExchange`; PredictionExchange extends BaseExchange - Python: async base -> BaseExchange + thin Exchange; prediction extends BaseExchange - PHP: async base -> BaseExchange + thin Exchange; prediction extends \ccxt\async\BaseExchange - Go: `type BaseExchange struct` (receivers retargeted) + thin `Exchange struct { BaseExchange }`; PredictionExchange embeds BaseExchange - C#: Exchange partials -> BaseExchange + thin `Exchange : BaseExchange`; PredictionExchange : BaseExchange - Java: Exchange.java -> BaseExchange + thin `Exchange extends BaseExchange`; PredictionExchange extends BaseExchange Transpilers updated to emit the 3-tier hierarchy and recognize BaseExchange as a base class (fixes a TS-type leak from name-keyed type stripping). Verified: all 6 langs build clean; prediction is not-an-Exchange while regular exchanges and prediction both work live (public + private). Follow-up: generated static-test harness is still Exchange-typed; prediction static tests need the harness handle widened to BaseExchange (live/CLI work). * refactor(base): fine split + standalone Prediction* types (TS) Move the 62 symbol-based trading methods (fetch/create/cancel/edit/watch* + the convenience wrappers) out of BaseExchange into the thin Exchange tier, so PredictionExchange (extends BaseExchange) no longer inherits them and defines its own outcome-based versions as fresh methods (not overrides). Make the Prediction* structure types standalone (PredictionOrder/Trade/Ticker/ Position/OrderBook/TradingFee/OpenInterest no longer `extends` the base types; outcome/outcomeId identity, no symbol). This is what required the fine split: a standalone PredictionOrder[] can't covariantly override a base Order[] return. Prediction venues' parsers renamed parse{Order,Ticker,Trade,Position,OpenInterest} -> parsePrediction* so they no longer override the base parsers (which stay in BaseExchange returning base types, used by safeOrder's fill parsing). TS: tsBuild + lint clean; runtime verified — prediction independent, returns standalone types (no symbol), private + regular exchanges work. * refactor(base): propagate fine split + standalone types to Python & PHP Python/PHP are dynamically typed (no return-covariance constraint), so recombine the 62 trading methods (now in the TS `Exchange extends BaseExchange` class) back into the transpiled base: transpileBaseMethods now also extracts the Exchange class's methods and appends them to the base method set. Prediction still shadows them with its own outcome-typed versions. - exclude loadOrderBook from the recombine (hand-written above the marker in the WS async bases; it uses WS cache primitives the REST path can't transpile) - add a general `new X (` -> `X (` strip for Python (no `new` keyword) - import Market into the Python prediction base skeleton (…

    @github-actions github-actions[bot] committed Jul 15, 2026
  • [Automated changes] doc: ccxt pro links (#28535) update Co-authored-by: Igor Kroitor <igor.kroitor@gmail.com>

    @github-actions github-actions[bot] committed Jul 14, 2026
  • [Automated changes] refactor(build): pass head_commit.message via env in github workflows (#29203) * ci(js): pass head_commit.message via env in js.yml github.event.head_commit.message is attacker-controllable (a commit author sets it). js.yml interpolates it directly into three run: shells, including the 'Push To CCXT.WIKI' step, which runs with GH_TOKEN in scope. A message containing shell metacharacters would be evaluated by the shell. Pass it through an env: variable and reference "$HEAD_COMMIT_MESSAGE" so the value is data, not code. Behaviour is unchanged for normal commit messages. The same pattern exists in the other language workflows (cs/java/php/python/ go-app/rust); happy to follow up with those in separate PRs if useful. Signed-off-by: kobihikri <kobi.hikri@gmail.com> * refactor: move HEAD_COMMIT_MESSAGE env variable to job level Added HEAD_COMMIT_MESSAGE environment variable for better commit message handling in workflow. * refactor(build): Use environment variable for commit message check in cs.yml * refactor(build): Use environment variable for HEAD_COMMIT_MESSAGE in java.yml * refactor(build): Use environment variable for commit message check in php.yml * refactor(build): Use environment variable for HEAD_COMMIT_MESSAGE in python.yml --------- Signed-off-by: kobihikri <kobi.hikri@gmail.com> Co-authored-by: Igor Kroitor <igor.kroitor@gmail.com>

    @github-actions github-actions[bot] committed Jul 14, 2026
  • [Automated changes] chore(go): add unique in interface (#29126) chore(go): unique interface

    @github-actions github-actions[bot] committed Jul 8, 2026
  • [Automated changes] fix(aftermath)!: delist (#29125)

    @github-actions github-actions[bot] committed Jul 6, 2026
  • [Automated changes] fix(mudrex): logo (#29121)

    @github-actions github-actions[bot] committed Jul 6, 2026
  • [Automated changes] New exchange: Mudrex (#28266) * Add Mudrex exchange Mudrex linear USDT-margined futures: private REST on trade.mudrex.com (X-Authentication header), public market data from Bybit V5 linear. * Add Partner-Id volume attribution; replace Bybit market data with native Mudrex market data + WebSocket; add INR margin; bump rate limits. * revert files * rm generated files * rm php * revert files * revert * make code transpilable * fix pro/ * remove this.request calls * rm unncessary code * fix parsing * fix tp sl * some static tests and fixes * add logo * use precision * update logo * add markets * add jsdocs * skip mudrex * update static * static test fix * fix * fix php * fix c# * fix go transpiling --------- Co-authored-by: DecentralizedJM <DecentralizedJM@users.noreply.github.com> Co-authored-by: carlosmiei <43336371+carlosmiei@users.noreply.github.com>

    @github-actions github-actions[bot] committed Jul 3, 2026
  • [Automated changes] fix(hyperliquid): remove future type (#29076)

    @github-actions github-actions[bot] committed Jul 2, 2026
  • [Automated changes] fix(ascendex)!: delist (#29079)

    @github-actions github-actions[bot] committed Jul 2, 2026
  • [Automated changes] chore: add Kucoin EU (#29039)

    @github-actions github-actions[bot] committed Jun 30, 2026
  • [Automated changes] fix(extended): remove hostname from urls

    @github-actions github-actions[bot] committed Jun 27, 2026
  • [Automated changes] fix(bitvavo): logo

    @github-actions github-actions[bot] committed Jun 27, 2026
  • [Automated changes] fix(bitso): logo

    @github-actions github-actions[bot] committed Jun 26, 2026
  • [Automated changes] fix(cex): logo

    @github-actions github-actions[bot] committed Jun 26, 2026
  • [Automated changes] fix(bitmart): logo

    @github-actions github-actions[bot] committed Jun 26, 2026
  • [Automated changes] fix(bitmex): logo

    @github-actions github-actions[bot] committed Jun 26, 2026
  • [Automated changes] fix(bitget): logo

    @github-actions github-actions[bot] committed Jun 26, 2026
  • [Automated changes] fix(xt): logo

    @github-actions github-actions[bot] committed Jun 26, 2026
  • [Automated changes] fix(zebpay): logo

    @github-actions github-actions[bot] committed Jun 26, 2026
  • [Automated changes] feat(gateeu): add gate EU (#29018) * feat(gateeu): add gate EU * init fix ob * several fixes * fix extend * fix unwatch * fix gate etended order * fix describe data * fix describeData

    @github-actions github-actions[bot] committed Jun 26, 2026
  • [Automated changes] fix(grvt): logo

    @github-actions github-actions[bot] committed Jun 26, 2026
  • [Automated changes] fix(coinbasexchange): logo

    @github-actions github-actions[bot] committed Jun 26, 2026