coinrayjs 1.4.34

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.
Files changed (76) hide show
  1. package/CHANGELOG.md +10 -0
  2. package/LICENSE +21 -0
  3. package/README.md +27 -0
  4. package/dist/candles-cache.d.ts +7 -0
  5. package/dist/candles-cache.js +57 -0
  6. package/dist/candles-cache.js.map +1 -0
  7. package/dist/coinray-cache.d.ts +30 -0
  8. package/dist/coinray-cache.js +109 -0
  9. package/dist/coinray-cache.js.map +1 -0
  10. package/dist/coinray.d.ts +156 -0
  11. package/dist/coinray.js +957 -0
  12. package/dist/coinray.js.map +1 -0
  13. package/dist/crypto.d.ts +1 -0
  14. package/dist/crypto.js +57 -0
  15. package/dist/crypto.js.map +1 -0
  16. package/dist/current-market.d.ts +61 -0
  17. package/dist/current-market.js +259 -0
  18. package/dist/current-market.js.map +1 -0
  19. package/dist/errors.d.ts +25 -0
  20. package/dist/errors.js +50 -0
  21. package/dist/errors.js.map +1 -0
  22. package/dist/event-emitter.d.ts +9 -0
  23. package/dist/event-emitter.js +36 -0
  24. package/dist/event-emitter.js.map +1 -0
  25. package/dist/exchange.d.ts +28 -0
  26. package/dist/exchange.js +107 -0
  27. package/dist/exchange.js.map +1 -0
  28. package/dist/i18n/locales.d.ts +21 -0
  29. package/dist/i18n/locales.js +21 -0
  30. package/dist/i18n/locales.js.map +1 -0
  31. package/dist/i18n.d.ts +4 -0
  32. package/dist/i18n.js +16 -0
  33. package/dist/i18n.js.map +1 -0
  34. package/dist/index.d.ts +9 -0
  35. package/dist/index.js +10 -0
  36. package/dist/index.js.map +1 -0
  37. package/dist/lru.d.ts +26 -0
  38. package/dist/lru.js +93 -0
  39. package/dist/lru.js.map +1 -0
  40. package/dist/market.d.ts +46 -0
  41. package/dist/market.js +117 -0
  42. package/dist/market.js.map +1 -0
  43. package/dist/orders/base.d.ts +29 -0
  44. package/dist/orders/base.js +47 -0
  45. package/dist/orders/base.js.map +1 -0
  46. package/dist/orders/index.d.ts +6 -0
  47. package/dist/orders/index.js +7 -0
  48. package/dist/orders/index.js.map +1 -0
  49. package/dist/orders/limit-ladder.d.ts +87 -0
  50. package/dist/orders/limit-ladder.js +229 -0
  51. package/dist/orders/limit-ladder.js.map +1 -0
  52. package/dist/orders/limit.d.ts +47 -0
  53. package/dist/orders/limit.js +86 -0
  54. package/dist/orders/limit.js.map +1 -0
  55. package/dist/orders/market.d.ts +35 -0
  56. package/dist/orders/market.js +52 -0
  57. package/dist/orders/market.js.map +1 -0
  58. package/dist/orders/oco.d.ts +54 -0
  59. package/dist/orders/oco.js +70 -0
  60. package/dist/orders/oco.js.map +1 -0
  61. package/dist/orders/stop-limit.d.ts +42 -0
  62. package/dist/orders/stop-limit.js +33 -0
  63. package/dist/orders/stop-limit.js.map +1 -0
  64. package/dist/orders/validate.d.ts +2 -0
  65. package/dist/orders/validate.js +6 -0
  66. package/dist/orders/validate.js.map +1 -0
  67. package/dist/trade.d.ts +10 -0
  68. package/dist/trade.js +32 -0
  69. package/dist/trade.js.map +1 -0
  70. package/dist/types.d.ts +185 -0
  71. package/dist/types.js +42 -0
  72. package/dist/types.js.map +1 -0
  73. package/dist/util.d.ts +33 -0
  74. package/dist/util.js +212 -0
  75. package/dist/util.js.map +1 -0
  76. package/package.json +79 -0
