Initial commit: 首次建仓,建立目录结构

This commit is contained in:
FXY
2026-06-11 23:49:54 +08:00
commit 4038a476b5
9396 changed files with 2372905 additions and 0 deletions

View File

@ -0,0 +1,224 @@
# -*- coding: utf-8 -*-
"""CCXT: CryptoCurrency eXchange Trading Library (Async)"""
# ----------------------------------------------------------------------------
__version__ = '4.5.56'
# ----------------------------------------------------------------------------
from ccxt.async_support.base.exchange import Exchange # noqa: F401
# CCXT Pro exchanges (now this is mainly used for importing exchanges in WS tests)
# DO_NOT_REMOVE__ERROR_IMPORTS_START
from ccxt.base.errors import BaseError # noqa: F401
from ccxt.base.errors import ExchangeError # noqa: F401
from ccxt.base.errors import AuthenticationError # noqa: F401
from ccxt.base.errors import PermissionDenied # noqa: F401
from ccxt.base.errors import AccountNotEnabled # noqa: F401
from ccxt.base.errors import AccountSuspended # noqa: F401
from ccxt.base.errors import ArgumentsRequired # noqa: F401
from ccxt.base.errors import BadRequest # noqa: F401
from ccxt.base.errors import BadSymbol # noqa: F401
from ccxt.base.errors import OperationRejected # noqa: F401
from ccxt.base.errors import NoChange # noqa: F401
from ccxt.base.errors import MarginModeAlreadySet # noqa: F401
from ccxt.base.errors import MarketClosed # noqa: F401
from ccxt.base.errors import ManualInteractionNeeded # noqa: F401
from ccxt.base.errors import RestrictedLocation # noqa: F401
from ccxt.base.errors import InsufficientFunds # noqa: F401
from ccxt.base.errors import InvalidAddress # noqa: F401
from ccxt.base.errors import AddressPending # noqa: F401
from ccxt.base.errors import InvalidOrder # noqa: F401
from ccxt.base.errors import OrderNotFound # noqa: F401
from ccxt.base.errors import OrderNotCached # noqa: F401
from ccxt.base.errors import OrderImmediatelyFillable # noqa: F401
from ccxt.base.errors import OrderNotFillable # noqa: F401
from ccxt.base.errors import DuplicateOrderId # noqa: F401
from ccxt.base.errors import ContractUnavailable # noqa: F401
from ccxt.base.errors import NotSupported # noqa: F401
from ccxt.base.errors import InvalidProxySettings # noqa: F401
from ccxt.base.errors import ExchangeClosedByUser # noqa: F401
from ccxt.base.errors import OperationFailed # noqa: F401
from ccxt.base.errors import NetworkError # noqa: F401
from ccxt.base.errors import DDoSProtection # noqa: F401
from ccxt.base.errors import RateLimitExceeded # noqa: F401
from ccxt.base.errors import ExchangeNotAvailable # noqa: F401
from ccxt.base.errors import OnMaintenance # noqa: F401
from ccxt.base.errors import InvalidNonce # noqa: F401
from ccxt.base.errors import ChecksumError # noqa: F401
from ccxt.base.errors import RequestTimeout # noqa: F401
from ccxt.base.errors import BadResponse # noqa: F401
from ccxt.base.errors import NullResponse # noqa: F401
from ccxt.base.errors import CancelPending # noqa: F401
from ccxt.base.errors import UnsubscribeError # noqa: F401
from ccxt.base.errors import error_hierarchy # noqa: F401
# DO_NOT_REMOVE__ERROR_IMPORTS_END
from ccxt.pro.aftermath import aftermath # noqa: F401
from ccxt.pro.alpaca import alpaca # noqa: F401
from ccxt.pro.apex import apex # noqa: F401
from ccxt.pro.arkham import arkham # noqa: F401
from ccxt.pro.ascendex import ascendex # noqa: F401
from ccxt.pro.aster import aster # noqa: F401
from ccxt.pro.backpack import backpack # noqa: F401
from ccxt.pro.bequant import bequant # noqa: F401
from ccxt.pro.binance import binance # noqa: F401
from ccxt.pro.binancecoinm import binancecoinm # noqa: F401
from ccxt.pro.binanceus import binanceus # noqa: F401
from ccxt.pro.binanceusdm import binanceusdm # noqa: F401
from ccxt.pro.bingx import bingx # noqa: F401
from ccxt.pro.bitfinex import bitfinex # noqa: F401
from ccxt.pro.bitget import bitget # noqa: F401
from ccxt.pro.bithumb import bithumb # noqa: F401
from ccxt.pro.bitmart import bitmart # noqa: F401
from ccxt.pro.bitmex import bitmex # noqa: F401
from ccxt.pro.bitopro import bitopro # noqa: F401
from ccxt.pro.bitrue import bitrue # noqa: F401
from ccxt.pro.bitstamp import bitstamp # noqa: F401
from ccxt.pro.bittrade import bittrade # noqa: F401
from ccxt.pro.bitvavo import bitvavo # noqa: F401
from ccxt.pro.blockchaincom import blockchaincom # noqa: F401
from ccxt.pro.blofin import blofin # noqa: F401
from ccxt.pro.bullish import bullish # noqa: F401
from ccxt.pro.bybit import bybit # noqa: F401
from ccxt.pro.bybiteu import bybiteu # noqa: F401
from ccxt.pro.bydfi import bydfi # noqa: F401
from ccxt.pro.cex import cex # noqa: F401
from ccxt.pro.coinbase import coinbase # noqa: F401
from ccxt.pro.coinbaseadvanced import coinbaseadvanced # noqa: F401
from ccxt.pro.coinbaseexchange import coinbaseexchange # noqa: F401
from ccxt.pro.coinbaseinternational import coinbaseinternational # noqa: F401
from ccxt.pro.coincheck import coincheck # noqa: F401
from ccxt.pro.coinex import coinex # noqa: F401
from ccxt.pro.coinone import coinone # noqa: F401
from ccxt.pro.cryptocom import cryptocom # noqa: F401
from ccxt.pro.deepcoin import deepcoin # noqa: F401
from ccxt.pro.deribit import deribit # noqa: F401
from ccxt.pro.derive import derive # noqa: F401
from ccxt.pro.dydx import dydx # noqa: F401
from ccxt.pro.exmo import exmo # noqa: F401
from ccxt.pro.gate import gate # noqa: F401
from ccxt.pro.gateio import gateio # noqa: F401
from ccxt.pro.gemini import gemini # noqa: F401
from ccxt.pro.grvt import grvt # noqa: F401
from ccxt.pro.hashkey import hashkey # noqa: F401
from ccxt.pro.hitbtc import hitbtc # noqa: F401
from ccxt.pro.hollaex import hollaex # noqa: F401
from ccxt.pro.htx import htx # noqa: F401
from ccxt.pro.huobi import huobi # noqa: F401
from ccxt.pro.hyperliquid import hyperliquid # noqa: F401
from ccxt.pro.independentreserve import independentreserve # noqa: F401
from ccxt.pro.kraken import kraken # noqa: F401
from ccxt.pro.krakenfutures import krakenfutures # noqa: F401
from ccxt.pro.kucoin import kucoin # noqa: F401
from ccxt.pro.kucoinfutures import kucoinfutures # noqa: F401
from ccxt.pro.lbank import lbank # noqa: F401
from ccxt.pro.lighter import lighter # noqa: F401
from ccxt.pro.luno import luno # noqa: F401
from ccxt.pro.mexc import mexc # noqa: F401
from ccxt.pro.modetrade import modetrade # noqa: F401
from ccxt.pro.myokx import myokx # noqa: F401
from ccxt.pro.ndax import ndax # noqa: F401
from ccxt.pro.okx import okx # noqa: F401
from ccxt.pro.okxus import okxus # noqa: F401
from ccxt.pro.onetrading import onetrading # noqa: F401
from ccxt.pro.oxfun import oxfun # noqa: F401
from ccxt.pro.p2b import p2b # noqa: F401
from ccxt.pro.pacifica import pacifica # noqa: F401
from ccxt.pro.paradex import paradex # noqa: F401
from ccxt.pro.phemex import phemex # noqa: F401
from ccxt.pro.poloniex import poloniex # noqa: F401
from ccxt.pro.toobit import toobit # noqa: F401
from ccxt.pro.upbit import upbit # noqa: F401
from ccxt.pro.weex import weex # noqa: F401
from ccxt.pro.whitebit import whitebit # noqa: F401
from ccxt.pro.woo import woo # noqa: F401
from ccxt.pro.woofipro import woofipro # noqa: F401
from ccxt.pro.xt import xt # noqa: F401
exchanges = [
'aftermath',
'alpaca',
'apex',
'arkham',
'ascendex',
'aster',
'backpack',
'bequant',
'binance',
'binancecoinm',
'binanceus',
'binanceusdm',
'bingx',
'bitfinex',
'bitget',
'bithumb',
'bitmart',
'bitmex',
'bitopro',
'bitrue',
'bitstamp',
'bittrade',
'bitvavo',
'blockchaincom',
'blofin',
'bullish',
'bybit',
'bybiteu',
'bydfi',
'cex',
'coinbase',
'coinbaseadvanced',
'coinbaseexchange',
'coinbaseinternational',
'coincheck',
'coinex',
'coinone',
'cryptocom',
'deepcoin',
'deribit',
'derive',
'dydx',
'exmo',
'gate',
'gateio',
'gemini',
'grvt',
'hashkey',
'hitbtc',
'hollaex',
'htx',
'huobi',
'hyperliquid',
'independentreserve',
'kraken',
'krakenfutures',
'kucoin',
'kucoinfutures',
'lbank',
'lighter',
'luno',
'mexc',
'modetrade',
'myokx',
'ndax',
'okx',
'okxus',
'onetrading',
'oxfun',
'p2b',
'pacifica',
'paradex',
'phemex',
'poloniex',
'toobit',
'upbit',
'weex',
'whitebit',
'woo',
'woofipro',
'xt',
]

View File

