Files
ccxt_with_mt5/ccxt/pro/ndax.py
lz_db 0fab423a18 add
2025-11-16 12:31:03 +08:00

520 lines
22 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
import json
from ccxt.base.types import Any, Int, OrderBook, Ticker, Trade
from ccxt.async_support.base.ws.client import Client
from typing import List
class ndax(ccxt.async_support.ndax):
def describe(self) -> Any:
return self.deep_extend(super(ndax, self).describe(), {
'has': {
'ws': True,
'watchOrderBook': True,
'watchTrades': True,
'watchTradesForSymbols': False,
'watchTicker': True,
'watchOHLCV': True,
},
'urls': {
'test': {
'ws': 'wss://ndaxmarginstaging.cdnhop.net:10456/WSAdminGatewa/',
},
'api': {
'ws': 'wss://api.ndax.io/WSGateway',
},
},
# 'options': {
# 'tradesLimit': 1000,
# 'ordersLimit': 1000,
# 'OHLCVLimit': 1000,
# },
})
def request_id(self):
requestId = self.sum(self.safe_integer(self.options, 'requestId', 0), 1)
self.options['requestId'] = requestId
return requestId
async def watch_ticker(self, symbol: str, params={}) -> Ticker:
"""
watches a price ticker, a statistical calculation with the information calculated over the past 24 hours for a specific market
https://apidoc.ndax.io/#subscribelevel1
:param str symbol: unified symbol of the market to fetch the ticker for
:param dict [params]: extra parameters specific to the exchange API endpoint
:returns dict: a `ticker structure <https://docs.ccxt.com/#/?id=ticker-structure>`
"""
omsId = self.safe_integer(self.options, 'omsId', 1)
await self.load_markets()
market = self.market(symbol)
name = 'SubscribeLevel1'
messageHash = name + ':' + market['id']
url = self.urls['api']['ws']
requestId = self.request_id()
payload: dict = {
'OMSId': omsId,
'InstrumentId': int(market['id']), # conditionally optional
# 'Symbol': market['info']['symbol'], # conditionally optional
}
request: dict = {
'm': 0, # message type, 0 request, 1 reply, 2 subscribe, 3 event, unsubscribe, 5 error
'i': requestId, # sequence number identifies an individual request or request-and-response pair, to your application
'n': name, # function name is the name of the function being called or that the server is responding to, the server echoes your call
'o': self.json(payload), # JSON-formatted string containing the data being sent with the message
}
message = self.extend(request, params)
return await self.watch(url, messageHash, message, messageHash)
def handle_ticker(self, client: Client, message):
payload = self.safe_value(message, 'o', {})
#
# {
# "OMSId": 1,
# "InstrumentId": 1,
# "BestBid": 6423.57,
# "BestOffer": 6436.53,
# "LastTradedPx": 6423.57,
# "LastTradedQty": 0.96183964,
# "LastTradeTime": 1534862990343,
# "SessionOpen": 6249.64,
# "SessionHigh": 11111,
# "SessionLow": 4433,
# "SessionClose": 6249.64,
# "Volume": 0.96183964,
# "CurrentDayVolume": 3516.31668185,
# "CurrentDayNumTrades": 8529,
# "CurrentDayPxChange": 173.93,
# "CurrentNotional": 0.0,
# "Rolling24HrNotional": 0.0,
# "Rolling24HrVolume": 4319.63870783,
# "Rolling24NumTrades": 10585,
# "Rolling24HrPxChange": -0.4165607307408487,
# "TimeStamp": "1534862990358"
# }
#
ticker = self.parse_ticker(payload)
symbol = ticker['symbol']
market = self.market(symbol)
self.tickers[symbol] = ticker
name = 'SubscribeLevel1'
messageHash = name + ':' + market['id']
client.resolve(ticker, messageHash)
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://apidoc.ndax.io/#subscribetrades
: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://docs.ccxt.com/#/?id=public-trades>`
"""
omsId = self.safe_integer(self.options, 'omsId', 1)
await self.load_markets()
market = self.market(symbol)
symbol = market['symbol']
name = 'SubscribeTrades'
messageHash = name + ':' + market['id']
url = self.urls['api']['ws']
requestId = self.request_id()
payload: dict = {
'OMSId': omsId,
'InstrumentId': int(market['id']), # conditionally optional
'IncludeLastCount': 100, # the number of previous trades to retrieve in the immediate snapshot, 100 by default
}
request: dict = {
'm': 0, # message type, 0 request, 1 reply, 2 subscribe, 3 event, unsubscribe, 5 error
'i': requestId, # sequence number identifies an individual request or request-and-response pair, to your application
'n': name, # function name is the name of the function being called or that the server is responding to, the server echoes your call
'o': self.json(payload), # JSON-formatted string containing the data being sent with the message
}
message = self.extend(request, params)
trades = await self.watch(url, messageHash, message, messageHash)
if self.newUpdates:
limit = trades.getLimit(symbol, limit)
return self.filter_by_since_limit(trades, since, limit, 'timestamp', True)
def handle_trades(self, client: Client, message):
payload = self.safe_value(message, 'o', [])
#
# initial snapshot
#
# [
# [
# 6913253, # 0 TradeId
# 8, # 1 ProductPairCode
# 0.03340802, # 2 Quantity
# 19116.08, # 3 Price
# 2543425077, # 4 Order1
# 2543425482, # 5 Order2
# 1606935922416, # 6 Tradetime
# 0, # 7 Direction
# 1, # 8 TakerSide
# 0, # 9 BlockTrade
# 0, # 10 Either Order1ClientId or Order2ClientId
# ]
# ]
#
name = 'SubscribeTrades'
updates: dict = {}
for i in range(0, len(payload)):
trade = self.parse_trade(payload[i])
symbol = trade['symbol']
tradesArray = self.safe_value(self.trades, symbol)
if tradesArray is None:
limit = self.safe_integer(self.options, 'tradesLimit', 1000)
tradesArray = ArrayCache(limit)
tradesArray.append(trade)
self.trades[symbol] = tradesArray
updates[symbol] = True
symbols = list(updates.keys())
for i in range(0, len(symbols)):
symbol = symbols[i]
market = self.market(symbol)
messageHash = name + ':' + market['id']
tradesArray = self.safe_value(self.trades, symbol)
client.resolve(tradesArray, messageHash)
async def watch_ohlcv(self, symbol: str, timeframe: str = '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://apidoc.ndax.io/#subscribeticker
: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
"""
omsId = self.safe_integer(self.options, 'omsId', 1)
await self.load_markets()
market = self.market(symbol)
symbol = market['symbol']
name = 'SubscribeTicker'
messageHash = name + ':' + timeframe + ':' + market['id']
url = self.urls['api']['ws']
requestId = self.request_id()
payload: dict = {
'OMSId': omsId,
'InstrumentId': int(market['id']), # conditionally optional
'Interval': int(self.safe_string(self.timeframes, timeframe, timeframe)),
'IncludeLastCount': 100, # the number of previous candles to retrieve in the immediate snapshot, 100 by default
}
request: dict = {
'm': 0, # message type, 0 request, 1 reply, 2 subscribe, 3 event, unsubscribe, 5 error
'i': requestId, # sequence number identifies an individual request or request-and-response pair, to your application
'n': name, # function name is the name of the function being called or that the server is responding to, the server echoes your call
'o': self.json(payload), # JSON-formatted string containing the data being sent with the message
}
message = self.extend(request, params)
ohlcv = await self.watch(url, messageHash, message, messageHash)
if self.newUpdates:
limit = ohlcv.getLimit(symbol, limit)
return self.filter_by_since_limit(ohlcv, since, limit, 0, True)
def handle_ohlcv(self, client: Client, message):
#
# {
# "m": 1,
# "i": 1,
# "n": "SubscribeTicker",
# "o": [[1608284160000,23113.52,23070.88,23075.76,23075.39,162.44964300,23075.38,23075.39,8,1608284100000]],
# }
#
payload = self.safe_value(message, 'o', [])
#
# [
# [
# 1501603632000, # 0 DateTime
# 2700.33, # 1 High
# 2687.01, # 2 Low
# 2687.01, # 3 Open
# 2687.01, # 4 Close
# 24.86100992, # 5 Volume
# 0, # 6 Inside Bid Price
# 2870.95, # 7 Inside Ask Price
# 1 # 8 InstrumentId
# 1608290188062.7678, # 9 candle timestamp
# ]
# ]
#
updates: dict = {}
for i in range(0, len(payload)):
ohlcv = payload[i]
marketId = self.safe_string(ohlcv, 8)
market = self.safe_market(marketId)
symbol = market['symbol']
updates[marketId] = {}
self.ohlcvs[symbol] = self.safe_value(self.ohlcvs, symbol, {})
keys = list(self.timeframes.keys())
for j in range(0, len(keys)):
timeframe = keys[j]
interval = self.safe_string(self.timeframes, timeframe, timeframe)
duration = int(interval) * 1000
timestamp = self.safe_integer(ohlcv, 0)
parsed = [
self.parse_to_int((timestamp / duration) * duration),
self.safe_float(ohlcv, 3),
self.safe_float(ohlcv, 1),
self.safe_float(ohlcv, 2),
self.safe_float(ohlcv, 4),
self.safe_float(ohlcv, 5),
]
stored = self.safe_value(self.ohlcvs[symbol], timeframe, [])
length = len(stored)
if length and (parsed[0] == stored[length - 1][0]):
previous = stored[length - 1]
stored[length - 1] = [
parsed[0],
previous[1],
max(parsed[1], previous[1]),
min(parsed[2], previous[2]),
parsed[4],
self.sum(parsed[5], previous[5]),
]
updates[marketId][timeframe] = True
else:
if length and (parsed[0] < stored[length - 1][0]):
continue
else:
stored.append(parsed)
limit = self.safe_integer(self.options, 'OHLCVLimit', 1000)
if length >= limit:
stored.pop(0)
updates[marketId][timeframe] = True
self.ohlcvs[symbol][timeframe] = stored
name = 'SubscribeTicker'
marketIds = list(updates.keys())
for i in range(0, len(marketIds)):
marketId = marketIds[i]
timeframes = list(updates[marketId].keys())
for j in range(0, len(timeframes)):
timeframe = timeframes[j]
messageHash = name + ':' + timeframe + ':' + marketId
market = self.safe_market(marketId)
symbol = market['symbol']
stored = self.safe_value(self.ohlcvs[symbol], timeframe, [])
client.resolve(stored, messageHash)
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://apidoc.ndax.io/#subscribelevel2
: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
"""
omsId = self.safe_integer(self.options, 'omsId', 1)
await self.load_markets()
market = self.market(symbol)
symbol = market['symbol']
name = 'SubscribeLevel2'
messageHash = name + ':' + market['id']
url = self.urls['api']['ws']
requestId = self.request_id()
limit = 100 if (limit is None) else limit
payload: dict = {
'OMSId': omsId,
'InstrumentId': int(market['id']), # conditionally optional
# 'Symbol': market['info']['symbol'], # conditionally optional
'Depth': limit, # default 100
}
request: dict = {
'm': 0, # message type, 0 request, 1 reply, 2 subscribe, 3 event, unsubscribe, 5 error
'i': requestId, # sequence number identifies an individual request or request-and-response pair, to your application
'n': name, # function name is the name of the function being called or that the server is responding to, the server echoes your call
'o': self.json(payload), # JSON-formatted string containing the data being sent with the message
}
subscription: dict = {
'id': requestId,
'messageHash': messageHash,
'name': name,
'symbol': symbol,
'marketId': market['id'],
'method': self.handle_order_book_subscription,
'limit': limit,
'params': params,
}
message = self.extend(request, params)
orderbook = await self.watch(url, messageHash, message, messageHash, subscription)
return orderbook.limit()
def handle_order_book(self, client: Client, message):
#
# {
# "m": 3,
# "i": 2,
# "n": "Level2UpdateEvent",
# "o": [[2,1,1608208308265,0,20782.49,1,25000,8,1,1]]
# }
#
payload = self.safe_value(message, 'o', [])
#
# [
# 0, # 0 MDUpdateId
# 1, # 1 Number of Unique Accounts
# 123, # 2 ActionDateTime in Posix format X 1000
# 0, # 3 ActionType 0(New), 1(Update), 2(Delete)
# 0.0, # 4 LastTradePrice
# 0, # 5 Number of Orders
# 0.0, # 6 Price
# 0, # 7 ProductPairCode
# 0.0, # 8 Quantity
# 0, # 9 Side
# ],
#
firstBidAsk = self.safe_value(payload, 0, [])
marketId = self.safe_string(firstBidAsk, 7)
if marketId is None:
return
market = self.safe_market(marketId)
symbol = market['symbol']
orderbook = self.safe_value(self.orderbooks, symbol)
if orderbook is None:
return
timestamp = None
nonce = None
for i in range(0, len(payload)):
bidask = payload[i]
if timestamp is None:
timestamp = self.safe_integer(bidask, 2)
else:
newTimestamp = self.safe_integer(bidask, 2)
timestamp = max(timestamp, newTimestamp)
if nonce is None:
nonce = self.safe_integer(bidask, 0)
else:
newNonce = self.safe_integer(bidask, 0)
nonce = max(nonce, newNonce)
# 0 new, 1 update, 2 remove
type = self.safe_integer(bidask, 3)
price = self.safe_float(bidask, 6)
amount = self.safe_float(bidask, 8)
side = self.safe_integer(bidask, 9)
# 0 buy, 1 sell, 2 short reserved for future use, 3 unknown
orderbookSide = orderbook['bids'] if (side == 0) else orderbook['asks']
# 0 new, 1 update, 2 remove
if type == 0:
orderbookSide.store(price, amount)
elif type == 1:
orderbookSide.store(price, amount)
elif type == 2:
orderbookSide.store(price, 0)
orderbook['nonce'] = nonce
orderbook['timestamp'] = timestamp
orderbook['datetime'] = self.iso8601(timestamp)
name = 'SubscribeLevel2'
messageHash = name + ':' + marketId
self.orderbooks[symbol] = orderbook
client.resolve(orderbook, messageHash)
def handle_order_book_subscription(self, client: Client, message, subscription):
#
# {
# "m": 1,
# "i": 1,
# "n": "SubscribeLevel2",
# "o": [[1,1,1608204295901,0,20782.49,1,18200,8,1,0]]
# }
#
payload = self.safe_value(message, 'o', [])
#
# [
# [
# 0, # 0 MDUpdateId
# 1, # 1 Number of Unique Accounts
# 123, # 2 ActionDateTime in Posix format X 1000
# 0, # 3 ActionType 0(New), 1(Update), 2(Delete)
# 0.0, # 4 LastTradePrice
# 0, # 5 Number of Orders
# 0.0, # 6 Price
# 0, # 7 ProductPairCode
# 0.0, # 8 Quantity
# 0, # 9 Side
# ],
# ]
#
symbol = self.safe_string(subscription, 'symbol')
snapshot = self.parse_order_book(payload, symbol)
limit = self.safe_integer(subscription, 'limit')
orderbook = self.order_book(snapshot, limit)
self.orderbooks[symbol] = orderbook
messageHash = self.safe_string(subscription, 'messageHash')
client.resolve(orderbook, messageHash)
def handle_subscription_status(self, client: Client, message):
#
# {
# "m": 1,
# "i": 1,
# "n": "SubscribeLevel2",
# "o": "[[1,1,1608204295901,0,20782.49,1,18200,8,1,0]]"
# }
#
subscriptionsById = self.index_by(client.subscriptions, 'id')
id = self.safe_integer(message, 'i')
subscription = self.safe_value(subscriptionsById, id)
if subscription is not None:
method = self.safe_value(subscription, 'method')
if method is not None:
method(client, message, subscription)
def handle_message(self, client: Client, message):
#
# {
# "m": 0, # message type, 0 request, 1 reply, 2 subscribe, 3 event, unsubscribe, 5 error
# "i": 0, # sequence number identifies an individual request or request-and-response pair, to your application
# "n":"function name", # function name is the name of the function being called or that the server is responding to, the server echoes your call
# "o":"payload", # JSON-formatted string containing the data being sent with the message
# }
#
# {
# "m": 1,
# "i": 1,
# "n": "SubscribeLevel2",
# "o": "[[1,1,1608204295901,0,20782.49,1,18200,8,1,0]]"
# }
#
# {
# "m": 3,
# "i": 2,
# "n": "Level2UpdateEvent",
# "o": "[[2,1,1608208308265,0,20782.49,1,25000,8,1,1]]"
# }
#
payload = self.safe_string(message, 'o')
if payload is None:
return
message['o'] = json.loads(payload)
methods: dict = {
'SubscribeLevel2': self.handle_subscription_status,
'SubscribeLevel1': self.handle_ticker,
'Level2UpdateEvent': self.handle_order_book,
'Level1UpdateEvent': self.handle_ticker,
'SubscribeTrades': self.handle_trades,
'TradeDataUpdateEvent': self.handle_trades,
'SubscribeTicker': self.handle_ohlcv,
'TickerDataUpdateEvent': self.handle_ohlcv,
}
event = self.safe_string(message, 'n')
method = self.safe_value(methods, event)
if method is not None:
method(client, message)