ccxt 4.1.22 → 4.1.24
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +7 -3
- package/dist/ccxt.browser.js +111 -43
- package/dist/ccxt.browser.min.js +2 -2
- package/dist/cjs/ccxt.js +1 -1
- package/dist/cjs/src/ascendex.js +1 -0
- package/dist/cjs/src/base/ws/OrderBookSide.js +20 -4
- package/dist/cjs/src/binance.js +4 -29
- package/dist/cjs/src/bitmart.js +1 -1
- package/dist/cjs/src/bybit.js +4 -2
- package/dist/cjs/src/krakenfutures.js +72 -2
- package/dist/cjs/src/pro/bitfinex2.js +8 -4
- package/js/ccxt.d.ts +1 -1
- package/js/ccxt.js +1 -1
- package/js/src/abstract/ascendex.d.ts +1 -0
- package/js/src/abstract/binance.d.ts +1 -14
- package/js/src/abstract/binancecoinm.d.ts +1 -14
- package/js/src/abstract/binanceus.d.ts +1 -14
- package/js/src/abstract/binanceusdm.d.ts +1 -14
- package/js/src/ascendex.js +1 -0
- package/js/src/base/ws/OrderBookSide.js +20 -4
- package/js/src/binance.js +4 -29
- package/js/src/bitmart.js +1 -1
- package/js/src/bybit.js +4 -2
- package/js/src/krakenfutures.d.ts +1 -0
- package/js/src/krakenfutures.js +72 -2
- package/js/src/pro/bitfinex2.js +8 -4
- package/package.json +1 -1
- package/skip-tests.json +2 -1
- package/js/src/bkex.d.ts +0 -95
- package/js/src/bkex.js +0 -1962
- package/js/src/pro/btcex.d.ts +0 -32
- package/js/src/pro/btcex.js +0 -776
- package/js/src/pro/ripio.d.ts +0 -18
- package/js/src/pro/ripio.js +0 -296
- package/js/src/pro/zb.d.ts +0 -22
- package/js/src/pro/zb.js +0 -605
package/js/src/pro/btcex.js
DELETED
|
@@ -1,776 +0,0 @@
|
|
|
1
|
-
// ----------------------------------------------------------------------------
|
|
2
|
-
|
|
3
|
-
// PLEASE DO NOT EDIT THIS FILE, IT IS GENERATED AND WILL BE OVERWRITTEN:
|
|
4
|
-
// https://github.com/ccxt/ccxt/blob/master/CONTRIBUTING.md#how-to-contribute-code
|
|
5
|
-
// EDIT THE CORRESPONDENT .ts FILE INSTEAD
|
|
6
|
-
|
|
7
|
-
// ---------------------------------------------------------------------------
|
|
8
|
-
import btcexRest from '../btcex.js';
|
|
9
|
-
import { NotSupported, ExchangeError, ArgumentsRequired } from '../base/errors.js';
|
|
10
|
-
import { ArrayCache, ArrayCacheBySymbolById, ArrayCacheByTimestamp } from '../base/ws/Cache.js';
|
|
11
|
-
// ---------------------------------------------------------------------------
|
|
12
|
-
export default class btcex extends btcexRest {
|
|
13
|
-
describe() {
|
|
14
|
-
return this.deepExtend(super.describe(), {
|
|
15
|
-
'has': {
|
|
16
|
-
'ws': true,
|
|
17
|
-
'watchBalance': true,
|
|
18
|
-
'watchTicker': true,
|
|
19
|
-
'watchTickers': false,
|
|
20
|
-
'watchTrades': true,
|
|
21
|
-
'watchMyTrades': true,
|
|
22
|
-
'watchOrders': true,
|
|
23
|
-
'watchOrderBook': true,
|
|
24
|
-
'watchOHLCV': true,
|
|
25
|
-
},
|
|
26
|
-
'urls': {
|
|
27
|
-
'api': {
|
|
28
|
-
'ws': 'wss://api.btcex.com/ws/api/v1',
|
|
29
|
-
},
|
|
30
|
-
},
|
|
31
|
-
'options': {
|
|
32
|
-
'watchOrderBook': {
|
|
33
|
-
'snapshotDelay': 0,
|
|
34
|
-
'maxRetries': 3,
|
|
35
|
-
},
|
|
36
|
-
},
|
|
37
|
-
'streaming': {
|
|
38
|
-
'ping': this.ping,
|
|
39
|
-
'keepAlive': 5000,
|
|
40
|
-
},
|
|
41
|
-
'exceptions': {},
|
|
42
|
-
'timeframes': {
|
|
43
|
-
'1m': '1',
|
|
44
|
-
'3m': '3',
|
|
45
|
-
'5m': '4',
|
|
46
|
-
'10m': '10',
|
|
47
|
-
'15m': '15',
|
|
48
|
-
'30m': '30',
|
|
49
|
-
'1h': '60',
|
|
50
|
-
'2h': '120',
|
|
51
|
-
'3h': '180',
|
|
52
|
-
'4h': '240',
|
|
53
|
-
'6h': '360',
|
|
54
|
-
'12h': '720',
|
|
55
|
-
'1d': '1D',
|
|
56
|
-
},
|
|
57
|
-
});
|
|
58
|
-
}
|
|
59
|
-
requestId() {
|
|
60
|
-
const requestId = this.sum(this.safeInteger(this.options, 'requestId', 0), 1);
|
|
61
|
-
this.options['requestId'] = requestId;
|
|
62
|
-
return requestId.toString();
|
|
63
|
-
}
|
|
64
|
-
async watchBalance(params = {}) {
|
|
65
|
-
/**
|
|
66
|
-
* @method
|
|
67
|
-
* @name btcex#watchBalance
|
|
68
|
-
* @description query for balance and get the amount of funds available for trading or funds locked in orders
|
|
69
|
-
* @see https://docs.btcex.com/#user-asset-asset_type
|
|
70
|
-
* @param {object} params extra parameters specific to the btcex api endpoint
|
|
71
|
-
* @param {string} params.type asset type WALLET, BTC,ETH,MARGIN,SPOT,PERPETUAL
|
|
72
|
-
* @returns {object} a [balance structure]{@link https://docs.ccxt.com/en/latest/manual.html?#balance-structure}
|
|
73
|
-
*/
|
|
74
|
-
const token = await this.authenticate(params);
|
|
75
|
-
let type = undefined;
|
|
76
|
-
[type, params] = this.handleMarketTypeAndParams('watchBalance', undefined, params);
|
|
77
|
-
const types = this.safeValue(this.options, 'accountsByType', {});
|
|
78
|
-
const assetType = this.safeString(types, type, type);
|
|
79
|
-
params = this.omit(params, 'type');
|
|
80
|
-
const messageHash = 'balancess';
|
|
81
|
-
const url = this.urls['api']['ws'];
|
|
82
|
-
const subscribe = {
|
|
83
|
-
'jsonrpc': '2.0',
|
|
84
|
-
'id': this.requestId(),
|
|
85
|
-
'method': '/private/subscribe',
|
|
86
|
-
'params': {
|
|
87
|
-
'access_token': token,
|
|
88
|
-
'channels': [
|
|
89
|
-
'user.asset.' + assetType,
|
|
90
|
-
],
|
|
91
|
-
},
|
|
92
|
-
};
|
|
93
|
-
const request = this.deepExtend(subscribe, params);
|
|
94
|
-
return await this.watch(url, messageHash, request, messageHash, request);
|
|
95
|
-
}
|
|
96
|
-
handleBalance(client, message) {
|
|
97
|
-
//
|
|
98
|
-
// {
|
|
99
|
-
// "jsonrpc": "2.0",
|
|
100
|
-
// "method": "subscription",
|
|
101
|
-
// "params": {
|
|
102
|
-
// "channel": "user.asset.WALLET",
|
|
103
|
-
// "data": {
|
|
104
|
-
// "WALLET": {
|
|
105
|
-
// "total": "5578184962",
|
|
106
|
-
// "coupon": "0",
|
|
107
|
-
// "details": [
|
|
108
|
-
// {
|
|
109
|
-
// "available": "4999",
|
|
110
|
-
// "freeze": "0",
|
|
111
|
-
// "coin_type": "BTC",
|
|
112
|
-
// "current_mark_price": "38000"
|
|
113
|
-
// },
|
|
114
|
-
// ...
|
|
115
|
-
// ]
|
|
116
|
-
// }
|
|
117
|
-
// }
|
|
118
|
-
// }
|
|
119
|
-
// }
|
|
120
|
-
//
|
|
121
|
-
const params = this.safeValue(message, 'params', {});
|
|
122
|
-
const data = this.safeValue(params, 'data', {});
|
|
123
|
-
const messageHash = 'balancess';
|
|
124
|
-
this.balance = this.parseBalance(data);
|
|
125
|
-
client.resolve(this.balance, messageHash);
|
|
126
|
-
}
|
|
127
|
-
async watchOHLCV(symbol, timeframe = '1m', since = undefined, limit = undefined, params = {}) {
|
|
128
|
-
/**
|
|
129
|
-
* @method
|
|
130
|
-
* @name btcex#watchOHLCV
|
|
131
|
-
* @description watches historical candlestick data containing the open, high, low, and close price, and the volume of a market.
|
|
132
|
-
* @see https://docs.btcex.com/#chart-trades-instrument_name-resolution
|
|
133
|
-
* @param {string} symbol unified symbol of the market to fetch OHLCV data for
|
|
134
|
-
* @param {string} timeframe the length of time each candle represents.
|
|
135
|
-
* @param {int|undefined} since timestamp in ms of the earliest candle to fetch
|
|
136
|
-
* @param {int|undefined} limit the maximum amount of candles to fetch
|
|
137
|
-
* @param {object} params extra parameters specific to the bitfinex2 api endpoint
|
|
138
|
-
* @returns {[[int]]} A list of candles ordered as timestamp, open, high, low, close, volume
|
|
139
|
-
*/
|
|
140
|
-
await this.loadMarkets();
|
|
141
|
-
const market = this.market(symbol);
|
|
142
|
-
symbol = market['symbol'];
|
|
143
|
-
let instrumentName = market['id'];
|
|
144
|
-
if (market['spot']) {
|
|
145
|
-
instrumentName = market['baseId'] + '-' + market['quoteId'];
|
|
146
|
-
}
|
|
147
|
-
const interval = this.safeString(this.timeframes, timeframe, timeframe);
|
|
148
|
-
const messageHash = 'ohlcv:' + symbol + ':' + interval;
|
|
149
|
-
let request = {
|
|
150
|
-
'jsonrpc': '2.0',
|
|
151
|
-
'id': this.requestId(),
|
|
152
|
-
'method': '/public/subscribe',
|
|
153
|
-
'params': {
|
|
154
|
-
'channels': [
|
|
155
|
-
'chart.trades.' + instrumentName + '.' + interval,
|
|
156
|
-
],
|
|
157
|
-
},
|
|
158
|
-
};
|
|
159
|
-
request = this.deepExtend(request, params);
|
|
160
|
-
const url = this.urls['api']['ws'];
|
|
161
|
-
const ohlcv = await this.watch(url, messageHash, request, messageHash, request);
|
|
162
|
-
if (this.newUpdates) {
|
|
163
|
-
limit = ohlcv.getLimit(symbol, limit);
|
|
164
|
-
}
|
|
165
|
-
return this.filterBySinceLimit(ohlcv, since, limit, 0, true);
|
|
166
|
-
}
|
|
167
|
-
handleOHLCV(client, message) {
|
|
168
|
-
//
|
|
169
|
-
// {
|
|
170
|
-
// "params": {
|
|
171
|
-
// "data": {
|
|
172
|
-
// "tick": "1660095420",
|
|
173
|
-
// "open": "22890.30000000",
|
|
174
|
-
// "high": "22890.50000000",
|
|
175
|
-
// "low": "22886.50000000",
|
|
176
|
-
// "close": "22886.50000000",
|
|
177
|
-
// "volume": "314.46800000",
|
|
178
|
-
// "cost": "7197974.01690000"
|
|
179
|
-
// },
|
|
180
|
-
// "channel": "chart.trades.BTC-USDT-PERPETUAL.1"
|
|
181
|
-
// },
|
|
182
|
-
// "method": "subscription",
|
|
183
|
-
// "jsonrpc": "2.0"
|
|
184
|
-
// }
|
|
185
|
-
//
|
|
186
|
-
const params = this.safeValue(message, 'params');
|
|
187
|
-
const channel = this.safeString(params, 'channel');
|
|
188
|
-
const symbolInterval = channel.slice(13);
|
|
189
|
-
const dotIndex = symbolInterval.indexOf('.');
|
|
190
|
-
const marketId = symbolInterval.slice(0, dotIndex);
|
|
191
|
-
const timeframeId = symbolInterval.slice(dotIndex + 1);
|
|
192
|
-
const timeframe = this.findTimeframe(timeframeId);
|
|
193
|
-
const symbol = this.safeSymbol(marketId, undefined, '-');
|
|
194
|
-
const messageHash = 'ohlcv:' + symbol + ':' + timeframeId;
|
|
195
|
-
const data = this.safeValue(params, 'data', {});
|
|
196
|
-
const ohlcv = this.parseOHLCV(data);
|
|
197
|
-
this.ohlcvs[symbol] = this.safeValue(this.ohlcvs, symbol, {});
|
|
198
|
-
let stored = this.safeValue(this.ohlcvs[symbol], timeframe);
|
|
199
|
-
if (stored === undefined) {
|
|
200
|
-
const limit = this.safeInteger(this.options, 'OHLCVLimit', 1000);
|
|
201
|
-
stored = new ArrayCacheByTimestamp(limit);
|
|
202
|
-
this.ohlcvs[symbol][timeframe] = stored;
|
|
203
|
-
}
|
|
204
|
-
stored.append(ohlcv);
|
|
205
|
-
client.resolve(stored, messageHash);
|
|
206
|
-
}
|
|
207
|
-
async watchTicker(symbol, params = {}) {
|
|
208
|
-
/**
|
|
209
|
-
* @method
|
|
210
|
-
* @name btcex#watchTicker
|
|
211
|
-
* @description watches a price ticker, a statistical calculation with the information calculated over the past 24 hours for a specific market
|
|
212
|
-
* @see https://docs.btcex.com/#ticker-instrument_name-interval
|
|
213
|
-
* @param {string} symbol unified symbol of the market to fetch the ticker for
|
|
214
|
-
* @param {object} params extra parameters specific to the btcex api endpoint
|
|
215
|
-
* @returns {object} a [ticker structure]{@link https://docs.ccxt.com/#/?id=ticker-structure}
|
|
216
|
-
*/
|
|
217
|
-
await this.loadMarkets();
|
|
218
|
-
const market = this.market(symbol);
|
|
219
|
-
symbol = market['symbol'];
|
|
220
|
-
let instrumentName = market['id'];
|
|
221
|
-
if (market['spot']) {
|
|
222
|
-
instrumentName = market['baseId'] + '-' + market['quoteId'];
|
|
223
|
-
}
|
|
224
|
-
const url = this.urls['api']['ws'];
|
|
225
|
-
const messageHash = 'ticker:' + symbol;
|
|
226
|
-
let request = {
|
|
227
|
-
'jsonrpc': '2.0',
|
|
228
|
-
'id': this.requestId(),
|
|
229
|
-
'method': '/public/subscribe',
|
|
230
|
-
'params': {
|
|
231
|
-
'channels': [
|
|
232
|
-
'ticker.' + instrumentName + '.raw',
|
|
233
|
-
],
|
|
234
|
-
},
|
|
235
|
-
};
|
|
236
|
-
request = this.deepExtend(request, params);
|
|
237
|
-
return await this.watch(url, messageHash, request, messageHash);
|
|
238
|
-
}
|
|
239
|
-
handleTicker(client, message) {
|
|
240
|
-
//
|
|
241
|
-
// {
|
|
242
|
-
// "params": {
|
|
243
|
-
// "data": {
|
|
244
|
-
// "timestamp": "1660094543813",
|
|
245
|
-
// "stats": {
|
|
246
|
-
// "volume": "630219.70300000000008822",
|
|
247
|
-
// "price_change": "-0.0378",
|
|
248
|
-
// "low": "22659.50000000",
|
|
249
|
-
// "turnover": "14648416962.26930706016719341",
|
|
250
|
-
// "high": "23919.00000000"
|
|
251
|
-
// },
|
|
252
|
-
// "state": "open",
|
|
253
|
-
// "last_price": "22890.00000000",
|
|
254
|
-
// "instrument_name": "BTC-USDT-PERPETUAL",
|
|
255
|
-
// "best_bid_price": "22888.60000000",
|
|
256
|
-
// "best_bid_amount": "33.38500000",
|
|
257
|
-
// "best_ask_price": "22889.40000000",
|
|
258
|
-
// "best_ask_amount": "5.45200000",
|
|
259
|
-
// "mark_price": "22890.5",
|
|
260
|
-
// "underlying_price": "22891",
|
|
261
|
-
// "open_interest": "33886.083"
|
|
262
|
-
// },
|
|
263
|
-
// "channel": "ticker.BTC-USDT-PERPETUAL.raw"
|
|
264
|
-
// },
|
|
265
|
-
// "method": "subscription",
|
|
266
|
-
// "jsonrpc": "2.0"
|
|
267
|
-
// }
|
|
268
|
-
//
|
|
269
|
-
const params = this.safeValue(message, 'params');
|
|
270
|
-
const data = this.safeValue(params, 'data');
|
|
271
|
-
const ticker = this.parseTicker(data);
|
|
272
|
-
const symbol = this.safeString(ticker, 'symbol');
|
|
273
|
-
const messageHash = 'ticker:' + symbol;
|
|
274
|
-
this.tickers[symbol] = ticker;
|
|
275
|
-
client.resolve(ticker, messageHash);
|
|
276
|
-
}
|
|
277
|
-
async watchTrades(symbol, since = undefined, limit = undefined, params = {}) {
|
|
278
|
-
/**
|
|
279
|
-
* @method
|
|
280
|
-
* @name btcex#watchTrades
|
|
281
|
-
* @description get the list of most recent trades for a particular symbol
|
|
282
|
-
* @see https://docs.btcex.com/#trades-instrument_name-interval
|
|
283
|
-
* @param {string} symbol unified symbol of the market to fetch trades for
|
|
284
|
-
* @param {int|undefined} since timestamp in ms of the earliest trade to fetch
|
|
285
|
-
* @param {int|undefined} limit the maximum amount of trades to fetch
|
|
286
|
-
* @param {object} params extra parameters specific to the btcex api endpoint
|
|
287
|
-
* @returns {[object]} a list of [trade structures]{@link https://docs.ccxt.com/en/latest/manual.html?#public-trades}
|
|
288
|
-
*/
|
|
289
|
-
await this.loadMarkets();
|
|
290
|
-
const market = this.market(symbol);
|
|
291
|
-
symbol = market['symbol'];
|
|
292
|
-
const url = this.urls['api']['ws'];
|
|
293
|
-
const messageHash = 'trades:' + symbol;
|
|
294
|
-
let request = {
|
|
295
|
-
'jsonrpc': '2.0',
|
|
296
|
-
'id': this.requestId(),
|
|
297
|
-
'method': '/public/subscribe',
|
|
298
|
-
'params': {
|
|
299
|
-
'channels': [
|
|
300
|
-
'trades.' + market['id'] + '.raw',
|
|
301
|
-
],
|
|
302
|
-
},
|
|
303
|
-
};
|
|
304
|
-
request = this.deepExtend(request, params);
|
|
305
|
-
const trades = await this.watch(url, messageHash, request, messageHash, request);
|
|
306
|
-
if (this.newUpdates) {
|
|
307
|
-
limit = trades.getLimit(symbol, limit);
|
|
308
|
-
}
|
|
309
|
-
return this.filterBySinceLimit(trades, since, limit, 'timestamp', true);
|
|
310
|
-
}
|
|
311
|
-
handleTrades(client, message) {
|
|
312
|
-
//
|
|
313
|
-
// {
|
|
314
|
-
// "jsonrpc": "2.0",
|
|
315
|
-
// "method": "subscription",
|
|
316
|
-
// "params": {
|
|
317
|
-
// "channel": "trades.BTC-USDT-PERPETUAL.raw",
|
|
318
|
-
// "data": [{
|
|
319
|
-
// "timestamp": "1660093462553",
|
|
320
|
-
// "price": "22815.9",
|
|
321
|
-
// "amount": "4.479",
|
|
322
|
-
// "iv": "0",
|
|
323
|
-
// "direction": "sell",
|
|
324
|
-
// "instrument_name": "BTC-USDT-PERPETUAL",
|
|
325
|
-
// "trade_id": "227976617",
|
|
326
|
-
// "mark_price": "22812.7"
|
|
327
|
-
// }]
|
|
328
|
-
// }
|
|
329
|
-
// }
|
|
330
|
-
//
|
|
331
|
-
const params = this.safeValue(message, 'params', {});
|
|
332
|
-
const fullChannel = this.safeString(params, 'channel');
|
|
333
|
-
const parts = fullChannel.split('.');
|
|
334
|
-
const marketId = parts[1];
|
|
335
|
-
const symbol = this.safeSymbol(marketId);
|
|
336
|
-
const messageHash = 'trades:' + symbol;
|
|
337
|
-
let stored = this.safeValue(this.trades, symbol);
|
|
338
|
-
if (stored === undefined) {
|
|
339
|
-
const limit = this.safeInteger(this.options, 'tradesLimit', 1000);
|
|
340
|
-
stored = new ArrayCache(limit);
|
|
341
|
-
this.trades[symbol] = stored;
|
|
342
|
-
}
|
|
343
|
-
const rawTrades = this.safeValue(params, 'data', []);
|
|
344
|
-
for (let i = 0; i < rawTrades.length; i++) {
|
|
345
|
-
const rawTrade = rawTrades[i];
|
|
346
|
-
const trade = this.parseTrade(rawTrade, undefined);
|
|
347
|
-
stored.append(trade);
|
|
348
|
-
}
|
|
349
|
-
this.trades[symbol] = stored;
|
|
350
|
-
client.resolve(stored, messageHash);
|
|
351
|
-
}
|
|
352
|
-
async watchMyTrades(symbol = undefined, since = undefined, limit = undefined, params = {}) {
|
|
353
|
-
/**
|
|
354
|
-
* @method
|
|
355
|
-
* @name bibox#fetchMyTrades
|
|
356
|
-
* @description watch all trades made by the user
|
|
357
|
-
* @see https://docs.btcex.com/#user-trades-instrument_name-interval
|
|
358
|
-
* @param {string} symbol unified market symbol
|
|
359
|
-
* @param {int|undefined} since the earliest time in ms to fetch trades for
|
|
360
|
-
* @param {int|undefined} limit the maximum number of trades structures to retrieve
|
|
361
|
-
* @param {object} params extra parameters specific to the bibox api endpoint
|
|
362
|
-
* @returns {[object]} a list of [trade structures]{@link https://docs.ccxt.com/#/?id=trade-structure}
|
|
363
|
-
*/
|
|
364
|
-
if (symbol === undefined) {
|
|
365
|
-
throw new ArgumentsRequired(this.id + ' watchMyTrades() requires a symbol argument');
|
|
366
|
-
}
|
|
367
|
-
await this.loadMarkets();
|
|
368
|
-
const token = await this.authenticate();
|
|
369
|
-
const market = this.market(symbol);
|
|
370
|
-
symbol = market['symbol'];
|
|
371
|
-
const url = this.urls['api']['ws'];
|
|
372
|
-
const messageHash = 'myTrades:' + symbol;
|
|
373
|
-
const request = {
|
|
374
|
-
'jsonrpc': '2.0',
|
|
375
|
-
'id': this.requestId(),
|
|
376
|
-
'method': '/private/subscribe',
|
|
377
|
-
'params': {
|
|
378
|
-
'access_token': token,
|
|
379
|
-
'channels': [
|
|
380
|
-
'user.trades.' + market['id'] + '.raw',
|
|
381
|
-
],
|
|
382
|
-
},
|
|
383
|
-
};
|
|
384
|
-
const trades = await this.watch(url, messageHash, request, messageHash);
|
|
385
|
-
if (this.newUpdates) {
|
|
386
|
-
limit = trades.getLimit(symbol, limit);
|
|
387
|
-
}
|
|
388
|
-
return this.filterBySymbolSinceLimit(trades, symbol, since, limit, true);
|
|
389
|
-
}
|
|
390
|
-
handleMyTrades(client, message) {
|
|
391
|
-
//
|
|
392
|
-
// {
|
|
393
|
-
// "jsonrpc": "2.0",
|
|
394
|
-
// "method": "subscription",
|
|
395
|
-
// "params": {
|
|
396
|
-
// "channel": "user.trades.BTC-14AUG20.raw",
|
|
397
|
-
// "data": [{
|
|
398
|
-
// "direction": "sell",
|
|
399
|
-
// "amount": "1",
|
|
400
|
-
// "price": "33000",
|
|
401
|
-
// "iv": "0",
|
|
402
|
-
// "fee": "0",
|
|
403
|
-
// "timestamp": 1626148488157,
|
|
404
|
-
// "trade_id": "1",
|
|
405
|
-
// "order_id": "160717710099746816",
|
|
406
|
-
// "instrument_name": "BTC-24SEP21",
|
|
407
|
-
// "order_type": "limit",
|
|
408
|
-
// "fee_coin_type": "USDT",
|
|
409
|
-
// "index_price": "33157.63"
|
|
410
|
-
// }]
|
|
411
|
-
// }
|
|
412
|
-
// }
|
|
413
|
-
//
|
|
414
|
-
const params = this.safeValue(message, 'params', {});
|
|
415
|
-
const channel = this.safeString(params, 'channel', '');
|
|
416
|
-
const endIndex = channel.indexOf('.raw');
|
|
417
|
-
const marketId = channel.slice(12, endIndex);
|
|
418
|
-
const symbol = this.safeSymbol(marketId, undefined, '-');
|
|
419
|
-
const rawTrades = this.safeValue(params, 'data', []);
|
|
420
|
-
let stored = this.myTrades;
|
|
421
|
-
if (stored === undefined) {
|
|
422
|
-
const limit = this.safeInteger(this.options, 'tradesLimit', 1000);
|
|
423
|
-
stored = new ArrayCacheBySymbolById(limit);
|
|
424
|
-
}
|
|
425
|
-
for (let i = 0; i < rawTrades.length; i++) {
|
|
426
|
-
const rawTrade = rawTrades[i];
|
|
427
|
-
const trade = this.parseTrade(rawTrade);
|
|
428
|
-
stored.append(trade);
|
|
429
|
-
}
|
|
430
|
-
this.myTrades = stored;
|
|
431
|
-
const messageHash = 'myTrades:' + symbol;
|
|
432
|
-
client.resolve(stored, messageHash);
|
|
433
|
-
}
|
|
434
|
-
async watchOrders(symbol = undefined, since = undefined, limit = undefined, params = {}) {
|
|
435
|
-
/**
|
|
436
|
-
* @method
|
|
437
|
-
* @name btcex#fetchOrders
|
|
438
|
-
* @description watches information on multiple orders made by the user
|
|
439
|
-
* @see https://docs.btcex.com/#user-changes-kind-currency-interval
|
|
440
|
-
* @param {string} symbol unified market symbol of the market orders were made in
|
|
441
|
-
* @param {int|undefined} since the earliest time in ms to fetch orders for
|
|
442
|
-
* @param {int|undefined} limit the maximum number of orde structures to retrieve
|
|
443
|
-
* @param {object} params extra parameters specific to the btcex api endpoint
|
|
444
|
-
* @returns {[object]} a list of [order structures]{@link https://docs.ccxt.com/#/?id=order-structure}
|
|
445
|
-
*/
|
|
446
|
-
if (symbol === undefined) {
|
|
447
|
-
throw new ArgumentsRequired(this.id + 'watchesOrders() requires a symbol');
|
|
448
|
-
}
|
|
449
|
-
await this.loadMarkets();
|
|
450
|
-
const token = await this.authenticate();
|
|
451
|
-
const market = this.market(symbol);
|
|
452
|
-
symbol = market['symbol'];
|
|
453
|
-
const url = this.urls['api']['ws'];
|
|
454
|
-
const message = {
|
|
455
|
-
'jsonrpc': '2.0',
|
|
456
|
-
'id': this.requestId(),
|
|
457
|
-
'method': '/private/subscribe',
|
|
458
|
-
'params': {
|
|
459
|
-
'access_token': token,
|
|
460
|
-
'channels': [
|
|
461
|
-
'user.orders.' + market['id'] + '.raw',
|
|
462
|
-
],
|
|
463
|
-
},
|
|
464
|
-
};
|
|
465
|
-
const messageHash = 'orders:' + symbol;
|
|
466
|
-
const request = this.deepExtend(message, params);
|
|
467
|
-
const orders = await this.watch(url, messageHash, request, messageHash);
|
|
468
|
-
if (this.newUpdates) {
|
|
469
|
-
limit = orders.getLimit(symbol, limit);
|
|
470
|
-
}
|
|
471
|
-
return this.filterBySymbolSinceLimit(orders, symbol, since, limit);
|
|
472
|
-
}
|
|
473
|
-
handleOrder(client, message) {
|
|
474
|
-
//
|
|
475
|
-
// {
|
|
476
|
-
// "jsonrpc": "2.0",
|
|
477
|
-
// "method": "subscription",
|
|
478
|
-
// "params": {
|
|
479
|
-
// "channel": "user.orders.BTC-14AUG20.raw",
|
|
480
|
-
// "data": {
|
|
481
|
-
// "amount": "1",
|
|
482
|
-
// "price": "11895.00",
|
|
483
|
-
// "direction": "buy",
|
|
484
|
-
// "version": 0,
|
|
485
|
-
// "order_state": "filled",
|
|
486
|
-
// "instrument_name": "BTC-14AUG20",
|
|
487
|
-
// "time_in_force": "good_til_cancelled",
|
|
488
|
-
// "last_update_timestamp": 1597130534567,
|
|
489
|
-
// "filled_amount": "1",
|
|
490
|
-
// "average_price": "11770.00",
|
|
491
|
-
// "order_id": "39007591615041536",
|
|
492
|
-
// "creation_timestamp": 1597130534567,
|
|
493
|
-
// "order_type": "limit"
|
|
494
|
-
// }
|
|
495
|
-
// }
|
|
496
|
-
//
|
|
497
|
-
const params = this.safeValue(message, 'params', {});
|
|
498
|
-
const rawOrder = this.safeValue(params, 'data', {});
|
|
499
|
-
let cachedOrders = this.orders;
|
|
500
|
-
if (cachedOrders === undefined) {
|
|
501
|
-
const limit = this.safeInteger(this.options, 'ordersLimit', 1000);
|
|
502
|
-
cachedOrders = new ArrayCacheBySymbolById(limit);
|
|
503
|
-
}
|
|
504
|
-
const order = this.parseOrder(rawOrder);
|
|
505
|
-
const symbol = this.safeString(order, 'symbol');
|
|
506
|
-
const messageHash = 'orders:' + symbol;
|
|
507
|
-
cachedOrders.append(order);
|
|
508
|
-
this.orders = cachedOrders;
|
|
509
|
-
client.resolve(this.orders, messageHash);
|
|
510
|
-
}
|
|
511
|
-
async watchOrderBook(symbol, limit = undefined, params = {}) {
|
|
512
|
-
/**
|
|
513
|
-
* @method
|
|
514
|
-
* @name btcex#watchOrderBook
|
|
515
|
-
* @description watches information on open orders with bid (buy) and ask (sell) prices, volumes and other data
|
|
516
|
-
* @see https://docs.btcex.com/#book-instrument_name-interval
|
|
517
|
-
* @param {string} symbol unified symbol of the market to fetch the order book for
|
|
518
|
-
* @param {int|undefined} limit the maximum amount of order book entries to return
|
|
519
|
-
* @param {objectConstructor} params extra parameters specific to the btcex api endpoint
|
|
520
|
-
* @param {string|undefined} params.type accepts l2 or l3 for level 2 or level 3 order book
|
|
521
|
-
* @returns {object} A dictionary of [order book structures]{@link https://docs.ccxt.com/#/?id=order-book-structure} indexed by market symbols
|
|
522
|
-
*/
|
|
523
|
-
await this.loadMarkets();
|
|
524
|
-
const market = this.market(symbol);
|
|
525
|
-
symbol = market['symbol'];
|
|
526
|
-
let instrumentName = market['id'];
|
|
527
|
-
if (market['spot']) {
|
|
528
|
-
instrumentName = market['baseId'] + '-' + market['quoteId'];
|
|
529
|
-
}
|
|
530
|
-
const url = this.urls['api']['ws'];
|
|
531
|
-
params = this.omit(params, 'type');
|
|
532
|
-
const messageHash = 'orderbook:' + symbol;
|
|
533
|
-
const subscribe = {
|
|
534
|
-
'jsonrpc': '2.0',
|
|
535
|
-
'id': this.requestId(),
|
|
536
|
-
'method': '/public/subscribe',
|
|
537
|
-
'params': {
|
|
538
|
-
'channels': [
|
|
539
|
-
'book.' + instrumentName + '.raw',
|
|
540
|
-
],
|
|
541
|
-
},
|
|
542
|
-
};
|
|
543
|
-
const request = this.deepExtend(subscribe, params);
|
|
544
|
-
const orderbook = await this.watch(url, messageHash, request, messageHash);
|
|
545
|
-
return orderbook.limit();
|
|
546
|
-
}
|
|
547
|
-
handleOrderBook(client, message) {
|
|
548
|
-
//
|
|
549
|
-
// {
|
|
550
|
-
// "params": {
|
|
551
|
-
// "data": {
|
|
552
|
-
// "timestamp": 1626056933600,
|
|
553
|
-
// "change_id": 1566764,
|
|
554
|
-
// "asks": [
|
|
555
|
-
// [
|
|
556
|
-
// "new",
|
|
557
|
-
// "34227.122",
|
|
558
|
-
// "0.00554"
|
|
559
|
-
// ],
|
|
560
|
-
// ...
|
|
561
|
-
// ],
|
|
562
|
-
// "bids": [
|
|
563
|
-
// [
|
|
564
|
-
// "delete",
|
|
565
|
-
// "34105.540",
|
|
566
|
-
// "0"
|
|
567
|
-
// ],
|
|
568
|
-
// ...
|
|
569
|
-
// ],
|
|
570
|
-
// "instrument_name": "BTC-USDT"
|
|
571
|
-
// },
|
|
572
|
-
// "channel": "book.BTC-USDT.raw"
|
|
573
|
-
// },
|
|
574
|
-
// "method": "subscription",
|
|
575
|
-
// "jsonrpc": "2.0"
|
|
576
|
-
// }
|
|
577
|
-
// `
|
|
578
|
-
const params = this.safeValue(message, 'params');
|
|
579
|
-
const data = this.safeValue(params, 'data');
|
|
580
|
-
const marketId = this.safeString(data, 'instrument_name');
|
|
581
|
-
const symbol = this.safeSymbol(marketId, undefined, '-');
|
|
582
|
-
const storedOrderBook = this.safeValue(this.orderbooks, symbol);
|
|
583
|
-
const nonce = this.safeInteger(storedOrderBook, 'nonce');
|
|
584
|
-
const deltaNonce = this.safeInteger(data, 'change_id');
|
|
585
|
-
const messageHash = 'orderbook:' + symbol;
|
|
586
|
-
if (nonce === undefined) {
|
|
587
|
-
const cacheLength = storedOrderBook.cache.length;
|
|
588
|
-
const snapshotDelay = this.handleOption('watchOrderBook', 'snapshotDelay', 0);
|
|
589
|
-
if (cacheLength === snapshotDelay) {
|
|
590
|
-
const limit = 0;
|
|
591
|
-
this.spawn(this.loadOrderBook, client, messageHash, symbol, limit);
|
|
592
|
-
}
|
|
593
|
-
storedOrderBook.cache.push(data);
|
|
594
|
-
return;
|
|
595
|
-
}
|
|
596
|
-
else if (deltaNonce <= nonce) {
|
|
597
|
-
return;
|
|
598
|
-
}
|
|
599
|
-
this.handleDelta(storedOrderBook, data);
|
|
600
|
-
client.resolve(storedOrderBook, messageHash);
|
|
601
|
-
}
|
|
602
|
-
getCacheIndex(orderBook, cache) {
|
|
603
|
-
const firstElement = cache[0];
|
|
604
|
-
let lastChangeId = this.safeInteger(firstElement, 'change_id');
|
|
605
|
-
const nonce = this.safeInteger(orderBook, 'nonce');
|
|
606
|
-
if (nonce < lastChangeId - 1) {
|
|
607
|
-
return -1;
|
|
608
|
-
}
|
|
609
|
-
for (let i = 0; i < cache.length; i++) {
|
|
610
|
-
const delta = cache[i];
|
|
611
|
-
lastChangeId = this.safeInteger(delta, 'change_id');
|
|
612
|
-
if (nonce === lastChangeId - 1) {
|
|
613
|
-
// nonce is inside the cache
|
|
614
|
-
// [ d, d, n, d ]
|
|
615
|
-
return i;
|
|
616
|
-
}
|
|
617
|
-
}
|
|
618
|
-
return cache.length;
|
|
619
|
-
}
|
|
620
|
-
handleDelta(orderbook, delta) {
|
|
621
|
-
const timestamp = this.safeInteger(delta, 'timestamp');
|
|
622
|
-
orderbook['timestamp'] = timestamp;
|
|
623
|
-
orderbook['datetime'] = this.iso8601(timestamp);
|
|
624
|
-
orderbook['nonce'] = this.safeInteger(delta, 'change_id');
|
|
625
|
-
const bids = this.safeValue(delta, 'bids', []);
|
|
626
|
-
const asks = this.safeValue(delta, 'asks', []);
|
|
627
|
-
const storedBids = orderbook['bids'];
|
|
628
|
-
const storedAsks = orderbook['asks'];
|
|
629
|
-
this.handleBidAsks(storedBids, bids);
|
|
630
|
-
this.handleBidAsks(storedAsks, asks);
|
|
631
|
-
}
|
|
632
|
-
handleBidAsks(bookSide, bidAsks) {
|
|
633
|
-
for (let i = 0; i < bidAsks.length; i++) {
|
|
634
|
-
const bidAsk = this.parseBidAsk(bidAsks[i], 1, 2);
|
|
635
|
-
bookSide.storeArray(bidAsk);
|
|
636
|
-
}
|
|
637
|
-
}
|
|
638
|
-
handleUser(client, message) {
|
|
639
|
-
const params = this.safeValue(message, 'params');
|
|
640
|
-
const fullChannel = this.safeString(params, 'channel');
|
|
641
|
-
const sliceUser = fullChannel.slice(5);
|
|
642
|
-
const endIndex = sliceUser.indexOf('.');
|
|
643
|
-
const userChannel = sliceUser.slice(0, endIndex);
|
|
644
|
-
const handlers = {
|
|
645
|
-
'asset': this.handleBalance,
|
|
646
|
-
'orders': this.handleOrder,
|
|
647
|
-
'trades': this.handleMyTrades,
|
|
648
|
-
};
|
|
649
|
-
const handler = this.safeValue(handlers, userChannel);
|
|
650
|
-
if (handler !== undefined) {
|
|
651
|
-
return handler.call(this, client, message);
|
|
652
|
-
}
|
|
653
|
-
throw new NotSupported(this.id + ' received an unsupported message: ' + this.json(message));
|
|
654
|
-
}
|
|
655
|
-
handleErrorMessage(client, message) {
|
|
656
|
-
//
|
|
657
|
-
// {
|
|
658
|
-
// id: '1',
|
|
659
|
-
// jsonrpc: '2.0',
|
|
660
|
-
// usIn: 1660140064049,
|
|
661
|
-
// usOut: 1660140064051,
|
|
662
|
-
// usDiff: 2,
|
|
663
|
-
// error: { code: 10000, message: 'Authentication Failure' }
|
|
664
|
-
// }
|
|
665
|
-
//
|
|
666
|
-
const error = this.safeValue(message, 'error', {});
|
|
667
|
-
throw new ExchangeError(this.id + ' error: ' + this.json(error));
|
|
668
|
-
}
|
|
669
|
-
handleAuthenticate(client, message) {
|
|
670
|
-
//
|
|
671
|
-
// {
|
|
672
|
-
// id: '1',
|
|
673
|
-
// jsonrpc: '2.0',
|
|
674
|
-
// usIn: 1660140846671,
|
|
675
|
-
// usOut: 1660140846688,
|
|
676
|
-
// usDiff: 17,
|
|
677
|
-
// result: {
|
|
678
|
-
// access_token: 'xxxxxx43jIXYrF3VSm90ar+f5n447M3ll82AiFO58L85pxb/DbVf6Bn4ZyBX1i1tM/KYFBJ234ZkrUkwImUIEu8vY1PBh5JqaaaaaeGnao=',
|
|
679
|
-
// token_type: 'bearer',
|
|
680
|
-
// refresh_token: '/I56sUOB/zwpwo8X8Q0Z234bW8Lz1YNlXOXSP6C+ZJDWR+49CjVPr0Z3PVXoL3BOB234WxXtTid+YmNjQ8OqGn1MM9pQL5TKZ97s49SvaRc=',
|
|
681
|
-
// expires_in: 604014,
|
|
682
|
-
// scope: 'account:read_write block_trade:read_write trade:read_write wallet:read_write',
|
|
683
|
-
// m: '00000000006e446c6b44694759735570786e5668387335431274546e633867474d647772717a463924a6d3746756951334b637459653970576d63693143e6e335972584e48594c74674c4d416872564a4d56424c347438737938736f4645747263315374454e73324e546d346e5651792b69696279336647347737413d3d'
|
|
684
|
-
// }
|
|
685
|
-
// }
|
|
686
|
-
//
|
|
687
|
-
const result = this.safeValue(message, 'result', {});
|
|
688
|
-
const expiresIn = this.safeInteger(result, 'expires_in', 0);
|
|
689
|
-
this.options['expiresAt'] = this.sum(this.seconds(), expiresIn) * 1000;
|
|
690
|
-
const accessToken = this.safeString(result, 'access_token');
|
|
691
|
-
client.resolve(accessToken, 'authenticated');
|
|
692
|
-
}
|
|
693
|
-
handleSubscription(client, message) {
|
|
694
|
-
const channels = this.safeValue(message, 'result', []);
|
|
695
|
-
for (let i = 0; i < channels.length; i++) {
|
|
696
|
-
const fullChannel = channels[i];
|
|
697
|
-
const parts = fullChannel.split('.');
|
|
698
|
-
const channel = this.safeString(parts, 0);
|
|
699
|
-
const marketId = this.safeString(parts, 1);
|
|
700
|
-
if (channel === 'book') {
|
|
701
|
-
const symbol = this.safeSymbol(marketId, undefined, '-');
|
|
702
|
-
this.orderbooks[symbol] = this.orderBook({});
|
|
703
|
-
// get full depth book
|
|
704
|
-
}
|
|
705
|
-
}
|
|
706
|
-
}
|
|
707
|
-
handlePong(client, message) {
|
|
708
|
-
client.lastPong = this.milliseconds();
|
|
709
|
-
}
|
|
710
|
-
handleMessage(client, message) {
|
|
711
|
-
if (message === 'PONG') {
|
|
712
|
-
this.handlePong(client, message);
|
|
713
|
-
return;
|
|
714
|
-
}
|
|
715
|
-
const error = this.safeValue(message, 'error');
|
|
716
|
-
if (error !== undefined) {
|
|
717
|
-
return this.handleErrorMessage(client, message);
|
|
718
|
-
}
|
|
719
|
-
const result = this.safeValue(message, 'result', {});
|
|
720
|
-
const accessToken = this.safeString(result, 'access_token');
|
|
721
|
-
if (accessToken !== undefined) {
|
|
722
|
-
return this.handleAuthenticate(client, message);
|
|
723
|
-
}
|
|
724
|
-
const method = this.safeString(message, 'method');
|
|
725
|
-
if (method === 'subscription') {
|
|
726
|
-
const params = this.safeValue(message, 'params');
|
|
727
|
-
const fullChannel = this.safeString(params, 'channel');
|
|
728
|
-
const parts = fullChannel.split('.');
|
|
729
|
-
const channel = this.safeString(parts, 0);
|
|
730
|
-
const handlers = {
|
|
731
|
-
'ticker': this.handleTicker,
|
|
732
|
-
'trades': this.handleTrades,
|
|
733
|
-
'chart': this.handleOHLCV,
|
|
734
|
-
'balances': this.handleBalance,
|
|
735
|
-
'trading': this.handleOrder,
|
|
736
|
-
'user': this.handleUser,
|
|
737
|
-
'book': this.handleOrderBook,
|
|
738
|
-
};
|
|
739
|
-
const handler = this.safeValue(handlers, channel);
|
|
740
|
-
if (handler !== undefined) {
|
|
741
|
-
return handler.call(this, client, message);
|
|
742
|
-
}
|
|
743
|
-
}
|
|
744
|
-
else if ('result' in message) {
|
|
745
|
-
this.handleSubscription(client, message);
|
|
746
|
-
}
|
|
747
|
-
return message;
|
|
748
|
-
}
|
|
749
|
-
authenticate(params = {}) {
|
|
750
|
-
const url = this.urls['api']['ws'];
|
|
751
|
-
const client = this.client(url);
|
|
752
|
-
const messageHash = 'authenticated';
|
|
753
|
-
const expiresAt = this.safeNumber(this.options, 'expiresAt');
|
|
754
|
-
const time = this.milliseconds();
|
|
755
|
-
let future = this.safeValue(client.subscriptions, messageHash);
|
|
756
|
-
if ((future === undefined) || (expiresAt <= time)) {
|
|
757
|
-
const request = {
|
|
758
|
-
'jsonrpc': '2.0',
|
|
759
|
-
'id': this.requestId(),
|
|
760
|
-
'method': '/public/auth',
|
|
761
|
-
'params': {
|
|
762
|
-
'grant_type': 'client_credentials',
|
|
763
|
-
'client_id': this.apiKey,
|
|
764
|
-
'client_secret': this.secret,
|
|
765
|
-
},
|
|
766
|
-
};
|
|
767
|
-
const message = this.extend(request, params);
|
|
768
|
-
future = this.watch(url, messageHash, message);
|
|
769
|
-
client.subscriptions[messageHash] = future;
|
|
770
|
-
}
|
|
771
|
-
return future;
|
|
772
|
-
}
|
|
773
|
-
ping(client) {
|
|
774
|
-
return 'PING';
|
|
775
|
-
}
|
|
776
|
-
}
|