@ -0,0 +1,347 @@
# -*- 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, ArrayCacheBySymbolBySide
from ccxt.base.types import Any, Int, OrderBook, Position, Strings, Trade
from ccxt.async_support.base.ws.client import Client
from typing import List
from ccxt.base.errors import ExchangeError
from ccxt.base.errors import AuthenticationError
class aftermath(ccxt.async_support.aftermath):
def describe(self) -> Any:
return self.deep_extend(super(aftermath, self).describe(), {
'has': {
'ws': True,
'watchBalance': False,
'watchMyTrades': False,
'watchOHLCV': False,
'watchOrderBook': True,
'watchOrders': False,
'watchTicker': False,
'watchTickers': False,
'watchBidsAsks': False,
'watchTrades': True,
'watchTradesForSymbols': False,
'watchPositions': True,
},
'urls': {
'api': {
'ws': {
'swap': 'wss://aftermath.finance/iperps-api/ccxt/stream',
},
},
'test': {
'ws': {
'swap': 'wss://testnet.aftermath.finance/iperps-api/ccxt/stream',
},
},
},
'options': {
'tradesLimit': 1000,
'ordersLimit': 1000,
'watchPositions': {
'fetchPositionsSnapshot': True, # or False
'awaitPositionsSnapshot': True, # whether to wait for the positions snapshot before providing updates
},
},
'streaming': {
'keepAlive': 59000,
},
'exceptions': {
},
})
async def watch_public(self, suffix, messageHash, message):
url = self.urls['api']['ws']['swap'] + '/' + suffix
return await self.watch(url, messageHash, self.json(message), messageHash, message)
async def watch_public_multiple(self, suffix, messageHashes, message):
url = self.urls['api']['ws']['swap'] + '/' + suffix
return await self.watch_multiple(url, messageHashes, self.json(message), messageHashes, message)
async def watch_trades(self, symbol: str, since: Int = None, limit: Int = None, params={}) -> List[Trade]:
"""
watches information on multiple trades made in a market
https://testnet.aftermath.finance/docs/#/CCXT/service%3A%3Ahandlers%3A%3Accxt%3A%3Astream%3A%3Atrades
:param str symbol: unified market symbol of the market trades were made in
:param int [since]: the earliest time in ms to fetch trades for
:param int [limit]: the maximum number of trade structures to retrieve
:param dict [params]: extra parameters specific to the exchange API endpoint
:returns dict[]: a list of `trade structures <https://docs.ccxt.com/?id=trade-structure>`
"""
await self.load_markets()
market = self.market(symbol)
symbol = market['symbol']
topic = market['id'] + '@trade'
request: dict = {
'chId': market['id'],
}
message = self.extend(request, params)
trades = await self.watch_public('trades', topic, message)
if self.newUpdates:
limit = trades.getLimit(market['symbol'], limit)
return self.filter_by_symbol_since_limit(trades, symbol, since, limit, True)
def handle_trade(self, client: Client, message):
#
# {
# "amount": 0.1,
# "cost": 0.1,
# "datetime": "string",
# "fee": null,
# "id": "string",
# "order": "string",
# "price": 0.1,
# "side": null,
# "symbol": "string",
# "takerOrMaker": null,
# "timestamp": null,
# "type": "string"
# }
#
trade = self.parse_trade(message)
symbol = trade['symbol']
market = self.market(symbol)
if not (symbol in self.trades):
limit = self.safe_integer(self.options, 'tradesLimit', 1000)
stored = ArrayCache(limit)
self.trades[symbol] = stored
messageHash = market['id'] + '@trade'
trades = self.trades[symbol]
trades.append(trade)
self.trades[symbol] = trades
client.resolve(trades, messageHash)
async def watch_order_book(self, symbol: str, limit: Int = None, params={}) -> OrderBook:
"""
https://testnet.aftermath.finance/docs/#/CCXT/service%3A%3Ahandlers%3A%3Accxt%3A%3Astream%3A%3Aorderbook
watches information on open orders with bid(buy) and ask(sell) prices, volumes and other data
: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()
market = self.market(symbol)
symbol = market['symbol']
topic = market['id'] + '@orderbook'
request: dict = {
'chId': market['id'],
}
message = self.extend(request, params)
orderbook = await self.watch_public('orderbook', topic, message)
return orderbook.limit()
def handle_order_book(self, client: Client, message):
#
# {
# "asks": [
# []
# ],
# "bids": [
# []
# ],
# "datetime": "string",
# "nonce": 9007199254740991,
# "symbol": "string",
# "timestamp": 9007199254740991
# }
#
symbol = self.safe_string(message, 'symbol')
market = self.market(symbol)
topic = market['id'] + '@orderbook'
if not (symbol in self.orderbooks):
defaultLimit = self.safe_integer(self.options, 'watchOrderBookLimit', 1000)
subscription = client.subscriptions[topic]
limit = self.safe_integer(subscription, 'limit', defaultLimit)
self.orderbooks[symbol] = self.order_book({}, limit)
subscription['limit'] = limit
self.spawn(self.fetch_order_book_snapshot, client, message, subscription)
else:
orderbook = self.orderbooks[symbol]
prevNonce = self.safe_integer(orderbook, 'nonce')
nonce = self.safe_integer(message, 'nonce')
if nonce == (prevNonce + 1):
self.handle_order_book_message(client, message, orderbook)
client.resolve(orderbook, topic)
async def fetch_order_book_snapshot(self, client, message, subscription):
symbol = self.safe_string(message, 'symbol')
market = self.market(symbol)
messageHash = market['id'] + '@orderbook'
try:
defaultLimit = self.safe_integer(self.options, 'watchOrderBookLimit', 1000)
limit = self.safe_integer(subscription, 'limit', defaultLimit)
params = self.safe_dict(subscription, 'params')
snapshot = await self.fetch_rest_order_book_safe(symbol, limit, params)
if self.safe_value(self.orderbooks, symbol) is None:
# if the orderbook is dropped before the snapshot is received
return
orderbook = self.orderbooks[symbol]
orderbook.reset(snapshot)
self.orderbooks[symbol] = orderbook
client.resolve(orderbook, messageHash)
except Exception as e:
del client.subscriptions[messageHash]
client.reject(e, messageHash)
def handle_order_book_message(self, client: Client, message, orderbook):
self.handle_deltas(orderbook['asks'], self.safe_value(message, 'asks', []))
self.handle_deltas(orderbook['bids'], self.safe_value(message, 'bids', []))
timestamp = self.safe_integer(message, 'timestamp')
nonce = self.safe_integer(message, 'nonce')
orderbook['timestamp'] = timestamp
orderbook['datetime'] = self.iso8601(timestamp)
orderbook['nonce'] = nonce
return orderbook
def handle_delta(self, bookside, delta):
price = self.safe_float_2(delta, 'price', 0)
amount = self.safe_float_2(delta, 'quantity', 1)
bookside.store(price, amount)
def handle_deltas(self, bookside, deltas):
for i in range(0, len(deltas)):
self.handle_delta(bookside, deltas[i])
async def watch_positions(self, symbols: Strings = None, since: Int = None, limit: Int = None, params={}) -> List[Position]:
"""
https://testnet.aftermath.finance/docs/#/CCXT/service%3A%3Ahandlers%3A%3Accxt%3A%3Astream%3A%3Apositions
watch all open positions
:param str[]|None symbols: list of unified market symbols
:param int [since]: the earliest time in ms to fetch positions for
:param int [limit]: the maximum number of position structures to retrieve
:param dict params: extra parameters specific to the exchange API endpoint
:param int [params.accountNumber]: account number to query orders for, required
:returns dict[]: a list of `position structure <https://docs.ccxt.com/en/latest/manual.html#position-structure>`
"""
await self.load_markets()
messageHashes = []
symbols = self.market_symbols(symbols)
if not self.is_empty(symbols):
for i in range(0, len(symbols)):
symbol = symbols[i]
messageHashes.append('positions::' + symbol)
else:
messageHashes.append('positions')
accountNumber = self.safe_number(params, 'accountNumber')
request = {
'accountNumber': accountNumber,
}
message = self.extend(request, params)
suffix = 'positions'
url = self.urls['api']['ws']['swap'] + '/' + suffix
client = self.client(url)
self.set_positions_cache(client, symbols, params)
fetchPositionsSnapshot = self.handle_option('watchPositions', 'fetchPositionsSnapshot', True)
awaitPositionsSnapshot = self.handle_option('watchPositions', 'awaitPositionsSnapshot', True)
if fetchPositionsSnapshot and awaitPositionsSnapshot and self.positions is None:
snapshot = await client.future('fetchPositionsSnapshot')
return self.filter_by_symbols_since_limit(snapshot, symbols, since, limit, True)
newPositions = await self.watch_public_multiple(suffix, messageHashes, message)
if self.newUpdates:
return newPositions
return self.filter_by_symbols_since_limit(self.positions, symbols, since, limit, True)
def set_positions_cache(self, client: Client, symbols: Strings = None, params: dict = {}):
fetchPositionsSnapshot = self.handle_option('watchPositions', 'fetchPositionsSnapshot', False)
if fetchPositionsSnapshot:
messageHash = 'fetchPositionsSnapshot'
if not (messageHash in client.futures):
client.future(messageHash)
self.spawn(self.load_positions_snapshot, client, messageHash, symbols, params)
else:
self.positions = ArrayCacheBySymbolBySide()
async def load_positions_snapshot(self, client, messageHash, symbols, params):
positions = await self.fetch_positions(symbols, params)
self.positions = ArrayCacheBySymbolBySide()
cache = self.positions
for i in range(0, len(positions)):
position = positions[i]
cache.append(position)
# don't remove the future from the .futures cache
future = client.futures[messageHash]
future.resolve(cache)
client.resolve(cache, 'positions')
def handle_positions(self, client, message):
#
# {
# "collateral": 0.1,
# "contractSize": 0.1,
# "contracts": 0.1,
# "datetime": "string",
# "entryPrice": 0.1,
# "id": "0x895037c09dd1025a136b5a5789c4ea2481176adf4c3b0c3521d5d2039bdfc3ba:123",
# "initialMargin": 0.1,
# "initialMarginPercentage": 0.1,
# "leverage": 0.1,
# "liquidationPrice": 0.1,
# "maintenanceMargin": 0.1,
# "maintenanceMarginPercentage": 0.1,
# "marginMode": "cross",
# "marginRatio": 0.1,
# "notional": 0.1,
# "side": "long",
# "symbol": "BTC/USD:USDC",
# "timestamp": 9007199254740991,
# "unrealizedPnl": 0.1
# }
#
if self.positions is None:
self.positions = ArrayCacheBySymbolBySide()
cache = self.positions
symbol = self.safe_string(message, 'symbol')
market = self.safe_market(symbol)
position = self.parse_position(message, market)
cache.append(position)
messageHash = 'positions::' + market['symbol']
client.resolve(position, messageHash)
client.resolve([position], 'positions')
def handle_error_message(self, client: Client, message):
#
# User error: Expected Message::Text from client, got Ping(b\"\")
#
if isinstance(message, str):
if message.find('error') >= 0:
try:
feedback = self.id + ' ' + message
self.throw_exactly_matched_exception(self.exceptions['exact'], message, feedback)
raise ExchangeError(message)
except Exception as error:
if isinstance(error, AuthenticationError):
messageHash = 'authenticated'
client.reject(error, messageHash)
if messageHash in client.subscriptions:
del client.subscriptions[messageHash]
else:
client.reject(error)
return True
return False
def handle_message(self, client: Client, message):
if self.handle_error_message(client, message):
return
# methods: Dict = {
# 'trade': self.handle_trade,
# }
if 'asks' in message:
self.handle_order_book(client, message)
elif 'notional' in message:
self.handle_positions(client, message)
else:
self.handle_trade(client, message)

View File

@ -0,0 +1,716 @@
# -*- 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, ArrayCacheBySymbolById, ArrayCacheByTimestamp
from ccxt.base.types import Any, Bool, Int, Order, OrderBook, Str, Ticker, Trade
from ccxt.async_support.base.ws.client import Client
from typing import List
from ccxt.base.errors import ExchangeError
from ccxt.base.errors import AuthenticationError
class alpaca(ccxt.async_support.alpaca):
def describe(self) -> Any:
return self.deep_extend(super(alpaca, self).describe(), {
'has': {
'ws': True,
'createOrderWithTakeProfitAndStopLossWs': False,
'createReduceOnlyOrderWs': False,
'createStopLossOrderWs': False,
'createTakeProfitOrderWs': False,
'fetchPositionForSymbolWs': False,
'fetchPositionsForSymbolWs': False,
'fetchPositionsWs': False,
'fetchPositionWs': False,
'unWatchPositions': False,
'watchBalance': False,
'watchLiquidations': False,
'watchLiquidationsForSymbols': False,
'watchMarkPrice': False,
'watchMarkPrices': False,
'watchMyLiquidations': False,
'watchMyLiquidationsForSymbols': False,
'watchMyTrades': True,
'watchOHLCV': True,
'watchOrderBook': True,
'watchOrders': True,
'watchPosition': False,
'watchPositions': False,
'watchTicker': True,
'watchTickers': False, # for now
'watchTrades': True,
},
'urls': {
'api': {
'ws': {
'crypto': 'wss://stream.data.alpaca.markets/v1beta2/crypto',
'trading': 'wss://api.alpaca.markets/stream',
},
},
'test': {
'ws': {
'crypto': 'wss://stream.data.alpaca.markets/v1beta2/crypto',
'trading': 'wss://paper-api.alpaca.markets/stream',
},
},
},
'options': {
},
'streaming': {},
'exceptions': {
'ws': {
'exact': {
},
},
},
})
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://docs.alpaca.markets/docs/real-time-crypto-pricing-data#quotes
: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>`
"""
url = self.urls['api']['ws']['crypto']
await self.authenticate(url)
await self.load_markets()
market = self.market(symbol)
messageHash = 'ticker:' + market['symbol']
request: dict = {
'action': 'subscribe',
'quotes': [market['id']],
}
return await self.watch(url, messageHash, self.extend(request, params), messageHash)
def handle_ticker(self, client: Client, message):
#
# {
# "T": "q",
# "S": "BTC/USDT",
# "bp": 17394.44,
# "bs": 0.021981,
# "ap": 17397.99,
# "as": 0.02,
# "t": "2022-12-16T06:07:56.611063286Z"
# ]
#
ticker = self.parse_ticker(message)
symbol = ticker['symbol']
messageHash = 'ticker:' + symbol
self.tickers[symbol] = ticker
client.resolve(self.tickers[symbol], messageHash)
def parse_ticker(self, ticker, market=None) -> Ticker:
#
# {
# "T": "q",
# "S": "BTC/USDT",
# "bp": 17394.44,
# "bs": 0.021981,
# "ap": 17397.99,
# "as": 0.02,
# "t": "2022-12-16T06:07:56.611063286Z"
# }
#
marketId = self.safe_string(ticker, 'S')
datetime = self.safe_string(ticker, 't')
return self.safe_ticker({
'symbol': self.safe_symbol(marketId, market),
'timestamp': self.parse8601(datetime),
'datetime': datetime,
'high': None,
'low': None,
'bid': self.safe_string(ticker, 'bp'),
'bidVolume': self.safe_string(ticker, 'bs'),
'ask': self.safe_string(ticker, 'ap'),
'askVolume': self.safe_string(ticker, 'as'),
'vwap': None,
'open': None,
'close': None,
'last': None,
'previousClose': None,
'change': None,
'percentage': None,
'average': None,
'baseVolume': None,
'quoteVolume': None,
'info': ticker,
}, market)
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://docs.alpaca.markets/docs/real-time-crypto-pricing-data#bars
: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
"""
url = self.urls['api']['ws']['crypto']
await self.authenticate(url)
await self.load_markets()
market = self.market(symbol)
symbol = market['symbol']
request: dict = {
'action': 'subscribe',
'bars': [market['id']],
}
messageHash = 'ohlcv:' + symbol
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)
def handle_ohlcv(self, client: Client, message):
#
# {
# "T": "b",
# "S": "BTC/USDT",
# "o": 17416.39,
# "h": 17424.82,
# "l": 17416.39,
# "c": 17424.82,
# "v": 1.341054,
# "t": "2022-12-16T06:53:00Z",
# "n": 21,
# "vw": 17421.9529234915
# }
#
marketId = self.safe_string(message, 'S')
symbol = self.safe_symbol(marketId)
stored = self.safe_value(self.ohlcvs, symbol)
if stored is None:
limit = self.safe_integer(self.options, 'OHLCVLimit', 1000)
stored = ArrayCacheByTimestamp(limit)
self.ohlcvs[symbol] = stored
parsed = self.parse_ohlcv(message)
stored.append(parsed)
messageHash = 'ohlcv:' + symbol
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://docs.alpaca.markets/docs/real-time-crypto-pricing-data#orderbooks
: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
"""
url = self.urls['api']['ws']['crypto']
await self.authenticate(url)
await self.load_markets()
market = self.market(symbol)
symbol = market['symbol']
messageHash = 'orderbook' + ':' + symbol
request: dict = {
'action': 'subscribe',
'orderbooks': [market['id']],
}
orderbook = await self.watch(url, messageHash, self.extend(request, params), messageHash)
return orderbook.limit()
def handle_order_book(self, client: Client, message):
#
# snapshot
# {
# "T": "o",
# "S": "BTC/USDT",
# "t": "2022-12-16T06:35:31.585113205Z",
# "b": [{
# "p": 17394.37,
# "s": 0.015499,
# },
# ...
# ],
# "a": [{
# "p": 17398.8,
# "s": 0.042919,
# },
# ...
# ],
# "r": True,
# }
#
marketId = self.safe_string(message, 'S')
symbol = self.safe_symbol(marketId)
datetime = self.safe_string(message, 't')
timestamp = self.parse8601(datetime)
isSnapshot = self.safe_bool(message, 'r', False)
if not (symbol in self.orderbooks):
self.orderbooks[symbol] = self.order_book()
orderbook = self.orderbooks[symbol]
if isSnapshot:
snapshot = self.parse_order_book(message, symbol, timestamp, 'b', 'a', 'p', 's')
orderbook.reset(snapshot)
else:
asks = self.safe_list(message, 'a', [])
bids = self.safe_list(message, 'b', [])
self.handle_deltas(orderbook['asks'], asks)
self.handle_deltas(orderbook['bids'], bids)
orderbook['timestamp'] = timestamp
orderbook['datetime'] = datetime
messageHash = 'orderbook' + ':' + symbol
self.orderbooks[symbol] = orderbook
client.resolve(orderbook, messageHash)
def handle_delta(self, bookside, delta):
bidAsk = self.parse_bid_ask(delta, 'p', 's')
bookside.storeArray(bidAsk)
def handle_deltas(self, bookside, deltas):
for i in range(0, len(deltas)):
self.handle_delta(bookside, deltas[i])
async def watch_trades(self, symbol: str, since: Int = None, limit: Int = None, params={}) -> List[Trade]:
"""
watches information on multiple trades made in a market
https://docs.alpaca.markets/docs/real-time-crypto-pricing-data#trades
:param str symbol: unified market symbol of the market trades were made in
:param int [since]: the earliest time in ms to fetch orders for
:param int [limit]: the maximum number of trade structures to retrieve
:param dict [params]: extra parameters specific to the exchange API endpoint
:returns dict[]: a list of `trade structures <https://docs.ccxt.com/?id=trade-structure>`
"""
url = self.urls['api']['ws']['crypto']
await self.authenticate(url)
await self.load_markets()
market = self.market(symbol)
symbol = market['symbol']
messageHash = 'trade:' + symbol
request: dict = {
'action': 'subscribe',
'trades': [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)
def handle_trades(self, client: Client, message):
#
# {
# "T": "t",
# "S": "BTC/USDT",
# "p": 17408.8,
# "s": 0.042919,
# "t": "2022-12-16T06:43:18.327Z",
# "i": 16585162,
# "tks": "B"
# ]
#
marketId = self.safe_string(message, 'S')
symbol = self.safe_symbol(marketId)
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
parsed = self.parse_trade(message)
stored.append(parsed)
messageHash = 'trade' + ':' + symbol
client.resolve(stored, messageHash)
async def watch_my_trades(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}) -> List[Trade]:
"""
watches information on multiple trades made by the user
https://docs.alpaca.markets/docs/websocket-streaming#trade-updates
:param str symbol: unified market symbol of the market trades were made in
:param int [since]: the earliest time in ms to fetch trades for
:param int [limit]: the maximum number of trade structures to retrieve
:param dict [params]: extra parameters specific to the exchange API endpoint
:param boolean [params.unifiedMargin]: use unified margin account
:returns dict[]: a list of `trade structures <https://docs.ccxt.com/?id=trade-structure>`
"""
url = self.urls['api']['ws']['trading']
await self.authenticate(url)
messageHash = 'myTrades'
await self.load_markets()
if symbol is not None:
symbol = self.symbol(symbol)
messageHash += ':' + symbol
request: dict = {
'action': 'listen',
'data': {
'streams': ['trade_updates'],
},
}
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 watch_orders(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}) -> List[Order]:
"""
watches information on multiple orders made by the user
:param str symbol: unified market symbol of the market orders were made in
:param int [since]: the earliest time in ms to fetch orders for
:param int [limit]: the maximum number of order structures to retrieve
:param dict [params]: extra parameters specific to the exchange API endpoint
:returns dict[]: a list of `order structures <https://docs.ccxt.com/?id=order-structure>`
"""
url = self.urls['api']['ws']['trading']
await self.authenticate(url)
await self.load_markets()
messageHash = 'orders'
if symbol is not None:
market = self.market(symbol)
symbol = market['symbol']
messageHash = 'orders:' + symbol
request: dict = {
'action': 'listen',
'data': {
'streams': ['trade_updates'],
},
}
orders = await self.watch(url, messageHash, self.extend(request, params), messageHash)
if self.newUpdates:
limit = orders.getLimit(symbol, limit)
return self.filter_by_symbol_since_limit(orders, symbol, since, limit, True)
def handle_trade_update(self, client: Client, message):
self.handle_order(client, message)
self.handle_my_trade(client, message)
def handle_order(self, client: Client, message):
#
# {
# "stream": "trade_updates",
# "data": {
# "event": "new",
# "timestamp": "2022-12-16T07:28:51.67621869Z",
# "order": {
# "id": "c2470331-8993-4051-bf5d-428d5bdc9a48",
# "client_order_id": "0f1f3764-107a-4d09-8b9a-d75a11738f5c",
# "created_at": "2022-12-16T02:28:51.673531798-05:00",
# "updated_at": "2022-12-16T02:28:51.678736847-05:00",
# "submitted_at": "2022-12-16T02:28:51.673015558-05:00",
# "filled_at": null,
# "expired_at": null,
# "cancel_requested_at": null,
# "canceled_at": null,
# "failed_at": null,
# "replaced_at": null,
# "replaced_by": null,
# "replaces": null,
# "asset_id": "276e2673-764b-4ab6-a611-caf665ca6340",
# "symbol": "BTC/USD",
# "asset_class": "crypto",
# "notional": null,
# "qty": "0.01",
# "filled_qty": "0",
# "filled_avg_price": null,
# "order_class": '',
# "order_type": "market",
# "type": "market",
# "side": "buy",
# "time_in_force": "gtc",
# "limit_price": null,
# "stop_price": null,
# "status": "new",
# "extended_hours": False,
# "legs": null,
# "trail_percent": null,
# "trail_price": null,
# "hwm": null
# },
# "execution_id": "5f781a30-b9a3-4c86-b466-2175850cf340"
# }
# }
#
data = self.safe_value(message, 'data', {})
rawOrder = self.safe_value(data, 'order', {})
if self.orders is None:
limit = self.safe_integer(self.options, 'ordersLimit', 1000)
self.orders = ArrayCacheBySymbolById(limit)
orders = self.orders
order = self.parse_order(rawOrder)
orders.append(order)
messageHash = 'orders'
client.resolve(orders, messageHash)
messageHash = 'orders:' + order['symbol']
client.resolve(orders, messageHash)
def handle_my_trade(self, client: Client, message):
#
# {
# "stream": "trade_updates",
# "data": {
# "event": "new",
# "timestamp": "2022-12-16T07:28:51.67621869Z",
# "order": {
# "id": "c2470331-8993-4051-bf5d-428d5bdc9a48",
# "client_order_id": "0f1f3764-107a-4d09-8b9a-d75a11738f5c",
# "created_at": "2022-12-16T02:28:51.673531798-05:00",
# "updated_at": "2022-12-16T02:28:51.678736847-05:00",
# "submitted_at": "2022-12-16T02:28:51.673015558-05:00",
# "filled_at": null,
# "expired_at": null,
# "cancel_requested_at": null,
# "canceled_at": null,
# "failed_at": null,
# "replaced_at": null,
# "replaced_by": null,
# "replaces": null,
# "asset_id": "276e2673-764b-4ab6-a611-caf665ca6340",
# "symbol": "BTC/USD",
# "asset_class": "crypto",
# "notional": null,
# "qty": "0.01",
# "filled_qty": "0",
# "filled_avg_price": null,
# "order_class": '',
# "order_type": "market",
# "type": "market",
# "side": "buy",
# "time_in_force": "gtc",
# "limit_price": null,
# "stop_price": null,
# "status": "new",
# "extended_hours": False,
# "legs": null,
# "trail_percent": null,
# "trail_price": null,
# "hwm": null
# },
# "execution_id": "5f781a30-b9a3-4c86-b466-2175850cf340"
# }
# }
#
data = self.safe_value(message, 'data', {})
event = self.safe_string(data, 'event')
if event != 'fill' and event != 'partial_fill':
return
rawOrder = self.safe_value(data, 'order', {})
myTrades = self.myTrades
if myTrades is None:
limit = self.safe_integer(self.options, 'tradesLimit', 1000)
myTrades = ArrayCacheBySymbolById(limit)
trade = self.parse_my_trade(rawOrder)
myTrades.append(trade)
messageHash = 'myTrades:' + trade['symbol']
client.resolve(myTrades, messageHash)
messageHash = 'myTrades'
client.resolve(myTrades, messageHash)
def parse_my_trade(self, trade, market=None):
#
# {
# "id": "c2470331-8993-4051-bf5d-428d5bdc9a48",
# "client_order_id": "0f1f3764-107a-4d09-8b9a-d75a11738f5c",
# "created_at": "2022-12-16T02:28:51.673531798-05:00",
# "updated_at": "2022-12-16T02:28:51.678736847-05:00",
# "submitted_at": "2022-12-16T02:28:51.673015558-05:00",
# "filled_at": null,
# "expired_at": null,
# "cancel_requested_at": null,
# "canceled_at": null,
# "failed_at": null,
# "replaced_at": null,
# "replaced_by": null,
# "replaces": null,
# "asset_id": "276e2673-764b-4ab6-a611-caf665ca6340",
# "symbol": "BTC/USD",
# "asset_class": "crypto",
# "notional": null,
# "qty": "0.01",
# "filled_qty": "0",
# "filled_avg_price": null,
# "order_class": '',
# "order_type": "market",
# "type": "market",
# "side": "buy",
# "time_in_force": "gtc",
# "limit_price": null,
# "stop_price": null,
# "status": "new",
# "extended_hours": False,
# "legs": null,
# "trail_percent": null,
# "trail_price": null,
# "hwm": null
# }
#
marketId = self.safe_string(trade, 'symbol')
datetime = self.safe_string(trade, 'filled_at')
type = self.safe_string(trade, 'type')
if type.find('limit') >= 0:
# might be limit or stop-limit
type = 'limit'
return self.safe_trade({
'id': self.safe_string(trade, 'i'),
'info': trade,
'timestamp': self.parse8601(datetime),
'datetime': datetime,
'symbol': self.safe_symbol(marketId, None, '/'),
'order': self.safe_string(trade, 'id'),
'type': type,
'side': self.safe_string(trade, 'side'),
'takerOrMaker': 'taker' if (type == 'market') else 'maker',
'price': self.safe_string(trade, 'filled_avg_price'),
'amount': self.safe_string(trade, 'filled_qty'),
'cost': None,
'fee': None,
}, market)
async def authenticate(self, url, params={}):
self.check_required_credentials()
messageHash = 'authenticated'
client = self.client(url)
future = client.reusableFuture(messageHash)
authenticated = self.safe_value(client.subscriptions, messageHash)
if authenticated is None:
request = {
'action': 'auth',
'key': self.apiKey,
'secret': self.secret,
}
if url == self.urls['api']['ws']['trading']:
# self auth request is being deprecated in test environment
request = {
'action': 'authenticate',
'data': {
'key_id': self.apiKey,
'secret_key': self.secret,
},
}
self.watch(url, messageHash, request, messageHash, future)
return await future
def handle_error_message(self, client: Client, message) -> Bool:
#
# {
# "T": "error",
# "code": 400,
# "msg": "invalid syntax"
# }
#
code = self.safe_string(message, 'code')
msg = self.safe_value(message, 'msg', {})
raise ExchangeError(self.id + ' code: ' + code + ' message: ' + msg)
def handle_connected(self, client: Client, message):
#
# {
# "T": "success",
# "msg": "connected"
# }
#
return message
def handle_crypto_message(self, client: Client, message):
for i in range(0, len(message)):
data = message[i]
T = self.safe_string(data, 'T')
msg = self.safe_string(data, 'msg')
if T == 'subscription':
self.handle_subscription(client, data)
return
if T == 'success' and msg == 'connected':
self.handle_connected(client, data)
return
if T == 'success' and msg == 'authenticated':
self.handle_authenticate(client, data)
return
methods: dict = {
'error': self.handle_error_message,
'b': self.handle_ohlcv,
'q': self.handle_ticker,
't': self.handle_trades,
'o': self.handle_order_book,
}
method = self.safe_value(methods, T)
if method is not None:
method(client, data)
def handle_trading_message(self, client: Client, message):
stream = self.safe_string(message, 'stream')
methods: dict = {
'authorization': self.handle_authenticate,
'listening': self.handle_subscription,
'trade_updates': self.handle_trade_update,
}
method = self.safe_value(methods, stream)
if method is not None:
method(client, message)
def handle_message(self, client: Client, message):
if isinstance(message, list):
self.handle_crypto_message(client, message)
return
self.handle_trading_message(client, message)
def handle_authenticate(self, client: Client, message):
#
# crypto
# {
# "T": "success",
# "msg": "connected"
# ]
#
# trading
# {
# "stream": "authorization",
# "data": {
# "status": "authorized",
# "action": "authenticate"
# }
# }
# error
# {
# "stream": "authorization",
# "data": {
# "action": "authenticate",
# "message": "access key verification failed",
# "status": "unauthorized"
# }
# }
#
T = self.safe_string(message, 'T')
data = self.safe_value(message, 'data', {})
status = self.safe_string(data, 'status')
if T == 'success' or status == 'authorized':
promise = client.futures['authenticated']
promise.resolve(message)
return
raise AuthenticationError(self.id + ' failed to authenticate.')
def handle_subscription(self, client: Client, message):
#
# crypto
# {
# "T": "subscription",
# "trades": [],
# "quotes": ["BTC/USDT"],
# "orderbooks": [],
# "bars": [],
# "updatedBars": [],
# "dailyBars": []
# }
# trading
# {
# "stream": "listening",
# "data": {
# "streams": ["trade_updates"]
# }
# }
#
return message

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,686 @@
# -*- 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, ArrayCacheBySymbolById, ArrayCacheBySymbolBySide, ArrayCacheByTimestamp
import hashlib
from ccxt.base.types import Any, Balances, Bool, Int, Order, OrderBook, Position, Str, Strings, Ticker, Trade
from ccxt.async_support.base.ws.client import Client
from typing import List
from ccxt.base.errors import ExchangeError
class arkham(ccxt.async_support.arkham):
def describe(self) -> Any:
return self.deep_extend(super(arkham, self).describe(), {
'has': {
'ws': True,
'watchTrades': True,
'watchTradesForSymbols': False,
'watchOrderBook': True,
'watchOrderBookForSymbols': False,
'watchOHLCV': True,
'watchOHLCVForSymbols': False,
'watchOrders': True,
'watchMyTrades': False,
'watchTicker': True,
'watchTickers': False,
'watchBalance': True,
},
'urls': {
'api': {
'ws': 'wss://arkm.com/ws',
},
},
'options': {
'watchOrderBook': {
'depth': 100, # 5, 10, 20, 50, 100
'interval': 500, # 100, 200, 500, 1000
},
},
'streaming': {
'keepAlive': 300000, # 5 minutes
},
})
def handle_message(self, client: Client, message):
#
# confirmation
#
# {channel: 'confirmations', confirmationId: 'myCustomId-123'}
if self.handle_error_message(client, message):
return
methods: dict = {
'ticker': self.handle_ticker,
'candles': self.handle_ohlcv,
'l2_updates': self.handle_order_book,
'trades': self.handle_trades,
'balances': self.handle_balance,
'positions': self.handle_positions,
'order_statuses': self.handle_order,
'trigger_orders': self.handle_order,
# 'confirmations': self.handle_ticker,
}
channel = self.safe_string(message, 'channel')
if channel == 'confirmations':
return
# type = self.safe_string(message, 'type')
# if type != 'update' and type != 'snapshot':
# debugger
# }
method = self.safe_value(methods, channel)
if method is not None:
method(client, message)
async def subscribe(self, messageHash: str, rawChannel: str, params: dict) -> Any:
subscriptionHash = messageHash
request: dict = {
'args': {
'channel': rawChannel,
'params': params,
},
'confirmationId': self.uuid(),
'method': 'subscribe',
}
return await self.watch(self.urls['api']['ws'], messageHash, request, subscriptionHash)
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://arkm.com/docs#stream/ticker
: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>`
"""
await self.load_markets()
market = self.market(symbol)
requestArg = {
'symbol': market['id'],
}
messageHash = 'ticker::' + market['symbol']
return await self.subscribe(messageHash, 'ticker', self.extend(params, requestArg))
def handle_ticker(self, client: Client, message):
#
# {
# channel: 'ticker',
# type: 'update',
# data: {
# symbol: 'BTC_USDT',
# baseSymbol: 'BTC',
# quoteSymbol: 'USDT',
# price: '118962.74',
# price24hAgo: '118780.42',
# high24h: '120327.96',
# low24h: '118217.28',
# volume24h: '32.89729',
# quoteVolume24h: '3924438.7146048',
# markPrice: '0',
# indexPrice: '118963.080293502',
# fundingRate: '0',
# nextFundingRate: '0',
# nextFundingTime: 0,
# productType: 'spot',
# openInterest: '0',
# indexCurrency: 'USDT',
# usdVolume24h: '3924438.7146048',
# openInterestUSD: '0'
# }
# }
#
data = self.safe_dict(message, 'data', {})
marketId = self.safe_string(data, 'symbol')
market = self.safe_market(marketId, None)
symbol = market['symbol']
ticker = self.parse_ws_ticker(data, market)
self.tickers[symbol] = ticker
client.resolve(ticker, 'ticker::' + symbol)
# if self.safe_string(message, 'dataType') == 'all@ticker':
# client.resolve(ticker, self.getMessageHash('ticker'))
# }
def parse_ws_ticker(self, message, market=None):
# same dict api
return self.parse_ticker(message, market)
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://arkm.com/docs#stream/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()
market = self.market(symbol)
rawTimeframe = self.safe_string(self.timeframes, timeframe, timeframe)
requestArg = {
'symbol': market['id'],
'duration': rawTimeframe,
}
messageHash = 'ohlcv::' + market['symbol'] + '::' + rawTimeframe
result = await self.subscribe(messageHash, 'candles', self.extend(requestArg, params))
ohlcv = result
if self.newUpdates:
limit = ohlcv.getLimit(market['symbol'], limit)
return self.filter_by_since_limit(ohlcv, since, limit, 0, True)
def handle_ohlcv(self, client: Client, message):
#
# {
# channel: 'candles',
# type: 'update',
# data: {
# symbol: 'BTC_USDT',
# time: '1755076380000000',
# duration: 60000000,
# open: '120073.01',
# high: '120073.01',
# low: '120073.01',
# close: '120073.01',
# volume: '0',
# quoteVolume: '0'
# }
# }
#
data = self.safe_dict(message, 'data', {})
marketId = self.safe_string(data, 'symbol')
market = self.safe_market(marketId, None)
symbol = market['symbol']
duration = self.safe_integer(data, 'duration')
timeframe = self.findTimeframeByDuration(duration)
messageHash = 'ohlcv::' + symbol + '::' + timeframe
self.ohlcvs[symbol] = self.safe_value(self.ohlcvs, symbol, {})
if not (timeframe in self.ohlcvs[symbol]):
limit = self.handle_option('watchOHLCV', 'limit', 1000)
self.ohlcvs[symbol][timeframe] = ArrayCacheByTimestamp(limit)
stored = self.ohlcvs[symbol][timeframe]
parsed = self.parse_ws_ohlcv(data, market)
stored.append(parsed)
client.resolve(stored, messageHash)
return message
def parse_ws_ohlcv(self, ohlcv, market=None) -> list:
# same api
return self.parse_ohlcv(ohlcv, 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://arkm.com/docs#stream/l2_updates
: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()
market = self.market(symbol)
requestArg = {
'symbol': market['id'],
'snapshot': True,
}
messageHash = 'orderBook::' + market['symbol']
orderbook = await self.subscribe(messageHash, 'l2_updates', self.extend(requestArg, params))
return orderbook.limit()
def handle_order_book(self, client: Client, message):
#
# snapshot:
#
# {
# channel: 'l2_updates',
# type: 'snapshot',
# data: {
# symbol: 'BTC_USDT',
# group: '0.01',
# asks: [ [Object], [Object], ...],
# bids: [ [Object], [Object], ...],
# lastTime: 1755115180608299
# }
# }
#
# update:
#
# {
# channel: "l2_updates",
# type: "update",
# data: {
# symbol: "BTC_USDT",
# group: "0.01",
# side: "sell",
# size: "0.05295",
# price: "122722.76",
# revisionId: 2455511217,
# time: 1755115736475207,
# }
# }
#
data = self.safe_dict(message, 'data')
type = self.safe_string(message, 'type')
marketId = self.safe_string(data, 'symbol')
market = self.safe_market(marketId)
symbol = market['symbol']
messageHash = 'orderBook::' + symbol
if not (symbol in self.orderbooks):
ob = self.order_book({})
ob['symbol'] = symbol
self.orderbooks[symbol] = ob
orderbook = self.orderbooks[symbol]
if type == 'snapshot':
timestamp = self.safe_integer_product(data, 'lastTime', 0.001)
parsedOrderBook = self.parse_order_book(data, symbol, timestamp, 'bids', 'asks', 'price', 'size')
orderbook.reset(parsedOrderBook)
elif type == 'update':
timestamp = self.safe_integer_product(data, 'time', 0.001)
side = self.safe_string(data, 'side')
bookside = orderbook['bids'] if (side == 'buy') else orderbook['asks']
self.handle_delta(bookside, data)
orderbook['timestamp'] = timestamp
orderbook['datetime'] = self.iso8601(timestamp)
self.orderbooks[symbol] = orderbook
client.resolve(self.orderbooks[symbol], messageHash)
def handle_delta(self, bookside, delta):
bidAsk = self.parse_bid_ask(delta, 'price', 'size')
bookside.storeArray(bidAsk)
async def watch_trades(self, symbol: str, since: Int = None, limit: Int = None, params={}) -> List[Trade]:
"""
watches information on multiple trades made in a market
https://arkm.com/docs#stream/trades
:param str symbol: unified market symbol of the market trades were made in
:param int [since]: the earliest time in ms to fetch orders for
:param int [limit]: the maximum number of trade structures to retrieve
:param dict [params]: extra parameters specific to the exchange API endpoint
:returns dict[]: a list of `trade structures <https://docs.ccxt.com/?id=trade-structure>`
"""
await self.load_markets()
market = self.market(symbol)
requestArg = {
'symbol': market['id'],
}
messageHash = 'trade::' + market['symbol']
trades = await self.subscribe(messageHash, 'trades', self.extend(requestArg, params))
if self.newUpdates:
limit = trades.getLimit(market['symbol'], limit)
return self.filter_by_since_limit(trades, since, limit, 'timestamp', True)
def handle_trades(self, client: Client, message):
#
# {
# channel: 'trades',
# type: 'update',
# data: {
# symbol: 'BTC_USDT',
# revisionId: 2643896903,
# size: '0.00261',
# price: '118273.2',
# takerSide: 'buy',
# time: 1755200320146389
# }
# }
#
data = self.safe_dict(message, 'data')
marketId = self.safe_string(data, 'symbol')
symbol = self.safe_symbol(marketId)
if not (symbol in self.trades):
limit = self.safe_integer(self.options, 'tradesLimit', 1000)
self.trades[symbol] = ArrayCache(limit)
parsed = self.parse_ws_trade(data)
stored = self.trades[symbol]
stored.append(parsed)
client.resolve(stored, 'trade::' + symbol)
def parse_ws_trade(self, trade, market=None):
# same api
return self.parse_trade(trade, market)
async def authenticate(self, params={}):
self.check_required_credentials()
expires = (self.milliseconds() + self.safe_integer(self.options, 'requestExpiration', 5000)) * 1000 # need macroseconds
wsOptions: dict = self.safe_dict(self.options, 'ws', {})
authenticated = self.safe_string(wsOptions, 'token')
if authenticated is None:
method = 'GET'
bodyStr = ''
path = 'ws'
payload = self.apiKey + str(expires) + method.upper() + '/' + path + bodyStr
decodedSecret = self.base64_to_binary(self.secret)
signature = self.hmac(self.encode(payload), decodedSecret, hashlib.sha256, 'base64')
defaultOptions: dict = {
'ws': {
'options': {
'headers': {
'Content-Type': 'application/json',
'Accept': 'application/json',
'Arkham-Api-Key': self.apiKey,
'Arkham-Expires': str(expires),
'Arkham-Signature': signature,
},
},
},
}
self.extend_exchange_options(defaultOptions)
self.client(self.urls['api']['ws'])
async def watch_balance(self, params={}) -> Balances:
"""
watch balance and get the amount of funds available for trading or funds locked in orders
https://arkm.com/docs#stream/balances
:param dict [params]: extra parameters specific to the exchange API endpoint
:param str [params.type]: spot or contract if not provided self.options['defaultType'] is used
:returns dict: a `balance structure <https://docs.ccxt.com/?id=balance-structure>`
"""
await self.authenticate()
await self.load_markets()
requestArg = {
'snapshot': True,
}
messageHash = 'balances'
result = await self.subscribe(messageHash, 'balances', self.extend(requestArg, params))
return result
def handle_balance(self, client: Client, message):
#
# snapshot:
#
# {
# channel: 'balances',
# type: 'snapshot',
# data: [
# {
# subaccountId: 0,
# symbol: 'USDT',
# balance: '7.035335375',
# free: '7.035335375',
# priceUSDT: '1',
# balanceUSDT: '7.035335375',
# freeUSDT: '7.035335375',
# lastUpdateReason: 'withdrawalFee',
# lastUpdateTime: '1753905990432678',
# lastUpdateId: 250483404,
# lastUpdateAmount: '-2'
# },
# {
# subaccountId: 0,
# symbol: 'SOL',
# balance: '0.03',
# free: '0.03',
# priceUSDT: '197.37823276',
# balanceUSDT: '5.921346982',
# freeUSDT: '5.921346982',
# lastUpdateReason: 'orderFill',
# lastUpdateTime: '1753777760560164',
# lastUpdateId: 248588190,
# lastUpdateAmount: '0.03'
# }
# ]
# }
#
# update:
#
# {
# channel: 'balances',
# type: 'update',
# data: {
# subaccountId: 0,
# symbol: 'USDT',
# balance: '7.028357615',
# free: '7.028357615',
# priceUSDT: '1',
# balanceUSDT: '7.028357615',
# freeUSDT: '7.028357615',
# lastUpdateReason: 'tradingFee',
# lastUpdateTime: '1755240882544056',
# lastUpdateId: 2697860787,
# lastUpdateAmount: '-0.00697776'
# }
# }
#
type = self.safe_string(message, 'type')
parsed = {}
if type == 'snapshot':
# response same api
data = self.safe_list(message, 'data')
parsed = self.parse_ws_balance(data)
parsed['info'] = message
self.balance = parsed
else:
data = self.safe_dict(message, 'data')
balancesArray = [data]
parsed = self.parse_ws_balance(balancesArray)
currencyId = self.safe_string(data, 'symbol')
code = self.safe_currency_code(currencyId)
self.balance[code] = parsed[code]
messageHash = 'balances'
client.resolve(self.safe_balance(self.balance), messageHash)
def parse_ws_balance(self, balance):
# same api
return self.parse_balance(balance)
async def watch_positions(self, symbols: Strings = None, since: Int = None, limit: Int = None, params={}) -> List[Position]:
"""
https://arkm.com/docs#stream/positions
watch all open positions
:param str[] [symbols]: list of unified market symbols
:param int [since]: the earliest time in ms to fetch positions for
:param int [limit]: the maximum number of positions to retrieve
:param dict params: extra parameters specific to the exchange API endpoint
:returns dict[]: a list of `position structure <https://docs.ccxt.com/en/latest/manual.html#position-structure>`
"""
await self.authenticate()
await self.load_markets()
messageHash = 'positions'
if not self.is_empty(symbols):
symbols = self.market_symbols(symbols)
messageHash += '::' + ','.join(symbols)
self.positions = ArrayCacheBySymbolBySide()
requestArg = {
'snapshot': False, # no need for initial snapshot, it's done in REST api
}
newPositions = await self.subscribe(messageHash, 'positions', self.extend(requestArg, params))
if self.newUpdates:
return newPositions
return self.filter_by_symbols_since_limit(self.positions, symbols, since, limit, True)
def handle_positions(self, client, message):
#
# snapshot:
#
# {
# channel: 'positions',
# type: 'snapshot',
# data: [
# {
# subaccountId: 0,
# symbol: 'SOL_USDT_PERP',
# base: '0.059',
# quote: '-11.50618',
# openBuySize: '0',
# openSellSize: '0',
# openBuyNotional: '0',
# openSellNotional: '0',
# lastUpdateReason: 'orderFill',
# lastUpdateTime: '1755251065621402',
# lastUpdateId: 2709589783,
# lastUpdateBaseDelta: '0.059',
# lastUpdateQuoteDelta: '-11.50618',
# breakEvenPrice: '195.02',
# markPrice: '195',
# value: '11.505',
# pnl: '-0.00118',
# initialMargin: '1.1505',
# maintenanceMargin: '0.6903',
# averageEntryPrice: '195.02'
# }
# ]
# }
#
newPositions = []
if self.positions is None:
self.positions = {}
type = self.safe_string(message, 'type')
if type == 'snapshot':
data = self.safe_list(message, 'data', [])
for i in range(0, len(data)):
position = self.parse_ws_position(data[i])
if self.safe_integer(position, 'entryPrice') != 0:
newPositions.append(position)
symbol = self.safe_string(position, 'symbol')
self.positions[symbol] = position
else:
data = self.safe_dict(message, 'data')
position = self.parse_ws_position(data)
symbol = self.safe_string(position, 'symbol')
self.positions[symbol] = position
newPositions.append(position)
messageHashes = self.find_message_hashes(client, 'positions::')
for i in range(0, len(messageHashes)):
messageHash = messageHashes[i]
parts = messageHash.split('::')
symbolsString = parts[1]
symbols = symbolsString.split(',')
positions = self.filter_by_array(newPositions, 'symbol', symbols, False)
if not self.is_empty(positions):
client.resolve(positions, messageHash)
length = len(newPositions)
if length > 0:
client.resolve(newPositions, 'positions')
def parse_ws_positions(self, positions: List[Any], symbols: List[str] = None, params={}) -> List[Position]:
symbols = self.market_symbols(symbols)
positions = self.to_array(positions)
result = []
for i in range(0, len(positions)):
position = self.extend(self.parse_ws_position(positions[i], None), params)
result.append(position)
return self.filter_by_array_positions(result, 'symbol', symbols, False)
def parse_ws_position(self, position, market=None):
# same api
return self.parse_position(position, market)
async def watch_orders(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}) -> List[Order]:
"""
watches information on multiple orders made by the user
https://arkm.com/docs#stream/order_statuses
:param str symbol: unified market symbol of the market orders were made in
:param int [since]: the earliest time in ms to fetch orders for
:param int [limit]: the maximum number of order structures to retrieve
:param dict [params]: extra parameters specific to the exchange API endpoint
:returns dict[]: a list of `order structures <https://docs.ccxt.com/?id=order-structure>`
"""
await self.authenticate()
await self.load_markets()
market = None
if symbol is not None:
market = self.market(symbol)
requestArg = {
'snapshot': False,
}
isTriggerOrder = False
isTriggerOrder, params = self.handle_option_and_params(params, 'watchOrders', 'trigger', False)
rawChannel = 'trigger_orders' if isTriggerOrder else 'order_statuses'
messageHash = 'orders'
if symbol is not None:
messageHash += '::' + market['symbol']
messageHash += '::' + rawChannel
orders = await self.subscribe(messageHash, rawChannel, self.extend(requestArg, params))
if self.newUpdates:
limit = orders.getLimit(symbol, limit)
return self.filter_by_symbol_since_limit(orders, symbol, since, limit, True)
def handle_order(self, client: Client, message):
#
# {
# channel: "order_statuses",
# type: "update",
# data: {
# orderId: 4200775347657,
# userId: 2959880,
# subaccountId: 0,
# symbol: "ARKM_USDT_PERP",
# time: "1755253639782186",
# side: "buy",
# type: "limitGtc",
# size: "10",
# price: "0.5",
# postOnly: False,
# reduceOnly: False,
# executedSize: "0",
# status: "cancelled",
# avgPrice: "0",
# executedNotional: "0",
# creditFeePaid: "0",
# marginBonusFeePaid: "0",
# quoteFeePaid: "0",
# arkmFeePaid: "0",
# revisionId: 2752963990,
# lastTime: "1755272026403545",
# clientOrderId: "",
# lastSize: "0",
# lastPrice: "0",
# lastCreditFee: "0",
# lastMarginBonusFee: "0",
# lastQuoteFee: "0",
# lastArkmFee: "0",
# }
# }
#
channel = self.safe_string(message, 'channel')
data = self.safe_dict(message, 'data')
if self.orders is None:
limit = self.safe_integer(self.options, 'ordersLimit', 1000)
self.orders = ArrayCacheBySymbolById(limit)
orders = self.orders
order = self.parse_ws_order(data)
orders.append(order)
client.resolve(orders, 'orders')
client.resolve(orders, 'orders::' + order['symbol'] + '::' + channel)
client.resolve(orders, 'orders::' + channel)
def parse_ws_order(self, order, market=None) -> Order:
# same api
return self.parse_order(order, market)
def handle_error_message(self, client: Client, response) -> Bool:
#
# error example:
#
# {
# "id": "30005",
# "name": "InvalidNotional",
# "message": "order validation failed: invalid notional: notional 0.25 is less than min notional 1"
# }
#
message = self.safe_string(response, 'message')
if message is not None:
body = self.json(response)
errorCode = self.safe_string(response, 'id')
feedback = self.id + ' ' + body
self.throw_exactly_matched_exception(self.exceptions['exact'], errorCode, feedback)
self.throw_exactly_matched_exception(self.exceptions['exact'], message, feedback)
self.throw_broadly_matched_exception(self.exceptions['broad'], message, feedback)
raise ExchangeError(self.id + ' ' + body)
return False

View File

@ -0,0 +1,964 @@
# -*- 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, ArrayCacheBySymbolById, ArrayCacheByTimestamp
import hashlib
from ccxt.base.types import Any, Balances, Bool, Int, Order, OrderBook, Str, Trade
from ccxt.async_support.base.ws.client import Client
from typing import List
from ccxt.base.errors import AuthenticationError
from ccxt.base.errors import NetworkError
class ascendex(ccxt.async_support.ascendex):
def describe(self) -> Any:
return self.deep_extend(super(ascendex, self).describe(), {
'has': {
'ws': True,
'watchBalance': True,
'watchOHLCV': True,
'watchOrderBook': True,
'watchOrders': True,
'watchTicker': False,
'watchTrades': True,
'watchTradesForSymbols': True,
},
'urls': {
'api': {
'ws': {
'public': 'wss://ascendex.com:443/api/pro/v2/stream',
'private': 'wss://ascendex.com:443/{accountGroup}/api/pro/v2/stream',
},
},
'test': {
'ws': {
'public': 'wss://api-test.ascendex-sandbox.com:443/api/pro/v2/stream',
'private': 'wss://api-test.ascendex-sandbox.com:443/{accountGroup}/api/pro/v2/stream',
},
},
},
'options': {
'tradesLimit': 1000,
'ordersLimit': 1000,
'OHLCVLimit': 1000,
'categoriesAccount': {
'cash': 'spot',
'futures': 'swap',
'margin': 'margin',
},
},
})
async def watch_public(self, messageHash, params={}):
url = self.urls['api']['ws']['public']
id = self.nonce()
request: dict = {
'id': str(id),
'op': 'sub',
}
message = self.extend(request, params)
return await self.watch(url, messageHash, message, messageHash)
async def watch_public_multiple(self, messageHashes, params={}):
url = self.urls['api']['ws']['public']
id = self.nonce()
request: dict = {
'id': str(id),
'op': 'sub',
}
message = self.extend(request, params)
return await self.watch_multiple(url, messageHashes, message, messageHashes)
async def watch_private(self, channel, messageHash, params={}):
await self.load_accounts()
accountGroup = self.safe_string(self.options, 'account-group')
url = self.urls['api']['ws']['private']
url = self.implode_params(url, {'accountGroup': accountGroup})
id = self.nonce()
request: dict = {
'id': str(id),
'op': 'sub',
'ch': channel,
}
message = self.extend(request, params)
await self.authenticate(url, params)
return await self.watch(url, messageHash, message, channel)
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://ascendex.github.io/ascendex-pro-api/#channel-bar-data
: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()
market = self.market(symbol)
symbol = market['symbol']
if (limit is None) or (limit > 1440):
limit = 100
interval = self.safe_string(self.timeframes, timeframe, timeframe)
channel = 'bar' + ':' + interval + ':' + market['id']
params = {
'ch': channel,
}
ohlcv = await self.watch_public(channel, params)
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": "bar",
# "s": "ASD/USDT",
# "data": {
# "i": "1",
# "ts": 1575398940000,
# "o": "0.04993",
# "c": "0.04970",
# "h": "0.04993",
# "l": "0.04970",
# "v": "8052"
# }
# }
#
marketId = self.safe_string(message, 's')
symbol = self.safe_symbol(marketId)
channel = self.safe_string(message, 'm')
data = self.safe_value(message, 'data', {})
interval = self.safe_string(data, 'i')
messageHash = channel + ':' + interval + ':' + marketId
timeframe = self.find_timeframe(interval)
market = self.market(symbol)
parsed = self.parse_ohlcv(message, 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)
return message
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://ascendex.github.io/ascendex-pro-api/#channel-market-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://docs.ccxt.com/?id=public-trades>`
"""
return await self.watch_trades_for_symbols([symbol], since, limit, params)
async def watch_trades_for_symbols(self, symbols: List[str], since: Int = None, limit: Int = None, params={}) -> List[Trade]:
"""
get the list of most recent trades for a list of symbols
https://ascendex.github.io/ascendex-pro-api/#channel-market-trades
:param str[] symbols: 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
:param str [params.name]: the name of the method to call, 'trade' or 'aggTrade', default is 'trade'
:returns dict[]: a list of `trade structures <https://docs.ccxt.com/?id=public-trades>`
"""
await self.load_markets()
symbols = self.market_symbols(symbols, None, False, True, True)
marketIds = []
messageHashes = []
if symbols is not None:
for i in range(0, len(symbols)):
market = self.market(symbols[i])
marketIds.append(market['id'])
messageHashes.append('trades:' + market['id'])
channel = 'trades:' + ','.join(marketIds)
params = self.extend(params, {
'ch': channel,
})
trades = await self.watch_public_multiple(messageHashes, params)
if self.newUpdates:
first = self.safe_value(trades, 0)
tradeSymbol = self.safe_string(first, 'symbol')
limit = trades.getLimit(tradeSymbol, limit)
return self.filter_by_since_limit(trades, since, limit, 'timestamp', True)
def handle_trades(self, client: Client, message):
#
# {
# "m": "trades",
# "symbol": "BTC/USDT",
# "data": [
# {
# "p": "40744.28",
# "q": "0.00150",
# "ts": 1647514330758,
# "bm": True,
# "seqnum": 72057633465800320
# }
# ]
# }
#
marketId = self.safe_string(message, 'symbol')
symbol = self.safe_symbol(marketId)
channel = self.safe_string(message, 'm')
messageHash = channel + ':' + marketId
market = self.market(symbol)
rawData = self.safe_value(message, 'data')
if rawData is None:
rawData = []
trades = self.parse_trades(rawData, market)
tradesArray = self.safe_value(self.trades, symbol)
if tradesArray is None:
limit = self.safe_integer(self.options, 'tradesLimit', 1000)
tradesArray = ArrayCache(limit)
for i in range(0, len(trades)):
tradesArray.append(trades[i])
self.trades[symbol] = tradesArray
client.resolve(tradesArray, 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://ascendex.github.io/ascendex-pro-api/#channel-level-2-order-book-updates
: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()
market = self.market(symbol)
channel = 'depth' + ':' + market['id']
params = self.extend(params, {
'ch': channel,
})
orderbook = await self.watch_public(channel, params)
return orderbook.limit()
async def watch_order_book_snapshot(self, symbol: str, limit: Int = None, params={}):
await self.load_markets()
market = self.market(symbol)
action = 'depth-snapshot'
channel = action + ':' + market['id']
params = self.extend(params, {
'action': action,
'args': {
'symbol': market['id'],
},
'op': 'req',
})
orderbook = await self.watch_public(channel, params)
return orderbook.limit()
async def fetch_order_book_snapshot_custom(self, symbol: str, limit: Int = None, params={}):
restOrderBook = await self.fetch_rest_order_book_safe(symbol, limit, params)
if not (symbol in self.orderbooks):
self.orderbooks[symbol] = self.order_book()
orderbook = self.orderbooks[symbol]
orderbook.reset(restOrderBook)
return orderbook
def handle_order_book_snapshot(self, client: Client, message):
#
# {
# "m": "depth",
# "symbol": "BTC/USDT",
# "data": {
# "ts": 1647520500149,
# "seqnum": 28590487626,
# "asks": [
# [Array], [Array], [Array],
# [Array], [Array], [Array],
# ],
# "bids": [
# [Array], [Array], [Array],
# [Array], [Array], [Array],
# ]
# }
# }
#
marketId = self.safe_string(message, 'symbol')
symbol = self.safe_symbol(marketId)
channel = self.safe_string(message, 'm')
messageHash = channel + ':' + symbol
orderbook = self.orderbooks[symbol]
data = self.safe_value(message, 'data')
snapshot = self.parse_order_book(data, symbol)
snapshot['nonce'] = self.safe_integer(data, 'seqnum')
orderbook.reset(snapshot)
# unroll the accumulated deltas
messages = orderbook.cache
for i in range(0, len(messages)):
messageItem = messages[i]
self.handle_order_book_message(client, messageItem, orderbook)
self.orderbooks[symbol] = orderbook
client.resolve(orderbook, messageHash)
def handle_order_book(self, client: Client, message):
#
# {
# "m": "depth",
# "symbol": "BTC/USDT",
# "data": {
# "ts": 1647515136144,
# "seqnum": 28590470736,
# "asks": [[Array], [Array]],
# "bids": [[Array], [Array], [Array], [Array], [Array], [Array]]
# }
# }
#
channel = self.safe_string(message, 'm')
marketId = self.safe_string(message, 'symbol')
symbol = self.safe_symbol(marketId)
messageHash = channel + ':' + marketId
if not (symbol in self.orderbooks):
self.orderbooks[symbol] = self.order_book({})
orderbook = self.orderbooks[symbol]
if orderbook['nonce'] is None:
orderbook.cache.append(message)
else:
self.handle_order_book_message(client, message, orderbook)
client.resolve(orderbook, messageHash)
def handle_delta(self, bookside, delta):
#
# ["40990.47","0.01619"],
#
price = self.safe_float(delta, 0)
amount = self.safe_float(delta, 1)
bookside.store(price, amount)
def handle_deltas(self, bookside, deltas):
for i in range(0, len(deltas)):
self.handle_delta(bookside, deltas[i])
def handle_order_book_message(self, client: Client, message, orderbook):
#
# {
# "m":"depth",
# "symbol":"BTC/USDT",
# "data":{
# "ts":1647527417715,
# "seqnum":28590257013,
# "asks":[
# ["40990.47","0.01619"],
# ["41021.21","0"],
# ["41031.59","0.06096"]
# ],
# "bids":[
# ["40990.46","0.76114"],
# ["40985.18","0"]
# ]
# }
# }
#
data = self.safe_value(message, 'data', {})
seqNum = self.safe_integer(data, 'seqnum')
if seqNum > orderbook['nonce']:
asks = self.safe_value(data, 'asks', [])
bids = self.safe_value(data, 'bids', [])
self.handle_deltas(orderbook['asks'], asks)
self.handle_deltas(orderbook['bids'], bids)
orderbook['nonce'] = seqNum
timestamp = self.safe_integer(data, 'ts')
orderbook['timestamp'] = timestamp
orderbook['datetime'] = self.iso8601(timestamp)
return orderbook
async def watch_balance(self, params={}) -> Balances:
"""
watch balance and get the amount of funds available for trading or funds locked in orders
https://ascendex.github.io/ascendex-pro-api/#channel-order-and-balance
:param dict [params]: extra parameters specific to the exchange API endpoint
:returns dict: a `balance structure <https://docs.ccxt.com/?id=balance-structure>`
"""
await self.load_markets()
type, query = self.handle_market_type_and_params('watchBalance', None, params)
channel = None
messageHash = None
if (type == 'spot') or (type == 'margin'):
accountCategories = self.safe_value(self.options, 'accountCategories', {})
accountCategory = self.safe_string(accountCategories, type, 'cash') # cash, margin,
accountCategory = accountCategory.upper()
channel = 'order:' + accountCategory # order and balance share the same channel
messageHash = 'balance:' + type
else:
channel = 'futures-account-update'
messageHash = 'balance:swap'
return await self.watch_private(channel, messageHash, query)
def handle_balance(self, client: Client, message):
#
# cash account
#
# {
# "m": "balance",
# "accountId": "cshQtyfq8XLAA9kcf19h8bXHbAwwoqEo",
# "ac": "CASH",
# "data": {
# "a" : "USDT",
# "sn": 8159798,
# "tb": "600",
# "ab": "600"
# }
# }
#
# margin account
#
# {
# "m": "balance",
# "accountId": "marOxpKJV83dxTRx0Eyxpa0gxc4Txt0P",
# "ac": "MARGIN",
# "data": {
# "a" : "USDT",
# "sn" : 8159802,
# "tb" : "400", # total Balance
# "ab" : "400", # available balance
# "brw": "0", # borrowws
# "int": "0" # interest
# }
# }
#
# futures
# {
# "m" : "futures-account-update", # message
# "e" : "ExecutionReport", # event type
# "t" : 1612508562129, # time
# "acc" : "futures-account-id", # account ID
# "at" : "FUTURES", # account type
# "sn" : 23128, # sequence number,
# "id" : "r177710001cbU3813942147C5kbFGOan",
# "col": [
# {
# "a": "USDT", # asset code
# "b": "1000000", # balance
# "f": "1" # discount factor
# }
# ],
# (...)
#
channel = self.safe_string(message, 'm')
result = None
type = None
if (channel == 'order') or (channel == 'futures-order'):
data = self.safe_value(message, 'data')
marketId = self.safe_string(data, 's')
market = self.safe_market(marketId)
baseAccount = self.account()
baseAccount['free'] = self.safe_string(data, 'bab')
baseAccount['total'] = self.safe_string(data, 'btb')
quoteAccount = self.account()
quoteAccount['free'] = self.safe_string(data, 'qab')
quoteAccount['total'] = self.safe_string(data, 'qtb')
if market['contract']:
type = 'swap'
result = self.safe_value(self.balance, type, {})
else:
type = market['type']
result = self.safe_value(self.balance, type, {})
result[market['base']] = baseAccount
result[market['quote']] = quoteAccount
else:
accountType = self.safe_string_lower_2(message, 'ac', 'at')
categoriesAccounts = self.safe_value(self.options, 'categoriesAccount')
type = self.safe_string(categoriesAccounts, accountType, 'spot')
result = self.safe_value(self.balance, type, {})
data = self.safe_value(message, 'data')
balances = None
if data is None:
balances = self.safe_value(message, 'col')
else:
balances = [data]
for i in range(0, len(balances)):
balance = balances[i]
code = self.safe_currency_code(self.safe_string(balance, 'a'))
account = self.account()
account['free'] = self.safe_string(balance, 'ab')
account['total'] = self.safe_string_2(balance, 'tb', 'b')
result[code] = account
messageHash = 'balance' + ':' + type
client.resolve(self.safe_balance(result), messageHash)
async def watch_orders(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}) -> List[Order]:
"""
https://ascendex.github.io/ascendex-pro-api/#channel-order-and-balance
watches information on multiple orders made by the user
:param str symbol: unified market symbol of the market orders were made in
:param int [since]: the earliest time in ms to fetch orders for
:param int [limit]: the maximum number of order structures to retrieve
:param dict [params]: extra parameters specific to the exchange API endpoint
:returns dict[]: a list of `order structures <https://docs.ccxt.com/?id=order-structure>`
"""
await self.load_markets()
market = None
if symbol is not None:
market = self.market(symbol)
symbol = market['symbol']
type, query = self.handle_market_type_and_params('watchOrders', market, params)
messageHash = None
channel = None
if type != 'spot' and type != 'margin':
channel = 'futures-order'
messageHash = 'order:FUTURES'
else:
accountCategories = self.safe_value(self.options, 'accountCategories', {})
accountCategory = self.safe_string(accountCategories, type, 'cash') # cash, margin
accountCategory = accountCategory.upper()
messageHash = 'order' + ':' + accountCategory
channel = messageHash
if symbol is not None:
messageHash = messageHash + ':' + symbol
orders = await self.watch_private(channel, messageHash, query)
if self.newUpdates:
limit = orders.getLimit(symbol, limit)
return self.filter_by_symbol_since_limit(orders, symbol, since, limit, True)
def handle_order(self, client: Client, message):
#
# spot order
# {
# "m": "order",
# "accountId": "cshF5SlR9ukAXoDOuXbND4dVpBMw9gzH",
# "ac": "CASH",
# "data": {
# "sn": 19399016185,
# "orderId": "r17f9d7983faU7223046196CMlrj3bfC",
# "s": "LTC/USDT",
# "ot": "Limit",
# "t": 1647614461160,
# "p": "50",
# "q": "0.1",
# "sd": "Buy",
# "st": "New",
# "ap": "0",
# "cfq": "0",
# "sp": '',
# "err": '',
# "btb": "0",
# "bab": "0",
# "qtb": "8",
# "qab": "2.995",
# "cf": "0",
# "fa": "USDT",
# "ei": "NULL_VAL"
# }
# }
#
# futures order
# {
# "m": "futures-order",
# "sn": 19399927636,
# "e": "ExecutionReport",
# "a": "futF5SlR9ukAXoDOuXbND4dVpBMw9gzH", # account id
# "ac": "FUTURES",
# "t": 1647622515434, # last execution time
# (...)
# }
#
accountType = self.safe_string(message, 'ac')
messageHash = 'order:' + accountType
data = self.safe_value(message, 'data', message)
order = self.parse_ws_order(data)
if self.orders is None:
limit = self.safe_integer(self.options, 'ordersLimit', 1000)
self.orders = ArrayCacheBySymbolById(limit)
orders = self.orders
orders.append(order)
symbolMessageHash = messageHash + ':' + order['symbol']
client.resolve(orders, symbolMessageHash)
client.resolve(orders, messageHash)
def parse_ws_order(self, order, market=None):
#
# spot order
# {
# "sn": 19399016185, #sequence number
# "orderId": "r17f9d7983faU7223046196CMlrj3bfC",
# "s": "LTC/USDT",
# "ot": "Limit", # order type
# "t": 1647614461160, # last execution timestamp
# "p": "50", # price
# "q": "0.1", # quantity
# "sd": "Buy", # side
# "st": "New", # status
# "ap": "0", # average fill price
# "cfq": "0", # cumulated fill quantity
# "sp": '', # stop price
# "err": '',
# "btb": "0", # base asset total balance
# "bab": "0", # base asset available balance
# "qtb": "8", # quote asset total balance
# "qab": "2.995", # quote asset available balance
# "cf": "0", # cumulated commission
# "fa": "USDT", # fee asset
# "ei": "NULL_VAL"
# }
#
# futures order
# {
# "m": "futures-order",
# "sn": 19399927636,
# "e": "ExecutionReport",
# "a": "futF5SlR9ukAXoDOuXbND4dVpBMw9gzH", # account id
# "ac": "FUTURES",
# "t": 1647622515434, # last execution time
# "ct": 1647622515413, # order creation time
# "orderId": "r17f9df469b1U7223046196Okf5Kbmd",
# "sd": "Buy", # side
# "ot": "Limit", # order type
# "ei": "NULL_VAL",
# "q": "1", # quantity
# "p": "50", #price
# "sp": "0", # stopPrice
# "spb": '', # stopTrigger
# "s": "LTC-PERP", # symbol
# "st": "New", # state
# "err": '',
# "lp": "0", # last filled price
# "lq": "0", # last filled quantity(base asset)
# "ap": "0", # average filled price
# "cfq": "0", # cummulative filled quantity(base asset)
# "f": "0", # commission fee of the current execution
# "cf": "0", # cumulative commission fee
# "fa": "USDT", # fee asset
# "psl": "0",
# "pslt": "market",
# "ptp": "0",
# "ptpt": "market"
# }
#
status = self.parse_order_status(self.safe_string(order, 'st'))
marketId = self.safe_string(order, 's')
timestamp = self.safe_integer(order, 't')
symbol = self.safe_symbol(marketId, market, '/')
lastTradeTimestamp = self.safe_integer(order, 't')
price = self.safe_string(order, 'p')
amount = self.safe_string(order, 'q')
average = self.safe_string(order, 'ap')
filled = self.safe_string(order, 'cfq')
id = self.safe_string(order, 'orderId')
type = self.safe_string_lower(order, 'ot')
side = self.safe_string_lower(order, 'sd')
feeCost = self.safe_number(order, 'cf')
fee = None
if feeCost is not None:
feeCurrencyId = self.safe_string(order, 'fa')
feeCurrencyCode = self.safe_currency_code(feeCurrencyId)
fee = {
'cost': feeCost,
'currency': feeCurrencyCode,
}
stopPrice = self.parse_number(self.omit_zero(self.safe_string(order, 'sp')))
return self.safe_order({
'info': order,
'id': id,
'clientOrderId': None,
'timestamp': timestamp,
'datetime': self.iso8601(timestamp),
'lastTradeTimestamp': lastTradeTimestamp,
'symbol': symbol,
'type': type,
'timeInForce': None,
'postOnly': None,
'side': side,
'price': price,
'stopPrice': stopPrice,
'triggerPrice': stopPrice,
'amount': amount,
'cost': None,
'average': average,
'filled': filled,
'remaining': None,
'status': status,
'fee': fee,
'trades': None,
}, market)
def handle_error_message(self, client: Client, message) -> Bool:
#
# {
# "m": "disconnected",
# "code": 100005,
# "reason": "INVALID_WS_REQUEST_DATA",
# "info": "Session is disconnected due to missing pong message from the client"
# }
#
errorCode = self.safe_integer(message, 'code')
try:
if errorCode is not None:
feedback = self.id + ' ' + self.json(message)
self.throw_exactly_matched_exception(self.exceptions['exact'], errorCode, feedback)
messageString = self.safe_value(message, 'message')
if messageString is not None:
self.throw_broadly_matched_exception(self.exceptions['broad'], messageString, feedback)
return False
except Exception as e:
if isinstance(e, AuthenticationError):
messageHash = 'authenticated'
client.reject(e, messageHash)
if messageHash in client.subscriptions:
del client.subscriptions[messageHash]
else:
client.reject(e)
return True
def handle_authenticate(self, client: Client, message):
#
# {m: "auth", id: "1647605234", code: 0}
#
messageHash = 'authenticated'
client.resolve(message, messageHash)
def handle_message(self, client: Client, message):
if self.handle_error_message(client, message):
return
#
# {m: "ping", hp: 3}
#
# {m: "sub", ch: "bar:BTC/USDT", code: 0}
#
# {m: 'sub', id: "1647515701", ch: "depth:BTC/USDT", code: 0}
#
# {m: "connected", type: "unauth"}
#
# {m: "auth", id: "1647605234", code: 0}
#
# order or balance sub
# {
# "m": "sub",
# "id": "1647605952",
# "ch": "order:cshF5SlR9ukAXoDOuXbND4dVpBMw9gzH", or futures-order
# "code": 0
# }
#
# ohlcv
# {
# "m": "bar",
# "s": "BTC/USDT",
# "data": {
# "i": "1",
# "ts": 1647510060000,
# "o": "40813.93",
# "c": "40804.57",
# "h": "40814.21",
# "l": "40804.56",
# "v": "0.01537"
# }
# }
#
# trades
#
# {
# "m": "trades",
# "symbol": "BTC/USDT",
# "data": [
# {
# "p": "40762.26",
# "q": "0.01500",
# "ts": 1647514306759,
# "bm": True,
# "seqnum": 72057633465795180
# }
# ]
# }
#
# orderbook deltas
#
# {
# "m":"depth",
# "symbol":"BTC/USDT",
# "data":{
# "ts":1647527417715,
# "seqnum":28590257013,
# "asks":[
# ["40990.47","0.01619"],
# ["41021.21","0"],
# ["41031.59","0.06096"]
# ],
# "bids":[
# ["40990.46","0.76114"],
# ["40985.18","0"]
# ]
# }
# }
#
# orderbook snapshot
# {
# "m": "depth-snapshot",
# "symbol": "BTC/USDT",
# "data": {
# "ts": 1647525938513,
# "seqnum": 28590504772,
# "asks": [
# [Array], [Array], [Array], [Array], [Array], [Array], [Array],
# [Array], [Array], [Array], [Array], [Array], [Array], [Array],
# [Array], [Array], [Array], [Array], [Array], [Array], [Array],
# (...)
# ]
# }
#
# spot order update
# {
# "m": "order",
# "accountId": "cshQtyfq8XLAA9kcf19h8bXHbAwwoqDo",
# "ac": "CASH",
# "data": {
# "s": "BTC/USDT",
# "sn": 8159711,
# "sd": "Buy",
# "ap": "0",
# "bab": "2006.5974027",
# "btb": "2006.5974027",
# "cf": "0",
# "cfq": "0",
# (...)
# }
# }
# future order update
# {
# "m": "futures-order",
# "sn": 19404258063,
# "e": "ExecutionReport",
# "a": "futF5SlR9ukAXoDOuXbND4dVpBMw9gzH",
# "ac": "FUTURES",
# "t": 1647681792543,
# "ct": 1647622515413,
# "orderId": "r17f9df469b1U7223046196Okf5KbmdL",
# (...)
# "ptpt": "None"
# }
#
# balance update cash
# {
# "m": "balance",
# "accountId": "cshQtyfq8XLAA9kcf19h8bXHbAwwoqDo",
# "ac": "CASH",
# "data": {
# "a" : "USDT",
# "sn": 8159798,
# "tb": "600",
# "ab": "600"
# }
# }
#
# balance update margin
# {
# "m": "balance",
# "accountId": "marOxpKJV83dxTRx0Eyxpa0gxc4Txt0P",
# "ac": "MARGIN",
# "data": {
# "a" : "USDT",
# "sn" : 8159802,
# "tb" : "400",
# "ab" : "400",
# "brw": "0",
# "int": "0"
# }
# }
#
subject = self.safe_string(message, 'm')
methods: dict = {
'ping': self.handle_ping,
'auth': self.handle_authenticate,
'sub': self.handle_subscription_status,
'depth': self.handle_order_book,
'depth-snapshot': self.handle_order_book_snapshot,
'trades': self.handle_trades,
'bar': self.handle_ohlcv,
'balance': self.handle_balance,
'futures-account-update': self.handle_balance,
}
method = self.safe_value(methods, subject)
if method is not None:
method(client, message)
if (subject == 'order') or (subject == 'futures-order'):
# self.handle_order(client, message)
# balance updates may be in the order structure
# they may also be standalone balance updates related to account transfers
self.handle_order(client, message)
if subject == 'order':
self.handle_balance(client, message)
def handle_subscription_status(self, client: Client, message):
#
# {m: "sub", ch: "bar:BTC/USDT", code: 0}
#
# {m: 'sub', id: "1647515701", ch: "depth:BTC/USDT", code: 0}
#
channel = self.safe_string(message, 'ch', '')
if channel.find('depth') > -1 and not (channel.find('depth-snapshot') > -1):
self.handle_order_book_subscription(client, message)
return message
def handle_order_book_subscription(self, client: Client, message):
channel = self.safe_string(message, 'ch')
parts = channel.split(':')
marketId = parts[1]
market = self.safe_market(marketId)
symbol = market['symbol']
if symbol in self.orderbooks:
del self.orderbooks[symbol]
self.orderbooks[symbol] = self.order_book({})
if self.options['defaultType'] == 'swap' or market['contract']:
self.spawn(self.fetch_order_book_snapshot_custom, symbol)
else:
self.spawn(self.watch_order_book_snapshot, symbol)
async def pong(self, client, message):
#
# {m: "ping", hp: 3}
#
try:
await client.send({'op': 'pong', 'hp': self.safe_integer(message, 'hp')})
except Exception as e:
error = NetworkError(self.id + ' handlePing failed with error ' + self.exception_message(e))
client.reset(error)
def handle_ping(self, client: Client, message):
self.spawn(self.pong, client, message)
async def authenticate(self, url, params={}):
self.check_required_credentials()
messageHash = 'authenticated'
client = self.client(url)
future = self.safe_value(client.subscriptions, messageHash)
if future is None:
timestamp = str(self.milliseconds())
urlParts = url.split('/')
partsLength = len(urlParts)
path = self.safe_string(urlParts, partsLength - 1)
version = self.safe_string(urlParts, partsLength - 2)
auth = timestamp + '+' + version + '/' + path
secret = self.base64_to_binary(self.secret)
signature = self.hmac(self.encode(auth), secret, hashlib.sha256, 'base64')
request: dict = {
'op': 'auth',
'id': str(self.nonce()),
't': timestamp,
'key': self.apiKey,
'sig': signature,
}
future = await self.watch(url, messageHash, self.extend(request, params), messageHash)
client.subscriptions[messageHash] = future
return future

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,43 @@
# -*- 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
from ccxt.pro.hitbtc import hitbtc
from ccxt.base.types import Any
import ccxt.async_support.bequant as bequantRest
class bequant(hitbtc):
def describe(self) -> Any:
# eslint-disable-next-line new-cap
restInstance = bequantRest()
restDescribe = restInstance.describe()
extended = self.deep_extend(super(bequant, self).describe(), restDescribe)
return self.deep_extend(extended, {
'id': 'bequant',
'name': 'Bequant',
'countries': ['MT'], # Malta
'pro': True,
'urls': {
'logo': 'https://user-images.githubusercontent.com/1294454/55248342-a75dfe00-525a-11e9-8aa2-05e9dca943c6.jpg',
'api': {
'public': 'https://api.bequant.io/api/3',
'private': 'https://api.bequant.io/api/3',
'ws': {
'public': 'wss://api.bequant.io/api/3/ws/public',
'private': 'wss://api.bequant.io/api/3/ws/trading',
},
},
'www': 'https://bequant.io',
'doc': [
'https://api.bequant.io/',
],
'fees': [
'https://bequant.io/fees-and-limits',
],
'referral': 'https://bequant.io',
},
})

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,32 @@
# -*- 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
from ccxt.pro.binance import binance
from ccxt.base.types import Any
import ccxt.async_support.binancecoinm as binancecoinmRest
class binancecoinm(binance):
def describe(self) -> Any:
# eslint-disable-next-line new-cap
restInstance = binancecoinmRest()
restDescribe = restInstance.describe()
extended = self.deep_extend(super(binancecoinm, self).describe(), restDescribe)
return self.deep_extend(extended, {
'id': 'binancecoinm',
'name': 'Binance COIN-M',
'urls': {
'logo': 'https://user-images.githubusercontent.com/1294454/117738721-668c8d80-b205-11eb-8c49-3fad84c4a07f.jpg',
'doc': 'https://developers.binance.com/en',
},
'options': {
'fetchMarkets': {
'types': ['inverse'],
},
'defaultSubType': 'inverse',
},
})

