This document records the current Binance-first CCXT Pro Elixir generation path.
Goal
Build an extensible Elixir target for CCXT Pro from ts/src/pro/binance.ts.
The target should move toward TypeScript AST to IR to Elixir code generation,
while websocket lifecycle, subscriptions, caches, and resolve/reject semantics
live in a reusable Elixir Pro runtime.
This document is Binance-first. The current goal is to make Binance Pro production-mature before generalizing to another exchange. Binance-specific logic should stay in metadata, URL selection, signing, and routing; method coverage, websocket lifecycle, caches, parser output, and request/waiter semantics should remain reusable runtime or IR concepts.
Maturity Checklist
The Elixir Pro target is considered mature only when each item below has current evidence from generated files, manifest assertions, tests, or live smoke runs:
- Instance model:
Ccxt.Pro.binance/1andCcxt.Pro.Binance.new/1accept CCXT-styleapiKey,secret,options, andbinanceEnv/binance_env; exchange-first wrappers merge instance credentials/options with call options so users do not need to pass full opts to every method. - Source coverage:
pro_manifest.jsonrecords all107methods fromts/src/pro/binance.ts, withunsupportedMethods: [], source spans, generated/runtime-owned status,renderPlan, and runtime contracts. - IR coverage: public watch, private watch, unwatch, authenticate,
listenKey/listenToken, websocket API request, signing, parser, cache,
handler, and reconnect behavior must be represented by structured
irSummary.nodesor explicit runtime contracts. Complex branches must not be patched into output with regex/string fallbacks. - Runtime coverage:
runtimeSemanticCoveragemust include the required features for OTP Registry/DynamicSupervisor ownership, websocket reconnect, message-hash routing, subscription/unwatch lifecycle, request-id routing, websocket API response routing, listenKey auth/keepalive, ArrayCache, OrderBook, balance, positions, order/trade caches, public/private event routing, parser output, and waiter error rejection.Ccxt.ProLifecycleCoverageexposes this evidence as a runtime coverage matrix, anddoc/ccxt-pro-cache-parity.mdtracks specialized cache-class parity, anddoc/ccxt-pro-lifecycle-coverage.mdrecords the current human-readable view. - Live-test policy: public streams run as ordinary live smoke; private
read-only websocket API calls use
BINANCE_PROD_API_KEY/BINANCE_PROD_API_SECRETor demo credentials where supported; prod-only order mutation tests requireCCXT_PRO_ENABLE_PROD_ORDER_LIVE=true, place a non-marketable order, and cancel it immediately. - Risk boundary: Binance Pro currently exposes order mutations only
(
createOrderWs,editOrderWs,cancelOrderWs,cancelAllOrdersWs) as state-changing methods. Withdraw, transfer, borrow, repay, convert, and gift code APIs are REST-surface risks, not Pro manifest methods; they remain dry-run/signature/manual-confirmation only. - Stable gates:
npm run assertElixirPro,npm run checkElixir, andmix compile --warnings-as-errorsmust pass against the current worktree. Live smoke remains env-gated and must report whether a branch executed, skipped for missing credentials, or recorded an expected Binance permission limitation.
Completion Audit Snapshot
Current evidence for the Binance-only Pro target:
- Instance model:
Ccxt.Pro.binance/1,Ccxt.Pro.Binance.new/1, and exchange-first wrappers are generated.pro_manifest.jsonrecords52required exchange-callable public methods and52wrapped methods, withgetPrivateWsUrlexplicitly excluded as a websocket URL helper. ExUnit asserts wrapper coverage and no-opts instance calls for signed helpers. - Source coverage:
pro_manifest.jsonrecords107Binance Pro TypeScript methods, split into66generated methods and41runtime-owned methods, withunsupportedMethods: []. - Traceability: every manifest method records
source.path/startLine/endLine,irSummary.nodes, and generated/runtime-owned lowering status. Generated methods haverenderPlanentries; runtime-owned methods have runtime contracts. - IR/codegen discipline:
npm run assertElixirProfails on unsupported source methods, missing render plans, missing runtime contracts, generated drift, incomplete exchange wrappers, or missing runtime semantic features. The broadernpm run checkElixirgate also asserts the non-Pro selected Elixir target has no fallback markers or regex/string-style source rewrites. - Runtime semantics:
runtimeSemanticCoveragerecords18required features and current evidence entries for OTP registry/dynamic supervisor ownership, websocket reconnect, message-hash routing, subscription/unwatch lifecycle, request-id routing, websocket API response routing, listenKey auth/keepalive, ArrayCache, OrderBook, balance, positions, order/trade caches, public/private event routing, parser output, and waiter rejection.Ccxt.ProLifecycleCoverage.summary/0reports18/18required features covered with125evidence entries. - Live/demo/prod policy: public streams and signed read-only websocket API calls
run through env-gated live smoke. Demo read-only websocket API calls run under
demo_private_live. Production order mutation is isolated behindCCXT_PRO_ENABLE_PROD_ORDER_LIVE=true, uses a non-marketable spot limit order, and immediately cancels it. Event-driven private watchers are covered deterministically through fake-connection/cache/snapshot tests instead of unstable live event waits. - Method-level evidence:
methodCoverageMatrixrecords one row for every Binance Pro source method, including generated/runtime owner, unit evidence, live evidence, risk class, and skip/manual reason. The matrix is part of the generated manifest and is asserted by ExUnit. - Risk inventory: Binance Pro mutation surface is limited to
createOrderWs,editOrderWs,cancelOrderWs, andcancelAllOrdersWs; manifest tests assert that withdraw, transfer, borrow, repay, convert, and gift-code methods are not Pro methods.createOrderWs,editOrderWs,cancelOrderWs,fetchOrderWs, andwatchOrdersare covered by gated non-marketable production live tests.cancelAllOrdersWsremains manual-confirmed only because cancel-all can cancel unrelated user orders on the same symbol. - Manual-only boundary:
watchMyTradesrequires a real fill event and therefore remainsmanual-fill-only; the non-marketable production order policy intentionally cannot prove fills. Private liquidation watchers areevent-driven-private-unit-onlybecause waiting for a real liquidation is not deterministic or safe as an always-on live gate. - Binance-only scope: the original broader target mentioned a second Pro exchange as a generalization proof, but the active scope is explicitly Binance-only. No second-exchange work is required for the current goal.
Completion boundary:
- The current Binance-first goal is complete when the generated manifest records
107/107source methods,unsupportedMethods: [], a synchronizedmethodCoverageMatrix, passing unit/generation gates, ordinary live smoke, and gated non-marketable production order smoke. - Manual-only rows are acceptable only when the matrix records their risk and
skip reason. At this snapshot those rows are exactly
watchMyTrades(manual-fill-only) andcancelAllOrdersWs(manual-confirmed-cancel-all-only). - Re-run the live gates whenever credentials, Binance permissions, network restrictions, signing runtime, or websocket runtime behavior changes.
Current Architecture
The runtime is OTP-based:
Ccxt.Applicationstarts the application supervision tree.Ccxt.Pro.SupervisorstartsCcxt.Pro.RegistryandCcxt.Pro.ConnectionSupervisor.Ccxt.Pro.connection/1returns one dynamically supervised connection process per websocket URL.Ccxt.Pro.connections/0,Ccxt.Pro.connection_info/1, andCcxt.Pro.close_connection/1provide Elixir runtime introspection and explicit connection lifecycle control for IEx/manual testing. These helpers do not change CCXT ProunWatch*semantics:unWatch*still only sendsUNSUBSCRIBEand waits for the exchange acknowledgement.- CCXT-style
:verbosecan be passed through generated watch/request options; it toggles connection-level websocket send/message/close logging on the reused URL connection. The Elixir runtime also emits:telemetryevents under[:ccxt, :pro, ...], andCcxt.Pro.attach_debug_logger/0/Ccxt.Pro.detach_debug_logger/0provide an IEx-friendly event logger. Ccxt.Pro.Binance.stream_ticker/2,stream_trades/4,stream_order_book/3, andstream_ohlcv/5are Elixir-native convenience wrappers over generatedwatch_*methods; they keep CCXT's one-message watch semantics intact while letting callers consume repeated public updates withEnum.take/2,Stream.each/2, or otherEnumerabletooling.- Private watcher convenience wrappers are available as
stream_balance/1,stream_orders/4,stream_positions/4, andstream_my_trades/4. These repeat the generated privatewatch_*methods and intentionally do not imply a privateunwatch_*API; useCcxt.Pro.close_connection/1for explicit connection shutdown. Ccxt.Pro.Connectionowns websocket subscriptions, message hash routing, waiter resolution, and disconnect rejection.Ccxt.Pro.Connection.handle_disconnect/2returns the WebSockex reconnect directive and rejects pending waiters with{:disconnected, reason}; the lifecycle coverage matrix exposes this aswebsocket-process-reconnectwithreject-pending-waiters.Ccxt.Pro.ArrayCacheprovides a reusable bounded newest-first cache used by public ticker/trade/OHLCV streams, private order/trade/liquidation stream retention, and order book pre-snapshot delta buffers. Subscriptions can pass:cache_limitto configure retention per message hash.- Private stream subscriptions can also carry
:snapshot_payloads; the connection runtime preloads those payloads into the private cache and resolves matching waiters immediately. Generated private watch helpers also support:fetch_balance_snapshot/:fetchBalanceSnapshotand:fetch_positions_snapshot/:fetchPositionsSnapshot; those option branches can use an injectable:snapshot_fetcher, an injectable REST:rest_fetcher, or the generated high-level REST methods.
Manual examples live under elixir/examples/:
pro_watch_ticker.exspro_unwatch_ticker.exspro_connection_info.exspro_close_connection.exspro_debug_logger.exspro_stream_ticker.exspro_ticker_worker.exspro_public_market_streams.exspro_private_readonly.exspro_safe_order_lifecycle.exspro_order_event_stream.exspro_order_event_worker.exspro_soak_smoke.exspro_structure_persistence.exs
Run examples from ccxt/elixir with mix run examples/<name>.exs. Public
examples do not require API keys. Private examples load ../../.env when it is
present and require production credentials. Order examples require
CCXT_PRO_ENABLE_PROD_ORDER_LIVE=true and use non-marketable spot limit orders
with immediate cleanup.
Production public-stream soak is deliberately opt-in and does not require API keys:
cd ..
npm run testElixirProSoak
npm run testElixirProLongSoak
The soak gate runs test/ccxt_pro_binance_soak_test.exs with the :soak tag.
It validates a public order-book snapshot, consumes stream_ticker/2 for
CCXT_PRO_SOAK_SECONDS seconds, checks maximum ticker update gaps through
CCXT_PRO_SOAK_MAX_GAP_MS, verifies connection introspection, validates
explicit close/reopen behavior for a public ticker watch, verifies supervised
restart after an abnormal connection process exit, and then closes all Pro
websocket connections. The default symbol is BTC/USDT; override it with
BINANCE_PRO_SOAK_SYMBOL. Because soak is an operational stability gate,
ordinary mix test and npm run checkElixir exclude it by default.
The long soak gate runs test/ccxt_pro_binance_long_soak_test.exs with the
:soak_long tag. It defaults to CCXT_PRO_LONG_SOAK_SECONDS=900 and records
public ticker update count, maximum update gap, telemetry message count,
connection start count, disconnect count, terminated count, and cleanup status.
For a quick sanity run, override CCXT_PRO_LONG_SOAK_SECONDS=5 and
CCXT_PRO_LONG_SOAK_MIN_UPDATES=1.
The generator is currently an AST-driven Pro slice:
build/elixirProTranspiler.tsreadsts/src/pro/binance.tswith the TypeScript compiler API.- The generator builds a
ProMethodModelfor every TypeScript class method. - Each method model records structured source span
(
source.path/startLine/endLine), async/static/visibility, parameters, return type, body AST summary, method category, AST-derivedirSummary, and lowering status. - Every source method now has non-empty structured
irSummary.nodes; ExUnit asserts this for all 107 Binance Pro TypeScript methods. - Lowering coverage is inferred from
ProMethodModelcategory plus AST/body signals such as calls, awaits, returns, and statement shape; it no longer depends on a hand-maintained required-method/lowering list. - Generated
elixir/lib/ccxt/pro/binance.exincludes source trace lines for each method. - Generated
elixir/lib/ccxt/pro_manifest.jsonrecords coverage, generated methods, runtime-owned methods, unsupported methods, unsupported reasons, structured source trace,renderPlanrecords for generated methods, andruntimeContractrecords for runtime-owned methods. - Generated method blocks in
renderBinanceProare now selected through the manifest-backedrenderPlan; inline metadata helpers remain in the module scaffold, while non-inline generated methods must resolve through a renderer entry before they can be emitted. Non-inline renderer names are dispatched throughMETHOD_RENDERER_REGISTRY, so the manifest renderer key is the actual generation entrypoint. The generated module insertion points readrenderSections.main/parser, which are derived from non-inlinerenderPlanentries and TypeScript source order rather than a hand-maintained method order list. - Runtime-owned method contracts record the owning Elixir module/function, the contract kind, and the dispatch/cache/signing signals that connect the TypeScript method to reusable Pro runtime behavior.
- Websocket API request methods expose AST-derived sub-IR signals and nodes in the manifest, including signed request routing, request waiter routing, order-payload create/edit/cancel variants, option routing, market-symbol routing, and response filter nodes.
- Public/private stream, unsubscribe, helper, cache, and orderbook methods also
expose structured
irSummary.nodes, including watch single/multiple nodes, channel families, private user-data auth nodes, cache nodes, unsubscribe families, snapshot preload nodes, and orderbook snapshot/delta cache nodes. - Auth/listenKey, parser, websocket API response handler, public/private event handler, and top-level dispatch methods also expose structured nodes for signing, listen-token routing, parser branches, response handlers, event dispatch, waiter rejection, and cache updates.
npm run assertElixirProverifies every TypeScript source method is lowered, every manifest method has structured source trace matching its AST span, every generated method has a render plan, every render entrypoint method is backed by a non-inline render plan entry, every non-inline generated method is consumed by the module render entrypoint, every non-inline render plan entry resolves throughMETHOD_RENDERER_REGISTRY, the registry has no unused renderer keys, every runtime-owned method has a complete runtime contract, and compares generated output plus manifest byte-for-byte to prevent manual drift.
The current generator uses AST-derived IR summaries for coverage and source
trace. Generated method bodies are emitted through manifest-backed renderer
entries, and stabilized payload/cache/auth/parser/router behavior is also
recorded as smaller reusable Pro IR nodes. Further work can keep splitting
large renderer internals into finer IR nodes, but that is now an incremental
refinement rather than a source-method coverage gap. The public watch renderer slice
emits watch_ticker/2, watch_tickers/2,
watch_trades/4, watch_trades_for_symbols/4, watch_order_book/3,
watch_order_book_for_symbols/3, watch_ohlcv/5,
watch_ohlcv_for_symbols/4, watch_liquidations/4, and
watch_liquidations_for_symbols/4 from shared Pro IR specs rather than inline
method templates. The ticker-family public stream methods, including mark
prices and bids/asks, are covered through generated
watch_multi_ticker_helper/5 plus a shared ticker-family wrapper renderer for
watch_tickers/2, watch_mark_prices/2, and watch_bids_asks/2; the helper
delegates public watch-any subscription, cache registration, and parser
market-type selection to a typed ticker-family subscription node. The public
unwatch_* methods are covered by shared unsubscribe wrapper, channel-family,
and ticker-stream renderers. The first websocket API request renderer slice
emits market-data request methods including fetch_order_book_ws/3,
fetch_ohlcv_ws/5, fetch_ticker_ws/2, and fetch_trades_ws/4, plus signed
helper query methods including fetch_balance_ws/1, fetch_positions_ws/2,
fetch_order_ws/3, and fetch_open_orders_ws/4. The shared websocket API
request renderer now delegates request setup, payload, request mode, and
response rendering to WsApiRequestNodeIrSpec; its dispatcher now delegates to
dedicated signed-waiter, unsigned request, and signed-helper request renderers,
covering signed waiter, unsigned connection, unsigned helper, and signed helper
request modes. The
websocket API wrapper renderer covers fetch_position_ws/2 and
fetch_closed_orders_ws/4.
Validation-aware websocket API request rendering covers fetch_orders_ws/4
and fetch_my_trades_ws/4, plus cancel mutations cancel_order_ws/3 and
cancel_all_orders_ws/2; these methods render guarded validation branches plus
typed signed-request payload/response nodes through the validated request IR.
Signed order mutation rendering now covers
create_order_ws/6 and edit_order_ws/7, including test/SOR/algo-order method
selection, spot cancel-replace, and contract modify-order payload selection;
their signed request/response path is centralized through a generated order
mutation request helper, and the generated order mutation methods render their
success path through typed payload-wrapper, pre-request, and signed-request IR
nodes rather than an opaque method-body line block. Edit-order spot/swap
payload selection is centralized through generated order payload helpers. Order payload helper
generation is driven by a composed payload-helper IR spec with typed child
specs for order-id payloads, create-order payload delegation, order request
market stubs, spot cancel-replace payloads, contract modify payloads, base
order payloads, option/camel-case params, and conditional-order detection. The
manifest also records AST-derived websocket API sub-IR signals and structured
nodes such as
order-payload:create, order-payload:spot-cancel-replace,
order-payload:contract-modify, order-payload:cancel,
request:signed-waiter, request:unsigned-connection,
request:unsigned-helper, request:signed-helper,
validation:guarded-request, request:signed-validated,
order-mutation:success, request:signed-order-mutation,
payload-shape:book-depth, payload-shape:ohlcv-query,
payload-shape:my-trades-query, payload-field:symbol,
payload-field:order-id, payload-field:return-rate-limits,
response-filter:positions, and response-filter:symbol-since-limit. Stream,
unsubscribe, helper, cache, and orderbook methods also record structured nodes
such as watch:single, watch:multiple, channel-family:trades,
subscription:public-single, request:public-watch,
subscription:public-multiple, request:public-watch-any,
auth:user-data-stream, cache:snapshot-preload, unsubscribe:orderbook,
snapshot:balance, snapshot:positions, request:snapshot-fetch,
payload:unsubscribe, request:unsubscribe-waiter, and
orderbook:snapshot-delta-merge. Auth, parser, and handler methods record
nodes such as auth:signature, auth:listen-token, parser:trade,
auth-signing:hmac-sha256, auth-signing:rsa-sha256,
auth-signing:eddsa-ed25519, credential:api-key,
payload:sorted-rawencode,
metadata-field:capabilities, metadata-field:urls,
metadata-field:timeframes, request-counter:per-url,
runtime-state:options-request-id, request-id:increment,
auth-subscription:request, response:subscription-id,
auth-route:spot-signature, auth-route:listen-key,
auth-route:listen-token, auth-route:unsupported,
listen-token-lifecycle:subscribe-ack,
listen-token-lifecycle:renewal,
listen-key-keepalive:supported, listen-key-keepalive:unsupported,
request:rest-keepalive,
routing:public-websocket-url, routing:private-websocket-url,
routing:stream-path, routing-dimension:market-type,
routing-dimension:listen-key,
parser-branch:public-private, parser-branch:ticker-family,
parser-wrapper:safe_trade, parser-wrapper:safe_ticker,
parser-wrapper:safe_order, parser-wrapper:safe_liquidation,
parser-field:liquidation-order, parser-field:contracts,
parser-field:side, parser-field:hedged, handler:ws-api-response,
response:ws-api-success, error:status-error, request:request-id,
private-event:order, cache-engine:order-cache,
cache-engine:array-cache, cache-engine:balance-position-cache,
cache-class:array-cache, cache-class:order-cache,
cache-class:position-cache, cache-class:orderbook-cache,
cache-semantic:bounded-newest-first, cache-semantic:symbol-id-index,
cache-semantic:order-trade-merge, cache-semantic:balance-delta, and
dispatch:request-channel-private-error,
dispatch-branch:request-id, dispatch-branch:channel,
dispatch-branch:private-event.
Auth/listenKey IR rendering covers spot websocket API signature subscription,
margin listenToken subscription, authenticate/1 routing, renewal, and futures
listenKey keepalive; the signature and listenToken subscription methods render
their websocket API auth request and subscription-id response handling through a
typed auth subscription request node. authenticate/1 routes through typed
auth router branch specs for spot signature, futures listenKey, margin
listenToken, and unsupported branches. keep_alive_listen_key/3 renders its
supported futures endpoint fetch and unsupported branch through a typed
listenKey keepalive request node. Shared private watch IR rendering covers private balance,
orders, positions, my trades, and my liquidation stream methods, with private
payload fetches delegated to a typed private watch payload/request node; the single
symbol private liquidation wrapper uses the same single-from-multiple wrapper
IR as the public mark-price wrapper. Structured
parser IR rendering now covers the field-mapping parser shape used by
parse_ws_liquidation/2, parse_ws_order/2, and parse_ws_position/1;
conditional parser IR rendering covers the branch shapes used by
parse_ws_ticker/3 and parse_ws_trade/2.
Covered Public Websocket Methods
Generated Binance Pro methods currently covered:
watch_ticker/2watch_tickers/2watch_trades/4watch_trades_for_symbols/4watch_order_book/3watch_order_book_for_symbols/3watch_ohlcv/5watch_ohlcv_for_symbols/4watch_liquidations/4watch_liquidations_for_symbols/4watch_mark_price/2watch_mark_prices/2watch_bids_asks/2watch_multi_ticker_helper/5unwatch_ticker/2unwatch_tickers/2unwatch_mark_price/2unwatch_mark_prices/2unwatch_order_book/2unwatch_order_book_for_symbols/2unwatch_trades/2unwatch_trades_for_symbols/2unwatch_ohlcv/3unwatch_ohlcv_for_symbols/2fetch_ohlcv_ws/5fetch_ticker_ws/2fetch_order_book_ws/3fetch_balance_ws/1fetch_position_ws/2fetch_positions_ws/2cancel_order_ws/3cancel_all_orders_ws/2fetch_order_ws/3fetch_orders_ws/4fetch_closed_orders_ws/4fetch_open_orders_ws/4fetch_my_trades_ws/4fetch_trades_ws/4create_order_ws/6edit_order_ws/7sign_params/2ensure_user_data_stream_ws_subscribe_signature/2ensure_user_data_stream_ws_subscribe_listen_token/2renew_listen_token/1authenticate/1get_private_ws_url/3keep_alive_listen_key/3watch_my_liquidations/4watch_my_liquidations_for_symbols/4watch_balance/1watch_orders/4watch_positions/4watch_my_trades/4parse_ws_order/2parse_ws_position/1
Current TypeScript source-method trace coverage:
107/107Binance Pro methods are currently bound to generated Elixir output or explicit runtime-owned Pro behavior.- Current manifest split is
66generated methods and41runtime-owned methods. publicStreamcoverage is14/14.unsubscribecoverage is10/10.authcoverage is8/8; covered methods include the HMAC branch ofsignParamsand the spotuserDataStream.subscribe.signatureauthentication path, futures listenKey creation/keepalive helpers, and margin listenToken subscription/renewal. The subscription, routing, renewal, and keepalive methods are emitted through shared auth/listenKey IR renderers.privateStreamcoverage is6/6; covered methods include private balance, orders, positions, my trades, and my liquidations streams. These methods are emitted through shared private watch IR renderers.parsercoverage is5/5;parse_ws_liquidation/2andparse_ws_position/1are emitted through structured parser IR, whileparse_ws_ticker/3andparse_ws_trade/2are emitted through conditional parser IR.parse_ws_order/2is also emitted through structured parser IR.handlercoverage is26/26; AST call signals classify handler contracts into public stream handlers, private stream handlers, unsubscribe acknowledgements, order book cache handlers, websocket API response handlers, and a small top-level event dispatch set. These runtime-owned contracts are recorded in the manifest with owner functions such asdispatch/3,dispatch_private/2,handle_orderbook_delta/3,resolve_or_reject_request_message/3, andhandle_frame/2.wsApicoverage is24/24; covered methods now include public market-data requests, signed balance/position/order/trade query requests, signed cancel-order requests, and signed create/edit order requests.helpercoverage is14/14; metadata/url/category/account-type/market-type helpers are generated, while snapshot/cache helpers are explicit runtime-owned behavior with manifest runtime contracts.- Coverage can be inspected with
npm run inspectElixirPro. npm run inspectElixirProreads TypeScript AST-derivedProMethodModelrecords and groups coverage by method category.elixir/lib/ccxt/pro_manifest.jsonrecordsirSummaryfor every source method; tests assert that all 107 methods have non-empty AST-derived IR signals, non-empty structured IR nodes, structured source trace (source.path/startLine/endLine), MethodModel metadata, and no unsupported entries.- The same manifest records
methodCoverageMatrixfor every source method, including source span, category, generated/runtime owner, renderer or runtime owner function, unit evidence, live evidence, risk class, and skip reason. Tests assert the matrix covers107/107methods and stays synchronized with the source-method manifest. - The same manifest records a
renderPlanfor every generated method; tests assert that the render plan and generated method set are identical. The manifest also records source-derivedrenderSections.main/parserfor module emission; tests assert those sections match the non-inline render plan. - The generator assert also checks that the method blocks emitted by
renderBinanceProare resolved fromrenderPlan, rather than from a separate hand-maintained required-method or render-order source; non-inline render plan entries that are not consumed by a module render section fail the assert path, and renderer registry drift is rejected in both directions. - Runtime-owned source methods also record
runtimeContract; generator assert and ExUnit both require complete contract metadata for those methods. Ccxt.ProLifecycleCoveragegroupsruntimeSemanticCoverageinto required lifecycle feature rows, owner modules/functions, source methods, contract kinds, and signals.doc/ccxt-pro-lifecycle-coverage.mdis the rendered matrix for review.- This number is method-trace coverage, not runtime behavior quality; several traced handler/helper methods are represented by shared runtime behavior.
requestIdremains runtime-owned because the TypeScript method mutates instance-localoptions.requestId[url]counters. The current Elixir Pro module is stateless at the exchange-function boundary, so request id ownership stays with websocket request/waiter runtime behavior until exchange instance state is modeled explicitly. The Pro IR still records the counter shape asrequest-counter:per-url,runtime-state:options-request-id,request-id:increment, andwaiter:message-hash.
The generator tracks these TypeScript source methods:
watchTickerwatchLiquidationswatchLiquidationsForSymbolshandleLiquidationparseWsLiquidationwatchTickerswatchMultiTickerHelperparseWsTickerwatchOrderBookwatchOrderBookForSymbolsfetchOrderBookSnapshothandleDeltahandleDeltashandleOrderBookMessagehandleOrderBookhandleOrderBookSubscriptionunWatchOrderBookForSymbolsunWatchOrderBookunWatchTradesForSymbolsunWatchTradeswatchTradeswatchTradesForSymbolsparseWsTradehandleTradewatchOHLCVwatchOHLCVForSymbolsunWatchOHLCVForSymbolsunWatchOHLCVhandleOHLCVfetchOHLCVWshandleFetchOHLCVfetchTickerWshandleTickerWsfetchOrderBookWshandleFetchOrderBookfetchBalanceWshandleBalanceWshandleAccountStatusWsfetchPositionWsfetchPositionsWshandlePositionsWscancelOrderWscancelAllOrdersWsfetchOrderWsfetchOrdersWsfetchClosedOrdersWsfetchOpenOrdersWshandleOrderWshandleOrdersWsfetchMyTradesWsfetchTradesWshandleTradesWscreateOrderWseditOrderWshandleEditOrderWssignParamsgetPrivateWsUrlensureUserDataStreamWsSubscribeSignaturehandleUserDataStreamSubscribeauthenticatekeepAliveListenKeywatchMarkPricewatchMarkPricesunWatchTickersunWatchMarkPricesunWatchMarkPriceunWatchTickerwatchBidsAskshandleBidsAskshandleTickershandleMarkPriceshandleTickersAndBidsAsksgetWsUrlstreamwatchMyLiquidationswatchMyLiquidationsForSymbolswatchBalancewatchOrderswatchPositionswatchMyTradesparseWsOrderparseWsPositionhandleMyLiquidationhandleBalancehandleOrderUpdatehandlePositionshandleMyTradehandleOrderhandleAcountUpdate
Runtime Semantics Implemented
Current websocket dispatch supports:
24hrMiniTicker24hrTickertradeaggTradeklinemarkPrice_klineindexPrice_klinedepthUpdatemarkPriceUpdateforceOrder- book ticker payloads without an
eevent field - Binance
UNSUBSCRIBEacknowledgement frames - Binance private user-data events:
executionReport,outboundAccountPosition,balanceUpdate,ACCOUNT_UPDATE, andORDER_TRADE_UPDATE - Binance websocket API request frames with
status != 200or anerrorbody are rejected by request id. - Invalid websocket JSON rejects all pending stream/request waiters, so callers
do not remain blocked after a malformed frame. Request and unsubscribe waiters
unwrap their internal waiter tags and report errors with the original caller
ref, matching
request/3andunwatch_any/3receive contracts. - Binance
UNSUBSCRIBEerror acknowledgements reject the unwatch caller instead of reporting a successful unsubscribe. - Binance
eventStreamTerminateduser-data events reject matching private stream waiters instead of leaving callers blocked.
Current parser coverage:
- ticker: mini ticker, full 24h ticker, book ticker, mark price update
- liquidation: futures
forceOrderpayloads - tickers: individual ticker update maps and all-market ticker arrays
- trade: public trade, aggregate trade, private execution trade payload
- order book: REST snapshot plus websocket depth delta merge
- OHLCV: kline payload to
[timestamp, open, high, low, close, volume] - private order: spot
executionReportand futuresORDER_TRADE_UPDATE - private position: futures account update position entries
Current cache behavior is intentionally minimal:
watch_ticker/2returns the latest parsed ticker update.watch_tickers/2returns a one-update%{symbol => ticker}map for symbol subscriptions and parses all-market ticker arrays.watch_trades/4andwatch_trades_for_symbols/4subscribe all requested trade channels through cachedwatch_any; raw trade payloads are retained inCcxt.Pro.ArrayCacheand parsed/filtered bysinceandlimit.watch_ohlcv/5andwatch_ohlcv_for_symbols/4subscribe requested kline channels through cachedwatch_any; raw kline payloads are retained inCcxt.Pro.ArrayCacheand parsed/filtered bysinceandlimit.watch_tickers/2,watch_mark_price/2,watch_mark_prices/2, andwatch_bids_asks/2use cached ticker-familywatch_any; raw ticker payloads are retained inCcxt.Pro.ArrayCacheand parsed into symbol-keyed ticker maps.- Public ticker, trade, and OHLCV cache retention is covered by offline
connection tests that assert per-message-hash
ArrayCachestorage and newest-first bounded semantics. watch_liquidations/4andwatch_liquidations_for_symbols/4return one liquidation update when Binance emits a matchingforceOrderevent; theForSymbolspath subscribes all requested futuresforceOrderchannels throughwatch_any.watch_order_book_for_symbols/3registers all requested order book channels, loads snapshots per symbol, and returns the first normalized order book that reaches a valid snapshot/delta state. Snapshot-time websocket delta buffers useCcxt.Pro.ArrayCachewith optional per-subscription:cache_limit.watch_balance/1,watch_orders/4,watch_positions/4,watch_my_trades/4, andwatch_my_liquidations/4authenticate the user-data stream, reuse the supervised websocket connection, and wait on CCXT message hashes. Balance, positions, orders, my trades, and my liquidations are merged into runtime private cache structures before watcher resolution. Private order/trade/liquidation list retention now usesCcxt.Pro.ArrayCachewith bounded newest-first append semantics and optional per-subscription:cache_limit.- Private event-driven watchers are not part of the always-on live smoke
because they depend on future account events that may not occur during a
deterministic timeout.
watch_balance/1,watch_orders/4,watch_positions/4,watch_my_trades/4,watch_my_liquidations/4, andwatch_my_liquidations_for_symbols/4are covered by deterministic fake-connection tests, cache payload tests, snapshot preload tests, and message-hash routing tests instead. The Pro unit suite asserts these watcher calls stay out oftest/ccxt_pro_binance_live_test.exs. fetch_ohlcv_ws/5sends a Binance websocket APIklinesrequest and parses the responseresultinto OHLCV arrays.fetch_ticker_ws/2andfetch_order_book_ws/3send signed Binance futures websocket API requests using generatedsign_params/2.fetch_balance_ws/1,fetch_position_ws/2,fetch_positions_ws/2,fetch_order_ws/3,fetch_orders_ws/4,fetch_open_orders_ws/4,fetch_closed_orders_ws/4, andfetch_my_trades_ws/4send signed websocket API read requests and parse the response through shared ws-api helpers.cancel_order_ws/3andcancel_all_orders_ws/2are generated and covered by offline signed request/response tests. They are excluded from the always-on live smoke because they mutate order state and need a user-confirmed target order or a freshly created test order.fetch_trades_ws/4sends the unsigned websocket API public historical trades request and is included in the live smoke.create_order_ws/6andedit_order_ws/7are generated and covered by offline signed request/response tests. Real production order mutation is gated byCCXT_PRO_ENABLE_PROD_ORDER_LIVE=true; when enabled, the live test builds a deliberately non-marketable spot limit buy from the current production order book, submits it, and immediately cancels it. Without that explicit flag the test reports that no production order was sent.- Prod-only funding or account-state mutations that are not order placement remain out of live execution. Withdraw, transfer, borrow, repay, convert, and gift-code flows should be covered only by inventory lists, dry-run/signature rendering, or request-shape tests unless they receive a separate manual confirmation for the exact operation.
- The Binance Pro manifest does not include withdraw, transfer, borrow, repay,
convert, or gift-code methods. Its current mutation surface is limited to
create_order_ws/6,edit_order_ws/7,cancel_order_ws/3, andcancel_all_orders_ws/2; an offline manifest test asserts this risk inventory. - Non-Pro Binance production-only mutation classes are covered by
test/ccxt_binance_prod_only_dry_run_test.exswith fake credentials and no HTTP execution. That dry-run suite renders signed production request shapes and asserts demo rejection for withdraw, transfer, futures transfer, gift-code create/redeem, convert accept/transfer, margin borrow/repay, portfolio margin borrow/repay, simple earn redeem, option order, portfolio margin order, and portfolio margin leverage. sign_params/2implements the TypeScriptsignParamssigning branches: HMAC SHA256 for ordinary API secrets, RSA SHA256 for long PEM private keys, and Ed25519 for short Binance EdDSA PEM private keys. The manifest records credential requirements, timestamp/recvWindow payload extension, sorted rawencode canonicalization, and all three signing algorithms.ensure_user_data_stream_ws_subscribe_signature/2sends the signed spot websocket APIuserDataStream.subscribe.signaturerequest and returns the subscription id.ensure_user_data_stream_ws_subscribe_listen_token/2creates a margin listenToken throughsapiPostUserListenToken, subscribes it through websocket APIuserDataStream.subscribe.listenToken, and returns subscription metadata.renew_listen_token/1reuses the margin listenToken subscription path with explicit parameters, matching the TypeScript renewal wrapper at the current stateless Elixir boundary.authenticate/1currently covers the TypeScript spot signature branch, margin listenToken branch, and listenKey branches for future, delivery, and portfolio-margin streams.get_private_ws_url/3generates Binance private websocket URLs for listenKey-backed future, delivery, and portfolio-margin streams. Public and private websocket URL helpers now record typed routing nodes with market type, category, environment, stream hash, and listenKey dimensions in the manifest.keep_alive_listen_key/3implements listenKey keepalive requests for future, delivery, and portfolio-margin streams.- All generated
unwatch_*public methods send BinanceUNSUBSCRIBEand wait for the request acknowledgement. watch_order_book/3keeps local order book state in the websocket connection process.
The cache-class parity milestone now has runtime owners for the Binance Pro
cache semantics used so far. Ccxt.Pro.IndexedArrayCache owns the reusable
symbol -> key cache behavior behind ArrayCacheBySymbolById and
ArrayCacheBySymbolBySide style caches. Ccxt.Pro.TimestampArrayCache owns the
ArrayCacheByTimestamp style timestamp replacement cache used by OHLCV streams.
Ccxt.Pro.PositionCache wires symbol+side indexing into Binance position
streams, and Ccxt.Pro.CacheUpdates owns CCXT Pro getLimit-style
newUpdates counters. Ccxt.Pro.Connection wires those counters into public
cached streams and private list/order streams when callers pass
newUpdates: true or new_updates: true.
Order book state currently follows the Binance/CCXT Pro sequence rules:
- Deltas received before the REST snapshot are buffered.
- The REST snapshot initializes bids, asks, and nonce from
lastUpdateId. - Spot deltas with
u <= nonceare dropped. - The first valid spot delta must satisfy
U - 1 <= nonceandu - 1 >= nonce. - Later spot deltas must satisfy
U - 1 == previous u. - Futures deltas use
U/u/pucontinuity; cached futures deltas can bridge the REST snapshot and later deltas must continue from the previous update id. - Sequence gaps reject the waiter with a checksum-style error, matching the TypeScript
watchOrderBookbehavior where checksum mode turns sequence inconsistency intoChecksumError. - When checksum mode is disabled, the same sequence inconsistency is surfaced
as
:sequence_gapfor testable non-checksum order book subscriptions.
Verification
Standard gate:
npm run checkElixir
Pro generation stability:
npm run assertElixirPro
This gate fails if any TypeScript method is unsupported, if any runtime-owned method lacks a complete runtime contract, or if generated files drift from the AST-derived output.
Public Binance Pro live smoke:
cd elixir
mix test --include live --exclude prod_order_live \
test/ccxt_pro_binance_live_test.exs --timeout 180000
The public stream live tests use Binance websocket streams and do not require
API keys. Event-driven liquidation streams are covered by a stable live
forceOrder subscribe/unsubscribe acknowledgement test, while actual forced
order payload parsing stays in deterministic parser and fake-connection tests
because Binance only emits payloads when a real forced-order event occurs.
Signed websocket API live tests run when BINANCE_PROD_API_KEY /
BINANCE_PROD_API_SECRET are available. The Pro live test credential check
intentionally does not fall back to generic BINANCE_API_KEY /
BINANCE_API_SECRET, because those may point at demo credentials and mask
production permission failures.
The signed read-only websocket API smoke covers fetch_balance_ws/1,
fetch_position_ws/2, fetch_positions_ws/2, fetch_open_orders_ws/4,
fetch_orders_ws/4, fetch_closed_orders_ws/4, and fetch_my_trades_ws/4.
These calls inspect account/order/trade state and do not create, edit, cancel,
transfer, borrow, repay, convert, or withdraw.
The always-on live smoke does not wait for a real liquidation payload; it
verifies the public forceOrder subscription lifecycle against Binance and
keeps payload shape assertions deterministic.
Demo private read-only smoke can be run on its own:
cd elixir
mix test --exclude live --include demo_private_live \
test/ccxt_pro_binance_live_test.exs --timeout 180000
This verifies the demo read-only websocket API matrix for
fetch_balance_ws/1, fetch_positions_ws/2, fetch_open_orders_ws/4,
fetch_orders_ws/4, fetch_closed_orders_ws/4, and fetch_my_trades_ws/4.
The test accepts successful demo responses or explicit Binance demo
unsupported/credential/permission responses. It is read-only and does not place
orders or move funds.
Production order mutation smoke is deliberately opt-in:
cd elixir
CCXT_PRO_ENABLE_PROD_ORDER_LIVE=true \
BINANCE_PROD_ORDER_AMOUNT=0.0002 \
mix test --exclude live --include prod_order_live \
test/ccxt_pro_binance_live_test.exs --timeout 120000
That test uses production credentials, places a non-marketable spot limit buy, and cancels the created order immediately. It is meant only for the prod-only order-placement class; non-order funding mutations stay dry-run/request-shape only.
Latest verified run, 2026-06-11:
npm run inspectElixirPro:107/107Binance Pro source methods covered, split as66generated and41runtime-owned.npm run assertElixirPro: generated output stable.mix test test/ccxt_pro_binance_test.exs test/ccxt_pro_binance_soak_test.exs:114 tests, 0 failures (4 excluded); this includes HMAC SHA256, RSA SHA256, Ed25519signParamsbranch coverage, Pro runtime connection lifecycle helper coverage, and proof that the:soakgate stays opt-in.mix compile --warnings-as-errors: passed.npm run checkElixir:509 tests, 0 failures (60 excluded).CCXT_PRO_SOAK_SECONDS=5 CCXT_PRO_SOAK_MIN_UPDATES=1 mix test --include soak test/ccxt_pro_binance_soak_test.exs --timeout 120000:3 tests, 0 failures. This short public-stream run validated order-book snapshots before/after a ticker stream, repeated ticker updates, connection introspection, ticker unwatch-on-halt, explicit close/reopen, supervised restart after abnormal process exit, and websocket cleanup.CCXT_PRO_LONG_SOAK_SECONDS=5 CCXT_PRO_LONG_SOAK_MIN_UPDATES=1 npm run testElixirProLongSoak:1 test, 0 failures. This short long-soak sanity run records ticker update count, maximum update gap, connection starts, disconnects, terminations, telemetry message count, and explicit websocket cleanup.CCXT_PRO_WORKER_SECONDS=5 mix run examples/pro_ticker_worker.exs: received3public ticker updates forBTC/USDT, returned a GenServer snapshot withlast_error: nil, and stopped the worker with explicit websocket cleanup.BINANCE_PRO_ENV=prod CCXT_PRO_ORDER_EVENT_WORKER_SECONDS=90 mix run examples/pro_order_event_worker.exswhileCCXT_PRO_ENABLE_PROD_ORDER_LIVE=true BINANCE_PROD_ORDER_SYMBOL=BTC/USDT BINANCE_PROD_ORDER_AMOUNT=0.0002 mix run examples/pro_safe_order_lifecycle.exswas running: the private worker received3order-event updates for a non-marketable production spot order lifecycle covering create/open, cancel of the original order, and cancel of the edited order. The final worker snapshot retained recent orders and the retry path surfaced Binance-2035 User Data Stream subscription already active, which is an exchange lifecycle condition after an active user-data stream subscription.npm run testElixirConsumer: compiledsmoke/consumer_appas an external path dependency consumer using{:ccxt, path: "../.."}and ran1live public Binance Pro test with0failures. This verifiesCcxt.Pro.binance/1,watch_ticker/2,stream_ticker/2, andCcxt.Pro.close_connection/1outside the package project.npm run buildElixirPackage: builtccxt-0.1.0-binance-pro-preview.tarwith package metadata and the intended runtime/docs payload. A follow-upmix hex.build --unpacksucceeded and confirmed the package includeslib,priv,doc,mix.exs, andREADME.md, includingdoc/real-project-integration.mdanddoc/release-checklist.md, while excludingtest,examples, andsmoke.npm run testElixirPackageConsumer: built and unpacked the local Hex package into a temporary directory, copiedsmoke/consumer_appinto a clean temporary consumer project, setCCXT_CONSUMER_CCXT_PATHto the unpacked package, and ran the same public Binance Pro watch/stream/close smoke successfully from the packaged payload.npm run releaseElixirPreviewCheck: release-preview aggregation gate that runscheckElixir,docsElixir, andtestElixirPackageConsumerin order. Latest local run completed all three phases, including docs generation and packaged consumer smoke with1test and0failures.npm run testElixirProLongSoak:1 test, 0 failuresover901.0seconds. This default production public ticker soak usedBTC/USDTonprodfor900seconds and recorded883ticker updates,1767websocket messages,2992ms maximum update gap,2353ms first update latency,1connection start,0disconnects,0terminations, and explicit websocket cleanup.mix test --include live --exclude prod_order_live test/ccxt_pro_binance_live_test.exs --timeout 180000:34 tests, 0 failures. This run covered the public single-symbol and multi-symbol ticker, trade, OHLCV, order book, mark-price, bids/asks, and unsubscribe smoke paths, plus liveforceOrdersubscribe/unsubscribe ACK coverage for the liquidation stream. It also covered signed read-only balance, position, open-orders, all-orders, closed-orders, and my-trades websocket API calls when matching credentials were available, or recorded the expected Binance credential / permission reason.CCXT_PRO_ENABLE_PROD_ORDER_LIVE=true BINANCE_PROD_ORDER_SYMBOL=BTC/USDT BINANCE_PROD_ORDER_AMOUNT=0.0002 mix test --only prod_order_live test/ccxt_pro_binance_live_test.exs --timeout 180000:3 tests, 0 failures (31 excluded). The gated production order smoke placed non-marketable spot limit orders and verified create, fetch, edit, cancel, andstream_orders/4execution-report event handling before cleanup.
Remaining Public Scope
All TypeScript methods categorized as public websocket streams are now covered in the current manifest.
Remaining Private Scope
All TypeScript methods categorized as private websocket streams are now covered
in the current manifest. Balance, positions, orders, my trades, and my
liquidations now maintain lightweight runtime private cache state across
user-data events. Spot/margin balanceUpdate events add the websocket delta to
the existing cached free balance, matching the TypeScript
Precise.stringAdd(previousValue, delta) branch. Futures/delivery
ACCOUNT_UPDATE position entries inherit the websocket event timestamp so
watch_positions/4 can return parsed positions with timestamp and
datetime, matching the TypeScript handlePositions timestamp assignment.
Ccxt.Pro.PositionCache owns the symbol+side-indexed position cache,
per-symbol payload view, and flattened values view used by
watch_positions/4.
Private order caches now merge trade execution metadata by order id: TRADE
events are routed through Ccxt.Pro.OrderCache, attach cached raw trades and
accumulated fee metadata to the cached order payload, and generated
parse_ws_order/2 emits unified orders with trades and fee. The same
runtime component exposes a hashmap/1 view keyed by symbol -> order id,
matching the lookup shape used by CCXT Pro order caches while preserving list
payload compatibility for current watchers.
Order/trade/liquidation list retention is now routed through
Ccxt.Pro.ArrayCache. Private stream subscriptions support per-message-hash
:cache_limit. Private stream subscriptions also support injectable
:snapshot_payloads, which preload balance/position caches and immediately
resolve matching private watch waiters. The generated private watch helpers now
wire the TypeScript fetchBalanceSnapshot and fetchPositionsSnapshot option
branches through :snapshot_fetcher, :rest_fetcher, or generated high-level
REST methods. Remaining cache work is deeper specialized cache variants beyond
the cache classes already represented in the manifest.
Binance Pro Coverage Status
ts/src/pro/binance.ts source-method coverage is complete for Binance. The
remaining work listed here is incremental parity refinement and should continue
to be implemented as generic capabilities rather than one-off method templates:
Stream Helper Completion Matrix
The Elixir-only stream_* helpers are generated convenience wrappers around
the generated watch_* methods. They repeatedly await the matching CCXT Pro
watch method and call the matching public unwatch_* method when the enumerable
halts where Binance exposes an unsubscribe channel. Private account streams use
the Binance user data stream lifecycle and runtime connection cleanup instead
of method-specific unsubscribe calls.
| Stream helper | Watch source | Unit coverage | Live coverage | Notes |
|---|---|---|---|---|
stream_ticker/2,3 | watch_ticker/2 | fake repeated updates | prod public live | Public stream; Enum.take/2 receives repeated ticker updates. |
stream_trades/4,5 | watch_trades/4 | fake repeated updates | prod public live | Public stream; no funds risk. |
stream_order_book/3,4 | watch_order_book/3 | fake repeated snapshots | prod public live | Public stream; uses generated order-book watch path. |
stream_ohlcv/5,6 | watch_ohlcv/5 | fake repeated candles | prod public live | Public stream; no funds risk. |
stream_balance/1,2 | watch_balance/1 | fake private cache updates | prod private read-only smoke | Private stream; live can report credential, permission, or active subscription state. |
stream_positions/4,5 | watch_positions/4 | fake private cache updates | prod private read-only smoke | Private futures stream; live depends on futures permission and account state. |
stream_orders/4,5 | watch_orders/4 | fake repeated order events | gated prod live order event | Live proof uses CCXT_PRO_ENABLE_PROD_ORDER_LIVE=true, a non-marketable order, and immediate cancel. |
stream_my_trades/4,5 | watch_my_trades/4 | fake repeated trade events | manual-fill only | Non-marketable orders intentionally do not emit trade fills; live proof requires an explicitly accepted real fill or remains fake/unit evidence. |
Current stream completion status is therefore complete for generated API
surface, repeated enumerable behavior, public live behavior, read-only private
smoke behavior, and gated order-event behavior. The only intentionally
ungated live gap is stream_my_trades/4,5, because proving it on Binance
requires a real executed trade rather than the non-marketable production order
policy.
unsubscribe: the now-coveredun_watch_*channel families are generated through shared unsubscribe wrapper, channel-family, and ticker-stream renderers. Direct channel-family unsubscribe methods delegate theunwatch_channels/5waiter request to a typed unsubscribe request node; ticker and mark-price unsubscribe wrappers delegate theirunwatch_ticker_stream/6call through a typed ticker-stream unsubscribe node. The sharedunwatch_channels/5helper is rendered through a typed payload/waiter node that owns the BinanceUNSUBSCRIBEmessage, generated request id, public websocket URL, andCcxt.Pro.Connection.unwatch_any/3call.publicStream: source-method coverage is complete.watch_ticker/2,watch_tickers/2,watch_trades/4,watch_trades_for_symbols/4,watch_ohlcv/5,watch_ohlcv_for_symbols/4,watch_liquidations/4,watch_liquidations_for_symbols/4,watch_mark_price/2,watch_mark_prices/2,watch_bids_asks/2, andwatch_multi_ticker_helper/5are covered by shared public watch/watchMultiple/ticker-family renderers. The single and multiple public watch renderers now delegate channel/message-hash/subscription/watch-call rendering to typed public subscription nodes forwatch_ticker/2,watch_trades_for_symbols/4,watch_ohlcv_for_symbols/4, andwatch_liquidations_for_symbols/4;watch_multi_ticker_helper/5delegates ticker-family public watch-any subscription, cache registration, and parser market-type selection to a typed subscription node while preserving its unsubscribe branch.watch_order_book/3andwatch_order_book_for_symbols/3are covered by orderbook watch renderers, including multi-symbol channel registration and per-symbol snapshot loading.wsApi: source-method coverage is complete.fetch_order_book_ws/3,fetch_ohlcv_ws/5,fetch_ticker_ws/2, andfetch_trades_ws/4are covered by the shared websocket API request renderer, whose typed request node covers signed waiter, unsigned connection, and unsigned helper request modes through dedicated request-mode renderers.fetch_balance_ws/1,fetch_positions_ws/2,fetch_order_ws/3, andfetch_open_orders_ws/4use the same renderer through signed helper request mode.fetch_position_ws/2andfetch_closed_orders_ws/4are covered by the websocket API wrapper renderer; wrapper nodes now record their delegated ws-api method, list result shape, and response filter semantics.fetch_orders_ws/4andfetch_my_trades_ws/4are covered by validation-aware websocket API request rendering, as arecancel_order_ws/3andcancel_all_orders_ws/2; their success path now uses typed payload, signed-request, and response IR nodes after guarded validation branches.create_order_ws/6andedit_order_ws/7are covered by signed order mutation IR rendering, with shared signed request/response handling for order mutation results, typed success/request IR nodes for the generated mutation method body, and shared edit-order payload routing for spot cancel-replace versus contract modify-order. The runtime-owned websocket API response handlers now record typed success-response, status-error, and request-id waiter nodes in the manifest. The payload-helper renderer now owns ignored option keys, Binance camel-case key mappings, and conditional-order option key detection. The manifest records AST-derived sub-IR signals and structured nodes for signed requests, request waiters, ordinary websocket API request modes, guarded validation requests, websocket API payload shapes/fields, create-order payload delegation, spot cancel-replace, contract modify-order, signed order mutation requests, cancel payloads, and response filters. Stream, unsubscribe, and cache helpers also expose structured nodes for watch mode, channel family, private auth, cache, snapshot preload, and orderbook snapshot/delta behavior. Auth/listenKey, parser, websocket API response, event handler, and top-level dispatch methods also expose structured nodes in the same manifest format. The payload helper renderer now consumes a composed typed IR spec and delegates to smaller reusable render nodes for order-id payloads, create-order request delegation, edit payload branch selection, base order payloads, option mapping, and conditional-order detection. Further improvements should keep moving renderer-specific internals into explicit IR specs where a reusable pattern is clear.auth: websocket signature subscription, listenToken subscription, renewal, authenticate routing, and listenKey keepalive are covered by shared auth/listenKey IR renderers. The signature and listenToken subscription methods now use typed request/result nodes for websocket API auth subscription and subscription-id response handling.authenticate/1now uses typed router branch specs rather than an opaque branch-line block, andkeep_alive_listen_key/3uses a typed keepalive request spec for supported endpoint fetch versus unsupported types. The signer runtime now covers the HMAC SHA256, RSA SHA256, and Ed25519 branches used by Binance ProsignParams.privateStream: the now-covered private stream methods are generated through shared private watch IR renderers. Theirwatch_private_payload/3calls are now rendered through a typed private watch payload/request node. Balance, positions, orders, my trades, and my liquidations consume runtime private cache payloads. The single-symbol private liquidation method is also covered by the shared single-from-multiple wrapper IR. Spot/margin balance delta updates now accumulate against existing cached free balances, andCcxt.Pro.PositionCachestores symbol-indexed position entries with event timestamps for parsedwatch_positions/4results. Private order cache entries useCcxt.Pro.OrderCacheto merge TRADE execution metadata into the generated order parser output, including cached trades and accumulated fee metadata, and expose a symbol/order-id index view; private order handlers now recordcache-engine:order-cache,cache-class:order-cache,cache-semantic:symbol-id-index, andcache-semantic:order-trade-mergein the manifest. Private trade/liquidation list retention uses the reusableCcxt.Pro.ArrayCacheruntime component with per-subscription:cache_limit. Their handlers recordcache-engine:array-cache,cache-class:array-cache, andcache-semantic:bounded-newest-first, while account handlers recordcache-engine:balance-position-cache,cache-class:position-cache,cache-semantic:symbol-index,cache-semantic:side-index, andcache-semantic:balance-delta. Private watch subscriptions can preload snapshot payloads into the runtime cache and resolve the matching waiter immediately, matching the cache warm-up role ofsetBalanceCache/setPositionsCache. Generated watch helpers now support the TypeScriptfetchBalanceSnapshotandfetchPositionsSnapshotoption branches with injectable snapshot fetchers for offline tests, optional REST fetchers, and generated high-level REST fallback; the snapshot preload helpers are now rendered through typed preload/fetch nodes that record balance and positions snapshot fetch semantics in the manifest. Runtime-owned cache helper methods also record snapshot targets, REST snapshot requests, cache-engine nodes, cache-class nodes, and cache semantic nodes for balance, positions, and orderbook snapshot caches. The next private-stream improvement is broader watcher wiring for the new indexed cache primitives and broader live coverage where credentials permit it.parser: simple field-mapping parsers are covered by structured parser IR, and ticker/trade are covered by conditional parser IR. Parser manifest nodes now record conditional branch names, safe wrapper usage, and order/trade cache merge semantics. The parser category has no remaining inline method template; future parser work should improve field parity with the TypeScript implementation where current Elixir behavior is intentionally narrower.cache: public ticker-family streams, public trades/OHLCV, and private order/trade/liquidation list retention now useCcxt.Pro.ArrayCache. Order book pre-snapshot delta buffers use the same bounded append semantics. Balance cache updates handle both full account-position payloads and incrementalbalanceUpdatedeltas, while position cache entries preserve event timestamps for parser output throughCcxt.Pro.PositionCache.Ccxt.Pro.CacheUpdatesowns CCXT ProallNewUpdates,newUpdatesBySymbol, nested id/side, and timestamp counter semantics without changing default list-shaped watcher payloads. Public cached watch streams and private list/order watchers can opt into that incremental window withnewUpdates: trueornew_updates: true.Ccxt.Pro.OrderCachemerges private trade metadata by order id before generated parsing. Private snapshot preload is available through subscription-level:snapshot_payloads, and generated private watch helpers can fetch balance/position snapshots before subscription registration. Remaining cache work is any exchange-specific specialized cache variant beyond Binance, plus future private payload shapes that can safely expose incremental windows without changing non-list parser inputs. Current cache-owned TypeScript methods are explicitly represented by runtime contracts inpro_manifest.json.Pro IR: continue splitting large renderer internals into smaller Pro IR nodes as patterns stabilize, especially for deeper payload helper internals and specialized cache-class variants.