feat(binance): add eOptions WebSocket support#27982
feat(binance): add eOptions WebSocket support#27982lucasjamar wants to merge 18 commits intoccxt:masterfrom
Conversation
Add full public + private WebSocket support for Binance eOptions (European-style options, eapi.binance.com): Public streams: - watchOrderBookForSymbols, unWatchOrderBookForSymbols - watchTradesForSymbols, unWatchTradesForSymbols (uses @optiontrade stream) - watchOHLCVForSymbols, unWatchOHLCVForSymbols - watchTickers, watchBidsAsks, watchMarkPrices (via watchMultiTickerHelper) - unWatchBidsAsks (new method) - Mark price stream: <underlying>@optionMarkPrice (per-underlying, deduped) - watchLiquidationsForSymbols: throws NotSupported (no eOptions liquidation stream) Private streams: - watchBalance, watchOrders, watchMyTrades, watchPositions - handleOptionsAccountUpdate for BALANCE_POSITION_UPDATE events - parseWsOptionsPosition for eOptions P[] position entries - authenticate/keepAliveListenKey via eapiPrivate{Post,Put}ListenKey Fixes: - parseWsTrade, parseWsOrder, handleTrade, handleOHLCV: detect option symbols by '-' in market ID - parseWsTicker: use safeString2(mp, p) for mark price to support eOptions mp field - getAccountTypeFromSubscriptions: add 'option' account type Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
new Set<string>() does not transpile correctly to C#, PHP, Go, or Python. Replace with a plain object used as a set. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…eoptions/ws Was incorrectly using fstream.binance.com (futures URL). The eOptions public and private WS streams both use wss://nbstream.binance.com/eoptions/ws. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Use wss://fstream.binance.com/public/stream for tickers/depth/trades
- Use wss://fstream.binance.com/market/stream for mark prices and klines
- Unwrap {"stream": "...", "data": {...}} combined stream message format
in handleMessage so events are routed correctly
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Binance's isLinear() override returns subType == 'linear' regardless of marketType. Since USDT-settled eOptions have linear=True, handleSubTypeAndParams sets subType='linear', causing isLinear() to return True for option markets. This routed option symbols to the futures WebSocket URL instead of the eOptions endpoint. Fix: move the `marketType === 'option'` check before the isLinear check in watchMultiTickerHelper so options always route to the correct endpoint. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
CCXT uses subscribe/unsubscribe JSON messages over a persistent WebSocket connection, appending an index (e.g. /0) to the base URL. The combined stream URLs (/public/stream, /market/stream) only support query-param subscriptions (?streams=...) and return 404 when accessed as /stream/0. Correct base URLs for eOptions WebSocket subscribe/unsubscribe API: /public/ws (depth, trades, tickers) /market/ws (mark price, klines, OI) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- watchTradesForSymbols: remove @optiontrade override — Binance eOptions uses the standard @trade stream (not @optiontrade). The handleTrade handler already detects option markets via the '-' in the market ID. - watchOHLCVForSymbols / unWatchOHLCVForSymbols: route option markets to 'optionMarket' URL (/market/ws) instead of 'option' (/public/ws), since eOptions kline streams are served from the /market/ws endpoint. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The user data (private) stream for Binance eOptions connects to: wss://fstream.binance.com/private/ws/<listenKey> Not /public/ws. See: https://developers.binance.com/docs/derivatives/options-trading/user-data-streams Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…erBook
- watchOHLCVForSymbols / unWatchOHLCVForSymbols: introduce separate
wsUrlType variable (type: Str) to hold the WS URL routing key
('optionMarket') without conflicting with the MarketType-typed 'type'
variable. Fixes TS2322 error.
- handleOrderBook: add isOption detection (same pattern as handleTrade)
so option depth update messages use marketType='option' for market
lookup instead of 'swap', ensuring correct symbol resolution.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Replace indexOf('-') heuristic with markets_by_id lookup for option detection
- Consolidate isSpotUrl + 'ps' field checks into marketById['type'] lookup
- watchMarkPrices: fix defaultMarket overriding defaultType='option', fix isOptionMarkPrice detection when no symbols given, wait on batch hash so full dict is returned when symbols list provided
- watchMarkPrices/watchTickers: support underlying+expirationDate params when no symbols given
- watchTradesForSymbols: always subscribe per-underlying (btcusdt@optionTrade) for eOptions
- watchMultiTickerHelper: return batch result directly for isOptionMarkPrice (fixes KeyError 'symbol')
- fetchMarkPrice/fetchMarkPrices: add eOptions branch via eapiPublicGetMark
- fetchBidsAsks: add eOptions branch via eapiPublicGetTicker
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- handleOptionsOrderUpdate: handle eOptions ORDER_TRADE_UPDATE where "o" is an array of orders (not a dict like futures), each with a "fi" fills array. Normalizes eOptions fields (oid→i, S status→X, oty→o, tif→f, signed q→abs qty + side) to the flat format handleOrder/handleMyTrade already understand. Dispatches per-fill trades for watchMyTrades. - handleBalance: default safeList(message, 'B') to [] to prevent TypeError when ACCOUNT_UPDATE arrives without a B field on eOptions stream Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Replace ternary expressions with if/else blocks to avoid Python syntax errors generated by the transpiler for conditions with method calls. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
Hi CCXT Team,
Local testing on all endpoints worked. Can you please have a look? |
Replace rawQty.charAt(0) string manipulation (JS-only) with safeNumber + Math.abs + numberToString which transpiles correctly to all target languages including C#. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Replace Math.abs (transpiles to undefined mathAbs in Go) with Precise.stringLt + Precise.stringAbs which transpile correctly to all target languages. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
ccxt.Remove() panics in Go when the key does not exist (unlike JS delete which is a safe no-op). The handleOrderBook catch block deletes this.orderbooks[symbol] and client.subscriptions[messageHash], both of which may be absent when a ChecksumError occurs. Add 'in' checks before each delete so the transpiled Go uses ccxt.InOp guards before Remove. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
Hello @lucasjamar thanks for your contribution, cna you please revert all files but .ts? All the others are automatically generated. |
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
done |
|
@lucasjamar I think there's some issues with options testnet/demo currently so it might be best to remove those URL's for now. When I sign on to the demo site there's no option contracts available. The REST API would need to be adjusted when the demo account is working for options, the test and demo URLs for options were removed in the REST implementation and there's this skip in fetchMarkets: There's also a skip for |
…rivate methods Option markets are not available in testnet/demo environments. Matches the existing REST behavior where fetchMarkets skips option markets when isDemoEnv is true. - Remove option/optionMarket/optionPrivate URLs from test and demo WS URL blocks - Add NotSupported guard in watchBalance/watchOrders/watchPositions/watchMyTrades when type='option' and sandbox/demo mode is enabled Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Hi @Dan-krm , is the current version ok? my tests still pass on my side |
@lucasjamar Yeah that looks good to me, and we can watch for any demo/sandbox updates in the changelog and remove those checks later when it's properly supported. |
Add full public + private WebSocket support for Binance eOptions (European-style options, eapi.binance.com):
fix: #26333
Public streams:
Private streams:
Fixes: