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

486 lines
20 KiB
Python

# -*- coding: utf-8 -*-
# PLEASE DO NOT EDIT THIS FILE, IT IS GENERATED AND WILL BE OVERWRITTEN:
# https://github.com/ccxt/ccxt/blob/master/CONTRIBUTING.md#how-to-contribute-code
import ccxt.async_support
from ccxt.async_support.base.ws.cache import ArrayCache, ArrayCacheByTimestamp
from ccxt.base.types import Any, Bool, Int, OrderBook, Strings, Ticker, Tickers, 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 BadRequest
class p2b(ccxt.async_support.p2b):
def describe(self) -> Any:
return self.deep_extend(super(p2b, self).describe(), {
'has': {
'ws': True,
'cancelAllOrdersWs': False,
'cancelOrdersWs': False,
'cancelOrderWs': False,
'createOrderWs': False,
'editOrderWs': False,
'fetchBalanceWs': False,
'fetchOpenOrdersWs': False,
'fetchOrderWs': False,
'fetchTradesWs': False,
'watchBalance': False,
'watchMyTrades': False,
'watchOHLCV': True,
'watchOrderBook': True,
'watchOrders': False,
# 'watchStatus': True,
'watchTicker': True,
'watchTickers': True,
'watchTrades': True,
'watchTradesForSymbols': True,
},
'urls': {
'api': {
'ws': 'wss://apiws.p2pb2b.com/',
},
},
'options': {
'OHLCVLimit': 1000,
'tradesLimit': 1000,
'timeframes': {
'15m': 900,
'30m': 1800,
'1h': 3600,
'1d': 86400,
},
'watchTicker': {
'name': 'state', # or 'price'
},
'watchTickers': {
'name': 'state', # or 'price'
},
'tickerSubs': self.create_safe_dictionary(),
},
'streaming': {
'ping': self.ping,
},
})
async def subscribe(self, name: str, messageHash: str, request, params={}):
"""
@ignore
Connects to a websocket channel
:param str name: name of the channel
:param str messageHash: string to look up in handler
:param str[]|float[] request: endpoint parameters
:param dict [params]: extra parameters specific to the p2b api
:returns dict: data from the websocket stream
"""
url = self.urls['api']['ws']
subscribe: dict = {
'method': name,
'params': request,
'id': self.milliseconds(),
}
query = self.extend(subscribe, params)
return await self.watch(url, messageHash, query, messageHash)
async def watch_ohlcv(self, symbol: str, timeframe: str = '15m', 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. Can only subscribe to one timeframe at a time for each symbol
https://github.com/P2B-team/P2B-WSS-Public/blob/main/wss_documentation.md#kline-candlestick
:param str symbol: unified symbol of the market to fetch OHLCV data for
:param str timeframe: 15m, 30m, 1h or 1d
: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()
timeframes = self.safe_value(self.options, 'timeframes', {})
channel = self.safe_integer(timeframes, timeframe)
if channel is None:
raise BadRequest(self.id + ' watchOHLCV cannot take a timeframe of ' + timeframe)
market = self.market(symbol)
request = [
market['id'],
channel,
]
messageHash = 'kline::' + market['symbol']
ohlcv = await self.subscribe('kline.subscribe', messageHash, request, params)
if self.newUpdates:
limit = ohlcv.getLimit(symbol, limit)
return self.filter_by_since_limit(ohlcv, since, limit, 0, True)
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://github.com/P2B-team/P2B-WSS-Public/blob/main/wss_documentation.md#last-price
https://github.com/P2B-team/P2B-WSS-Public/blob/main/wss_documentation.md#market-status
: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 dict [params.method]: 'state'(default) or 'price'
:returns dict: a `ticker structure <https://docs.ccxt.com/#/?id=ticker-structure>`
"""
await self.load_markets()
watchTickerOptions = self.safe_dict(self.options, 'watchTicker')
name = self.safe_string(watchTickerOptions, 'name', 'state') # or price
name, params = self.handle_option_and_params(params, 'method', 'name', name)
market = self.market(symbol)
symbol = market['symbol']
self.options['tickerSubs'][market['id']] = True # we need to re-subscribe to all tickers upon watching a new ticker
tickerSubs = self.options['tickerSubs']
request = list(tickerSubs.keys())
messageHash = name + '::' + market['symbol']
return await self.subscribe(name + '.subscribe', messageHash, request, params)
async def watch_tickers(self, symbols: Strings = None, params={}) -> Tickers:
"""
https://github.com/P2B-team/P2B-WSS-Public/blob/main/wss_documentation.md#last-price
https://github.com/P2B-team/P2B-WSS-Public/blob/main/wss_documentation.md#market-status
watches a price ticker, a statistical calculation with the information calculated over the past 24 hours for all markets of a specific list
:param str[] [symbols]: unified symbol of the market to fetch the ticker for
:param dict [params]: extra parameters specific to the exchange API endpoint
:param dict [params.method]: 'state'(default) or 'price'
:returns dict: a `ticker structure <https://docs.ccxt.com/#/?id=ticker-structure>`
"""
await self.load_markets()
symbols = self.market_symbols(symbols, None, False)
watchTickerOptions = self.safe_dict(self.options, 'watchTicker')
name = self.safe_string(watchTickerOptions, 'name', 'state') # or price
name, params = self.handle_option_and_params(params, 'method', 'name', name)
messageHashes = []
args = []
for i in range(0, len(symbols)):
market = self.market(symbols[i])
messageHashes.append(name + '::' + market['symbol'])
args.append(market['id'])
url = self.urls['api']['ws']
request: dict = {
'method': name + '.subscribe',
'params': args,
'id': self.milliseconds(),
}
await self.watch_multiple(url, messageHashes, self.extend(request, params), messageHashes)
return self.filter_by_array(self.tickers, 'symbol', symbols)
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://github.com/P2B-team/P2B-WSS-Public/blob/main/wss_documentation.md#deals
: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://github.com/P2B-team/P2B-WSS-Public/blob/main/wss_documentation.md#deals
: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
: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)
messageHashes = []
if symbols is not None:
for i in range(0, len(symbols)):
messageHashes.append('deals::' + symbols[i])
marketIds = self.market_ids(symbols)
url = self.urls['api']['ws']
subscribe: dict = {
'method': 'deals.subscribe',
'params': marketIds,
'id': self.milliseconds(),
}
query = self.extend(subscribe, params)
trades = await self.watch_multiple(url, messageHashes, query, messageHashes)
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)
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://github.com/P2B-team/P2B-WSS-Public/blob/main/wss_documentation.md#depth-of-market
:param str symbol: unified symbol of the market to fetch the order book for
:param int [limit]: 1-100, default=100
:param dict [params]: extra parameters specific to the exchange API endpoint
:param float [params.interval]: 0, 0.00000001, 0.0000001, 0.000001, 0.00001, 0.0001, 0.001, 0.01, 0.1, interval of precision for order, default=0.001
: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)
name = 'depth.subscribe'
messageHash = 'orderbook::' + market['symbol']
interval = self.safe_string(params, 'interval', '0.001')
if limit is None:
limit = 100
request = [
market['id'],
limit,
interval,
]
orderbook = await self.subscribe(name, messageHash, request, params)
return orderbook.limit()
def handle_ohlcv(self, client: Client, message):
#
# {
# "method": "kline.update",
# "params": [
# [
# 1657648800, # Kline start time
# "0.054146", # Kline open price
# "0.053938", # Kline close price(current price)
# "0.054146", # Kline high price
# "0.053911", # Kline low price
# "596.4674", # Volume for stock currency
# "32.2298758767", # Volume for money currency
# "ETH_BTC" # Market
# ]
# ],
# "id": null
# }
#
data = self.safe_list(message, 'params')
data = self.safe_list(data, 0)
method = self.safe_string(message, 'method')
splitMethod = method.split('.')
channel = self.safe_string(splitMethod, 0)
marketId = self.safe_string(data, 7)
market = self.safe_market(marketId)
timeframes = self.safe_dict(self.options, 'timeframes', {})
timeframe = self.find_timeframe(channel, timeframes)
symbol = self.safe_string(market, 'symbol')
messageHash = channel + '::' + symbol
parsed = self.parse_ohlcv(data, market)
self.ohlcvs[symbol] = self.safe_value(self.ohlcvs, symbol, {})
stored = self.safe_value(self.ohlcvs[symbol], timeframe)
if symbol is not None:
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
def handle_trade(self, client: Client, message):
#
# {
# "method": "deals.update",
# "params": [
# "ETH_BTC",
# [
# {
# "id": 4503032979, # Order_id
# "amount": "0.103",
# "type": "sell", # Side
# "time": 1657661950.8487639, # Creation time
# "price": "0.05361"
# },
# ...
# ]
# ],
# "id": null
# }
#
data = self.safe_list(message, 'params', [])
trades = self.safe_list(data, 1)
marketId = self.safe_string(data, 0)
market = self.safe_market(marketId)
symbol = self.safe_string(market, 'symbol')
tradesArray = self.safe_value(self.trades, symbol)
if tradesArray is None:
tradesLimit = self.safe_integer(self.options, 'tradesLimit', 1000)
tradesArray = ArrayCache(tradesLimit)
self.trades[symbol] = tradesArray
for i in range(0, len(trades)):
item = trades[i]
trade = self.parse_trade(item, market)
tradesArray.append(trade)
messageHash = 'deals::' + symbol
client.resolve(tradesArray, messageHash)
return message
def handle_ticker(self, client: Client, message):
#
# state
#
# {
# "method": "state.update",
# "params": [
# "ETH_BTC",
# {
# "high": "0.055774", # High price for the last 24h
# "close": "0.053679", # Close price for the last 24h
# "low": "0.053462", # Low price for the last 24h
# "period": 86400, # Period 24h
# "last": "0.053679", # Last price for the last 24h
# "volume": "38463.6132", # Stock volume for the last 24h
# "open": "0.055682", # Open price for the last 24h
# "deal": "2091.0038055314" # Money volume for the last 24h
# }
# ],
# "id": null
# }
#
# price
#
# {
# "method": "price.update",
# "params": [
# "ETH_BTC", # market
# "0.053836" # last price
# ],
# "id": null
# }
#
data = self.safe_list(message, 'params', [])
marketId = self.safe_string(data, 0)
market = self.safe_market(marketId)
method = self.safe_string(message, 'method')
splitMethod = method.split('.')
messageHashStart = self.safe_string(splitMethod, 0)
tickerData = self.safe_dict(data, 1)
ticker = None
if method == 'price.update':
lastPrice = self.safe_string(data, 1)
ticker = self.safe_ticker({
'last': lastPrice,
'close': lastPrice,
'symbol': market['symbol'],
})
else:
ticker = self.parse_ticker(tickerData, market)
symbol = ticker['symbol']
self.tickers[symbol] = ticker
messageHash = messageHashStart + '::' + symbol
client.resolve(ticker, messageHash)
return message
def handle_order_book(self, client: Client, message):
#
# {
# "method": "depth.update",
# "params": [
# False, # True - all records, False - new records
# {
# "asks": [ # side
# [
# "19509.81", # price
# "0.277" # amount
# ]
# ]
# },
# "BTC_USDT"
# ],
# "id": null
# }
#
params = self.safe_list(message, 'params', [])
data = self.safe_dict(params, 1)
asks = self.safe_list(data, 'asks')
bids = self.safe_list(data, 'bids')
marketId = self.safe_string(params, 2)
market = self.safe_market(marketId)
symbol = market['symbol']
messageHash = 'orderbook::' + market['symbol']
subscription = self.safe_value(client.subscriptions, messageHash, {})
limit = self.safe_integer(subscription, 'limit')
orderbook = self.safe_value(self.orderbooks, symbol)
if orderbook is None:
self.orderbooks[symbol] = self.order_book({}, limit)
orderbook = self.orderbooks[symbol]
if bids is not None:
for i in range(0, len(bids)):
bid = self.safe_value(bids, i)
price = self.safe_number(bid, 0)
amount = self.safe_number(bid, 1)
bookSide = orderbook['bids']
bookSide.store(price, amount)
if asks is not None:
for i in range(0, len(asks)):
ask = self.safe_value(asks, i)
price = self.safe_number(ask, 0)
amount = self.safe_number(ask, 1)
bookside = orderbook['asks']
bookside.store(price, amount)
orderbook['symbol'] = symbol
client.resolve(orderbook, messageHash)
def handle_message(self, client: Client, message):
if self.handle_error_message(client, message):
return
result = self.safe_string(message, 'result')
if result == 'pong':
self.handle_pong(client, message)
return
method = self.safe_string(message, 'method')
methods: dict = {
'depth.update': self.handle_order_book,
'price.update': self.handle_ticker,
'kline.update': self.handle_ohlcv,
'state.update': self.handle_ticker,
'deals.update': self.handle_trade,
}
endpoint = self.safe_value(methods, method)
if endpoint is not None:
endpoint(client, message)
def handle_error_message(self, client: Client, message) -> Bool:
error = self.safe_string(message, 'error')
if error is not None:
raise ExchangeError(self.id + ' error: ' + self.json(error))
return False
def ping(self, client: Client):
"""
https://github.com/P2B-team/P2B-WSS-Public/blob/main/wss_documentation.md#ping
@param client
"""
return {
'method': 'server.ping',
'params': [],
'id': self.milliseconds(),
}
def handle_pong(self, client: Client, message):
#
# {
# error: null,
# result: 'pong',
# id: 1706539608030
# }
#
client.lastPong = self.safe_integer(message, 'id')
return message
def on_error(self, client: Client, error):
self.options['tickerSubs'] = self.create_safe_dictionary()
super(p2b, self).on_error(client, error)
def on_close(self, client: Client, error):
self.options['tickerSubs'] = self.create_safe_dictionary()
super(p2b, self).on_close(client, error)