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
package/js/bitstamp.js ADDED
@@ -0,0 +1,1757 @@
1
+ 'use strict';
2
+
3
+ // ---------------------------------------------------------------------------
4
+
5
+ const Exchange = require ('./base/Exchange');
6
+ const { AuthenticationError, BadRequest, ExchangeError, NotSupported, PermissionDenied, InvalidNonce, OrderNotFound, InsufficientFunds, InvalidAddress, InvalidOrder, ArgumentsRequired, OnMaintenance, ExchangeNotAvailable } = require ('./base/errors');
7
+ const Precise = require ('./base/Precise');
8
+
9
+ // ---------------------------------------------------------------------------
10
+
11
+ module.exports = class bitstamp extends Exchange {
12
+ describe () {
13
+ return this.deepExtend (super.describe (), {
14
+ 'id': 'bitstamp',
15
+ 'name': 'Bitstamp',
16
+ 'countries': [ 'GB' ],
17
+ // 8000 requests per 10 minutes = 8000 / 600 = 13.33333333 requests per second => 1000ms / 13.33333333 = 75ms between requests on average
18
+ 'rateLimit': 75,
19
+ 'version': 'v2',
20
+ 'userAgent': this.userAgents['chrome'],
21
+ 'pro': true,
22
+ 'has': {
23
+ 'CORS': true,
24
+ 'spot': true,
25
+ 'margin': false,
26
+ 'swap': false,
27
+ 'future': false,
28
+ 'option': false,
29
+ 'addMargin': false,
30
+ 'cancelAllOrders': true,
31
+ 'cancelOrder': true,
32
+ 'createOrder': true,
33
+ 'createReduceOnlyOrder': false,
34
+ 'fetchBalance': true,
35
+ 'fetchBorrowRate': false,
36
+ 'fetchBorrowRateHistories': false,
37
+ 'fetchBorrowRateHistory': false,
38
+ 'fetchBorrowRates': false,
39
+ 'fetchBorrowRatesPerSymbol': false,
40
+ 'fetchCurrencies': true,
41
+ 'fetchDepositAddress': true,
42
+ 'fetchFundingFees': true,
43
+ 'fetchFundingHistory': false,
44
+ 'fetchFundingRate': false,
45
+ 'fetchFundingRateHistory': false,
46
+ 'fetchFundingRates': false,
47
+ 'fetchIndexOHLCV': false,
48
+ 'fetchLedger': true,
49
+ 'fetchLeverage': false,
50
+ 'fetchMarkets': true,
51
+ 'fetchMarkOHLCV': false,
52
+ 'fetchMyTrades': true,
53
+ 'fetchOHLCV': true,
54
+ 'fetchOpenOrders': true,
55
+ 'fetchOrder': true,
56
+ 'fetchOrderBook': true,
57
+ 'fetchPosition': false,
58
+ 'fetchPositions': false,
59
+ 'fetchPositionsRisk': false,
60
+ 'fetchPremiumIndexOHLCV': false,
61
+ 'fetchTicker': true,
62
+ 'fetchTrades': true,
63
+ 'fetchTradingFee': true,
64
+ 'fetchTradingFees': true,
65
+ 'fetchTransactions': true,
66
+ 'fetchWithdrawals': true,
67
+ 'reduceMargin': false,
68
+ 'setLeverage': false,
69
+ 'setMarginMode': false,
70
+ 'setPositionMode': false,
71
+ 'withdraw': true,
72
+ },
73
+ 'urls': {
74
+ 'logo': 'https://user-images.githubusercontent.com/1294454/27786377-8c8ab57e-5fe9-11e7-8ea4-2b05b6bcceec.jpg',
75
+ 'api': {
76
+ 'public': 'https://www.bitstamp.net/api',
77
+ 'private': 'https://www.bitstamp.net/api',
78
+ },
79
+ 'www': 'https://www.bitstamp.net',
80
+ 'doc': 'https://www.bitstamp.net/api',
81
+ },
82
+ 'timeframes': {
83
+ '1m': '60',
84
+ '3m': '180',
85
+ '5m': '300',
86
+ '15m': '900',
87
+ '30m': '1800',
88
+ '1h': '3600',
89
+ '2h': '7200',
90
+ '4h': '14400',
91
+ '6h': '21600',
92
+ '12h': '43200',
93
+ '1d': '86400',
94
+ '1w': '259200',
95
+ },
96
+ 'requiredCredentials': {
97
+ 'apiKey': true,
98
+ 'secret': true,
99
+ },
100
+ 'api': {
101
+ 'public': {
102
+ 'get': {
103
+ 'ohlc/{pair}/': 1,
104
+ 'order_book/{pair}/': 1,
105
+ 'ticker_hour/{pair}/': 1,
106
+ 'ticker/{pair}/': 1,
107
+ 'transactions/{pair}/': 1,
108
+ 'trading-pairs-info/': 1,
109
+ },
110
+ },
111
+ 'private': {
112
+ 'post': {
113
+ 'balance/': 1,
114
+ 'balance/{pair}/': 1,
115
+ 'bch_withdrawal/': 1,
116
+ 'bch_address/': 1,
117
+ 'user_transactions/': 1,
118
+ 'user_transactions/{pair}/': 1,
119
+ 'open_orders/all/': 1,
120
+ 'open_orders/{pair}/': 1,
121
+ 'order_status/': 1,
122
+ 'cancel_order/': 1,
123
+ 'cancel_all_orders/': 1,
124
+ 'cancel_all_orders/{pair}/': 1,
125
+ 'buy/{pair}/': 1,
126
+ 'buy/market/{pair}/': 1,
127
+ 'buy/instant/{pair}/': 1,
128
+ 'sell/{pair}/': 1,
129
+ 'sell/market/{pair}/': 1,
130
+ 'sell/instant/{pair}/': 1,
131
+ 'btc_withdrawal/': 1,
132
+ 'btc_address/': 1,
133
+ 'ripple_withdrawal/': 1,
134
+ 'ripple_address/': 1,
135
+ 'ltc_withdrawal/': 1,
136
+ 'ltc_address/': 1,
137
+ 'eth_withdrawal/': 1,
138
+ 'eth_address/': 1,
139
+ 'xrp_withdrawal/': 1,
140
+ 'xrp_address/': 1,
141
+ 'xlm_withdrawal/': 1,
142
+ 'xlm_address/': 1,
143
+ 'pax_withdrawal/': 1,
144
+ 'pax_address/': 1,
145
+ 'link_withdrawal/': 1,
146
+ 'link_address/': 1,
147
+ 'usdc_withdrawal/': 1,
148
+ 'usdc_address/': 1,
149
+ 'omg_withdrawal/': 1,
150
+ 'omg_address/': 1,
151
+ 'dai_withdrawal/': 1,
152
+ 'dai_address/': 1,
153
+ 'knc_withdrawal/': 1,
154
+ 'knc_address/': 1,
155
+ 'mkr_withdrawal/': 1,
156
+ 'mkr_address/': 1,
157
+ 'zrx_withdrawal/': 1,
158
+ 'zrx_address/': 1,
159
+ 'gusd_withdrawal/': 1,
160
+ 'gusd_address/': 1,
161
+ 'aave_withdrawal/': 1,
162
+ 'aave_address/': 1,
163
+ 'bat_withdrawal/': 1,
164
+ 'bat_address/': 1,
165
+ 'uma_withdrawal/': 1,
166
+ 'uma_address/': 1,
167
+ 'snx_withdrawal/': 1,
168
+ 'snx_address/': 1,
169
+ 'uni_withdrawal/': 1,
170
+ 'uni_address/': 1,
171
+ 'yfi_withdrawal/': 1,
172
+ 'yfi_address': 1,
173
+ 'audio_withdrawal/': 1,
174
+ 'audio_address/': 1,
175
+ 'crv_withdrawal/': 1,
176
+ 'crv_address/': 1,
177
+ 'algo_withdrawal/': 1,
178
+ 'algo_address/': 1,
179
+ 'comp_withdrawal/': 1,
180
+ 'comp_address/': 1,
181
+ 'grt_withdrawal': 1,
182
+ 'grt_address/': 1,
183
+ 'usdt_withdrawal/': 1,
184
+ 'usdt_address/': 1,
185
+ 'eurt_withdrawal/': 1,
186
+ 'eurt_address/': 1,
187
+ 'matic_withdrawal/': 1,
188
+ 'matic_address/': 1,
189
+ 'sushi_withdrawal/': 1,
190
+ 'sushi_address/': 1,
191
+ 'chz_withdrawal/': 1,
192
+ 'chz_address/': 1,
193
+ 'enj_withdrawal/': 1,
194
+ 'enj_address/': 1,
195
+ 'alpha_withdrawal/': 1,
196
+ 'alpha_address/': 1,
197
+ 'ftt_withdrawal/': 1,
198
+ 'ftt_address/': 1,
199
+ 'storj_withdrawal/': 1,
200
+ 'storj_address/': 1,
201
+ 'axs_withdrawal/': 1,
202
+ 'axs_address/': 1,
203
+ 'sand_withdrawal/': 1,
204
+ 'sand_address/': 1,
205
+ 'hbar_withdrawal/': 1,
206
+ 'hbar_address/': 1,
207
+ 'rgt_withdrawal/': 1,
208
+ 'rgt_address/': 1,
209
+ 'fet_withdrawal/': 1,
210
+ 'fet_address/': 1,
211
+ 'skl_withdrawal/': 1,
212
+ 'skl_address/': 1,
213
+ 'cel_withdrawal/': 1,
214
+ 'cel_address/': 1,
215
+ 'sxp_withdrawal/': 1,
216
+ 'sxp_address/': 1,
217
+ 'ada_withdrawal/': 1,
218
+ 'ada_address/': 1,
219
+ 'slp_withdrawal/': 1,
220
+ 'slp_address/': 1,
221
+ 'ftm_withdrawal/': 1,
222
+ 'ftm_address/': 1,
223
+ 'perp_withdrawal/': 1,
224
+ 'perp_address/': 1,
225
+ 'dydx_withdrawal/': 1,
226
+ 'dydx_address/': 1,
227
+ 'gala_withdrawal/': 1,
228
+ 'gala_address/': 1,
229
+ 'shib_withdrawal/': 1,
230
+ 'shib_address/': 1,
231
+ 'amp_withdrawal/': 1,
232
+ 'amp_address/': 1,
233
+ 'sgb_withdrawal/': 1,
234
+ 'sgb_address/': 1,
235
+ 'avax_withdrawal/': 1,
236
+ 'avax_address/': 1,
237
+ 'wbtc_withdrawal/': 1,
238
+ 'wbtc_address/': 1,
239
+ 'ctsi_withdrawal/': 1,
240
+ 'ctsi_address/': 1,
241
+ 'cvx_withdrawal/': 1,
242
+ 'cvx_address/': 1,
243
+ 'imx_withdrawal/': 1,
244
+ 'imx_address/': 1,
245
+ 'nexo_withdrawal/': 1,
246
+ 'nexo_address/': 1,
247
+ 'ust_withdrawal/': 1,
248
+ 'ust_address/': 1,
249
+ 'ant_withdrawal/': 1,
250
+ 'ant_address/': 1,
251
+ 'gods_withdrawal/': 1,
252
+ 'gods_address/': 1,
253
+ 'rad_withdrawal/': 1,
254
+ 'rad_address/': 1,
255
+ 'transfer-to-main/': 1,
256
+ 'transfer-from-main/': 1,
257
+ 'withdrawal-requests/': 1,
258
+ 'withdrawal/open/': 1,
259
+ 'withdrawal/status/': 1,
260
+ 'withdrawal/cancel/': 1,
261
+ 'liquidation_address/new/': 1,
262
+ 'liquidation_address/info/': 1,
263
+ 'btc_unconfirmed/': 1,
264
+ 'websockets_token/': 1,
265
+ },
266
+ },
267
+ },
268
+ 'fees': {
269
+ 'trading': {
270
+ 'tierBased': true,
271
+ 'percentage': true,
272
+ 'taker': this.parseNumber ('0.005'),
273
+ 'maker': this.parseNumber ('0.005'),
274
+ 'tiers': {
275
+ 'taker': [
276
+ [ this.parseNumber ('0'), this.parseNumber ('0.005') ],
277
+ [ this.parseNumber ('20000'), this.parseNumber ('0.0025') ],
278
+ [ this.parseNumber ('100000'), this.parseNumber ('0.0024') ],
279
+ [ this.parseNumber ('200000'), this.parseNumber ('0.0022') ],
280
+ [ this.parseNumber ('400000'), this.parseNumber ('0.0020') ],
281
+ [ this.parseNumber ('600000'), this.parseNumber ('0.0015') ],
282
+ [ this.parseNumber ('1000000'), this.parseNumber ('0.0014') ],
283
+ [ this.parseNumber ('2000000'), this.parseNumber ('0.0013') ],
284
+ [ this.parseNumber ('4000000'), this.parseNumber ('0.0012') ],
285
+ [ this.parseNumber ('20000000'), this.parseNumber ('0.0011') ],
286
+ [ this.parseNumber ('50000000'), this.parseNumber ('0.0010') ],
287
+ [ this.parseNumber ('100000000'), this.parseNumber ('0.0007') ],
288
+ [ this.parseNumber ('500000000'), this.parseNumber ('0.0005') ],
289
+ [ this.parseNumber ('2000000000'), this.parseNumber ('0.0003') ],
290
+ [ this.parseNumber ('6000000000'), this.parseNumber ('0.0001') ],
291
+ [ this.parseNumber ('20000000000'), this.parseNumber ('0.00005') ],
292
+ [ this.parseNumber ('20000000001'), this.parseNumber ('0') ],
293
+ ],
294
+ 'maker': [
295
+ [ this.parseNumber ('0'), this.parseNumber ('0.005') ],
296
+ [ this.parseNumber ('20000'), this.parseNumber ('0.0025') ],
297
+ [ this.parseNumber ('100000'), this.parseNumber ('0.0024') ],
298
+ [ this.parseNumber ('200000'), this.parseNumber ('0.0022') ],
299
+ [ this.parseNumber ('400000'), this.parseNumber ('0.0020') ],
300
+ [ this.parseNumber ('600000'), this.parseNumber ('0.0015') ],
301
+ [ this.parseNumber ('1000000'), this.parseNumber ('0.0014') ],
302
+ [ this.parseNumber ('2000000'), this.parseNumber ('0.0013') ],
303
+ [ this.parseNumber ('4000000'), this.parseNumber ('0.0012') ],
304
+ [ this.parseNumber ('20000000'), this.parseNumber ('0.0011') ],
305
+ [ this.parseNumber ('50000000'), this.parseNumber ('0.0010') ],
306
+ [ this.parseNumber ('100000000'), this.parseNumber ('0.0007') ],
307
+ [ this.parseNumber ('500000000'), this.parseNumber ('0.0005') ],
308
+ [ this.parseNumber ('2000000000'), this.parseNumber ('0.0003') ],
309
+ [ this.parseNumber ('6000000000'), this.parseNumber ('0.0001') ],
310
+ [ this.parseNumber ('20000000000'), this.parseNumber ('0.00005') ],
311
+ [ this.parseNumber ('20000000001'), this.parseNumber ('0') ],
312
+ ],
313
+ },
314
+ },
315
+ 'funding': {
316
+ 'tierBased': false,
317
+ 'percentage': false,
318
+ 'withdraw': {},
319
+ 'deposit': {
320
+ 'BTC': 0,
321
+ 'BCH': 0,
322
+ 'LTC': 0,
323
+ 'ETH': 0,
324
+ 'XRP': 0,
325
+ 'XLM': 0,
326
+ 'PAX': 0,
327
+ 'USD': 7.5,
328
+ 'EUR': 0,
329
+ },
330
+ },
331
+ },
332
+ 'exceptions': {
333
+ 'exact': {
334
+ 'No permission found': PermissionDenied,
335
+ 'API key not found': AuthenticationError,
336
+ 'IP address not allowed': PermissionDenied,
337
+ 'Invalid nonce': InvalidNonce,
338
+ 'Invalid signature': AuthenticationError,
339
+ 'Authentication failed': AuthenticationError,
340
+ 'Missing key, signature and nonce parameters': AuthenticationError,
341
+ 'Wrong API key format': AuthenticationError,
342
+ 'Your account is frozen': PermissionDenied,
343
+ 'Please update your profile with your FATCA information, before using API.': PermissionDenied,
344
+ 'Order not found': OrderNotFound,
345
+ 'Price is more than 20% below market price.': InvalidOrder,
346
+ "Bitstamp.net is under scheduled maintenance. We'll be back soon.": OnMaintenance, // { "error": "Bitstamp.net is under scheduled maintenance. We'll be back soon." }
347
+ 'Order could not be placed.': ExchangeNotAvailable, // Order could not be placed (perhaps due to internal error or trade halt). Please retry placing order.
348
+ 'Invalid offset.': BadRequest,
349
+ },
350
+ 'broad': {
351
+ 'Minimum order size is': InvalidOrder, // Minimum order size is 5.0 EUR.
352
+ 'Check your account balance for details.': InsufficientFunds, // You have only 0.00100000 BTC available. Check your account balance for details.
353
+ 'Ensure this value has at least': InvalidAddress, // Ensure this value has at least 25 characters (it has 4).
354
+ },
355
+ },
356
+ });
357
+ }
358
+
359
+ async fetchMarkets (params = {}) {
360
+ const response = await this.fetchMarketsFromCache (params);
361
+ //
362
+ // [
363
+ // {
364
+ // "trading": "Enabled",
365
+ // "base_decimals": 8,
366
+ // "url_symbol": "btcusd",
367
+ // "name": "BTC/USD",
368
+ // "instant_and_market_orders": "Enabled",
369
+ // "minimum_order": "20.0 USD",
370
+ // "counter_decimals": 2,
371
+ // "description": "Bitcoin / U.S. dollar"
372
+ // }
373
+ // ]
374
+ //
375
+ const result = [];
376
+ for (let i = 0; i < response.length; i++) {
377
+ const market = response[i];
378
+ const name = this.safeString (market, 'name');
379
+ let [ base, quote ] = name.split ('/');
380
+ const baseId = base.toLowerCase ();
381
+ const quoteId = quote.toLowerCase ();
382
+ base = this.safeCurrencyCode (base);
383
+ quote = this.safeCurrencyCode (quote);
384
+ const minimumOrder = this.safeString (market, 'minimum_order');
385
+ const parts = minimumOrder.split (' ');
386
+ const status = this.safeString (market, 'trading');
387
+ result.push ({
388
+ 'id': this.safeString (market, 'url_symbol'),
389
+ 'marketId': baseId + '_' + quoteId,
390
+ 'symbol': base + '/' + quote,
391
+ 'base': base,
392
+ 'quote': quote,
393
+ 'settle': undefined,
394
+ 'baseId': baseId,
395
+ 'quoteId': quoteId,
396
+ 'settleId': undefined,
397
+ 'type': 'spot',
398
+ 'spot': true,
399
+ 'margin': false,
400
+ 'future': false,
401
+ 'swap': false,
402
+ 'option': false,
403
+ 'active': (status === 'Enabled'),
404
+ 'contract': false,
405
+ 'linear': undefined,
406
+ 'inverse': undefined,
407
+ 'contractSize': undefined,
408
+ 'expiry': undefined,
409
+ 'expiryDatetime': undefined,
410
+ 'strike': undefined,
411
+ 'optionType': undefined,
412
+ 'precision': {
413
+ 'amount': this.safeInteger (market, 'base_decimals'),
414
+ 'price': this.safeInteger (market, 'counter_decimals'),
415
+ },
416
+ 'limits': {
417
+ 'leverage': {
418
+ 'min': undefined,
419
+ 'max': undefined,
420
+ },
421
+ 'amount': {
422
+ 'min': undefined,
423
+ 'max': undefined,
424
+ },
425
+ 'price': {
426
+ 'min': undefined,
427
+ 'max': undefined,
428
+ },
429
+ 'cost': {
430
+ 'min': this.safeNumber (parts, 0),
431
+ 'max': undefined,
432
+ },
433
+ },
434
+ 'info': market,
435
+ });
436
+ }
437
+ return result;
438
+ }
439
+
440
+ constructCurrencyObject (id, code, name, precision, minCost, originalPayload) {
441
+ let currencyType = 'crypto';
442
+ const description = this.describe ();
443
+ if (this.isFiat (code)) {
444
+ currencyType = 'fiat';
445
+ }
446
+ return {
447
+ 'id': id,
448
+ 'code': code,
449
+ 'info': originalPayload, // the original payload
450
+ 'type': currencyType,
451
+ 'name': name,
452
+ 'active': true,
453
+ 'deposit': undefined,
454
+ 'withdraw': undefined,
455
+ 'fee': this.safeNumber (description['fees']['funding']['withdraw'], code),
456
+ 'precision': precision,
457
+ 'limits': {
458
+ 'amount': {
459
+ 'min': Math.pow (10, -precision),
460
+ 'max': undefined,
461
+ },
462
+ 'price': {
463
+ 'min': Math.pow (10, -precision),
464
+ 'max': undefined,
465
+ },
466
+ 'cost': {
467
+ 'min': minCost,
468
+ 'max': undefined,
469
+ },
470
+ 'withdraw': {
471
+ 'min': undefined,
472
+ 'max': undefined,
473
+ },
474
+ },
475
+ };
476
+ }
477
+
478
+ async fetchMarketsFromCache (params = {}) {
479
+ // this method is now redundant
480
+ // currencies are now fetched before markets
481
+ const options = this.safeValue (this.options, 'fetchMarkets', {});
482
+ const timestamp = this.safeInteger (options, 'timestamp');
483
+ const expires = this.safeInteger (options, 'expires', 1000);
484
+ const now = this.milliseconds ();
485
+ if ((timestamp === undefined) || ((now - timestamp) > expires)) {
486
+ const response = await this.publicGetTradingPairsInfo (params);
487
+ this.options['fetchMarkets'] = this.extend (options, {
488
+ 'response': response,
489
+ 'timestamp': now,
490
+ });
491
+ }
492
+ return this.safeValue (this.options['fetchMarkets'], 'response');
493
+ }
494
+
495
+ async fetchCurrencies (params = {}) {
496
+ const response = await this.fetchMarketsFromCache (params);
497
+ //
498
+ // [
499
+ // {
500
+ // "trading": "Enabled",
501
+ // "base_decimals": 8,
502
+ // "url_symbol": "btcusd",
503
+ // "name": "BTC/USD",
504
+ // "instant_and_market_orders": "Enabled",
505
+ // "minimum_order": "20.0 USD",
506
+ // "counter_decimals": 2,
507
+ // "description": "Bitcoin / U.S. dollar"
508
+ // },
509
+ // ]
510
+ //
511
+ const result = {};
512
+ for (let i = 0; i < response.length; i++) {
513
+ const market = response[i];
514
+ const name = this.safeString (market, 'name');
515
+ let [ base, quote ] = name.split ('/');
516
+ const baseId = base.toLowerCase ();
517
+ const quoteId = quote.toLowerCase ();
518
+ base = this.safeCurrencyCode (base);
519
+ quote = this.safeCurrencyCode (quote);
520
+ const description = this.safeString (market, 'description');
521
+ const [ baseDescription, quoteDescription ] = description.split (' / ');
522
+ const minimumOrder = this.safeString (market, 'minimum_order');
523
+ const parts = minimumOrder.split (' ');
524
+ const cost = parts[0];
525
+ if (!(base in result)) {
526
+ const baseDecimals = this.safeInteger (market, 'base_decimals');
527
+ result[base] = this.constructCurrencyObject (baseId, base, baseDescription, baseDecimals, undefined, market);
528
+ }
529
+ if (!(quote in result)) {
530
+ const counterDecimals = this.safeInteger (market, 'counter_decimals');
531
+ result[quote] = this.constructCurrencyObject (quoteId, quote, quoteDescription, counterDecimals, this.parseNumber (cost), market);
532
+ }
533
+ }
534
+ return result;
535
+ }
536
+
537
+ async fetchOrderBook (symbol, limit = undefined, params = {}) {
538
+ await this.loadMarkets ();
539
+ const request = {
540
+ 'pair': this.marketId (symbol),
541
+ };
542
+ const response = await this.publicGetOrderBookPair (this.extend (request, params));
543
+ //
544
+ // {
545
+ // "timestamp": "1583652948",
546
+ // "microtimestamp": "1583652948955826",
547
+ // "bids": [
548
+ // [ "8750.00", "1.33685271" ],
549
+ // [ "8749.39", "0.07700000" ],
550
+ // [ "8746.98", "0.07400000" ],
551
+ // ]
552
+ // "asks": [
553
+ // [ "8754.10", "1.51995636" ],
554
+ // [ "8754.71", "1.40000000" ],
555
+ // [ "8754.72", "2.50000000" ],
556
+ // ]
557
+ // }
558
+ //
559
+ const microtimestamp = this.safeInteger (response, 'microtimestamp');
560
+ const timestamp = parseInt (microtimestamp / 1000);
561
+ const orderbook = this.parseOrderBook (response, symbol, timestamp);
562
+ orderbook['nonce'] = microtimestamp;
563
+ return orderbook;
564
+ }
565
+
566
+ parseTicker (ticker, market = undefined) {
567
+ //
568
+ // {
569
+ // "high": "37534.15",
570
+ // "last": "36487.44",
571
+ // "timestamp":
572
+ // "1643370585",
573
+ // "bid": "36475.15",
574
+ // "vwap": "36595.67",
575
+ // "volume": "2848.49168527",
576
+ // "low": "35511.32",
577
+ // "ask": "36487.44",
578
+ // "open": "37179.62"
579
+ // }
580
+ //
581
+ const symbol = this.safeSymbol (undefined, market);
582
+ const timestamp = this.safeTimestamp (ticker, 'timestamp');
583
+ const vwap = this.safeString (ticker, 'vwap');
584
+ const baseVolume = this.safeString (ticker, 'volume');
585
+ const quoteVolume = Precise.stringMul (baseVolume, vwap);
586
+ const last = this.safeString (ticker, 'last');
587
+ return this.safeTicker ({
588
+ 'symbol': symbol,
589
+ 'timestamp': timestamp,
590
+ 'datetime': this.iso8601 (timestamp),
591
+ 'high': this.safeString (ticker, 'high'),
592
+ 'low': this.safeString (ticker, 'low'),
593
+ 'bid': this.safeString (ticker, 'bid'),
594
+ 'bidVolume': undefined,
595
+ 'ask': this.safeString (ticker, 'ask'),
596
+ 'askVolume': undefined,
597
+ 'vwap': vwap,
598
+ 'open': this.safeString (ticker, 'open'),
599
+ 'close': last,
600
+ 'last': last,
601
+ 'previousClose': undefined,
602
+ 'change': undefined,
603
+ 'percentage': undefined,
604
+ 'average': undefined,
605
+ 'baseVolume': baseVolume,
606
+ 'quoteVolume': quoteVolume,
607
+ 'info': ticker,
608
+ }, market, false);
609
+ }
610
+
611
+ async fetchTicker (symbol, params = {}) {
612
+ await this.loadMarkets ();
613
+ const market = this.market (symbol);
614
+ const request = {
615
+ 'pair': market['id'],
616
+ };
617
+ const ticker = await this.publicGetTickerPair (this.extend (request, params));
618
+ //
619
+ // {
620
+ // "high": "37534.15",
621
+ // "last": "36487.44",
622
+ // "timestamp":
623
+ // "1643370585",
624
+ // "bid": "36475.15",
625
+ // "vwap": "36595.67",
626
+ // "volume": "2848.49168527",
627
+ // "low": "35511.32",
628
+ // "ask": "36487.44",
629
+ // "open": "37179.62"
630
+ // }
631
+ //
632
+ return this.parseTicker (ticker, market);
633
+ }
634
+
635
+ getCurrencyIdFromTransaction (transaction) {
636
+ //
637
+ // {
638
+ // "fee": "0.00000000",
639
+ // "btc_usd": "0.00",
640
+ // "datetime": XXX,
641
+ // "usd": 0.0,
642
+ // "btc": 0.0,
643
+ // "eth": "0.05000000",
644
+ // "type": "0",
645
+ // "id": XXX,
646
+ // "eur": 0.0
647
+ // }
648
+ //
649
+ const currencyId = this.safeStringLower (transaction, 'currency');
650
+ if (currencyId !== undefined) {
651
+ return currencyId;
652
+ }
653
+ transaction = this.omit (transaction, [
654
+ 'fee',
655
+ 'price',
656
+ 'datetime',
657
+ 'type',
658
+ 'status',
659
+ 'id',
660
+ ]);
661
+ const ids = Object.keys (transaction);
662
+ for (let i = 0; i < ids.length; i++) {
663
+ const id = ids[i];
664
+ if (id.indexOf ('_') < 0) {
665
+ const value = this.safeNumber (transaction, id);
666
+ if ((value !== undefined) && (value !== 0)) {
667
+ return id;
668
+ }
669
+ }
670
+ }
671
+ return undefined;
672
+ }
673
+
674
+ getMarketFromTrade (trade) {
675
+ trade = this.omit (trade, [
676
+ 'fee',
677
+ 'price',
678
+ 'datetime',
679
+ 'tid',
680
+ 'type',
681
+ 'order_id',
682
+ 'side',
683
+ ]);
684
+ const currencyIds = Object.keys (trade);
685
+ const numCurrencyIds = currencyIds.length;
686
+ if (numCurrencyIds > 2) {
687
+ throw new ExchangeError (this.id + ' getMarketFromTrade() too many keys: ' + this.json (currencyIds) + ' in the trade: ' + this.json (trade));
688
+ }
689
+ if (numCurrencyIds === 2) {
690
+ let marketId = currencyIds[0] + currencyIds[1];
691
+ if (marketId in this.markets_by_id) {
692
+ return this.markets_by_id[marketId];
693
+ }
694
+ marketId = currencyIds[1] + currencyIds[0];
695
+ if (marketId in this.markets_by_id) {
696
+ return this.markets_by_id[marketId];
697
+ }
698
+ }
699
+ return undefined;
700
+ }
701
+
702
+ parseTrade (trade, market = undefined) {
703
+ //
704
+ // fetchTrades (public)
705
+ //
706
+ // {
707
+ // "date": "1637845199",
708
+ // "tid": "209895701",
709
+ // "amount": "0.00500000",
710
+ // "type": "0", // Transaction type: 0 - buy; 1 - sell
711
+ // "price": "4451.25"
712
+ // }
713
+ //
714
+ // fetchMyTrades, trades returned within fetchOrder (private)
715
+ //
716
+ // {
717
+ // "fee": "0.11128",
718
+ // "eth_usdt": 4451.25,
719
+ // "datetime": "2021-11-25 12:59:59.322000",
720
+ // "usdt": "-22.26",
721
+ // "order_id": 1429545880227846,
722
+ // "usd": 0,
723
+ // "btc": 0,
724
+ // "eth": "0.00500000",
725
+ // "type": "2", // Transaction type: 0 - deposit; 1 - withdrawal; 2 - market trade; 14 - sub account transfer; 25 - credited with staked assets; 26 - sent assets to staking; 27 - staking reward; 32 - referral reward; 35 - inter account transfer.
726
+ // "id": 209895701,
727
+ // "eur": 0
728
+ // }
729
+ //
730
+ // from fetchOrder (private)
731
+ //
732
+ // {
733
+ // "fee": "0.11128",
734
+ // "price": "4451.25000000",
735
+ // "datetime": "2021-11-25 12:59:59.322000",
736
+ // "usdt": "22.25625000",
737
+ // "tid": 209895701,
738
+ // "eth": "0.00500000",
739
+ // "type": 2 // Transaction type: 0 - deposit; 1 - withdrawal; 2 - market trade
740
+ // }
741
+ //
742
+ const id = this.safeString2 (trade, 'id', 'tid');
743
+ let symbol = undefined;
744
+ let side = undefined;
745
+ let priceString = this.safeString (trade, 'price');
746
+ let amountString = this.safeString (trade, 'amount');
747
+ const orderId = this.safeString (trade, 'order_id');
748
+ const type = undefined;
749
+ let costString = this.safeString (trade, 'cost');
750
+ if (market === undefined) {
751
+ const keys = Object.keys (trade);
752
+ for (let i = 0; i < keys.length; i++) {
753
+ if (keys[i].indexOf ('_') >= 0) {
754
+ const marketId = keys[i].replace ('_', '');
755
+ if (marketId in this.markets_by_id) {
756
+ market = this.markets_by_id[marketId];
757
+ }
758
+ }
759
+ }
760
+ // if the market is still not defined
761
+ // try to deduce it from used keys
762
+ if (market === undefined) {
763
+ market = this.getMarketFromTrade (trade);
764
+ }
765
+ }
766
+ const feeCostString = this.safeString (trade, 'fee');
767
+ let feeCurrency = undefined;
768
+ if (market !== undefined) {
769
+ priceString = this.safeString (trade, market['marketId'], priceString);
770
+ amountString = this.safeString (trade, market['baseId'], amountString);
771
+ costString = this.safeString (trade, market['quoteId'], costString);
772
+ feeCurrency = market['quote'];
773
+ symbol = market['symbol'];
774
+ }
775
+ let timestamp = this.safeString2 (trade, 'date', 'datetime');
776
+ if (timestamp !== undefined) {
777
+ if (timestamp.indexOf (' ') >= 0) {
778
+ // iso8601
779
+ timestamp = this.parse8601 (timestamp);
780
+ } else {
781
+ // string unix epoch in seconds
782
+ timestamp = parseInt (timestamp);
783
+ timestamp = timestamp * 1000;
784
+ }
785
+ }
786
+ // if it is a private trade
787
+ if ('id' in trade) {
788
+ if (amountString !== undefined) {
789
+ const isAmountNeg = Precise.stringLt (amountString, '0');
790
+ if (isAmountNeg) {
791
+ side = 'sell';
792
+ amountString = Precise.stringNeg (amountString);
793
+ } else {
794
+ side = 'buy';
795
+ }
796
+ }
797
+ } else {
798
+ side = this.safeString (trade, 'type');
799
+ if (side === '1') {
800
+ side = 'sell';
801
+ } else if (side === '0') {
802
+ side = 'buy';
803
+ } else {
804
+ side = undefined;
805
+ }
806
+ }
807
+ if (costString !== undefined) {
808
+ costString = Precise.stringAbs (costString);
809
+ }
810
+ let fee = undefined;
811
+ if (feeCostString !== undefined) {
812
+ fee = {
813
+ 'cost': feeCostString,
814
+ 'currency': feeCurrency,
815
+ };
816
+ }
817
+ return this.safeTrade ({
818
+ 'id': id,
819
+ 'info': trade,
820
+ 'timestamp': timestamp,
821
+ 'datetime': this.iso8601 (timestamp),
822
+ 'symbol': symbol,
823
+ 'order': orderId,
824
+ 'type': type,
825
+ 'side': side,
826
+ 'takerOrMaker': undefined,
827
+ 'price': priceString,
828
+ 'amount': amountString,
829
+ 'cost': costString,
830
+ 'fee': fee,
831
+ }, market);
832
+ }
833
+
834
+ async fetchTrades (symbol, since = undefined, limit = undefined, params = {}) {
835
+ await this.loadMarkets ();
836
+ const market = this.market (symbol);
837
+ const request = {
838
+ 'pair': market['id'],
839
+ 'time': 'hour',
840
+ };
841
+ const response = await this.publicGetTransactionsPair (this.extend (request, params));
842
+ //
843
+ // [
844
+ // {
845
+ // date: '1551814435',
846
+ // tid: '83581898',
847
+ // price: '0.03532850',
848
+ // type: '1',
849
+ // amount: '0.85945907'
850
+ // },
851
+ // {
852
+ // date: '1551814434',
853
+ // tid: '83581896',
854
+ // price: '0.03532851',
855
+ // type: '1',
856
+ // amount: '11.34130961'
857
+ // },
858
+ // ]
859
+ //
860
+ return this.parseTrades (response, market, since, limit);
861
+ }
862
+
863
+ parseOHLCV (ohlcv, market = undefined) {
864
+ //
865
+ // {
866
+ // "high": "9064.77",
867
+ // "timestamp": "1593961440",
868
+ // "volume": "18.49436608",
869
+ // "low": "9040.87",
870
+ // "close": "9064.77",
871
+ // "open": "9040.87"
872
+ // }
873
+ //
874
+ return [
875
+ this.safeTimestamp (ohlcv, 'timestamp'),
876
+ this.safeNumber (ohlcv, 'open'),
877
+ this.safeNumber (ohlcv, 'high'),
878
+ this.safeNumber (ohlcv, 'low'),
879
+ this.safeNumber (ohlcv, 'close'),
880
+ this.safeNumber (ohlcv, 'volume'),
881
+ ];
882
+ }
883
+
884
+ async fetchOHLCV (symbol, timeframe = '1m', since = undefined, limit = undefined, params = {}) {
885
+ await this.loadMarkets ();
886
+ const market = this.market (symbol);
887
+ const request = {
888
+ 'pair': market['id'],
889
+ 'step': this.timeframes[timeframe],
890
+ };
891
+ const duration = this.parseTimeframe (timeframe);
892
+ if (limit === undefined) {
893
+ if (since === undefined) {
894
+ throw new ArgumentsRequired (this.id + ' fetchOHLCV() requires a since argument or a limit argument');
895
+ } else {
896
+ limit = 1000;
897
+ const start = parseInt (since / 1000);
898
+ request['start'] = start;
899
+ request['end'] = this.sum (start, limit * duration);
900
+ request['limit'] = limit;
901
+ }
902
+ } else {
903
+ if (since !== undefined) {
904
+ const start = parseInt (since / 1000);
905
+ request['start'] = start;
906
+ request['end'] = this.sum (start, limit * duration);
907
+ }
908
+ request['limit'] = Math.min (limit, 1000); // min 1, max 1000
909
+ }
910
+ const response = await this.publicGetOhlcPair (this.extend (request, params));
911
+ //
912
+ // {
913
+ // "data": {
914
+ // "pair": "BTC/USD",
915
+ // "ohlc": [
916
+ // {"high": "9064.77", "timestamp": "1593961440", "volume": "18.49436608", "low": "9040.87", "close": "9064.77", "open": "9040.87"},
917
+ // {"high": "9071.59", "timestamp": "1593961500", "volume": "3.48631711", "low": "9058.76", "close": "9061.07", "open": "9064.66"},
918
+ // {"high": "9067.33", "timestamp": "1593961560", "volume": "0.04142833", "low": "9061.94", "close": "9061.94", "open": "9067.33"},
919
+ // ],
920
+ // }
921
+ // }
922
+ //
923
+ const data = this.safeValue (response, 'data', {});
924
+ const ohlc = this.safeValue (data, 'ohlc', []);
925
+ return this.parseOHLCVs (ohlc, market, timeframe, since, limit);
926
+ }
927
+
928
+ parseBalance (response) {
929
+ const result = {
930
+ 'info': response,
931
+ 'timestamp': undefined,
932
+ 'datetime': undefined,
933
+ };
934
+ const codes = Object.keys (this.currencies);
935
+ for (let i = 0; i < codes.length; i++) {
936
+ const code = codes[i];
937
+ const currency = this.currency (code);
938
+ const currencyId = currency['id'];
939
+ const account = this.account ();
940
+ account['free'] = this.safeString (response, currencyId + '_available');
941
+ account['used'] = this.safeString (response, currencyId + '_reserved');
942
+ account['total'] = this.safeString (response, currencyId + '_balance');
943
+ result[code] = account;
944
+ }
945
+ return this.safeBalance (result);
946
+ }
947
+
948
+ async fetchBalance (params = {}) {
949
+ await this.loadMarkets ();
950
+ const response = await this.privatePostBalance (params);
951
+ //
952
+ // {
953
+ // "aave_available": "0.00000000",
954
+ // "aave_balance": "0.00000000",
955
+ // "aave_reserved": "0.00000000",
956
+ // "aave_withdrawal_fee": "0.07000000",
957
+ // "aavebtc_fee": "0.000",
958
+ // "aaveeur_fee": "0.000",
959
+ // "aaveusd_fee": "0.000",
960
+ // "bat_available": "0.00000000",
961
+ // "bat_balance": "0.00000000",
962
+ // "bat_reserved": "0.00000000",
963
+ // "bat_withdrawal_fee": "5.00000000",
964
+ // "batbtc_fee": "0.000",
965
+ // "bateur_fee": "0.000",
966
+ // "batusd_fee": "0.000",
967
+ // }
968
+ //
969
+ return this.parseBalance (response);
970
+ }
971
+
972
+ async fetchTradingFee (symbol, params = {}) {
973
+ await this.loadMarkets ();
974
+ const market = this.market (symbol);
975
+ const request = {
976
+ 'pair': market['id'],
977
+ };
978
+ const response = await this.privatePostBalancePair (this.extend (request, params));
979
+ return this.parseTradingFee (response, market);
980
+ }
981
+
982
+ parseTradingFee (fee, market = undefined) {
983
+ market = this.safeMarket (undefined, market);
984
+ const feeString = this.safeString (fee, market['id'] + '_fee');
985
+ const dividedFeeString = Precise.stringDiv (feeString, '100');
986
+ const tradeFee = this.parseNumber (dividedFeeString);
987
+ return {
988
+ 'info': fee,
989
+ 'symbol': market['symbol'],
990
+ 'maker': tradeFee,
991
+ 'taker': tradeFee,
992
+ };
993
+ }
994
+
995
+ parseTradingFees (fees) {
996
+ const result = { 'info': fees };
997
+ const symbols = this.symbols;
998
+ for (let i = 0; i < symbols.length; i++) {
999
+ const symbol = symbols[i];
1000
+ const market = this.market (symbol);
1001
+ const fee = this.parseTradingFee (fees, market);
1002
+ result[symbol] = fee;
1003
+ }
1004
+ return result;
1005
+ }
1006
+
1007
+ async fetchTradingFees (params = {}) {
1008
+ await this.loadMarkets ();
1009
+ const response = await this.privatePostBalance (params);
1010
+ return this.parseTradingFees (response);
1011
+ }
1012
+
1013
+ parseFundingFees (balance) {
1014
+ const withdraw = {};
1015
+ const ids = Object.keys (balance);
1016
+ for (let i = 0; i < ids.length; i++) {
1017
+ const id = ids[i];
1018
+ if (id.indexOf ('_withdrawal_fee') >= 0) {
1019
+ const currencyId = id.split ('_')[0];
1020
+ const code = this.safeCurrencyCode (currencyId);
1021
+ withdraw[code] = this.safeNumber (balance, id);
1022
+ }
1023
+ }
1024
+ return {
1025
+ 'info': balance,
1026
+ 'withdraw': withdraw,
1027
+ 'deposit': {},
1028
+ };
1029
+ }
1030
+
1031
+ async fetchFundingFees (params = {}) {
1032
+ await this.loadMarkets ();
1033
+ const balance = await this.privatePostBalance (params);
1034
+ return this.parseFundingFees (balance);
1035
+ }
1036
+
1037
+ async createOrder (symbol, type, side, amount, price = undefined, params = {}) {
1038
+ await this.loadMarkets ();
1039
+ const market = this.market (symbol);
1040
+ let method = 'privatePost' + this.capitalize (side);
1041
+ const request = {
1042
+ 'pair': market['id'],
1043
+ 'amount': this.amountToPrecision (symbol, amount),
1044
+ };
1045
+ if (type === 'market') {
1046
+ method += 'Market';
1047
+ } else if (type === 'instant') {
1048
+ method += 'Instant';
1049
+ } else {
1050
+ request['price'] = this.priceToPrecision (symbol, price);
1051
+ }
1052
+ method += 'Pair';
1053
+ const clientOrderId = this.safeString2 (params, 'client_order_id', 'clientOrderId');
1054
+ if (clientOrderId !== undefined) {
1055
+ request['client_order_id'] = clientOrderId;
1056
+ params = this.omit (params, [ 'client_order_id', 'clientOrderId' ]);
1057
+ }
1058
+ const response = await this[method] (this.extend (request, params));
1059
+ const order = this.parseOrder (response, market);
1060
+ return this.extend (order, {
1061
+ 'type': type,
1062
+ });
1063
+ }
1064
+
1065
+ async cancelOrder (id, symbol = undefined, params = {}) {
1066
+ await this.loadMarkets ();
1067
+ const request = {
1068
+ 'id': id,
1069
+ };
1070
+ return await this.privatePostCancelOrder (this.extend (request, params));
1071
+ }
1072
+
1073
+ async cancelAllOrders (symbol = undefined, params = {}) {
1074
+ await this.loadMarkets ();
1075
+ let market = undefined;
1076
+ const request = {};
1077
+ let method = 'privatePostCancelAllOrders';
1078
+ if (symbol !== undefined) {
1079
+ market = this.market (symbol);
1080
+ request['pair'] = market['id'];
1081
+ method = 'privatePostCancelAllOrdersPair';
1082
+ }
1083
+ return await this[method] (this.extend (request, params));
1084
+ }
1085
+
1086
+ parseOrderStatus (status) {
1087
+ const statuses = {
1088
+ 'In Queue': 'open',
1089
+ 'Open': 'open',
1090
+ 'Finished': 'closed',
1091
+ 'Canceled': 'canceled',
1092
+ };
1093
+ return this.safeString (statuses, status, status);
1094
+ }
1095
+
1096
+ async fetchOrderStatus (id, symbol = undefined, params = {}) {
1097
+ await this.loadMarkets ();
1098
+ const clientOrderId = this.safeValue2 (params, 'client_order_id', 'clientOrderId');
1099
+ const request = {};
1100
+ if (clientOrderId !== undefined) {
1101
+ request['client_order_id'] = clientOrderId;
1102
+ params = this.omit (params, [ 'client_order_id', 'clientOrderId' ]);
1103
+ } else {
1104
+ request['id'] = id;
1105
+ }
1106
+ const response = await this.privatePostOrderStatus (this.extend (request, params));
1107
+ return this.parseOrderStatus (this.safeString (response, 'status'));
1108
+ }
1109
+
1110
+ async fetchOrder (id, symbol = undefined, params = {}) {
1111
+ await this.loadMarkets ();
1112
+ let market = undefined;
1113
+ if (symbol !== undefined) {
1114
+ market = this.market (symbol);
1115
+ }
1116
+ const clientOrderId = this.safeValue2 (params, 'client_order_id', 'clientOrderId');
1117
+ const request = {};
1118
+ if (clientOrderId !== undefined) {
1119
+ request['client_order_id'] = clientOrderId;
1120
+ params = this.omit (params, [ 'client_order_id', 'clientOrderId' ]);
1121
+ } else {
1122
+ request['id'] = id;
1123
+ }
1124
+ const response = await this.privatePostOrderStatus (this.extend (request, params));
1125
+ //
1126
+ // {
1127
+ // "status": "Finished",
1128
+ // "id": 1429545880227846,
1129
+ // "amount_remaining": "0.00000000",
1130
+ // "transactions": [
1131
+ // {
1132
+ // "fee": "0.11128",
1133
+ // "price": "4451.25000000",
1134
+ // "datetime": "2021-11-25 12:59:59.322000",
1135
+ // "usdt": "22.25625000",
1136
+ // "tid": 209895701,
1137
+ // "eth": "0.00500000",
1138
+ // "type": 2
1139
+ // }
1140
+ // ]
1141
+ // }
1142
+ //
1143
+ return this.parseOrder (response, market);
1144
+ }
1145
+
1146
+ async fetchMyTrades (symbol = undefined, since = undefined, limit = undefined, params = {}) {
1147
+ await this.loadMarkets ();
1148
+ const request = {};
1149
+ let method = 'privatePostUserTransactions';
1150
+ let market = undefined;
1151
+ if (symbol !== undefined) {
1152
+ market = this.market (symbol);
1153
+ request['pair'] = market['id'];
1154
+ method += 'Pair';
1155
+ }
1156
+ if (limit !== undefined) {
1157
+ request['limit'] = limit;
1158
+ }
1159
+ const response = await this[method] (this.extend (request, params));
1160
+ const result = this.filterBy (response, 'type', '2');
1161
+ return this.parseTrades (result, market, since, limit);
1162
+ }
1163
+
1164
+ async fetchTransactions (code = undefined, since = undefined, limit = undefined, params = {}) {
1165
+ await this.loadMarkets ();
1166
+ const request = {};
1167
+ if (limit !== undefined) {
1168
+ request['limit'] = limit;
1169
+ }
1170
+ const response = await this.privatePostUserTransactions (this.extend (request, params));
1171
+ //
1172
+ // [
1173
+ // {
1174
+ // "fee": "0.00000000",
1175
+ // "btc_usd": "0.00",
1176
+ // "id": 1234567894,
1177
+ // "usd": 0,
1178
+ // "btc": 0,
1179
+ // "datetime": "2018-09-08 09:00:31",
1180
+ // "type": "1",
1181
+ // "xrp": "-20.00000000",
1182
+ // "eur": 0,
1183
+ // },
1184
+ // {
1185
+ // "fee": "0.00000000",
1186
+ // "btc_usd": "0.00",
1187
+ // "id": 1134567891,
1188
+ // "usd": 0,
1189
+ // "btc": 0,
1190
+ // "datetime": "2018-09-07 18:47:52",
1191
+ // "type": "0",
1192
+ // "xrp": "20.00000000",
1193
+ // "eur": 0,
1194
+ // },
1195
+ // ]
1196
+ //
1197
+ let currency = undefined;
1198
+ if (code !== undefined) {
1199
+ currency = this.currency (code);
1200
+ }
1201
+ const transactions = this.filterByArray (response, 'type', [ '0', '1' ], false);
1202
+ return this.parseTransactions (transactions, currency, since, limit);
1203
+ }
1204
+
1205
+ async fetchWithdrawals (code = undefined, since = undefined, limit = undefined, params = {}) {
1206
+ await this.loadMarkets ();
1207
+ const request = {};
1208
+ if (since !== undefined) {
1209
+ request['timedelta'] = this.milliseconds () - since;
1210
+ } else {
1211
+ request['timedelta'] = 50000000; // use max bitstamp approved value
1212
+ }
1213
+ const response = await this.privatePostWithdrawalRequests (this.extend (request, params));
1214
+ //
1215
+ // [
1216
+ // {
1217
+ // status: 2,
1218
+ // datetime: '2018-10-17 10:58:13',
1219
+ // currency: 'BTC',
1220
+ // amount: '0.29669259',
1221
+ // address: 'aaaaa',
1222
+ // type: 1,
1223
+ // id: 111111,
1224
+ // transaction_id: 'xxxx',
1225
+ // },
1226
+ // {
1227
+ // status: 2,
1228
+ // datetime: '2018-10-17 10:55:17',
1229
+ // currency: 'ETH',
1230
+ // amount: '1.11010664',
1231
+ // address: 'aaaa',
1232
+ // type: 16,
1233
+ // id: 222222,
1234
+ // transaction_id: 'xxxxx',
1235
+ // },
1236
+ // ]
1237
+ //
1238
+ return this.parseTransactions (response, undefined, since, limit);
1239
+ }
1240
+
1241
+ parseTransaction (transaction, currency = undefined) {
1242
+ //
1243
+ // fetchTransactions
1244
+ //
1245
+ // {
1246
+ // "fee": "0.00000000",
1247
+ // "btc_usd": "0.00",
1248
+ // "id": 1234567894,
1249
+ // "usd": 0,
1250
+ // "btc": 0,
1251
+ // "datetime": "2018-09-08 09:00:31",
1252
+ // "type": "1",
1253
+ // "xrp": "-20.00000000",
1254
+ // "eur": 0,
1255
+ // }
1256
+ //
1257
+ // fetchWithdrawals
1258
+ //
1259
+ // {
1260
+ // status: 2,
1261
+ // datetime: '2018-10-17 10:58:13',
1262
+ // currency: 'BTC',
1263
+ // amount: '0.29669259',
1264
+ // address: 'aaaaa',
1265
+ // type: 1,
1266
+ // id: 111111,
1267
+ // transaction_id: 'xxxx',
1268
+ // }
1269
+ //
1270
+ // {
1271
+ // "id": 3386432,
1272
+ // "type": 14,
1273
+ // "amount": "863.21332500",
1274
+ // "status": 2,
1275
+ // "address": "rE1sdh25BJQ3qFwngiTBwaq3zPGGYcrjp1?dt=1455",
1276
+ // "currency": "XRP",
1277
+ // "datetime": "2018-01-05 15:27:55",
1278
+ // "transaction_id": "001743B03B0C79BA166A064AC0142917B050347B4CB23BA2AB4B91B3C5608F4C"
1279
+ // }
1280
+ //
1281
+ const timestamp = this.parse8601 (this.safeString (transaction, 'datetime'));
1282
+ const id = this.safeString (transaction, 'id');
1283
+ const currencyId = this.getCurrencyIdFromTransaction (transaction);
1284
+ const code = this.safeCurrencyCode (currencyId, currency);
1285
+ const feeCost = this.safeNumber (transaction, 'fee');
1286
+ let feeCurrency = undefined;
1287
+ let amount = undefined;
1288
+ if ('amount' in transaction) {
1289
+ amount = this.safeNumber (transaction, 'amount');
1290
+ } else if (currency !== undefined) {
1291
+ amount = this.safeNumber (transaction, currency['id'], amount);
1292
+ feeCurrency = currency['code'];
1293
+ } else if ((code !== undefined) && (currencyId !== undefined)) {
1294
+ amount = this.safeNumber (transaction, currencyId, amount);
1295
+ feeCurrency = code;
1296
+ }
1297
+ if (amount !== undefined) {
1298
+ // withdrawals have a negative amount
1299
+ amount = Math.abs (amount);
1300
+ }
1301
+ let status = 'ok';
1302
+ if ('status' in transaction) {
1303
+ status = this.parseTransactionStatus (this.safeString (transaction, 'status'));
1304
+ }
1305
+ let type = undefined;
1306
+ if ('type' in transaction) {
1307
+ // from fetchTransactions
1308
+ const rawType = this.safeString (transaction, 'type');
1309
+ if (rawType === '0') {
1310
+ type = 'deposit';
1311
+ } else if (rawType === '1') {
1312
+ type = 'withdrawal';
1313
+ }
1314
+ } else {
1315
+ // from fetchWithdrawals
1316
+ type = 'withdrawal';
1317
+ }
1318
+ const txid = this.safeString (transaction, 'transaction_id');
1319
+ let tag = undefined;
1320
+ let address = this.safeString (transaction, 'address');
1321
+ if (address !== undefined) {
1322
+ // dt (destination tag) is embedded into the address field
1323
+ const addressParts = address.split ('?dt=');
1324
+ const numParts = addressParts.length;
1325
+ if (numParts > 1) {
1326
+ address = addressParts[0];
1327
+ tag = addressParts[1];
1328
+ }
1329
+ }
1330
+ const addressFrom = undefined;
1331
+ const addressTo = address;
1332
+ const tagFrom = undefined;
1333
+ const tagTo = tag;
1334
+ let fee = undefined;
1335
+ if (feeCost !== undefined) {
1336
+ fee = {
1337
+ 'currency': feeCurrency,
1338
+ 'cost': feeCost,
1339
+ 'rate': undefined,
1340
+ };
1341
+ }
1342
+ return {
1343
+ 'info': transaction,
1344
+ 'id': id,
1345
+ 'txid': txid,
1346
+ 'timestamp': timestamp,
1347
+ 'datetime': this.iso8601 (timestamp),
1348
+ 'network': undefined,
1349
+ 'addressFrom': addressFrom,
1350
+ 'addressTo': addressTo,
1351
+ 'address': address,
1352
+ 'tagFrom': tagFrom,
1353
+ 'tagTo': tagTo,
1354
+ 'tag': tag,
1355
+ 'type': type,
1356
+ 'amount': amount,
1357
+ 'currency': code,
1358
+ 'status': status,
1359
+ 'updated': undefined,
1360
+ 'fee': fee,
1361
+ };
1362
+ }
1363
+
1364
+ parseTransactionStatus (status) {
1365
+ // withdrawals:
1366
+ // 0 (open), 1 (in process), 2 (finished), 3 (canceled) or 4 (failed).
1367
+ const statuses = {
1368
+ '0': 'pending', // Open
1369
+ '1': 'pending', // In process
1370
+ '2': 'ok', // Finished
1371
+ '3': 'canceled', // Canceled
1372
+ '4': 'failed', // Failed
1373
+ };
1374
+ return this.safeString (statuses, status, status);
1375
+ }
1376
+
1377
+ parseOrder (order, market = undefined) {
1378
+ // from fetch order:
1379
+ // { status: 'Finished',
1380
+ // id: 731693945,
1381
+ // client_order_id: '',
1382
+ // transactions:
1383
+ // [ { fee: '0.000019',
1384
+ // price: '0.00015803',
1385
+ // datetime: '2018-01-07 10:45:34.132551',
1386
+ // btc: '0.0079015000000000',
1387
+ // tid: 42777395,
1388
+ // type: 2,
1389
+ // xrp: '50.00000000' } ] }
1390
+ //
1391
+ // partially filled order:
1392
+ // { "id": 468646390,
1393
+ // "client_order_id": "",
1394
+ // "status": "Canceled",
1395
+ // "transactions": [{
1396
+ // "eth": "0.23000000",
1397
+ // "fee": "0.09",
1398
+ // "tid": 25810126,
1399
+ // "usd": "69.8947000000000000",
1400
+ // "type": 2,
1401
+ // "price": "303.89000000",
1402
+ // "datetime": "2017-11-11 07:22:20.710567"
1403
+ // }]}
1404
+ //
1405
+ // from create order response:
1406
+ // {
1407
+ // price: '0.00008012',
1408
+ // client_order_id: '',
1409
+ // currency_pair: 'XRP/BTC',
1410
+ // datetime: '2019-01-31 21:23:36',
1411
+ // amount: '15.00000000',
1412
+ // type: '0',
1413
+ // id: '2814205012'
1414
+ // }
1415
+ //
1416
+ const id = this.safeString (order, 'id');
1417
+ const clientOrderId = this.safeString (order, 'client_order_id');
1418
+ let side = this.safeString (order, 'type');
1419
+ if (side !== undefined) {
1420
+ side = (side === '1') ? 'sell' : 'buy';
1421
+ }
1422
+ // there is no timestamp from fetchOrder
1423
+ const timestamp = this.parse8601 (this.safeString (order, 'datetime'));
1424
+ const marketId = this.safeStringLower (order, 'currency_pair');
1425
+ const symbol = this.safeSymbol (marketId, market, '/');
1426
+ const status = this.parseOrderStatus (this.safeString (order, 'status'));
1427
+ const amount = this.safeString (order, 'amount');
1428
+ const transactions = this.safeValue (order, 'transactions', []);
1429
+ const price = this.safeString (order, 'price');
1430
+ return this.safeOrder ({
1431
+ 'id': id,
1432
+ 'clientOrderId': clientOrderId,
1433
+ 'datetime': this.iso8601 (timestamp),
1434
+ 'timestamp': timestamp,
1435
+ 'lastTradeTimestamp': undefined,
1436
+ 'status': status,
1437
+ 'symbol': symbol,
1438
+ 'type': undefined,
1439
+ 'timeInForce': undefined,
1440
+ 'postOnly': undefined,
1441
+ 'side': side,
1442
+ 'price': price,
1443
+ 'stopPrice': undefined,
1444
+ 'cost': undefined,
1445
+ 'amount': amount,
1446
+ 'filled': undefined,
1447
+ 'remaining': undefined,
1448
+ 'trades': transactions,
1449
+ 'fee': undefined,
1450
+ 'info': order,
1451
+ 'average': undefined,
1452
+ }, market);
1453
+ }
1454
+
1455
+ parseLedgerEntryType (type) {
1456
+ const types = {
1457
+ '0': 'transaction',
1458
+ '1': 'transaction',
1459
+ '2': 'trade',
1460
+ '14': 'transfer',
1461
+ };
1462
+ return this.safeString (types, type, type);
1463
+ }
1464
+
1465
+ parseLedgerEntry (item, currency = undefined) {
1466
+ //
1467
+ // [
1468
+ // {
1469
+ // "fee": "0.00000000",
1470
+ // "btc_usd": "0.00",
1471
+ // "id": 1234567894,
1472
+ // "usd": 0,
1473
+ // "btc": 0,
1474
+ // "datetime": "2018-09-08 09:00:31",
1475
+ // "type": "1",
1476
+ // "xrp": "-20.00000000",
1477
+ // "eur": 0,
1478
+ // },
1479
+ // {
1480
+ // "fee": "0.00000000",
1481
+ // "btc_usd": "0.00",
1482
+ // "id": 1134567891,
1483
+ // "usd": 0,
1484
+ // "btc": 0,
1485
+ // "datetime": "2018-09-07 18:47:52",
1486
+ // "type": "0",
1487
+ // "xrp": "20.00000000",
1488
+ // "eur": 0,
1489
+ // },
1490
+ // ]
1491
+ //
1492
+ const type = this.parseLedgerEntryType (this.safeString (item, 'type'));
1493
+ if (type === 'trade') {
1494
+ const parsedTrade = this.parseTrade (item);
1495
+ let market = undefined;
1496
+ const keys = Object.keys (item);
1497
+ for (let i = 0; i < keys.length; i++) {
1498
+ if (keys[i].indexOf ('_') >= 0) {
1499
+ const marketId = keys[i].replace ('_', '');
1500
+ if (marketId in this.markets_by_id) {
1501
+ market = this.markets_by_id[marketId];
1502
+ }
1503
+ }
1504
+ }
1505
+ // if the market is still not defined
1506
+ // try to deduce it from used keys
1507
+ if (market === undefined) {
1508
+ market = this.getMarketFromTrade (item);
1509
+ }
1510
+ const direction = (parsedTrade['side'] === 'buy') ? 'in' : 'out';
1511
+ return {
1512
+ 'id': parsedTrade['id'],
1513
+ 'info': item,
1514
+ 'timestamp': parsedTrade['timestamp'],
1515
+ 'datetime': parsedTrade['datetime'],
1516
+ 'direction': direction,
1517
+ 'account': undefined,
1518
+ 'referenceId': parsedTrade['order'],
1519
+ 'referenceAccount': undefined,
1520
+ 'type': type,
1521
+ 'currency': market['base'],
1522
+ 'amount': parsedTrade['amount'],
1523
+ 'before': undefined,
1524
+ 'after': undefined,
1525
+ 'status': 'ok',
1526
+ 'fee': parsedTrade['fee'],
1527
+ };
1528
+ } else {
1529
+ const parsedTransaction = this.parseTransaction (item, currency);
1530
+ let direction = undefined;
1531
+ if ('amount' in item) {
1532
+ const amount = this.safeNumber (item, 'amount');
1533
+ direction = (amount > 0) ? 'in' : 'out';
1534
+ } else if (('currency' in parsedTransaction) && parsedTransaction['currency'] !== undefined) {
1535
+ const currencyCode = this.safeString (parsedTransaction, 'currency');
1536
+ currency = this.currency (currencyCode);
1537
+ const amount = this.safeNumber (item, currency['id']);
1538
+ direction = (amount > 0) ? 'in' : 'out';
1539
+ }
1540
+ return {
1541
+ 'id': parsedTransaction['id'],
1542
+ 'info': item,
1543
+ 'timestamp': parsedTransaction['timestamp'],
1544
+ 'datetime': parsedTransaction['datetime'],
1545
+ 'direction': direction,
1546
+ 'account': undefined,
1547
+ 'referenceId': parsedTransaction['txid'],
1548
+ 'referenceAccount': undefined,
1549
+ 'type': type,
1550
+ 'currency': parsedTransaction['currency'],
1551
+ 'amount': parsedTransaction['amount'],
1552
+ 'before': undefined,
1553
+ 'after': undefined,
1554
+ 'status': parsedTransaction['status'],
1555
+ 'fee': parsedTransaction['fee'],
1556
+ };
1557
+ }
1558
+ }
1559
+
1560
+ async fetchLedger (code = undefined, since = undefined, limit = undefined, params = {}) {
1561
+ await this.loadMarkets ();
1562
+ const request = {};
1563
+ if (limit !== undefined) {
1564
+ request['limit'] = limit;
1565
+ }
1566
+ const response = await this.privatePostUserTransactions (this.extend (request, params));
1567
+ let currency = undefined;
1568
+ if (code !== undefined) {
1569
+ currency = this.currency (code);
1570
+ }
1571
+ return this.parseLedger (response, currency, since, limit);
1572
+ }
1573
+
1574
+ async fetchOpenOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) {
1575
+ let market = undefined;
1576
+ await this.loadMarkets ();
1577
+ if (symbol !== undefined) {
1578
+ market = this.market (symbol);
1579
+ }
1580
+ const response = await this.privatePostOpenOrdersAll (params);
1581
+ // [
1582
+ // {
1583
+ // price: '0.00008012',
1584
+ // currency_pair: 'XRP/BTC',
1585
+ // client_order_id: '',
1586
+ // datetime: '2019-01-31 21:23:36',
1587
+ // amount: '15.00000000',
1588
+ // type: '0',
1589
+ // id: '2814205012',
1590
+ // }
1591
+ // ]
1592
+ //
1593
+ return this.parseOrders (response, market, since, limit, {
1594
+ 'status': 'open',
1595
+ 'type': 'limit',
1596
+ });
1597
+ }
1598
+
1599
+ getCurrencyName (code) {
1600
+ return code.toLowerCase ();
1601
+ }
1602
+
1603
+ isFiat (code) {
1604
+ return code === 'USD' || code === 'EUR' || code === 'GBP';
1605
+ }
1606
+
1607
+ async fetchDepositAddress (code, params = {}) {
1608
+ if (this.isFiat (code)) {
1609
+ throw new NotSupported (this.id + ' fiat fetchDepositAddress() for ' + code + ' is not supported!');
1610
+ }
1611
+ const name = this.getCurrencyName (code);
1612
+ const method = 'privatePost' + this.capitalize (name) + 'Address';
1613
+ const response = await this[method] (params);
1614
+ const address = this.safeString (response, 'address');
1615
+ const tag = this.safeString2 (response, 'memo_id', 'destination_tag');
1616
+ this.checkAddress (address);
1617
+ return {
1618
+ 'currency': code,
1619
+ 'address': address,
1620
+ 'tag': tag,
1621
+ 'network': undefined,
1622
+ 'info': response,
1623
+ };
1624
+ }
1625
+
1626
+ async withdraw (code, amount, address, tag = undefined, params = {}) {
1627
+ // For fiat withdrawals please provide all required additional parameters in the 'params'
1628
+ // Check https://www.bitstamp.net/api/ under 'Open bank withdrawal' for list and description.
1629
+ [ tag, params ] = this.handleWithdrawTagAndParams (tag, params);
1630
+ await this.loadMarkets ();
1631
+ this.checkAddress (address);
1632
+ const request = {
1633
+ 'amount': amount,
1634
+ };
1635
+ let currency = undefined;
1636
+ let method = undefined;
1637
+ if (!this.isFiat (code)) {
1638
+ const name = this.getCurrencyName (code);
1639
+ method = 'privatePost' + this.capitalize (name) + 'Withdrawal';
1640
+ if (code === 'XRP') {
1641
+ if (tag !== undefined) {
1642
+ request['destination_tag'] = tag;
1643
+ }
1644
+ } else if (code === 'XLM' || code === 'HBAR') {
1645
+ if (tag !== undefined) {
1646
+ request['memo_id'] = tag;
1647
+ }
1648
+ }
1649
+ request['address'] = address;
1650
+ } else {
1651
+ method = 'privatePostWithdrawalOpen';
1652
+ currency = this.currency (code);
1653
+ request['iban'] = address;
1654
+ request['account_currency'] = currency['id'];
1655
+ }
1656
+ const response = await this[method] (this.extend (request, params));
1657
+ return this.parseTransaction (response, currency);
1658
+ }
1659
+
1660
+ nonce () {
1661
+ return this.milliseconds ();
1662
+ }
1663
+
1664
+ sign (path, api = 'public', method = 'GET', params = {}, headers = undefined, body = undefined) {
1665
+ let url = this.urls['api'][api] + '/';
1666
+ url += this.version + '/';
1667
+ url += this.implodeParams (path, params);
1668
+ const query = this.omit (params, this.extractParams (path));
1669
+ if (api === 'public') {
1670
+ if (Object.keys (query).length) {
1671
+ url += '?' + this.urlencode (query);
1672
+ }
1673
+ } else {
1674
+ this.checkRequiredCredentials ();
1675
+ const xAuth = 'BITSTAMP ' + this.apiKey;
1676
+ const xAuthNonce = this.uuid ();
1677
+ const xAuthTimestamp = this.milliseconds ().toString ();
1678
+ const xAuthVersion = 'v2';
1679
+ let contentType = '';
1680
+ headers = {
1681
+ 'X-Auth': xAuth,
1682
+ 'X-Auth-Nonce': xAuthNonce,
1683
+ 'X-Auth-Timestamp': xAuthTimestamp,
1684
+ 'X-Auth-Version': xAuthVersion,
1685
+ };
1686
+ if (method === 'POST') {
1687
+ if (Object.keys (query).length) {
1688
+ body = this.urlencode (query);
1689
+ contentType = 'application/x-www-form-urlencoded';
1690
+ headers['Content-Type'] = contentType;
1691
+ } else {
1692
+ // sending an empty POST request will trigger
1693
+ // an API0020 error returned by the exchange
1694
+ // therefore for empty requests we send a dummy object
1695
+ // https://github.com/ccxt/ccxt/issues/6846
1696
+ body = this.urlencode ({ 'foo': 'bar' });
1697
+ contentType = 'application/x-www-form-urlencoded';
1698
+ headers['Content-Type'] = contentType;
1699
+ }
1700
+ }
1701
+ const authBody = body ? body : '';
1702
+ const auth = xAuth + method + url.replace ('https://', '') + contentType + xAuthNonce + xAuthTimestamp + xAuthVersion + authBody;
1703
+ const signature = this.hmac (this.encode (auth), this.encode (this.secret));
1704
+ headers['X-Auth-Signature'] = signature;
1705
+ }
1706
+ return { 'url': url, 'method': method, 'body': body, 'headers': headers };
1707
+ }
1708
+
1709
+ handleErrors (httpCode, reason, url, method, headers, body, response, requestHeaders, requestBody) {
1710
+ if (response === undefined) {
1711
+ return;
1712
+ }
1713
+ //
1714
+ // {"error": "No permission found"} // fetchDepositAddress returns this on apiKeys that don't have the permission required
1715
+ // {"status": "error", "reason": {"__all__": ["Minimum order size is 5.0 EUR."]}}
1716
+ // reuse of a nonce gives: { status: 'error', reason: 'Invalid nonce', code: 'API0004' }
1717
+ const status = this.safeString (response, 'status');
1718
+ const error = this.safeValue (response, 'error');
1719
+ if ((status === 'error') || (error !== undefined)) {
1720
+ let errors = [];
1721
+ if (typeof error === 'string') {
1722
+ errors.push (error);
1723
+ } else if (error !== undefined) {
1724
+ const keys = Object.keys (error);
1725
+ for (let i = 0; i < keys.length; i++) {
1726
+ const key = keys[i];
1727
+ const value = this.safeValue (error, key);
1728
+ if (Array.isArray (value)) {
1729
+ errors = this.arrayConcat (errors, value);
1730
+ } else {
1731
+ errors.push (value);
1732
+ }
1733
+ }
1734
+ }
1735
+ const reason = this.safeValue (response, 'reason', {});
1736
+ if (typeof reason === 'string') {
1737
+ errors.push (reason);
1738
+ } else {
1739
+ const all = this.safeValue (reason, '__all__', []);
1740
+ for (let i = 0; i < all.length; i++) {
1741
+ errors.push (all[i]);
1742
+ }
1743
+ }
1744
+ const code = this.safeString (response, 'code');
1745
+ if (code === 'API0005') {
1746
+ throw new AuthenticationError (this.id + ' invalid signature, use the uid for the main account if you have subaccounts');
1747
+ }
1748
+ const feedback = this.id + ' ' + body;
1749
+ for (let i = 0; i < errors.length; i++) {
1750
+ const value = errors[i];
1751
+ this.throwExactlyMatchedException (this.exceptions['exact'], value, feedback);
1752
+ this.throwBroadlyMatchedException (this.exceptions['broad'], value, feedback);
1753
+ }
1754
+ throw new ExchangeError (feedback);
1755
+ }
1756
+ }
1757
+ };