ccxt
Version:
507 lines (504 loc) • 22.3 kB
JavaScript
// ----------------------------------------------------------------------------
// 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
// EDIT THE CORRESPONDENT .ts FILE INSTEAD
// ---------------------------------------------------------------------------
import p2bRest from '../p2b.js';
import { BadRequest, ExchangeError } from '../base/errors.js';
import { ArrayCache, ArrayCacheByTimestamp } from '../base/ws/Cache.js';
// ---------------------------------------------------------------------------
export default class p2b extends p2bRest {
describe() {
return this.deepExtend(super.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': this.createSafeDictionary(),
},
'streaming': {
'ping': this.ping,
},
});
}
/**
* @ignore
* @method
* @description Connects to a websocket channel
* @param {string} name name of the channel
* @param {string} messageHash string to look up in handler
* @param {string[]|float[]} request endpoint parameters
* @param {object} [params] extra parameters specific to the p2b api
* @returns {object} data from the websocket stream
*/
async subscribe(name, messageHash, request, params = {}) {
const url = this.urls['api']['ws'];
const subscribe = {
'method': name,
'params': request,
'id': this.milliseconds(),
};
const query = this.extend(subscribe, params);
return await this.watch(url, messageHash, query, messageHash);
}
/**
* @method
* @name p2b#watchOHLCV
* @description 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
* @see https://github.com/P2B-team/P2B-WSS-Public/blob/main/wss_documentation.md#kline-candlestick
* @param {string} symbol unified symbol of the market to fetch OHLCV data for
* @param {string} 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 {object} [params] extra parameters specific to the exchange API endpoint
* @returns {int[][]} A list of candles ordered as timestamp, open, high, low, close, volume
*/
async watchOHLCV(symbol, timeframe = '15m', since = undefined, limit = undefined, params = {}) {
await this.loadMarkets();
const timeframes = this.safeValue(this.options, 'timeframes', {});
const channel = this.safeInteger(timeframes, timeframe);
if (channel === undefined) {
throw new BadRequest(this.id + ' watchOHLCV cannot take a timeframe of ' + timeframe);
}
const market = this.market(symbol);
const request = [
market['id'],
channel,
];
const messageHash = 'kline::' + market['symbol'];
const ohlcv = await this.subscribe('kline.subscribe', messageHash, request, params);
if (this.newUpdates) {
limit = ohlcv.getLimit(symbol, limit);
}
return this.filterBySinceLimit(ohlcv, since, limit, 0, true);
}
/**
* @method
* @name p2b#watchTicker
* @description watches a price ticker, a statistical calculation with the information calculated over the past 24 hours for a specific market
* @see https://github.com/P2B-team/P2B-WSS-Public/blob/main/wss_documentation.md#last-price
* @see https://github.com/P2B-team/P2B-WSS-Public/blob/main/wss_documentation.md#market-status
* @param {string} symbol unified symbol of the market to fetch the ticker for
* @param {object} [params] extra parameters specific to the exchange API endpoint
* @param {object} [params.method] 'state' (default) or 'price'
* @returns {object} a [ticker structure]{@link https://docs.ccxt.com/#/?id=ticker-structure}
*/
async watchTicker(symbol, params = {}) {
await this.loadMarkets();
const watchTickerOptions = this.safeDict(this.options, 'watchTicker');
let name = this.safeString(watchTickerOptions, 'name', 'state'); // or price
[name, params] = this.handleOptionAndParams(params, 'method', 'name', name);
const market = this.market(symbol);
symbol = market['symbol'];
this.options['tickerSubs'][market['id']] = true; // we need to re-subscribe to all tickers upon watching a new ticker
const tickerSubs = this.options['tickerSubs'];
const request = Object.keys(tickerSubs);
const messageHash = name + '::' + market['symbol'];
return await this.subscribe(name + '.subscribe', messageHash, request, params);
}
/**
* @method
* @name p2b#watchTickers
* @see https://github.com/P2B-team/P2B-WSS-Public/blob/main/wss_documentation.md#last-price
* @see https://github.com/P2B-team/P2B-WSS-Public/blob/main/wss_documentation.md#market-status
* @description watches a price ticker, a statistical calculation with the information calculated over the past 24 hours for all markets of a specific list
* @param {string[]} [symbols] unified symbol of the market to fetch the ticker for
* @param {object} [params] extra parameters specific to the exchange API endpoint
* @param {object} [params.method] 'state' (default) or 'price'
* @returns {object} a [ticker structure]{@link https://docs.ccxt.com/#/?id=ticker-structure}
*/
async watchTickers(symbols = undefined, params = {}) {
await this.loadMarkets();
symbols = this.marketSymbols(symbols, undefined, false);
const watchTickerOptions = this.safeDict(this.options, 'watchTicker');
let name = this.safeString(watchTickerOptions, 'name', 'state'); // or price
[name, params] = this.handleOptionAndParams(params, 'method', 'name', name);
const messageHashes = [];
const args = [];
for (let i = 0; i < symbols.length; i++) {
const market = this.market(symbols[i]);
messageHashes.push(name + '::' + market['symbol']);
args.push(market['id']);
}
const url = this.urls['api']['ws'];
const request = {
'method': name + '.subscribe',
'params': args,
'id': this.milliseconds(),
};
await this.watchMultiple(url, messageHashes, this.extend(request, params), messageHashes);
return this.filterByArray(this.tickers, 'symbol', symbols);
}
/**
* @method
* @name p2b#watchTrades
* @description get the list of most recent trades for a particular symbol
* @see https://github.com/P2B-team/P2B-WSS-Public/blob/main/wss_documentation.md#deals
* @param {string} 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 {object} [params] extra parameters specific to the exchange API endpoint
* @returns {object[]} a list of [trade structures]{@link https://docs.ccxt.com/#/?id=public-trades}
*/
async watchTrades(symbol, since = undefined, limit = undefined, params = {}) {
return await this.watchTradesForSymbols([symbol], since, limit, params);
}
/**
* @method
* @name p2b#watchTradesForSymbols
* @description get the list of most recent trades for a list of symbols
* @see https://github.com/P2B-team/P2B-WSS-Public/blob/main/wss_documentation.md#deals
* @param {string[]} 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 {object} [params] extra parameters specific to the exchange API endpoint
* @returns {object[]} a list of [trade structures]{@link https://docs.ccxt.com/#/?id=public-trades}
*/
async watchTradesForSymbols(symbols, since = undefined, limit = undefined, params = {}) {
await this.loadMarkets();
symbols = this.marketSymbols(symbols, undefined, false, true, true);
const messageHashes = [];
if (symbols !== undefined) {
for (let i = 0; i < symbols.length; i++) {
messageHashes.push('deals::' + symbols[i]);
}
}
const marketIds = this.marketIds(symbols);
const url = this.urls['api']['ws'];
const subscribe = {
'method': 'deals.subscribe',
'params': marketIds,
'id': this.milliseconds(),
};
const query = this.extend(subscribe, params);
const trades = await this.watchMultiple(url, messageHashes, query, messageHashes);
if (this.newUpdates) {
const first = this.safeValue(trades, 0);
const tradeSymbol = this.safeString(first, 'symbol');
limit = trades.getLimit(tradeSymbol, limit);
}
return this.filterBySinceLimit(trades, since, limit, 'timestamp', true);
}
/**
* @method
* @name p2b#watchOrderBook
* @description watches information on open orders with bid (buy) and ask (sell) prices, volumes and other data
* @see https://github.com/P2B-team/P2B-WSS-Public/blob/main/wss_documentation.md#depth-of-market
* @param {string} symbol unified symbol of the market to fetch the order book for
* @param {int} [limit] 1-100, default=100
* @param {object} [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 {object} A dictionary of [order book structures]{@link https://docs.ccxt.com/#/?id=order-book-structure} indexed by market symbols
*/
async watchOrderBook(symbol, limit = undefined, params = {}) {
await this.loadMarkets();
const market = this.market(symbol);
const name = 'depth.subscribe';
const messageHash = 'orderbook::' + market['symbol'];
const interval = this.safeString(params, 'interval', '0.001');
if (limit === undefined) {
limit = 100;
}
const request = [
market['id'],
limit,
interval,
];
const orderbook = await this.subscribe(name, messageHash, request, params);
return orderbook.limit();
}
handleOHLCV(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
// }
//
let data = this.safeList(message, 'params');
data = this.safeList(data, 0);
const method = this.safeString(message, 'method');
const splitMethod = method.split('.');
const channel = this.safeString(splitMethod, 0);
const marketId = this.safeString(data, 7);
const market = this.safeMarket(marketId);
const timeframes = this.safeDict(this.options, 'timeframes', {});
const timeframe = this.findTimeframe(channel, timeframes);
const symbol = this.safeString(market, 'symbol');
const messageHash = channel + '::' + symbol;
const parsed = this.parseOHLCV(data, market);
this.ohlcvs[symbol] = this.safeValue(this.ohlcvs, symbol, {});
let stored = this.safeValue(this.ohlcvs[symbol], timeframe);
if (symbol !== undefined) {
if (stored === undefined) {
const limit = this.safeInteger(this.options, 'OHLCVLimit', 1000);
stored = new ArrayCacheByTimestamp(limit);
this.ohlcvs[symbol][timeframe] = stored;
}
stored.append(parsed);
client.resolve(stored, messageHash);
}
return message;
}
handleTrade(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
// }
//
const data = this.safeList(message, 'params', []);
const trades = this.safeList(data, 1);
const marketId = this.safeString(data, 0);
const market = this.safeMarket(marketId);
const symbol = this.safeString(market, 'symbol');
let tradesArray = this.safeValue(this.trades, symbol);
if (tradesArray === undefined) {
const tradesLimit = this.safeInteger(this.options, 'tradesLimit', 1000);
tradesArray = new ArrayCache(tradesLimit);
this.trades[symbol] = tradesArray;
}
for (let i = 0; i < trades.length; i++) {
const item = trades[i];
const trade = this.parseTrade(item, market);
tradesArray.append(trade);
}
const messageHash = 'deals::' + symbol;
client.resolve(tradesArray, messageHash);
return message;
}
handleTicker(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
// }
//
const data = this.safeList(message, 'params', []);
const marketId = this.safeString(data, 0);
const market = this.safeMarket(marketId);
const method = this.safeString(message, 'method');
const splitMethod = method.split('.');
const messageHashStart = this.safeString(splitMethod, 0);
const tickerData = this.safeDict(data, 1);
let ticker = undefined;
if (method === 'price.update') {
const lastPrice = this.safeString(data, 1);
ticker = this.safeTicker({
'last': lastPrice,
'close': lastPrice,
'symbol': market['symbol'],
});
}
else {
ticker = this.parseTicker(tickerData, market);
}
const symbol = ticker['symbol'];
this.tickers[symbol] = ticker;
const messageHash = messageHashStart + '::' + symbol;
client.resolve(ticker, messageHash);
return message;
}
handleOrderBook(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
// }
//
const params = this.safeList(message, 'params', []);
const data = this.safeDict(params, 1);
const asks = this.safeList(data, 'asks');
const bids = this.safeList(data, 'bids');
const marketId = this.safeString(params, 2);
const market = this.safeMarket(marketId);
const symbol = market['symbol'];
const messageHash = 'orderbook::' + market['symbol'];
const subscription = this.safeValue(client.subscriptions, messageHash, {});
const limit = this.safeInteger(subscription, 'limit');
let orderbook = this.safeValue(this.orderbooks, symbol);
if (orderbook === undefined) {
this.orderbooks[symbol] = this.orderBook({}, limit);
orderbook = this.orderbooks[symbol];
}
if (bids !== undefined) {
for (let i = 0; i < bids.length; i++) {
const bid = this.safeValue(bids, i);
const price = this.safeNumber(bid, 0);
const amount = this.safeNumber(bid, 1);
const bookSide = orderbook['bids'];
bookSide.store(price, amount);
}
}
if (asks !== undefined) {
for (let i = 0; i < asks.length; i++) {
const ask = this.safeValue(asks, i);
const price = this.safeNumber(ask, 0);
const amount = this.safeNumber(ask, 1);
const bookside = orderbook['asks'];
bookside.store(price, amount);
}
}
orderbook['symbol'] = symbol;
client.resolve(orderbook, messageHash);
}
handleMessage(client, message) {
if (this.handleErrorMessage(client, message)) {
return;
}
const result = this.safeString(message, 'result');
if (result === 'pong') {
this.handlePong(client, message);
return;
}
const method = this.safeString(message, 'method');
const methods = {
'depth.update': this.handleOrderBook,
'price.update': this.handleTicker,
'kline.update': this.handleOHLCV,
'state.update': this.handleTicker,
'deals.update': this.handleTrade,
};
const endpoint = this.safeValue(methods, method);
if (endpoint !== undefined) {
endpoint.call(this, client, message);
}
}
handleErrorMessage(client, message) {
const error = this.safeString(message, 'error');
if (error !== undefined) {
throw new ExchangeError(this.id + ' error: ' + this.json(error));
}
return false;
}
ping(client) {
/**
* @see https://github.com/P2B-team/P2B-WSS-Public/blob/main/wss_documentation.md#ping
* @param client
*/
return {
'method': 'server.ping',
'params': [],
'id': this.milliseconds(),
};
}
handlePong(client, message) {
//
// {
// error: null,
// result: 'pong',
// id: 1706539608030
// }
//
client.lastPong = this.safeInteger(message, 'id');
return message;
}
onError(client, error) {
this.options['tickerSubs'] = this.createSafeDictionary();
super.onError(client, error);
}
onClose(client, error) {
this.options['tickerSubs'] = this.createSafeDictionary();
super.onClose(client, error);
}
}