forked from AndrewBarba/bittrex-node
-
Notifications
You must be signed in to change notification settings - Fork 2
/
bittrex-client.ts
1029 lines (922 loc) · 32.8 KB
/
bittrex-client.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
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
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
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
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
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
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
import axios, { AxiosInstance, Method } from 'axios'
import * as crypto from 'crypto'
import * as https from 'https'
import * as querystring from 'querystring'
import * as BTT from './bittrex-types'
class BittrexClient {
private _apiKey: string
private _apiSecret: string
private _client: AxiosInstance
/**
* Create a new client instance with API Keys
* @param param0
*/
constructor({ apiKey, apiSecret, keepAlive = true }: {
apiKey: string,
apiSecret: string,
keepAlive?: boolean
}) {
this._apiKey = apiKey
this._apiSecret = apiSecret
this._client = axios.create({
baseURL: 'https://api.bittrex.com/v3',
httpsAgent: new https.Agent({ keepAlive })
})
}
/**
* REFERENCE: https://bittrex.github.io/api/v3
*/
//#region V3 ACCOUNT ENDPOINTS (8 endpoints)
/**
* Retrieve information for the account associated with the request.
* For now, it only echoes the subaccount if one was specified in the header,
* which can be used to verify that one is operating on the intended account.
* More fields will be added later.
* @returns {Promise}
*/
async account(): Promise<BTT.Account> {
return this.request('get', '/account')
}
/**
* Get trade fee for the given marketSymbol.
* Get trade fees for each markets when marketSymbol is not provided.
* @param {string} marketSymbol
* @returns {Promise}
*/
async accountFeesTrading(): Promise<BTT.CommissionRatesWithMarket[]>;
/**
* Get trade fee for the given marketSymbol.
* @param marketSymbol
*/
async accountFeesTrading(marketSymbol: string): Promise<BTT.CommissionRatesWithMarket>;
async accountFeesTrading(marketSymbol?: string) {
if (marketSymbol) {
return this.request('get', '/account/fees/trading/' + marketSymbol)
}
return this.request('get', '/account/fees/trading')
}
/**
* Get 30 day volume for account
* @returns {Promise}
*/
async accountVolume(): Promise<BTT.AccountVolume> {
return this.request('get', '/account/volume')
}
/**
* Get trading permissions when marketSymbol is not provided.
* Get trading permissions for a single market.
* @param {string} marketSymbol
* @returns {Promise}
*/
async accountPermissionsMarkets(marketSymbol?: string): Promise<BTT.MarketPolicy[]> {
if (marketSymbol) {
return this.request('get', '/account/permissions/markets/' + marketSymbol)
}
return this.request('get', '/account/permissions/markets')
}
/**
* Get currency permissions for a single currency.
* Get all currency permissions when marketSymbol is not provided.
* @param {string} marketSymbol
* @returns {Promise}
*/
async accountPermissionsCurrencies(marketSymbol?: string): Promise<BTT.CurrencyPolicy[]> {
if (marketSymbol) {
return this.request('get', '/account/permissions/currencies/' + marketSymbol)
}
return this.request('get', '/account/permissions/currencies')
}
//#endregion
//#region V3 ADDRESSES ENDPOINTS (3 endpoints)
/**
* List deposit addresses that have been requested or provisioned.
* Retrieve the status of the deposit address for a particular currency for which one has been requested or provisioned.
* @param {string} marketSymbol
* @returns {Promise}
*/
async addresses(): Promise<BTT.Address[]>
/**
* Retrieve the status of the deposit address for a particular currency for which one has been requested or provisioned.
* Alias of addressesStatus(marketSymbol)
* @param marketSymbol symbol of the currency to retrieve the deposit address for
* @returns
*/
async addresses(marketSymbol: string): Promise<BTT.Address>
async addresses(marketSymbol?: string) {
if (marketSymbol) {
return this.request('get', '/addresses/' + marketSymbol)
}
return this.request('get', '/addresses')
}
/**
* Retrieve the status of the deposit address for a particular currency for which one has been requested or provisioned.
* Alias of addresses(marketSymbol)
* @param marketSymbol symbol of the currency to retrieve the deposit address for
* @returns
*/
async addressStatus(marketSymbol: string) {
return this.addresses(marketSymbol);
}
/**
* Request provisioning of a deposit address for a currency
* for which no address has been requested or provisioned.
* @param {string} marketSymbol
* @returns {Promise}
*/
async addressCreate(marketSymbol: string): Promise<BTT.Address> {
return this.request('post', '/addresses', {
body: {
currencySymbol: marketSymbol
}
})
}
//#endregion
//#region V3 BALANCES ENDPOINTS (3 endpoints)
/**
* List account balances across available currencies.
* Returns a Balance entry for each currency for which there
* is either a balance or an address.
* @returns {Promise}
*/
async balances(): Promise<BTT.Balance[]> {
return this.request('get', '/balances');
}
/**
* Retrieve account balance for a specific currency.
* Request will always succeed when the currency exists,
* regardless of whether there is a balance or address.
* @param {string} marketSymbol
* @returns {Promise}
*/
async balance(marketSymbol: string): Promise<BTT.Balance> {
return this.request('get', '/balances/' + marketSymbol);
}
/**
* Get sequence of balances snapshot.
* @returns {Promise}
*/
async headBalances(): Promise<void> {
return this.request('head', '/balances')
}
//#endregion
//#region V3 BATCH ENDPOINTS (1 endpoint)
/**
* Create a new batch request.
* Currently batch requests are limited to placing and cancelling orders.
* The request model corresponds to the equivalent individual operations.
* Batch operations are executed sequentially in the order
* they are listed in the request.
* The response will return one result for each operation in the request
* in the same order.
* The status and response payload are the same as the responses
* would be if individual API requests were made for each operation.
* @param payload List of operations in the batch
* @returns
*/
async batch(payload: BTT.BatchSchemaBody): Promise<{
status: number
payload: any
}[]> {
return this.request('post', '/batch', { body: payload })
}
//#endregion
//#region V3 ConditionalOrders ENDPOINTS (6 endpoints)
/**
* Retrieve information on a specific conditional order.
* @param conditionalOrderId (uuid-formatted string) - ID of conditional order to retrieve
* @returns
*/
async conditionalOrders(conditionalOrderId: string): Promise<BTT.ConditionalOrder> {
return this.request('get', '/conditional-orders/' + conditionalOrderId)
}
/**
* Cancel a conditional order.
* @param conditionalOrderId (uuid-formatted string) - ID of order to cancel
* @returns
*/
async conditionalOrderDelete(conditionalOrderId: string): Promise<BTT.ConditionalOrder> {
return this.request('delete', '/conditional-orders/' + conditionalOrderId)
}
/**
* List closed conditional orders.
* StartDate and EndDate filters apply to the ClosedAt field.
* Pagination and the sort order of the results are in inverse
* order of the ClosedAt field.
* @param props
* @returns
*/
async conditionalOrdersClosed(props?: {
marketSymbol: string
nextPageToken: string
previousPageToken: string
pageSize: number
startDate: string
endDate: string
}): Promise<BTT.ConditionalOrder[]> {
return this.request('get', '/conditional-orders/closed', { params: props })
}
/**
* List open conditional orders.
* @param marketSymbol filter by market (optional)
* @returns
*/
async conditionalOrdersOpen(marketSymbol?: string): Promise<BTT.ConditionalOrder[]> {
return this.request('get', '/conditional-orders/open', { params: { marketSymbol } })
}
/**
* Get sequence of open conditional orders snapshot.
* @returns
*/
async headConditionalOrdersOpen(): Promise<void> {
return this.request('head', '/conditional-orders/open')
}
/**
* Create a new conditional order.
* @param newConditionalOrder information specifying the conditional order to create
* @returns
*/
async conditionalOrdersCreate(newConditionalOrder: BTT.NewConditionalOrder): Promise<BTT.ConditionalOrder> {
return this.request('post', '/conditional-orders', { body: newConditionalOrder })
}
//#endregion
//#region V3 CURRENCIES ENDPOINTS (2 endpoints)
/**
* List currencies.
*/
async currencies(): Promise<BTT.Currency[]>;
/**
* Retrieve info on a specified currency.
* @param marketSymbol symbol of the currency to retrieve
*/
async currencies(marketSymbol: string): Promise<BTT.Currency>;
async currencies(marketSymbol?: any) {
if (marketSymbol) {
return this.request('get', '/currencies/' + marketSymbol)
}
return this.request('get', '/currencies');
}
//#endregion
//#region V3 DEPOSITS ENDPOINTS (5 endpoints)
/**
* List open deposits.
* Results are sorted in inverse order of UpdatedAt,
* and are limited to the first 1000.
* @param props
* @returns
*/
async depositsOpen(props?: {
status: string
currencySymbol: string
}): Promise<BTT.Deposit[]> {
return this.request('get', '/deposits/open', { params: props })
}
/**
* Get open deposits sequence.
* @returns {Promise}
*/
async headDepositsOpen(): Promise<void> {
return this.request('head', '/deposits/open')
}
/**
* List closed deposits.
* StartDate and EndDate filters apply to the CompletedAt field.
* Pagination and the sort order of the results are in inverse
* order of the CompletedAt field.
* @returns
*/
async depositsClosed(props?: {
status?: 'completed' | 'orphaned' | 'invalidated'
currencySymbol?: string
nextPageToken?: string
previousPageToken?: string
pageSize?: number
startSate?: string
endDate?: string
}): Promise<BTT.Deposit[]> {
return this.request('get', '/deposits/closed', { params: props })
}
/**
* Retrieves all deposits for this account with the given TxId
* @param txId the transaction id to lookup
* @returns
*/
async depositsByTxId(txId: string): Promise<BTT.Deposit[]> {
return this.request('get', '/deposits/ByTxId/' + txId)
}
/**
* Retrieve information for a specific deposit.
* @param depositId (uuid-formatted string) - ID of the deposit to retrieve
* @returns
*/
async deposits(depositId: string) {
return this.request('get', '/deposits/' + depositId)
}
//#endregion
//#region V3 EXECUTIONS ENDPOINTS (4 endpoints)
/**
* Retrieve information on a specific execution.
* NOTE: Executions from before 5/27/2019 are not available.
* Also, there may be a delay before an executed trade is visible in this endpoint.
* @param executionId (uuid-formatted string) - ID of execution to retrieve
*/
async executions(executionId: string): Promise<BTT.Execution>;
/**
* List historical executions for account.
* Pagination and the sort order of the results are
* in inverse order of the Executed field.
*
* NOTE: Executions from before 5/27/2019 are not available.
* Also, there may be a delay before an executed trade
* is visible in this endpoint.
* @param props
*/
async executions(props: BTT.ExecutionsRequestParams): Promise<BTT.Execution[]>;
async executions(props: any) {
if (typeof props === 'string') {
return this.request('get', '/executions/' + props)
}
return this.request('get', '/executions', { params: props });
}
/**
* Gets sequence number and last execution id.
* @returns {Promise}
*/
async executionLastId(): Promise<BTT.ExecutionLastId> {
return this.request('get', '/executions/last-id')
}
/**
* Get sequence number for executions.
* @returns
*/
async headExecutionLastId(): Promise<void> {
return this.request('head', '/executions/last-id')
}
//#endregion
//#region V3 FundsTransferMethods ENDPOINTS (1 endpoints)
/**
* Get details about a linked bank account
* @param fundsTransferMethodId (uuid-formatted string) - ID of funds transfer method to retrieve
* @returns
*/
async fundsTransferMethods(fundsTransferMethodId: string): Promise<BTT.FundsTransferMethod> {
return this.request('get', '/funds-transfer-methods/' + fundsTransferMethodId)
}
//#endregion
//#region V3 Markets ENDPOINTS (15 endpoints)
/**
* List markets.
* @returns
*/
async markets(): Promise<BTT.Market[]> {
const results = await this.request('get', '/markets')
return this.parseDates(results, ['createdAt'])
}
/**
* List summaries of the last 24 hours of activity for all markets.
* @returns
*/
async marketsSummaries(): Promise<BTT.MarketSummary[]> {
const results = await this.request('get', '/markets/summaries')
return this.parseDates(results, ['updatedAt'])
}
/**
* Retrieve the current sequence number for the market summaries snapshot.
* @returns
*/
async headMarketsSummaries(): Promise<void> {
return this.request('head', '/markets/summaries')
}
/**
* List tickers for all markets.
* @returns
*/
async marketsTickers(): Promise<BTT.Ticker[]> {
return this.request('get', '/markets/tickers')
}
/**
* Retrieve the current sequence number for the tickers snapshot.
* @returns
*/
async headMarketsTickers(): Promise<void> {
return this.request('head', '/markets/tickers')
}
/**
* Retrieve the ticker for a specific market.
* @param marketSymbol symbol of market to retrieve ticker for
* @returns
*/
async marketTicker(marketSymbol: string): Promise<BTT.Ticker> {
return this.request('get', '/markets/' + marketSymbol + '/ticker')
}
/**
* Retrieve information for a specific market.
* @param marketSymbol symbol of market to retrieve
* @returns
*/
async market(marketSymbol: string): Promise<BTT.Market> {
return this.request('get', '/markets/' + marketSymbol)
}
/**
* Retrieve summary of the last 24 hours of activity for a specific market.
* @param marketSymbol symbol of market to retrieve summary for
* @returns
*/
async marketSummary(marketSymbol: string): Promise<BTT.MarketSummary> {
return this.request('get', '/markets/' + marketSymbol + '/summary')
}
/**
* Retrieve the order book for a specific market.
* @param marketSymbol symbol of market to retrieve order book for
* @param depth maximum depth of order book to return (optional, allowed values are [1, 25, 500], default is 25)
* @returns
*/
async marketOrderBook(marketSymbol: string, depth?: number): Promise<BTT.OrderBook> {
if (depth && ![1, 25, 500].includes(depth)) {
throw Error('DEPTH_INVALID')
}
return this.request('get', '/markets/' + marketSymbol + '/orderbook', { params: { depth } })
}
/**
* Retrieve the current sequence number for the specified market's order book snapshot.
* @param marketSymbol symbol of market to retrieve order book for
* @param depth maximum depth of order book to return (optional, allowed values are [1, 25, 500], default is 25)
* @returns
*/
async headMarketOrderBook(marketSymbol: string, depth?: number): Promise<void> {
return this.request('head', '/markets/' + marketSymbol + '/orderbook', { params: { depth } })
}
/**
* Retrieve the recent trades for a specific market.
* @param marketSymbol symbol of market to retrieve recent trades for
* @returns
*/
async marketTrades(marketSymbol: string): Promise<BTT.Trade[]> {
return this.request('get', '/markets/' + marketSymbol + '/trades')
}
/**
* Retrieve the current sequence number for the specified market's recent trades snapshot.
* @param marketSymbol symbol of market to retrieve order book for
* @returns
*/
async headMarketTrades(marketSymbol: string): Promise<void> {
return this.request('head', '/markets/' + marketSymbol + '/trade')
}
/**
* Retrieve recent candles for a specific market and candle interval.
* The maximum age of the returned candles
* depends on the interval as follows:
* (MINUTE_1: 1 day, MINUTE_5: 1 day, HOUR_1: 31 days, DAY_1: 366 days).
* Candles for intervals without any trading activity
* will match the previous close and volume will be zero.
* @param marketSymbol symbol of market to retrieve candles for
* @param candleInterval desired time interval between candles
* @param candleType type of candles (trades or midpoint). This portion of the url may be omitted if trade based candles are desired (e.g. /candles/{candleInterval}/recent will return trade based candles)
* @returns
*/
async marketCandles(marketSymbol: string, candleInterval: 'MINUTE_1' | 'MINUTE_5' | 'HOUR_1' | 'DAY_1', candleType?: 'TRADE' | 'MIDPOINT'): Promise<BTT.Candle[]> {
return this.request('get', '/markets/' + marketSymbol + '/candles/' + (!!candleType ? candleType + '/' : '') + candleInterval + '/recent')
}
/**
* Retrieve the current sequence number for the specified market's candles snapshot.
* @param marketSymbol symbol of market to retrieve candles for
* @param candleInterval desired time interval between candles
* @param candleType type of candles (trades or midpoint). This portion of the url may be omitted if trade based candles are desired (e.g. /candles/{candleInterval}/recent will return trade based candles)
* @returns
*/
async headMarketCandles(marketSymbol: string, candleInterval: 'MINUTE_1' | 'MINUTE_5' | 'HOUR_1' | 'DAY_1', candleType?: 'TRADE' | 'MIDPOINT'): Promise<void> {
return this.request('head', '/markets/' + marketSymbol + '/candles/' + (!!candleType ? candleType + '/' : '') + candleInterval + '/recent')
}
/**
* Retrieve recent candles for a specific market and candle interval.
* The date range of returned candles depends on the interval as follows:
* (MINUTE_1: 1 day, MINUTE_5: 1 day, HOUR_1: 31 days, DAY_1: 366 days).
* Candles for intervals without any trading activity
* will match the previous close and volume will be zero.
*
* WARNING: (Not documented in the official API).
* The optional params are not arbitrary, are not really "optional".
*
* If you specify YEAR, MONTH and DAY, interval must be DAY_1
*
* If you specify YEAR and MONTH (omit day), interval must be HOUR_1
*
* If you only specify YEAR (omit month and day), interval must be MINUTE_1 or MINUTE_5
*
* In the future: Overload function to lock fixed params depending on the candleInterval value to avoid api call errors.
*
* @param marketSymbol symbol of market to retrieve candles for
* @param candleInterval desired time interval between candles
* @param year desired year to start from
* @param candleType type of candles (trades or midpoint). This portion of the url may be omitted if trade based candles are desired (e.g. /candles/{candleInterval}/historical/{year} will return trade based candles)
* @param month desired month to start from (if applicable)
* @param day desired day to start from (if applicable)
* @returns
*/
async marketCandlesDate(marketSymbol: string, candleInterval: 'MINUTE_1' | 'MINUTE_5' | 'HOUR_1' | 'DAY_1', year: number, candleType?: 'TRADE' | 'MIDPOINT', month?: number, day?: number): Promise<BTT.Candle[]> {
if (!year) throw Error('Invalid year')
if (!month && candleInterval !== 'DAY_1') throw Error('Years can only be DAY_1 interval')
if (year && month && !day && candleInterval !== 'HOUR_1') throw Error('Year+month can only be HOUR_1 interval')
if (day && (candleInterval !== 'MINUTE_1' && candleInterval !== 'MINUTE_5')) throw Error('Year+month+day and only be MINUTE_5 or MINUTE_1 interval')
const url = '/markets/' + marketSymbol + '/candles/' + (!!candleType ? candleType + '/' : '') + candleInterval + '/historical/' + year + (!!month ? '/' + month : '') + (!!day ? '/' + day : '')
return this.request('get', url)
}
//#endregion
//#region V3 Orders ENDPOINTS (8 endpoints)
/**
* List closed orders.
* StartDate and EndDate filters apply to the ClosedAt field.
* Pagination and the sort order of the results are in inverse order of the ClosedAt field.
* @param props
* @returns
*/
async ordersClosed(props?: {
marketSymbol?: string
nextPageToken?: string
previousPageToken?: string
pageSize?: number
startDate: string
endDate: string
}): Promise<BTT.Order[]> {
return this.request('get', '/orders/closed', {
params: props
})
}
/**
* List open orders.
* @param marketSymbol filter by market (optional)
* @returns
*/
async ordersOpen(marketSymbol: string): Promise<BTT.Order[]> {
return this.request('get', '/orders/open', { params: { marketSymbol } })
}
/**
* Bulk cancel all open orders (can be limited to a specified market)
* @param marketSymbol
* @returns
*/
async ordersDelete(marketSymbol: string): Promise<BTT.BulkCancelResult[]> {
return this.request('delete', '/orders/open', { params: { marketSymbol } })
}
/**
* Get sequence of open orders snapshot.
* @returns
*/
async headOrdersOpen(): Promise<void> {
return this.request('head', '/orders/open')
}
/**
* Retrieve information on a specific order.
* @param orderId (uuid-formatted string) - ID of order to retrieve
* @returns
*/
async order(orderId: string): Promise<BTT.Order> {
return this.request('get', '/orders/' + orderId)
}
/**
* Cancel an order.
* @param orderId (uuid-formatted string) - ID of order to cancel
* @returns
*/
async orderDelete(orderId: string): Promise<BTT.Order> {
return this.request('delete', '/orders/' + orderId)
}
/**
* Retrieve executions for a specific order.
*
* Results are sorted in inverse order of execution time, and are limited to the first 1000.
*
* NOTE: Executions from before 5/27/2019 are not available.
*
* Also, there may be a delay before an executed trade is visible in this endpoint.
* @param orderId
* @returns
*/
async ordersExecutions(orderId: string): Promise<BTT.Execution[]> {
return this.request('get', '/orders/' + orderId + '/executions')
}
/**
* Create a new order.
* @param newOrder information specifying the order to create
* @returns
*/
async orderCreate(newOrder: BTT.NewOrder): Promise<BTT.Order> {
return this.request('post', '/orders', { body: newOrder })
}
//#endregion
//#region V3 Ping ENDPOINTS (1 endpoints)
/**
* Pings the service
* @returns {Promise<ServicePing>}
*/
async ping(): Promise<BTT.ServicePing> {
return this.request('get', '/ping');
}
//#endregion
//#region V3 Subaccounts ENDPOINTS (7 endpoints)
/*-------------------------------------------------------------------------*
* WARNING: Subaccounts API are only for partners.
* Regular traders cannot use it.
*-------------------------------------------------------------------------*/
/**
* List subaccounts.
*
* (NOTE: This API is limited to partners and not available for traders.)
*
* Pagination and the sort order of the results are in inverse order of the CreatedAt field.
* @returns
*/
async subaccounts(): Promise<BTT.Subaccount[]>;
/**
* Retrieve details for a specified subaccount. (NOTE: This API is limited to partners and not available for traders.)
* @param subaccountId (uuid-formatted string) - ID of the subaccount to retrieve details for
*/
async subaccounts(subaccountId: string): Promise<BTT.Subaccount>;
async subaccounts(subaccountId?: string) {
if (subaccountId) {
return this.request('get', '/subaccounts/' + subaccountId)
}
return this.request('get', '/subaccounts')
}
/**
* Create a new subaccount.
*
* (NOTE: This API is limited to partners and not available for traders.)
*
* (WARNING: Official API doesn't provide information about NewSubaccount body payload)
* @param payload information specifying the subaccount to create
* @returns
*/
async subaccountCreate(newSubaccount: {}): Promise<BTT.Subaccount> {
return this.request('post', '/subaccounts', { body: newSubaccount })
}
/**
* List open withdrawals for all subaccounts.
*
* Results are sorted in inverse order of the CreatedAt field, and are limited to the first 1000.
* @param options
* @returns
*/
async subaccountWithdrawalsOpen(options?: {
status?: 'requested' | 'authorized' | 'pending' | 'error_invalid_address'
currencySymbol?: string
nextPageToken?: string
previousPageToken?: string
pageSize?: number
startDate?: string
endDate?: string
}): Promise<BTT.Withdrawal> {
return this.request('get', '/subaccounts/withdrawals/open', { params: options })
}
/**
* List closed withdrawals for all subaccounts.
*
* StartDate and EndDate filters apply to the CompletedAt field.
*
* Pagination and the sort order of the results are in inverse order of the CompletedAt field.
* @param options
* @returns
*/
async subaccountWithdrawalsClosed(options?: {
status?: 'completed' | 'cancelled'
currencySymbol?: string
nextPageToken?: string
previousPageToken?: string
pageSize?: number
startDate?: string
endDate?: string
}): Promise<BTT.Withdrawal> {
return this.request('get', '/subaccounts/withdrawals/closed', { params: options })
}
/**
* List closed deposits for all subaccounts.
*
* StartDate and EndDate filters apply to the CompletedAt field.
*
* Pagination and the sort order of the results are in inverse order of the CompletedAt field.
* @param options
* @returns
*/
async subaccountsDepositsClosed(options?: {
status?: 'completed' | 'orphaned' | 'invalidated'
currencySymbol?: string
nextPageToken?: string
previousPageToken?: string
pageSize?: number
startDate?: string
endDate?: string
}) {
return this.request('get', '/subaccounts/deposits/closed', { params: options })
}
//#endregion
//#region V3 Transfers ENDPOINTS (4 endpoints)
/**
* List sent transfers.
* (NOTE: This API is limited to partners and not available for traders.)
* Pagination and the sort order of the results are in inverse order of the Executed field.
* @param options
* @returns
*/
async transfersSent(options?: {
toSubaccountId?: string
toMasterAccount?: boolean
currencySymbol?: string
nextPageToken?: string
previousPageToken?: string
pageSize?: number
startDate?: string
endDate?: string
}): Promise<BTT.SentTransferInfo[]> {
return this.request('get', '/transfers/sent', { params: options })
}
/**
* List received transfers.
* (NOTE: This API is limited to partners and not available for traders.)
* Pagination and the sort order of the results are in inverse order of the Executed field.
* @param options
* @returns
*/
async transfersReceived(options?: {
fromSubaccountId?: string
fromMasterAccount?: boolean
currencySymbol?: string
nextPageToken?: string
previousPageToken?: string
pageSize?: number
startDate?: string
endDate?: string
}): Promise<BTT.ReceivedTransferInfo[]> {
return this.request('get', '/transfers/received', { params: options })
}
/**
* Retrieve information on the specified transfer.
* (NOTE: This API is limited to partners and not available for traders.)
* @param transferId (uuid-formatted string) - ID of the transfer to retrieve
* @returns
*/
async transfer(transferId: string): Promise<BTT.ReceivedTransferInfo> {
return this.request('get', '/transfers/' + transferId)
}
/**
* Executes a new transfer.
* (NOTE: This API is limited to partners and not available for traders.)
* @param newTransfer information specifying the transfer to execute
* @returns
*/
async transferCreate(newTransfer: BTT.NewTransfer): Promise<BTT.NewTransfer> {
return this.request('post', '/transfers', { body: newTransfer })
}
//#endregion
//#region V3 Withdrawals ENDPOINTS (7 endpoints)
/**
* List open withdrawals. Results are sorted in inverse order of the CreatedAt field, and are limited to the first 1000.
* @param props
* @returns
*/
async withdrawalsOpen(props?: {
status?: 'REQUESTED' | 'AUTHORIZED' | 'PENDING' | 'ERROR_INVALID_ADDRESS'
currencySymbol?: string
}): Promise<BTT.Withdrawal[]> {
return this.request('get', '/withdrawals/open', { params: props })
}
/**
* List closed withdrawals.
*
* StartDate and EndDate filters apply to the CompletedAt field.
*
* Pagination and the sort order of the results are in inverse order of the CompletedAt field.
* @param props
* @returns
*/
async withdrawalsClosed(props?: {
status?: 'COMPLETED' | 'CANCELLED'
currencySymbol?: string
nextPageToken?: string
previousPageToken?: string
pageSize?: number
startDate?: string
endDate?: string
}): Promise<BTT.Withdrawal[]> {
return this.request('get', '/withdrawals/closed', { params: props })
}
/**
* Retrieves all withdrawals for this account with the given TxId
* @param txId the transaction id to lookup
* @returns
*/
async withdrawalByTxId(txId: string): Promise<BTT.Withdrawal[]> {
return this.request('get', '/withdrawals/ByTxId/' + txId)
}
/**
* Retrieve information on a specified withdrawal.
* @param withdrawalId (uuid-formatted string) - ID of withdrawal to retrieve
* @returns
*/
async withdrawal(withdrawalId: string): Promise<BTT.Withdrawal> {
return this.request('get', '/withdrawals/' + withdrawalId)
}
/**
* Cancel a withdrawal.
*
* (Withdrawals can only be cancelled if status is REQUESTED, AUTHORIZED, or ERROR_INVALID_ADDRESS.)
* @param withdrawalId
* @returns
*/
async withdrawalDelete(withdrawalId: string): Promise<BTT.Withdrawal> {
return this.request('delete', '/withdrawals/' + withdrawalId)
}
/**
* Create a new withdrawal.
*
* To initiate a fiat withdrawal specify a funds transfer method id instead of a crypto address.
* @param newWithdrawal information specifying the withdrawal to create
* @returns
*/
async withdrawalCreate(newWithdrawal: BTT.NewWithdrawal): Promise<BTT.Withdrawal> {
return this.request('post', '/withdrawals', { body: newWithdrawal })
}
/**
* Returns a list of allowed addresses.
* @returns
*/
async withdrawalsAllowedAddresses(): Promise<BTT.AllowedAddress> {
return this.request('get', '/withdrawals/allowed-addresses')
}
//#endregion
//#region private methods
/**
* Creates an axios request with signed headers
* @param method request method (GET, POST, HEAD...)
* @param url base url without query string
* @param options
* @returns
*/
private async request<R>(method: Method, url: string, { headers = {}, params = {}, body = '' }: any = {}): Promise<R> {
params = this.sanitizeParams(params)
if (this._apiKey) {
const nonce = Date.now()
const contentHash = crypto.createHash('sha512').update(body ? JSON.stringify(body) : '').digest('hex')
headers['Api-Key'] = this._apiKey
headers['Api-Timestamp'] = nonce
headers['Api-Content-Hash'] = contentHash
headers['Api-Signature'] = this.requestSignature(nonce, url, method, contentHash, params)
}
const { data } = await this._client.request({ method, url, headers, params, data: body }).catch(err => {
if (err.isAxiosError) {
return err.response
}
/* istanbul ignore next */
throw err
})
if (data.code) {
throw new Error(data.code)
}
return data
}
/**
* Create a pre-sign string, and sign via HmacSHA512, using your API secret as the signing secret. Hex-encode the result of this operation and populate the Api-Signature header with it.
* @param nonce
* @param path
* @param method
* @param contentHash
* @param params query string params
* @returns
*/
private requestSignature(nonce: number, path: string, method: Method, contentHash: string, params: any) {
const query = querystring.stringify(params)
const url = `${this._client.defaults.baseURL}${path}${query ? '?' + query : ''}`
const preSign = [nonce, url, method.toUpperCase(), contentHash, ''].join('')
const hmac = crypto.createHmac('sha512', this._apiSecret)
return hmac.update(preSign).digest('hex')
}
/**
* Clean up object removing undefined keys in order to avoid
* useless query params in the request.
* @param params
* @returns
*/