Files
beast-trader/dashboard/venv/lib/python3.12/site-packages/ccxt/pro/dydx.py

406 lines
16 KiB
Python

# -*- coding: utf-8 -*-
# PLEASE DO NOT EDIT THIS FILE, IT IS GENERATED AND WILL BE OVERWRITTEN:
# https://github.com/ccxt/ccxt/blob/master/CONTRIBUTING.md#how-to-contribute-code
import ccxt.async_support
from ccxt.async_support.base.ws.cache import ArrayCache, ArrayCacheByTimestamp
from ccxt.base.types import Any, Int, OrderBook, Trade
from ccxt.async_support.base.ws.client import Client
from typing import List
from ccxt.base.errors import ExchangeError
class dydx(ccxt.async_support.dydx):
def describe(self) -> Any:
return self.deep_extend(super(dydx, self).describe(), {
'has': {
'ws': True,
'watchBalance': False,
'watchTicker': False,
'watchTickers': False,
'watchTrades': True,
'watchOrderBook': True,
'watchOHLCV': True,
},
'urls': {
'test': {
'ws': 'wss://indexer.v4testnet.dydx.exchange/v4/ws',
},
'api': {
'ws': 'wss://indexer.dydx.trade/v4/ws',
},
},
'options': {},
'streaming': {},
'exceptions': {},
})
async def watch_trades(self, symbol: str, since: Int = None, limit: Int = None, params={}) -> List[Trade]:
"""
get the list of most recent trades for a particular symbol
https://docs.dydx.xyz/indexer-client/websockets#trades
:param str symbol: unified symbol of the market to fetch trades for
:param int [since]: timestamp in ms of the earliest trade to fetch
:param int [limit]: the maximum amount of trades to fetch
:param dict [params]: extra parameters specific to the exchange API endpoint
:returns dict[]: a list of `trade structures <https://github.com/ccxt/ccxt/wiki/Manual#public-trades>`
"""
await self.load_markets()
url = self.urls['api']['ws']
market = self.market(symbol)
messageHash = 'trade:' + market['symbol']
request: dict = {
'type': 'subscribe',
'channel': 'v4_trades',
'id': market['id'],
}
trades = await self.watch(url, messageHash, self.extend(request, params), messageHash)
if self.newUpdates:
limit = trades.getLimit(symbol, limit)
return self.filter_by_since_limit(trades, since, limit, 'timestamp', True)
async def un_watch_trades(self, symbol: str, params={}) -> Any:
"""
unsubscribes from the trades channel
https://docs.dydx.xyz/indexer-client/websockets#trades
:param str symbol: unified symbol of the market to fetch trades for
:param dict [params]: extra parameters specific to the exchange API endpoint
:returns dict[]: a list of `trade structures <https://docs.ccxt.com/?id=public-trades>`
"""
await self.load_markets()
url = self.urls['api']['ws']
market = self.market(symbol)
messageHash = 'trade:' + market['symbol']
request: dict = {
'type': 'unsubscribe',
'channel': 'v4_trades',
'id': market['id'],
}
return await self.watch(url, messageHash, self.extend(request, params), messageHash)
def handle_trades(self, client, message):
#
# {
# "type": "subscribed",
# "connection_id": "9011edff-d8f7-47fc-bbc6-0c7b5ba7dfae",
# "message_id": 3,
# "channel": "v4_trades",
# "id": "BTC-USD",
# "contents": {
# "trades": [
# {
# "id": "02b6148d0000000200000005",
# "side": "BUY",
# "size": "0.024",
# "price": "114581",
# "type": "LIMIT",
# "createdAt": "2025-08-04T00:42:07.119Z",
# "createdAtHeight": "45487245"
# }
# ]
# }
# }
#
marketId = self.safe_string(message, 'id')
market = self.safe_market(marketId)
symbol = market['symbol']
content = self.safe_dict(message, 'contents')
rawTrades = self.safe_list(content, 'trades', [])
stored = self.safe_value(self.trades, symbol)
if stored is None:
limit = self.safe_integer(self.options, 'tradesLimit', 1000)
stored = ArrayCache(limit)
self.trades[symbol] = stored
parsedTrades = self.parse_trades(rawTrades, market)
for i in range(0, len(parsedTrades)):
parsed = parsedTrades[i]
stored.append(parsed)
messageHash = 'trade' + ':' + symbol
client.resolve(stored, messageHash)
def parse_ws_trade(self, trade, market=None):
#
# {
# "id": "02b6148d0000000200000003",
# "side": "BUY",
# "size": "0.024",
# "price": "114581",
# "type": "LIMIT",
# "createdAt": "2025-08-04T00:42:07.118Z",
# "createdAtHeight": "45487244"
# }
#
timestamp = self.parse8601(self.safe_string(trade, 'createdAt'))
return self.safe_trade({
'id': self.safe_string(trade, 'id'),
'info': trade,
'timestamp': timestamp,
'datetime': self.iso8601(timestamp),
'symbol': self.safe_string(market, 'symbol'),
'order': None,
'type': self.safe_string_lower(trade, 'type'),
'side': self.safe_string_lower(trade, 'side'),
'takerOrMaker': None,
'price': self.safe_string(trade, 'price'),
'amount': self.safe_string(trade, 'size'),
'cost': None,
'fee': None,
}, market)
async def watch_order_book(self, symbol: str, limit: Int = None, params={}) -> OrderBook:
"""
watches information on open orders with bid(buy) and ask(sell) prices, volumes and other data
https://docs.dydx.xyz/indexer-client/websockets#orders
:param str symbol: unified symbol of the market to fetch the order book for
:param int [limit]: the maximum amount of order book entries to return
:param dict [params]: extra parameters specific to the exchange API endpoint
:returns dict: A dictionary of `order book structures <https://docs.ccxt.com/?id=order-book-structure>` indexed by market symbols
"""
await self.load_markets()
url = self.urls['api']['ws']
market = self.market(symbol)
messageHash = 'orderbook:' + market['symbol']
request: dict = {
'type': 'subscribe',
'channel': 'v4_orderbook',
'id': market['id'],
}
orderbook = await self.watch(url, messageHash, self.extend(request, params), messageHash)
return orderbook.limit()
async def un_watch_order_book(self, symbol: str, params={}) -> Any:
"""
unWatches information on open orders with bid(buy) and ask(sell) prices, volumes and other data
https://docs.dydx.xyz/indexer-client/websockets#orders
:param str symbol: unified array of symbols
:param dict [params]: extra parameters specific to the exchange API endpoint
:returns dict: A dictionary of `order book structures <https://docs.ccxt.com/?id=order-book-structure>` indexed by market symbols
"""
await self.load_markets()
url = self.urls['api']['ws']
market = self.market(symbol)
messageHash = 'orderbook:' + market['symbol']
request: dict = {
'type': 'unsubscribe',
'channel': 'v4_orderbook',
'id': market['id'],
}
return await self.watch(url, messageHash, self.extend(request, params), messageHash)
def handle_order_book(self, client: Client, message):
#
# {
# "type": "subscribed",
# "connection_id": "7af140fb-b33d-4f0e-8f4c-30f16337b360",
# "message_id": 1,
# "channel": "v4_orderbook",
# "id": "BTC-USD",
# "contents": {
# "bids": [
# {
# "price": "114623",
# "size": "0.1112"
# }
# ],
# "asks": [
# {
# "price": "114624",
# "size": "0.0872"
# }
# ]
# }
# }
#
marketId = self.safe_string(message, 'id')
market = self.safe_market(marketId)
symbol = market['symbol']
content = self.safe_dict(message, 'contents')
orderbook = self.safe_value(self.orderbooks, symbol)
if orderbook is None:
orderbook = self.order_book()
orderbook['symbol'] = symbol
asks = self.safe_list(content, 'asks', [])
bids = self.safe_list(content, 'bids', [])
self.handle_deltas(orderbook['asks'], asks)
self.handle_deltas(orderbook['bids'], bids)
orderbook['nonce'] = self.safe_integer(message, 'message_id')
messageHash = 'orderbook:' + symbol
self.orderbooks[symbol] = orderbook
client.resolve(orderbook, messageHash)
def handle_delta(self, bookside, delta):
if isinstance(delta, list):
price = self.safe_float(delta, 0)
amount = self.safe_float(delta, 1)
bookside.store(price, amount)
else:
bidAsk = self.parse_bid_ask(delta, 'price', 'size')
bookside.storeArray(bidAsk)
async def watch_ohlcv(self, symbol: str, timeframe='1m', since: Int = None, limit: Int = None, params={}) -> List[list]:
"""
watches historical candlestick data containing the open, high, low, and close price, and the volume of a market
https://docs.dydx.xyz/indexer-client/websockets#candles
:param str symbol: unified symbol of the market to fetch OHLCV data for
:param str timeframe: the length of time each candle represents
:param int [since]: timestamp in ms of the earliest candle to fetch
:param int [limit]: the maximum amount of candles to fetch
:param dict [params]: extra parameters specific to the exchange API endpoint
:returns int[][]: A list of candles ordered, open, high, low, close, volume
"""
await self.load_markets()
url = self.urls['api']['ws']
market = self.market(symbol)
messageHash = 'ohlcv:' + market['symbol']
resolution = self.safe_string(self.timeframes, timeframe, timeframe)
request: dict = {
'type': 'subscribe',
'channel': 'v4_candles',
'id': market['id'] + '/' + resolution,
}
ohlcv = await self.watch(url, messageHash, self.extend(request, params), messageHash)
if self.newUpdates:
limit = ohlcv.getLimit(symbol, limit)
return self.filter_by_since_limit(ohlcv, since, limit, 0, True)
async def un_watch_ohlcv(self, symbol: str, timeframe='1m', params={}) -> Any:
"""
unWatches historical candlestick data containing the open, high, low, and close price, and the volume of a market
https://docs.dydx.xyz/indexer-client/websockets#candles
:param str symbol: unified symbol of the market to fetch OHLCV data for
:param str timeframe: the length of time each candle represents
:param dict [params]: extra parameters specific to the exchange API endpoint
:param dict [params.timezone]: if provided, kline intervals are interpreted in that timezone instead of UTC, example '+08:00'
:returns int[][]: A list of candles ordered, open, high, low, close, volume
"""
await self.load_markets()
url = self.urls['api']['ws']
market = self.market(symbol)
messageHash = 'ohlcv:' + market['symbol']
resolution = self.safe_string(self.timeframes, timeframe, timeframe)
request: dict = {
'type': 'unsubscribe',
'channel': 'v4_candles',
'id': market['id'] + '/' + resolution,
}
return await self.watch(url, messageHash, self.extend(request, params), messageHash)
def handle_ohlcv(self, client: Client, message):
#
# {
# "type": "subscribed",
# "connection_id": "e00b6e27-590c-4e91-a24d-b0645289434b",
# "message_id": 1,
# "channel": "v4_candles",
# "id": "BTC-USD/1MIN",
# "contents": {
# "candles": [
# {
# "startedAt": "2025-08-05T03:40:00.000Z",
# "ticker": "BTC-USD",
# "resolution": "1MIN",
# "low": "114249",
# "high": "114256",
# "open": "114256",
# "close": "114249",
# "baseTokenVolume": "0.4726",
# "usdVolume": "53996.1818",
# "trades": 7,
# "startingOpenInterest": "501.7424",
# "orderbookMidPriceOpen": "114255.5",
# "orderbookMidPriceClose": "114255.5"
# }
# ]
# }
# }
# {
# "type": "channel_data",
# "connection_id": "e00b6e27-590c-4e91-a24d-b0645289434b",
# "message_id": 3,
# "id": "BTC-USD/1MIN",
# "channel": "v4_candles",
# "version": "1.0.0",
# "contents": {
# "startedAt": "2025-08-05T03:40:00.000Z",
# "ticker": "BTC-USD",
# "resolution": "1MIN",
# "low": "114249",
# "high": "114262",
# "open": "114256",
# "close": "114261",
# "baseTokenVolume": "0.4753",
# "usdVolume": "54304.6873",
# "trades": 9,
# "startingOpenInterest": "501.7424",
# "orderbookMidPriceOpen": "114255.5",
# "orderbookMidPriceClose": "114255.5"
# }
# }
#
id = self.safe_string(message, 'id')
part = id.split('/')
interval = self.safe_string(part, 1)
timeframe = self.find_timeframe(interval)
marketId = self.safe_string(part, 0)
market = self.safe_market(marketId)
symbol = market['symbol']
content = self.safe_dict(message, 'contents')
candles = self.safe_list(content, 'candles')
messageHash = 'ohlcv:' + symbol
ohlcv = self.safe_dict(candles, 0, content)
parsed = self.parse_ohlcv(ohlcv, market)
self.ohlcvs[symbol] = self.safe_value(self.ohlcvs, symbol, {})
stored = self.safe_value(self.ohlcvs[symbol], timeframe)
if stored is None:
limit = self.safe_integer(self.options, 'OHLCVLimit', 1000)
stored = ArrayCacheByTimestamp(limit)
self.ohlcvs[symbol][timeframe] = stored
stored.append(parsed)
client.resolve(stored, messageHash)
def handle_error_message(self, client: Client, message):
#
# {
# "type": "error",
# "message": "....",
# "connection_id": "9011edff-d8f7-47fc-bbc6-0c7b5ba7dfae",
# "message_id": 4
# }
#
try:
msg = self.safe_string(message, 'message')
raise ExchangeError(self.id + ' ' + msg)
except Exception as e:
client.reject(e)
return True
def handle_message(self, client: Client, message):
type = self.safe_string(message, 'type')
if type == 'error':
self.handle_error_message(client, message)
return
if type is not None:
topic = self.safe_string(message, 'channel')
methods: dict = {
'v4_trades': self.handle_trades,
'v4_orderbook': self.handle_order_book,
'v4_candles': self.handle_ohlcv,
}
method = self.safe_value(methods, topic)
if method is not None:
method(client, message)