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.
Files changed (264) hide show
  1. package/.cache/eslintcache +1 -0
  2. package/.dockerignore +6 -0
  3. package/.eslintignore +1 -0
  4. package/.gitattributes +5 -0
  5. package/.readthedocs.yaml +16 -0
  6. package/CONTRIBUTING.md +1049 -0
  7. package/LICENSE.txt +21 -0
  8. package/README.md +537 -0
  9. package/SECURITY.md +5 -0
  10. package/build/cleanup-old-tags.js +94 -0
  11. package/build/countries.js +256 -0
  12. package/build/export-exchanges.js +520 -0
  13. package/build/fs.js +51 -0
  14. package/build/transpile.js +1772 -0
  15. package/build/vss.js +78 -0
  16. package/ccxt.browser.js +7 -0
  17. package/ccxt.d.ts +692 -0
  18. package/ccxt.js +171 -0
  19. package/cleanup.sh +2 -0
  20. package/composer-install.sh +20 -0
  21. package/dist/ccxt.browser.js +208383 -0
  22. package/gource.sh +3 -0
  23. package/index.html +7 -0
  24. package/js/.eslintrc +87 -0
  25. package/js/aax.js +2686 -0
  26. package/js/ascendex.js +2584 -0
  27. package/js/base/.eslintrc.js +43 -0
  28. package/js/base/Exchange.js +2371 -0
  29. package/js/base/Precise.js +283 -0
  30. package/js/base/errorHierarchy.js +47 -0
  31. package/js/base/errors.js +55 -0
  32. package/js/base/functions/crypto.js +158 -0
  33. package/js/base/functions/encode.js +118 -0
  34. package/js/base/functions/generic.js +270 -0
  35. package/js/base/functions/misc.js +138 -0
  36. package/js/base/functions/number.js +329 -0
  37. package/js/base/functions/platform.js +38 -0
  38. package/js/base/functions/string.js +21 -0
  39. package/js/base/functions/throttle.js +79 -0
  40. package/js/base/functions/time.js +210 -0
  41. package/js/base/functions/type.js +66 -0
  42. package/js/base/functions.js +28 -0
  43. package/js/bequant.js +32 -0
  44. package/js/bibox.js +1407 -0
  45. package/js/bigone.js +1366 -0
  46. package/js/binance.js +5652 -0
  47. package/js/binancecoinm.js +46 -0
  48. package/js/binanceus.js +46 -0
  49. package/js/binanceusdm.js +49 -0
  50. package/js/bit2c.js +535 -0
  51. package/js/bitbank.js +842 -0
  52. package/js/bitbay.js +16 -0
  53. package/js/bitbns.js +1073 -0
  54. package/js/bitcoincom.js +15 -0
  55. package/js/bitfinex.js +1433 -0
  56. package/js/bitfinex2.js +2025 -0
  57. package/js/bitflyer.js +840 -0
  58. package/js/bitforex.js +614 -0
  59. package/js/bitget.js +2397 -0
  60. package/js/bithumb.js +980 -0
  61. package/js/bitmart.js +2516 -0
  62. package/js/bitmex.js +1809 -0
  63. package/js/bitopro.js +1443 -0
  64. package/js/bitpanda.js +1782 -0
  65. package/js/bitrue.js +1747 -0
  66. package/js/bitso.js +1062 -0
  67. package/js/bitstamp.js +1757 -0
  68. package/js/bitstamp1.js +343 -0
  69. package/js/bittrex.js +1876 -0
  70. package/js/bitvavo.js +1579 -0
  71. package/js/bkex.js +1233 -0
  72. package/js/bl3p.js +346 -0
  73. package/js/blockchaincom.js +969 -0
  74. package/js/btcalpha.js +680 -0
  75. package/js/btcbox.js +477 -0
  76. package/js/btcmarkets.js +1022 -0
  77. package/js/btctradeua.js +466 -0
  78. package/js/btcturk.js +734 -0
  79. package/js/buda.js +946 -0
  80. package/js/bw.js +1265 -0
  81. package/js/bybit.js +3372 -0
  82. package/js/bytetrade.js +1336 -0
  83. package/js/cdax.js +1646 -0
  84. package/js/cex.js +1410 -0
  85. package/js/coinbase.js +1342 -0
  86. package/js/coinbaseprime.js +31 -0
  87. package/js/coinbasepro.js +1466 -0
  88. package/js/coincheck.js +755 -0
  89. package/js/coinex.js +3400 -0
  90. package/js/coinfalcon.js +880 -0
  91. package/js/coinmate.js +794 -0
  92. package/js/coinone.js +816 -0
  93. package/js/coinspot.js +345 -0
  94. package/js/crex24.js +1636 -0
  95. package/js/cryptocom.js +1832 -0
  96. package/js/currencycom.js +1748 -0
  97. package/js/delta.js +1547 -0
  98. package/js/deribit.js +2148 -0
  99. package/js/digifinex.js +1585 -0
  100. package/js/eqonex.js +1660 -0
  101. package/js/exmo.js +1670 -0
  102. package/js/fairdesk.js +1231 -0
  103. package/js/flowbtc.js +35 -0
  104. package/js/fmfwio.js +34 -0
  105. package/js/ftx.js +2751 -0
  106. package/js/ftxus.js +38 -0
  107. package/js/gateio.js +4174 -0
  108. package/js/gemini.js +1397 -0
  109. package/js/hitbtc.js +1343 -0
  110. package/js/hitbtc3.js +2329 -0
  111. package/js/hollaex.js +1486 -0
  112. package/js/huobi.js +5706 -0
  113. package/js/huobijp.js +1710 -0
  114. package/js/huobipro.js +18 -0
  115. package/js/idex.js +1439 -0
  116. package/js/independentreserve.js +649 -0
  117. package/js/indodax.js +742 -0
  118. package/js/itbit.js +722 -0
  119. package/js/kraken.js +2179 -0
  120. package/js/kucoin.js +2571 -0
  121. package/js/kucoinfutures.js +1771 -0
  122. package/js/kuna.js +809 -0
  123. package/js/latoken.js +1445 -0
  124. package/js/lbank.js +760 -0
  125. package/js/liquid.js +1432 -0
  126. package/js/luno.js +873 -0
  127. package/js/lykke.js +1147 -0
  128. package/js/mercado.js +771 -0
  129. package/js/mexc.js +3151 -0
  130. package/js/ndax.js +2233 -0
  131. package/js/novadax.js +1318 -0
  132. package/js/oceanex.js +816 -0
  133. package/js/okcoin.js +3841 -0
  134. package/js/okex.js +16 -0
  135. package/js/okex5.js +16 -0
  136. package/js/okx.js +4795 -0
  137. package/js/paymium.js +498 -0
  138. package/js/phemex.js +2957 -0
  139. package/js/poloniex.js +1674 -0
  140. package/js/probit.js +1346 -0
  141. package/js/qtrade.js +1588 -0
  142. package/js/ripio.js +1061 -0
  143. package/js/static_dependencies/BN/bn.js +3526 -0
  144. package/js/static_dependencies/README.md +1 -0
  145. package/js/static_dependencies/crypto-js/crypto-js.js +5988 -0
  146. package/js/static_dependencies/elliptic/lib/elliptic/curve/base.js +375 -0
  147. package/js/static_dependencies/elliptic/lib/elliptic/curve/edwards.js +433 -0
  148. package/js/static_dependencies/elliptic/lib/elliptic/curve/index.js +8 -0
  149. package/js/static_dependencies/elliptic/lib/elliptic/curve/mont.js +180 -0
  150. package/js/static_dependencies/elliptic/lib/elliptic/curve/short.js +938 -0
  151. package/js/static_dependencies/elliptic/lib/elliptic/curves.js +204 -0
  152. package/js/static_dependencies/elliptic/lib/elliptic/ec/index.js +240 -0
  153. package/js/static_dependencies/elliptic/lib/elliptic/ec/key.js +119 -0
  154. package/js/static_dependencies/elliptic/lib/elliptic/ec/signature.js +24 -0
  155. package/js/static_dependencies/elliptic/lib/elliptic/eddsa/index.js +145 -0
  156. package/js/static_dependencies/elliptic/lib/elliptic/eddsa/key.js +100 -0
  157. package/js/static_dependencies/elliptic/lib/elliptic/eddsa/signature.js +65 -0
  158. package/js/static_dependencies/elliptic/lib/elliptic/precomputed/secp256k1.js +780 -0
  159. package/js/static_dependencies/elliptic/lib/elliptic/utils.js +214 -0
  160. package/js/static_dependencies/elliptic/lib/elliptic.js +22 -0
  161. package/js/static_dependencies/elliptic/lib/hmac-drbg/hmac-drbg.js +114 -0
  162. package/js/static_dependencies/fetch-ponyfill/fetch-node.js +39 -0
  163. package/js/static_dependencies/node-fetch/index.js +1564 -0
  164. package/js/static_dependencies/node-rsa/NodeRSA.js +223 -0
  165. package/js/static_dependencies/node-rsa/asn1/ber/errors.js +13 -0
  166. package/js/static_dependencies/node-rsa/asn1/ber/index.js +21 -0
  167. package/js/static_dependencies/node-rsa/asn1/ber/reader.js +262 -0
  168. package/js/static_dependencies/node-rsa/asn1/ber/types.js +36 -0
  169. package/js/static_dependencies/node-rsa/asn1/index.js +17 -0
  170. package/js/static_dependencies/node-rsa/encryptEngines/js.js +34 -0
  171. package/js/static_dependencies/node-rsa/formats/components.js +71 -0
  172. package/js/static_dependencies/node-rsa/formats/formats.js +31 -0
  173. package/js/static_dependencies/node-rsa/formats/pkcs1.js +148 -0
  174. package/js/static_dependencies/node-rsa/formats/pkcs8.js +187 -0
  175. package/js/static_dependencies/node-rsa/libs/jsbn.js +1252 -0
  176. package/js/static_dependencies/node-rsa/libs/rsa.js +147 -0
  177. package/js/static_dependencies/node-rsa/schemes/pkcs1.js +176 -0
  178. package/js/static_dependencies/node-rsa/schemes/schemes.js +21 -0
  179. package/js/static_dependencies/node-rsa/utils.js +98 -0
  180. package/js/static_dependencies/qs/formats.js +18 -0
  181. package/js/static_dependencies/qs/index.js +11 -0
  182. package/js/static_dependencies/qs/parse.js +242 -0
  183. package/js/static_dependencies/qs/stringify.js +269 -0
  184. package/js/static_dependencies/qs/utils.js +230 -0
  185. package/js/stex.js +1925 -0
  186. package/js/test/.eslintrc.js +42 -0
  187. package/js/test/Exchange/test.balance.js +61 -0
  188. package/js/test/Exchange/test.borrowRate.js +32 -0
  189. package/js/test/Exchange/test.currency.js +52 -0
  190. package/js/test/Exchange/test.fetchBalance.js +23 -0
  191. package/js/test/Exchange/test.fetchBorrowInterest.js +59 -0
  192. package/js/test/Exchange/test.fetchBorrowRate.js +32 -0
  193. package/js/test/Exchange/test.fetchBorrowRates.js +28 -0
  194. package/js/test/Exchange/test.fetchClosedOrders.js +32 -0
  195. package/js/test/Exchange/test.fetchCurrencies.js +35 -0
  196. package/js/test/Exchange/test.fetchDeposits.js +31 -0
  197. package/js/test/Exchange/test.fetchFundingFees.js +19 -0
  198. package/js/test/Exchange/test.fetchFundingRateHistory.js +40 -0
  199. package/js/test/Exchange/test.fetchL2OrderBook.js +23 -0
  200. package/js/test/Exchange/test.fetchLedger.js +42 -0
  201. package/js/test/Exchange/test.fetchLeverageTiers.js +33 -0
  202. package/js/test/Exchange/test.fetchMarketLeverageTiers.js +22 -0
  203. package/js/test/Exchange/test.fetchMarkets.js +33 -0
  204. package/js/test/Exchange/test.fetchMyTrades.js +42 -0
  205. package/js/test/Exchange/test.fetchOHLCV.js +46 -0
  206. package/js/test/Exchange/test.fetchOpenOrders.js +36 -0
  207. package/js/test/Exchange/test.fetchOrderBook.js +25 -0
  208. package/js/test/Exchange/test.fetchOrderBooks.js +35 -0
  209. package/js/test/Exchange/test.fetchOrders.js +41 -0
  210. package/js/test/Exchange/test.fetchPositions.js +47 -0
  211. package/js/test/Exchange/test.fetchStatus.js +35 -0
  212. package/js/test/Exchange/test.fetchTicker.js +38 -0
  213. package/js/test/Exchange/test.fetchTickers.js +49 -0
  214. package/js/test/Exchange/test.fetchTrades.js +39 -0
  215. package/js/test/Exchange/test.fetchTradingFee.js +18 -0
  216. package/js/test/Exchange/test.fetchTradingFees.js +22 -0
  217. package/js/test/Exchange/test.fetchTransactions.js +31 -0
  218. package/js/test/Exchange/test.fetchWithdrawals.js +31 -0
  219. package/js/test/Exchange/test.ledgerItem.js +46 -0
  220. package/js/test/Exchange/test.leverageTier.js +33 -0
  221. package/js/test/Exchange/test.loadMarkets.js +35 -0
  222. package/js/test/Exchange/test.market.js +129 -0
  223. package/js/test/Exchange/test.ohlcv.js +33 -0
  224. package/js/test/Exchange/test.order.js +62 -0
  225. package/js/test/Exchange/test.orderbook.js +61 -0
  226. package/js/test/Exchange/test.position.js +21 -0
  227. package/js/test/Exchange/test.throttle.js +94 -0
  228. package/js/test/Exchange/test.ticker.js +95 -0
  229. package/js/test/Exchange/test.trade.js +68 -0
  230. package/js/test/Exchange/test.tradingFee.js +34 -0
  231. package/js/test/Exchange/test.transaction.js +35 -0
  232. package/js/test/base/.eslintrc +38 -0
  233. package/js/test/base/functions/test.crypto.js +110 -0
  234. package/js/test/base/functions/test.datetime.js +62 -0
  235. package/js/test/base/functions/test.generic.js +152 -0
  236. package/js/test/base/functions/test.number.js +362 -0
  237. package/js/test/base/functions/test.time.js +56 -0
  238. package/js/test/base/functions/test.type.js +53 -0
  239. package/js/test/base/test.base.js +193 -0
  240. package/js/test/errors/test.InsufficientFunds.js +86 -0
  241. package/js/test/errors/test.InvalidNonce.js +64 -0
  242. package/js/test/errors/test.InvalidOrder.js +35 -0
  243. package/js/test/errors/test.OrderNotFound.js +39 -0
  244. package/js/test/test.js +426 -0
  245. package/js/test/test.timeout_hang.js +12 -0
  246. package/js/therock.js +1431 -0
  247. package/js/tidebit.js +632 -0
  248. package/js/tidex.js +939 -0
  249. package/js/timex.js +1283 -0
  250. package/js/upbit.js +1622 -0
  251. package/js/vcc.js +1353 -0
  252. package/js/wavesexchange.js +2185 -0
  253. package/js/wazirx.js +732 -0
  254. package/js/whitebit.js +1352 -0
  255. package/js/woo.js +1577 -0
  256. package/js/xena.js +1948 -0
  257. package/js/yobit.js +1129 -0
  258. package/js/zaif.js +647 -0
  259. package/js/zb.js +4088 -0
  260. package/js/zipmex.js +40 -0
  261. package/js/zonda.js +1497 -0
  262. package/multilang.sh +159 -0
  263. package/package.json +591 -0
  264. 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
+ };