View File

@ -0,0 +1,70 @@
# -*- 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
from ccxt.pro.binance import binance
from ccxt.base.types import Any
import ccxt.async_support.binanceus as binanceusRest
class binanceus(binance):
def describe(self) -> Any:
# eslint-disable-next-line new-cap
restInstance = binanceusRest()
restDescribe = restInstance.describe()
parentWsDescribe = super(binanceus, self).describe_data()
extended = self.deep_extend(restDescribe, parentWsDescribe)
return self.deep_extend(extended, {
'id': 'binanceus',
'name': 'Binance US',
'countries': ['US'], # US
'certified': False,
'urls': {
'logo': 'https://user-images.githubusercontent.com/1294454/65177307-217b7c80-da5f-11e9-876e-0b748ba0a358.jpg',
'api': {
'ws': {
'spot': 'wss://stream.binance.us:9443/ws',
},
'web': 'https://www.binance.us',
'sapi': 'https://api.binance.us/sapi/v1',
'wapi': 'https://api.binance.us/wapi/v3',
'public': 'https://api.binance.us/api/v3',
'private': 'https://api.binance.us/api/v3',
'v3': 'https://api.binance.us/api/v3',
'v1': 'https://api.binance.us/api/v1',
},
'www': 'https://www.binance.us',
'referral': 'https://www.binance.us/?ref=35005074',
'doc': 'https://github.com/binance-us/binance-official-api-docs',
'fees': 'https://www.binance.us/en/fee/schedule',
},
'has': {
'createOrderWithTakeProfitAndStopLossWs': False,
'createReduceOnlyOrderWs': False,
'createStopLossOrderWs': False,
'createTakeProfitOrderWs': False,
'fetchPositionForSymbolWs': False,
'fetchPositionsForSymbolWs': False,
'fetchPositionsWs': False,
'fetchPositionWs': False,
'unWatchPositions': False,
'watchLiquidations': False,
'watchLiquidationsForSymbols': False,
'watchMarkPrice': False,
'watchMarkPrices': False,
'watchMyLiquidations': False,
'watchMyLiquidationsForSymbols': False,
'watchPosition': False,
'watchPositions': False,
},
'options': {
'quoteOrderQty': False,
'defaultType': 'spot',
'fetchMarkets': {
'types': ['spot'],
},
},
})

