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
@@ -0,0 +1,1466 @@
|
|
1
|
+
'use strict';
|
2
|
+
|
3
|
+
// ----------------------------------------------------------------------------
|
4
|
+
|
5
|
+
const Exchange = require ('./base/Exchange');
|
6
|
+
const { InsufficientFunds, ArgumentsRequired, ExchangeError, InvalidOrder, InvalidAddress, AuthenticationError, NotSupported, OrderNotFound, OnMaintenance, PermissionDenied, RateLimitExceeded } = require ('./base/errors');
|
7
|
+
const { TICK_SIZE } = require ('./base/functions/number');
|
8
|
+
const Precise = require ('./base/Precise');
|
9
|
+
|
10
|
+
// ----------------------------------------------------------------------------
|
11
|
+
|
12
|
+
module.exports = class coinbasepro extends Exchange {
|
13
|
+
describe () {
|
14
|
+
return this.deepExtend (super.describe (), {
|
15
|
+
'id': 'coinbasepro',
|
16
|
+
'name': 'Coinbase Pro',
|
17
|
+
'countries': [ 'US' ],
|
18
|
+
'rateLimit': 100,
|
19
|
+
'userAgent': this.userAgents['chrome'],
|
20
|
+
'pro': true,
|
21
|
+
'has': {
|
22
|
+
'CORS': true,
|
23
|
+
'spot': true,
|
24
|
+
'margin': undefined, // has but not fully inplemented
|
25
|
+
'swap': undefined, // has but not fully inplemented
|
26
|
+
'future': undefined, // has but not fully inplemented
|
27
|
+
'option': undefined,
|
28
|
+
'cancelAllOrders': true,
|
29
|
+
'cancelOrder': true,
|
30
|
+
'createDepositAddress': true,
|
31
|
+
'createOrder': true,
|
32
|
+
'createStopLimitOrder': true,
|
33
|
+
'createStopMarketOrder': true,
|
34
|
+
'createStopOrder': true,
|
35
|
+
'fetchAccounts': true,
|
36
|
+
'fetchBalance': true,
|
37
|
+
'fetchClosedOrders': true,
|
38
|
+
'fetchCurrencies': true,
|
39
|
+
'fetchDepositAddress': undefined, // the exchange does not have this method, only createDepositAddress, see https://github.com/ccxt/ccxt/pull/7405
|
40
|
+
'fetchDeposits': true,
|
41
|
+
'fetchLedger': true,
|
42
|
+
'fetchMarkets': true,
|
43
|
+
'fetchMyTrades': true,
|
44
|
+
'fetchOHLCV': true,
|
45
|
+
'fetchOpenOrders': true,
|
46
|
+
'fetchOrder': true,
|
47
|
+
'fetchOrderBook': true,
|
48
|
+
'fetchOrders': true,
|
49
|
+
'fetchOrderTrades': true,
|
50
|
+
'fetchTicker': true,
|
51
|
+
'fetchTickers': true,
|
52
|
+
'fetchTime': true,
|
53
|
+
'fetchTrades': true,
|
54
|
+
'fetchTradingFee': false,
|
55
|
+
'fetchTradingFees': true,
|
56
|
+
'fetchTransactions': true,
|
57
|
+
'fetchWithdrawals': true,
|
58
|
+
'withdraw': true,
|
59
|
+
},
|
60
|
+
'timeframes': {
|
61
|
+
'1m': 60,
|
62
|
+
'5m': 300,
|
63
|
+
'15m': 900,
|
64
|
+
'1h': 3600,
|
65
|
+
'6h': 21600,
|
66
|
+
'1d': 86400,
|
67
|
+
},
|
68
|
+
'hostname': 'pro.coinbase.com',
|
69
|
+
'urls': {
|
70
|
+
'test': {
|
71
|
+
'public': 'https://api-public.sandbox.pro.coinbase.com',
|
72
|
+
'private': 'https://api-public.sandbox.pro.coinbase.com',
|
73
|
+
},
|
74
|
+
'logo': 'https://user-images.githubusercontent.com/1294454/41764625-63b7ffde-760a-11e8-996d-a6328fa9347a.jpg',
|
75
|
+
'api': {
|
76
|
+
'public': 'https://api.{hostname}',
|
77
|
+
'private': 'https://api.{hostname}',
|
78
|
+
},
|
79
|
+
'www': 'https://pro.coinbase.com/',
|
80
|
+
'doc': 'https://docs.pro.coinbase.com',
|
81
|
+
'fees': [
|
82
|
+
'https://docs.pro.coinbase.com/#fees',
|
83
|
+
'https://support.pro.coinbase.com/customer/en/portal/articles/2945310-fees',
|
84
|
+
],
|
85
|
+
},
|
86
|
+
'requiredCredentials': {
|
87
|
+
'apiKey': true,
|
88
|
+
'secret': true,
|
89
|
+
'password': true,
|
90
|
+
},
|
91
|
+
'api': {
|
92
|
+
'public': {
|
93
|
+
'get': [
|
94
|
+
'currencies',
|
95
|
+
'products',
|
96
|
+
'products/{id}',
|
97
|
+
'products/{id}/book',
|
98
|
+
'products/{id}/candles',
|
99
|
+
'products/{id}/stats',
|
100
|
+
'products/{id}/ticker',
|
101
|
+
'products/{id}/trades',
|
102
|
+
'time',
|
103
|
+
'products/spark-lines', // experimental
|
104
|
+
],
|
105
|
+
},
|
106
|
+
'private': {
|
107
|
+
'get': [
|
108
|
+
'accounts',
|
109
|
+
'accounts/{id}',
|
110
|
+
'accounts/{id}/holds',
|
111
|
+
'accounts/{id}/ledger',
|
112
|
+
'accounts/{id}/transfers',
|
113
|
+
'coinbase-accounts',
|
114
|
+
'fills',
|
115
|
+
'funding',
|
116
|
+
'fees',
|
117
|
+
'margin/profile_information',
|
118
|
+
'margin/buying_power',
|
119
|
+
'margin/withdrawal_power',
|
120
|
+
'margin/withdrawal_power_all',
|
121
|
+
'margin/exit_plan',
|
122
|
+
'margin/liquidation_history',
|
123
|
+
'margin/position_refresh_amounts',
|
124
|
+
'margin/status',
|
125
|
+
'oracle',
|
126
|
+
'orders',
|
127
|
+
'orders/{id}',
|
128
|
+
'orders/client:{client_oid}',
|
129
|
+
'otc/orders',
|
130
|
+
'payment-methods',
|
131
|
+
'position',
|
132
|
+
'profiles',
|
133
|
+
'profiles/{id}',
|
134
|
+
'reports/{report_id}',
|
135
|
+
'transfers',
|
136
|
+
'transfers/{transfer_id}',
|
137
|
+
'users/self/exchange-limits',
|
138
|
+
'users/self/hold-balances',
|
139
|
+
'users/self/trailing-volume',
|
140
|
+
'withdrawals/fee-estimate',
|
141
|
+
],
|
142
|
+
'post': [
|
143
|
+
'conversions',
|
144
|
+
'deposits/coinbase-account',
|
145
|
+
'deposits/payment-method',
|
146
|
+
'coinbase-accounts/{id}/addresses',
|
147
|
+
'funding/repay',
|
148
|
+
'orders',
|
149
|
+
'position/close',
|
150
|
+
'profiles/margin-transfer',
|
151
|
+
'profiles/transfer',
|
152
|
+
'reports',
|
153
|
+
'withdrawals/coinbase',
|
154
|
+
'withdrawals/coinbase-account',
|
155
|
+
'withdrawals/crypto',
|
156
|
+
'withdrawals/payment-method',
|
157
|
+
],
|
158
|
+
'delete': [
|
159
|
+
'orders',
|
160
|
+
'orders/client:{client_oid}',
|
161
|
+
'orders/{id}',
|
162
|
+
],
|
163
|
+
},
|
164
|
+
},
|
165
|
+
'commonCurrencies': {
|
166
|
+
'CGLD': 'CELO',
|
167
|
+
},
|
168
|
+
'precisionMode': TICK_SIZE,
|
169
|
+
'fees': {
|
170
|
+
'trading': {
|
171
|
+
'tierBased': true, // complicated tier system per coin
|
172
|
+
'percentage': true,
|
173
|
+
'maker': 0.4 / 100, // highest fee of all tiers
|
174
|
+
'taker': 0.6 / 100, // highest fee of all tiers
|
175
|
+
},
|
176
|
+
'funding': {
|
177
|
+
'tierBased': false,
|
178
|
+
'percentage': false,
|
179
|
+
'withdraw': {
|
180
|
+
'BCH': 0,
|
181
|
+
'BTC': 0,
|
182
|
+
'LTC': 0,
|
183
|
+
'ETH': 0,
|
184
|
+
'EUR': 0.15,
|
185
|
+
'USD': 25,
|
186
|
+
},
|
187
|
+
'deposit': {
|
188
|
+
'BCH': 0,
|
189
|
+
'BTC': 0,
|
190
|
+
'LTC': 0,
|
191
|
+
'ETH': 0,
|
192
|
+
'EUR': 0.15,
|
193
|
+
'USD': 10,
|
194
|
+
},
|
195
|
+
},
|
196
|
+
},
|
197
|
+
'exceptions': {
|
198
|
+
'exact': {
|
199
|
+
'Insufficient funds': InsufficientFunds,
|
200
|
+
'NotFound': OrderNotFound,
|
201
|
+
'Invalid API Key': AuthenticationError,
|
202
|
+
'invalid signature': AuthenticationError,
|
203
|
+
'Invalid Passphrase': AuthenticationError,
|
204
|
+
'Invalid order id': InvalidOrder,
|
205
|
+
'Private rate limit exceeded': RateLimitExceeded,
|
206
|
+
'Trading pair not available': PermissionDenied,
|
207
|
+
'Product not found': InvalidOrder,
|
208
|
+
},
|
209
|
+
'broad': {
|
210
|
+
'Order already done': OrderNotFound,
|
211
|
+
'order not found': OrderNotFound,
|
212
|
+
'price too small': InvalidOrder,
|
213
|
+
'price too precise': InvalidOrder,
|
214
|
+
'under maintenance': OnMaintenance,
|
215
|
+
'size is too small': InvalidOrder,
|
216
|
+
'Cancel only mode': OnMaintenance, // https://github.com/ccxt/ccxt/issues/7690
|
217
|
+
},
|
218
|
+
},
|
219
|
+
});
|
220
|
+
}
|
221
|
+
|
222
|
+
async fetchCurrencies (params = {}) {
|
223
|
+
const response = await this.publicGetCurrencies (params);
|
224
|
+
//
|
225
|
+
// [
|
226
|
+
// {
|
227
|
+
// id: 'XTZ',
|
228
|
+
// name: 'Tezos',
|
229
|
+
// min_size: '0.000001',
|
230
|
+
// status: 'online',
|
231
|
+
// message: '',
|
232
|
+
// max_precision: '0.000001',
|
233
|
+
// convertible_to: [],
|
234
|
+
// details: {
|
235
|
+
// type: 'crypto',
|
236
|
+
// symbol: 'Τ',
|
237
|
+
// network_confirmations: 60,
|
238
|
+
// sort_order: 53,
|
239
|
+
// crypto_address_link: 'https://tzstats.com/{{address}}',
|
240
|
+
// crypto_transaction_link: 'https://tzstats.com/{{txId}}',
|
241
|
+
// push_payment_methods: [ 'crypto' ],
|
242
|
+
// group_types: [],
|
243
|
+
// display_name: '',
|
244
|
+
// processing_time_seconds: 0,
|
245
|
+
// min_withdrawal_amount: 1
|
246
|
+
// }
|
247
|
+
// }
|
248
|
+
// ]
|
249
|
+
//
|
250
|
+
const result = {};
|
251
|
+
for (let i = 0; i < response.length; i++) {
|
252
|
+
const currency = response[i];
|
253
|
+
const id = this.safeString (currency, 'id');
|
254
|
+
const name = this.safeString (currency, 'name');
|
255
|
+
const code = this.safeCurrencyCode (id);
|
256
|
+
const details = this.safeValue (currency, 'details', {});
|
257
|
+
const precision = this.safeNumber (currency, 'max_precision');
|
258
|
+
const status = this.safeString (currency, 'status');
|
259
|
+
const active = (status === 'online');
|
260
|
+
result[code] = {
|
261
|
+
'id': id,
|
262
|
+
'code': code,
|
263
|
+
'info': currency,
|
264
|
+
'type': this.safeString (details, 'type'),
|
265
|
+
'name': name,
|
266
|
+
'active': active,
|
267
|
+
'deposit': undefined,
|
268
|
+
'withdraw': undefined,
|
269
|
+
'fee': undefined,
|
270
|
+
'precision': precision,
|
271
|
+
'limits': {
|
272
|
+
'amount': {
|
273
|
+
'min': this.safeNumber (details, 'min_size'),
|
274
|
+
'max': undefined,
|
275
|
+
},
|
276
|
+
'withdraw': {
|
277
|
+
'min': this.safeNumber (details, 'min_withdrawal_amount'),
|
278
|
+
'max': undefined,
|
279
|
+
},
|
280
|
+
},
|
281
|
+
};
|
282
|
+
}
|
283
|
+
return result;
|
284
|
+
}
|
285
|
+
|
286
|
+
async fetchMarkets (params = {}) {
|
287
|
+
const response = await this.publicGetProducts (params);
|
288
|
+
//
|
289
|
+
// [
|
290
|
+
// {
|
291
|
+
// "id": "ZEC-BTC",
|
292
|
+
// "base_currency": "ZEC",
|
293
|
+
// "quote_currency": "BTC",
|
294
|
+
// "base_min_size": "0.0056",
|
295
|
+
// "base_max_size": "3600",
|
296
|
+
// "quote_increment": "0.000001",
|
297
|
+
// "base_increment": "0.0001",
|
298
|
+
// "display_name": "ZEC/BTC",
|
299
|
+
// "min_market_funds": "0.000016",
|
300
|
+
// "max_market_funds": "12",
|
301
|
+
// "margin_enabled": false,
|
302
|
+
// "fx_stablecoin": false,
|
303
|
+
// "max_slippage_percentage": "0.03000000",
|
304
|
+
// "post_only": false,
|
305
|
+
// "limit_only": false,
|
306
|
+
// "cancel_only": false,
|
307
|
+
// "trading_disabled": false,
|
308
|
+
// "status": "online",
|
309
|
+
// "status_message": "",
|
310
|
+
// "auction_mode": false
|
311
|
+
// },
|
312
|
+
// ]
|
313
|
+
//
|
314
|
+
const result = [];
|
315
|
+
for (let i = 0; i < response.length; i++) {
|
316
|
+
const market = response[i];
|
317
|
+
const id = this.safeString (market, 'id');
|
318
|
+
const baseId = this.safeString (market, 'base_currency');
|
319
|
+
const quoteId = this.safeString (market, 'quote_currency');
|
320
|
+
const base = this.safeCurrencyCode (baseId);
|
321
|
+
const quote = this.safeCurrencyCode (quoteId);
|
322
|
+
const status = this.safeString (market, 'status');
|
323
|
+
result.push (this.extend (this.fees['trading'], {
|
324
|
+
'id': id,
|
325
|
+
'symbol': base + '/' + quote,
|
326
|
+
'base': base,
|
327
|
+
'quote': quote,
|
328
|
+
'settle': undefined,
|
329
|
+
'baseId': baseId,
|
330
|
+
'quoteId': quoteId,
|
331
|
+
'settleId': undefined,
|
332
|
+
'type': 'spot',
|
333
|
+
'spot': true,
|
334
|
+
'margin': this.safeValue (market, 'margin_enabled'),
|
335
|
+
'swap': false,
|
336
|
+
'future': false,
|
337
|
+
'option': false,
|
338
|
+
'active': (status === 'online'),
|
339
|
+
'contract': false,
|
340
|
+
'linear': undefined,
|
341
|
+
'inverse': undefined,
|
342
|
+
'contractSize': undefined,
|
343
|
+
'expiry': undefined,
|
344
|
+
'expiryDatetime': undefined,
|
345
|
+
'strike': undefined,
|
346
|
+
'optionType': undefined,
|
347
|
+
'precision': {
|
348
|
+
'amount': this.safeNumber (market, 'base_increment'),
|
349
|
+
'price': this.safeNumber (market, 'quote_increment'),
|
350
|
+
},
|
351
|
+
'limits': {
|
352
|
+
'leverage': {
|
353
|
+
'min': undefined,
|
354
|
+
'max': undefined,
|
355
|
+
},
|
356
|
+
'amount': {
|
357
|
+
'min': this.safeNumber (market, 'base_min_size'),
|
358
|
+
'max': this.safeNumber (market, 'base_max_size'),
|
359
|
+
},
|
360
|
+
'price': {
|
361
|
+
'min': undefined,
|
362
|
+
'max': undefined,
|
363
|
+
},
|
364
|
+
'cost': {
|
365
|
+
'min': this.safeNumber (market, 'min_market_funds'),
|
366
|
+
'max': this.safeNumber (market, 'max_market_funds'),
|
367
|
+
},
|
368
|
+
},
|
369
|
+
'info': market,
|
370
|
+
}));
|
371
|
+
}
|
372
|
+
return result;
|
373
|
+
}
|
374
|
+
|
375
|
+
async fetchAccounts (params = {}) {
|
376
|
+
await this.loadMarkets ();
|
377
|
+
const response = await this.privateGetAccounts (params);
|
378
|
+
//
|
379
|
+
// [
|
380
|
+
// {
|
381
|
+
// id: '4aac9c60-cbda-4396-9da4-4aa71e95fba0',
|
382
|
+
// currency: 'BTC',
|
383
|
+
// balance: '0.0000000000000000',
|
384
|
+
// available: '0',
|
385
|
+
// hold: '0.0000000000000000',
|
386
|
+
// profile_id: 'b709263e-f42a-4c7d-949a-a95c83d065da'
|
387
|
+
// },
|
388
|
+
// {
|
389
|
+
// id: 'f75fa69a-1ad1-4a80-bd61-ee7faa6135a3',
|
390
|
+
// currency: 'USDC',
|
391
|
+
// balance: '0.0000000000000000',
|
392
|
+
// available: '0',
|
393
|
+
// hold: '0.0000000000000000',
|
394
|
+
// profile_id: 'b709263e-f42a-4c7d-949a-a95c83d065da'
|
395
|
+
// },
|
396
|
+
// ]
|
397
|
+
//
|
398
|
+
const result = [];
|
399
|
+
for (let i = 0; i < response.length; i++) {
|
400
|
+
const account = response[i];
|
401
|
+
const accountId = this.safeString (account, 'id');
|
402
|
+
const currencyId = this.safeString (account, 'currency');
|
403
|
+
const code = this.safeCurrencyCode (currencyId);
|
404
|
+
result.push ({
|
405
|
+
'id': accountId,
|
406
|
+
'type': undefined,
|
407
|
+
'currency': code,
|
408
|
+
'info': account,
|
409
|
+
});
|
410
|
+
}
|
411
|
+
return result;
|
412
|
+
}
|
413
|
+
|
414
|
+
parseBalance (response) {
|
415
|
+
const result = { 'info': response };
|
416
|
+
for (let i = 0; i < response.length; i++) {
|
417
|
+
const balance = response[i];
|
418
|
+
const currencyId = this.safeString (balance, 'currency');
|
419
|
+
const code = this.safeCurrencyCode (currencyId);
|
420
|
+
const account = this.account ();
|
421
|
+
account['free'] = this.safeString (balance, 'available');
|
422
|
+
account['used'] = this.safeString (balance, 'hold');
|
423
|
+
account['total'] = this.safeString (balance, 'balance');
|
424
|
+
result[code] = account;
|
425
|
+
}
|
426
|
+
return this.safeBalance (result);
|
427
|
+
}
|
428
|
+
|
429
|
+
async fetchBalance (params = {}) {
|
430
|
+
await this.loadMarkets ();
|
431
|
+
const response = await this.privateGetAccounts (params);
|
432
|
+
return this.parseBalance (response);
|
433
|
+
}
|
434
|
+
|
435
|
+
async fetchOrderBook (symbol, limit = undefined, params = {}) {
|
436
|
+
await this.loadMarkets ();
|
437
|
+
// level 1 - only the best bid and ask
|
438
|
+
// level 2 - top 50 bids and asks (aggregated)
|
439
|
+
// level 3 - full order book (non aggregated)
|
440
|
+
const request = {
|
441
|
+
'id': this.marketId (symbol),
|
442
|
+
'level': 2, // 1 best bidask, 2 aggregated, 3 full
|
443
|
+
};
|
444
|
+
const response = await this.publicGetProductsIdBook (this.extend (request, params));
|
445
|
+
//
|
446
|
+
// {
|
447
|
+
// "sequence":1924393896,
|
448
|
+
// "bids":[
|
449
|
+
// ["0.01825","24.34811287",2],
|
450
|
+
// ["0.01824","72.5463",3],
|
451
|
+
// ["0.01823","424.54298049",6],
|
452
|
+
// ],
|
453
|
+
// "asks":[
|
454
|
+
// ["0.01826","171.10414904",4],
|
455
|
+
// ["0.01827","22.60427028",1],
|
456
|
+
// ["0.01828","397.46018784",7],
|
457
|
+
// ]
|
458
|
+
// }
|
459
|
+
//
|
460
|
+
const orderbook = this.parseOrderBook (response, symbol);
|
461
|
+
orderbook['nonce'] = this.safeInteger (response, 'sequence');
|
462
|
+
return orderbook;
|
463
|
+
}
|
464
|
+
|
465
|
+
parseTicker (ticker, market = undefined) {
|
466
|
+
//
|
467
|
+
// fetchTickers
|
468
|
+
//
|
469
|
+
// [
|
470
|
+
// 1639472400, // timestamp
|
471
|
+
// 4.26, // low
|
472
|
+
// 4.38, // high
|
473
|
+
// 4.35, // open
|
474
|
+
// 4.27 // close
|
475
|
+
// ]
|
476
|
+
//
|
477
|
+
// fetchTicker
|
478
|
+
//
|
479
|
+
// publicGetProductsIdTicker
|
480
|
+
//
|
481
|
+
// {
|
482
|
+
// "trade_id":843439,
|
483
|
+
// "price":"0.997999",
|
484
|
+
// "size":"80.29769",
|
485
|
+
// "time":"2020-01-28T02:13:33.012523Z",
|
486
|
+
// "bid":"0.997094",
|
487
|
+
// "ask":"0.998",
|
488
|
+
// "volume":"1903188.03750000"
|
489
|
+
// }
|
490
|
+
//
|
491
|
+
// publicGetProductsIdStats
|
492
|
+
//
|
493
|
+
// {
|
494
|
+
// "open": "34.19000000",
|
495
|
+
// "high": "95.70000000",
|
496
|
+
// "low": "7.06000000",
|
497
|
+
// "volume": "2.41000000"
|
498
|
+
// }
|
499
|
+
//
|
500
|
+
let timestamp = undefined;
|
501
|
+
let bid = undefined;
|
502
|
+
let ask = undefined;
|
503
|
+
let last = undefined;
|
504
|
+
let high = undefined;
|
505
|
+
let low = undefined;
|
506
|
+
let open = undefined;
|
507
|
+
let volume = undefined;
|
508
|
+
const symbol = (market === undefined) ? undefined : market['symbol'];
|
509
|
+
if (Array.isArray (ticker)) {
|
510
|
+
last = this.safeString (ticker, 4);
|
511
|
+
timestamp = this.milliseconds ();
|
512
|
+
} else {
|
513
|
+
timestamp = this.parse8601 (this.safeValue (ticker, 'time'));
|
514
|
+
bid = this.safeString (ticker, 'bid');
|
515
|
+
ask = this.safeString (ticker, 'ask');
|
516
|
+
high = this.safeString (ticker, 'high');
|
517
|
+
low = this.safeString (ticker, 'low');
|
518
|
+
open = this.safeString (ticker, 'open');
|
519
|
+
last = this.safeString2 (ticker, 'price', 'last');
|
520
|
+
volume = this.safeString (ticker, 'volume');
|
521
|
+
}
|
522
|
+
return this.safeTicker ({
|
523
|
+
'symbol': symbol,
|
524
|
+
'timestamp': timestamp,
|
525
|
+
'datetime': this.iso8601 (timestamp),
|
526
|
+
'high': high,
|
527
|
+
'low': low,
|
528
|
+
'bid': bid,
|
529
|
+
'bidVolume': undefined,
|
530
|
+
'ask': ask,
|
531
|
+
'askVolume': undefined,
|
532
|
+
'vwap': undefined,
|
533
|
+
'open': open,
|
534
|
+
'close': last,
|
535
|
+
'last': last,
|
536
|
+
'previousClose': undefined,
|
537
|
+
'change': undefined,
|
538
|
+
'percentage': undefined,
|
539
|
+
'average': undefined,
|
540
|
+
'baseVolume': volume,
|
541
|
+
'quoteVolume': undefined,
|
542
|
+
'info': ticker,
|
543
|
+
}, market, false);
|
544
|
+
}
|
545
|
+
|
546
|
+
async fetchTickers (symbols = undefined, params = {}) {
|
547
|
+
await this.loadMarkets ();
|
548
|
+
const request = {};
|
549
|
+
const response = await this.publicGetProductsSparkLines (this.extend (request, params));
|
550
|
+
//
|
551
|
+
// {
|
552
|
+
// YYY-USD: [
|
553
|
+
// [
|
554
|
+
// 1639472400, // timestamp
|
555
|
+
// 4.26, // low
|
556
|
+
// 4.38, // high
|
557
|
+
// 4.35, // open
|
558
|
+
// 4.27 // close
|
559
|
+
// ],
|
560
|
+
// [
|
561
|
+
// 1639468800,
|
562
|
+
// 4.31,
|
563
|
+
// 4.45,
|
564
|
+
// 4.35,
|
565
|
+
// 4.35
|
566
|
+
// ],
|
567
|
+
// ]
|
568
|
+
// }
|
569
|
+
//
|
570
|
+
const result = {};
|
571
|
+
const marketIds = Object.keys (response);
|
572
|
+
const delimiter = '-';
|
573
|
+
for (let i = 0; i < marketIds.length; i++) {
|
574
|
+
const marketId = marketIds[i];
|
575
|
+
const entry = this.safeValue (response, marketId, []);
|
576
|
+
const first = this.safeValue (entry, 0, []);
|
577
|
+
const market = this.safeMarket (marketId, undefined, delimiter);
|
578
|
+
const symbol = market['symbol'];
|
579
|
+
result[symbol] = this.parseTicker (first, market);
|
580
|
+
}
|
581
|
+
return this.filterByArray (result, 'symbol', symbols);
|
582
|
+
}
|
583
|
+
|
584
|
+
async fetchTicker (symbol, params = {}) {
|
585
|
+
await this.loadMarkets ();
|
586
|
+
const market = this.market (symbol);
|
587
|
+
const request = {
|
588
|
+
'id': market['id'],
|
589
|
+
};
|
590
|
+
// publicGetProductsIdTicker or publicGetProductsIdStats
|
591
|
+
const method = this.safeString (this.options, 'fetchTickerMethod', 'publicGetProductsIdTicker');
|
592
|
+
const response = await this[method] (this.extend (request, params));
|
593
|
+
//
|
594
|
+
// publicGetProductsIdTicker
|
595
|
+
//
|
596
|
+
// {
|
597
|
+
// "trade_id":843439,
|
598
|
+
// "price":"0.997999",
|
599
|
+
// "size":"80.29769",
|
600
|
+
// "time":"2020-01-28T02:13:33.012523Z",
|
601
|
+
// "bid":"0.997094",
|
602
|
+
// "ask":"0.998",
|
603
|
+
// "volume":"1903188.03750000"
|
604
|
+
// }
|
605
|
+
//
|
606
|
+
// publicGetProductsIdStats
|
607
|
+
//
|
608
|
+
// {
|
609
|
+
// "open": "34.19000000",
|
610
|
+
// "high": "95.70000000",
|
611
|
+
// "low": "7.06000000",
|
612
|
+
// "volume": "2.41000000"
|
613
|
+
// }
|
614
|
+
//
|
615
|
+
return this.parseTicker (response, market);
|
616
|
+
}
|
617
|
+
|
618
|
+
parseTrade (trade, market = undefined) {
|
619
|
+
//
|
620
|
+
// {
|
621
|
+
// type: 'match',
|
622
|
+
// trade_id: 82047307,
|
623
|
+
// maker_order_id: '0f358725-2134-435e-be11-753912a326e0',
|
624
|
+
// taker_order_id: '252b7002-87a3-425c-ac73-f5b9e23f3caf',
|
625
|
+
// order_id: 'd50ec984-77a8-460a-b958-66f114b0de9b',
|
626
|
+
// side: 'sell',
|
627
|
+
// size: '0.00513192',
|
628
|
+
// price: '9314.78',
|
629
|
+
// product_id: 'BTC-USD',
|
630
|
+
// profile_id: '6244401d-c078-40d9-b305-7ad3551bc3b0',
|
631
|
+
// sequence: 12038915443,
|
632
|
+
// time: '2020-01-31T20:03:41.158814Z'
|
633
|
+
// created_at: '2014-11-07T22:19:28.578544Z',
|
634
|
+
// liquidity: 'T',
|
635
|
+
// fee: '0.00025',
|
636
|
+
// settled: true,
|
637
|
+
// usd_volume: '0.0924556000000000',
|
638
|
+
// user_id: '595eb864313c2b02ddf2937d'
|
639
|
+
// }
|
640
|
+
//
|
641
|
+
const timestamp = this.parse8601 (this.safeString2 (trade, 'time', 'created_at'));
|
642
|
+
const marketId = this.safeString (trade, 'product_id');
|
643
|
+
market = this.safeMarket (marketId, market, '-');
|
644
|
+
let feeRate = undefined;
|
645
|
+
let takerOrMaker = undefined;
|
646
|
+
let cost = undefined;
|
647
|
+
const feeCurrencyId = this.safeStringLower (market, 'quoteId');
|
648
|
+
if (feeCurrencyId !== undefined) {
|
649
|
+
const costField = feeCurrencyId + '_value';
|
650
|
+
cost = this.safeString (trade, costField);
|
651
|
+
const liquidity = this.safeString (trade, 'liquidity');
|
652
|
+
if (liquidity !== undefined) {
|
653
|
+
takerOrMaker = (liquidity === 'T') ? 'taker' : 'maker';
|
654
|
+
feeRate = this.safeString (market, takerOrMaker);
|
655
|
+
}
|
656
|
+
}
|
657
|
+
const feeCost = this.safeString2 (trade, 'fill_fees', 'fee');
|
658
|
+
const fee = {
|
659
|
+
'cost': feeCost,
|
660
|
+
'currency': market['quote'],
|
661
|
+
'rate': feeRate,
|
662
|
+
};
|
663
|
+
const id = this.safeString (trade, 'trade_id');
|
664
|
+
let side = (trade['side'] === 'buy') ? 'sell' : 'buy';
|
665
|
+
const orderId = this.safeString (trade, 'order_id');
|
666
|
+
// Coinbase Pro returns inverted side to fetchMyTrades vs fetchTrades
|
667
|
+
const makerOrderId = this.safeString (trade, 'maker_order_id');
|
668
|
+
const takerOrderId = this.safeString (trade, 'taker_order_id');
|
669
|
+
if ((orderId !== undefined) || ((makerOrderId !== undefined) && (takerOrderId !== undefined))) {
|
670
|
+
side = (trade['side'] === 'buy') ? 'buy' : 'sell';
|
671
|
+
}
|
672
|
+
const price = this.safeString (trade, 'price');
|
673
|
+
const amount = this.safeString (trade, 'size');
|
674
|
+
return this.safeTrade ({
|
675
|
+
'id': id,
|
676
|
+
'order': orderId,
|
677
|
+
'info': trade,
|
678
|
+
'timestamp': timestamp,
|
679
|
+
'datetime': this.iso8601 (timestamp),
|
680
|
+
'symbol': market['symbol'],
|
681
|
+
'type': undefined,
|
682
|
+
'takerOrMaker': takerOrMaker,
|
683
|
+
'side': side,
|
684
|
+
'price': price,
|
685
|
+
'amount': amount,
|
686
|
+
'fee': fee,
|
687
|
+
'cost': cost,
|
688
|
+
}, market);
|
689
|
+
}
|
690
|
+
|
691
|
+
async fetchMyTrades (symbol = undefined, since = undefined, limit = undefined, params = {}) {
|
692
|
+
// as of 2018-08-23
|
693
|
+
if (symbol === undefined) {
|
694
|
+
throw new ArgumentsRequired (this.id + ' fetchMyTrades() requires a symbol argument');
|
695
|
+
}
|
696
|
+
await this.loadMarkets ();
|
697
|
+
const market = this.market (symbol);
|
698
|
+
const request = {
|
699
|
+
'product_id': market['id'],
|
700
|
+
};
|
701
|
+
if (limit !== undefined) {
|
702
|
+
request['limit'] = limit;
|
703
|
+
}
|
704
|
+
const response = await this.privateGetFills (this.extend (request, params));
|
705
|
+
return this.parseTrades (response, market, since, limit);
|
706
|
+
}
|
707
|
+
|
708
|
+
async fetchTrades (symbol, since = undefined, limit = undefined, params = {}) {
|
709
|
+
await this.loadMarkets ();
|
710
|
+
const market = this.market (symbol);
|
711
|
+
const request = {
|
712
|
+
'id': market['id'], // fixes issue #2
|
713
|
+
};
|
714
|
+
if (limit !== undefined) {
|
715
|
+
request['limit'] = limit; // default 100
|
716
|
+
}
|
717
|
+
const response = await this.publicGetProductsIdTrades (this.extend (request, params));
|
718
|
+
return this.parseTrades (response, market, since, limit);
|
719
|
+
}
|
720
|
+
|
721
|
+
async fetchTradingFees (params = {}) {
|
722
|
+
await this.loadMarkets ();
|
723
|
+
const response = await this.privateGetFees (params);
|
724
|
+
//
|
725
|
+
// {
|
726
|
+
// "maker_fee_rate": "0.0050",
|
727
|
+
// "taker_fee_rate": "0.0050",
|
728
|
+
// "usd_volume": "43806.92"
|
729
|
+
// }
|
730
|
+
//
|
731
|
+
const maker = this.safeNumber (response, 'maker_fee_rate');
|
732
|
+
const taker = this.safeNumber (response, 'taker_fee_rate');
|
733
|
+
const result = {};
|
734
|
+
for (let i = 0; i < this.symbols.length; i++) {
|
735
|
+
const symbol = this.symbols[i];
|
736
|
+
result[symbol] = {
|
737
|
+
'info': response,
|
738
|
+
'symbol': symbol,
|
739
|
+
'maker': maker,
|
740
|
+
'taker': taker,
|
741
|
+
'percentage': true,
|
742
|
+
'tierBased': true,
|
743
|
+
};
|
744
|
+
}
|
745
|
+
return result;
|
746
|
+
}
|
747
|
+
|
748
|
+
parseOHLCV (ohlcv, market = undefined) {
|
749
|
+
//
|
750
|
+
// [
|
751
|
+
// 1591514160,
|
752
|
+
// 0.02507,
|
753
|
+
// 0.02507,
|
754
|
+
// 0.02507,
|
755
|
+
// 0.02507,
|
756
|
+
// 0.02816506
|
757
|
+
// ]
|
758
|
+
//
|
759
|
+
return [
|
760
|
+
this.safeTimestamp (ohlcv, 0),
|
761
|
+
this.safeNumber (ohlcv, 3),
|
762
|
+
this.safeNumber (ohlcv, 2),
|
763
|
+
this.safeNumber (ohlcv, 1),
|
764
|
+
this.safeNumber (ohlcv, 4),
|
765
|
+
this.safeNumber (ohlcv, 5),
|
766
|
+
];
|
767
|
+
}
|
768
|
+
|
769
|
+
async fetchOHLCV (symbol, timeframe = '1m', since = undefined, limit = undefined, params = {}) {
|
770
|
+
await this.loadMarkets ();
|
771
|
+
const market = this.market (symbol);
|
772
|
+
const granularity = this.timeframes[timeframe];
|
773
|
+
const request = {
|
774
|
+
'id': market['id'],
|
775
|
+
'granularity': granularity,
|
776
|
+
};
|
777
|
+
if (since !== undefined) {
|
778
|
+
request['start'] = this.iso8601 (since);
|
779
|
+
if (limit === undefined) {
|
780
|
+
// https://docs.pro.coinbase.com/#get-historic-rates
|
781
|
+
limit = 300; // max = 300
|
782
|
+
} else {
|
783
|
+
limit = Math.min (300, limit);
|
784
|
+
}
|
785
|
+
request['end'] = this.iso8601 (this.sum ((limit - 1) * granularity * 1000, since));
|
786
|
+
}
|
787
|
+
const response = await this.publicGetProductsIdCandles (this.extend (request, params));
|
788
|
+
//
|
789
|
+
// [
|
790
|
+
// [1591514160,0.02507,0.02507,0.02507,0.02507,0.02816506],
|
791
|
+
// [1591514100,0.02507,0.02507,0.02507,0.02507,1.63830323],
|
792
|
+
// [1591514040,0.02505,0.02507,0.02505,0.02507,0.19918178]
|
793
|
+
// ]
|
794
|
+
//
|
795
|
+
return this.parseOHLCVs (response, market, timeframe, since, limit);
|
796
|
+
}
|
797
|
+
|
798
|
+
async fetchTime (params = {}) {
|
799
|
+
const response = await this.publicGetTime (params);
|
800
|
+
//
|
801
|
+
// {
|
802
|
+
// "iso":"2020-05-12T08:00:51.504Z",
|
803
|
+
// "epoch":1589270451.504
|
804
|
+
// }
|
805
|
+
//
|
806
|
+
return this.safeTimestamp (response, 'epoch');
|
807
|
+
}
|
808
|
+
|
809
|
+
parseOrderStatus (status) {
|
810
|
+
const statuses = {
|
811
|
+
'pending': 'open',
|
812
|
+
'active': 'open',
|
813
|
+
'open': 'open',
|
814
|
+
'done': 'closed',
|
815
|
+
'canceled': 'canceled',
|
816
|
+
'canceling': 'open',
|
817
|
+
};
|
818
|
+
return this.safeString (statuses, status, status);
|
819
|
+
}
|
820
|
+
|
821
|
+
parseOrder (order, market = undefined) {
|
822
|
+
//
|
823
|
+
// createOrder
|
824
|
+
//
|
825
|
+
// {
|
826
|
+
// "id": "d0c5340b-6d6c-49d9-b567-48c4bfca13d2",
|
827
|
+
// "price": "0.10000000",
|
828
|
+
// "size": "0.01000000",
|
829
|
+
// "product_id": "BTC-USD",
|
830
|
+
// "side": "buy",
|
831
|
+
// "stp": "dc",
|
832
|
+
// "type": "limit",
|
833
|
+
// "time_in_force": "GTC",
|
834
|
+
// "post_only": false,
|
835
|
+
// "created_at": "2016-12-08T20:02:28.53864Z",
|
836
|
+
// "fill_fees": "0.0000000000000000",
|
837
|
+
// "filled_size": "0.00000000",
|
838
|
+
// "executed_value": "0.0000000000000000",
|
839
|
+
// "status": "pending",
|
840
|
+
// "settled": false
|
841
|
+
// }
|
842
|
+
//
|
843
|
+
const timestamp = this.parse8601 (this.safeString (order, 'created_at'));
|
844
|
+
const marketId = this.safeString (order, 'product_id');
|
845
|
+
market = this.safeMarket (marketId, market, '-');
|
846
|
+
let status = this.parseOrderStatus (this.safeString (order, 'status'));
|
847
|
+
const doneReason = this.safeString (order, 'done_reason');
|
848
|
+
if ((status === 'closed') && (doneReason === 'canceled')) {
|
849
|
+
status = 'canceled';
|
850
|
+
}
|
851
|
+
const price = this.safeString (order, 'price');
|
852
|
+
const filled = this.safeString (order, 'filled_size');
|
853
|
+
const amount = this.safeString (order, 'size', filled);
|
854
|
+
const cost = this.safeString (order, 'executed_value');
|
855
|
+
const feeCost = this.safeNumber (order, 'fill_fees');
|
856
|
+
let fee = undefined;
|
857
|
+
if (feeCost !== undefined) {
|
858
|
+
fee = {
|
859
|
+
'cost': feeCost,
|
860
|
+
'currency': market['quote'],
|
861
|
+
'rate': undefined,
|
862
|
+
};
|
863
|
+
}
|
864
|
+
const id = this.safeString (order, 'id');
|
865
|
+
const type = this.safeString (order, 'type');
|
866
|
+
const side = this.safeString (order, 'side');
|
867
|
+
const timeInForce = this.safeString (order, 'time_in_force');
|
868
|
+
const postOnly = this.safeValue (order, 'post_only');
|
869
|
+
const stopPrice = this.safeNumber (order, 'stop_price');
|
870
|
+
const clientOrderId = this.safeString (order, 'client_oid');
|
871
|
+
return this.safeOrder ({
|
872
|
+
'id': id,
|
873
|
+
'clientOrderId': clientOrderId,
|
874
|
+
'info': order,
|
875
|
+
'timestamp': timestamp,
|
876
|
+
'datetime': this.iso8601 (timestamp),
|
877
|
+
'lastTradeTimestamp': undefined,
|
878
|
+
'status': status,
|
879
|
+
'symbol': market['symbol'],
|
880
|
+
'type': type,
|
881
|
+
'timeInForce': timeInForce,
|
882
|
+
'postOnly': postOnly,
|
883
|
+
'side': side,
|
884
|
+
'price': price,
|
885
|
+
'stopPrice': stopPrice,
|
886
|
+
'cost': cost,
|
887
|
+
'amount': amount,
|
888
|
+
'filled': filled,
|
889
|
+
'remaining': undefined,
|
890
|
+
'fee': fee,
|
891
|
+
'average': undefined,
|
892
|
+
'trades': undefined,
|
893
|
+
}, market);
|
894
|
+
}
|
895
|
+
|
896
|
+
async fetchOrder (id, symbol = undefined, params = {}) {
|
897
|
+
await this.loadMarkets ();
|
898
|
+
const request = {};
|
899
|
+
const clientOrderId = this.safeString2 (params, 'clientOrderId', 'client_oid');
|
900
|
+
let method = undefined;
|
901
|
+
if (clientOrderId === undefined) {
|
902
|
+
method = 'privateGetOrdersId';
|
903
|
+
request['id'] = id;
|
904
|
+
} else {
|
905
|
+
method = 'privateGetOrdersClientClientOid';
|
906
|
+
request['client_oid'] = clientOrderId;
|
907
|
+
params = this.omit (params, [ 'clientOrderId', 'client_oid' ]);
|
908
|
+
}
|
909
|
+
const response = await this[method] (this.extend (request, params));
|
910
|
+
return this.parseOrder (response);
|
911
|
+
}
|
912
|
+
|
913
|
+
async fetchOrderTrades (id, symbol = undefined, since = undefined, limit = undefined, params = {}) {
|
914
|
+
await this.loadMarkets ();
|
915
|
+
let market = undefined;
|
916
|
+
if (symbol !== undefined) {
|
917
|
+
market = this.market (symbol);
|
918
|
+
}
|
919
|
+
const request = {
|
920
|
+
'order_id': id,
|
921
|
+
};
|
922
|
+
const response = await this.privateGetFills (this.extend (request, params));
|
923
|
+
return this.parseTrades (response, market, since, limit);
|
924
|
+
}
|
925
|
+
|
926
|
+
async fetchOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) {
|
927
|
+
const request = {
|
928
|
+
'status': 'all',
|
929
|
+
};
|
930
|
+
return await this.fetchOpenOrders (symbol, since, limit, this.extend (request, params));
|
931
|
+
}
|
932
|
+
|
933
|
+
async fetchOpenOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) {
|
934
|
+
await this.loadMarkets ();
|
935
|
+
const request = {};
|
936
|
+
let market = undefined;
|
937
|
+
if (symbol !== undefined) {
|
938
|
+
market = this.market (symbol);
|
939
|
+
request['product_id'] = market['id'];
|
940
|
+
}
|
941
|
+
if (limit !== undefined) {
|
942
|
+
request['limit'] = limit; // default 100
|
943
|
+
}
|
944
|
+
const response = await this.privateGetOrders (this.extend (request, params));
|
945
|
+
return this.parseOrders (response, market, since, limit);
|
946
|
+
}
|
947
|
+
|
948
|
+
async fetchClosedOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) {
|
949
|
+
const request = {
|
950
|
+
'status': 'done',
|
951
|
+
};
|
952
|
+
return await this.fetchOpenOrders (symbol, since, limit, this.extend (request, params));
|
953
|
+
}
|
954
|
+
|
955
|
+
async createOrder (symbol, type, side, amount, price = undefined, params = {}) {
|
956
|
+
await this.loadMarkets ();
|
957
|
+
const market = this.market (symbol);
|
958
|
+
const request = {
|
959
|
+
// common params --------------------------------------------------
|
960
|
+
// 'client_oid': clientOrderId,
|
961
|
+
'type': type,
|
962
|
+
'side': side,
|
963
|
+
'product_id': market['id'],
|
964
|
+
// 'size': this.amountToPrecision (symbol, amount),
|
965
|
+
// 'stp': 'dc', // self-trade prevention, dc = decrease and cancel, co = cancel oldest, cn = cancel newest, cb = cancel both
|
966
|
+
// 'stop': 'loss', // "loss" = stop loss below price, "entry" = take profit above price
|
967
|
+
// 'stop_price': this.priceToPrecision (symbol, price),
|
968
|
+
// limit order params ---------------------------------------------
|
969
|
+
// 'price': this.priceToPrecision (symbol, price),
|
970
|
+
// 'size': this.amountToPrecision (symbol, amount),
|
971
|
+
// 'time_in_force': 'GTC', // GTC, GTT, IOC, or FOK
|
972
|
+
// 'cancel_after' [optional]* min, hour, day, requires time_in_force to be GTT
|
973
|
+
// 'post_only': false, // invalid when time_in_force is IOC or FOK
|
974
|
+
// market order params --------------------------------------------
|
975
|
+
// 'size': this.amountToPrecision (symbol, amount),
|
976
|
+
// 'funds': this.costToPrecision (symbol, amount),
|
977
|
+
};
|
978
|
+
const clientOrderId = this.safeString2 (params, 'clientOrderId', 'client_oid');
|
979
|
+
if (clientOrderId !== undefined) {
|
980
|
+
request['client_oid'] = clientOrderId;
|
981
|
+
}
|
982
|
+
const stopPrice = this.safeNumber2 (params, 'stopPrice', 'stop_price');
|
983
|
+
if (stopPrice !== undefined) {
|
984
|
+
request['stop_price'] = this.priceToPrecision (symbol, stopPrice);
|
985
|
+
}
|
986
|
+
const timeInForce = this.safeString2 (params, 'timeInForce', 'time_in_force');
|
987
|
+
if (timeInForce !== undefined) {
|
988
|
+
request['time_in_force'] = timeInForce;
|
989
|
+
}
|
990
|
+
const postOnly = this.safeValue2 (params, 'postOnly', 'post_only', false);
|
991
|
+
if (postOnly) {
|
992
|
+
request['post_only'] = true;
|
993
|
+
}
|
994
|
+
params = this.omit (params, [ 'timeInForce', 'time_in_force', 'stopPrice', 'stop_price', 'clientOrderId', 'client_oid', 'postOnly', 'post_only' ]);
|
995
|
+
if (type === 'limit') {
|
996
|
+
request['price'] = this.priceToPrecision (symbol, price);
|
997
|
+
request['size'] = this.amountToPrecision (symbol, amount);
|
998
|
+
} else if (type === 'market') {
|
999
|
+
let cost = this.safeNumber2 (params, 'cost', 'funds');
|
1000
|
+
if (cost === undefined) {
|
1001
|
+
if (price !== undefined) {
|
1002
|
+
cost = amount * price;
|
1003
|
+
}
|
1004
|
+
} else {
|
1005
|
+
params = this.omit (params, [ 'cost', 'funds' ]);
|
1006
|
+
}
|
1007
|
+
if (cost !== undefined) {
|
1008
|
+
request['funds'] = this.costToPrecision (symbol, cost);
|
1009
|
+
} else {
|
1010
|
+
request['size'] = this.amountToPrecision (symbol, amount);
|
1011
|
+
}
|
1012
|
+
}
|
1013
|
+
const response = await this.privatePostOrders (this.extend (request, params));
|
1014
|
+
//
|
1015
|
+
// {
|
1016
|
+
// "id": "d0c5340b-6d6c-49d9-b567-48c4bfca13d2",
|
1017
|
+
// "price": "0.10000000",
|
1018
|
+
// "size": "0.01000000",
|
1019
|
+
// "product_id": "BTC-USD",
|
1020
|
+
// "side": "buy",
|
1021
|
+
// "stp": "dc",
|
1022
|
+
// "type": "limit",
|
1023
|
+
// "time_in_force": "GTC",
|
1024
|
+
// "post_only": false,
|
1025
|
+
// "created_at": "2016-12-08T20:02:28.53864Z",
|
1026
|
+
// "fill_fees": "0.0000000000000000",
|
1027
|
+
// "filled_size": "0.00000000",
|
1028
|
+
// "executed_value": "0.0000000000000000",
|
1029
|
+
// "status": "pending",
|
1030
|
+
// "settled": false
|
1031
|
+
// }
|
1032
|
+
//
|
1033
|
+
return this.parseOrder (response, market);
|
1034
|
+
}
|
1035
|
+
|
1036
|
+
async cancelOrder (id, symbol = undefined, params = {}) {
|
1037
|
+
await this.loadMarkets ();
|
1038
|
+
const request = {
|
1039
|
+
// 'product_id': market['id'], // the request will be more performant if you include it
|
1040
|
+
};
|
1041
|
+
const clientOrderId = this.safeString2 (params, 'clientOrderId', 'client_oid');
|
1042
|
+
let method = undefined;
|
1043
|
+
if (clientOrderId === undefined) {
|
1044
|
+
method = 'privateDeleteOrdersId';
|
1045
|
+
request['id'] = id;
|
1046
|
+
} else {
|
1047
|
+
method = 'privateDeleteOrdersClientClientOid';
|
1048
|
+
request['client_oid'] = clientOrderId;
|
1049
|
+
params = this.omit (params, [ 'clientOrderId', 'client_oid' ]);
|
1050
|
+
}
|
1051
|
+
let market = undefined;
|
1052
|
+
if (symbol !== undefined) {
|
1053
|
+
market = this.market (symbol);
|
1054
|
+
request['product_id'] = market['symbol']; // the request will be more performant if you include it
|
1055
|
+
}
|
1056
|
+
return await this[method] (this.extend (request, params));
|
1057
|
+
}
|
1058
|
+
|
1059
|
+
async cancelAllOrders (symbol = undefined, params = {}) {
|
1060
|
+
await this.loadMarkets ();
|
1061
|
+
const request = {};
|
1062
|
+
let market = undefined;
|
1063
|
+
if (symbol !== undefined) {
|
1064
|
+
market = this.market (symbol);
|
1065
|
+
request['product_id'] = market['symbol']; // the request will be more performant if you include it
|
1066
|
+
}
|
1067
|
+
return await this.privateDeleteOrders (this.extend (request, params));
|
1068
|
+
}
|
1069
|
+
|
1070
|
+
async fetchPaymentMethods (params = {}) {
|
1071
|
+
return await this.privateGetPaymentMethods (params);
|
1072
|
+
}
|
1073
|
+
|
1074
|
+
async deposit (code, amount, address, params = {}) {
|
1075
|
+
/**
|
1076
|
+
* @method
|
1077
|
+
* @name coinbasepro#deposit
|
1078
|
+
* @description Creates a new deposit address, as required by coinbasepro
|
1079
|
+
* @param {str} code Unified CCXT currency code (e.g. `"USDT"`)
|
1080
|
+
* @param {float} amount The amount of currency to send in the deposit (e.g. `20`)
|
1081
|
+
* @param {str} address Not used by coinbasepro
|
1082
|
+
* @param {dict} params Parameters specific to the exchange API endpoint (e.g. `{"network": "TRX"}`)
|
1083
|
+
* @returns a [transaction structure]{@link https://docs.ccxt.com/en/latest/manual.html#transaction-structure}
|
1084
|
+
*/
|
1085
|
+
await this.loadMarkets ();
|
1086
|
+
const currency = this.currency (code);
|
1087
|
+
const request = {
|
1088
|
+
'currency': currency['id'],
|
1089
|
+
'amount': amount,
|
1090
|
+
};
|
1091
|
+
let method = 'privatePostDeposits';
|
1092
|
+
if ('payment_method_id' in params) {
|
1093
|
+
// deposit from a payment_method, like a bank account
|
1094
|
+
method += 'PaymentMethod';
|
1095
|
+
} else if ('coinbase_account_id' in params) {
|
1096
|
+
// deposit into Coinbase Pro account from a Coinbase account
|
1097
|
+
method += 'CoinbaseAccount';
|
1098
|
+
} else {
|
1099
|
+
// deposit methodotherwise we did not receive a supported deposit location
|
1100
|
+
// relevant docs link for the Googlers
|
1101
|
+
// https://docs.pro.coinbase.com/#deposits
|
1102
|
+
throw new NotSupported (this.id + ' deposit() requires one of `coinbase_account_id` or `payment_method_id` extra params');
|
1103
|
+
}
|
1104
|
+
const response = await this[method] (this.extend (request, params));
|
1105
|
+
if (!response) {
|
1106
|
+
throw new ExchangeError (this.id + ' deposit() error: ' + this.json (response));
|
1107
|
+
}
|
1108
|
+
return {
|
1109
|
+
'info': response,
|
1110
|
+
'id': response['id'],
|
1111
|
+
};
|
1112
|
+
}
|
1113
|
+
|
1114
|
+
async withdraw (code, amount, address, tag = undefined, params = {}) {
|
1115
|
+
[ tag, params ] = this.handleWithdrawTagAndParams (tag, params);
|
1116
|
+
this.checkAddress (address);
|
1117
|
+
await this.loadMarkets ();
|
1118
|
+
const currency = this.currency (code);
|
1119
|
+
const request = {
|
1120
|
+
'currency': currency['id'],
|
1121
|
+
'amount': amount,
|
1122
|
+
};
|
1123
|
+
let method = 'privatePostWithdrawals';
|
1124
|
+
if ('payment_method_id' in params) {
|
1125
|
+
method += 'PaymentMethod';
|
1126
|
+
} else if ('coinbase_account_id' in params) {
|
1127
|
+
method += 'CoinbaseAccount';
|
1128
|
+
} else {
|
1129
|
+
method += 'Crypto';
|
1130
|
+
request['crypto_address'] = address;
|
1131
|
+
if (tag !== undefined) {
|
1132
|
+
request['destination_tag'] = tag;
|
1133
|
+
}
|
1134
|
+
}
|
1135
|
+
const response = await this[method] (this.extend (request, params));
|
1136
|
+
if (!response) {
|
1137
|
+
throw new ExchangeError (this.id + ' withdraw() error: ' + this.json (response));
|
1138
|
+
}
|
1139
|
+
return this.parseTransaction (response, currency);
|
1140
|
+
}
|
1141
|
+
|
1142
|
+
parseLedgerEntryType (type) {
|
1143
|
+
const types = {
|
1144
|
+
'transfer': 'transfer', // Funds moved between portfolios
|
1145
|
+
'match': 'trade', // Funds moved as a result of a trade
|
1146
|
+
'fee': 'fee', // Fee as a result of a trade
|
1147
|
+
'rebate': 'rebate', // Fee rebate
|
1148
|
+
'conversion': 'trade', // Funds converted between fiat currency and a stablecoin
|
1149
|
+
};
|
1150
|
+
return this.safeString (types, type, type);
|
1151
|
+
}
|
1152
|
+
|
1153
|
+
parseLedgerEntry (item, currency = undefined) {
|
1154
|
+
// {
|
1155
|
+
// id: '12087495079',
|
1156
|
+
// amount: '-0.0100000000000000',
|
1157
|
+
// balance: '0.0645419900000000',
|
1158
|
+
// created_at: '2021-10-28T17:14:32.593168Z',
|
1159
|
+
// type: 'transfer',
|
1160
|
+
// details: {
|
1161
|
+
// from: '2f74edf7-1440-4586-86dc-ae58c5693691',
|
1162
|
+
// profile_transfer_id: '3ef093ad-2482-40d1-8ede-2f89cff5099e',
|
1163
|
+
// to: 'dda99503-4980-4b60-9549-0b770ee51336'
|
1164
|
+
// }
|
1165
|
+
// },
|
1166
|
+
// {
|
1167
|
+
// id: '11740725774',
|
1168
|
+
// amount: '-1.7565669701255000',
|
1169
|
+
// balance: '0.0016490047745000',
|
1170
|
+
// created_at: '2021-10-22T03:47:34.764122Z',
|
1171
|
+
// type: 'fee',
|
1172
|
+
// details: {
|
1173
|
+
// order_id: 'ad06abf4-95ab-432a-a1d8-059ef572e296',
|
1174
|
+
// product_id: 'ETH-DAI',
|
1175
|
+
// trade_id: '1740617'
|
1176
|
+
// }
|
1177
|
+
// }
|
1178
|
+
const id = this.safeString (item, 'id');
|
1179
|
+
let amountString = this.safeString (item, 'amount');
|
1180
|
+
let direction = undefined;
|
1181
|
+
const afterString = this.safeString (item, 'balance');
|
1182
|
+
const beforeString = Precise.stringSub (afterString, amountString);
|
1183
|
+
if (Precise.stringLt (amountString, '0')) {
|
1184
|
+
direction = 'out';
|
1185
|
+
amountString = Precise.stringAbs (amountString);
|
1186
|
+
} else {
|
1187
|
+
direction = 'in';
|
1188
|
+
}
|
1189
|
+
const amount = this.parseNumber (amountString);
|
1190
|
+
const after = this.parseNumber (afterString);
|
1191
|
+
const before = this.parseNumber (beforeString);
|
1192
|
+
const timestamp = this.parse8601 (this.safeValue (item, 'created_at'));
|
1193
|
+
const type = this.parseLedgerEntryType (this.safeString (item, 'type'));
|
1194
|
+
const code = this.safeCurrencyCode (undefined, currency);
|
1195
|
+
const details = this.safeValue (item, 'details', {});
|
1196
|
+
let account = undefined;
|
1197
|
+
let referenceAccount = undefined;
|
1198
|
+
let referenceId = undefined;
|
1199
|
+
if (type === 'transfer') {
|
1200
|
+
account = this.safeString (details, 'from');
|
1201
|
+
referenceAccount = this.safeString (details, 'to');
|
1202
|
+
referenceId = this.safeString (details, 'profile_transfer_id');
|
1203
|
+
} else {
|
1204
|
+
referenceId = this.safeString (details, 'order_id');
|
1205
|
+
}
|
1206
|
+
const status = 'ok';
|
1207
|
+
return {
|
1208
|
+
'id': id,
|
1209
|
+
'currency': code,
|
1210
|
+
'account': account,
|
1211
|
+
'referenceAccount': referenceAccount,
|
1212
|
+
'referenceId': referenceId,
|
1213
|
+
'status': status,
|
1214
|
+
'amount': amount,
|
1215
|
+
'before': before,
|
1216
|
+
'after': after,
|
1217
|
+
'fee': undefined,
|
1218
|
+
'direction': direction,
|
1219
|
+
'timestamp': timestamp,
|
1220
|
+
'datetime': this.iso8601 (timestamp),
|
1221
|
+
'type': type,
|
1222
|
+
'info': item,
|
1223
|
+
};
|
1224
|
+
}
|
1225
|
+
|
1226
|
+
async fetchLedger (code = undefined, since = undefined, limit = undefined, params = {}) {
|
1227
|
+
// https://docs.cloud.coinbase.com/exchange/reference/exchangerestapi_getaccountledger
|
1228
|
+
if (code === undefined) {
|
1229
|
+
throw new ArgumentsRequired (this.id + ' fetchLedger() requires a code param');
|
1230
|
+
}
|
1231
|
+
await this.loadMarkets ();
|
1232
|
+
await this.loadAccounts ();
|
1233
|
+
const currency = this.currency (code);
|
1234
|
+
const accountsByCurrencyCode = this.indexBy (this.accounts, 'currency');
|
1235
|
+
const account = this.safeValue (accountsByCurrencyCode, code);
|
1236
|
+
if (account === undefined) {
|
1237
|
+
throw new ExchangeError (this.id + ' fetchLedger() could not find account id for ' + code);
|
1238
|
+
}
|
1239
|
+
const request = {
|
1240
|
+
'id': account['id'],
|
1241
|
+
// 'start_date': this.iso8601 (since),
|
1242
|
+
// 'end_date': this.iso8601 (this.milliseconds ()),
|
1243
|
+
// 'before': 'cursor', // sets start cursor to before date
|
1244
|
+
// 'after': 'cursor', // sets end cursor to after date
|
1245
|
+
// 'limit': limit, // default 100
|
1246
|
+
// 'profile_id': 'string'
|
1247
|
+
};
|
1248
|
+
if (since !== undefined) {
|
1249
|
+
request['start_date'] = this.iso8601 (since);
|
1250
|
+
}
|
1251
|
+
if (limit !== undefined) {
|
1252
|
+
request['limit'] = limit; // default 100
|
1253
|
+
}
|
1254
|
+
const response = await this.privateGetAccountsIdLedger (this.extend (request, params));
|
1255
|
+
for (let i = 0; i < response.length; i++) {
|
1256
|
+
response[i]['currency'] = code;
|
1257
|
+
}
|
1258
|
+
return this.parseLedger (response, currency, since, limit);
|
1259
|
+
}
|
1260
|
+
|
1261
|
+
async fetchTransactions (code = undefined, since = undefined, limit = undefined, params = {}) {
|
1262
|
+
await this.loadMarkets ();
|
1263
|
+
await this.loadAccounts ();
|
1264
|
+
let currency = undefined;
|
1265
|
+
let id = this.safeString (params, 'id'); // account id
|
1266
|
+
if (id === undefined) {
|
1267
|
+
if (code !== undefined) {
|
1268
|
+
currency = this.currency (code);
|
1269
|
+
const accountsByCurrencyCode = this.indexBy (this.accounts, 'currency');
|
1270
|
+
const account = this.safeValue (accountsByCurrencyCode, code);
|
1271
|
+
if (account === undefined) {
|
1272
|
+
throw new ExchangeError (this.id + ' fetchTransactions() could not find account id for ' + code);
|
1273
|
+
}
|
1274
|
+
id = account['id'];
|
1275
|
+
}
|
1276
|
+
}
|
1277
|
+
const request = {};
|
1278
|
+
if (id !== undefined) {
|
1279
|
+
request['id'] = id;
|
1280
|
+
}
|
1281
|
+
if (limit !== undefined) {
|
1282
|
+
request['limit'] = limit;
|
1283
|
+
}
|
1284
|
+
let response = undefined;
|
1285
|
+
if (id === undefined) {
|
1286
|
+
response = await this.privateGetTransfers (this.extend (request, params));
|
1287
|
+
for (let i = 0; i < response.length; i++) {
|
1288
|
+
const account_id = this.safeString (response[i], 'account_id');
|
1289
|
+
const account = this.safeValue (this.accountsById, account_id);
|
1290
|
+
const code = this.safeString (account, 'currency');
|
1291
|
+
response[i]['currency'] = code;
|
1292
|
+
}
|
1293
|
+
} else {
|
1294
|
+
response = await this.privateGetAccountsIdTransfers (this.extend (request, params));
|
1295
|
+
for (let i = 0; i < response.length; i++) {
|
1296
|
+
response[i]['currency'] = code;
|
1297
|
+
}
|
1298
|
+
}
|
1299
|
+
return this.parseTransactions (response, currency, since, limit);
|
1300
|
+
}
|
1301
|
+
|
1302
|
+
async fetchDeposits (code = undefined, since = undefined, limit = undefined, params = {}) {
|
1303
|
+
return this.fetchTransactions (code, since, limit, this.extend ({ 'type': 'deposit' }, params));
|
1304
|
+
}
|
1305
|
+
|
1306
|
+
async fetchWithdrawals (code = undefined, since = undefined, limit = undefined, params = {}) {
|
1307
|
+
return this.fetchTransactions (code, since, limit, this.extend ({ 'type': 'withdraw' }, params));
|
1308
|
+
}
|
1309
|
+
|
1310
|
+
parseTransactionStatus (transaction) {
|
1311
|
+
const canceled = this.safeValue (transaction, 'canceled_at');
|
1312
|
+
if (canceled) {
|
1313
|
+
return 'canceled';
|
1314
|
+
}
|
1315
|
+
const processed = this.safeValue (transaction, 'processed_at');
|
1316
|
+
const completed = this.safeValue (transaction, 'completed_at');
|
1317
|
+
if (completed) {
|
1318
|
+
return 'ok';
|
1319
|
+
} else if (processed && !completed) {
|
1320
|
+
return 'failed';
|
1321
|
+
} else {
|
1322
|
+
return 'pending';
|
1323
|
+
}
|
1324
|
+
}
|
1325
|
+
|
1326
|
+
parseTransaction (transaction, currency = undefined) {
|
1327
|
+
const details = this.safeValue (transaction, 'details', {});
|
1328
|
+
const id = this.safeString (transaction, 'id');
|
1329
|
+
const txid = this.safeString (details, 'crypto_transaction_hash');
|
1330
|
+
const timestamp = this.parse8601 (this.safeString (transaction, 'created_at'));
|
1331
|
+
const updated = this.parse8601 (this.safeString (transaction, 'processed_at'));
|
1332
|
+
const currencyId = this.safeString (transaction, 'currency');
|
1333
|
+
const code = this.safeCurrencyCode (currencyId, currency);
|
1334
|
+
const status = this.parseTransactionStatus (transaction);
|
1335
|
+
let amount = this.safeNumber (transaction, 'amount');
|
1336
|
+
let type = this.safeString (transaction, 'type');
|
1337
|
+
let address = this.safeString (details, 'crypto_address');
|
1338
|
+
const tag = this.safeString (details, 'destination_tag');
|
1339
|
+
address = this.safeString (transaction, 'crypto_address', address);
|
1340
|
+
let fee = undefined;
|
1341
|
+
if (type === 'withdraw') {
|
1342
|
+
type = 'withdrawal';
|
1343
|
+
address = this.safeString (details, 'sent_to_address', address);
|
1344
|
+
const feeCost = this.safeNumber (details, 'fee');
|
1345
|
+
if (feeCost !== undefined) {
|
1346
|
+
if (amount !== undefined) {
|
1347
|
+
amount -= feeCost;
|
1348
|
+
}
|
1349
|
+
fee = {
|
1350
|
+
'cost': feeCost,
|
1351
|
+
'currency': code,
|
1352
|
+
};
|
1353
|
+
}
|
1354
|
+
}
|
1355
|
+
return {
|
1356
|
+
'info': transaction,
|
1357
|
+
'id': id,
|
1358
|
+
'txid': txid,
|
1359
|
+
'timestamp': timestamp,
|
1360
|
+
'datetime': this.iso8601 (timestamp),
|
1361
|
+
'network': undefined,
|
1362
|
+
'address': address,
|
1363
|
+
'addressTo': undefined,
|
1364
|
+
'addressFrom': undefined,
|
1365
|
+
'tag': tag,
|
1366
|
+
'tagTo': undefined,
|
1367
|
+
'tagFrom': undefined,
|
1368
|
+
'type': type,
|
1369
|
+
'amount': amount,
|
1370
|
+
'currency': code,
|
1371
|
+
'status': status,
|
1372
|
+
'updated': updated,
|
1373
|
+
'fee': fee,
|
1374
|
+
};
|
1375
|
+
}
|
1376
|
+
|
1377
|
+
async createDepositAddress (code, params = {}) {
|
1378
|
+
await this.loadMarkets ();
|
1379
|
+
const currency = this.currency (code);
|
1380
|
+
let accounts = this.safeValue (this.options, 'coinbaseAccounts');
|
1381
|
+
if (accounts === undefined) {
|
1382
|
+
accounts = await this.privateGetCoinbaseAccounts ();
|
1383
|
+
this.options['coinbaseAccounts'] = accounts; // cache it
|
1384
|
+
this.options['coinbaseAccountsByCurrencyId'] = this.indexBy (accounts, 'currency');
|
1385
|
+
}
|
1386
|
+
const currencyId = currency['id'];
|
1387
|
+
const account = this.safeValue (this.options['coinbaseAccountsByCurrencyId'], currencyId);
|
1388
|
+
if (account === undefined) {
|
1389
|
+
// eslint-disable-next-line quotes
|
1390
|
+
throw new InvalidAddress (this.id + " fetchDepositAddress() could not find currency code " + code + " with id = " + currencyId + " in this.options['coinbaseAccountsByCurrencyId']");
|
1391
|
+
}
|
1392
|
+
const request = {
|
1393
|
+
'id': account['id'],
|
1394
|
+
};
|
1395
|
+
const response = await this.privatePostCoinbaseAccountsIdAddresses (this.extend (request, params));
|
1396
|
+
const address = this.safeString (response, 'address');
|
1397
|
+
const tag = this.safeString (response, 'destination_tag');
|
1398
|
+
return {
|
1399
|
+
'currency': code,
|
1400
|
+
'address': this.checkAddress (address),
|
1401
|
+
'tag': tag,
|
1402
|
+
'info': response,
|
1403
|
+
};
|
1404
|
+
}
|
1405
|
+
|
1406
|
+
sign (path, api = 'public', method = 'GET', params = {}, headers = undefined, body = undefined) {
|
1407
|
+
let request = '/' + this.implodeParams (path, params);
|
1408
|
+
const query = this.omit (params, this.extractParams (path));
|
1409
|
+
if (method === 'GET') {
|
1410
|
+
if (Object.keys (query).length) {
|
1411
|
+
request += '?' + this.urlencode (query);
|
1412
|
+
}
|
1413
|
+
}
|
1414
|
+
const url = this.implodeHostname (this.urls['api'][api]) + request;
|
1415
|
+
if (api === 'private') {
|
1416
|
+
this.checkRequiredCredentials ();
|
1417
|
+
const nonce = this.nonce ().toString ();
|
1418
|
+
let payload = '';
|
1419
|
+
if (method !== 'GET') {
|
1420
|
+
if (Object.keys (query).length) {
|
1421
|
+
body = this.json (query);
|
1422
|
+
payload = body;
|
1423
|
+
}
|
1424
|
+
}
|
1425
|
+
const what = nonce + method + request + payload;
|
1426
|
+
let secret = undefined;
|
1427
|
+
try {
|
1428
|
+
secret = this.base64ToBinary (this.secret);
|
1429
|
+
} catch (e) {
|
1430
|
+
throw new AuthenticationError (this.id + ' sign() invalid base64 secret');
|
1431
|
+
}
|
1432
|
+
const signature = this.hmac (this.encode (what), secret, 'sha256', 'base64');
|
1433
|
+
headers = {
|
1434
|
+
'CB-ACCESS-KEY': this.apiKey,
|
1435
|
+
'CB-ACCESS-SIGN': signature,
|
1436
|
+
'CB-ACCESS-TIMESTAMP': nonce,
|
1437
|
+
'CB-ACCESS-PASSPHRASE': this.password,
|
1438
|
+
'Content-Type': 'application/json',
|
1439
|
+
};
|
1440
|
+
}
|
1441
|
+
return { 'url': url, 'method': method, 'body': body, 'headers': headers };
|
1442
|
+
}
|
1443
|
+
|
1444
|
+
handleErrors (code, reason, url, method, headers, body, response, requestHeaders, requestBody) {
|
1445
|
+
if ((code === 400) || (code === 404)) {
|
1446
|
+
if (body[0] === '{') {
|
1447
|
+
const message = this.safeString (response, 'message');
|
1448
|
+
const feedback = this.id + ' ' + message;
|
1449
|
+
this.throwExactlyMatchedException (this.exceptions['exact'], message, feedback);
|
1450
|
+
this.throwBroadlyMatchedException (this.exceptions['broad'], message, feedback);
|
1451
|
+
throw new ExchangeError (feedback); // unknown message
|
1452
|
+
}
|
1453
|
+
throw new ExchangeError (this.id + ' ' + body);
|
1454
|
+
}
|
1455
|
+
}
|
1456
|
+
|
1457
|
+
async request (path, api = 'public', method = 'GET', params = {}, headers = undefined, body = undefined, config = {}, context = {}) {
|
1458
|
+
const response = await this.fetch2 (path, api, method, params, headers, body, config, context);
|
1459
|
+
if (typeof response !== 'string') {
|
1460
|
+
if ('message' in response) {
|
1461
|
+
throw new ExchangeError (this.id + ' ' + this.json (response));
|
1462
|
+
}
|
1463
|
+
}
|
1464
|
+
return response;
|
1465
|
+
}
|
1466
|
+
};
|