@@ -0,0 +1,957 @@
1
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
2
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
3
+ return new (P || (P = Promise))(function (resolve, reject) {
4
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
5
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
6
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
7
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
8
+ });
9
+ };
10
+ import axios from "axios";
11
+ import { Socket } from "phoenix";
12
+ import { camelize, createJWT, encryptPayload, jwkToPublicKey, jwtExpired, parseJWT, safeBigNumber, safeTime, signHMAC } from "./util";
13
+ import Market from "./market";
14
+ import Exchange from "./exchange";
15
+ import BigNumber from "bignumber.js";
16
+ import _ from "lodash";
17
+ import I18n from "./i18n";
18
+ const VERSION = require('../package.json').version;
19
+ export class CoinrayError extends Error {
20
+ constructor({ code, message, exchange }) {
21
+ super("Request failed");
22
+ this.name = "CoinrayError";
23
+ this.errorCode = code;
24
+ this.errorMessage = message;
25
+ this.exchange = exchange;
26
+ }
27
+ }
28
+ export default class Coinray {
29
+ constructor(token, { apiEndpoint, orderEndpoint, websocketEndpoint } = {
30
+ apiEndpoint: "https://api.coinray.eu",
31
+ orderEndpoint: "https://api.coinray.eu",
32
+ websocketEndpoint: "wss://ws.coinray.eu/v1",
33
+ }) {
34
+ this._tickerListeners = {};
35
+ this._tradeListeners = {};
36
+ this._tradeSnapshots = {};
37
+ this._orderbookListeners = {};
38
+ this._orderbookSnapshots = {};
39
+ this._candleTradeListeners = {};
40
+ this._candleListeners = {};
41
+ this._candles = {};
42
+ this._channels = {};
43
+ this.tickersSubscribed = false;
44
+ this.tradesSubscribed = false;
45
+ this.orderBookSubscribed = false;
46
+ this.authenticateDevice = (credential, sessionKey) => {
47
+ this._credential = credential;
48
+ this._sessionKey = sessionKey;
49
+ };
50
+ this.destroy = () => {
51
+ this._tradeListeners = {};
52
+ this._orderbookListeners = {};
53
+ this._tickerListeners = {};
54
+ this._channels = {};
55
+ if (this._timeOffsetInterval) {
56
+ clearInterval(this._timeOffsetInterval);
57
+ }
58
+ if (this._tokenCheckInterval) {
59
+ clearInterval(this._tokenCheckInterval);
60
+ }
61
+ this.disconnect();
62
+ };
63
+ this.checkToken = () => __awaiter(this, void 0, void 0, function* () {
64
+ if (jwtExpired(this._token)) {
65
+ console.log("Coinray token expired. Can refresh:", !!this._onTokenExpired);
66
+ if (!this._onTokenExpired) {
67
+ return false;
68
+ }
69
+ if (!this._refreshingToken) {
70
+ this._refreshingToken = this._onTokenExpired();
71
+ }
72
+ try {
73
+ this._token = yield this._refreshingToken;
74
+ }
75
+ catch (error) {
76
+ console.log("Coinray token could not be refreshed", error);
77
+ this._refreshingToken = undefined;
78
+ return false;
79
+ }
80
+ this._refreshingToken = undefined;
81
+ if (!jwtExpired(this._token)) {
82
+ this.reconnect();
83
+ }
84
+ else {
85
+ return false;
86
+ }
87
+ }
88
+ return true;
89
+ });
90
+ this.setTransport = (transport) => {
91
+ this._transport = transport;
92
+ };
93
+ this.onTokenExpired = (callback) => {
94
+ this._onTokenExpired = callback;
95
+ this._tokenCheckInterval = setInterval(this.checkToken, 5000);
96
+ };
97
+ this.refreshToken = (token) => {
98
+ this._token = token;
99
+ };
100
+ this.getNonce = () => {
101
+ if (this._nonceOffset > 900) {
102
+ this._nonceOffset = 0;
103
+ }
104
+ this._nonceOffset += 1;
105
+ return this.getTime() + this._nonceOffset;
106
+ };
107
+ this.getTime = () => {
108
+ return Math.floor(new Date().getTime() / 1000) * 1000 + this._timeOffset;
109
+ };
110
+ this.loadTimeOffset = () => __awaiter(this, void 0, void 0, function* () {
111
+ const { result } = yield this.get("/coinray/time");
112
+ this._timeOffset = result.time - new Date().getTime();
113
+ });
114
+ this.getToken = () => __awaiter(this, void 0, void 0, function* () {
115
+ const tokenValid = yield this.checkToken();
116
+ if (tokenValid) {
117
+ return this._token;
118
+ }
119
+ else {
120
+ throw new Error("Token is expired. call refreshToken in the onTokenExpired callback");
121
+ }
122
+ });
123
+ this.reconnect = () => {
124
+ if (this._connected) {
125
+ // @ts-ignore
126
+ this.socket.conn.close();
127
+ }
128
+ };
129
+ this.disconnect = () => {
130
+ if (this._socket) {
131
+ this._socket.disconnect();
132
+ this._socket = undefined;
133
+ }
134
+ this._connected = undefined;
135
+ };
136
+ this.connect = () => __awaiter(this, void 0, void 0, function* () {
137
+ if (this._connected) {
138
+ yield this._connected;
139
+ return;
140
+ }
141
+ else {
142
+ this._connected = new Promise((resolve) => {
143
+ this.markConnected = resolve;
144
+ });
145
+ }
146
+ // @ts-ignore
147
+ this.socket.onOpen((event) => {
148
+ if (this._onOpen) {
149
+ this._onOpen(event);
150
+ }
151
+ });
152
+ // @ts-ignore
153
+ this.socket.onError((event) => {
154
+ if (this._onError) {
155
+ this._onError(event);
156
+ }
157
+ });
158
+ this.socket.connect();
159
+ this.markConnected();
160
+ });
161
+ this.onOpen = (callback) => {
162
+ this._onOpen = callback;
163
+ };
164
+ this.onError = (callback) => {
165
+ this._onError = callback;
166
+ };
167
+ this.resubscribe = () => {
168
+ if (this._firstOpen) {
169
+ this._firstOpen = false;
170
+ return;
171
+ }
172
+ Object.keys(this._tickerListeners).forEach((exchangeCode) => {
173
+ if (this._tickerListeners[exchangeCode].length > 0) {
174
+ const channel = this.getChannel("tickers");
175
+ channel.push("subscribe", { exchangeCodes: [exchangeCode] }, 5000);
176
+ }
177
+ });
178
+ Object.keys(this._tradeListeners).forEach((coinraySymbol) => {
179
+ if (this._tradeListeners[coinraySymbol].length > 0) {
180
+ const channel = this.getChannel("trades");
181
+ channel.push("subscribe", { symbols: coinraySymbol, snapshots: true }, 5000);
182
+ }
183
+ });
184
+ Object.keys(this._orderbookListeners).forEach((coinraySymbol) => {
185
+ if (this._orderbookListeners[coinraySymbol].length > 0) {
186
+ const channel = this.getChannel("orderbooks");
187
+ channel.push("subscribe", { symbols: coinraySymbol, snapshots: true }, 5000);
188
+ }
189
+ });
190
+ };
191
+ this.subscribeTickers = (exchangeCode, callback) => __awaiter(this, void 0, void 0, function* () {
192
+ if (this._tickerListeners[exchangeCode] && this._tickerListeners[exchangeCode].length > 0) {
193
+ this._tickerListeners[exchangeCode].push(callback);
194
+ return callback;
195
+ }
196
+ // Run only once per coinraySymbol
197
+ this._tickerListeners[exchangeCode] = [callback];
198
+ yield this.connect();
199
+ const channel = this.getChannel("tickers");
200
+ channel.push("subscribe", { exchangeCodes: [exchangeCode] }, 5000);
201
+ if (this.tickersSubscribed) {
202
+ return callback;
203
+ }
204
+ this.tickersSubscribed = true;
205
+ channel.on("update", (payload) => {
206
+ let { exchange_code: exchangeCode, tickers } = payload;
207
+ const callbacks = Object.values(this._tickerListeners[exchangeCode]);
208
+ const parsedTickers = tickers.map(Coinray._parseTicker);
209
+ callbacks.map((callback) => callback({
210
+ type: "tickers:update",
211
+ exchangeCode,
212
+ tickers: parsedTickers
213
+ }));
214
+ });
215
+ channel.on("error", (payload) => console.error(payload));
216
+ return callback;
217
+ });
218
+ this.unsubscribeTickers = (exchangeCode, callback) => {
219
+ if (callback && this._tickerListeners[exchangeCode]) {
220
+ this._tickerListeners[exchangeCode] = this._tickerListeners[exchangeCode].filter((c) => c !== callback);
221
+ if (this._tickerListeners[exchangeCode].length === 0) {
222
+ this.getChannel("tickers")
223
+ .push("unsubscribe", { exchangeCodes: [exchangeCode] }, 5000);
224
+ }
225
+ }
226
+ else {
227
+ this._tickerListeners[exchangeCode] = [];
228
+ }
229
+ };
230
+ this.subscribeTrades = ({ coinraySymbol }, callback) => __awaiter(this, void 0, void 0, function* () {
231
+ if (this._tradeListeners[coinraySymbol] && this._tradeListeners[coinraySymbol].length > 0) {
232
+ this._tradeListeners[coinraySymbol].push(callback);
233
+ callback({
234
+ type: "trades:snapshot",
235
+ coinraySymbol: coinraySymbol,
236
+ trades: this._tradeSnapshots[coinraySymbol]
237
+ });
238
+ return callback;
239
+ }
240
+ // Run only once per coinraySymbol
241
+ this._tradeSnapshots[coinraySymbol] = [];
242
+ this._tradeListeners[coinraySymbol] = [callback];
243
+ yield this.connect();
244
+ const channel = this.getChannel("trades");
245
+ channel.push("subscribe", { symbols: coinraySymbol, snapshots: true }, 5000);
246
+ if (this.tradesSubscribed) {
247
+ return callback;
248
+ }
249
+ this.tradesSubscribed = true;
250
+ channel.on("snapshot", ({ symbol, trades }) => {
251
+ const callbacks = Object.values(this._tradeListeners[symbol]);
252
+ const parsedTrades = trades.map(Coinray._parseTrade);
253
+ this._tradeSnapshots[symbol] = parsedTrades;
254
+ callbacks.map((callback) => callback({
255
+ type: "trades:snapshot",
256
+ coinraySymbol: symbol,
257
+ trades: parsedTrades
258
+ }));
259
+ });
260
+ channel.on("update", ({ symbol, trades }) => {
261
+ const callbacks = Object.values(this._tradeListeners[symbol]);
262
+ const parsedTrades = trades.map(Coinray._parseTrade);
263
+ const snapshot = [...parsedTrades, ...this._tradeSnapshots[symbol]];
264
+ const minTime = new Date(new Date().getTime() - 120000);
265
+ const relevantSnapshot = snapshot.filter(({ time }) => time > minTime);
266
+ if (relevantSnapshot.length > 100) {
267
+ this._tradeSnapshots[symbol] = relevantSnapshot;
268
+ }
269
+ else {
270
+ this._tradeSnapshots[symbol] = snapshot.slice(0, 100);
271
+ }
272
+ callbacks.map((callback) => callback({
273
+ type: "trades:update",
274
+ coinraySymbol: symbol,
275
+ trades: parsedTrades
276
+ }));
277
+ });
278
+ channel.on("error", (payload) => console.error(payload));
279
+ return callback;
280
+ });
281
+ this.unsubscribeTrades = ({ coinraySymbol }, callback) => {
282
+ if (callback && this._tradeListeners[coinraySymbol]) {
283
+ this._tradeListeners[coinraySymbol] = this._tradeListeners[coinraySymbol].filter((c) => c !== callback);
284
+ if (this._tradeListeners[coinraySymbol].length === 0) {
285
+ this.getChannel("trades")
286
+ .push("unsubscribe", { symbols: coinraySymbol }, 5000);
287
+ }
288
+ }
289
+ else {
290
+ this._tradeSnapshots[coinraySymbol] = [];
291
+ this._tradeListeners[coinraySymbol] = [];
292
+ }
293
+ };
294
+ this.subscribeOrderBook = ({ coinraySymbol }, callback) => __awaiter(this, void 0, void 0, function* () {
295
+ if (this._orderbookListeners[coinraySymbol] && this._orderbookListeners[coinraySymbol].length > 0) {
296
+ this._orderbookListeners[coinraySymbol].push(callback);
297
+ callback({
298
+ type: "orderBook:snapshot",
299
+ coinraySymbol: coinraySymbol,
300
+ orderBook: this._orderbookSnapshots[coinraySymbol]
301
+ });
302
+ return callback;
303
+ }
304
+ this._orderbookSnapshots[coinraySymbol] = { minSeq: 0, maxSeq: 0, bids: {}, asks: {} };
305
+ this._orderbookListeners[coinraySymbol] = [callback];
306
+ yield this.connect();
307
+ const channel = this.getChannel("orderbooks");
308
+ channel.push("subscribe", { symbols: coinraySymbol }, 10000);
309
+ if (this.orderBookSubscribed) {
310
+ return callback;
311
+ }
312
+ this.orderBookSubscribed = true;
313
+ channel.on("snapshot", ({ orderbooks }) => {
314
+ const incoming_symbols = Object.keys(orderbooks);
315
+ incoming_symbols.forEach(symbol => {
316
+ const callbacks = Object.values(this._orderbookListeners[symbol]);
317
+ const parsedOrderBook = Coinray._parseOrderBookSnapshot(orderbooks[symbol]);
318
+ this._orderbookSnapshots[symbol] = parsedOrderBook;
319
+ callbacks.map((callback) => callback({
320
+ type: "orderBook:snapshot",
321
+ coinraySymbol: symbol,
322
+ orderBook: parsedOrderBook
323
+ }));
324
+ });
325
+ });
326
+ channel.on("update", ({ orderbooks }) => {
327
+ const incoming_symbols = Object.keys(orderbooks);
328
+ if (incoming_symbols.length === 0) {
329
+ return;
330
+ }
331
+ incoming_symbols.forEach(symbol => {
332
+ const callbacks = Object.values(this._orderbookListeners[symbol]);
333
+ const parsedOrderBook = Coinray._parseOrderBookUpdate(orderbooks[symbol]);
334
+ this._orderbookSnapshots[symbol] = Coinray._updateOrderBook(this._orderbookSnapshots[symbol], parsedOrderBook);
335
+ callbacks.map((callback) => callback({
336
+ type: "orderBook:update",
337
+ coinraySymbol: symbol,
338
+ orderBook: parsedOrderBook
339
+ }));
340
+ });
341
+ });
342
+ channel.on("error", (payload) => console.error(payload));
343
+ return callback;
344
+ });
345
+ this.unsubscribeOrderBook = ({ coinraySymbol }, callback) => {
346
+ if (callback && this._orderbookListeners[coinraySymbol]) {
347
+ this._orderbookListeners[coinraySymbol] = this._orderbookListeners[coinraySymbol].filter((c) => c !== callback);
348
+ if (this._orderbookListeners[coinraySymbol].length === 0) {
349
+ this.getChannel("orderbooks")
350
+ .push("unsubscribe", { symbols: coinraySymbol }, 5000);
351
+ }
352
+ }
353
+ else {
354
+ this._orderbookSnapshots[coinraySymbol] = { minSeq: 0, maxSeq: 0, bids: {}, asks: {} };
355
+ this._orderbookListeners[coinraySymbol] = [];
356
+ }
357
+ };
358
+ this.subscribeCandles = ({ coinraySymbol, resolution, lastCandle }, callback) => __awaiter(this, void 0, void 0, function* () {
359
+ const candleId = `${coinraySymbol}-${resolution}`;
360
+ if (this._candleListeners[candleId] && this._candleListeners[candleId].length > 0) {
361
+ this._candleListeners[candleId].push(callback);
362
+ return callback;
363
+ }
364
+ this._candleListeners[candleId] = [callback];
365
+ const candleCallback = ({ type, coinraySymbol, trades }) => {
366
+ const callbacks = Object.values(this._candleListeners[candleId]);
367
+ const lastCandles = Coinray._tradesToLastCandle(resolution, trades);
368
+ const lastCandle = lastCandles[lastCandles.length - 1];
369
+ if (lastCandle) {
370
+ if (this._candles[candleId] && type === "trades:snapshot") {
371
+ this._candles[candleId].skipVolume = true;
372
+ }
373
+ this._candles[candleId] = Coinray._mergeCandle(this._candles[candleId], lastCandle);
374
+ callbacks.map((callback) => callback({
375
+ coinraySymbol,
376
+ resolution,
377
+ candle: this._candles[candleId],
378
+ previousCandles: lastCandles
379
+ }));
380
+ }
381
+ };
382
+ if (this._candleTradeListeners[coinraySymbol]) {
383
+ this._candleTradeListeners[coinraySymbol][candleId] = candleCallback;
384
+ }
385
+ else {
386
+ this._candleTradeListeners[coinraySymbol] = { [candleId]: candleCallback };
387
+ }
388
+ this._candles[candleId] = lastCandle || { time: 0 };
389
+ yield this.subscribeTrades({ coinraySymbol }, candleCallback);
390
+ return callback;
391
+ });
392
+ this.unsubscribeCandles = ({ coinraySymbol, resolution }, callback) => {
393
+ const candleId = `${coinraySymbol}-${resolution}`;
394
+ if (callback && this._candleListeners[candleId]) {
395
+ this._candleListeners[candleId] = this._candleListeners[candleId].filter((c) => c !== callback);
396
+ }
397
+ else {
398
+ this._candleListeners[candleId] = [];
399
+ }
400
+ if (this._candleListeners[candleId].length === 0) {
401
+ this.unsubscribeTrades({ coinraySymbol }, this._candleTradeListeners[coinraySymbol][candleId]);
402
+ delete this._candles[candleId];
403
+ delete this._candleTradeListeners[coinraySymbol][candleId];
404
+ }
405
+ };
406
+ this.fetchCandles = ({ coinraySymbol, resolution, start, end, useWebSocket }) => __awaiter(this, void 0, void 0, function* () {
407
+ const minDate = new Date();
408
+ minDate.setMinutes(minDate.getMinutes() - 5);
409
+ let indexedSnapshot = {};
410
+ const candlePromise = this.get("candles", {
411
+ version: "v1",
412
+ params: {
413
+ symbol: coinraySymbol,
414
+ resolution: resolution,
415
+ start_time: start,
416
+ end_time: end
417
+ }
418
+ });
419
+ // Fetch data from the websocket snapshot to merge the highs and lows
420
+ if (useWebSocket && end > minDate.getTime() / 1000) {
421
+ const subscribe = new Promise(resolve => {
422
+ let timeout = setTimeout(() => resolve([]), 1000);
423
+ const onSnapshot = ({ previousCandles }) => {
424
+ clearTimeout(timeout);
425
+ this.unsubscribeCandles({ coinraySymbol, resolution }, onSnapshot);
426
+ resolve(previousCandles);
427
+ };
428
+ this.subscribeCandles({ coinraySymbol, resolution }, onSnapshot);
429
+ });
430
+ const snapshot = yield subscribe;
431
+ indexedSnapshot = _.keyBy(snapshot, ({ time }) => time.getTime());
432
+ }
433
+ const { result } = yield candlePromise;
434
+ return result.map(Coinray._parseCandle).map((candle) => {
435
+ const snapshotCandle = indexedSnapshot[candle.time.getTime()];
436
+ if (snapshotCandle) {
437
+ return Coinray._mergeCandle(candle, snapshotCandle);
438
+ }
439
+ else {
440
+ return candle;
441
+ }
442
+ });
443
+ });
444
+ this.fetchExchanges = () => __awaiter(this, void 0, void 0, function* () {
445
+ const { result: { exchanges } } = yield this.get("exchanges", {
446
+ version: "v1",
447
+ });
448
+ return exchanges.map((exhange) => Exchange.Create(exhange, this));
449
+ });
450
+ this.fetchMarkets = (exchange) => __awaiter(this, void 0, void 0, function* () {
451
+ const { result: { markets } } = yield this.get("markets", {
452
+ version: "v1",
453
+ params: {
454
+ exchange
455
+ }
456
+ });
457
+ return markets.map((market) => {
458
+ try {
459
+ return Market.Create(market, this);
460
+ }
461
+ catch (error) {
462
+ return new Market(market, this);
463
+ }
464
+ });
465
+ });
466
+ this.fetchTrades = (coinraySymbol) => __awaiter(this, void 0, void 0, function* () {
467
+ const { result: trades } = yield this.get("trades", {
468
+ version: "v1",
469
+ params: {
470
+ symbol: coinraySymbol
471
+ }
472
+ });
473
+ return trades.map(Coinray._parseTrade);
474
+ });
475
+ this.fetchOrderBook = (coinraySymbol) => __awaiter(this, void 0, void 0, function* () {
476
+ const { result: { seq, asks, bids } } = yield this.get("order_book", {
477
+ version: "v1",
478
+ params: {
479
+ symbol: coinraySymbol
480
+ }
481
+ });
482
+ return Coinray._parseOrderBookSnapshot({ seq, asks, bids });
483
+ });
484
+ this.createCredential = (deviceId, password) => __awaiter(this, void 0, void 0, function* () {
485
+ const publicKey = yield this.publicKey();
486
+ try {
487
+ const encryptedPassword = yield encryptPayload(yield createJWT({ password }), publicKey);
488
+ const { result } = yield this.post("credentials", {
489
+ secret: password,
490
+ body: {
491
+ deviceId, encryptedPassword
492
+ }
493
+ });
494
+ return result;
495
+ }
496
+ catch (error) {
497
+ throw error;
498
+ }
499
+ });
500
+ this.wrapApiKey = (apiKeySettings) => __awaiter(this, void 0, void 0, function* () {
501
+ const publicKey = yield this.publicKey();
502
+ try {
503
+ const apiKey = JSON.stringify(apiKeySettings);
504
+ const encryptedApiKey = yield encryptPayload(yield createJWT({ apiKey }), publicKey);
505
+ const { result } = yield this.post("credentials/wrap_api_key", {
506
+ secret: this._sessionKey,
507
+ body: {
508
+ encryptedApiKey, credential: this._credential
509
+ }
510
+ });
511
+ return result;
512
+ }
513
+ catch (error) {
514
+ throw error;
515
+ }
516
+ });
517
+ this.testAccount = (accountTest) => __awaiter(this, void 0, void 0, function* () {
518
+ try {
519
+ const { result } = yield this.post("account/test", {
520
+ secret: this._sessionKey,
521
+ apiEndpoint: this.config.orderEndpoint,
522
+ body: Object.assign(Object.assign({}, accountTest), { credential: this._credential })
523
+ });
524
+ return result;
525
+ }
526
+ catch (error) {
527
+ throw error;
528
+ }
529
+ });
530
+ this.createSmartOrderSignature = (smartOrder) => __awaiter(this, void 0, void 0, function* () {
531
+ try {
532
+ const { result } = yield this.post("order/smart_order_signature", {
533
+ secret: this._sessionKey,
534
+ apiEndpoint: this.config.orderEndpoint,
535
+ body: { smartOrder, credential: this._credential }
536
+ });
537
+ return result;
538
+ }
539
+ catch (error) {
540
+ throw error;
541
+ }
542
+ });
543
+ this.createOrder = (order) => __awaiter(this, void 0, void 0, function* () {
544
+ try {
545
+ const { result } = yield this.post("order", {
546
+ secret: this._sessionKey,
547
+ apiEndpoint: this.config.orderEndpoint,
548
+ body: Object.assign(Object.assign({}, order), { credential: this._credential })
549
+ });
550
+ return result;
551
+ }
552
+ catch (error) {
553
+ throw error;
554
+ }
555
+ });
556
+ this.updateOrder = (order) => __awaiter(this, void 0, void 0, function* () {
557
+ try {
558
+ const { result } = yield this.patch("order", {
559
+ secret: this._sessionKey,
560
+ apiEndpoint: this.config.orderEndpoint,
561
+ body: Object.assign(Object.assign({}, order), { credential: this._credential })
562
+ });
563
+ return result;
564
+ }
565
+ catch (error) {
566
+ throw error;
567
+ }
568
+ });
569
+ this.cancelOrder = (order) => __awaiter(this, void 0, void 0, function* () {
570
+ try {
571
+ const { result } = yield this.delete("order", {
572
+ secret: this._sessionKey,
573
+ apiEndpoint: this.config.orderEndpoint,
574
+ body: Object.assign(Object.assign({}, order), { credential: this._credential })
575
+ });
576
+ return result;
577
+ }
578
+ catch (error) {
579
+ throw error;
580
+ }
581
+ });
582
+ this.createWebSocketToken = ({ exchangeCode, encryptedApiKey }) => __awaiter(this, void 0, void 0, function* () {
583
+ try {
584
+ const { result } = yield this.post("exchanges/ws_token", {
585
+ secret: this._sessionKey,
586
+ apiEndpoint: this.config.orderEndpoint,
587
+ body: { encryptedApiKey, exchangeCode, credential: this._credential }
588
+ });
589
+ return result;
590
+ }
591
+ catch (error) {
592
+ throw error;
593
+ }
594
+ });
595
+ this.fetchPositions = ({ exchangeCode, encryptedApiKey }) => __awaiter(this, void 0, void 0, function* () {
596
+ try {
597
+ const { result } = yield this.get("futures/positions", {
598
+ secret: this._sessionKey,
599
+ apiEndpoint: this.config.orderEndpoint,
600
+ params: {
601
+ credential: this._credential,
602
+ exchangeCode,
603
+ encryptedApiKey
604
+ }
605
+ });
606
+ return result;
607
+ }
608
+ catch (error) {
609
+ throw error;
610
+ }
611
+ });
612
+ this.getBalances = ({ exchangeCode, encryptedApiKey }) => __awaiter(this, void 0, void 0, function* () {
613
+ try {
614
+ const { result: { balances, positions } } = yield this.get("account/balances", {
615
+ secret: this._sessionKey,
616
+ apiEndpoint: this.config.orderEndpoint,
617
+ params: {
618
+ credential: this._credential,
619
+ exchangeCode,
620
+ encryptedApiKey
621
+ }
622
+ });
623
+ return { balances: balances.map(Coinray._parseBalance), positions };
624
+ }
625
+ catch (error) {
626
+ throw error;
627
+ }
628
+ });
629
+ this.setLeverage = ({ coinraySymbol, leverage, encryptedApiKey }) => __awaiter(this, void 0, void 0, function* () {
630
+ try {
631
+ const { result } = yield this.post("futures/leverage", {
632
+ secret: this._sessionKey,
633
+ apiEndpoint: this.config.orderEndpoint,
634
+ body: {
635
+ credential: this._credential,
636
+ coinraySymbol,
637
+ leverage,
638
+ encryptedApiKey
639
+ }
640
+ });
641
+ return result;
642
+ }
643
+ catch (error) {
644
+ throw error;
645
+ }
646
+ });
647
+ this.setMarginType = ({ coinraySymbol, marginType, encryptedApiKey }) => __awaiter(this, void 0, void 0, function* () {
648
+ try {
649
+ const { result } = yield this.post("futures/margin_type", {
650
+ secret: this._sessionKey,
651
+ apiEndpoint: this.config.orderEndpoint,
652
+ body: {
653
+ credential: this._credential,
654
+ coinraySymbol,
655
+ marginType,
656
+ encryptedApiKey
657
+ }
658
+ });
659
+ return result;
660
+ }
661
+ catch (error) {
662
+ throw error;
663
+ }
664
+ });
665
+ this.get = (endpoint, { apiEndpoint = undefined, version = "v2", headers = {}, params = {}, secret = "" } = {}) => __awaiter(this, void 0, void 0, function* () {
666
+ return yield this._request(endpoint, "GET", {
667
+ version,
668
+ apiEndpoint,
669
+ headers,
670
+ secret,
671
+ params
672
+ });
673
+ });
674
+ this.post = (endpoint, attributes) => __awaiter(this, void 0, void 0, function* () { return yield this._request(endpoint, "POST", attributes); });
675
+ this.patch = (endpoint, attributes) => __awaiter(this, void 0, void 0, function* () { return yield this._request(endpoint, "PATCH", attributes); });
676
+ this.delete = (endpoint, attributes) => __awaiter(this, void 0, void 0, function* () { return yield this._request(endpoint, "delete", attributes); });
677
+ this._token = token;
678
+ this._nonceOffset = 0;
679
+ this._timeOffset = 0;
680
+ this._firstOpen = true;
681
+ this.config = {
682
+ apiEndpoint: apiEndpoint || "https://coinray.io",
683
+ orderEndpoint: orderEndpoint || apiEndpoint || "https://coinray.io",
684
+ websocketEndpoint: websocketEndpoint || "wss://ws.coinray.io/v1"
685
+ };
686
+ this.loadTimeOffset().then();
687
+ this._timeOffsetInterval = setInterval(this.loadTimeOffset, 60 * 1000);
688
+ }
689
+ publicKey() {
690
+ return __awaiter(this, void 0, void 0, function* () {
691
+ if (!this._publicKey) {
692
+ const { result: { jwk } } = yield this.get("credentials/certificate");
693
+ this._publicKey = yield jwkToPublicKey(jwk);
694
+ }
695
+ return this._publicKey;
696
+ });
697
+ }
698
+ get clientId() {
699
+ return parseJWT(this._token).header.kid;
700
+ }
701
+ get socket() {
702
+ if (!this._token) {
703
+ throw new Error("Token not present");
704
+ }
705
+ if (!this._socket) {
706
+ this._socket = new Socket(this.config.websocketEndpoint, {
707
+ heartbeatIntervalMs: 5000,
708
+ transport: this._transport,
709
+ reconnectAfterMs: (tries) => {
710
+ if (jwtExpired(this._token)) {
711
+ return 30000;
712
+ }
713
+ else {
714
+ return 1000;
715
+ }
716
+ }
717
+ });
718
+ this.onOpen(this.resubscribe);
719
+ }
720
+ // @ts-ignore
721
+ this._socket.params = () => ({ reconnect: true, token: this._token, client: "coinrayjs", version: VERSION });
722
+ return this._socket;
723
+ }
724
+ getChannel(name) {
725
+ this.connect();
726
+ if (this._channels[name]) {
727
+ return this._channels[name];
728
+ }
729
+ const channel = this.socket.channel(name, {});
730
+ this._channels[name] = channel;
731
+ channel.join();
732
+ return channel;
733
+ }
734
+ _request(endpoint, method, { apiEndpoint, version = "v2", headers = {}, params = {}, body = {}, secret = "" }) {
735
+ return __awaiter(this, void 0, void 0, function* () {
736
+ const token = yield this.getToken();
737
+ const paramString = Object.entries(params).length > 0 ? '?' + Object.entries(params).map(([key, val]) => val ? `${key}=${val}` : undefined).filter(Boolean).join('&') : "";
738
+ const nonce = this.getNonce();
739
+ const requestUri = `/api/${version}/${endpoint}${paramString}`;
740
+ if (version === "v2") {
741
+ const dataToSign = [nonce, method.toUpperCase(), requestUri, method === "GET" ? "" : JSON.stringify(body)].join("");
742
+ const signature = signHMAC(dataToSign, secret);
743
+ headers = Object.assign(Object.assign({}, headers), { "Cr-Access-Token": `${token}`, "Cr-Nonce": nonce, "Cr-Signature": signature });
744
+ }
745
+ const options = {
746
+ method,
747
+ url: (apiEndpoint || this.config.apiEndpoint) + requestUri,
748
+ timeout: 20000,
749
+ headers: Object.assign({ "Accept": "application/json", "Content-Type": "application/json", "Authorization": `Bearer ${token}`, "Cr-Client-version": VERSION }, headers),
750
+ data: method === "GET" ? undefined : JSON.stringify(body)
751
+ };
752
+ try {
753
+ const response = yield axios(options);
754
+ let result;
755
+ if (response.status === 200) {
756
+ result = response.data;
757
+ }
758
+ else if (response.status === 204) {
759
+ result = {};
760
+ }
761
+ else {
762
+ result = response.data;
763
+ }
764
+ return { result: camelize(result), _headers: response.headers };
765
+ }
766
+ catch (error) {
767
+ const { response, request } = error;
768
+ if (response) {
769
+ const { error } = response.data;
770
+ throw new CoinrayError(error);
771
+ }
772
+ else {
773
+ throw error;
774
+ }
775
+ }
776
+ });
777
+ }
778
+ static _parseOrderBookSnapshot({ asks, bids, min_seq, max_seq }) {
779
+ return {
780
+ minSeq: min_seq,
781
+ maxSeq: max_seq,
782
+ asks: Coinray._parseBidAsk(asks),
783
+ bids: Coinray._parseBidAsk(bids),
784
+ };
785
+ }
786
+ static _parseOrderBookUpdate({ asks_diff, bids_diff, min_seq, max_seq }) {
787
+ return {
788
+ minSeq: min_seq,
789
+ maxSeq: max_seq,
790
+ asks: Coinray._parseBidAsk(asks_diff),
791
+ bids: Coinray._parseBidAsk(bids_diff),
792
+ };
793
+ }
794
+ static _updateOrderBook(orderBook, { asks, bids, min_seq, max_seq }) {
795
+ const update = (side, updates) => {
796
+ _.forEach(updates, (quantity, price) => {
797
+ if (quantity.gt(0)) {
798
+ side[price] = quantity;
799
+ }
800
+ else {
801
+ delete side[price];
802
+ }
803
+ });
804
+ };
805
+ orderBook.minSeq = min_seq;
806
+ orderBook.maxSeq = max_seq;
807
+ update(orderBook.bids, bids);
808
+ update(orderBook.asks, asks);
809
+ return orderBook;
810
+ }
811
+ static _parseBidAsk(bidAsk) {
812
+ if (Array.isArray(bidAsk)) {
813
+ return bidAsk.reduce((acc, [price, quantity]) => {
814
+ acc[price] = new BigNumber(quantity);
815
+ return acc;
816
+ }, {});
817
+ }
818
+ else {
819
+ return Object.keys(bidAsk).reduce((acc, price) => {
820
+ acc[price] = new BigNumber(bidAsk[price]);
821
+ return acc;
822
+ }, {});
823
+ }
824
+ }
825
+ static _parseCandle(result) {
826
+ if (result) {
827
+ const [time, open, high, low, close, baseVolume, quoteVolume] = result;
828
+ return {
829
+ time: safeTime(time),
830
+ open: safeBigNumber(open),
831
+ high: safeBigNumber(high),
832
+ low: safeBigNumber(low),
833
+ close: safeBigNumber(close),
834
+ baseVolume: safeBigNumber(baseVolume),
835
+ quoteVolume: safeBigNumber(quoteVolume),
836
+ };
837
+ }
838
+ else {
839
+ throw new Error("Candle");
840
+ }
841
+ }
842
+ static _parseTrade([id, time, price, quantity, isBuy]) {
843
+ return {
844
+ id,
845
+ time: safeTime(time),
846
+ price: safeBigNumber(price),
847
+ quantity: safeBigNumber(quantity),
848
+ type: ['1', 'buy'].includes(isBuy.toString()) ? "buy" : "sell"
849
+ };
850
+ }
851
+ static _parseTicker(ticker) {
852
+ return {
853
+ askPrice: safeBigNumber(ticker.a),
854
+ baseVolume: safeBigNumber(ticker.bv),
855
+ bidPrice: safeBigNumber(ticker.b),
856
+ btcVolume: safeBigNumber(ticker.B),
857
+ coinraySymbol: ticker.s,
858
+ highPrice1s: safeBigNumber(ticker.h),
859
+ highPrice24h: safeBigNumber(ticker.H),
860
+ lastPrice: safeBigNumber(ticker.c),
861
+ lowPrice1s: safeBigNumber(ticker.l),
862
+ lowPrice24h: safeBigNumber(ticker.L),
863
+ openPrice1s: safeBigNumber(ticker.o),
864
+ openPrice24h: safeBigNumber(ticker.O),
865
+ quoteVolume: safeBigNumber(ticker.qv),
866
+ usdVolume: safeBigNumber(ticker.U)
867
+ };
868
+ }
869
+ static _parseBalance(balance) {
870
+ let newBalance = {
871
+ currency: balance.currency,
872
+ available: safeBigNumber(balance.available),
873
+ inOrders: safeBigNumber(balance.inOrders),
874
+ total: safeBigNumber(balance.inOrders),
875
+ };
876
+ if (balance.initialMargin) {
877
+ newBalance = Object.assign(Object.assign({}, newBalance), {
878
+ initialMargin: safeBigNumber(balance.initialMargin),
879
+ openOrderInitialMargin: safeBigNumber(balance.openOrderInitialMargin),
880
+ positionInitialMargin: safeBigNumber(balance.positionInitialMargin),
881
+ unrealizedProfit: safeBigNumber(balance.unrealizedProfit),
882
+ crossWalletBalance: safeBigNumber(balance.crossWalletBalance),
883
+ crossUnrealizedProfit: safeBigNumber(balance.crossUnrealizedProfit),
884
+ });
885
+ }
886
+ return newBalance;
887
+ }
888
+ static _tradesToLastCandle(resolution, trades) {
889
+ if (trades.length > 0 && trades[0].time > trades[trades.length - 1].time) {
890
+ trades = trades.reverse();
891
+ }
892
+ const seconds = Coinray._resolutionToSeconds(resolution);
893
+ const groupedTrades = _.groupBy(trades.reverse(), ({ time }) => Math.floor(time.getTime() / seconds) * seconds);
894
+ return _.sortBy(Object.keys(groupedTrades), (date) => parseInt(date)).map((date) => {
895
+ const currentCandleTrades = groupedTrades[date];
896
+ const currentTime = currentCandleTrades[0].time.getTime();
897
+ const startDate = new Date(currentTime - (currentTime % seconds));
898
+ if (currentCandleTrades.length === 0) {
899
+ return undefined;
900
+ }
901
+ let first = currentCandleTrades[0];
902
+ let open, low, high, close;
903
+ let baseVolume = new BigNumber(0);
904
+ let quoteVolume = new BigNumber(0);
905
+ open = low = high = close = first.price;
906
+ currentCandleTrades.reverse().map(({ price, quantity }) => {
907
+ low = BigNumber.min(low, price);
908
+ high = BigNumber.max(high, price);
909
+ close = price;
910
+ baseVolume = baseVolume.plus(quantity);
911
+ quoteVolume = quoteVolume.plus(quantity.multipliedBy(price));
912
+ });
913
+ return {
914
+ time: new Date(startDate),
915
+ open,
916
+ high,
917
+ low,
918
+ close,
919
+ baseVolume,
920
+ quoteVolume,
921
+ };
922
+ });
923
+ }
924
+ ;
925
+ static _mergeCandle(currentCandle, candle) {
926
+ if (!currentCandle || currentCandle.time < candle.time) {
927
+ return candle;
928
+ }
929
+ currentCandle.high = BigNumber.max(currentCandle.high, candle.high);
930
+ currentCandle.low = BigNumber.min(currentCandle.low, candle.low);
931
+ currentCandle.close = candle.close;
932
+ if (currentCandle.skipVolume) {
933
+ currentCandle.skipVolume = false;
934
+ }
935
+ else {
936
+ currentCandle.baseVolume = currentCandle.baseVolume.plus(candle.baseVolume);
937
+ currentCandle.quoteVolume = currentCandle.quoteVolume.plus(candle.quoteVolume);
938
+ }
939
+ return currentCandle;
940
+ }
941
+ static _resolutionToSeconds(resolution) {
942
+ if (resolution.indexOf("W") > 0) {
943
+ return parseInt(resolution) * 24 * 60 * 60 * 1000;
944
+ }
945
+ else if (resolution.indexOf("D") > 0) {
946
+ return parseInt(resolution) * 24 * 60 * 60 * 1000;
947
+ }
948
+ else if (resolution === "D") {
949
+ return 24 * 60 * 60 * 1000;
950
+ }
951
+ else {
952
+ return parseInt(resolution) * 60 * 1000;
953
+ }
954
+ }
955
+ }
956
+ Coinray.I18n = I18n;
957
+ //# sourceMappingURL=coinray.js.map