View File

@ -0,0 +1,42 @@
# -*- 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
from ccxt.pro.binance import binance
from ccxt.base.types import Any
from ccxt.base.errors import InvalidOrder
import ccxt.async_support.binanceusdm as binanceusdmRest
class binanceusdm(binance):
def describe(self) -> Any:
# eslint-disable-next-line new-cap
restInstance = binanceusdmRest()
restDescribe = restInstance.describe()
extended = self.deep_extend(super(binanceusdm, self).describe(), restDescribe)
return self.deep_extend(extended, {
'id': 'binanceusdm',
'name': 'Binance USDⓈ-M',
'urls': {
'logo': 'https://user-images.githubusercontent.com/1294454/117738721-668c8d80-b205-11eb-8c49-3fad84c4a07f.jpg',
'doc': 'https://developers.binance.com/en',
},
'options': {
'fetchMarkets': {
'types': ['linear'],
},
'defaultSubType': 'linear',
},
# https://binance-docs.github.io/apidocs/futures/en/#error-codes
# https://developers.binance.com/docs/derivatives/usds-margined-futures/error-code
'exceptions': {
'exact': {
'-5021': InvalidOrder, # {"code":-5021,"msg":"Due to the order could not be filled immediately, the FOK order has been rejected."}
'-5022': InvalidOrder, # {"code":-5022,"msg":"Due to the order could not be executed, the Post Only order will be rejected."}
'-5028': InvalidOrder, # {"code":-5028,"msg":"Timestamp for self request is outside of the ME recvWindow."}
},
},
})

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,622 @@
# -*- 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, ArrayCacheBySymbolById
from ccxt.base.types import Any, Balances, Bool, Int, Order, OrderBook, Str, Strings, Ticker, Tickers, Trade
from ccxt.async_support.base.ws.client import Client
from typing import List
from ccxt.base.errors import ExchangeError
class bithumb(ccxt.async_support.bithumb):
def describe(self) -> Any:
return self.deep_extend(super(bithumb, self).describe(), {
'has': {
'ws': True,
'watchBalance': True,
'watchOrders': True,
'watchTicker': True,
'watchTickers': True,
'watchTrades': True,
'watchOrderBook': True,
'watchOHLCV': False,
},
'urls': {
'api': {
'ws': {
'public': 'wss://pubwss.bithumb.com/pub/ws', # v1.2.0
'publicV2': 'wss://ws-api.bithumb.com/websocket/v1', # v2.1.5
'privateV2': 'wss://ws-api.bithumb.com/websocket/v1/private', # v2.1.5
},
},
},
'options': {},
'streaming': {},
'exceptions': {},
})
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://apidocs.bithumb.com/v1.2.0/reference/%EB%B9%97%EC%8D%B8-%EA%B1%B0%EB%9E%98%EC%86%8C-%EC%A0%95%EB%B3%B4-%EC%88%98%EC%8B%A0
:param str symbol: unified symbol of the market to fetch the ticker for
:param dict [params]: extra parameters specific to the exchange API endpoint
:param str [params.channel]: the channel to subscribe to, tickers by default. Can be tickers, sprd-tickers, index-tickers, block-tickers
:returns dict: a `ticker structure <https://github.com/ccxt/ccxt/wiki/Manual#ticker-structure>`
"""
url = self.urls['api']['ws']['public']
await self.load_markets()
market = self.market(symbol)
messageHash = 'ticker:' + market['symbol']
request: dict = {
'type': 'ticker',
'symbols': [market['base'] + '_' + market['quote']],
'tickTypes': [self.safe_string(params, 'tickTypes', '24H')],
}
return await self.watch(url, messageHash, self.extend(request, params), messageHash)
async def watch_tickers(self, symbols: Strings = None, params={}) -> Tickers:
"""
watches a price ticker, a statistical calculation with the information calculated over the past 24 hours for all markets of a specific list
https://apidocs.bithumb.com/v1.2.0/reference/%EB%B9%97%EC%8D%B8-%EA%B1%B0%EB%9E%98%EC%86%8C-%EC%A0%95%EB%B3%B4-%EC%88%98%EC%8B%A0
:param str[] symbols: 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>`
"""
await self.load_markets()
url = self.urls['api']['ws']['public']
marketIds = []
messageHashes = []
symbols = self.market_symbols(symbols, None, False, True, True)
for i in range(0, len(symbols)):
symbol = symbols[i]
market = self.market(symbol)
marketIds.append(market['base'] + '_' + market['quote'])
messageHashes.append('ticker:' + market['symbol'])
request: dict = {
'type': 'ticker',
'symbols': marketIds,
'tickTypes': [self.safe_string(params, 'tickTypes', '24H')],
}
message = self.extend(request, params)
newTicker = await self.watch_multiple(url, messageHashes, message, messageHashes)
if self.newUpdates:
result: dict = {}
result[newTicker['symbol']] = newTicker
return result
return self.filter_by_array(self.tickers, 'symbol', symbols)
def handle_ticker(self, client: Client, message):
#
# {
# "type" : "ticker",
# "content" : {
# "symbol" : "BTC_KRW", # 통화코드
# "tickType" : "24H", # 변동 기준시간- 30M, 1H, 12H, 24H, MID
# "date" : "20200129", # 일자
# "time" : "121844", # 시간
# "openPrice" : "2302", # 시가
# "closePrice" : "2317", # 종가
# "lowPrice" : "2272", # 저가
# "highPrice" : "2344", # 고가
# "value" : "2831915078.07065789", # 누적거래금액
# "volume" : "1222314.51355788", # 누적거래량
# "sellVolume" : "760129.34079004", # 매도누적거래량
# "buyVolume" : "462185.17276784", # 매수누적거래량
# "prevClosePrice" : "2326", # 전일종가
# "chgRate" : "0.65", # 변동률
# "chgAmt" : "15", # 변동금액
# "volumePower" : "60.80" # 체결강도
# }
# }
#
content = self.safe_dict(message, 'content', {})
marketId = self.safe_string(content, 'symbol')
symbol = self.safe_symbol(marketId, None, '_')
ticker = self.parse_ws_ticker(content)
messageHash = 'ticker:' + symbol
self.tickers[symbol] = ticker
client.resolve(self.tickers[symbol], messageHash)
def parse_ws_ticker(self, ticker, market=None):
#
# {
# "symbol" : "BTC_KRW", # 통화코드
# "tickType" : "24H", # 변동 기준시간- 30M, 1H, 12H, 24H, MID
# "date" : "20200129", # 일자
# "time" : "121844", # 시간
# "openPrice" : "2302", # 시가
# "closePrice" : "2317", # 종가
# "lowPrice" : "2272", # 저가
# "highPrice" : "2344", # 고가
# "value" : "2831915078.07065789", # 누적거래금액
# "volume" : "1222314.51355788", # 누적거래량
# "sellVolume" : "760129.34079004", # 매도누적거래량
# "buyVolume" : "462185.17276784", # 매수누적거래량
# "prevClosePrice" : "2326", # 전일종가
# "chgRate" : "0.65", # 변동률
# "chgAmt" : "15", # 변동금액
# "volumePower" : "60.80" # 체결강도
# }
#
date = self.safe_string(ticker, 'date', '')
time = self.safe_string(ticker, 'time', '')
datetime = date[0:4] + '-' + date[4:6] + '-' + date[6:8] + 'T' + time[0:2] + ':' + time[2:4] + ':' + time[4:6]
marketId = self.safe_string(ticker, 'symbol')
return self.safe_ticker({
'symbol': self.safe_symbol(marketId, market, '_'),
'timestamp': self.parse8601(datetime),
'datetime': datetime,
'high': self.safe_string(ticker, 'highPrice'),
'low': self.safe_string(ticker, 'lowPrice'),
'bid': None,
'bidVolume': self.safe_string(ticker, 'buyVolume'),
'ask': None,
'askVolume': self.safe_string(ticker, 'sellVolume'),
'vwap': None,
'open': self.safe_string(ticker, 'openPrice'),
'close': self.safe_string(ticker, 'closePrice'),
'last': None,
'previousClose': self.safe_string(ticker, 'prevClosePrice'),
'change': self.safe_string(ticker, 'chgAmt'),
'percentage': self.safe_string(ticker, 'chgRate'),
'average': None,
'baseVolume': self.safe_string(ticker, 'volume'),
'quoteVolume': self.safe_string(ticker, 'value'),
'info': ticker,
}, market)
async def watch_order_book(self, symbol: str, limit: Int = None, params={}) -> OrderBook:
"""
https://apidocs.bithumb.com/v1.2.0/reference/%EB%B9%97%EC%8D%B8-%EA%B1%B0%EB%9E%98%EC%86%8C-%EC%A0%95%EB%B3%B4-%EC%88%98%EC%8B%A0
watches information on open orders with bid(buy) and ask(sell) prices, volumes and other data
: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://github.com/ccxt/ccxt/wiki/Manual#order-book-structure>` indexed by market symbols
"""
await self.load_markets()
url = self.urls['api']['ws']['public']
market = self.market(symbol)
symbol = market['symbol']
messageHash = 'orderbook' + ':' + symbol
request: dict = {
'type': 'orderbookdepth',
'symbols': [market['base'] + '_' + market['quote']],
}
orderbook = await self.watch(url, messageHash, self.extend(request, params), messageHash)
return orderbook.limit()
def handle_order_book(self, client: Client, message):
#
# {
# "type" : "orderbookdepth",
# "content" : {
# "list" : [
# {
# "symbol" : "BTC_KRW",
# "orderType" : "ask", # 주문타입 bid / ask
# "price" : "10593000", # 호가
# "quantity" : "1.11223318", # 잔량
# "total" : "3" # 건수
# },
# {"symbol" : "BTC_KRW", "orderType" : "ask", "price" : "10596000", "quantity" : "0.5495", "total" : "8"},
# {"symbol" : "BTC_KRW", "orderType" : "ask", "price" : "10598000", "quantity" : "18.2085", "total" : "10"},
# {"symbol" : "BTC_KRW", "orderType" : "bid", "price" : "10532000", "quantity" : "0", "total" : "0"},
# {"symbol" : "BTC_KRW", "orderType" : "bid", "price" : "10572000", "quantity" : "2.3324", "total" : "4"},
# {"symbol" : "BTC_KRW", "orderType" : "bid", "price" : "10571000", "quantity" : "1.469", "total" : "3"},
# {"symbol" : "BTC_KRW", "orderType" : "bid", "price" : "10569000", "quantity" : "0.5152", "total" : "2"}
# ],
# "datetime":1580268255864325 # 일시
# }
# }
#
content = self.safe_dict(message, 'content', {})
list = self.safe_list(content, 'list', [])
first = self.safe_dict(list, 0, {})
marketId = self.safe_string(first, 'symbol')
symbol = self.safe_symbol(marketId, None, '_')
timestampStr = self.safe_string(content, 'datetime')
timestamp = self.parse_to_int(timestampStr[0:13])
if not (symbol in self.orderbooks):
ob = self.order_book()
ob['symbol'] = symbol
self.orderbooks[symbol] = ob
orderbook = self.orderbooks[symbol]
self.handle_deltas(orderbook, list)
orderbook['timestamp'] = timestamp
orderbook['datetime'] = self.iso8601(timestamp)
messageHash = 'orderbook' + ':' + symbol
client.resolve(orderbook, messageHash)
def handle_delta(self, orderbook, delta):
#
# {
# symbol: "ETH_BTC",
# orderType: "bid",
# price: "0.07349517",
# quantity: "0",
# total: "0",
# }
#
sideId = self.safe_string(delta, 'orderType')
side = 'bids' if (sideId == 'bid') else 'asks'
bidAsk = self.parse_bid_ask(delta, 'price', 'quantity')
orderbookSide = orderbook[side]
orderbookSide.storeArray(bidAsk)
def handle_deltas(self, orderbook, deltas):
for i in range(0, len(deltas)):
self.handle_delta(orderbook, deltas[i])
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://apidocs.bithumb.com/v1.2.0/reference/%EB%B9%97%EC%8D%B8-%EA%B1%B0%EB%9E%98%EC%86%8C-%EC%A0%95%EB%B3%B4-%EC%88%98%EC%8B%A0
: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']['public']
market = self.market(symbol)
symbol = market['symbol']
messageHash = 'trade:' + symbol
request: dict = {
'type': 'transaction',
'symbols': [market['base'] + '_' + market['quote']],
}
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)
def handle_trades(self, client, message):
#
# {
# "type" : "transaction",
# "content" : {
# "list" : [
# {
# "symbol" : "BTC_KRW",
# "buySellGb" : "1",
# "contPrice" : "10579000",
# "contQty" : "0.01",
# "contAmt" : "105790.00",
# "contDtm" : "2020-01-29 12:24:18.830039",
# "updn" : "dn"
# }
# ]
# }
# }
#
content = self.safe_dict(message, 'content', {})
rawTrades = self.safe_list(content, 'list', [])
for i in range(0, len(rawTrades)):
rawTrade = rawTrades[i]
marketId = self.safe_string(rawTrade, 'symbol')
symbol = self.safe_symbol(marketId, None, '_')
if not (symbol in self.trades):
limit = self.safe_integer(self.options, 'tradesLimit', 1000)
stored = ArrayCache(limit)
self.trades[symbol] = stored
trades = self.trades[symbol]
parsed = self.parse_ws_trade(rawTrade)
trades.append(parsed)
messageHash = 'trade' + ':' + symbol
client.resolve(trades, messageHash)
def parse_ws_trade(self, trade, market=None):
#
# {
# "symbol" : "BTC_KRW",
# "buySellGb" : "1",
# "contPrice" : "10579000",
# "contQty" : "0.01",
# "contAmt" : "105790.00",
# "contDtm" : "2020-01-29 12:24:18.830038",
# "updn" : "dn"
# }
#
marketId = self.safe_string(trade, 'symbol')
datetime = self.safe_string(trade, 'contDtm')
# that date is not UTC iso8601, but exchange's local time, -9hr difference
timestamp = self.parse8601(datetime) - 32400000
sideId = self.safe_string(trade, 'buySellGb')
return self.safe_trade({
'id': None,
'info': trade,
'timestamp': timestamp,
'datetime': self.iso8601(timestamp),
'symbol': self.safe_symbol(marketId, market, '_'),
'order': None,
'type': None,
'side': 'buy' if (sideId == '1') else 'sell',
'takerOrMaker': None,
'price': self.safe_string(trade, 'contPrice'),
'amount': self.safe_string(trade, 'contQty'),
'cost': self.safe_string(trade, 'contAmt'),
'fee': None,
}, market)
def handle_error_message(self, client: Client, message) -> Bool:
#
# {
# "status" : "5100",
# "resmsg" : "Invalid Filter Syntax"
# }
#
if not ('status' in message):
return True
errorCode = self.safe_string(message, 'status')
try:
if errorCode != '0000':
msg = self.safe_string(message, 'resmsg')
raise ExchangeError(self.id + ' ' + msg)
return True
except Exception as e:
client.reject(e)
return True
async def watch_balance(self, params={}) -> Balances:
"""
watch balance and get the amount of funds available for trading or funds locked in orders
https://apidocs.bithumb.com/v2.1.5/reference/%EB%82%B4-%EC%9E%90%EC%82%B0-myasset
:param dict [params]: extra parameters specific to the exchange API endpoint
:returns dict: a `balance structure <https://docs.ccxt.com/?id=balance-structure>`
"""
await self.load_markets()
await self.authenticate()
url = self.urls['api']['ws']['privateV2']
messageHash = 'myAsset'
request = [
{'ticket': 'ccxt'},
{'type': messageHash},
]
balance = await self.watch(url, messageHash, request, messageHash)
return balance
def handle_balance(self, client: Client, message):
#
# {
# "type": "myAsset",
# "assets": [
# {
# "currency": "KRW",
# "balance": "2061832.35",
# "locked": "3824127.3"
# }
# ],
# "asset_timestamp": 1727052537592,
# "timestamp": 1727052537687,
# "stream_type": "REALTIME"
# }
#
messageHash = 'myAsset'
assets = self.safe_list(message, 'assets', [])
if self.balance is None:
self.balance = {}
for i in range(0, len(assets)):
asset = assets[i]
currencyId = self.safe_string(asset, 'currency')
code = self.safe_currency_code(currencyId)
account = self.account()
account['free'] = self.safe_string(asset, 'balance')
account['used'] = self.safe_string(asset, 'locked')
self.balance[code] = account
self.balance['info'] = message
timestamp = self.safe_integer(message, 'timestamp')
self.balance['timestamp'] = timestamp
self.balance['datetime'] = self.iso8601(timestamp)
self.balance = self.safe_balance(self.balance)
client.resolve(self.balance, messageHash)
async def authenticate(self, params={}):
self.check_required_credentials()
wsOptions: dict = self.safe_dict(self.options, 'ws', {})
authenticated = self.safe_string(wsOptions, 'token')
if authenticated is None:
payload: dict = {
'access_key': self.apiKey,
'nonce': self.uuid(),
'timestamp': self.milliseconds(),
}
jwtToken = self.jwt(payload, self.encode(self.secret), 'sha256')
wsOptions['token'] = jwtToken
wsOptions['options'] = {
'headers': {
'authorization': 'Bearer ' + jwtToken,
},
}
self.options['ws'] = wsOptions
url = self.urls['api']['ws']['privateV2']
client = self.client(url)
return client
async def watch_orders(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}) -> List[Order]:
"""
watches information on multiple orders made by the user
https://apidocs.bithumb.com/v2.1.5/reference/%EB%82%B4-%EC%A3%BC%EB%AC%B8-%EB%B0%8F-%EC%B2%B4%EA%B2%B0-myorder
:param str symbol: unified market symbol of the market orders were made in
:param int [since]: the earliest time in ms to fetch orders for
:param int [limit]: the maximum number of order structures to retrieve
:param dict [params]: extra parameters specific to the exchange API endpoint
:param str[] [params.codes]: market codes to filter orders
:returns dict[]: a list of `order structures <https://docs.ccxt.com/?id=order-structure>`
"""
await self.load_markets()
await self.authenticate()
url = self.urls['api']['ws']['privateV2']
messageHash = 'myOrder'
codes = self.safe_list(params, 'codes', [])
request = [
{'ticket': 'ccxt'},
{'type': messageHash, 'codes': codes},
]
if symbol is not None:
market = self.market(symbol)
symbol = market['symbol']
messageHash = messageHash + ':' + symbol
orders = await self.watch(url, messageHash, request, messageHash)
if self.newUpdates:
limit = orders.getLimit(symbol, limit)
return self.filter_by_symbol_since_limit(orders, symbol, since, limit, True)
def handle_orders(self, client: Client, message):
#
# {
# "type": "myOrder",
# "code": "KRW-BTC",
# "uuid": "C0101000000001818113",
# "ask_bid": "BID",
# "order_type": "limit",
# "state": "trade",
# "trade_uuid": "C0101000000001744207",
# "price": 1927000,
# "volume": 0.4697,
# "remaining_volume": 0.0803,
# "executed_volume": 0.4697,
# "trades_count": 1,
# "reserved_fee": 0,
# "remaining_fee": 0,
# "paid_fee": 0,
# "executed_funds": 905111.9000,
# "trade_timestamp": 1727052318148,
# "order_timestamp": 1727052318074,
# "timestamp": 1727052318369,
# "stream_type": "REALTIME"
# }
#
messageHash = 'myOrder'
parsed = self.parse_ws_order(message)
symbol = self.safe_string(parsed, 'symbol')
# orderId = self.safe_string(parsed, 'id')
if self.orders is None:
limit = self.safe_integer(self.options, 'ordersLimit', 1000)
self.orders = ArrayCacheBySymbolById(limit)
cachedOrders = self.orders
cachedOrders.append(parsed)
client.resolve(cachedOrders, messageHash)
symbolSpecificMessageHash = messageHash + ':' + symbol
client.resolve(cachedOrders, symbolSpecificMessageHash)
def parse_ws_order(self, order, market=None):
#
# {
# "type": "myOrder",
# "code": "KRW-BTC",
# "uuid": "C0101000000001818113",
# "ask_bid": "BID",
# "order_type": "limit",
# "state": "trade",
# "trade_uuid": "C0101000000001744207",
# "price": 1927000,
# "volume": 0.4697,
# "remaining_volume": 0.0803,
# "executed_volume": 0.4697,
# "trades_count": 1,
# "reserved_fee": 0,
# "remaining_fee": 0,
# "paid_fee": 0,
# "executed_funds": 905111.9000,
# "trade_timestamp": 1727052318148,
# "order_timestamp": 1727052318074,
# "timestamp": 1727052318369,
# "stream_type": "REALTIME"
# }
#
marketId = self.safe_string(order, 'code')
symbol = self.safe_symbol(marketId, market, '-')
timestamp = self.safe_integer(order, 'order_timestamp')
sideId = self.safe_string(order, 'ask_bid')
side = ('buy') if (sideId == 'BID') else ('sell')
typeId = self.safe_string(order, 'order_type')
type = None
if typeId == 'limit':
type = 'limit'
elif typeId == 'price':
type = 'market'
elif typeId == 'market':
type = 'market'
stateId = self.safe_string(order, 'state')
status = None
if stateId == 'wait':
status = 'open'
elif stateId == 'trade':
status = 'open'
elif stateId == 'done':
status = 'closed'
elif stateId == 'cancel':
status = 'canceled'
price = self.safe_string(order, 'price')
amount = self.safe_string(order, 'volume')
remaining = self.safe_string(order, 'remaining_volume')
filled = self.safe_string(order, 'executed_volume')
cost = self.safe_string(order, 'executed_funds')
feeCost = self.safe_string(order, 'paid_fee')
fee = None
if feeCost is not None:
marketForFee = self.safe_market(marketId, market)
feeCurrency = self.safe_string(marketForFee, 'quote')
fee = {
'cost': feeCost,
'currency': feeCurrency,
}
return self.safe_order({
'info': order,
'id': self.safe_string(order, 'uuid'),
'clientOrderId': None,
'timestamp': timestamp,
'datetime': self.iso8601(timestamp),
'lastTradeTimestamp': self.safe_integer(order, 'trade_timestamp'),
'symbol': symbol,
'type': type,
'timeInForce': None,
'postOnly': None,
'side': side,
'price': price,
'stopPrice': None,
'triggerPrice': None,
'amount': amount,
'cost': cost,
'average': None,
'filled': filled,
'remaining': remaining,
'status': status,
'fee': fee,
'trades': None,
}, market)
def handle_message(self, client: Client, message):
if not self.handle_error_message(client, message):
return
topic = self.safe_string(message, 'type')
if topic is not None:
methods: dict = {
'ticker': self.handle_ticker,
'orderbookdepth': self.handle_order_book,
'transaction': self.handle_trades,
'myAsset': self.handle_balance,
'myOrder': self.handle_orders,
}
method = self.safe_value(methods, topic)
if method is not None:
method(client, message)

File diff suppressed because it is too large Load Diff

Some files were not shown because too many files have changed in this diff Show More