ccxt 4.0.91 → 4.0.94
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 +3 -3
- package/dist/ccxt.browser.js +951 -285
- package/dist/ccxt.browser.min.js +2 -2
- package/dist/cjs/ccxt.js +1 -1
- package/dist/cjs/src/bigone.js +5 -3
- package/dist/cjs/src/binance.js +1 -1
- package/dist/cjs/src/bitopro.js +34 -34
- package/dist/cjs/src/bybit.js +1 -1
- package/dist/cjs/src/cryptocom.js +1 -1
- package/dist/cjs/src/delta.js +1 -1
- package/dist/cjs/src/gate.js +2 -1
- package/dist/cjs/src/hollaex.js +3 -0
- package/dist/cjs/src/huobi.js +3 -3
- package/dist/cjs/src/okx.js +3 -3
- package/dist/cjs/src/pro/binance.js +3 -3
- package/dist/cjs/src/pro/hitbtc.js +893 -235
- package/js/ccxt.d.ts +1 -1
- package/js/ccxt.js +1 -1
- package/js/src/abstract/gate.d.ts +1 -0
- package/js/src/abstract/gateio.d.ts +1 -0
- package/js/src/bigone.js +5 -3
- package/js/src/binance.js +1 -1
- package/js/src/bitopro.js +34 -34
- package/js/src/bybit.js +1 -1
- package/js/src/cryptocom.js +1 -1
- package/js/src/delta.js +1 -1
- package/js/src/gate.js +2 -1
- package/js/src/hollaex.js +3 -0
- package/js/src/huobi.js +3 -3
- package/js/src/okx.js +3 -3
- package/js/src/pro/binance.js +3 -3
- package/js/src/pro/hitbtc.d.ts +19 -4
- package/js/src/pro/hitbtc.js +894 -236
- package/package.json +1 -1
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
var hitbtc$1 = require('../hitbtc.js');
|
|
4
4
|
var Cache = require('../base/ws/Cache.js');
|
|
5
|
+
var sha256 = require('../static_dependencies/noble-hashes/sha256.js');
|
|
6
|
+
var errors = require('../base/errors.js');
|
|
5
7
|
|
|
6
8
|
// ---------------------------------------------------------------------------
|
|
7
9
|
// ---------------------------------------------------------------------------
|
|
@@ -11,145 +13,245 @@ class hitbtc extends hitbtc$1 {
|
|
|
11
13
|
'has': {
|
|
12
14
|
'ws': true,
|
|
13
15
|
'watchTicker': true,
|
|
14
|
-
'watchTickers':
|
|
16
|
+
'watchTickers': true,
|
|
15
17
|
'watchTrades': true,
|
|
16
18
|
'watchOrderBook': true,
|
|
17
|
-
'watchBalance':
|
|
19
|
+
'watchBalance': true,
|
|
20
|
+
'watchOrders': true,
|
|
18
21
|
'watchOHLCV': true,
|
|
22
|
+
'watchMyTrades': false,
|
|
19
23
|
},
|
|
20
24
|
'urls': {
|
|
21
25
|
'api': {
|
|
22
|
-
'ws':
|
|
26
|
+
'ws': {
|
|
27
|
+
'public': 'wss://api.hitbtc.com/api/3/ws/public',
|
|
28
|
+
'private': 'wss://api.hitbtc.com/api/3/ws/trading',
|
|
29
|
+
},
|
|
23
30
|
},
|
|
24
31
|
},
|
|
25
32
|
'options': {
|
|
26
33
|
'tradesLimit': 1000,
|
|
27
|
-
'
|
|
28
|
-
'
|
|
29
|
-
'ticker': 'subscribeTicker',
|
|
30
|
-
'trades': 'subscribeTrades',
|
|
31
|
-
'ohlcv': 'subscribeCandles',
|
|
34
|
+
'watchTicker': {
|
|
35
|
+
'method': 'ticker/{speed}', // 'ticker/{speed}' or 'ticker/price/{speed}'
|
|
32
36
|
},
|
|
37
|
+
'watchTickers': {
|
|
38
|
+
'method': 'ticker/{speed}', // 'ticker/{speed}','ticker/price/{speed}', 'ticker/{speed}/batch', or 'ticker/{speed}/price/batch''
|
|
39
|
+
},
|
|
40
|
+
'watchOrderBook': {
|
|
41
|
+
'method': 'orderbook/full', // 'orderbook/full', 'orderbook/{depth}/{speed}', 'orderbook/{depth}/{speed}/batch', 'orderbook/top/{speed}', or 'orderbook/top/{speed}/batch'
|
|
42
|
+
},
|
|
43
|
+
},
|
|
44
|
+
'timeframes': {
|
|
45
|
+
'1m': 'M1',
|
|
46
|
+
'3m': 'M3',
|
|
47
|
+
'5m': 'M5',
|
|
48
|
+
'15m': 'M15',
|
|
49
|
+
'30m': 'M30',
|
|
50
|
+
'1h': 'H1',
|
|
51
|
+
'4h': 'H4',
|
|
52
|
+
'1d': 'D1',
|
|
53
|
+
'1w': 'D7',
|
|
54
|
+
'1M': '1M',
|
|
55
|
+
},
|
|
56
|
+
'streaming': {
|
|
57
|
+
'keepAlive': 4000,
|
|
33
58
|
},
|
|
34
59
|
});
|
|
35
60
|
}
|
|
36
|
-
async
|
|
61
|
+
async authenticate() {
|
|
62
|
+
/**
|
|
63
|
+
* @ignore
|
|
64
|
+
* @method
|
|
65
|
+
* @description authenticates the user to access private web socket channels
|
|
66
|
+
* @see https://api.hitbtc.com/#socket-authentication
|
|
67
|
+
* @returns {object} response from exchange
|
|
68
|
+
*/
|
|
69
|
+
this.checkRequiredCredentials();
|
|
70
|
+
const url = this.urls['api']['ws']['private'];
|
|
71
|
+
const messageHash = 'authenticated';
|
|
72
|
+
const client = this.client(url);
|
|
73
|
+
const future = client.future(messageHash);
|
|
74
|
+
const authenticated = this.safeValue(client.subscriptions, messageHash);
|
|
75
|
+
if (authenticated === undefined) {
|
|
76
|
+
const timestamp = this.milliseconds();
|
|
77
|
+
const signature = this.hmac(this.encode(this.numberToString(timestamp)), this.encode(this.secret), sha256.sha256, 'hex');
|
|
78
|
+
const request = {
|
|
79
|
+
'method': 'login',
|
|
80
|
+
'params': {
|
|
81
|
+
'type': 'HS256',
|
|
82
|
+
'api_key': this.apiKey,
|
|
83
|
+
'timestamp': timestamp,
|
|
84
|
+
'signature': signature,
|
|
85
|
+
},
|
|
86
|
+
};
|
|
87
|
+
this.watch(url, messageHash, request, messageHash);
|
|
88
|
+
//
|
|
89
|
+
// {
|
|
90
|
+
// jsonrpc: '2.0',
|
|
91
|
+
// result: true
|
|
92
|
+
// }
|
|
93
|
+
//
|
|
94
|
+
// # Failure to return results
|
|
95
|
+
//
|
|
96
|
+
// {
|
|
97
|
+
// jsonrpc: '2.0',
|
|
98
|
+
// error: {
|
|
99
|
+
// code: 1002,
|
|
100
|
+
// message: 'Authorization is required or has been failed',
|
|
101
|
+
// description: 'invalid signature format'
|
|
102
|
+
// }
|
|
103
|
+
// }
|
|
104
|
+
//
|
|
105
|
+
}
|
|
106
|
+
return future;
|
|
107
|
+
}
|
|
108
|
+
async subscribePublic(name, symbols = undefined, params = {}) {
|
|
109
|
+
/**
|
|
110
|
+
* @ignore
|
|
111
|
+
* @method
|
|
112
|
+
* @param {string} name websocket endpoint name
|
|
113
|
+
* @param {[string]} [symbols] unified CCXT symbol(s)
|
|
114
|
+
* @param {object} [params] extra parameters specific to the hitbtc api
|
|
115
|
+
* @returns
|
|
116
|
+
*/
|
|
37
117
|
await this.loadMarkets();
|
|
38
|
-
const
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
messageHash += ':' + timeframe;
|
|
118
|
+
const url = this.urls['api']['ws']['public'];
|
|
119
|
+
let messageHash = name;
|
|
120
|
+
if (symbols !== undefined) {
|
|
121
|
+
messageHash = messageHash + '::' + symbols.join(',');
|
|
43
122
|
}
|
|
44
|
-
const methods = this.safeValue(this.options, 'methods', {});
|
|
45
|
-
const method = this.safeString(methods, channel, channel);
|
|
46
|
-
const requestId = this.nonce();
|
|
47
123
|
const subscribe = {
|
|
48
|
-
'method':
|
|
49
|
-
'
|
|
50
|
-
|
|
51
|
-
},
|
|
52
|
-
'id': requestId,
|
|
124
|
+
'method': 'subscribe',
|
|
125
|
+
'id': this.nonce(),
|
|
126
|
+
'ch': name,
|
|
53
127
|
};
|
|
54
|
-
const request = this.
|
|
128
|
+
const request = this.extend(subscribe, params);
|
|
55
129
|
return await this.watch(url, messageHash, request, messageHash);
|
|
56
130
|
}
|
|
131
|
+
async subscribePrivate(name, symbol = undefined, params = {}) {
|
|
132
|
+
/**
|
|
133
|
+
* @ignore
|
|
134
|
+
* @method
|
|
135
|
+
* @param {string} name websocket endpoint name
|
|
136
|
+
* @param {string} [symbol] unified CCXT symbol
|
|
137
|
+
* @param {object} [params] extra parameters specific to the hitbtc api
|
|
138
|
+
* @returns
|
|
139
|
+
*/
|
|
140
|
+
await this.loadMarkets();
|
|
141
|
+
await this.authenticate();
|
|
142
|
+
const url = this.urls['api']['ws']['private'];
|
|
143
|
+
const splitName = name.split('_subscribe');
|
|
144
|
+
let messageHash = this.safeString(splitName, 0);
|
|
145
|
+
if (symbol !== undefined) {
|
|
146
|
+
messageHash = messageHash + '::' + symbol;
|
|
147
|
+
}
|
|
148
|
+
const subscribe = {
|
|
149
|
+
'method': name,
|
|
150
|
+
'params': params,
|
|
151
|
+
'id': this.nonce(),
|
|
152
|
+
};
|
|
153
|
+
return await this.watch(url, messageHash, subscribe, messageHash);
|
|
154
|
+
}
|
|
57
155
|
async watchOrderBook(symbol, limit = undefined, params = {}) {
|
|
58
156
|
/**
|
|
59
157
|
* @method
|
|
60
158
|
* @name hitbtc#watchOrderBook
|
|
61
159
|
* @description watches information on open orders with bid (buy) and ask (sell) prices, volumes and other data
|
|
160
|
+
* @see https://api.hitbtc.com/#subscribe-to-full-order-book
|
|
161
|
+
* @see https://api.hitbtc.com/#subscribe-to-partial-order-book
|
|
162
|
+
* @see https://api.hitbtc.com/#subscribe-to-partial-order-book-in-batches
|
|
163
|
+
* @see https://api.hitbtc.com/#subscribe-to-top-of-book
|
|
164
|
+
* @see https://api.hitbtc.com/#subscribe-to-top-of-book-in-batches
|
|
62
165
|
* @param {string} symbol unified symbol of the market to fetch the order book for
|
|
63
166
|
* @param {int} [limit] the maximum amount of order book entries to return
|
|
64
167
|
* @param {object} [params] extra parameters specific to the hitbtc api endpoint
|
|
65
|
-
* @
|
|
168
|
+
* @param {string} [params.method] 'orderbook/full', 'orderbook/{depth}/{speed}', 'orderbook/{depth}/{speed}/batch', 'orderbook/top/{speed}', or 'orderbook/top/{speed}/batch'
|
|
169
|
+
* @param {int} [params.depth] 5 , 10, or 20 (default)
|
|
170
|
+
* @param {int} [params.speed] 100 (default), 500, or 1000
|
|
171
|
+
* @returns {object} A dictionary of [order book structures]{@link https://docs.ccxt.com/#/?id=order-book-structure} indexed by market symbols
|
|
66
172
|
*/
|
|
67
|
-
const
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
// ],
|
|
81
|
-
// bid: [
|
|
82
|
-
// { price: "6926.18", size: "0.16898" },
|
|
83
|
-
// { price: "6926.17", size: "0.06200" },
|
|
84
|
-
// { price: "6925.97", size: "0.00125" },
|
|
85
|
-
// ],
|
|
86
|
-
// symbol: "BTCUSD",
|
|
87
|
-
// sequence: 494854,
|
|
88
|
-
// timestamp: "2020-04-03T08:58:53.460Z"
|
|
89
|
-
// }
|
|
90
|
-
// }
|
|
91
|
-
//
|
|
92
|
-
const params = this.safeValue(message, 'params', {});
|
|
93
|
-
const marketId = this.safeString(params, 'symbol');
|
|
94
|
-
const market = this.safeMarket(marketId);
|
|
95
|
-
const symbol = market['symbol'];
|
|
96
|
-
const timestamp = this.parse8601(this.safeString(params, 'timestamp'));
|
|
97
|
-
const nonce = this.safeInteger(params, 'sequence');
|
|
98
|
-
if (symbol in this.orderbooks) {
|
|
99
|
-
delete this.orderbooks[symbol];
|
|
173
|
+
const options = this.safeValue(this.options, 'watchOrderBook');
|
|
174
|
+
const defaultMethod = this.safeString(options, 'method', 'orderbook/full');
|
|
175
|
+
let name = this.safeString2(params, 'method', 'defaultMethod', defaultMethod);
|
|
176
|
+
const depth = this.safeString(params, 'depth', '20');
|
|
177
|
+
const speed = this.safeString(params, 'depth', '100');
|
|
178
|
+
if (name === 'orderbook/{depth}/{speed}') {
|
|
179
|
+
name = 'orderbook/D' + depth + '/' + speed + 'ms';
|
|
180
|
+
}
|
|
181
|
+
else if (name === 'orderbook/{depth}/{speed}/batch') {
|
|
182
|
+
name = 'orderbook/D' + depth + '/' + speed + 'ms/batch';
|
|
183
|
+
}
|
|
184
|
+
else if (name === 'orderbook/top/{speed}') {
|
|
185
|
+
name = 'orderbook/top/' + speed + 'ms';
|
|
100
186
|
}
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
this.
|
|
105
|
-
const
|
|
106
|
-
|
|
187
|
+
else if (name === 'orderbook/top/{speed}/batch') {
|
|
188
|
+
name = 'orderbook/top/' + speed + 'ms/batch';
|
|
189
|
+
}
|
|
190
|
+
const market = this.market(symbol);
|
|
191
|
+
const request = {
|
|
192
|
+
'params': {
|
|
193
|
+
'symbols': [market['id']],
|
|
194
|
+
},
|
|
195
|
+
};
|
|
196
|
+
const orderbook = await this.subscribePublic(name, [symbol], this.deepExtend(request, params));
|
|
197
|
+
return orderbook.limit();
|
|
107
198
|
}
|
|
108
|
-
|
|
109
|
-
//
|
|
110
|
-
//
|
|
111
|
-
//
|
|
112
|
-
//
|
|
113
|
-
//
|
|
114
|
-
//
|
|
115
|
-
//
|
|
116
|
-
//
|
|
117
|
-
//
|
|
118
|
-
//
|
|
119
|
-
//
|
|
120
|
-
//
|
|
121
|
-
//
|
|
122
|
-
//
|
|
123
|
-
//
|
|
124
|
-
//
|
|
125
|
-
//
|
|
126
|
-
//
|
|
127
|
-
//
|
|
128
|
-
//
|
|
129
|
-
//
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
const
|
|
133
|
-
const
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
const
|
|
199
|
+
handleOrderBook(client, message) {
|
|
200
|
+
//
|
|
201
|
+
// {
|
|
202
|
+
// "ch": "orderbook/full", // Channel
|
|
203
|
+
// "snapshot": {
|
|
204
|
+
// "ETHBTC": {
|
|
205
|
+
// "t": 1626866578796, // Timestamp in milliseconds
|
|
206
|
+
// "s": 27617207, // Sequence number
|
|
207
|
+
// "a": [ // Asks
|
|
208
|
+
// ["0.060506", "0"],
|
|
209
|
+
// ["0.060549", "12.6431"],
|
|
210
|
+
// ["0.060570", "0"],
|
|
211
|
+
// ["0.060612", "0"]
|
|
212
|
+
// ],
|
|
213
|
+
// "b": [ // Bids
|
|
214
|
+
// ["0.060439", "4.4095"],
|
|
215
|
+
// ["0.060414", "0"],
|
|
216
|
+
// ["0.060407", "7.3349"],
|
|
217
|
+
// ["0.060390", "0"]
|
|
218
|
+
// ]
|
|
219
|
+
// }
|
|
220
|
+
// }
|
|
221
|
+
// }
|
|
222
|
+
//
|
|
223
|
+
const data = this.safeValue2(message, 'snapshot', 'update', {});
|
|
224
|
+
const marketIds = Object.keys(data);
|
|
225
|
+
const channel = this.safeString(message, 'ch');
|
|
226
|
+
for (let i = 0; i < marketIds.length; i++) {
|
|
227
|
+
const marketId = marketIds[i];
|
|
228
|
+
const market = this.safeMarket(marketId);
|
|
229
|
+
const symbol = market['symbol'];
|
|
230
|
+
const item = data[marketId];
|
|
231
|
+
const messageHash = channel + '::' + symbol;
|
|
232
|
+
if (!(symbol in this.orderbooks)) {
|
|
233
|
+
const subscription = this.safeValue(client.subscriptions, messageHash, {});
|
|
234
|
+
const limit = this.safeInteger(subscription, 'limit');
|
|
235
|
+
this.orderbooks[symbol] = this.orderBook({}, limit);
|
|
236
|
+
}
|
|
237
|
+
const timestamp = this.safeInteger(item, 't');
|
|
238
|
+
const nonce = this.safeInteger(item, 's');
|
|
137
239
|
const orderbook = this.orderbooks[symbol];
|
|
138
|
-
const asks = this.safeValue(
|
|
139
|
-
const bids = this.safeValue(
|
|
240
|
+
const asks = this.safeValue(item, 'a', []);
|
|
241
|
+
const bids = this.safeValue(item, 'b', []);
|
|
140
242
|
this.handleDeltas(orderbook['asks'], asks);
|
|
141
243
|
this.handleDeltas(orderbook['bids'], bids);
|
|
142
244
|
orderbook['timestamp'] = timestamp;
|
|
143
245
|
orderbook['datetime'] = this.iso8601(timestamp);
|
|
144
246
|
orderbook['nonce'] = nonce;
|
|
247
|
+
orderbook['symbol'] = symbol;
|
|
145
248
|
this.orderbooks[symbol] = orderbook;
|
|
146
|
-
const messageHash = 'orderbook:' + marketId;
|
|
147
249
|
client.resolve(orderbook, messageHash);
|
|
148
250
|
}
|
|
149
251
|
}
|
|
150
252
|
handleDelta(bookside, delta) {
|
|
151
|
-
const price = this.
|
|
152
|
-
const amount = this.
|
|
253
|
+
const price = this.safeNumber(delta, 0);
|
|
254
|
+
const amount = this.safeNumber(delta, 1);
|
|
153
255
|
bookside.store(price, amount);
|
|
154
256
|
}
|
|
155
257
|
handleDeltas(bookside, deltas) {
|
|
@@ -162,180 +264,394 @@ class hitbtc extends hitbtc$1 {
|
|
|
162
264
|
* @method
|
|
163
265
|
* @name hitbtc#watchTicker
|
|
164
266
|
* @description watches a price ticker, a statistical calculation with the information calculated over the past 24 hours for a specific market
|
|
267
|
+
* @see https://api.hitbtc.com/#subscribe-to-ticker
|
|
268
|
+
* @see https://api.hitbtc.com/#subscribe-to-ticker-in-batches
|
|
269
|
+
* @see https://api.hitbtc.com/#subscribe-to-mini-ticker
|
|
270
|
+
* @see https://api.hitbtc.com/#subscribe-to-mini-ticker-in-batches
|
|
165
271
|
* @param {string} symbol unified symbol of the market to fetch the ticker for
|
|
166
272
|
* @param {object} [params] extra parameters specific to the hitbtc api endpoint
|
|
167
|
-
* @
|
|
273
|
+
* @param {string} [params.method] 'ticker/{speed}' (default), or 'ticker/price/{speed}'
|
|
274
|
+
* @param {string} [params.speed] '1s' (default), or '3s'
|
|
275
|
+
* @returns {object} a [ticker structure]{@link https://docs.ccxt.com/#/?id=ticker-structure}
|
|
276
|
+
*/
|
|
277
|
+
const options = this.safeValue(this.options, 'watchTicker');
|
|
278
|
+
const defaultMethod = this.safeString(options, 'method', 'ticker/{speed}');
|
|
279
|
+
const method = this.safeString2(params, 'method', 'defaultMethod', defaultMethod);
|
|
280
|
+
const speed = this.safeString(params, 'speed', '1s');
|
|
281
|
+
const name = this.implodeParams(method, { 'speed': speed });
|
|
282
|
+
params = this.omit(params, ['method', 'speed']);
|
|
283
|
+
const market = this.market(symbol);
|
|
284
|
+
const request = {
|
|
285
|
+
'params': {
|
|
286
|
+
'symbols': [market['id']],
|
|
287
|
+
},
|
|
288
|
+
};
|
|
289
|
+
return await this.subscribePublic(name, [symbol], this.deepExtend(request, params));
|
|
290
|
+
}
|
|
291
|
+
async watchTickers(symbols = undefined, params = {}) {
|
|
292
|
+
/**
|
|
293
|
+
* @method
|
|
294
|
+
* @name hitbtc#watchTicker
|
|
295
|
+
* @description watches a price ticker, a statistical calculation with the information calculated over the past 24 hours for a specific market
|
|
296
|
+
* @param {string} symbol unified symbol of the market to fetch the ticker for
|
|
297
|
+
* @param {object} params extra parameters specific to the hitbtc api endpoint
|
|
298
|
+
* @param {string} params.method 'ticker/{speed}' (default),'ticker/price/{speed}', 'ticker/{speed}/batch', or 'ticker/{speed}/price/batch''
|
|
299
|
+
* @param {string} params.speed '1s' (default), or '3s'
|
|
300
|
+
* @returns {object} a [ticker structure]{@link https://docs.ccxt.com/en/latest/manual.html#ticker-structure}
|
|
168
301
|
*/
|
|
169
|
-
|
|
302
|
+
await this.loadMarkets();
|
|
303
|
+
const options = this.safeValue(this.options, 'watchTicker');
|
|
304
|
+
const defaultMethod = this.safeString(options, 'method', 'ticker/{speed}');
|
|
305
|
+
const method = this.safeString2(params, 'method', 'defaultMethod', defaultMethod);
|
|
306
|
+
const speed = this.safeString(params, 'speed', '1s');
|
|
307
|
+
const name = this.implodeParams(method, { 'speed': speed });
|
|
308
|
+
params = this.omit(params, ['method', 'speed']);
|
|
309
|
+
const marketIds = [];
|
|
310
|
+
if (symbols === undefined) {
|
|
311
|
+
marketIds.push('*');
|
|
312
|
+
}
|
|
313
|
+
else {
|
|
314
|
+
for (let i = 0; i < symbols.length; i++) {
|
|
315
|
+
const marketId = this.marketId(symbols[i]);
|
|
316
|
+
marketIds.push(marketId);
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
const request = {
|
|
320
|
+
'params': {
|
|
321
|
+
'symbols': marketIds,
|
|
322
|
+
},
|
|
323
|
+
};
|
|
324
|
+
const tickers = await this.subscribePublic(name, symbols, this.deepExtend(request, params));
|
|
325
|
+
if (this.newUpdates) {
|
|
326
|
+
return tickers;
|
|
327
|
+
}
|
|
328
|
+
return this.filterByArray(this.tickers, 'symbol', symbols);
|
|
170
329
|
}
|
|
171
330
|
handleTicker(client, message) {
|
|
172
331
|
//
|
|
173
|
-
//
|
|
174
|
-
//
|
|
175
|
-
//
|
|
176
|
-
//
|
|
177
|
-
//
|
|
178
|
-
//
|
|
179
|
-
//
|
|
180
|
-
//
|
|
181
|
-
//
|
|
182
|
-
//
|
|
183
|
-
//
|
|
184
|
-
//
|
|
185
|
-
//
|
|
186
|
-
//
|
|
187
|
-
//
|
|
188
|
-
//
|
|
332
|
+
// {
|
|
333
|
+
// "ch": "ticker/1s",
|
|
334
|
+
// "data": {
|
|
335
|
+
// "ETHBTC": {
|
|
336
|
+
// "t": 1614815872000, // Timestamp in milliseconds
|
|
337
|
+
// "a": "0.031175", // Best ask
|
|
338
|
+
// "A": "0.03329", // Best ask quantity
|
|
339
|
+
// "b": "0.031148", // Best bid
|
|
340
|
+
// "B": "0.10565", // Best bid quantity
|
|
341
|
+
// "c": "0.031210", // Last price
|
|
342
|
+
// "o": "0.030781", // Open price
|
|
343
|
+
// "h": "0.031788", // High price
|
|
344
|
+
// "l": "0.030733", // Low price
|
|
345
|
+
// "v": "62.587", // Base asset volume
|
|
346
|
+
// "q": "1.951420577", // Quote asset volume
|
|
347
|
+
// "p": "0.000429", // Price change
|
|
348
|
+
// "P": "1.39", // Price change percent
|
|
349
|
+
// "L": 1182694927 // Last trade identifier
|
|
350
|
+
// }
|
|
351
|
+
// }
|
|
352
|
+
// }
|
|
189
353
|
//
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
354
|
+
// {
|
|
355
|
+
// "ch": "ticker/price/1s",
|
|
356
|
+
// "data": {
|
|
357
|
+
// "BTCUSDT": {
|
|
358
|
+
// "t": 1614815872030,
|
|
359
|
+
// "o": "32636.79",
|
|
360
|
+
// "c": "32085.51",
|
|
361
|
+
// "h": "33379.92",
|
|
362
|
+
// "l": "30683.28",
|
|
363
|
+
// "v": "11.90667",
|
|
364
|
+
// "q": "384081.1955629"
|
|
365
|
+
// }
|
|
366
|
+
// }
|
|
367
|
+
// }
|
|
368
|
+
//
|
|
369
|
+
const data = this.safeValue(message, 'data', {});
|
|
370
|
+
const marketIds = Object.keys(data);
|
|
371
|
+
const channel = this.safeString(message, 'ch');
|
|
372
|
+
const newTickers = [];
|
|
373
|
+
for (let i = 0; i < marketIds.length; i++) {
|
|
374
|
+
const marketId = marketIds[i];
|
|
375
|
+
const market = this.safeMarket(marketId);
|
|
376
|
+
const symbol = market['symbol'];
|
|
377
|
+
const ticker = this.parseWsTicker(data[marketId], market);
|
|
378
|
+
this.tickers[symbol] = ticker;
|
|
379
|
+
newTickers.push(ticker);
|
|
380
|
+
const messageHash = channel + '::' + symbol;
|
|
381
|
+
client.resolve(this.tickers[symbol], messageHash);
|
|
382
|
+
}
|
|
383
|
+
const messageHashes = this.findMessageHashes(client, channel + '::');
|
|
384
|
+
for (let i = 0; i < messageHashes.length; i++) {
|
|
385
|
+
const messageHash = messageHashes[i];
|
|
386
|
+
const parts = messageHash.split('::');
|
|
387
|
+
const symbolsString = parts[1];
|
|
388
|
+
const symbols = symbolsString.split(',');
|
|
389
|
+
const tickers = this.filterByArray(newTickers, 'symbol', symbols);
|
|
390
|
+
const tickersSymbols = Object.keys(tickers);
|
|
391
|
+
const numTickers = tickersSymbols.length;
|
|
392
|
+
if (numTickers > 0) {
|
|
393
|
+
client.resolve(tickers, messageHash);
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
client.resolve(this.tickers, channel);
|
|
397
|
+
return message;
|
|
398
|
+
}
|
|
399
|
+
parseWsTicker(ticker, market = undefined) {
|
|
400
|
+
//
|
|
401
|
+
// {
|
|
402
|
+
// "t": 1614815872000, // Timestamp in milliseconds
|
|
403
|
+
// "a": "0.031175", // Best ask
|
|
404
|
+
// "A": "0.03329", // Best ask quantity
|
|
405
|
+
// "b": "0.031148", // Best bid
|
|
406
|
+
// "B": "0.10565", // Best bid quantity
|
|
407
|
+
// "c": "0.031210", // Last price
|
|
408
|
+
// "o": "0.030781", // Open price
|
|
409
|
+
// "h": "0.031788", // High price
|
|
410
|
+
// "l": "0.030733", // Low price
|
|
411
|
+
// "v": "62.587", // Base asset volume
|
|
412
|
+
// "q": "1.951420577", // Quote asset volume
|
|
413
|
+
// "p": "0.000429", // Price change
|
|
414
|
+
// "P": "1.39", // Price change percent
|
|
415
|
+
// "L": 1182694927 // Last trade identifier
|
|
416
|
+
// }
|
|
417
|
+
//
|
|
418
|
+
// {
|
|
419
|
+
// "t": 1614815872030,
|
|
420
|
+
// "o": "32636.79",
|
|
421
|
+
// "c": "32085.51",
|
|
422
|
+
// "h": "33379.92",
|
|
423
|
+
// "l": "30683.28",
|
|
424
|
+
// "v": "11.90667",
|
|
425
|
+
// "q": "384081.1955629"
|
|
426
|
+
// }
|
|
427
|
+
//
|
|
428
|
+
const timestamp = this.safeInteger(ticker, 't');
|
|
429
|
+
const symbol = this.safeSymbol(undefined, market);
|
|
430
|
+
const last = this.safeString(ticker, 'c');
|
|
431
|
+
return this.safeTicker({
|
|
432
|
+
'symbol': symbol,
|
|
433
|
+
'timestamp': timestamp,
|
|
434
|
+
'datetime': this.iso8601(timestamp),
|
|
435
|
+
'high': this.safeString(ticker, 'h'),
|
|
436
|
+
'low': this.safeString(ticker, 'l'),
|
|
437
|
+
'bid': this.safeString(ticker, 'b'),
|
|
438
|
+
'bidVolume': this.safeString(ticker, 'B'),
|
|
439
|
+
'ask': this.safeString(ticker, 'a'),
|
|
440
|
+
'askVolume': this.safeString(ticker, 'A'),
|
|
441
|
+
'vwap': undefined,
|
|
442
|
+
'open': this.safeString(ticker, 'o'),
|
|
443
|
+
'close': last,
|
|
444
|
+
'last': last,
|
|
445
|
+
'previousClose': undefined,
|
|
446
|
+
'change': undefined,
|
|
447
|
+
'percentage': undefined,
|
|
448
|
+
'average': undefined,
|
|
449
|
+
'baseVolume': this.safeString(ticker, 'v'),
|
|
450
|
+
'quoteVolume': this.safeString(ticker, 'q'),
|
|
451
|
+
'info': ticker,
|
|
452
|
+
}, market);
|
|
199
453
|
}
|
|
200
454
|
async watchTrades(symbol, since = undefined, limit = undefined, params = {}) {
|
|
201
455
|
/**
|
|
202
456
|
* @method
|
|
203
457
|
* @name hitbtc#watchTrades
|
|
204
458
|
* @description get the list of most recent trades for a particular symbol
|
|
459
|
+
* @see https://api.hitbtc.com/#subscribe-to-trades
|
|
205
460
|
* @param {string} symbol unified symbol of the market to fetch trades for
|
|
206
461
|
* @param {int} [since] timestamp in ms of the earliest trade to fetch
|
|
207
462
|
* @param {int} [limit] the maximum amount of trades to fetch
|
|
208
463
|
* @param {object} [params] extra parameters specific to the hitbtc api endpoint
|
|
209
464
|
* @returns {object[]} a list of [trade structures]{@link https://github.com/ccxt/ccxt/wiki/Manual#public-trades}
|
|
210
465
|
*/
|
|
211
|
-
|
|
466
|
+
await this.loadMarkets();
|
|
467
|
+
const market = this.market(symbol);
|
|
468
|
+
const request = {
|
|
469
|
+
'params': {
|
|
470
|
+
'symbols': [market['id']],
|
|
471
|
+
},
|
|
472
|
+
};
|
|
473
|
+
if (limit !== undefined) {
|
|
474
|
+
request['limit'] = limit;
|
|
475
|
+
}
|
|
476
|
+
const trades = await this.subscribePublic('trades', [symbol], this.deepExtend(request, params));
|
|
212
477
|
if (this.newUpdates) {
|
|
213
478
|
limit = trades.getLimit(symbol, limit);
|
|
214
479
|
}
|
|
215
|
-
return this.filterBySinceLimit(trades, since, limit, 'timestamp'
|
|
480
|
+
return this.filterBySinceLimit(trades, since, limit, 'timestamp');
|
|
216
481
|
}
|
|
217
482
|
handleTrades(client, message) {
|
|
218
483
|
//
|
|
219
|
-
//
|
|
220
|
-
//
|
|
221
|
-
//
|
|
222
|
-
//
|
|
223
|
-
//
|
|
224
|
-
//
|
|
225
|
-
//
|
|
226
|
-
//
|
|
227
|
-
//
|
|
228
|
-
//
|
|
229
|
-
//
|
|
230
|
-
//
|
|
231
|
-
//
|
|
232
|
-
//
|
|
233
|
-
//
|
|
234
|
-
//
|
|
235
|
-
//
|
|
236
|
-
//
|
|
237
|
-
//
|
|
238
|
-
//
|
|
239
|
-
//
|
|
240
|
-
//
|
|
241
|
-
//
|
|
242
|
-
//
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
}
|
|
255
|
-
|
|
256
|
-
|
|
484
|
+
// {
|
|
485
|
+
// "result": {
|
|
486
|
+
// "ch": "trades", // Channel
|
|
487
|
+
// "subscriptions": ["ETHBTC", "BTCUSDT"]
|
|
488
|
+
// },
|
|
489
|
+
// "id": 123
|
|
490
|
+
// }
|
|
491
|
+
//
|
|
492
|
+
// Notification snapshot
|
|
493
|
+
//
|
|
494
|
+
// {
|
|
495
|
+
// "ch": "trades", // Channel
|
|
496
|
+
// "snapshot": {
|
|
497
|
+
// "BTCUSDT": [{
|
|
498
|
+
// "t": 1626861109494, // Timestamp in milliseconds
|
|
499
|
+
// "i": 1555634969, // Trade identifier
|
|
500
|
+
// "p": "30881.96", // Price
|
|
501
|
+
// "q": "12.66828", // Quantity
|
|
502
|
+
// "s": "buy" // Side
|
|
503
|
+
// }]
|
|
504
|
+
// }
|
|
505
|
+
// }
|
|
506
|
+
//
|
|
507
|
+
// Notification update
|
|
508
|
+
//
|
|
509
|
+
// {
|
|
510
|
+
// "ch": "trades",
|
|
511
|
+
// "update": {
|
|
512
|
+
// "BTCUSDT": [{
|
|
513
|
+
// "t": 1626861123552,
|
|
514
|
+
// "i": 1555634969,
|
|
515
|
+
// "p": "30877.68",
|
|
516
|
+
// "q": "0.00006",
|
|
517
|
+
// "s": "sell"
|
|
518
|
+
// }]
|
|
519
|
+
// }
|
|
520
|
+
// }
|
|
521
|
+
//
|
|
522
|
+
const data = this.safeValue2(message, 'snapshot', 'update', {});
|
|
523
|
+
const marketIds = Object.keys(data);
|
|
524
|
+
for (let i = 0; i < marketIds.length; i++) {
|
|
525
|
+
const marketId = marketIds[i];
|
|
526
|
+
const market = this.safeMarket(marketId);
|
|
527
|
+
const tradesLimit = this.safeInteger(this.options, 'tradesLimit', 1000);
|
|
528
|
+
const symbol = market['symbol'];
|
|
529
|
+
let stored = this.safeValue(this.trades, symbol);
|
|
530
|
+
if (stored === undefined) {
|
|
531
|
+
stored = new Cache.ArrayCache(tradesLimit);
|
|
532
|
+
this.trades[symbol] = stored;
|
|
533
|
+
}
|
|
534
|
+
const trades = this.parseWsTrades(data[marketId], market);
|
|
257
535
|
for (let i = 0; i < trades.length; i++) {
|
|
258
536
|
stored.append(trades[i]);
|
|
259
537
|
}
|
|
538
|
+
const messageHash = 'trades::' + symbol;
|
|
539
|
+
client.resolve(stored, messageHash);
|
|
260
540
|
}
|
|
261
|
-
else {
|
|
262
|
-
const trade = this.parseTrade(message, market);
|
|
263
|
-
stored.append(trade);
|
|
264
|
-
}
|
|
265
|
-
client.resolve(stored, messageHash);
|
|
266
541
|
return message;
|
|
267
542
|
}
|
|
543
|
+
parseWsTrades(trades, market = undefined, since = undefined, limit = undefined, params = {}) {
|
|
544
|
+
trades = this.toArray(trades);
|
|
545
|
+
let result = [];
|
|
546
|
+
for (let i = 0; i < trades.length; i++) {
|
|
547
|
+
const trade = this.extend(this.parseWsTrade(trades[i], market), params);
|
|
548
|
+
result.push(trade);
|
|
549
|
+
}
|
|
550
|
+
result = this.sortBy2(result, 'timestamp', 'id');
|
|
551
|
+
const symbol = this.safeString(market, 'symbol');
|
|
552
|
+
return this.filterBySymbolSinceLimit(result, symbol, since, limit);
|
|
553
|
+
}
|
|
554
|
+
parseWsTrade(trade, market = undefined) {
|
|
555
|
+
//
|
|
556
|
+
// {
|
|
557
|
+
// "t": 1626861123552, // Timestamp in milliseconds
|
|
558
|
+
// "i": 1555634969, // Trade identifier
|
|
559
|
+
// "p": "30877.68", // Price
|
|
560
|
+
// "q": "0.00006", // Quantity
|
|
561
|
+
// "s": "sell" // Side
|
|
562
|
+
// }
|
|
563
|
+
//
|
|
564
|
+
const timestamp = this.safeInteger(trade, 't');
|
|
565
|
+
return this.safeTrade({
|
|
566
|
+
'info': trade,
|
|
567
|
+
'id': this.safeString(trade, 'i'),
|
|
568
|
+
'order': undefined,
|
|
569
|
+
'timestamp': timestamp,
|
|
570
|
+
'datetime': this.iso8601(timestamp),
|
|
571
|
+
'symbol': this.safeString(market, 'symbol'),
|
|
572
|
+
'type': undefined,
|
|
573
|
+
'side': this.safeString(trade, 's'),
|
|
574
|
+
'takerOrMaker': undefined,
|
|
575
|
+
'price': this.safeString(trade, 'p'),
|
|
576
|
+
'amount': this.safeString(trade, 'q'),
|
|
577
|
+
'cost': undefined,
|
|
578
|
+
'fee': undefined,
|
|
579
|
+
}, market);
|
|
580
|
+
}
|
|
268
581
|
async watchOHLCV(symbol, timeframe = '1m', since = undefined, limit = undefined, params = {}) {
|
|
269
582
|
/**
|
|
270
583
|
* @method
|
|
271
584
|
* @name hitbtc#watchOHLCV
|
|
272
585
|
* @description watches historical candlestick data containing the open, high, low, and close price, and the volume of a market
|
|
586
|
+
* @see https://api.hitbtc.com/#subscribe-to-candles
|
|
273
587
|
* @param {string} symbol unified symbol of the market to fetch OHLCV data for
|
|
274
|
-
* @param {string} timeframe the length of time each candle represents
|
|
275
|
-
* @param {int} [since]
|
|
276
|
-
* @param {int} [limit]
|
|
588
|
+
* @param {string} [timeframe] the length of time each candle represents
|
|
589
|
+
* @param {int} [since] not used by hitbtc watchOHLCV
|
|
590
|
+
* @param {int} [limit] 0 – 1000, default value = 0 (no history returned)
|
|
277
591
|
* @param {object} [params] extra parameters specific to the hitbtc api endpoint
|
|
278
|
-
* @returns {
|
|
592
|
+
* @returns {[[int]]} A list of candles ordered as timestamp, open, high, low, close, volume
|
|
279
593
|
*/
|
|
280
|
-
// if (limit === undefined) {
|
|
281
|
-
// limit = 100;
|
|
282
|
-
// }
|
|
283
594
|
const period = this.safeString(this.timeframes, timeframe, timeframe);
|
|
595
|
+
const name = 'candles/' + period;
|
|
596
|
+
const market = this.market(symbol);
|
|
284
597
|
const request = {
|
|
285
598
|
'params': {
|
|
286
|
-
'
|
|
287
|
-
// 'limit': limit,
|
|
599
|
+
'symbols': [market['id']],
|
|
288
600
|
},
|
|
289
601
|
};
|
|
290
|
-
|
|
291
|
-
|
|
602
|
+
if (limit !== undefined) {
|
|
603
|
+
request['params']['limit'] = limit;
|
|
604
|
+
}
|
|
605
|
+
const ohlcv = await this.subscribePublic(name, [symbol], this.deepExtend(request, params));
|
|
292
606
|
if (this.newUpdates) {
|
|
293
607
|
limit = ohlcv.getLimit(symbol, limit);
|
|
294
608
|
}
|
|
295
|
-
return this.filterBySinceLimit(ohlcv, since, limit, 0
|
|
609
|
+
return this.filterBySinceLimit(ohlcv, since, limit, 0);
|
|
296
610
|
}
|
|
297
611
|
handleOHLCV(client, message) {
|
|
298
612
|
//
|
|
299
|
-
//
|
|
300
|
-
//
|
|
301
|
-
//
|
|
302
|
-
//
|
|
303
|
-
//
|
|
304
|
-
//
|
|
305
|
-
//
|
|
306
|
-
//
|
|
307
|
-
//
|
|
308
|
-
//
|
|
309
|
-
//
|
|
310
|
-
//
|
|
311
|
-
//
|
|
312
|
-
//
|
|
313
|
-
//
|
|
314
|
-
//
|
|
315
|
-
//
|
|
316
|
-
//
|
|
317
|
-
//
|
|
318
|
-
//
|
|
319
|
-
//
|
|
320
|
-
//
|
|
321
|
-
//
|
|
322
|
-
//
|
|
323
|
-
//
|
|
324
|
-
//
|
|
325
|
-
//
|
|
326
|
-
//
|
|
327
|
-
//
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
const
|
|
332
|
-
const
|
|
333
|
-
const
|
|
613
|
+
// {
|
|
614
|
+
// "ch": "candles/M1", // Channel
|
|
615
|
+
// "snapshot": {
|
|
616
|
+
// "BTCUSDT": [{
|
|
617
|
+
// "t": 1626860340000, // Message timestamp
|
|
618
|
+
// "o": "30881.95", // Open price
|
|
619
|
+
// "c": "30890.96", // Last price
|
|
620
|
+
// "h": "30900.8", // High price
|
|
621
|
+
// "l": "30861.27", // Low price
|
|
622
|
+
// "v": "1.27852", // Base asset volume
|
|
623
|
+
// "q": "39493.9021811" // Quote asset volume
|
|
624
|
+
// }
|
|
625
|
+
// ...
|
|
626
|
+
// ]
|
|
627
|
+
// }
|
|
628
|
+
// }
|
|
629
|
+
//
|
|
630
|
+
// {
|
|
631
|
+
// "ch": "candles/M1",
|
|
632
|
+
// "update": {
|
|
633
|
+
// "ETHBTC": [{
|
|
634
|
+
// "t": 1626860880000,
|
|
635
|
+
// "o": "0.060711",
|
|
636
|
+
// "c": "0.060749",
|
|
637
|
+
// "h": "0.060749",
|
|
638
|
+
// "l": "0.060711",
|
|
639
|
+
// "v": "12.2800",
|
|
640
|
+
// "q": "0.7455339675"
|
|
641
|
+
// }]
|
|
642
|
+
// }
|
|
643
|
+
// }
|
|
644
|
+
//
|
|
645
|
+
const data = this.safeValue2(message, 'snapshot', 'update', {});
|
|
646
|
+
const marketIds = Object.keys(data);
|
|
647
|
+
const channel = this.safeString(message, 'ch');
|
|
648
|
+
const splitChannel = channel.split('/');
|
|
649
|
+
const period = this.safeString(splitChannel, 1);
|
|
334
650
|
const timeframe = this.findTimeframe(period);
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
const
|
|
338
|
-
const
|
|
651
|
+
for (let i = 0; i < marketIds.length; i++) {
|
|
652
|
+
const marketId = marketIds[i];
|
|
653
|
+
const market = this.safeMarket(marketId);
|
|
654
|
+
const symbol = market['symbol'];
|
|
339
655
|
this.ohlcvs[symbol] = this.safeValue(this.ohlcvs, symbol, {});
|
|
340
656
|
let stored = this.safeValue(this.ohlcvs[symbol], timeframe);
|
|
341
657
|
if (stored === undefined) {
|
|
@@ -343,11 +659,319 @@ class hitbtc extends hitbtc$1 {
|
|
|
343
659
|
stored = new Cache.ArrayCacheByTimestamp(limit);
|
|
344
660
|
this.ohlcvs[symbol][timeframe] = stored;
|
|
345
661
|
}
|
|
346
|
-
|
|
662
|
+
const ohlcvs = this.parseWsOHLCVs(data[marketId], market);
|
|
663
|
+
for (let i = 0; i < ohlcvs.length; i++) {
|
|
664
|
+
stored.append(ohlcvs[i]);
|
|
665
|
+
}
|
|
666
|
+
const messageHash = channel + '::' + symbol;
|
|
347
667
|
client.resolve(stored, messageHash);
|
|
348
668
|
}
|
|
349
669
|
return message;
|
|
350
670
|
}
|
|
671
|
+
parseWsOHLCV(ohlcv, market = undefined) {
|
|
672
|
+
//
|
|
673
|
+
// {
|
|
674
|
+
// "t": 1626860340000, // Message timestamp
|
|
675
|
+
// "o": "30881.95", // Open price
|
|
676
|
+
// "c": "30890.96", // Last price
|
|
677
|
+
// "h": "30900.8", // High price
|
|
678
|
+
// "l": "30861.27", // Low price
|
|
679
|
+
// "v": "1.27852", // Base asset volume
|
|
680
|
+
// "q": "39493.9021811" // Quote asset volume
|
|
681
|
+
// }
|
|
682
|
+
//
|
|
683
|
+
return [
|
|
684
|
+
this.safeInteger(ohlcv, 't'),
|
|
685
|
+
this.safeNumber(ohlcv, 'o'),
|
|
686
|
+
this.safeNumber(ohlcv, 'h'),
|
|
687
|
+
this.safeNumber(ohlcv, 'l'),
|
|
688
|
+
this.safeNumber(ohlcv, 'c'),
|
|
689
|
+
this.safeNumber(ohlcv, 'v'),
|
|
690
|
+
];
|
|
691
|
+
}
|
|
692
|
+
async watchOrders(symbol = undefined, since = undefined, limit = undefined, params = {}) {
|
|
693
|
+
/**
|
|
694
|
+
* @method
|
|
695
|
+
* @name hitbtc#watchOrders
|
|
696
|
+
* @description watches information on multiple orders made by the user
|
|
697
|
+
* @see https://api.hitbtc.com/#subscribe-to-reports
|
|
698
|
+
* @see https://api.hitbtc.com/#subscribe-to-reports-2
|
|
699
|
+
* @see https://api.hitbtc.com/#subscribe-to-reports-3
|
|
700
|
+
* @param {string} [symbol] unified CCXT market symbol
|
|
701
|
+
* @param {int} [since] timestamp in ms of the earliest order to fetch
|
|
702
|
+
* @param {int} [limit] the maximum amount of orders to fetch
|
|
703
|
+
* @param {object} [params] extra parameters specific to the hitbtc api endpoint
|
|
704
|
+
* @returns {[object]} a list of [order structures]{@link https://docs.ccxt.com/en/latest/manual.html#order-structure}
|
|
705
|
+
*/
|
|
706
|
+
await this.loadMarkets();
|
|
707
|
+
let marketType = undefined;
|
|
708
|
+
let market = undefined;
|
|
709
|
+
if (symbol !== undefined) {
|
|
710
|
+
market = this.market(symbol);
|
|
711
|
+
}
|
|
712
|
+
[marketType, params] = this.handleMarketTypeAndParams('watchOrders', market, params);
|
|
713
|
+
const name = this.getSupportedMapping(marketType, {
|
|
714
|
+
'spot': 'spot_subscribe',
|
|
715
|
+
'margin': 'margin_subscribe',
|
|
716
|
+
'swap': 'futures_subscribe',
|
|
717
|
+
'future': 'futures_subscribe',
|
|
718
|
+
});
|
|
719
|
+
const orders = await this.subscribePrivate(name, symbol, params);
|
|
720
|
+
if (this.newUpdates) {
|
|
721
|
+
limit = orders.getLimit(symbol, limit);
|
|
722
|
+
}
|
|
723
|
+
return this.filterBySinceLimit(orders, since, limit, 'timestamp');
|
|
724
|
+
}
|
|
725
|
+
handleOrder(client, message) {
|
|
726
|
+
//
|
|
727
|
+
// {
|
|
728
|
+
// "jsonrpc": "2.0",
|
|
729
|
+
// "method": "spot_order", // "margin_order", "future_order"
|
|
730
|
+
// "params": {
|
|
731
|
+
// "id": 584244931496,
|
|
732
|
+
// "client_order_id": "b5acd79c0a854b01b558665bcf379456",
|
|
733
|
+
// "symbol": "BTCUSDT",
|
|
734
|
+
// "side": "buy",
|
|
735
|
+
// "status": "new",
|
|
736
|
+
// "type": "limit",
|
|
737
|
+
// "time_in_force": "GTC",
|
|
738
|
+
// "quantity": "0.01000",
|
|
739
|
+
// "quantity_cumulative": "0",
|
|
740
|
+
// "price": "0.01", // only updates and snapshots
|
|
741
|
+
// "post_only": false,
|
|
742
|
+
// "reduce_only": false, // only margin and contract
|
|
743
|
+
// "display_quantity": "0", // only updates and snapshot
|
|
744
|
+
// "created_at": "2021-07-02T22:52:32.864Z",
|
|
745
|
+
// "updated_at": "2021-07-02T22:52:32.864Z",
|
|
746
|
+
// "trade_id": 1361977606, // only trades
|
|
747
|
+
// "trade_quantity": "0.00001", // only trades
|
|
748
|
+
// "trade_price": "49595.04", // only trades
|
|
749
|
+
// "trade_fee": "0.001239876000", // only trades
|
|
750
|
+
// "trade_taker": true, // only trades, only spot
|
|
751
|
+
// "trade_position_id": 485308, // only trades, only margin
|
|
752
|
+
// "report_type": "new" // "trade", "status" (snapshot)
|
|
753
|
+
// }
|
|
754
|
+
// }
|
|
755
|
+
//
|
|
756
|
+
// {
|
|
757
|
+
// "jsonrpc": "2.0",
|
|
758
|
+
// "method": "spot_orders", // "margin_orders", "future_orders"
|
|
759
|
+
// "params": [
|
|
760
|
+
// {
|
|
761
|
+
// "id": 584244931496,
|
|
762
|
+
// "client_order_id": "b5acd79c0a854b01b558665bcf379456",
|
|
763
|
+
// "symbol": "BTCUSDT",
|
|
764
|
+
// "side": "buy",
|
|
765
|
+
// "status": "new",
|
|
766
|
+
// "type": "limit",
|
|
767
|
+
// "time_in_force": "GTC",
|
|
768
|
+
// "quantity": "0.01000",
|
|
769
|
+
// "quantity_cumulative": "0",
|
|
770
|
+
// "price": "0.01", // only updates and snapshots
|
|
771
|
+
// "post_only": false,
|
|
772
|
+
// "reduce_only": false, // only margin and contract
|
|
773
|
+
// "display_quantity": "0", // only updates and snapshot
|
|
774
|
+
// "created_at": "2021-07-02T22:52:32.864Z",
|
|
775
|
+
// "updated_at": "2021-07-02T22:52:32.864Z",
|
|
776
|
+
// "trade_id": 1361977606, // only trades
|
|
777
|
+
// "trade_quantity": "0.00001", // only trades
|
|
778
|
+
// "trade_price": "49595.04", // only trades
|
|
779
|
+
// "trade_fee": "0.001239876000", // only trades
|
|
780
|
+
// "trade_taker": true, // only trades, only spot
|
|
781
|
+
// "trade_position_id": 485308, // only trades, only margin
|
|
782
|
+
// "report_type": "new" // "trade", "status" (snapshot)
|
|
783
|
+
// }
|
|
784
|
+
// ]
|
|
785
|
+
// }
|
|
786
|
+
//
|
|
787
|
+
if (this.orders === undefined) {
|
|
788
|
+
const limit = this.safeInteger(this.options, 'ordersLimit');
|
|
789
|
+
this.orders = new Cache.ArrayCacheBySymbolById(limit);
|
|
790
|
+
}
|
|
791
|
+
const data = this.safeValue(message, 'params', []);
|
|
792
|
+
if (Array.isArray(data)) {
|
|
793
|
+
for (let i = 0; i < data.length; i++) {
|
|
794
|
+
const order = data[i];
|
|
795
|
+
this.handleOrderHelper(client, message, order);
|
|
796
|
+
}
|
|
797
|
+
}
|
|
798
|
+
else {
|
|
799
|
+
this.handleOrderHelper(client, message, data);
|
|
800
|
+
}
|
|
801
|
+
return message;
|
|
802
|
+
}
|
|
803
|
+
handleOrderHelper(client, message, order) {
|
|
804
|
+
const orders = this.orders;
|
|
805
|
+
const marketId = this.safeStringLower2(order, 'instrument', 'symbol');
|
|
806
|
+
const method = this.safeString(message, 'method');
|
|
807
|
+
const splitMethod = method.split('_order');
|
|
808
|
+
const messageHash = this.safeString(splitMethod, 0);
|
|
809
|
+
const symbol = this.safeSymbol(marketId);
|
|
810
|
+
const parsed = this.parseOrder(order);
|
|
811
|
+
orders.append(parsed);
|
|
812
|
+
client.resolve(orders, messageHash);
|
|
813
|
+
client.resolve(orders, messageHash + '::' + symbol);
|
|
814
|
+
}
|
|
815
|
+
parseWsOrderTrade(trade, market = undefined) {
|
|
816
|
+
//
|
|
817
|
+
// {
|
|
818
|
+
// "id": 584244931496,
|
|
819
|
+
// "client_order_id": "b5acd79c0a854b01b558665bcf379456",
|
|
820
|
+
// "symbol": "BTCUSDT",
|
|
821
|
+
// "side": "buy",
|
|
822
|
+
// "status": "new",
|
|
823
|
+
// "type": "limit",
|
|
824
|
+
// "time_in_force": "GTC",
|
|
825
|
+
// "quantity": "0.01000",
|
|
826
|
+
// "quantity_cumulative": "0",
|
|
827
|
+
// "price": "0.01", // only updates and snapshots
|
|
828
|
+
// "post_only": false,
|
|
829
|
+
// "reduce_only": false, // only margin and contract
|
|
830
|
+
// "display_quantity": "0", // only updates and snapshot
|
|
831
|
+
// "created_at": "2021-07-02T22:52:32.864Z",
|
|
832
|
+
// "updated_at": "2021-07-02T22:52:32.864Z",
|
|
833
|
+
// "trade_id": 1361977606, // only trades
|
|
834
|
+
// "trade_quantity": "0.00001", // only trades
|
|
835
|
+
// "trade_price": "49595.04", // only trades
|
|
836
|
+
// "trade_fee": "0.001239876000", // only trades
|
|
837
|
+
// "trade_taker": true, // only trades, only spot
|
|
838
|
+
// "trade_position_id": 485308, // only trades, only margin
|
|
839
|
+
// "report_type": "new" // "trade", "status" (snapshot)
|
|
840
|
+
// }
|
|
841
|
+
//
|
|
842
|
+
const timestamp = this.safeInteger(trade, 'created_at');
|
|
843
|
+
const marketId = this.safeString(trade, 'symbol');
|
|
844
|
+
return this.safeTrade({
|
|
845
|
+
'info': trade,
|
|
846
|
+
'id': this.safeString(trade, 'trade_id'),
|
|
847
|
+
'order': this.safeString(trade, 'id'),
|
|
848
|
+
'timestamp': timestamp,
|
|
849
|
+
'datetime': this.iso8601(timestamp),
|
|
850
|
+
'symbol': this.safeMarket(marketId, market),
|
|
851
|
+
'type': undefined,
|
|
852
|
+
'side': this.safeString(trade, 'side'),
|
|
853
|
+
'takerOrMaker': this.safeString(trade, 'trade_taker'),
|
|
854
|
+
'price': this.safeString(trade, 'trade_price'),
|
|
855
|
+
'amount': this.safeString(trade, 'trade_quantity'),
|
|
856
|
+
'cost': undefined,
|
|
857
|
+
'fee': {
|
|
858
|
+
'cost': this.safeString(trade, 'trade_fee'),
|
|
859
|
+
'currency': undefined,
|
|
860
|
+
'rate': undefined,
|
|
861
|
+
},
|
|
862
|
+
}, market);
|
|
863
|
+
}
|
|
864
|
+
parseWsOrder(order, market = undefined) {
|
|
865
|
+
//
|
|
866
|
+
// {
|
|
867
|
+
// "id": 584244931496,
|
|
868
|
+
// "client_order_id": "b5acd79c0a854b01b558665bcf379456",
|
|
869
|
+
// "symbol": "BTCUSDT",
|
|
870
|
+
// "side": "buy",
|
|
871
|
+
// "status": "new",
|
|
872
|
+
// "type": "limit",
|
|
873
|
+
// "time_in_force": "GTC",
|
|
874
|
+
// "quantity": "0.01000",
|
|
875
|
+
// "quantity_cumulative": "0",
|
|
876
|
+
// "price": "0.01", // only updates and snapshots
|
|
877
|
+
// "post_only": false,
|
|
878
|
+
// "reduce_only": false, // only margin and contract
|
|
879
|
+
// "display_quantity": "0", // only updates and snapshot
|
|
880
|
+
// "created_at": "2021-07-02T22:52:32.864Z",
|
|
881
|
+
// "updated_at": "2021-07-02T22:52:32.864Z",
|
|
882
|
+
// "trade_id": 1361977606, // only trades
|
|
883
|
+
// "trade_quantity": "0.00001", // only trades
|
|
884
|
+
// "trade_price": "49595.04", // only trades
|
|
885
|
+
// "trade_fee": "0.001239876000", // only trades
|
|
886
|
+
// "trade_taker": true, // only trades, only spot
|
|
887
|
+
// "trade_position_id": 485308, // only trades, only margin
|
|
888
|
+
// "report_type": "new" // "trade", "status" (snapshot)
|
|
889
|
+
// }
|
|
890
|
+
//
|
|
891
|
+
const timestamp = this.safeString(order, 'created_at');
|
|
892
|
+
const marketId = this.safeSymbol(order, 'symbol');
|
|
893
|
+
market = this.safeMarket(marketId, market);
|
|
894
|
+
const tradeId = this.safeString(order, 'trade_id');
|
|
895
|
+
let trades = undefined;
|
|
896
|
+
if (tradeId !== undefined) {
|
|
897
|
+
const trade = this.parseWsOrderTrade(order, market);
|
|
898
|
+
trades = [trade];
|
|
899
|
+
}
|
|
900
|
+
return this.safeOrder({
|
|
901
|
+
'info': order,
|
|
902
|
+
'id': this.safeString(order, 'id'),
|
|
903
|
+
'clientOrderId': this.safeString(order, 'client_order_id'),
|
|
904
|
+
'timestamp': timestamp,
|
|
905
|
+
'datetime': this.iso8601(timestamp),
|
|
906
|
+
'lastTradeTimestamp': undefined,
|
|
907
|
+
'symbol': market['symbol'],
|
|
908
|
+
'price': this.safeString(order, 'price'),
|
|
909
|
+
'amount': this.safeString(order, 'quantity'),
|
|
910
|
+
'type': this.safeString(order, 'type'),
|
|
911
|
+
'side': this.safeStringUpper(order, 'side'),
|
|
912
|
+
'timeInForce': this.safeString(order, 'time_in_force'),
|
|
913
|
+
'postOnly': this.safeString(order, 'post_only'),
|
|
914
|
+
'reduceOnly': this.safeValue(order, 'reduce_only'),
|
|
915
|
+
'filled': undefined,
|
|
916
|
+
'remaining': undefined,
|
|
917
|
+
'cost': undefined,
|
|
918
|
+
'status': this.parseOrderStatus(this.safeString(order, 'status')),
|
|
919
|
+
'average': undefined,
|
|
920
|
+
'trades': trades,
|
|
921
|
+
'fee': undefined,
|
|
922
|
+
}, market);
|
|
923
|
+
}
|
|
924
|
+
async watchBalance(params = {}) {
|
|
925
|
+
/**
|
|
926
|
+
* @method
|
|
927
|
+
* @name hitbtc#watchBalance
|
|
928
|
+
* @description watches balance updates, cannot subscribe to margin account balances
|
|
929
|
+
* @see https://api.hitbtc.com/#subscribe-to-spot-balances
|
|
930
|
+
* @see https://api.hitbtc.com/#subscribe-to-futures-balances
|
|
931
|
+
* @param {object} [params] extra parameters specific to the hitbtc api endpoint
|
|
932
|
+
* @param {string} [params.type] 'spot', 'swap', or 'future'
|
|
933
|
+
*
|
|
934
|
+
* EXCHANGE SPECIFIC PARAMETERS
|
|
935
|
+
* @param {string} [params.mode] 'updates' or 'batches' (default), 'updates' = messages arrive after balance updates, 'batches' = messages arrive at equal intervals if there were any updates
|
|
936
|
+
* @returns {[object]} a list of [balance structures]{@link https://docs.ccxt.com/#/?id=balance-structure}
|
|
937
|
+
*/
|
|
938
|
+
await this.loadMarkets();
|
|
939
|
+
let type = undefined;
|
|
940
|
+
[type, params] = this.handleMarketTypeAndParams('watchBalance', undefined, params);
|
|
941
|
+
const name = this.getSupportedMapping(type, {
|
|
942
|
+
'spot': 'spot_balance_subscribe',
|
|
943
|
+
'swap': 'futures_balance_subscribe',
|
|
944
|
+
'future': 'futures_balance_subscribe',
|
|
945
|
+
});
|
|
946
|
+
const mode = this.safeString(params, 'mode', 'batches');
|
|
947
|
+
params = this.omit(params, 'mode');
|
|
948
|
+
const request = {
|
|
949
|
+
'mode': mode,
|
|
950
|
+
};
|
|
951
|
+
return await this.subscribePrivate(name, undefined, this.extend(request, params));
|
|
952
|
+
}
|
|
953
|
+
handleBalance(client, message) {
|
|
954
|
+
//
|
|
955
|
+
// {
|
|
956
|
+
// "jsonrpc": "2.0",
|
|
957
|
+
// "method": "futures_balance",
|
|
958
|
+
// "params": [
|
|
959
|
+
// {
|
|
960
|
+
// "currency": "BCN",
|
|
961
|
+
// "available": "100.000000000000",
|
|
962
|
+
// "reserved": "0",
|
|
963
|
+
// "reserved_margin": "0"
|
|
964
|
+
// },
|
|
965
|
+
// ...
|
|
966
|
+
// ]
|
|
967
|
+
// }
|
|
968
|
+
//
|
|
969
|
+
const messageHash = this.safeString(message, 'method');
|
|
970
|
+
const params = this.safeValue(message, 'params');
|
|
971
|
+
const balance = this.parseBalance(params);
|
|
972
|
+
this.balance = this.deepExtend(this.balance, balance);
|
|
973
|
+
client.resolve(this.balance, messageHash);
|
|
974
|
+
}
|
|
351
975
|
handleNotification(client, message) {
|
|
352
976
|
//
|
|
353
977
|
// { jsonrpc: '2.0', result: true, id: null }
|
|
@@ -355,23 +979,57 @@ class hitbtc extends hitbtc$1 {
|
|
|
355
979
|
return message;
|
|
356
980
|
}
|
|
357
981
|
handleMessage(client, message) {
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
'
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
982
|
+
let channel = this.safeString2(message, 'ch', 'method');
|
|
983
|
+
if (channel !== undefined) {
|
|
984
|
+
const splitChannel = channel.split('/');
|
|
985
|
+
channel = this.safeString(splitChannel, 0);
|
|
986
|
+
const methods = {
|
|
987
|
+
'candles': this.handleOHLCV,
|
|
988
|
+
'ticker': this.handleTicker,
|
|
989
|
+
'trades': this.handleTrades,
|
|
990
|
+
'orderbook': this.handleOrderBook,
|
|
991
|
+
'spot_order': this.handleOrder,
|
|
992
|
+
'spot_orders': this.handleOrder,
|
|
993
|
+
'margin_order': this.handleOrder,
|
|
994
|
+
'margin_orders': this.handleOrder,
|
|
995
|
+
'futures_order': this.handleOrder,
|
|
996
|
+
'futures_orders': this.handleOrder,
|
|
997
|
+
'spot_balance': this.handleBalance,
|
|
998
|
+
'futures_balance': this.handleBalance,
|
|
999
|
+
};
|
|
1000
|
+
const method = this.safeValue(methods, channel);
|
|
1001
|
+
if (method !== undefined) {
|
|
1002
|
+
method.call(this, client, message);
|
|
1003
|
+
}
|
|
371
1004
|
}
|
|
372
1005
|
else {
|
|
373
|
-
|
|
1006
|
+
const success = this.safeValue(message, 'result');
|
|
1007
|
+
if ((success === true) && !('id' in message)) {
|
|
1008
|
+
this.handleAuthenticate(client, message);
|
|
1009
|
+
}
|
|
1010
|
+
}
|
|
1011
|
+
}
|
|
1012
|
+
handleAuthenticate(client, message) {
|
|
1013
|
+
//
|
|
1014
|
+
// {
|
|
1015
|
+
// jsonrpc: '2.0',
|
|
1016
|
+
// result: true
|
|
1017
|
+
// }
|
|
1018
|
+
//
|
|
1019
|
+
const success = this.safeValue(message, 'result');
|
|
1020
|
+
const messageHash = 'authenticated';
|
|
1021
|
+
if (success) {
|
|
1022
|
+
const future = this.safeValue(client.futures, messageHash);
|
|
1023
|
+
future.resolve(true);
|
|
374
1024
|
}
|
|
1025
|
+
else {
|
|
1026
|
+
const error = new errors.AuthenticationError(this.id + ' ' + this.json(message));
|
|
1027
|
+
client.reject(error, messageHash);
|
|
1028
|
+
if (messageHash in client.subscriptions) {
|
|
1029
|
+
delete client.subscriptions[messageHash];
|
|
1030
|
+
}
|
|
1031
|
+
}
|
|
1032
|
+
return message;
|
|
375
1033
|
}
|
|
376
1034
|
}
|
|
377
1035
|
|