ccxt-look 1.81.50
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/.cache/eslintcache +1 -0
- package/.dockerignore +6 -0
- package/.eslintignore +1 -0
- package/.gitattributes +5 -0
- package/.readthedocs.yaml +16 -0
- package/CONTRIBUTING.md +1049 -0
- package/LICENSE.txt +21 -0
- package/README.md +537 -0
- package/SECURITY.md +5 -0
- package/build/cleanup-old-tags.js +94 -0
- package/build/countries.js +256 -0
- package/build/export-exchanges.js +520 -0
- package/build/fs.js +51 -0
- package/build/transpile.js +1772 -0
- package/build/vss.js +78 -0
- package/ccxt.browser.js +7 -0
- package/ccxt.d.ts +692 -0
- package/ccxt.js +171 -0
- package/cleanup.sh +2 -0
- package/composer-install.sh +20 -0
- package/dist/ccxt.browser.js +208383 -0
- package/gource.sh +3 -0
- package/index.html +7 -0
- package/js/.eslintrc +87 -0
- package/js/aax.js +2686 -0
- package/js/ascendex.js +2584 -0
- package/js/base/.eslintrc.js +43 -0
- package/js/base/Exchange.js +2371 -0
- package/js/base/Precise.js +283 -0
- package/js/base/errorHierarchy.js +47 -0
- package/js/base/errors.js +55 -0
- package/js/base/functions/crypto.js +158 -0
- package/js/base/functions/encode.js +118 -0
- package/js/base/functions/generic.js +270 -0
- package/js/base/functions/misc.js +138 -0
- package/js/base/functions/number.js +329 -0
- package/js/base/functions/platform.js +38 -0
- package/js/base/functions/string.js +21 -0
- package/js/base/functions/throttle.js +79 -0
- package/js/base/functions/time.js +210 -0
- package/js/base/functions/type.js +66 -0
- package/js/base/functions.js +28 -0
- package/js/bequant.js +32 -0
- package/js/bibox.js +1407 -0
- package/js/bigone.js +1366 -0
- package/js/binance.js +5652 -0
- package/js/binancecoinm.js +46 -0
- package/js/binanceus.js +46 -0
- package/js/binanceusdm.js +49 -0
- package/js/bit2c.js +535 -0
- package/js/bitbank.js +842 -0
- package/js/bitbay.js +16 -0
- package/js/bitbns.js +1073 -0
- package/js/bitcoincom.js +15 -0
- package/js/bitfinex.js +1433 -0
- package/js/bitfinex2.js +2025 -0
- package/js/bitflyer.js +840 -0
- package/js/bitforex.js +614 -0
- package/js/bitget.js +2397 -0
- package/js/bithumb.js +980 -0
- package/js/bitmart.js +2516 -0
- package/js/bitmex.js +1809 -0
- package/js/bitopro.js +1443 -0
- package/js/bitpanda.js +1782 -0
- package/js/bitrue.js +1747 -0
- package/js/bitso.js +1062 -0
- package/js/bitstamp.js +1757 -0
- package/js/bitstamp1.js +343 -0
- package/js/bittrex.js +1876 -0
- package/js/bitvavo.js +1579 -0
- package/js/bkex.js +1233 -0
- package/js/bl3p.js +346 -0
- package/js/blockchaincom.js +969 -0
- package/js/btcalpha.js +680 -0
- package/js/btcbox.js +477 -0
- package/js/btcmarkets.js +1022 -0
- package/js/btctradeua.js +466 -0
- package/js/btcturk.js +734 -0
- package/js/buda.js +946 -0
- package/js/bw.js +1265 -0
- package/js/bybit.js +3372 -0
- package/js/bytetrade.js +1336 -0
- package/js/cdax.js +1646 -0
- package/js/cex.js +1410 -0
- package/js/coinbase.js +1342 -0
- package/js/coinbaseprime.js +31 -0
- package/js/coinbasepro.js +1466 -0
- package/js/coincheck.js +755 -0
- package/js/coinex.js +3400 -0
- package/js/coinfalcon.js +880 -0
- package/js/coinmate.js +794 -0
- package/js/coinone.js +816 -0
- package/js/coinspot.js +345 -0
- package/js/crex24.js +1636 -0
- package/js/cryptocom.js +1832 -0
- package/js/currencycom.js +1748 -0
- package/js/delta.js +1547 -0
- package/js/deribit.js +2148 -0
- package/js/digifinex.js +1585 -0
- package/js/eqonex.js +1660 -0
- package/js/exmo.js +1670 -0
- package/js/fairdesk.js +1231 -0
- package/js/flowbtc.js +35 -0
- package/js/fmfwio.js +34 -0
- package/js/ftx.js +2751 -0
- package/js/ftxus.js +38 -0
- package/js/gateio.js +4174 -0
- package/js/gemini.js +1397 -0
- package/js/hitbtc.js +1343 -0
- package/js/hitbtc3.js +2329 -0
- package/js/hollaex.js +1486 -0
- package/js/huobi.js +5706 -0
- package/js/huobijp.js +1710 -0
- package/js/huobipro.js +18 -0
- package/js/idex.js +1439 -0
- package/js/independentreserve.js +649 -0
- package/js/indodax.js +742 -0
- package/js/itbit.js +722 -0
- package/js/kraken.js +2179 -0
- package/js/kucoin.js +2571 -0
- package/js/kucoinfutures.js +1771 -0
- package/js/kuna.js +809 -0
- package/js/latoken.js +1445 -0
- package/js/lbank.js +760 -0
- package/js/liquid.js +1432 -0
- package/js/luno.js +873 -0
- package/js/lykke.js +1147 -0
- package/js/mercado.js +771 -0
- package/js/mexc.js +3151 -0
- package/js/ndax.js +2233 -0
- package/js/novadax.js +1318 -0
- package/js/oceanex.js +816 -0
- package/js/okcoin.js +3841 -0
- package/js/okex.js +16 -0
- package/js/okex5.js +16 -0
- package/js/okx.js +4795 -0
- package/js/paymium.js +498 -0
- package/js/phemex.js +2957 -0
- package/js/poloniex.js +1674 -0
- package/js/probit.js +1346 -0
- package/js/qtrade.js +1588 -0
- package/js/ripio.js +1061 -0
- package/js/static_dependencies/BN/bn.js +3526 -0
- package/js/static_dependencies/README.md +1 -0
- package/js/static_dependencies/crypto-js/crypto-js.js +5988 -0
- package/js/static_dependencies/elliptic/lib/elliptic/curve/base.js +375 -0
- package/js/static_dependencies/elliptic/lib/elliptic/curve/edwards.js +433 -0
- package/js/static_dependencies/elliptic/lib/elliptic/curve/index.js +8 -0
- package/js/static_dependencies/elliptic/lib/elliptic/curve/mont.js +180 -0
- package/js/static_dependencies/elliptic/lib/elliptic/curve/short.js +938 -0
- package/js/static_dependencies/elliptic/lib/elliptic/curves.js +204 -0
- package/js/static_dependencies/elliptic/lib/elliptic/ec/index.js +240 -0
- package/js/static_dependencies/elliptic/lib/elliptic/ec/key.js +119 -0
- package/js/static_dependencies/elliptic/lib/elliptic/ec/signature.js +24 -0
- package/js/static_dependencies/elliptic/lib/elliptic/eddsa/index.js +145 -0
- package/js/static_dependencies/elliptic/lib/elliptic/eddsa/key.js +100 -0
- package/js/static_dependencies/elliptic/lib/elliptic/eddsa/signature.js +65 -0
- package/js/static_dependencies/elliptic/lib/elliptic/precomputed/secp256k1.js +780 -0
- package/js/static_dependencies/elliptic/lib/elliptic/utils.js +214 -0
- package/js/static_dependencies/elliptic/lib/elliptic.js +22 -0
- package/js/static_dependencies/elliptic/lib/hmac-drbg/hmac-drbg.js +114 -0
- package/js/static_dependencies/fetch-ponyfill/fetch-node.js +39 -0
- package/js/static_dependencies/node-fetch/index.js +1564 -0
- package/js/static_dependencies/node-rsa/NodeRSA.js +223 -0
- package/js/static_dependencies/node-rsa/asn1/ber/errors.js +13 -0
- package/js/static_dependencies/node-rsa/asn1/ber/index.js +21 -0
- package/js/static_dependencies/node-rsa/asn1/ber/reader.js +262 -0
- package/js/static_dependencies/node-rsa/asn1/ber/types.js +36 -0
- package/js/static_dependencies/node-rsa/asn1/index.js +17 -0
- package/js/static_dependencies/node-rsa/encryptEngines/js.js +34 -0
- package/js/static_dependencies/node-rsa/formats/components.js +71 -0
- package/js/static_dependencies/node-rsa/formats/formats.js +31 -0
- package/js/static_dependencies/node-rsa/formats/pkcs1.js +148 -0
- package/js/static_dependencies/node-rsa/formats/pkcs8.js +187 -0
- package/js/static_dependencies/node-rsa/libs/jsbn.js +1252 -0
- package/js/static_dependencies/node-rsa/libs/rsa.js +147 -0
- package/js/static_dependencies/node-rsa/schemes/pkcs1.js +176 -0
- package/js/static_dependencies/node-rsa/schemes/schemes.js +21 -0
- package/js/static_dependencies/node-rsa/utils.js +98 -0
- package/js/static_dependencies/qs/formats.js +18 -0
- package/js/static_dependencies/qs/index.js +11 -0
- package/js/static_dependencies/qs/parse.js +242 -0
- package/js/static_dependencies/qs/stringify.js +269 -0
- package/js/static_dependencies/qs/utils.js +230 -0
- package/js/stex.js +1925 -0
- package/js/test/.eslintrc.js +42 -0
- package/js/test/Exchange/test.balance.js +61 -0
- package/js/test/Exchange/test.borrowRate.js +32 -0
- package/js/test/Exchange/test.currency.js +52 -0
- package/js/test/Exchange/test.fetchBalance.js +23 -0
- package/js/test/Exchange/test.fetchBorrowInterest.js +59 -0
- package/js/test/Exchange/test.fetchBorrowRate.js +32 -0
- package/js/test/Exchange/test.fetchBorrowRates.js +28 -0
- package/js/test/Exchange/test.fetchClosedOrders.js +32 -0
- package/js/test/Exchange/test.fetchCurrencies.js +35 -0
- package/js/test/Exchange/test.fetchDeposits.js +31 -0
- package/js/test/Exchange/test.fetchFundingFees.js +19 -0
- package/js/test/Exchange/test.fetchFundingRateHistory.js +40 -0
- package/js/test/Exchange/test.fetchL2OrderBook.js +23 -0
- package/js/test/Exchange/test.fetchLedger.js +42 -0
- package/js/test/Exchange/test.fetchLeverageTiers.js +33 -0
- package/js/test/Exchange/test.fetchMarketLeverageTiers.js +22 -0
- package/js/test/Exchange/test.fetchMarkets.js +33 -0
- package/js/test/Exchange/test.fetchMyTrades.js +42 -0
- package/js/test/Exchange/test.fetchOHLCV.js +46 -0
- package/js/test/Exchange/test.fetchOpenOrders.js +36 -0
- package/js/test/Exchange/test.fetchOrderBook.js +25 -0
- package/js/test/Exchange/test.fetchOrderBooks.js +35 -0
- package/js/test/Exchange/test.fetchOrders.js +41 -0
- package/js/test/Exchange/test.fetchPositions.js +47 -0
- package/js/test/Exchange/test.fetchStatus.js +35 -0
- package/js/test/Exchange/test.fetchTicker.js +38 -0
- package/js/test/Exchange/test.fetchTickers.js +49 -0
- package/js/test/Exchange/test.fetchTrades.js +39 -0
- package/js/test/Exchange/test.fetchTradingFee.js +18 -0
- package/js/test/Exchange/test.fetchTradingFees.js +22 -0
- package/js/test/Exchange/test.fetchTransactions.js +31 -0
- package/js/test/Exchange/test.fetchWithdrawals.js +31 -0
- package/js/test/Exchange/test.ledgerItem.js +46 -0
- package/js/test/Exchange/test.leverageTier.js +33 -0
- package/js/test/Exchange/test.loadMarkets.js +35 -0
- package/js/test/Exchange/test.market.js +129 -0
- package/js/test/Exchange/test.ohlcv.js +33 -0
- package/js/test/Exchange/test.order.js +62 -0
- package/js/test/Exchange/test.orderbook.js +61 -0
- package/js/test/Exchange/test.position.js +21 -0
- package/js/test/Exchange/test.throttle.js +94 -0
- package/js/test/Exchange/test.ticker.js +95 -0
- package/js/test/Exchange/test.trade.js +68 -0
- package/js/test/Exchange/test.tradingFee.js +34 -0
- package/js/test/Exchange/test.transaction.js +35 -0
- package/js/test/base/.eslintrc +38 -0
- package/js/test/base/functions/test.crypto.js +110 -0
- package/js/test/base/functions/test.datetime.js +62 -0
- package/js/test/base/functions/test.generic.js +152 -0
- package/js/test/base/functions/test.number.js +362 -0
- package/js/test/base/functions/test.time.js +56 -0
- package/js/test/base/functions/test.type.js +53 -0
- package/js/test/base/test.base.js +193 -0
- package/js/test/errors/test.InsufficientFunds.js +86 -0
- package/js/test/errors/test.InvalidNonce.js +64 -0
- package/js/test/errors/test.InvalidOrder.js +35 -0
- package/js/test/errors/test.OrderNotFound.js +39 -0
- package/js/test/test.js +426 -0
- package/js/test/test.timeout_hang.js +12 -0
- package/js/therock.js +1431 -0
- package/js/tidebit.js +632 -0
- package/js/tidex.js +939 -0
- package/js/timex.js +1283 -0
- package/js/upbit.js +1622 -0
- package/js/vcc.js +1353 -0
- package/js/wavesexchange.js +2185 -0
- package/js/wazirx.js +732 -0
- package/js/whitebit.js +1352 -0
- package/js/woo.js +1577 -0
- package/js/xena.js +1948 -0
- package/js/yobit.js +1129 -0
- package/js/zaif.js +647 -0
- package/js/zb.js +4088 -0
- package/js/zipmex.js +40 -0
- package/js/zonda.js +1497 -0
- package/multilang.sh +159 -0
- package/package.json +591 -0
- package/postinstall.js +103 -0
package/js/bittrex.js
ADDED
@@ -0,0 +1,1876 @@
|
|
1
|
+
'use strict';
|
2
|
+
|
3
|
+
// ---------------------------------------------------------------------------
|
4
|
+
|
5
|
+
const Exchange = require ('./base/Exchange');
|
6
|
+
const { ArgumentsRequired, BadSymbol, ExchangeError, ExchangeNotAvailable, AuthenticationError, InvalidOrder, InsufficientFunds, OrderNotFound, DDoSProtection, PermissionDenied, AddressPending, OnMaintenance, BadRequest, InvalidAddress } = require ('./base/errors');
|
7
|
+
const { TRUNCATE, DECIMAL_PLACES } = require ('./base/functions/number');
|
8
|
+
|
9
|
+
// ---------------------------------------------------------------------------
|
10
|
+
|
11
|
+
module.exports = class bittrex extends Exchange {
|
12
|
+
describe () {
|
13
|
+
return this.deepExtend (super.describe (), {
|
14
|
+
'id': 'bittrex',
|
15
|
+
'name': 'Bittrex',
|
16
|
+
'countries': [ 'US' ],
|
17
|
+
'version': 'v3',
|
18
|
+
'rateLimit': 1500,
|
19
|
+
'certified': false,
|
20
|
+
'pro': true,
|
21
|
+
// new metainfo interface
|
22
|
+
'has': {
|
23
|
+
'CORS': undefined,
|
24
|
+
'spot': true,
|
25
|
+
'margin': false,
|
26
|
+
'swap': false,
|
27
|
+
'future': false,
|
28
|
+
'option': false,
|
29
|
+
'addMargin': false,
|
30
|
+
'cancelAllOrders': true,
|
31
|
+
'cancelOrder': true,
|
32
|
+
'createDepositAddress': true,
|
33
|
+
'createMarketOrder': true,
|
34
|
+
'createOrder': true,
|
35
|
+
'createReduceOnlyOrder': false,
|
36
|
+
'createStopLimitOrder': true,
|
37
|
+
'createStopMarketOrder': true,
|
38
|
+
'createStopOrder': true,
|
39
|
+
'fetchBalance': true,
|
40
|
+
'fetchBorrowRate': false,
|
41
|
+
'fetchBorrowRateHistories': false,
|
42
|
+
'fetchBorrowRateHistory': false,
|
43
|
+
'fetchBorrowRates': false,
|
44
|
+
'fetchBorrowRatesPerSymbol': false,
|
45
|
+
'fetchClosedOrders': true,
|
46
|
+
'fetchCurrencies': true,
|
47
|
+
'fetchDepositAddress': true,
|
48
|
+
'fetchDeposits': true,
|
49
|
+
'fetchFundingFees': undefined,
|
50
|
+
'fetchFundingHistory': false,
|
51
|
+
'fetchFundingRate': false,
|
52
|
+
'fetchFundingRateHistory': false,
|
53
|
+
'fetchFundingRates': false,
|
54
|
+
'fetchIndexOHLCV': false,
|
55
|
+
'fetchLeverage': false,
|
56
|
+
'fetchLeverageTiers': false,
|
57
|
+
'fetchMarkets': true,
|
58
|
+
'fetchMarkOHLCV': false,
|
59
|
+
'fetchMyTrades': 'emulated',
|
60
|
+
'fetchOHLCV': true,
|
61
|
+
'fetchOpenOrders': true,
|
62
|
+
'fetchOrder': true,
|
63
|
+
'fetchOrderBook': true,
|
64
|
+
'fetchOrderTrades': true,
|
65
|
+
'fetchPosition': false,
|
66
|
+
'fetchPositions': false,
|
67
|
+
'fetchPositionsRisk': false,
|
68
|
+
'fetchPremiumIndexOHLCV': false,
|
69
|
+
'fetchTicker': true,
|
70
|
+
'fetchTickers': true,
|
71
|
+
'fetchTime': true,
|
72
|
+
'fetchTrades': true,
|
73
|
+
'fetchTradingFee': true,
|
74
|
+
'fetchTradingFees': true,
|
75
|
+
'fetchTransactions': undefined,
|
76
|
+
'fetchWithdrawals': true,
|
77
|
+
'reduceMargin': false,
|
78
|
+
'setLeverage': false,
|
79
|
+
'setMarginMode': false,
|
80
|
+
'setPositionMode': false,
|
81
|
+
'withdraw': true,
|
82
|
+
},
|
83
|
+
'timeframes': {
|
84
|
+
'1m': 'MINUTE_1',
|
85
|
+
'5m': 'MINUTE_5',
|
86
|
+
'1h': 'HOUR_1',
|
87
|
+
'1d': 'DAY_1',
|
88
|
+
},
|
89
|
+
'hostname': 'bittrex.com',
|
90
|
+
'urls': {
|
91
|
+
'logo': 'https://user-images.githubusercontent.com/51840849/87153921-edf53180-c2c0-11ea-96b9-f2a9a95a455b.jpg',
|
92
|
+
'api': {
|
93
|
+
'public': 'https://api.bittrex.com',
|
94
|
+
'private': 'https://api.bittrex.com',
|
95
|
+
},
|
96
|
+
'www': 'https://bittrex.com',
|
97
|
+
'doc': [
|
98
|
+
'https://bittrex.github.io/api/v3',
|
99
|
+
],
|
100
|
+
'fees': [
|
101
|
+
'https://bittrex.zendesk.com/hc/en-us/articles/115003684371-BITTREX-SERVICE-FEES-AND-WITHDRAWAL-LIMITATIONS',
|
102
|
+
'https://bittrex.zendesk.com/hc/en-us/articles/115000199651-What-fees-does-Bittrex-charge-',
|
103
|
+
],
|
104
|
+
'referral': 'https://bittrex.com/Account/Register?referralCode=1ZE-G0G-M3B',
|
105
|
+
},
|
106
|
+
'api': {
|
107
|
+
'public': {
|
108
|
+
'get': [
|
109
|
+
'ping',
|
110
|
+
'currencies',
|
111
|
+
'currencies/{symbol}',
|
112
|
+
'markets',
|
113
|
+
'markets/tickers',
|
114
|
+
'markets/summaries',
|
115
|
+
'markets/{marketSymbol}',
|
116
|
+
'markets/{marketSymbol}/summary',
|
117
|
+
'markets/{marketSymbol}/orderbook',
|
118
|
+
'markets/{marketSymbol}/trades',
|
119
|
+
'markets/{marketSymbol}/ticker',
|
120
|
+
'markets/{marketSymbol}/candles/{candleInterval}/recent',
|
121
|
+
'markets/{marketSymbol}/candles/{candleInterval}/historical/{year}/{month}/{day}',
|
122
|
+
'markets/{marketSymbol}/candles/{candleInterval}/historical/{year}/{month}',
|
123
|
+
'markets/{marketSymbol}/candles/{candleInterval}/historical/{year}',
|
124
|
+
],
|
125
|
+
},
|
126
|
+
'private': {
|
127
|
+
'get': [
|
128
|
+
'account',
|
129
|
+
'account/fees/fiat',
|
130
|
+
'account/fees/fiat/{currencySymbol}',
|
131
|
+
'account/fees/trading',
|
132
|
+
'account/fees/trading/{marketSymbol}',
|
133
|
+
'account/volume',
|
134
|
+
'addresses',
|
135
|
+
'addresses/{currencySymbol}',
|
136
|
+
'balances',
|
137
|
+
'balances/{currencySymbol}',
|
138
|
+
'deposits/open',
|
139
|
+
'deposits/closed',
|
140
|
+
'deposits/ByTxId/{txId}',
|
141
|
+
'deposits/{depositId}',
|
142
|
+
'orders/closed',
|
143
|
+
'orders/open',
|
144
|
+
'orders/{orderId}',
|
145
|
+
'orders/{orderId}/executions',
|
146
|
+
'ping',
|
147
|
+
'subaccounts/{subaccountId}',
|
148
|
+
'subaccounts',
|
149
|
+
'withdrawals/open',
|
150
|
+
'withdrawals/closed',
|
151
|
+
'withdrawals/ByTxId/{txId}',
|
152
|
+
'withdrawals/{withdrawalId}',
|
153
|
+
'withdrawals/whitelistAddresses',
|
154
|
+
'conditional-orders/{conditionalOrderId}',
|
155
|
+
'conditional-orders/closed',
|
156
|
+
'conditional-orders/open',
|
157
|
+
'transfers/sent',
|
158
|
+
'transfers/received',
|
159
|
+
'transfers/{transferId}',
|
160
|
+
],
|
161
|
+
'post': [
|
162
|
+
'addresses',
|
163
|
+
'orders',
|
164
|
+
'subaccounts',
|
165
|
+
'withdrawals',
|
166
|
+
'conditional-orders',
|
167
|
+
'transfers',
|
168
|
+
],
|
169
|
+
'delete': [
|
170
|
+
'orders/open',
|
171
|
+
'orders/{orderId}',
|
172
|
+
'withdrawals/{withdrawalId}',
|
173
|
+
'conditional-orders/{conditionalOrderId}',
|
174
|
+
],
|
175
|
+
},
|
176
|
+
},
|
177
|
+
'fees': {
|
178
|
+
'trading': {
|
179
|
+
'tierBased': true,
|
180
|
+
'percentage': true,
|
181
|
+
'maker': this.parseNumber ('0.0075'),
|
182
|
+
'taker': this.parseNumber ('0.0075'),
|
183
|
+
},
|
184
|
+
'funding': {
|
185
|
+
'tierBased': false,
|
186
|
+
'percentage': false,
|
187
|
+
},
|
188
|
+
},
|
189
|
+
'exceptions': {
|
190
|
+
'exact': {
|
191
|
+
'BAD_REQUEST': BadRequest, // {"code":"BAD_REQUEST","detail":"Refer to the data field for specific field validation failures.","data":{"invalidRequestParameter":"day"}}
|
192
|
+
'STARTDATE_OUT_OF_RANGE': BadRequest, // {"code":"STARTDATE_OUT_OF_RANGE"}
|
193
|
+
// 'Call to Cancel was throttled. Try again in 60 seconds.': DDoSProtection,
|
194
|
+
// 'Call to GetBalances was throttled. Try again in 60 seconds.': DDoSProtection,
|
195
|
+
'APISIGN_NOT_PROVIDED': AuthenticationError,
|
196
|
+
'APIKEY_INVALID': AuthenticationError,
|
197
|
+
'INVALID_SIGNATURE': AuthenticationError,
|
198
|
+
'INVALID_CURRENCY': ExchangeError,
|
199
|
+
'INVALID_PERMISSION': AuthenticationError,
|
200
|
+
'INSUFFICIENT_FUNDS': InsufficientFunds,
|
201
|
+
'INVALID_CEILING_MARKET_BUY': InvalidOrder,
|
202
|
+
'INVALID_FIAT_ACCOUNT': InvalidOrder,
|
203
|
+
'INVALID_ORDER_TYPE': InvalidOrder,
|
204
|
+
'QUANTITY_NOT_PROVIDED': InvalidOrder,
|
205
|
+
'MIN_TRADE_REQUIREMENT_NOT_MET': InvalidOrder,
|
206
|
+
'NOT_FOUND': OrderNotFound,
|
207
|
+
'ORDER_NOT_OPEN': OrderNotFound,
|
208
|
+
'INVALID_ORDER': InvalidOrder,
|
209
|
+
'UUID_INVALID': OrderNotFound,
|
210
|
+
'RATE_NOT_PROVIDED': InvalidOrder, // createLimitBuyOrder ('ETH/BTC', 1, 0)
|
211
|
+
'INVALID_MARKET': BadSymbol, // {"success":false,"message":"INVALID_MARKET","result":null,"explanation":null}
|
212
|
+
'WHITELIST_VIOLATION_IP': PermissionDenied,
|
213
|
+
'DUST_TRADE_DISALLOWED_MIN_VALUE': InvalidOrder,
|
214
|
+
'RESTRICTED_MARKET': BadSymbol,
|
215
|
+
'We are down for scheduled maintenance, but we\u2019ll be back up shortly.': OnMaintenance, // {"success":false,"message":"We are down for scheduled maintenance, but we\u2019ll be back up shortly.","result":null,"explanation":null}
|
216
|
+
},
|
217
|
+
'broad': {
|
218
|
+
'throttled': DDoSProtection,
|
219
|
+
'problem': ExchangeNotAvailable,
|
220
|
+
},
|
221
|
+
},
|
222
|
+
'options': {
|
223
|
+
'fetchTicker': {
|
224
|
+
'method': 'publicGetMarketsMarketSymbolTicker', // publicGetMarketsMarketSymbolSummary
|
225
|
+
},
|
226
|
+
'fetchTickers': {
|
227
|
+
'method': 'publicGetMarketsTickers', // publicGetMarketsSummaries
|
228
|
+
},
|
229
|
+
'parseOrderStatus': false,
|
230
|
+
'hasAlreadyAuthenticatedSuccessfully': false, // a workaround for APIKEY_INVALID
|
231
|
+
// With certain currencies, like
|
232
|
+
// AEON, BTS, GXS, NXT, SBD, STEEM, STR, XEM, XLM, XMR, XRP
|
233
|
+
// an additional tag / memo / payment id is usually required by exchanges.
|
234
|
+
// With Bittrex some currencies imply the "base address + tag" logic.
|
235
|
+
// The base address for depositing is stored on this.currencies[code]
|
236
|
+
// The base address identifies the exchange as the recipient
|
237
|
+
// while the tag identifies the user account within the exchange
|
238
|
+
// and the tag is retrieved with fetchDepositAddress.
|
239
|
+
'tag': {
|
240
|
+
'NXT': true, // NXT, BURST
|
241
|
+
'CRYPTO_NOTE_PAYMENTID': true, // AEON, XMR
|
242
|
+
'BITSHAREX': true, // BTS
|
243
|
+
'RIPPLE': true, // XRP
|
244
|
+
'NEM': true, // XEM
|
245
|
+
'STELLAR': true, // XLM
|
246
|
+
'STEEM': true, // SBD, GOLOS
|
247
|
+
// https://github.com/ccxt/ccxt/issues/4794
|
248
|
+
// 'LISK': true, // LSK
|
249
|
+
},
|
250
|
+
'subaccountId': undefined,
|
251
|
+
// see the implementation of fetchClosedOrdersV3 below
|
252
|
+
// 'fetchClosedOrdersMethod': 'fetch_closed_orders_v3',
|
253
|
+
'fetchClosedOrdersFilterBySince': true,
|
254
|
+
// 'createOrderMethod': 'create_order_v1',
|
255
|
+
},
|
256
|
+
'commonCurrencies': {
|
257
|
+
'BIFI': 'Bifrost Finance',
|
258
|
+
'BTR': 'BTRIPS',
|
259
|
+
'GMT': 'GMT Token',
|
260
|
+
'MEME': 'Memetic', // conflict with Meme Inu
|
261
|
+
'MER': 'Mercury', // conflict with Mercurial Finance
|
262
|
+
'PROS': 'Pros.Finance',
|
263
|
+
'REPV2': 'REP',
|
264
|
+
'TON': 'Tokamak Network',
|
265
|
+
},
|
266
|
+
});
|
267
|
+
}
|
268
|
+
|
269
|
+
costToPrecision (symbol, cost) {
|
270
|
+
return this.decimalToPrecision (cost, TRUNCATE, this.markets[symbol]['precision']['price'], DECIMAL_PLACES);
|
271
|
+
}
|
272
|
+
|
273
|
+
feeToPrecision (symbol, fee) {
|
274
|
+
return this.decimalToPrecision (fee, TRUNCATE, this.markets[symbol]['precision']['price'], DECIMAL_PLACES);
|
275
|
+
}
|
276
|
+
|
277
|
+
async fetchMarkets (params = {}) {
|
278
|
+
const response = await this.publicGetMarkets (params);
|
279
|
+
//
|
280
|
+
// [
|
281
|
+
// {
|
282
|
+
// "symbol":"LTC-BTC",
|
283
|
+
// "baseCurrencySymbol":"LTC",
|
284
|
+
// "quoteCurrencySymbol":"BTC",
|
285
|
+
// "minTradeSize":"0.01686767",
|
286
|
+
// "precision":8,
|
287
|
+
// "status":"ONLINE", // "OFFLINE"
|
288
|
+
// "createdAt":"2014-02-13T00:00:00Z"
|
289
|
+
// },
|
290
|
+
// {
|
291
|
+
// "symbol":"VDX-USDT",
|
292
|
+
// "baseCurrencySymbol":"VDX",
|
293
|
+
// "quoteCurrencySymbol":"USDT",
|
294
|
+
// "minTradeSize":"300.00000000",
|
295
|
+
// "precision":8,
|
296
|
+
// "status":"ONLINE", // "OFFLINE"
|
297
|
+
// "createdAt":"2019-05-23T00:41:21.843Z",
|
298
|
+
// "notice":"USDT has swapped to an ERC20-based token as of August 5, 2019."
|
299
|
+
// }
|
300
|
+
// ]
|
301
|
+
//
|
302
|
+
const result = [];
|
303
|
+
for (let i = 0; i < response.length; i++) {
|
304
|
+
const market = response[i];
|
305
|
+
const baseId = this.safeString (market, 'baseCurrencySymbol');
|
306
|
+
const quoteId = this.safeString (market, 'quoteCurrencySymbol');
|
307
|
+
const base = this.safeCurrencyCode (baseId);
|
308
|
+
const quote = this.safeCurrencyCode (quoteId);
|
309
|
+
const status = this.safeString (market, 'status');
|
310
|
+
result.push ({
|
311
|
+
'id': this.safeString (market, 'symbol'),
|
312
|
+
'symbol': base + '/' + quote,
|
313
|
+
'base': base,
|
314
|
+
'quote': quote,
|
315
|
+
'settle': undefined,
|
316
|
+
'baseId': baseId,
|
317
|
+
'quoteId': quoteId,
|
318
|
+
'settleId': undefined,
|
319
|
+
'type': 'spot',
|
320
|
+
'spot': true,
|
321
|
+
'margin': false,
|
322
|
+
'swap': false,
|
323
|
+
'future': false,
|
324
|
+
'option': false,
|
325
|
+
'active': (status === 'ONLINE'),
|
326
|
+
'contract': false,
|
327
|
+
'linear': undefined,
|
328
|
+
'inverse': undefined,
|
329
|
+
'contractSize': undefined,
|
330
|
+
'expiry': undefined,
|
331
|
+
'expiryDatetime': undefined,
|
332
|
+
'strike': undefined,
|
333
|
+
'optionType': undefined,
|
334
|
+
'precision': {
|
335
|
+
'amount': parseInt ('8'),
|
336
|
+
'price': this.safeInteger (market, 'precision', 8),
|
337
|
+
},
|
338
|
+
'limits': {
|
339
|
+
'leverage': {
|
340
|
+
'min': undefined,
|
341
|
+
'max': undefined,
|
342
|
+
},
|
343
|
+
'amount': {
|
344
|
+
'min': this.safeNumber (market, 'minTradeSize'),
|
345
|
+
'max': undefined,
|
346
|
+
},
|
347
|
+
'price': {
|
348
|
+
'min': undefined,
|
349
|
+
'max': undefined,
|
350
|
+
},
|
351
|
+
'cost': {
|
352
|
+
'min': undefined,
|
353
|
+
'max': undefined,
|
354
|
+
},
|
355
|
+
},
|
356
|
+
'info': market,
|
357
|
+
});
|
358
|
+
}
|
359
|
+
return result;
|
360
|
+
}
|
361
|
+
|
362
|
+
parseBalance (response) {
|
363
|
+
const result = { 'info': response };
|
364
|
+
const indexed = this.indexBy (response, 'currencySymbol');
|
365
|
+
const currencyIds = Object.keys (indexed);
|
366
|
+
for (let i = 0; i < currencyIds.length; i++) {
|
367
|
+
const currencyId = currencyIds[i];
|
368
|
+
const code = this.safeCurrencyCode (currencyId);
|
369
|
+
const account = this.account ();
|
370
|
+
const balance = indexed[currencyId];
|
371
|
+
account['free'] = this.safeString (balance, 'available');
|
372
|
+
account['total'] = this.safeString (balance, 'total');
|
373
|
+
result[code] = account;
|
374
|
+
}
|
375
|
+
return this.safeBalance (result);
|
376
|
+
}
|
377
|
+
|
378
|
+
async fetchBalance (params = {}) {
|
379
|
+
await this.loadMarkets ();
|
380
|
+
const response = await this.privateGetBalances (params);
|
381
|
+
return this.parseBalance (response);
|
382
|
+
}
|
383
|
+
|
384
|
+
async fetchOrderBook (symbol, limit = undefined, params = {}) {
|
385
|
+
await this.loadMarkets ();
|
386
|
+
const request = {
|
387
|
+
'marketSymbol': this.marketId (symbol),
|
388
|
+
};
|
389
|
+
if (limit !== undefined) {
|
390
|
+
if ((limit !== 1) && (limit !== 25) && (limit !== 500)) {
|
391
|
+
throw new BadRequest (this.id + ' fetchOrderBook() limit argument must be undefined, 1, 25 or 500, default is 25');
|
392
|
+
}
|
393
|
+
request['depth'] = limit;
|
394
|
+
}
|
395
|
+
const response = await this.publicGetMarketsMarketSymbolOrderbook (this.extend (request, params));
|
396
|
+
//
|
397
|
+
// {
|
398
|
+
// "bid":[
|
399
|
+
// {"quantity":"0.01250000","rate":"10718.56200003"},
|
400
|
+
// {"quantity":"0.10000000","rate":"10718.56200002"},
|
401
|
+
// {"quantity":"0.39648292","rate":"10718.56200001"},
|
402
|
+
// ],
|
403
|
+
// "ask":[
|
404
|
+
// {"quantity":"0.05100000","rate":"10724.30099631"},
|
405
|
+
// {"quantity":"0.10000000","rate":"10724.30099632"},
|
406
|
+
// {"quantity":"0.26000000","rate":"10724.30099634"},
|
407
|
+
// ]
|
408
|
+
// }
|
409
|
+
//
|
410
|
+
const sequence = this.safeInteger (this.last_response_headers, 'Sequence');
|
411
|
+
const orderbook = this.parseOrderBook (response, symbol, undefined, 'bid', 'ask', 'rate', 'quantity');
|
412
|
+
orderbook['nonce'] = sequence;
|
413
|
+
return orderbook;
|
414
|
+
}
|
415
|
+
|
416
|
+
async fetchCurrencies (params = {}) {
|
417
|
+
const response = await this.publicGetCurrencies (params);
|
418
|
+
//
|
419
|
+
// [
|
420
|
+
// {
|
421
|
+
// "symbol":"1ST",
|
422
|
+
// "name":"Firstblood",
|
423
|
+
// "coinType":"ETH_CONTRACT",
|
424
|
+
// "status":"ONLINE",
|
425
|
+
// "minConfirmations":36,
|
426
|
+
// "notice":"",
|
427
|
+
// "txFee":"4.50000000",
|
428
|
+
// "logoUrl":"https://bittrexblobstorage.blob.core.windows.net/public/5685a7be-1edf-4ba0-a313-b5309bb204f8.png",
|
429
|
+
// "prohibitedIn":[],
|
430
|
+
// "baseAddress":"0xfbb1b73c4f0bda4f67dca266ce6ef42f520fbb98",
|
431
|
+
// "associatedTermsOfService":[]
|
432
|
+
// }
|
433
|
+
// ]
|
434
|
+
//
|
435
|
+
const result = {};
|
436
|
+
for (let i = 0; i < response.length; i++) {
|
437
|
+
const currency = response[i];
|
438
|
+
const id = this.safeString (currency, 'symbol');
|
439
|
+
const code = this.safeCurrencyCode (id);
|
440
|
+
const precision = 8; // default precision, todo: fix "magic constants"
|
441
|
+
const fee = this.safeNumber (currency, 'txFee'); // todo: redesign
|
442
|
+
const isActive = this.safeString (currency, 'status');
|
443
|
+
result[code] = {
|
444
|
+
'id': id,
|
445
|
+
'code': code,
|
446
|
+
'address': this.safeString (currency, 'baseAddress'),
|
447
|
+
'info': currency,
|
448
|
+
'type': this.safeString (currency, 'coinType'),
|
449
|
+
'name': this.safeString (currency, 'name'),
|
450
|
+
'active': (isActive === 'ONLINE'),
|
451
|
+
'deposit': undefined,
|
452
|
+
'withdraw': undefined,
|
453
|
+
'fee': fee,
|
454
|
+
'precision': precision,
|
455
|
+
'limits': {
|
456
|
+
'amount': {
|
457
|
+
'min': 1 / Math.pow (10, precision),
|
458
|
+
'max': undefined,
|
459
|
+
},
|
460
|
+
'withdraw': {
|
461
|
+
'min': fee,
|
462
|
+
'max': undefined,
|
463
|
+
},
|
464
|
+
},
|
465
|
+
};
|
466
|
+
}
|
467
|
+
return result;
|
468
|
+
}
|
469
|
+
|
470
|
+
parseTicker (ticker, market = undefined) {
|
471
|
+
//
|
472
|
+
// ticker
|
473
|
+
//
|
474
|
+
// {
|
475
|
+
// "symbol":"ETH-BTC",
|
476
|
+
// "lastTradeRate":"0.03284496",
|
477
|
+
// "bidRate":"0.03284523",
|
478
|
+
// "askRate":"0.03286857"
|
479
|
+
// }
|
480
|
+
//
|
481
|
+
// summary
|
482
|
+
//
|
483
|
+
// {
|
484
|
+
// "symbol":"ETH-BTC",
|
485
|
+
// "high":"0.03369528",
|
486
|
+
// "low":"0.03282442",
|
487
|
+
// "volume":"4307.83794556",
|
488
|
+
// "quoteVolume":"143.08608869",
|
489
|
+
// "percentChange":"0.79",
|
490
|
+
// "updatedAt":"2020-09-29T07:36:57.823Z"
|
491
|
+
// }
|
492
|
+
//
|
493
|
+
const timestamp = this.parse8601 (this.safeString (ticker, 'updatedAt'));
|
494
|
+
const marketId = this.safeString (ticker, 'symbol');
|
495
|
+
market = this.safeMarket (marketId, market, '-');
|
496
|
+
const symbol = market['symbol'];
|
497
|
+
const percentage = this.safeString (ticker, 'percentChange');
|
498
|
+
const last = this.safeString (ticker, 'lastTradeRate');
|
499
|
+
return this.safeTicker ({
|
500
|
+
'symbol': symbol,
|
501
|
+
'timestamp': timestamp,
|
502
|
+
'datetime': this.iso8601 (timestamp),
|
503
|
+
'high': this.safeString (ticker, 'high'),
|
504
|
+
'low': this.safeString (ticker, 'low'),
|
505
|
+
'bid': this.safeString (ticker, 'bidRate'),
|
506
|
+
'bidVolume': undefined,
|
507
|
+
'ask': this.safeString (ticker, 'askRate'),
|
508
|
+
'askVolume': undefined,
|
509
|
+
'vwap': undefined,
|
510
|
+
'open': undefined,
|
511
|
+
'close': last,
|
512
|
+
'last': last,
|
513
|
+
'previousClose': undefined,
|
514
|
+
'change': undefined,
|
515
|
+
'percentage': percentage,
|
516
|
+
'average': undefined,
|
517
|
+
'baseVolume': this.safeString (ticker, 'volume'),
|
518
|
+
'quoteVolume': this.safeString (ticker, 'quoteVolume'),
|
519
|
+
'info': ticker,
|
520
|
+
}, market, false);
|
521
|
+
}
|
522
|
+
|
523
|
+
async fetchTickers (symbols = undefined, params = {}) {
|
524
|
+
await this.loadMarkets ();
|
525
|
+
const options = this.safeValue (this.options, 'fetchTickers', {});
|
526
|
+
const defaultMethod = this.safeString (options, 'method', 'publicGetMarketsTickers');
|
527
|
+
const method = this.safeString (params, 'method', defaultMethod);
|
528
|
+
params = this.omit (params, 'method');
|
529
|
+
const response = await this[method] (params);
|
530
|
+
//
|
531
|
+
// publicGetMarketsTickers
|
532
|
+
//
|
533
|
+
// [
|
534
|
+
// {
|
535
|
+
// "symbol":"4ART-BTC",
|
536
|
+
// "lastTradeRate":"0.00000210",
|
537
|
+
// "bidRate":"0.00000210",
|
538
|
+
// "askRate":"0.00000215"
|
539
|
+
// }
|
540
|
+
// ]
|
541
|
+
//
|
542
|
+
// publicGetMarketsSummaries
|
543
|
+
//
|
544
|
+
// [
|
545
|
+
// {
|
546
|
+
// "symbol":"4ART-BTC",
|
547
|
+
// "high":"0.00000206",
|
548
|
+
// "low":"0.00000196",
|
549
|
+
// "volume":"14871.32000233",
|
550
|
+
// "quoteVolume":"0.02932756",
|
551
|
+
// "percentChange":"1.48",
|
552
|
+
// "updatedAt":"2020-09-29T07:34:32.757Z"
|
553
|
+
// }
|
554
|
+
// ]
|
555
|
+
//
|
556
|
+
const tickers = [];
|
557
|
+
for (let i = 0; i < response.length; i++) {
|
558
|
+
const ticker = this.parseTicker (response[i]);
|
559
|
+
tickers.push (ticker);
|
560
|
+
}
|
561
|
+
return this.filterByArray (tickers, 'symbol', symbols);
|
562
|
+
}
|
563
|
+
|
564
|
+
async fetchTicker (symbol, params = {}) {
|
565
|
+
await this.loadMarkets ();
|
566
|
+
const market = this.market (symbol);
|
567
|
+
const request = {
|
568
|
+
'marketSymbol': market['id'],
|
569
|
+
};
|
570
|
+
const options = this.safeValue (this.options, 'fetchTicker', {});
|
571
|
+
const defaultMethod = this.safeString (options, 'method', 'publicGetMarketsMarketSymbolTicker');
|
572
|
+
const method = this.safeString (params, 'method', defaultMethod);
|
573
|
+
params = this.omit (params, 'method');
|
574
|
+
const response = await this[method] (this.extend (request, params));
|
575
|
+
//
|
576
|
+
// publicGetMarketsMarketSymbolTicker
|
577
|
+
//
|
578
|
+
// {
|
579
|
+
// "symbol":"ETH-BTC",
|
580
|
+
// "lastTradeRate":"0.03284496",
|
581
|
+
// "bidRate":"0.03284523",
|
582
|
+
// "askRate":"0.03286857"
|
583
|
+
// }
|
584
|
+
//
|
585
|
+
//
|
586
|
+
// publicGetMarketsMarketSymbolSummary
|
587
|
+
//
|
588
|
+
// {
|
589
|
+
// "symbol":"ETH-BTC",
|
590
|
+
// "high":"0.03369528",
|
591
|
+
// "low":"0.03282442",
|
592
|
+
// "volume":"4307.83794556",
|
593
|
+
// "quoteVolume":"143.08608869",
|
594
|
+
// "percentChange":"0.79",
|
595
|
+
// "updatedAt":"2020-09-29T07:36:57.823Z"
|
596
|
+
// }
|
597
|
+
//
|
598
|
+
return this.parseTicker (response, market);
|
599
|
+
}
|
600
|
+
|
601
|
+
parseTrade (trade, market = undefined) {
|
602
|
+
//
|
603
|
+
// public fetchTrades
|
604
|
+
//
|
605
|
+
// {
|
606
|
+
// "id": "8a614d4e-e455-45b0-9aac-502b0aeb433f",
|
607
|
+
// "executedAt": "2021-11-25T14:54:44.65Z",
|
608
|
+
// "quantity": "30.00000000",
|
609
|
+
// "rate": "1.72923112",
|
610
|
+
// "takerSide": "SELL"
|
611
|
+
// }
|
612
|
+
//
|
613
|
+
// private fetchOrderTrades
|
614
|
+
// {
|
615
|
+
// "id": "8a614d4e-e455-45b0-9aac-502b0aeb433f",
|
616
|
+
// "marketSymbol": "ADA-USDT",
|
617
|
+
// "executedAt": "2021-11-25T14:54:44.65Z",
|
618
|
+
// "quantity": "30.00000000",
|
619
|
+
// "rate": "1.72923112",
|
620
|
+
// "orderId": "6f7abf18-6901-4659-a48c-db0e88440ea4",
|
621
|
+
// "commission": "0.38907700",
|
622
|
+
// "isTaker": true
|
623
|
+
// }
|
624
|
+
//
|
625
|
+
const timestamp = this.parse8601 (this.safeString (trade, 'executedAt'));
|
626
|
+
const id = this.safeString (trade, 'id');
|
627
|
+
const order = this.safeString (trade, 'orderId');
|
628
|
+
const marketId = this.safeString (trade, 'marketSymbol');
|
629
|
+
market = this.safeMarket (marketId, market, '-');
|
630
|
+
const priceString = this.safeString (trade, 'rate');
|
631
|
+
const amountString = this.safeString (trade, 'quantity');
|
632
|
+
let takerOrMaker = undefined;
|
633
|
+
const isTaker = this.safeValue (trade, 'isTaker');
|
634
|
+
if (isTaker !== undefined) {
|
635
|
+
takerOrMaker = isTaker ? 'taker' : 'maker';
|
636
|
+
}
|
637
|
+
let fee = undefined;
|
638
|
+
const feeCostString = this.safeString (trade, 'commission');
|
639
|
+
if (feeCostString !== undefined) {
|
640
|
+
fee = {
|
641
|
+
'cost': feeCostString,
|
642
|
+
'currency': market['quote'],
|
643
|
+
};
|
644
|
+
}
|
645
|
+
const side = this.safeStringLower (trade, 'takerSide');
|
646
|
+
return this.safeTrade ({
|
647
|
+
'info': trade,
|
648
|
+
'timestamp': timestamp,
|
649
|
+
'datetime': this.iso8601 (timestamp),
|
650
|
+
'symbol': market['symbol'],
|
651
|
+
'id': id,
|
652
|
+
'order': order,
|
653
|
+
'takerOrMaker': takerOrMaker,
|
654
|
+
'type': undefined,
|
655
|
+
'side': side,
|
656
|
+
'price': priceString,
|
657
|
+
'amount': amountString,
|
658
|
+
'cost': undefined,
|
659
|
+
'fee': fee,
|
660
|
+
}, market);
|
661
|
+
}
|
662
|
+
|
663
|
+
async fetchTime (params = {}) {
|
664
|
+
const response = await this.publicGetPing (params);
|
665
|
+
//
|
666
|
+
// {
|
667
|
+
// "serverTime": 1594596023162
|
668
|
+
// }
|
669
|
+
//
|
670
|
+
return this.safeInteger (response, 'serverTime');
|
671
|
+
}
|
672
|
+
|
673
|
+
async fetchTrades (symbol, since = undefined, limit = undefined, params = {}) {
|
674
|
+
await this.loadMarkets ();
|
675
|
+
const market = this.market (symbol);
|
676
|
+
const request = {
|
677
|
+
'marketSymbol': this.marketId (symbol),
|
678
|
+
};
|
679
|
+
const response = await this.publicGetMarketsMarketSymbolTrades (this.extend (request, params));
|
680
|
+
//
|
681
|
+
// [
|
682
|
+
// {
|
683
|
+
// "id":"9c5589db-42fb-436c-b105-5e2edcb95673",
|
684
|
+
// "executedAt":"2020-10-03T11:48:43.38Z",
|
685
|
+
// "quantity":"0.17939626",
|
686
|
+
// "rate":"0.03297952",
|
687
|
+
// "takerSide":"BUY"
|
688
|
+
// }
|
689
|
+
// ]
|
690
|
+
//
|
691
|
+
return this.parseTrades (response, market, since, limit);
|
692
|
+
}
|
693
|
+
|
694
|
+
async fetchTradingFee (symbol, params = {}) {
|
695
|
+
await this.loadMarkets ();
|
696
|
+
const market = this.market (symbol);
|
697
|
+
const request = {
|
698
|
+
'marketSymbol': market['id'],
|
699
|
+
};
|
700
|
+
const response = await this.privateGetAccountFeesTradingMarketSymbol (this.extend (request, params));
|
701
|
+
//
|
702
|
+
// {
|
703
|
+
// "marketSymbol":"1INCH-ETH",
|
704
|
+
// "makerRate":"0.00750000",
|
705
|
+
// "takerRate":"0.00750000"
|
706
|
+
// }
|
707
|
+
//
|
708
|
+
return this.parseTradingFee (response, market);
|
709
|
+
}
|
710
|
+
|
711
|
+
async fetchTradingFees (params = {}) {
|
712
|
+
await this.loadMarkets ();
|
713
|
+
const response = await this.privateGetAccountFeesTrading (params);
|
714
|
+
//
|
715
|
+
// [
|
716
|
+
// {"marketSymbol":"1ECO-BTC","makerRate":"0.00750000","takerRate":"0.00750000"},
|
717
|
+
// {"marketSymbol":"1ECO-USDT","makerRate":"0.00750000","takerRate":"0.00750000"},
|
718
|
+
// {"marketSymbol":"1INCH-BTC","makerRate":"0.00750000","takerRate":"0.00750000"},
|
719
|
+
// {"marketSymbol":"1INCH-ETH","makerRate":"0.00750000","takerRate":"0.00750000"},
|
720
|
+
// {"marketSymbol":"1INCH-USD","makerRate":"0.00750000","takerRate":"0.00750000"},
|
721
|
+
// ]
|
722
|
+
//
|
723
|
+
return this.parseTradingFees (response);
|
724
|
+
}
|
725
|
+
|
726
|
+
parseTradingFee (fee, market = undefined) {
|
727
|
+
const marketId = this.safeString (fee, 'marketSymbol');
|
728
|
+
const maker = this.safeNumber (fee, 'makerRate');
|
729
|
+
const taker = this.safeNumber (fee, 'takerRate');
|
730
|
+
return {
|
731
|
+
'info': fee,
|
732
|
+
'symbol': this.safeSymbol (marketId, market),
|
733
|
+
'maker': maker,
|
734
|
+
'taker': taker,
|
735
|
+
};
|
736
|
+
}
|
737
|
+
|
738
|
+
parseTradingFees (fees) {
|
739
|
+
const result = {
|
740
|
+
'info': fees,
|
741
|
+
};
|
742
|
+
for (let i = 0; i < fees.length; i++) {
|
743
|
+
const fee = this.parseTradingFee (fees[i]);
|
744
|
+
const symbol = fee['symbol'];
|
745
|
+
result[symbol] = fee;
|
746
|
+
}
|
747
|
+
return result;
|
748
|
+
}
|
749
|
+
|
750
|
+
parseOHLCV (ohlcv, market = undefined) {
|
751
|
+
//
|
752
|
+
// {
|
753
|
+
// "startsAt":"2020-06-12T02:35:00Z",
|
754
|
+
// "open":"0.02493753",
|
755
|
+
// "high":"0.02493753",
|
756
|
+
// "low":"0.02493753",
|
757
|
+
// "close":"0.02493753",
|
758
|
+
// "volume":"0.09590123",
|
759
|
+
// "quoteVolume":"0.00239153"
|
760
|
+
// }
|
761
|
+
//
|
762
|
+
return [
|
763
|
+
this.parse8601 (this.safeString (ohlcv, 'startsAt')),
|
764
|
+
this.safeNumber (ohlcv, 'open'),
|
765
|
+
this.safeNumber (ohlcv, 'high'),
|
766
|
+
this.safeNumber (ohlcv, 'low'),
|
767
|
+
this.safeNumber (ohlcv, 'close'),
|
768
|
+
this.safeNumber (ohlcv, 'volume'),
|
769
|
+
];
|
770
|
+
}
|
771
|
+
|
772
|
+
async fetchOHLCV (symbol, timeframe = '1m', since = undefined, limit = undefined, params = {}) {
|
773
|
+
await this.loadMarkets ();
|
774
|
+
const market = this.market (symbol);
|
775
|
+
const reverseId = market['baseId'] + '-' + market['quoteId'];
|
776
|
+
const request = {
|
777
|
+
'candleInterval': this.timeframes[timeframe],
|
778
|
+
'marketSymbol': reverseId,
|
779
|
+
};
|
780
|
+
let method = 'publicGetMarketsMarketSymbolCandlesCandleIntervalRecent';
|
781
|
+
if (since !== undefined) {
|
782
|
+
const now = this.milliseconds ();
|
783
|
+
const difference = Math.abs (now - since);
|
784
|
+
const sinceDate = this.yyyymmdd (since);
|
785
|
+
const parts = sinceDate.split ('-');
|
786
|
+
const sinceYear = this.safeInteger (parts, 0);
|
787
|
+
const sinceMonth = this.safeInteger (parts, 1);
|
788
|
+
const sinceDay = this.safeInteger (parts, 2);
|
789
|
+
if (timeframe === '1d') {
|
790
|
+
// if the since argument is beyond one year into the past
|
791
|
+
if (difference > 31622400000) {
|
792
|
+
method = 'publicGetMarketsMarketSymbolCandlesCandleIntervalHistoricalYear';
|
793
|
+
request['year'] = sinceYear;
|
794
|
+
}
|
795
|
+
// request['year'] = year;
|
796
|
+
} else if (timeframe === '1h') {
|
797
|
+
// if the since argument is beyond 31 days into the past
|
798
|
+
if (difference > 2678400000) {
|
799
|
+
method = 'publicGetMarketsMarketSymbolCandlesCandleIntervalHistoricalYearMonth';
|
800
|
+
request['year'] = sinceYear;
|
801
|
+
request['month'] = sinceMonth;
|
802
|
+
}
|
803
|
+
} else {
|
804
|
+
// if the since argument is beyond 1 day into the past
|
805
|
+
if (difference > 86400000) {
|
806
|
+
method = 'publicGetMarketsMarketSymbolCandlesCandleIntervalHistoricalYearMonthDay';
|
807
|
+
request['year'] = sinceYear;
|
808
|
+
request['month'] = sinceMonth;
|
809
|
+
request['day'] = sinceDay;
|
810
|
+
}
|
811
|
+
}
|
812
|
+
}
|
813
|
+
const response = await this[method] (this.extend (request, params));
|
814
|
+
//
|
815
|
+
// [
|
816
|
+
// {"startsAt":"2020-06-12T02:35:00Z","open":"0.02493753","high":"0.02493753","low":"0.02493753","close":"0.02493753","volume":"0.09590123","quoteVolume":"0.00239153"},
|
817
|
+
// {"startsAt":"2020-06-12T02:40:00Z","open":"0.02491874","high":"0.02491874","low":"0.02490970","close":"0.02490970","volume":"0.04515695","quoteVolume":"0.00112505"},
|
818
|
+
// {"startsAt":"2020-06-12T02:45:00Z","open":"0.02490753","high":"0.02493143","low":"0.02490753","close":"0.02493143","volume":"0.17769640","quoteVolume":"0.00442663"}
|
819
|
+
// ]
|
820
|
+
//
|
821
|
+
return this.parseOHLCVs (response, market, timeframe, since, limit);
|
822
|
+
}
|
823
|
+
|
824
|
+
async fetchOpenOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) {
|
825
|
+
await this.loadMarkets ();
|
826
|
+
const request = {};
|
827
|
+
let market = undefined;
|
828
|
+
const stop = this.safeValue (params, 'stop');
|
829
|
+
if (symbol !== undefined) {
|
830
|
+
market = this.market (symbol);
|
831
|
+
request['marketSymbol'] = market['id'];
|
832
|
+
}
|
833
|
+
let method = 'privateGetOrdersOpen';
|
834
|
+
if (stop) {
|
835
|
+
method = 'privateGetConditionalOrdersOpen';
|
836
|
+
}
|
837
|
+
const query = this.omit (params, 'stop');
|
838
|
+
const response = await this[method] (this.extend (request, query));
|
839
|
+
//
|
840
|
+
// Spot
|
841
|
+
//
|
842
|
+
// [
|
843
|
+
// {
|
844
|
+
// "id": "df6cf5ee-fc27-4b61-991a-cc94b6459ac9",
|
845
|
+
// "marketSymbol": "BTC-USDT",
|
846
|
+
// "direction": "BUY",
|
847
|
+
// "type": "LIMIT",
|
848
|
+
// "quantity": "0.00023277",
|
849
|
+
// "limit": "30000.00000000",
|
850
|
+
// "timeInForce": "GOOD_TIL_CANCELLED",
|
851
|
+
// "fillQuantity": "0.00000000",
|
852
|
+
// "commission": "0.00000000",
|
853
|
+
// "proceeds": "0.00000000",
|
854
|
+
// "status": "OPEN",
|
855
|
+
// "createdAt": "2022-04-20T02:33:53.16Z",
|
856
|
+
// "updatedAt": "2022-04-20T02:33:53.16Z"
|
857
|
+
// }
|
858
|
+
// ]
|
859
|
+
//
|
860
|
+
// Stop
|
861
|
+
//
|
862
|
+
// [
|
863
|
+
// {
|
864
|
+
// "id": "f64f7c4f-295c-408b-9cbc-601981abf100",
|
865
|
+
// "marketSymbol": "BTC-USDT",
|
866
|
+
// "operand": "LTE",
|
867
|
+
// "triggerPrice": "0.10000000",
|
868
|
+
// "orderToCreate": {
|
869
|
+
// "marketSymbol": "BTC-USDT",
|
870
|
+
// "direction": "BUY",
|
871
|
+
// "type": "LIMIT",
|
872
|
+
// "quantity": "0.00020000",
|
873
|
+
// "limit": "30000.00000000",
|
874
|
+
// "timeInForce": "GOOD_TIL_CANCELLED"
|
875
|
+
// },
|
876
|
+
// "status": "OPEN",
|
877
|
+
// "createdAt": "2022-04-20T02:38:12.26Z",
|
878
|
+
// "updatedAt": "2022-04-20T02:38:12.26Z"
|
879
|
+
// }
|
880
|
+
// ]
|
881
|
+
//
|
882
|
+
return this.parseOrders (response, market, since, limit);
|
883
|
+
}
|
884
|
+
|
885
|
+
async fetchOrderTrades (id, symbol = undefined, since = undefined, limit = undefined, params = {}) {
|
886
|
+
await this.loadMarkets ();
|
887
|
+
const request = {
|
888
|
+
'orderId': id,
|
889
|
+
};
|
890
|
+
const response = await this.privateGetOrdersOrderIdExecutions (this.extend (request, params));
|
891
|
+
let market = undefined;
|
892
|
+
if (symbol !== undefined) {
|
893
|
+
market = this.market (symbol);
|
894
|
+
}
|
895
|
+
return this.parseTrades (response, market, since, limit);
|
896
|
+
}
|
897
|
+
|
898
|
+
async createOrder (symbol, type, side, amount, price = undefined, params = {}) {
|
899
|
+
// A ceiling order is a market or limit order that allows you to specify
|
900
|
+
// the amount of quote currency you want to spend (or receive, if selling)
|
901
|
+
// instead of the quantity of the market currency (e.g. buy $100 USD of BTC
|
902
|
+
// at the current market BTC price)
|
903
|
+
await this.loadMarkets ();
|
904
|
+
const market = this.market (symbol);
|
905
|
+
let uppercaseType = undefined;
|
906
|
+
if (type !== undefined) {
|
907
|
+
uppercaseType = type.toUpperCase ();
|
908
|
+
}
|
909
|
+
const reverseId = market['baseId'] + '-' + market['quoteId'];
|
910
|
+
const stop = this.safeValue (params, 'stop');
|
911
|
+
const stopPrice = this.safeNumber2 (params, 'triggerPrice', 'stopPrice');
|
912
|
+
const request = {
|
913
|
+
'marketSymbol': reverseId, // SPOT and STOP
|
914
|
+
// 'direction': side.toUpperCase (), // SPOT, STOP 'orderToCreate'
|
915
|
+
// 'type': uppercaseType, // SPOT: LIMIT, MARKET, CEILING_LIMIT, CEILING_MARKET
|
916
|
+
// 'quantity': this.amountToPrecision (symbol, amount), // SPOT, required for limit orders, excluded for ceiling orders
|
917
|
+
// 'ceiling': this.priceToPrecision (symbol, price), // SPOT, required for ceiling orders, excluded for non-ceiling orders
|
918
|
+
// 'limit': this.priceToPrecision (symbol, price), // SPOT, required for limit orders, excluded for market orders
|
919
|
+
// 'timeInForce': 'GOOD_TIL_CANCELLED', // SPOT, IMMEDIATE_OR_CANCEL, FILL_OR_KILL, POST_ONLY_GOOD_TIL_CANCELLED
|
920
|
+
// 'useAwards': false, // SPOT, optional
|
921
|
+
// 'operand': 'LTE', // STOP, price above (GTE) or below (LTE) which the conditional order will trigger. either this or trailingStopPercent must be specified.
|
922
|
+
// 'triggerPrice': this.priceToPrecision (symbol, stopPrice), // STOP
|
923
|
+
// 'trailingStopPercent': this.priceToPrecision (symbol, stopPrice), // STOP, either this or triggerPrice must be set
|
924
|
+
// 'orderToCreate': {direction:side,type:uppercaseType}, // STOP, The spot order to be triggered
|
925
|
+
// 'orderToCancel': {id:'f03d5e98-b5ac-48fb-8647-dd4db828a297',type:uppercaseType}, // STOP, The spot order to be canceled
|
926
|
+
// 'clineConditionalOrderId': 'f03d5e98-b5ac-48fb-8647-dd4db828a297', // STOP
|
927
|
+
};
|
928
|
+
let method = 'privatePostOrders';
|
929
|
+
if (stop || stopPrice) {
|
930
|
+
method = 'privatePostConditionalOrders';
|
931
|
+
const operand = this.safeString (params, 'operand');
|
932
|
+
if (operand === undefined) {
|
933
|
+
throw new ArgumentsRequired (this.id + ' createOrder() requires an operand parameter');
|
934
|
+
}
|
935
|
+
const trailingStopPercent = this.safeNumber (params, 'trailingStopPercent');
|
936
|
+
const orderToCreate = this.safeValue (params, 'orderToCreate');
|
937
|
+
const orderToCancel = this.safeValue (params, 'orderToCancel');
|
938
|
+
if (stopPrice === undefined) {
|
939
|
+
request['trailingStopPercent'] = this.priceToPrecision (symbol, trailingStopPercent);
|
940
|
+
}
|
941
|
+
if (orderToCreate) {
|
942
|
+
const isCeilingLimit = (uppercaseType === 'CEILING_LIMIT');
|
943
|
+
const isCeilingMarket = (uppercaseType === 'CEILING_MARKET');
|
944
|
+
const isCeilingOrder = isCeilingLimit || isCeilingMarket;
|
945
|
+
let ceiling = undefined;
|
946
|
+
let limit = undefined;
|
947
|
+
let timeInForce = undefined;
|
948
|
+
if (isCeilingOrder) {
|
949
|
+
let cost = undefined;
|
950
|
+
if (isCeilingLimit) {
|
951
|
+
limit = this.priceToPrecision (symbol, price);
|
952
|
+
cost = this.safeNumber2 (params, 'ceiling', 'cost', amount);
|
953
|
+
} else if (isCeilingMarket) {
|
954
|
+
cost = this.safeNumber2 (params, 'ceiling', 'cost');
|
955
|
+
if (cost === undefined) {
|
956
|
+
if (price === undefined) {
|
957
|
+
cost = amount;
|
958
|
+
} else {
|
959
|
+
cost = amount * price;
|
960
|
+
}
|
961
|
+
}
|
962
|
+
}
|
963
|
+
ceiling = this.costToPrecision (symbol, cost);
|
964
|
+
timeInForce = 'IMMEDIATE_OR_CANCEL';
|
965
|
+
} else {
|
966
|
+
if (uppercaseType === 'LIMIT') {
|
967
|
+
limit = this.priceToPrecision (symbol, price);
|
968
|
+
timeInForce = 'GOOD_TIL_CANCELLED';
|
969
|
+
} else {
|
970
|
+
timeInForce = 'IMMEDIATE_OR_CANCEL';
|
971
|
+
}
|
972
|
+
}
|
973
|
+
request['orderToCreate'] = {
|
974
|
+
'marketSymbol': reverseId,
|
975
|
+
'direction': side.toUpperCase (),
|
976
|
+
'type': uppercaseType,
|
977
|
+
'quantity': this.amountToPrecision (symbol, amount),
|
978
|
+
'ceiling': ceiling,
|
979
|
+
'limit': limit,
|
980
|
+
'timeInForce': timeInForce,
|
981
|
+
'clientOrderId': this.safeString (params, 'clientOrderId'),
|
982
|
+
'useAwards': this.safeValue (params, 'useAwards'),
|
983
|
+
};
|
984
|
+
}
|
985
|
+
if (orderToCancel) {
|
986
|
+
request['orderToCancel'] = orderToCancel;
|
987
|
+
}
|
988
|
+
request['triggerPrice'] = this.priceToPrecision (symbol, stopPrice);
|
989
|
+
request['operand'] = operand;
|
990
|
+
} else {
|
991
|
+
if (side !== undefined) {
|
992
|
+
request['direction'] = side.toUpperCase ();
|
993
|
+
}
|
994
|
+
request['type'] = uppercaseType;
|
995
|
+
const isCeilingLimit = (uppercaseType === 'CEILING_LIMIT');
|
996
|
+
const isCeilingMarket = (uppercaseType === 'CEILING_MARKET');
|
997
|
+
const isCeilingOrder = isCeilingLimit || isCeilingMarket;
|
998
|
+
if (isCeilingOrder) {
|
999
|
+
let cost = undefined;
|
1000
|
+
if (isCeilingLimit) {
|
1001
|
+
request['limit'] = this.priceToPrecision (symbol, price);
|
1002
|
+
cost = this.safeNumber2 (params, 'ceiling', 'cost', amount);
|
1003
|
+
} else if (isCeilingMarket) {
|
1004
|
+
cost = this.safeNumber2 (params, 'ceiling', 'cost');
|
1005
|
+
if (cost === undefined) {
|
1006
|
+
if (price === undefined) {
|
1007
|
+
cost = amount;
|
1008
|
+
} else {
|
1009
|
+
cost = amount * price;
|
1010
|
+
}
|
1011
|
+
}
|
1012
|
+
}
|
1013
|
+
request['ceiling'] = this.costToPrecision (symbol, cost);
|
1014
|
+
// bittrex only accepts IMMEDIATE_OR_CANCEL or FILL_OR_KILL for ceiling orders
|
1015
|
+
request['timeInForce'] = 'IMMEDIATE_OR_CANCEL';
|
1016
|
+
} else {
|
1017
|
+
request['quantity'] = this.amountToPrecision (symbol, amount);
|
1018
|
+
if (uppercaseType === 'LIMIT') {
|
1019
|
+
request['limit'] = this.priceToPrecision (symbol, price);
|
1020
|
+
request['timeInForce'] = 'GOOD_TIL_CANCELLED';
|
1021
|
+
} else {
|
1022
|
+
// bittrex does not allow GOOD_TIL_CANCELLED for market orders
|
1023
|
+
request['timeInForce'] = 'IMMEDIATE_OR_CANCEL';
|
1024
|
+
}
|
1025
|
+
}
|
1026
|
+
}
|
1027
|
+
const query = this.omit (params, [ 'stop', 'stopPrice', 'ceiling', 'cost', 'operand', 'trailingStopPercent', 'orderToCreate', 'orderToCancel' ]);
|
1028
|
+
const response = await this[method] (this.extend (request, query));
|
1029
|
+
//
|
1030
|
+
// Spot
|
1031
|
+
//
|
1032
|
+
// {
|
1033
|
+
// id: 'f03d5e98-b5ac-48fb-8647-dd4db828a297',
|
1034
|
+
// marketSymbol: 'BTC-USDT',
|
1035
|
+
// direction: 'SELL',
|
1036
|
+
// type: 'LIMIT',
|
1037
|
+
// quantity: '0.01',
|
1038
|
+
// limit: '6000',
|
1039
|
+
// timeInForce: 'GOOD_TIL_CANCELLED',
|
1040
|
+
// fillQuantity: '0.00000000',
|
1041
|
+
// commission: '0.00000000',
|
1042
|
+
// proceeds: '0.00000000',
|
1043
|
+
// status: 'OPEN',
|
1044
|
+
// createdAt: '2020-03-18T02:37:33.42Z',
|
1045
|
+
// updatedAt: '2020-03-18T02:37:33.42Z'
|
1046
|
+
// }
|
1047
|
+
//
|
1048
|
+
// Stop
|
1049
|
+
//
|
1050
|
+
// {
|
1051
|
+
// "id": "9791fe52-a3e5-4ac3-ae03-e327b2993571",
|
1052
|
+
// "marketSymbol": "BTC-USDT",
|
1053
|
+
// "operand": "LTE",
|
1054
|
+
// "triggerPrice": "0.1",
|
1055
|
+
// "orderToCreate": {
|
1056
|
+
// "marketSymbol": "BTC-USDT",
|
1057
|
+
// "direction": "BUY",
|
1058
|
+
// "type": "LIMIT",
|
1059
|
+
// "quantity": "0.0002",
|
1060
|
+
// "limit": "30000",
|
1061
|
+
// "timeInForce": "GOOD_TIL_CANCELLED"
|
1062
|
+
// },
|
1063
|
+
// "status": "OPEN",
|
1064
|
+
// "createdAt": "2022-04-19T21:02:14.17Z",
|
1065
|
+
// "updatedAt": "2022-04-19T21:02:14.17Z"
|
1066
|
+
// }
|
1067
|
+
//
|
1068
|
+
return this.parseOrder (response, market);
|
1069
|
+
}
|
1070
|
+
|
1071
|
+
async cancelOrder (id, symbol = undefined, params = {}) {
|
1072
|
+
await this.loadMarkets ();
|
1073
|
+
const stop = this.safeValue (params, 'stop');
|
1074
|
+
let request = {};
|
1075
|
+
let method = undefined;
|
1076
|
+
let market = undefined;
|
1077
|
+
if (symbol !== undefined) {
|
1078
|
+
market = this.market (symbol);
|
1079
|
+
}
|
1080
|
+
if (stop) {
|
1081
|
+
method = 'privateDeleteConditionalOrdersConditionalOrderId';
|
1082
|
+
request = {
|
1083
|
+
'conditionalOrderId': id,
|
1084
|
+
};
|
1085
|
+
} else {
|
1086
|
+
method = 'privateDeleteOrdersOrderId';
|
1087
|
+
request = {
|
1088
|
+
'orderId': id,
|
1089
|
+
};
|
1090
|
+
}
|
1091
|
+
const query = this.omit (params, 'stop');
|
1092
|
+
const response = await this[method] (this.extend (request, query));
|
1093
|
+
//
|
1094
|
+
// Spot
|
1095
|
+
//
|
1096
|
+
// [
|
1097
|
+
// {
|
1098
|
+
// "id": "df6cf5ee-fc27-4b61-991a-cc94b6459ac9",
|
1099
|
+
// "marketSymbol": "BTC-USDT",
|
1100
|
+
// "direction": "BUY",
|
1101
|
+
// "type": "LIMIT",
|
1102
|
+
// "quantity": "0.00023277",
|
1103
|
+
// "limit": "30000.00000000",
|
1104
|
+
// "timeInForce": "GOOD_TIL_CANCELLED",
|
1105
|
+
// "fillQuantity": "0.00000000",
|
1106
|
+
// "commission": "0.00000000",
|
1107
|
+
// "proceeds": "0.00000000",
|
1108
|
+
// "status": "CANCELLED",
|
1109
|
+
// "createdAt": "2022-04-20T02:33:53.16Z",
|
1110
|
+
// "updatedAt": "2022-04-20T02:33:53.16Z"
|
1111
|
+
// }
|
1112
|
+
// ]
|
1113
|
+
//
|
1114
|
+
// Stop
|
1115
|
+
//
|
1116
|
+
// [
|
1117
|
+
// {
|
1118
|
+
// "id": "f64f7c4f-295c-408b-9cbc-601981abf100",
|
1119
|
+
// "marketSymbol": "BTC-USDT",
|
1120
|
+
// "operand": "LTE",
|
1121
|
+
// "triggerPrice": "0.10000000",
|
1122
|
+
// "orderToCreate": {
|
1123
|
+
// "marketSymbol": "BTC-USDT",
|
1124
|
+
// "direction": "BUY",
|
1125
|
+
// "type": "LIMIT",
|
1126
|
+
// "quantity": "0.00020000",
|
1127
|
+
// "limit": "30000.00000000",
|
1128
|
+
// "timeInForce": "GOOD_TIL_CANCELLED"
|
1129
|
+
// },
|
1130
|
+
// "status": "CANCELLED",
|
1131
|
+
// "createdAt": "2022-04-20T02:38:12.26Z",
|
1132
|
+
// "updatedAt": "2022-04-20T02:38:12.26Z"
|
1133
|
+
// "closedAt": "2022-04-20T03:47:24.69Z"
|
1134
|
+
// }
|
1135
|
+
// ]
|
1136
|
+
//
|
1137
|
+
return this.extend (this.parseOrder (response, market), {
|
1138
|
+
'id': id,
|
1139
|
+
'info': response,
|
1140
|
+
'status': 'canceled',
|
1141
|
+
});
|
1142
|
+
}
|
1143
|
+
|
1144
|
+
async cancelAllOrders (symbol = undefined, params = {}) {
|
1145
|
+
await this.loadMarkets ();
|
1146
|
+
const request = {};
|
1147
|
+
let market = undefined;
|
1148
|
+
if (symbol !== undefined) {
|
1149
|
+
market = this.market (symbol);
|
1150
|
+
request['marketSymbol'] = market['id'];
|
1151
|
+
}
|
1152
|
+
const response = await this.privateDeleteOrdersOpen (this.extend (request, params));
|
1153
|
+
//
|
1154
|
+
// [
|
1155
|
+
// {
|
1156
|
+
// "id":"66582be0-5337-4d8c-b212-c356dd525801",
|
1157
|
+
// "statusCode":"SUCCESS",
|
1158
|
+
// "result":{
|
1159
|
+
// "id":"66582be0-5337-4d8c-b212-c356dd525801",
|
1160
|
+
// "marketSymbol":"BTC-USDT",
|
1161
|
+
// "direction":"BUY",
|
1162
|
+
// "type":"LIMIT",
|
1163
|
+
// "quantity":"0.01000000",
|
1164
|
+
// "limit":"3000.00000000",
|
1165
|
+
// "timeInForce":"GOOD_TIL_CANCELLED",
|
1166
|
+
// "fillQuantity":"0.00000000",
|
1167
|
+
// "commission":"0.00000000",
|
1168
|
+
// "proceeds":"0.00000000",
|
1169
|
+
// "status":"CLOSED",
|
1170
|
+
// "createdAt":"2020-10-06T12:31:53.39Z",
|
1171
|
+
// "updatedAt":"2020-10-06T12:54:28.8Z",
|
1172
|
+
// "closedAt":"2020-10-06T12:54:28.8Z"
|
1173
|
+
// }
|
1174
|
+
// }
|
1175
|
+
// ]
|
1176
|
+
//
|
1177
|
+
const orders = [];
|
1178
|
+
for (let i = 0; i < response.length; i++) {
|
1179
|
+
const result = this.safeValue (response[i], 'result', {});
|
1180
|
+
orders.push (result);
|
1181
|
+
}
|
1182
|
+
return this.parseOrders (orders, market);
|
1183
|
+
}
|
1184
|
+
|
1185
|
+
async fetchDeposits (code = undefined, since = undefined, limit = undefined, params = {}) {
|
1186
|
+
await this.loadMarkets ();
|
1187
|
+
// https://support.bittrex.com/hc/en-us/articles/115003723911
|
1188
|
+
const request = {};
|
1189
|
+
let currency = undefined;
|
1190
|
+
if (code !== undefined) {
|
1191
|
+
currency = this.currency (code);
|
1192
|
+
request['currencySymbol'] = currency['id'];
|
1193
|
+
}
|
1194
|
+
const response = await this.privateGetDepositsClosed (this.extend (request, params));
|
1195
|
+
// we cannot filter by `since` timestamp, as it isn't set by Bittrex
|
1196
|
+
// see https://github.com/ccxt/ccxt/issues/4067
|
1197
|
+
// return this.parseTransactions (response, currency, since, limit);
|
1198
|
+
return this.parseTransactions (response, currency, undefined, limit);
|
1199
|
+
}
|
1200
|
+
|
1201
|
+
async fetchWithdrawals (code = undefined, since = undefined, limit = undefined, params = {}) {
|
1202
|
+
await this.loadMarkets ();
|
1203
|
+
// https://support.bittrex.com/hc/en-us/articles/115003723911
|
1204
|
+
const request = {};
|
1205
|
+
let currency = undefined;
|
1206
|
+
if (code !== undefined) {
|
1207
|
+
currency = this.currency (code);
|
1208
|
+
request['currencySymbol'] = currency['id'];
|
1209
|
+
}
|
1210
|
+
const response = await this.privateGetWithdrawalsClosed (this.extend (request, params));
|
1211
|
+
return this.parseTransactions (response, currency, since, limit);
|
1212
|
+
}
|
1213
|
+
|
1214
|
+
parseTransaction (transaction, currency = undefined) {
|
1215
|
+
//
|
1216
|
+
// fetchDeposits
|
1217
|
+
//
|
1218
|
+
// {
|
1219
|
+
// "id": "d00fdf2e-df9e-48f1-....",
|
1220
|
+
// "currencySymbol": "BTC",
|
1221
|
+
// "quantity": "0.00550000",
|
1222
|
+
// "cryptoAddress": "1PhmYjnJPZH5NUwV8AU...",
|
1223
|
+
// "txId": "d1f1afffe1b9b6614eaee7e8133c85d98...",
|
1224
|
+
// "confirmations": 2,
|
1225
|
+
// "updatedAt": "2020-01-12T16:49:30.41Z",
|
1226
|
+
// "completedAt": "2020-01-12T16:49:30.41Z",
|
1227
|
+
// "status": "COMPLETED",
|
1228
|
+
// "source": "BLOCKCHAIN"
|
1229
|
+
// }
|
1230
|
+
//
|
1231
|
+
// fetchWithdrawals
|
1232
|
+
//
|
1233
|
+
// {
|
1234
|
+
// "PaymentUuid" : "e293da98-788c-4188-a8f9-8ec2c33fdfcf",
|
1235
|
+
// "Currency" : "XC",
|
1236
|
+
// "Amount" : 7513.75121715,
|
1237
|
+
// "Address" : "EVnSMgAd7EonF2Dgc4c9K14L12RBaW5S5J",
|
1238
|
+
// "Opened" : "2014-07-08T23:13:31.83",
|
1239
|
+
// "Authorized" : true,
|
1240
|
+
// "PendingPayment" : false,
|
1241
|
+
// "TxCost" : 0.00002000,
|
1242
|
+
// "TxId" : "b4a575c2a71c7e56d02ab8e26bb1ef0a2f6cf2094f6ca2116476a569c1e84f6e",
|
1243
|
+
// "Canceled" : false,
|
1244
|
+
// "InvalidAddress" : false
|
1245
|
+
// }
|
1246
|
+
//
|
1247
|
+
// withdraw
|
1248
|
+
//
|
1249
|
+
// {
|
1250
|
+
// "currencySymbol": "string",
|
1251
|
+
// "quantity": "number (double)",
|
1252
|
+
// "cryptoAddress": "string",
|
1253
|
+
// "cryptoAddressTag": "string",
|
1254
|
+
// "fundsTransferMethodId": "string (uuid)",
|
1255
|
+
// "clientWithdrawalId": "string (uuid)"
|
1256
|
+
// }
|
1257
|
+
//
|
1258
|
+
const id = this.safeString2 (transaction, 'id', 'clientWithdrawalId');
|
1259
|
+
const amount = this.safeNumber (transaction, 'quantity');
|
1260
|
+
const address = this.safeString (transaction, 'cryptoAddress');
|
1261
|
+
const txid = this.safeString (transaction, 'txId');
|
1262
|
+
const updated = this.parse8601 (this.safeString (transaction, 'updatedAt'));
|
1263
|
+
const opened = this.parse8601 (this.safeString (transaction, 'createdAt'));
|
1264
|
+
const timestamp = opened ? opened : updated;
|
1265
|
+
const type = (opened === undefined) ? 'deposit' : 'withdrawal';
|
1266
|
+
const currencyId = this.safeString (transaction, 'currencySymbol');
|
1267
|
+
const code = this.safeCurrencyCode (currencyId, currency);
|
1268
|
+
let status = 'pending';
|
1269
|
+
if (type === 'deposit') {
|
1270
|
+
//
|
1271
|
+
// deposits numConfirmations never reach the minConfirmations number
|
1272
|
+
// we set all of them to 'ok', otherwise they'd all be 'pending'
|
1273
|
+
//
|
1274
|
+
// const numConfirmations = this.safeInteger (transaction, 'Confirmations', 0);
|
1275
|
+
// const minConfirmations = this.safeInteger (currency['info'], 'MinConfirmation');
|
1276
|
+
// if (numConfirmations >= minConfirmations) {
|
1277
|
+
// status = 'ok';
|
1278
|
+
// }
|
1279
|
+
//
|
1280
|
+
status = 'ok';
|
1281
|
+
} else {
|
1282
|
+
const responseStatus = this.safeString (transaction, 'status');
|
1283
|
+
if (responseStatus === 'ERROR_INVALID_ADDRESS') {
|
1284
|
+
status = 'failed';
|
1285
|
+
} else if (responseStatus === 'CANCELLED') {
|
1286
|
+
status = 'canceled';
|
1287
|
+
} else if (responseStatus === 'PENDING') {
|
1288
|
+
status = 'pending';
|
1289
|
+
} else if (responseStatus === 'COMPLETED') {
|
1290
|
+
status = 'ok';
|
1291
|
+
} else if (responseStatus === 'AUTHORIZED' && (txid !== undefined)) {
|
1292
|
+
status = 'ok';
|
1293
|
+
}
|
1294
|
+
}
|
1295
|
+
let feeCost = this.safeNumber (transaction, 'txCost');
|
1296
|
+
if (feeCost === undefined) {
|
1297
|
+
if (type === 'deposit') {
|
1298
|
+
// according to https://support.bittrex.com/hc/en-us/articles/115000199651-What-fees-does-Bittrex-charge-
|
1299
|
+
feeCost = 0;
|
1300
|
+
}
|
1301
|
+
}
|
1302
|
+
return {
|
1303
|
+
'info': transaction,
|
1304
|
+
'id': id,
|
1305
|
+
'currency': code,
|
1306
|
+
'amount': amount,
|
1307
|
+
'network': undefined,
|
1308
|
+
'address': address,
|
1309
|
+
'addressTo': undefined,
|
1310
|
+
'addressFrom': undefined,
|
1311
|
+
'tag': undefined,
|
1312
|
+
'tagTo': undefined,
|
1313
|
+
'tagFrom': undefined,
|
1314
|
+
'status': status,
|
1315
|
+
'type': type,
|
1316
|
+
'updated': updated,
|
1317
|
+
'txid': txid,
|
1318
|
+
'timestamp': timestamp,
|
1319
|
+
'datetime': this.iso8601 (timestamp),
|
1320
|
+
'fee': {
|
1321
|
+
'currency': code,
|
1322
|
+
'cost': feeCost,
|
1323
|
+
},
|
1324
|
+
};
|
1325
|
+
}
|
1326
|
+
|
1327
|
+
parseTimeInForce (timeInForce) {
|
1328
|
+
const timeInForces = {
|
1329
|
+
'GOOD_TIL_CANCELLED': 'GTC',
|
1330
|
+
'IMMEDIATE_OR_CANCEL': 'IOC',
|
1331
|
+
'FILL_OR_KILL': 'FOK',
|
1332
|
+
'POST_ONLY_GOOD_TIL_CANCELLED': 'PO',
|
1333
|
+
};
|
1334
|
+
return this.safeString (timeInForces, timeInForce, timeInForce);
|
1335
|
+
}
|
1336
|
+
|
1337
|
+
parseOrder (order, market = undefined) {
|
1338
|
+
//
|
1339
|
+
// Spot createOrder, fetchOpenOrders, fetchClosedOrders, fetchOrder, cancelOrder
|
1340
|
+
//
|
1341
|
+
// {
|
1342
|
+
// id: '1be35109-b763-44ce-b6ea-05b6b0735c0c',
|
1343
|
+
// marketSymbol: 'LTC-ETH',
|
1344
|
+
// direction: 'BUY',
|
1345
|
+
// type: 'LIMIT',
|
1346
|
+
// quantity: '0.50000000',
|
1347
|
+
// limit: '0.17846699',
|
1348
|
+
// timeInForce: 'GOOD_TIL_CANCELLED',
|
1349
|
+
// clientOrderId: 'ff156d39-fe01-44ca-8f21-b0afa19ef228',
|
1350
|
+
// fillQuantity: '0.50000000',
|
1351
|
+
// commission: '0.00022286',
|
1352
|
+
// proceeds: '0.08914915',
|
1353
|
+
// status: 'CLOSED',
|
1354
|
+
// createdAt: '2018-06-23T13:14:28.613Z',
|
1355
|
+
// updatedAt: '2018-06-23T13:14:30.19Z',
|
1356
|
+
// closedAt: '2018-06-23T13:14:30.19Z'
|
1357
|
+
// }
|
1358
|
+
//
|
1359
|
+
// Stop createOrder, fetchOpenOrders, fetchClosedOrders, fetchOrder, cancelOrder
|
1360
|
+
//
|
1361
|
+
// {
|
1362
|
+
// "id": "9791fe52-a3e5-4ac3-ae03-e327b2993571",
|
1363
|
+
// "marketSymbol": "BTC-USDT",
|
1364
|
+
// "operand": "LTE",
|
1365
|
+
// "triggerPrice": "0.1",
|
1366
|
+
// "orderToCreate": {
|
1367
|
+
// "marketSymbol": "BTC-USDT",
|
1368
|
+
// "direction": "BUY",
|
1369
|
+
// "type": "LIMIT",
|
1370
|
+
// "quantity": "0.0002",
|
1371
|
+
// "limit": "30000",
|
1372
|
+
// "timeInForce": "GOOD_TIL_CANCELLED"
|
1373
|
+
// },
|
1374
|
+
// "status": "OPEN",
|
1375
|
+
// "createdAt": "2022-04-19T21:02:14.17Z",
|
1376
|
+
// "updatedAt": "2022-04-19T21:02:14.17Z",
|
1377
|
+
// "closedAt": "2022-04-20T03:47:24.69Z"
|
1378
|
+
// }
|
1379
|
+
//
|
1380
|
+
const marketSymbol = this.safeString (order, 'marketSymbol');
|
1381
|
+
market = this.safeMarket (marketSymbol, market, '-');
|
1382
|
+
const symbol = market['symbol'];
|
1383
|
+
const feeCurrency = market['quote'];
|
1384
|
+
const createdAt = this.safeString (order, 'createdAt');
|
1385
|
+
const updatedAt = this.safeString (order, 'updatedAt');
|
1386
|
+
const closedAt = this.safeString (order, 'closedAt');
|
1387
|
+
const clientOrderId = this.safeString (order, 'clientOrderId');
|
1388
|
+
let lastTradeTimestamp = undefined;
|
1389
|
+
if (closedAt !== undefined) {
|
1390
|
+
lastTradeTimestamp = this.parse8601 (closedAt);
|
1391
|
+
} else if (updatedAt) {
|
1392
|
+
lastTradeTimestamp = this.parse8601 (updatedAt);
|
1393
|
+
}
|
1394
|
+
const timestamp = this.parse8601 (createdAt);
|
1395
|
+
let direction = this.safeStringLower (order, 'direction');
|
1396
|
+
if (direction === undefined) {
|
1397
|
+
let conditionalOrder = this.safeValue (order, 'orderToCreate');
|
1398
|
+
if (conditionalOrder === undefined) {
|
1399
|
+
conditionalOrder = this.safeValue (order, 'orderToCancel');
|
1400
|
+
}
|
1401
|
+
direction = this.safeStringLower (conditionalOrder, 'direction');
|
1402
|
+
}
|
1403
|
+
let type = this.safeStringLower (order, 'type');
|
1404
|
+
if (type === undefined) {
|
1405
|
+
let conditionalOrder = this.safeValue (order, 'orderToCreate');
|
1406
|
+
if (conditionalOrder === undefined) {
|
1407
|
+
conditionalOrder = this.safeValue (order, 'orderToCancel');
|
1408
|
+
}
|
1409
|
+
type = this.safeStringLower (conditionalOrder, 'type');
|
1410
|
+
}
|
1411
|
+
let quantity = this.safeString (order, 'quantity');
|
1412
|
+
if (quantity === undefined) {
|
1413
|
+
let conditionalOrder = this.safeValue (order, 'orderToCreate');
|
1414
|
+
if (conditionalOrder === undefined) {
|
1415
|
+
conditionalOrder = this.safeValue (order, 'orderToCancel');
|
1416
|
+
}
|
1417
|
+
quantity = this.safeString (conditionalOrder, 'quantity');
|
1418
|
+
}
|
1419
|
+
let limit = this.safeString (order, 'limit');
|
1420
|
+
if (limit === undefined) {
|
1421
|
+
let conditionalOrder = this.safeValue (order, 'orderToCreate');
|
1422
|
+
if (conditionalOrder === undefined) {
|
1423
|
+
conditionalOrder = this.safeValue (order, 'orderToCancel');
|
1424
|
+
}
|
1425
|
+
limit = this.safeString (conditionalOrder, 'limit');
|
1426
|
+
}
|
1427
|
+
let timeInForce = this.parseTimeInForce (this.safeString (order, 'timeInForce'));
|
1428
|
+
if (timeInForce === undefined) {
|
1429
|
+
let conditionalOrder = this.safeValue (order, 'orderToCreate');
|
1430
|
+
if (conditionalOrder === undefined) {
|
1431
|
+
conditionalOrder = this.safeValue (order, 'orderToCancel');
|
1432
|
+
}
|
1433
|
+
timeInForce = this.parseTimeInForce (this.safeString (conditionalOrder, 'timeInForce'));
|
1434
|
+
}
|
1435
|
+
const fillQuantity = this.safeString (order, 'fillQuantity');
|
1436
|
+
const commission = this.safeNumber (order, 'commission');
|
1437
|
+
const proceeds = this.safeString (order, 'proceeds');
|
1438
|
+
const status = this.safeStringLower (order, 'status');
|
1439
|
+
const postOnly = (timeInForce === 'PO');
|
1440
|
+
return this.safeOrder ({
|
1441
|
+
'id': this.safeString (order, 'id'),
|
1442
|
+
'clientOrderId': clientOrderId,
|
1443
|
+
'timestamp': timestamp,
|
1444
|
+
'datetime': this.iso8601 (timestamp),
|
1445
|
+
'lastTradeTimestamp': lastTradeTimestamp,
|
1446
|
+
'symbol': symbol,
|
1447
|
+
'type': type,
|
1448
|
+
'timeInForce': timeInForce,
|
1449
|
+
'postOnly': postOnly,
|
1450
|
+
'side': direction,
|
1451
|
+
'price': limit,
|
1452
|
+
'stopPrice': this.safeString (order, 'triggerPrice'),
|
1453
|
+
'cost': proceeds,
|
1454
|
+
'average': undefined,
|
1455
|
+
'amount': quantity,
|
1456
|
+
'filled': fillQuantity,
|
1457
|
+
'remaining': undefined,
|
1458
|
+
'status': status,
|
1459
|
+
'fee': {
|
1460
|
+
'cost': commission,
|
1461
|
+
'currency': feeCurrency,
|
1462
|
+
},
|
1463
|
+
'info': order,
|
1464
|
+
'trades': undefined,
|
1465
|
+
}, market);
|
1466
|
+
}
|
1467
|
+
|
1468
|
+
parseOrders (orders, market = undefined, since = undefined, limit = undefined, params = {}) {
|
1469
|
+
if (this.options['fetchClosedOrdersFilterBySince']) {
|
1470
|
+
return super.parseOrders (orders, market, since, limit, params);
|
1471
|
+
} else {
|
1472
|
+
return super.parseOrders (orders, market, undefined, limit, params);
|
1473
|
+
}
|
1474
|
+
}
|
1475
|
+
|
1476
|
+
parseOrderStatus (status) {
|
1477
|
+
const statuses = {
|
1478
|
+
'CLOSED': 'closed',
|
1479
|
+
'OPEN': 'open',
|
1480
|
+
'CANCELLED': 'canceled',
|
1481
|
+
'CANCELED': 'canceled',
|
1482
|
+
};
|
1483
|
+
return this.safeString (statuses, status, status);
|
1484
|
+
}
|
1485
|
+
|
1486
|
+
async fetchOrder (id, symbol = undefined, params = {}) {
|
1487
|
+
await this.loadMarkets ();
|
1488
|
+
const stop = this.safeValue (params, 'stop');
|
1489
|
+
let market = undefined;
|
1490
|
+
if (symbol !== undefined) {
|
1491
|
+
market = this.market (symbol);
|
1492
|
+
}
|
1493
|
+
let response = undefined;
|
1494
|
+
let method = undefined;
|
1495
|
+
try {
|
1496
|
+
const request = {};
|
1497
|
+
if (stop) {
|
1498
|
+
method = 'privateGetConditionalOrdersConditionalOrderId';
|
1499
|
+
request['conditionalOrderId'] = id;
|
1500
|
+
} else {
|
1501
|
+
method = 'privateGetOrdersOrderId';
|
1502
|
+
request['orderId'] = id;
|
1503
|
+
}
|
1504
|
+
const query = this.omit (params, 'stop');
|
1505
|
+
response = await this[method] (this.extend (request, query));
|
1506
|
+
} catch (e) {
|
1507
|
+
if (this.last_json_response) {
|
1508
|
+
const message = this.safeString (this.last_json_response, 'message');
|
1509
|
+
if (message === 'UUID_INVALID') {
|
1510
|
+
throw new OrderNotFound (this.id + ' fetchOrder() error: ' + this.last_http_response);
|
1511
|
+
}
|
1512
|
+
}
|
1513
|
+
throw e;
|
1514
|
+
}
|
1515
|
+
return this.parseOrder (response, market);
|
1516
|
+
}
|
1517
|
+
|
1518
|
+
orderToTrade (order) {
|
1519
|
+
// this entire method should be moved to the base class
|
1520
|
+
const timestamp = this.safeInteger2 (order, 'lastTradeTimestamp', 'timestamp');
|
1521
|
+
return {
|
1522
|
+
'id': this.safeString (order, 'id'),
|
1523
|
+
'side': this.safeString (order, 'side'),
|
1524
|
+
'order': this.safeString (order, 'id'),
|
1525
|
+
'type': this.safeString (order, 'type'),
|
1526
|
+
'price': this.safeNumber (order, 'average'),
|
1527
|
+
'amount': this.safeNumber (order, 'filled'),
|
1528
|
+
'cost': this.safeNumber (order, 'cost'),
|
1529
|
+
'symbol': this.safeString (order, 'symbol'),
|
1530
|
+
'timestamp': timestamp,
|
1531
|
+
'datetime': this.iso8601 (timestamp),
|
1532
|
+
'fee': this.safeValue (order, 'fee'),
|
1533
|
+
'info': order,
|
1534
|
+
'takerOrMaker': undefined,
|
1535
|
+
};
|
1536
|
+
}
|
1537
|
+
|
1538
|
+
ordersToTrades (orders) {
|
1539
|
+
// this entire method should be moved to the base class
|
1540
|
+
const result = [];
|
1541
|
+
for (let i = 0; i < orders.length; i++) {
|
1542
|
+
result.push (this.orderToTrade (orders[i]));
|
1543
|
+
}
|
1544
|
+
return result;
|
1545
|
+
}
|
1546
|
+
|
1547
|
+
async fetchMyTrades (symbol = undefined, since = undefined, limit = undefined, params = {}) {
|
1548
|
+
await this.loadMarkets ();
|
1549
|
+
const request = {};
|
1550
|
+
if (limit !== undefined) {
|
1551
|
+
request['pageSize'] = limit;
|
1552
|
+
}
|
1553
|
+
if (since !== undefined) {
|
1554
|
+
request['startDate'] = this.ymdhms (since, 'T') + 'Z';
|
1555
|
+
}
|
1556
|
+
let market = undefined;
|
1557
|
+
if (symbol !== undefined) {
|
1558
|
+
market = this.market (symbol);
|
1559
|
+
symbol = market['symbol'];
|
1560
|
+
// because of this line we will have to rethink the entire v3
|
1561
|
+
// in other words, markets define all the rest of the API
|
1562
|
+
// and v3 market ids are reversed in comparison to v1
|
1563
|
+
// v3 has to be a completely separate implementation
|
1564
|
+
// otherwise we will have to shuffle symbols and currencies everywhere
|
1565
|
+
// which is prone to errors, as was shown here
|
1566
|
+
// https://github.com/ccxt/ccxt/pull/5219#issuecomment-499646209
|
1567
|
+
request['marketSymbol'] = market['base'] + '-' + market['quote'];
|
1568
|
+
}
|
1569
|
+
const response = await this.privateGetOrdersClosed (this.extend (request, params));
|
1570
|
+
const orders = this.parseOrders (response, market);
|
1571
|
+
const trades = this.ordersToTrades (orders);
|
1572
|
+
return this.filterBySymbolSinceLimit (trades, symbol, since, limit);
|
1573
|
+
}
|
1574
|
+
|
1575
|
+
async fetchClosedOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) {
|
1576
|
+
await this.loadMarkets ();
|
1577
|
+
const stop = this.safeValue (params, 'stop');
|
1578
|
+
const request = {};
|
1579
|
+
if (limit !== undefined) {
|
1580
|
+
request['pageSize'] = limit;
|
1581
|
+
}
|
1582
|
+
if (since !== undefined) {
|
1583
|
+
request['startDate'] = this.ymdhms (since, 'T') + 'Z';
|
1584
|
+
}
|
1585
|
+
let market = undefined;
|
1586
|
+
if (symbol !== undefined) {
|
1587
|
+
market = this.market (symbol);
|
1588
|
+
// because of this line we will have to rethink the entire v3
|
1589
|
+
// in other words, markets define all the rest of the API
|
1590
|
+
// and v3 market ids are reversed in comparison to v1
|
1591
|
+
// v3 has to be a completely separate implementation
|
1592
|
+
// otherwise we will have to shuffle symbols and currencies everywhere
|
1593
|
+
// which is prone to errors, as was shown here
|
1594
|
+
// https://github.com/ccxt/ccxt/pull/5219#issuecomment-499646209
|
1595
|
+
request['marketSymbol'] = market['base'] + '-' + market['quote'];
|
1596
|
+
}
|
1597
|
+
let method = 'privateGetOrdersClosed';
|
1598
|
+
if (stop) {
|
1599
|
+
method = 'privateGetConditionalOrdersClosed';
|
1600
|
+
}
|
1601
|
+
const query = this.omit (params, 'stop');
|
1602
|
+
const response = await this[method] (this.extend (request, query));
|
1603
|
+
//
|
1604
|
+
// Spot
|
1605
|
+
//
|
1606
|
+
// [
|
1607
|
+
// {
|
1608
|
+
// "id": "df6cf5ee-fc27-4b61-991a-cc94b6459ac9",
|
1609
|
+
// "marketSymbol": "BTC-USDT",
|
1610
|
+
// "direction": "BUY",
|
1611
|
+
// "type": "LIMIT",
|
1612
|
+
// "quantity": "0.00023277",
|
1613
|
+
// "limit": "30000.00000000",
|
1614
|
+
// "timeInForce": "GOOD_TIL_CANCELLED",
|
1615
|
+
// "fillQuantity": "0.00000000",
|
1616
|
+
// "commission": "0.00000000",
|
1617
|
+
// "proceeds": "0.00000000",
|
1618
|
+
// "status": "OPEN",
|
1619
|
+
// "createdAt": "2022-04-20T02:33:53.16Z",
|
1620
|
+
// "updatedAt": "2022-04-20T02:33:53.16Z"
|
1621
|
+
// }
|
1622
|
+
// ]
|
1623
|
+
//
|
1624
|
+
// Stop
|
1625
|
+
//
|
1626
|
+
// [
|
1627
|
+
// {
|
1628
|
+
// "id": "f64f7c4f-295c-408b-9cbc-601981abf100",
|
1629
|
+
// "marketSymbol": "BTC-USDT",
|
1630
|
+
// "operand": "LTE",
|
1631
|
+
// "triggerPrice": "0.10000000",
|
1632
|
+
// "orderToCreate": {
|
1633
|
+
// "marketSymbol": "BTC-USDT",
|
1634
|
+
// "direction": "BUY",
|
1635
|
+
// "type": "LIMIT",
|
1636
|
+
// "quantity": "0.00020000",
|
1637
|
+
// "limit": "30000.00000000",
|
1638
|
+
// "timeInForce": "GOOD_TIL_CANCELLED"
|
1639
|
+
// },
|
1640
|
+
// "status": "OPEN",
|
1641
|
+
// "createdAt": "2022-04-20T02:38:12.26Z",
|
1642
|
+
// "updatedAt": "2022-04-20T02:38:12.26Z"
|
1643
|
+
// }
|
1644
|
+
// ]
|
1645
|
+
//
|
1646
|
+
return this.parseOrders (response, market, since, limit);
|
1647
|
+
}
|
1648
|
+
|
1649
|
+
async createDepositAddress (code, params = {}) {
|
1650
|
+
await this.loadMarkets ();
|
1651
|
+
const currency = this.currency (code);
|
1652
|
+
const request = {
|
1653
|
+
'currencySymbol': currency['id'],
|
1654
|
+
};
|
1655
|
+
const response = await this.privatePostAddresses (this.extend (request, params));
|
1656
|
+
//
|
1657
|
+
// {
|
1658
|
+
// "status":"PROVISIONED",
|
1659
|
+
// "currencySymbol":"XRP",
|
1660
|
+
// "cryptoAddress":"rPVMhWBsfF9iMXYj3aAzJVkPDTFNSyWdKy",
|
1661
|
+
// "cryptoAddressTag":"392034158"
|
1662
|
+
// }
|
1663
|
+
//
|
1664
|
+
let address = this.safeString (response, 'cryptoAddress');
|
1665
|
+
const message = this.safeString (response, 'status');
|
1666
|
+
if (!address || message === 'REQUESTED') {
|
1667
|
+
throw new AddressPending (this.id + ' the address for ' + code + ' is being generated (pending, not ready yet, retry again later)');
|
1668
|
+
}
|
1669
|
+
let tag = this.safeString (response, 'cryptoAddressTag');
|
1670
|
+
if ((tag === undefined) && (currency['type'] in this.options['tag'])) {
|
1671
|
+
tag = address;
|
1672
|
+
address = currency['address'];
|
1673
|
+
}
|
1674
|
+
this.checkAddress (address);
|
1675
|
+
return {
|
1676
|
+
'currency': code,
|
1677
|
+
'address': address,
|
1678
|
+
'tag': tag,
|
1679
|
+
'info': response,
|
1680
|
+
};
|
1681
|
+
}
|
1682
|
+
|
1683
|
+
async fetchDepositAddress (code, params = {}) {
|
1684
|
+
await this.loadMarkets ();
|
1685
|
+
const currency = this.currency (code);
|
1686
|
+
const request = {
|
1687
|
+
'currencySymbol': currency['id'],
|
1688
|
+
};
|
1689
|
+
const response = await this.privateGetAddressesCurrencySymbol (this.extend (request, params));
|
1690
|
+
//
|
1691
|
+
// {
|
1692
|
+
// "status":"PROVISIONED",
|
1693
|
+
// "currencySymbol":"XRP",
|
1694
|
+
// "cryptoAddress":"rPVMhWBsfF9iMXYj3aAzJVkPDTFNSyWdKy",
|
1695
|
+
// "cryptoAddressTag":"392034158"
|
1696
|
+
// }
|
1697
|
+
//
|
1698
|
+
let address = this.safeString (response, 'cryptoAddress');
|
1699
|
+
const message = this.safeString (response, 'status');
|
1700
|
+
if (!address || message === 'REQUESTED') {
|
1701
|
+
throw new AddressPending (this.id + ' the address for ' + code + ' is being generated (pending, not ready yet, retry again later)');
|
1702
|
+
}
|
1703
|
+
let tag = this.safeString (response, 'cryptoAddressTag');
|
1704
|
+
if ((tag === undefined) && (currency['type'] in this.options['tag'])) {
|
1705
|
+
tag = address;
|
1706
|
+
address = currency['address'];
|
1707
|
+
}
|
1708
|
+
this.checkAddress (address);
|
1709
|
+
return {
|
1710
|
+
'currency': code,
|
1711
|
+
'address': address,
|
1712
|
+
'tag': tag,
|
1713
|
+
'network': undefined,
|
1714
|
+
'info': response,
|
1715
|
+
};
|
1716
|
+
}
|
1717
|
+
|
1718
|
+
async withdraw (code, amount, address, tag = undefined, params = {}) {
|
1719
|
+
[ tag, params ] = this.handleWithdrawTagAndParams (tag, params);
|
1720
|
+
this.checkAddress (address);
|
1721
|
+
await this.loadMarkets ();
|
1722
|
+
const currency = this.currency (code);
|
1723
|
+
const request = {
|
1724
|
+
'currencySymbol': currency['id'],
|
1725
|
+
'quantity': amount,
|
1726
|
+
'cryptoAddress': address,
|
1727
|
+
};
|
1728
|
+
if (tag !== undefined) {
|
1729
|
+
request['cryptoAddressTag'] = tag;
|
1730
|
+
}
|
1731
|
+
const response = await this.privatePostWithdrawals (this.extend (request, params));
|
1732
|
+
//
|
1733
|
+
// {
|
1734
|
+
// "currencySymbol": "string",
|
1735
|
+
// "quantity": "number (double)",
|
1736
|
+
// "cryptoAddress": "string",
|
1737
|
+
// "cryptoAddressTag": "string",
|
1738
|
+
// "fundsTransferMethodId": "string (uuid)",
|
1739
|
+
// "clientWithdrawalId": "string (uuid)"
|
1740
|
+
// }
|
1741
|
+
//
|
1742
|
+
return this.parseTransaction (response, currency);
|
1743
|
+
}
|
1744
|
+
|
1745
|
+
sign (path, api = 'v3', method = 'GET', params = {}, headers = undefined, body = undefined) {
|
1746
|
+
let url = this.implodeParams (this.urls['api'][api], {
|
1747
|
+
'hostname': this.hostname,
|
1748
|
+
}) + '/';
|
1749
|
+
if (api === 'private') {
|
1750
|
+
url += this.version + '/';
|
1751
|
+
this.checkRequiredCredentials ();
|
1752
|
+
url += this.implodeParams (path, params);
|
1753
|
+
params = this.omit (params, this.extractParams (path));
|
1754
|
+
let hashString = '';
|
1755
|
+
if (method === 'POST') {
|
1756
|
+
body = this.json (params);
|
1757
|
+
hashString = body;
|
1758
|
+
} else {
|
1759
|
+
if (Object.keys (params).length) {
|
1760
|
+
url += '?' + this.rawencode (params);
|
1761
|
+
}
|
1762
|
+
}
|
1763
|
+
const contentHash = this.hash (this.encode (hashString), 'sha512', 'hex');
|
1764
|
+
const timestamp = this.milliseconds ().toString ();
|
1765
|
+
let auth = timestamp + url + method + contentHash;
|
1766
|
+
const subaccountId = this.safeValue (this.options, 'subaccountId');
|
1767
|
+
if (subaccountId !== undefined) {
|
1768
|
+
auth += subaccountId;
|
1769
|
+
}
|
1770
|
+
const signature = this.hmac (this.encode (auth), this.encode (this.secret), 'sha512');
|
1771
|
+
headers = {
|
1772
|
+
'Api-Key': this.apiKey,
|
1773
|
+
'Api-Timestamp': timestamp,
|
1774
|
+
'Api-Content-Hash': contentHash,
|
1775
|
+
'Api-Signature': signature,
|
1776
|
+
};
|
1777
|
+
if (subaccountId !== undefined) {
|
1778
|
+
headers['Api-Subaccount-Id'] = subaccountId;
|
1779
|
+
}
|
1780
|
+
if (method === 'POST') {
|
1781
|
+
headers['Content-Type'] = 'application/json';
|
1782
|
+
}
|
1783
|
+
} else {
|
1784
|
+
if (api === 'public') {
|
1785
|
+
url += this.version + '/';
|
1786
|
+
}
|
1787
|
+
url += this.implodeParams (path, params);
|
1788
|
+
params = this.omit (params, this.extractParams (path));
|
1789
|
+
if (Object.keys (params).length) {
|
1790
|
+
url += '?' + this.urlencode (params);
|
1791
|
+
}
|
1792
|
+
}
|
1793
|
+
return { 'url': url, 'method': method, 'body': body, 'headers': headers };
|
1794
|
+
}
|
1795
|
+
|
1796
|
+
handleErrors (code, reason, url, method, headers, body, response, requestHeaders, requestBody) {
|
1797
|
+
if (response === undefined) {
|
1798
|
+
return; // fallback to default error handler
|
1799
|
+
}
|
1800
|
+
//
|
1801
|
+
// { success: false, message: "message" }
|
1802
|
+
//
|
1803
|
+
if (body[0] === '{') {
|
1804
|
+
const feedback = this.id + ' ' + body;
|
1805
|
+
let success = this.safeValue (response, 'success');
|
1806
|
+
if (success === undefined) {
|
1807
|
+
const code = this.safeString (response, 'code');
|
1808
|
+
if ((code === 'NOT_FOUND') && (url.indexOf ('addresses') >= 0)) {
|
1809
|
+
throw new InvalidAddress (feedback);
|
1810
|
+
}
|
1811
|
+
if (code !== undefined) {
|
1812
|
+
this.throwExactlyMatchedException (this.exceptions['exact'], code, feedback);
|
1813
|
+
this.throwBroadlyMatchedException (this.exceptions['broad'], code, feedback);
|
1814
|
+
}
|
1815
|
+
// throw new ExchangeError (this.id + ' malformed response ' + this.json (response));
|
1816
|
+
return;
|
1817
|
+
}
|
1818
|
+
if (typeof success === 'string') {
|
1819
|
+
// bleutrade uses string instead of boolean
|
1820
|
+
success = (success === 'true');
|
1821
|
+
}
|
1822
|
+
if (!success) {
|
1823
|
+
const message = this.safeString (response, 'message');
|
1824
|
+
if (message === 'APIKEY_INVALID') {
|
1825
|
+
if (this.options['hasAlreadyAuthenticatedSuccessfully']) {
|
1826
|
+
throw new DDoSProtection (feedback);
|
1827
|
+
} else {
|
1828
|
+
throw new AuthenticationError (feedback);
|
1829
|
+
}
|
1830
|
+
}
|
1831
|
+
// https://github.com/ccxt/ccxt/issues/4932
|
1832
|
+
// the following two lines are now redundant, see line 171 in describe()
|
1833
|
+
//
|
1834
|
+
// if (message === 'DUST_TRADE_DISALLOWED_MIN_VALUE_50K_SAT')
|
1835
|
+
// throw new InvalidOrder (this.id + ' order cost should be over 50k satoshi ' + this.json (response));
|
1836
|
+
//
|
1837
|
+
if (message === 'INVALID_ORDER') {
|
1838
|
+
// Bittrex will return an ambiguous INVALID_ORDER message
|
1839
|
+
// upon canceling already-canceled and closed orders
|
1840
|
+
// therefore this special case for cancelOrder
|
1841
|
+
// let url = 'https://bittrex.com/api/v1.1/market/cancel?apikey=API_KEY&uuid=ORDER_UUID'
|
1842
|
+
const cancel = 'cancel';
|
1843
|
+
const indexOfCancel = url.indexOf (cancel);
|
1844
|
+
if (indexOfCancel >= 0) {
|
1845
|
+
const urlParts = url.split ('?');
|
1846
|
+
const numParts = urlParts.length;
|
1847
|
+
if (numParts > 1) {
|
1848
|
+
const query = urlParts[1];
|
1849
|
+
const params = query.split ('&');
|
1850
|
+
const numParams = params.length;
|
1851
|
+
let orderId = undefined;
|
1852
|
+
for (let i = 0; i < numParams; i++) {
|
1853
|
+
const param = params[i];
|
1854
|
+
const keyValue = param.split ('=');
|
1855
|
+
if (keyValue[0] === 'uuid') {
|
1856
|
+
orderId = keyValue[1];
|
1857
|
+
break;
|
1858
|
+
}
|
1859
|
+
}
|
1860
|
+
if (orderId !== undefined) {
|
1861
|
+
throw new OrderNotFound (this.id + ' cancelOrder ' + orderId + ' ' + this.json (response));
|
1862
|
+
} else {
|
1863
|
+
throw new OrderNotFound (this.id + ' cancelOrder ' + this.json (response));
|
1864
|
+
}
|
1865
|
+
}
|
1866
|
+
}
|
1867
|
+
}
|
1868
|
+
this.throwExactlyMatchedException (this.exceptions['exact'], message, feedback);
|
1869
|
+
if (message !== undefined) {
|
1870
|
+
this.throwBroadlyMatchedException (this.exceptions['broad'], message, feedback);
|
1871
|
+
}
|
1872
|
+
throw new ExchangeError (feedback);
|
1873
|
+
}
|
1874
|
+
}
|
1875
|
+
}
|
1876
|
+
};
|