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/kraken.js ADDED
@@ -0,0 +1,2179 @@
1
+ 'use strict';
2
+
3
+ // ---------------------------------------------------------------------------
4
+
5
+ const Exchange = require ('./base/Exchange');
6
+ const { BadSymbol, BadRequest, ExchangeNotAvailable, ArgumentsRequired, PermissionDenied, AuthenticationError, ExchangeError, OrderNotFound, DDoSProtection, InvalidNonce, InsufficientFunds, CancelPending, InvalidOrder, InvalidAddress, RateLimitExceeded, OnMaintenance } = require ('./base/errors');
7
+ const { TRUNCATE, DECIMAL_PLACES } = require ('./base/functions/number');
8
+ const Precise = require ('./base/Precise');
9
+
10
+ // ---------------------------------------------------------------------------
11
+
12
+ module.exports = class kraken extends Exchange {
13
+ describe () {
14
+ return this.deepExtend (super.describe (), {
15
+ 'id': 'kraken',
16
+ 'name': 'Kraken',
17
+ 'countries': [ 'US' ],
18
+ 'version': '0',
19
+ 'rateLimit': 3000,
20
+ 'certified': false,
21
+ 'pro': true,
22
+ 'has': {
23
+ 'CORS': undefined,
24
+ 'spot': true,
25
+ 'margin': true,
26
+ 'swap': false,
27
+ 'future': false,
28
+ 'option': false,
29
+ 'cancelAllOrders': true,
30
+ 'cancelOrder': true,
31
+ 'createDepositAddress': true,
32
+ 'createOrder': true,
33
+ 'createStopLimitOrder': true,
34
+ 'createStopMarketOrder': true,
35
+ 'createStopOrder': true,
36
+ 'fetchBalance': true,
37
+ 'fetchBorrowInterest': false,
38
+ 'fetchBorrowRate': false,
39
+ 'fetchBorrowRateHistories': false,
40
+ 'fetchBorrowRateHistory': false,
41
+ 'fetchBorrowRates': false,
42
+ 'fetchClosedOrders': true,
43
+ 'fetchCurrencies': true,
44
+ 'fetchDepositAddress': true,
45
+ 'fetchDeposits': true,
46
+ 'fetchFundingHistory': false,
47
+ 'fetchFundingRate': false,
48
+ 'fetchFundingRateHistory': false,
49
+ 'fetchFundingRates': false,
50
+ 'fetchIndexOHLCV': false,
51
+ 'fetchLedger': true,
52
+ 'fetchLedgerEntry': true,
53
+ 'fetchLeverageTiers': false,
54
+ 'fetchMarkets': true,
55
+ 'fetchMarkOHLCV': false,
56
+ 'fetchMyTrades': true,
57
+ 'fetchOHLCV': true,
58
+ 'fetchOpenOrders': true,
59
+ 'fetchOrder': true,
60
+ 'fetchOrderBook': true,
61
+ 'fetchOrderTrades': 'emulated',
62
+ 'fetchPositions': true,
63
+ 'fetchPremiumIndexOHLCV': false,
64
+ 'fetchTicker': true,
65
+ 'fetchTickers': true,
66
+ 'fetchTime': true,
67
+ 'fetchTrades': true,
68
+ 'fetchTradingFee': true,
69
+ 'fetchTradingFees': false,
70
+ 'fetchWithdrawals': true,
71
+ 'setLeverage': false,
72
+ 'setMarginMode': false, // Kraken only supports cross margin
73
+ 'withdraw': true,
74
+ },
75
+ 'marketsByAltname': {},
76
+ 'timeframes': {
77
+ '1m': 1,
78
+ '5m': 5,
79
+ '15m': 15,
80
+ '30m': 30,
81
+ '1h': 60,
82
+ '4h': 240,
83
+ '1d': 1440,
84
+ '1w': 10080,
85
+ '2w': 21600,
86
+ },
87
+ 'urls': {
88
+ 'logo': 'https://user-images.githubusercontent.com/51840849/76173629-fc67fb00-61b1-11ea-84fe-f2de582f58a3.jpg',
89
+ 'api': {
90
+ 'public': 'https://api.kraken.com',
91
+ 'private': 'https://api.kraken.com',
92
+ 'zendesk': 'https://kraken.zendesk.com/api/v2/help_center/en-us/articles', // use the public zendesk api to receive article bodies and bypass new anti-spam protections
93
+ },
94
+ 'www': 'https://www.kraken.com',
95
+ 'doc': 'https://www.kraken.com/features/api',
96
+ 'fees': 'https://www.kraken.com/en-us/features/fee-schedule',
97
+ },
98
+ 'fees': {
99
+ 'trading': {
100
+ 'tierBased': true,
101
+ 'percentage': true,
102
+ 'taker': 0.26 / 100,
103
+ 'maker': 0.16 / 100,
104
+ 'tiers': {
105
+ 'taker': [
106
+ [ 0, 0.0026 ],
107
+ [ 50000, 0.0024 ],
108
+ [ 100000, 0.0022 ],
109
+ [ 250000, 0.0020 ],
110
+ [ 500000, 0.0018 ],
111
+ [ 1000000, 0.0016 ],
112
+ [ 2500000, 0.0014 ],
113
+ [ 5000000, 0.0012 ],
114
+ [ 10000000, 0.0001 ],
115
+ ],
116
+ 'maker': [
117
+ [ 0, 0.0016 ],
118
+ [ 50000, 0.0014 ],
119
+ [ 100000, 0.0012 ],
120
+ [ 250000, 0.0010 ],
121
+ [ 500000, 0.0008 ],
122
+ [ 1000000, 0.0006 ],
123
+ [ 2500000, 0.0004 ],
124
+ [ 5000000, 0.0002 ],
125
+ [ 10000000, 0.0 ],
126
+ ],
127
+ },
128
+ },
129
+ },
130
+ 'handleContentTypeApplicationZip': true,
131
+ 'api': {
132
+ 'zendesk': {
133
+ 'get': [
134
+ // we should really refrain from putting fixed fee numbers and stop hardcoding
135
+ // we will be using their web APIs to scrape all numbers from these articles
136
+ '360000292886', // -What-are-the-deposit-fees-
137
+ '201893608', // -What-are-the-withdrawal-fees-
138
+ ],
139
+ },
140
+ 'public': {
141
+ 'get': [
142
+ 'Assets',
143
+ 'AssetPairs',
144
+ 'Depth',
145
+ 'OHLC',
146
+ 'Spread',
147
+ 'Ticker',
148
+ 'Time',
149
+ 'Trades',
150
+ ],
151
+ },
152
+ 'private': {
153
+ 'post': {
154
+ 'AddOrder': 0,
155
+ 'AddExport': 1,
156
+ 'Balance': 1,
157
+ 'CancelAll': 1,
158
+ 'CancelOrder': 0,
159
+ 'ClosedOrders': 2,
160
+ 'DepositAddresses': 1,
161
+ 'DepositMethods': 1,
162
+ 'DepositStatus': 1,
163
+ 'ExportStatus': 1,
164
+ 'GetWebSocketsToken': 1,
165
+ 'Ledgers': 2,
166
+ 'OpenOrders': 1,
167
+ 'OpenPositions': 1,
168
+ 'QueryLedgers': 1,
169
+ 'QueryOrders': 1,
170
+ 'QueryTrades': 1,
171
+ 'RetrieveExport': 1,
172
+ 'RemoveExport': 1,
173
+ 'TradeBalance': 1,
174
+ 'TradesHistory': 2,
175
+ 'TradeVolume': 1,
176
+ 'Withdraw': 1,
177
+ 'WithdrawCancel': 1,
178
+ 'WithdrawInfo': 1,
179
+ 'WithdrawStatus': 1,
180
+ // staking
181
+ 'Stake': 1,
182
+ 'Unstake': 1,
183
+ 'Staking/Assets': 1,
184
+ 'Staking/Pending': 1,
185
+ 'Staking/Transactions': 1,
186
+ },
187
+ },
188
+ },
189
+ 'commonCurrencies': {
190
+ 'XBT': 'BTC',
191
+ 'XBT.M': 'BTC.M', // https://support.kraken.com/hc/en-us/articles/360039879471-What-is-Asset-S-and-Asset-M-
192
+ 'XDG': 'DOGE',
193
+ 'REPV2': 'REP',
194
+ 'REP': 'REPV1',
195
+ },
196
+ 'options': {
197
+ 'delistedMarketsById': {},
198
+ // cannot withdraw/deposit these
199
+ 'inactiveCurrencies': [ 'CAD', 'USD', 'JPY', 'GBP' ],
200
+ 'networks': {
201
+ 'ETH': 'ERC20',
202
+ 'TRX': 'TRC20',
203
+ },
204
+ 'depositMethods': {
205
+ '1INCH': '1inch (1INCH)',
206
+ 'AAVE': 'Aave',
207
+ 'ADA': 'ADA',
208
+ 'ALGO': 'Algorand',
209
+ 'ANKR': 'ANKR (ANKR)',
210
+ 'ANT': 'Aragon (ANT)',
211
+ 'ATOM': 'Cosmos',
212
+ 'AXS': 'Axie Infinity Shards (AXS)',
213
+ 'BADGER': 'Bager DAO (BADGER)',
214
+ 'BAL': 'Balancer (BAL)',
215
+ 'BAND': 'Band Protocol (BAND)',
216
+ 'BAT': 'BAT',
217
+ 'BCH': 'Bitcoin Cash',
218
+ 'BNC': 'Bifrost (BNC)',
219
+ 'BNT': 'Bancor (BNT)',
220
+ 'BTC': 'Bitcoin',
221
+ 'CHZ': 'Chiliz (CHZ)',
222
+ 'COMP': 'Compound (COMP)',
223
+ 'CQT': '\tCovalent Query Token (CQT)',
224
+ 'CRV': 'Curve DAO Token (CRV)',
225
+ 'CTSI': 'Cartesi (CTSI)',
226
+ 'DAI': 'Dai',
227
+ 'DASH': 'Dash',
228
+ 'DOGE': 'Dogecoin',
229
+ 'DOT': 'Polkadot',
230
+ 'DYDX': 'dYdX (DYDX)',
231
+ 'ENJ': 'Enjin Coin (ENJ)',
232
+ 'EOS': 'EOS',
233
+ 'ETC': 'Ether Classic (Hex)',
234
+ 'ETH': 'Ether (Hex)',
235
+ 'EWT': 'Energy Web Token',
236
+ 'FEE': 'Kraken Fee Credit',
237
+ 'FIL': 'Filecoin',
238
+ 'FLOW': 'Flow',
239
+ 'GHST': 'Aavegotchi (GHST)',
240
+ 'GNO': 'GNO',
241
+ 'GRT': 'GRT',
242
+ 'ICX': 'Icon',
243
+ 'INJ': 'Injective Protocol (INJ)',
244
+ 'KAR': 'Karura (KAR)',
245
+ 'KAVA': 'Kava',
246
+ 'KEEP': 'Keep Token (KEEP)',
247
+ 'KNC': 'Kyber Network (KNC)',
248
+ 'KSM': 'Kusama',
249
+ 'LINK': 'Link',
250
+ 'LPT': 'Livepeer Token (LPT)',
251
+ 'LRC': 'Loopring (LRC)',
252
+ 'LSK': 'Lisk',
253
+ 'LTC': 'Litecoin',
254
+ 'MANA': 'MANA',
255
+ 'MATIC': 'Polygon (MATIC)',
256
+ 'MINA': 'Mina', // inspected from webui
257
+ 'MIR': 'Mirror Protocol (MIR)',
258
+ 'MKR': 'Maker (MKR)',
259
+ 'MLN': 'MLN',
260
+ 'MOVR': 'Moonriver (MOVR)',
261
+ 'NANO': 'NANO',
262
+ 'OCEAN': 'OCEAN',
263
+ 'OGN': 'Origin Protocol (OGN)',
264
+ 'OMG': 'OMG',
265
+ 'OXT': 'Orchid (OXT)',
266
+ 'OXY': 'Oxygen (OXY)',
267
+ 'PAXG': 'PAX (Gold)',
268
+ 'PERP': 'Perpetual Protocol (PERP)',
269
+ 'PHA': 'Phala (PHA)',
270
+ 'QTUM': 'QTUM',
271
+ 'RARI': 'Rarible (RARI)',
272
+ 'RAY': 'Raydium (RAY)',
273
+ 'REN': 'Ren Protocol (REN)',
274
+ 'REP': 'REPv2',
275
+ 'REPV1': 'REP',
276
+ 'SAND': 'The Sandbox (SAND)',
277
+ 'SC': 'Siacoin',
278
+ 'SDN': 'Shiden (SDN)',
279
+ 'SOL': 'Solana', // their deposit method api doesn't work for SOL - was guessed
280
+ 'SNX': 'Synthetix Network (SNX)',
281
+ 'SRM': 'Serum', // inspected from webui
282
+ 'STORJ': 'Storj (STORJ)',
283
+ 'SUSHI': 'Sushiswap (SUSHI)',
284
+ 'TBTC': 'tBTC',
285
+ 'TRX': 'Tron',
286
+ 'UNI': 'UNI',
287
+ 'USDC': 'USDC',
288
+ 'USDT': 'Tether USD (ERC20)',
289
+ 'USDT-TRC20': 'Tether USD (TRC20)',
290
+ 'WAVES': 'Waves',
291
+ 'WBTC': 'Wrapped Bitcoin (WBTC)',
292
+ 'XLM': 'Stellar XLM',
293
+ 'XMR': 'Monero',
294
+ 'XRP': 'Ripple XRP',
295
+ 'XTZ': 'XTZ',
296
+ 'YFI': 'YFI',
297
+ 'ZEC': 'Zcash (Transparent)',
298
+ 'ZRX': '0x (ZRX)',
299
+ },
300
+ },
301
+ 'exceptions': {
302
+ 'EQuery:Invalid asset pair': BadSymbol, // {"error":["EQuery:Invalid asset pair"]}
303
+ 'EAPI:Invalid key': AuthenticationError,
304
+ 'EFunding:Unknown withdraw key': InvalidAddress, // {"error":["EFunding:Unknown withdraw key"]}
305
+ 'EFunding:Invalid amount': InsufficientFunds,
306
+ 'EService:Unavailable': ExchangeNotAvailable,
307
+ 'EDatabase:Internal error': ExchangeNotAvailable,
308
+ 'EService:Busy': ExchangeNotAvailable,
309
+ 'EQuery:Unknown asset': BadSymbol, // {"error":["EQuery:Unknown asset"]}
310
+ 'EAPI:Rate limit exceeded': DDoSProtection,
311
+ 'EOrder:Rate limit exceeded': DDoSProtection,
312
+ 'EGeneral:Internal error': ExchangeNotAvailable,
313
+ 'EGeneral:Temporary lockout': DDoSProtection,
314
+ 'EGeneral:Permission denied': PermissionDenied,
315
+ 'EOrder:Unknown order': InvalidOrder,
316
+ 'EOrder:Order minimum not met': InvalidOrder,
317
+ 'EGeneral:Invalid arguments': BadRequest,
318
+ 'ESession:Invalid session': AuthenticationError,
319
+ 'EAPI:Invalid nonce': InvalidNonce,
320
+ 'EFunding:No funding method': BadRequest, // {"error":"EFunding:No funding method"}
321
+ 'EFunding:Unknown asset': BadSymbol, // {"error":["EFunding:Unknown asset"]}
322
+ 'EService:Market in post_only mode': OnMaintenance, // {"error":["EService:Market in post_only mode"]}
323
+ },
324
+ });
325
+ }
326
+
327
+ costToPrecision (symbol, cost) {
328
+ return this.decimalToPrecision (cost, TRUNCATE, this.markets[symbol]['precision']['price'], DECIMAL_PLACES);
329
+ }
330
+
331
+ feeToPrecision (symbol, fee) {
332
+ return this.decimalToPrecision (fee, TRUNCATE, this.markets[symbol]['precision']['amount'], DECIMAL_PLACES);
333
+ }
334
+
335
+ async fetchMarkets (params = {}) {
336
+ const response = await this.publicGetAssetPairs (params);
337
+ //
338
+ // {
339
+ // "error":[],
340
+ // "result":{
341
+ // "ADAETH":{
342
+ // "altname":"ADAETH",
343
+ // "wsname":"ADA\/ETH",
344
+ // "aclass_base":"currency",
345
+ // "base":"ADA",
346
+ // "aclass_quote":"currency",
347
+ // "quote":"XETH",
348
+ // "lot":"unit",
349
+ // "pair_decimals":7,
350
+ // "lot_decimals":8,
351
+ // "lot_multiplier":1,
352
+ // "leverage_buy":[],
353
+ // "leverage_sell":[],
354
+ // "fees":[
355
+ // [0,0.26],
356
+ // [50000,0.24],
357
+ // [100000,0.22],
358
+ // [250000,0.2],
359
+ // [500000,0.18],
360
+ // [1000000,0.16],
361
+ // [2500000,0.14],
362
+ // [5000000,0.12],
363
+ // [10000000,0.1]
364
+ // ],
365
+ // "fees_maker":[
366
+ // [0,0.16],
367
+ // [50000,0.14],
368
+ // [100000,0.12],
369
+ // [250000,0.1],
370
+ // [500000,0.08],
371
+ // [1000000,0.06],
372
+ // [2500000,0.04],
373
+ // [5000000,0.02],
374
+ // [10000000,0]
375
+ // ],
376
+ // "fee_volume_currency":"ZUSD",
377
+ // "margin_call":80,
378
+ // "margin_stop":40,
379
+ // "ordermin": "1"
380
+ // },
381
+ // }
382
+ // }
383
+ //
384
+ const markets = this.safeValue (response, 'result', {});
385
+ const keys = Object.keys (markets);
386
+ let result = [];
387
+ for (let i = 0; i < keys.length; i++) {
388
+ const id = keys[i];
389
+ const market = markets[id];
390
+ const baseId = this.safeString (market, 'base');
391
+ const quoteId = this.safeString (market, 'quote');
392
+ const base = this.safeCurrencyCode (baseId);
393
+ const quote = this.safeCurrencyCode (quoteId);
394
+ const darkpool = id.indexOf ('.d') >= 0;
395
+ const altname = this.safeString (market, 'altname');
396
+ const makerFees = this.safeValue (market, 'fees_maker', []);
397
+ const firstMakerFee = this.safeValue (makerFees, 0, []);
398
+ const firstMakerFeeRate = this.safeNumber (firstMakerFee, 1);
399
+ let maker = undefined;
400
+ if (firstMakerFeeRate !== undefined) {
401
+ maker = parseFloat (firstMakerFeeRate) / 100;
402
+ }
403
+ const takerFees = this.safeValue (market, 'fees', []);
404
+ const firstTakerFee = this.safeValue (takerFees, 0, []);
405
+ const firstTakerFeeRate = this.safeNumber (firstTakerFee, 1);
406
+ let taker = undefined;
407
+ if (firstTakerFeeRate !== undefined) {
408
+ taker = parseFloat (firstTakerFeeRate) / 100;
409
+ }
410
+ const leverageBuy = this.safeValue (market, 'leverage_buy', []);
411
+ const leverageBuyLength = leverageBuy.length;
412
+ const precisionPrice = this.safeString (market, 'pair_decimals');
413
+ result.push ({
414
+ 'id': id,
415
+ 'symbol': darkpool ? altname : (base + '/' + quote),
416
+ 'base': base,
417
+ 'quote': quote,
418
+ 'settle': undefined,
419
+ 'baseId': baseId,
420
+ 'quoteId': quoteId,
421
+ 'settleId': undefined,
422
+ 'darkpool': darkpool,
423
+ 'altname': market['altname'],
424
+ 'type': 'spot',
425
+ 'spot': true,
426
+ 'margin': (leverageBuyLength > 0),
427
+ 'swap': false,
428
+ 'future': false,
429
+ 'option': false,
430
+ 'active': true,
431
+ 'contract': false,
432
+ 'linear': undefined,
433
+ 'inverse': undefined,
434
+ 'taker': taker,
435
+ 'maker': maker,
436
+ 'contractSize': undefined,
437
+ 'expiry': undefined,
438
+ 'expiryDatetime': undefined,
439
+ 'strike': undefined,
440
+ 'optionType': undefined,
441
+ 'precision': {
442
+ 'amount': this.safeInteger (market, 'lot_decimals'),
443
+ 'price': this.safeInteger (market, 'pair_decimals'),
444
+ },
445
+ 'limits': {
446
+ 'leverage': {
447
+ 'min': this.parseNumber ('1'),
448
+ 'max': this.safeNumber (leverageBuy, leverageBuyLength - 1, 1),
449
+ },
450
+ 'amount': {
451
+ 'min': this.safeNumber (market, 'ordermin'),
452
+ 'max': undefined,
453
+ },
454
+ 'price': {
455
+ 'min': this.parseNumber (this.parsePrecision (precisionPrice)),
456
+ 'max': undefined,
457
+ },
458
+ 'cost': {
459
+ 'min': undefined,
460
+ 'max': undefined,
461
+ },
462
+ },
463
+ 'info': market,
464
+ });
465
+ }
466
+ result = this.appendInactiveMarkets (result);
467
+ this.marketsByAltname = this.indexBy (result, 'altname');
468
+ return result;
469
+ }
470
+
471
+ safeCurrency (currencyId, currency = undefined) {
472
+ if (currencyId !== undefined) {
473
+ if (currencyId.length > 3) {
474
+ if ((currencyId.indexOf ('X') === 0) || (currencyId.indexOf ('Z') === 0)) {
475
+ if (currencyId.indexOf ('.') > 0) {
476
+ return super.safeCurrency (currencyId, currency);
477
+ } else {
478
+ currencyId = currencyId.slice (1);
479
+ }
480
+ }
481
+ }
482
+ }
483
+ return super.safeCurrency (currencyId, currency);
484
+ }
485
+
486
+ appendInactiveMarkets (result) {
487
+ // result should be an array to append to
488
+ const precision = { 'amount': 8, 'price': 8 };
489
+ const costLimits = { 'min': 0, 'max': undefined };
490
+ const priceLimits = { 'min': Math.pow (10, -precision['price']), 'max': undefined };
491
+ const amountLimits = { 'min': Math.pow (10, -precision['amount']), 'max': Math.pow (10, precision['amount']) };
492
+ const limits = { 'amount': amountLimits, 'price': priceLimits, 'cost': costLimits };
493
+ const defaults = {
494
+ 'darkpool': false,
495
+ 'info': undefined,
496
+ 'maker': undefined,
497
+ 'taker': undefined,
498
+ 'active': false,
499
+ 'precision': precision,
500
+ 'limits': limits,
501
+ };
502
+ const markets = [
503
+ // { 'id': 'XXLMZEUR', 'symbol': 'XLM/EUR', 'base': 'XLM', 'quote': 'EUR', 'altname': 'XLMEUR' },
504
+ ];
505
+ for (let i = 0; i < markets.length; i++) {
506
+ result.push (this.extend (defaults, markets[i]));
507
+ }
508
+ return result;
509
+ }
510
+
511
+ async fetchCurrencies (params = {}) {
512
+ const response = await this.publicGetAssets (params);
513
+ //
514
+ // {
515
+ // "error": [],
516
+ // "result": {
517
+ // "ADA": { "aclass": "currency", "altname": "ADA", "decimals": 8, "display_decimals": 6 },
518
+ // "BCH": { "aclass": "currency", "altname": "BCH", "decimals": 10, "display_decimals": 5 },
519
+ // ...
520
+ // },
521
+ // }
522
+ //
523
+ const currencies = this.safeValue (response, 'result');
524
+ const ids = Object.keys (currencies);
525
+ const result = {};
526
+ for (let i = 0; i < ids.length; i++) {
527
+ const id = ids[i];
528
+ const currency = currencies[id];
529
+ // todo: will need to rethink the fees
530
+ // see: https://support.kraken.com/hc/en-us/articles/201893608-What-are-the-withdrawal-fees-
531
+ // to add support for multiple withdrawal/deposit methods and
532
+ // differentiated fees for each particular method
533
+ const code = this.safeCurrencyCode (this.safeString (currency, 'altname'));
534
+ const precision = this.safeInteger (currency, 'decimals');
535
+ // assumes all currencies are active except those listed above
536
+ const active = !this.inArray (code, this.options['inactiveCurrencies']);
537
+ result[code] = {
538
+ 'id': id,
539
+ 'code': code,
540
+ 'info': currency,
541
+ 'name': code,
542
+ 'active': active,
543
+ 'deposit': undefined,
544
+ 'withdraw': undefined,
545
+ 'fee': undefined,
546
+ 'precision': precision,
547
+ 'limits': {
548
+ 'amount': {
549
+ 'min': Math.pow (10, -precision),
550
+ 'max': Math.pow (10, precision),
551
+ },
552
+ 'withdraw': {
553
+ 'min': undefined,
554
+ 'max': Math.pow (10, precision),
555
+ },
556
+ },
557
+ };
558
+ }
559
+ return result;
560
+ }
561
+
562
+ async fetchTradingFee (symbol, params = {}) {
563
+ await this.loadMarkets ();
564
+ const market = this.market (symbol);
565
+ const request = {
566
+ 'pair': market['id'],
567
+ 'fee-info': true,
568
+ };
569
+ const response = await this.privatePostTradeVolume (this.extend (request, params));
570
+ //
571
+ // {
572
+ // error: [],
573
+ // result: {
574
+ // currency: 'ZUSD',
575
+ // volume: '0.0000',
576
+ // fees: {
577
+ // XXBTZUSD: {
578
+ // fee: '0.2600',
579
+ // minfee: '0.1000',
580
+ // maxfee: '0.2600',
581
+ // nextfee: '0.2400',
582
+ // tiervolume: '0.0000',
583
+ // nextvolume: '50000.0000'
584
+ // }
585
+ // },
586
+ // fees_maker: {
587
+ // XXBTZUSD: {
588
+ // fee: '0.1600',
589
+ // minfee: '0.0000',
590
+ // maxfee: '0.1600',
591
+ // nextfee: '0.1400',
592
+ // tiervolume: '0.0000',
593
+ // nextvolume: '50000.0000'
594
+ // }
595
+ // }
596
+ // }
597
+ // }
598
+ //
599
+ const result = this.safeValue (response, 'result', {});
600
+ return this.parseTradingFee (result, market);
601
+ }
602
+
603
+ parseTradingFee (response, market) {
604
+ const makerFees = this.safeValue (response, 'fees_maker', {});
605
+ const takerFees = this.safeValue (response, 'fees', {});
606
+ const symbolMakerFee = this.safeValue (makerFees, market['id'], {});
607
+ const symbolTakerFee = this.safeValue (takerFees, market['id'], {});
608
+ return {
609
+ 'info': response,
610
+ 'symbol': market['symbol'],
611
+ 'maker': this.safeNumber (symbolMakerFee, 'fee'),
612
+ 'taker': this.safeNumber (symbolTakerFee, 'fee'),
613
+ 'percentage': true,
614
+ 'tierBased': true,
615
+ };
616
+ }
617
+
618
+ parseBidAsk (bidask, priceKey = 0, amountKey = 1) {
619
+ const price = this.safeNumber (bidask, priceKey);
620
+ const amount = this.safeNumber (bidask, amountKey);
621
+ const timestamp = this.safeInteger (bidask, 2);
622
+ return [ price, amount, timestamp ];
623
+ }
624
+
625
+ async fetchOrderBook (symbol, limit = undefined, params = {}) {
626
+ await this.loadMarkets ();
627
+ const market = this.market (symbol);
628
+ if (market['darkpool']) {
629
+ throw new ExchangeError (this.id + ' fetchOrderBook() does not provide an order book for darkpool symbol ' + symbol);
630
+ }
631
+ const request = {
632
+ 'pair': market['id'],
633
+ };
634
+ if (limit !== undefined) {
635
+ request['count'] = limit; // 100
636
+ }
637
+ const response = await this.publicGetDepth (this.extend (request, params));
638
+ //
639
+ // {
640
+ // "error":[],
641
+ // "result":{
642
+ // "XETHXXBT":{
643
+ // "asks":[
644
+ // ["0.023480","4.000",1586321307],
645
+ // ["0.023490","50.095",1586321306],
646
+ // ["0.023500","28.535",1586321302],
647
+ // ],
648
+ // "bids":[
649
+ // ["0.023470","59.580",1586321307],
650
+ // ["0.023460","20.000",1586321301],
651
+ // ["0.023440","67.832",1586321306],
652
+ // ]
653
+ // }
654
+ // }
655
+ // }
656
+ //
657
+ const result = this.safeValue (response, 'result', {});
658
+ let orderbook = this.safeValue (result, market['id']);
659
+ // sometimes kraken returns wsname instead of market id
660
+ // https://github.com/ccxt/ccxt/issues/8662
661
+ const marketInfo = this.safeValue (market, 'info', {});
662
+ const wsName = this.safeValue (marketInfo, 'wsname');
663
+ if (wsName !== undefined) {
664
+ orderbook = this.safeValue (result, wsName, orderbook);
665
+ }
666
+ return this.parseOrderBook (orderbook, symbol);
667
+ }
668
+
669
+ parseTicker (ticker, market = undefined) {
670
+ //
671
+ // {
672
+ // "a":["2432.77000","1","1.000"],
673
+ // "b":["2431.37000","2","2.000"],
674
+ // "c":["2430.58000","0.04408910"],
675
+ // "v":["4147.94474901","8896.96086304"],
676
+ // "p":["2456.22239","2568.63032"],
677
+ // "t":[3907,10056],
678
+ // "l":["2302.18000","2302.18000"],
679
+ // "h":["2621.14000","2860.01000"],
680
+ // "o":"2571.56000"
681
+ // }
682
+ //
683
+ const timestamp = this.milliseconds ();
684
+ const symbol = this.safeSymbol (undefined, market);
685
+ const v = this.safeValue (ticker, 'v', []);
686
+ const baseVolume = this.safeString (v, 1);
687
+ const p = this.safeValue (ticker, 'p', []);
688
+ const vwap = this.safeString (p, 1);
689
+ const quoteVolume = Precise.stringMul (baseVolume, vwap);
690
+ const c = this.safeValue (ticker, 'c', []);
691
+ const last = this.safeString (c, 0);
692
+ const high = this.safeValue (ticker, 'h', []);
693
+ const low = this.safeValue (ticker, 'l', []);
694
+ const bid = this.safeValue (ticker, 'b', []);
695
+ const ask = this.safeValue (ticker, 'a', []);
696
+ return this.safeTicker ({
697
+ 'symbol': symbol,
698
+ 'timestamp': timestamp,
699
+ 'datetime': this.iso8601 (timestamp),
700
+ 'high': this.safeString (high, 1),
701
+ 'low': this.safeString (low, 1),
702
+ 'bid': this.safeString (bid, 0),
703
+ 'bidVolume': undefined,
704
+ 'ask': this.safeString (ask, 0),
705
+ 'askVolume': undefined,
706
+ 'vwap': vwap,
707
+ 'open': this.safeString (ticker, 'o'),
708
+ 'close': last,
709
+ 'last': last,
710
+ 'previousClose': undefined,
711
+ 'change': undefined,
712
+ 'percentage': undefined,
713
+ 'average': undefined,
714
+ 'baseVolume': baseVolume,
715
+ 'quoteVolume': quoteVolume,
716
+ 'info': ticker,
717
+ }, market, false);
718
+ }
719
+
720
+ async fetchTickers (symbols = undefined, params = {}) {
721
+ if (symbols === undefined) {
722
+ throw new ArgumentsRequired (this.id + ' fetchTickers() requires a symbols argument, an array of symbols');
723
+ }
724
+ await this.loadMarkets ();
725
+ const marketIds = [];
726
+ for (let i = 0; i < symbols.length; i++) {
727
+ const symbol = symbols[i];
728
+ const market = this.markets[symbol];
729
+ if (market['active'] && !market['darkpool']) {
730
+ marketIds.push (market['id']);
731
+ }
732
+ }
733
+ const request = {
734
+ 'pair': marketIds.join (','),
735
+ };
736
+ const response = await this.publicGetTicker (this.extend (request, params));
737
+ const tickers = response['result'];
738
+ const ids = Object.keys (tickers);
739
+ const result = {};
740
+ for (let i = 0; i < ids.length; i++) {
741
+ const id = ids[i];
742
+ const market = this.markets_by_id[id];
743
+ const symbol = market['symbol'];
744
+ const ticker = tickers[id];
745
+ result[symbol] = this.parseTicker (ticker, market);
746
+ }
747
+ return this.filterByArray (result, 'symbol', symbols);
748
+ }
749
+
750
+ async fetchTicker (symbol, params = {}) {
751
+ await this.loadMarkets ();
752
+ const darkpool = symbol.indexOf ('.d') >= 0;
753
+ if (darkpool) {
754
+ throw new ExchangeError (this.id + ' fetchTicker() does not provide a ticker for darkpool symbol ' + symbol);
755
+ }
756
+ const market = this.market (symbol);
757
+ const request = {
758
+ 'pair': market['id'],
759
+ };
760
+ const response = await this.publicGetTicker (this.extend (request, params));
761
+ const ticker = response['result'][market['id']];
762
+ return this.parseTicker (ticker, market);
763
+ }
764
+
765
+ parseOHLCV (ohlcv, market = undefined) {
766
+ //
767
+ // [
768
+ // 1591475640,
769
+ // "0.02500",
770
+ // "0.02500",
771
+ // "0.02500",
772
+ // "0.02500",
773
+ // "0.02500",
774
+ // "9.12201000",
775
+ // 5
776
+ // ]
777
+ //
778
+ return [
779
+ this.safeTimestamp (ohlcv, 0),
780
+ this.safeNumber (ohlcv, 1),
781
+ this.safeNumber (ohlcv, 2),
782
+ this.safeNumber (ohlcv, 3),
783
+ this.safeNumber (ohlcv, 4),
784
+ this.safeNumber (ohlcv, 6),
785
+ ];
786
+ }
787
+
788
+ async fetchOHLCV (symbol, timeframe = '1m', since = undefined, limit = undefined, params = {}) {
789
+ await this.loadMarkets ();
790
+ const market = this.market (symbol);
791
+ const request = {
792
+ 'pair': market['id'],
793
+ 'interval': this.timeframes[timeframe],
794
+ };
795
+ if (since !== undefined) {
796
+ request['since'] = parseInt ((since - 1) / 1000);
797
+ }
798
+ const response = await this.publicGetOHLC (this.extend (request, params));
799
+ //
800
+ // {
801
+ // "error":[],
802
+ // "result":{
803
+ // "XETHXXBT":[
804
+ // [1591475580,"0.02499","0.02499","0.02499","0.02499","0.00000","0.00000000",0],
805
+ // [1591475640,"0.02500","0.02500","0.02500","0.02500","0.02500","9.12201000",5],
806
+ // [1591475700,"0.02499","0.02499","0.02499","0.02499","0.02499","1.28681415",2],
807
+ // [1591475760,"0.02499","0.02499","0.02499","0.02499","0.02499","0.08800000",1],
808
+ // ],
809
+ // "last":1591517580
810
+ // }
811
+ // }
812
+ const result = this.safeValue (response, 'result', {});
813
+ const ohlcvs = this.safeValue (result, market['id'], []);
814
+ return this.parseOHLCVs (ohlcvs, market, timeframe, since, limit);
815
+ }
816
+
817
+ parseLedgerEntryType (type) {
818
+ const types = {
819
+ 'trade': 'trade',
820
+ 'withdrawal': 'transaction',
821
+ 'deposit': 'transaction',
822
+ 'transfer': 'transfer',
823
+ 'margin': 'margin',
824
+ };
825
+ return this.safeString (types, type, type);
826
+ }
827
+
828
+ parseLedgerEntry (item, currency = undefined) {
829
+ //
830
+ // {
831
+ // 'LTFK7F-N2CUX-PNY4SX': {
832
+ // refid: "TSJTGT-DT7WN-GPPQMJ",
833
+ // time: 1520102320.555,
834
+ // type: "trade",
835
+ // aclass: "currency",
836
+ // asset: "XETH",
837
+ // amount: "0.1087194600",
838
+ // fee: "0.0000000000",
839
+ // balance: "0.2855851000"
840
+ // },
841
+ // ...
842
+ // }
843
+ //
844
+ const id = this.safeString (item, 'id');
845
+ let direction = undefined;
846
+ const account = undefined;
847
+ const referenceId = this.safeString (item, 'refid');
848
+ const referenceAccount = undefined;
849
+ const type = this.parseLedgerEntryType (this.safeString (item, 'type'));
850
+ const code = this.safeCurrencyCode (this.safeString (item, 'asset'), currency);
851
+ let amount = this.safeNumber (item, 'amount');
852
+ if (amount < 0) {
853
+ direction = 'out';
854
+ amount = Math.abs (amount);
855
+ } else {
856
+ direction = 'in';
857
+ }
858
+ const time = this.safeNumber (item, 'time');
859
+ let timestamp = undefined;
860
+ if (time !== undefined) {
861
+ timestamp = parseInt (time * 1000);
862
+ }
863
+ const fee = {
864
+ 'cost': this.safeNumber (item, 'fee'),
865
+ 'currency': code,
866
+ };
867
+ const before = undefined;
868
+ const after = this.safeNumber (item, 'balance');
869
+ const status = 'ok';
870
+ return {
871
+ 'info': item,
872
+ 'id': id,
873
+ 'direction': direction,
874
+ 'account': account,
875
+ 'referenceId': referenceId,
876
+ 'referenceAccount': referenceAccount,
877
+ 'type': type,
878
+ 'currency': code,
879
+ 'amount': amount,
880
+ 'before': before,
881
+ 'after': after,
882
+ 'status': status,
883
+ 'timestamp': timestamp,
884
+ 'datetime': this.iso8601 (timestamp),
885
+ 'fee': fee,
886
+ };
887
+ }
888
+
889
+ async fetchLedger (code = undefined, since = undefined, limit = undefined, params = {}) {
890
+ // https://www.kraken.com/features/api#get-ledgers-info
891
+ await this.loadMarkets ();
892
+ const request = {};
893
+ let currency = undefined;
894
+ if (code !== undefined) {
895
+ currency = this.currency (code);
896
+ request['asset'] = currency['id'];
897
+ }
898
+ if (since !== undefined) {
899
+ request['start'] = parseInt (since / 1000);
900
+ }
901
+ const response = await this.privatePostLedgers (this.extend (request, params));
902
+ // { error: [],
903
+ // result: { ledger: { 'LPUAIB-TS774-UKHP7X': { refid: "A2B4HBV-L4MDIE-JU4N3N",
904
+ // time: 1520103488.314,
905
+ // type: "withdrawal",
906
+ // aclass: "currency",
907
+ // asset: "XETH",
908
+ // amount: "-0.2805800000",
909
+ // fee: "0.0050000000",
910
+ // balance: "0.0000051000" },
911
+ const result = this.safeValue (response, 'result', {});
912
+ const ledger = this.safeValue (result, 'ledger', {});
913
+ const keys = Object.keys (ledger);
914
+ const items = [];
915
+ for (let i = 0; i < keys.length; i++) {
916
+ const key = keys[i];
917
+ const value = ledger[key];
918
+ value['id'] = key;
919
+ items.push (value);
920
+ }
921
+ return this.parseLedger (items, currency, since, limit);
922
+ }
923
+
924
+ async fetchLedgerEntriesByIds (ids, code = undefined, params = {}) {
925
+ // https://www.kraken.com/features/api#query-ledgers
926
+ await this.loadMarkets ();
927
+ ids = ids.join (',');
928
+ const request = this.extend ({
929
+ 'id': ids,
930
+ }, params);
931
+ const response = await this.privatePostQueryLedgers (request);
932
+ // { error: [],
933
+ // result: { 'LPUAIB-TS774-UKHP7X': { refid: "A2B4HBV-L4MDIE-JU4N3N",
934
+ // time: 1520103488.314,
935
+ // type: "withdrawal",
936
+ // aclass: "currency",
937
+ // asset: "XETH",
938
+ // amount: "-0.2805800000",
939
+ // fee: "0.0050000000",
940
+ // balance: "0.0000051000" } } }
941
+ const result = response['result'];
942
+ const keys = Object.keys (result);
943
+ const items = [];
944
+ for (let i = 0; i < keys.length; i++) {
945
+ const key = keys[i];
946
+ const value = result[key];
947
+ value['id'] = key;
948
+ items.push (value);
949
+ }
950
+ return this.parseLedger (items);
951
+ }
952
+
953
+ async fetchLedgerEntry (id, code = undefined, params = {}) {
954
+ const items = await this.fetchLedgerEntriesByIds ([ id ], code, params);
955
+ return items[0];
956
+ }
957
+
958
+ parseTrade (trade, market = undefined) {
959
+ //
960
+ // fetchTrades (public)
961
+ //
962
+ // [
963
+ // "0.032310", // price
964
+ // "4.28169434", // amount
965
+ // 1541390792.763, // timestamp
966
+ // "s", // sell or buy
967
+ // "l", // limit or market
968
+ // ""
969
+ // ]
970
+ //
971
+ // fetchOrderTrades (private)
972
+ //
973
+ // {
974
+ // id: 'TIMIRG-WUNNE-RRJ6GT', // injected from outside
975
+ // ordertxid: 'OQRPN2-LRHFY-HIFA7D',
976
+ // postxid: 'TKH2SE-M7IF5-CFI7LT',
977
+ // pair: 'USDCUSDT',
978
+ // time: 1586340086.457,
979
+ // type: 'sell',
980
+ // ordertype: 'market',
981
+ // price: '0.99860000',
982
+ // cost: '22.16892001',
983
+ // fee: '0.04433784',
984
+ // vol: '22.20000000',
985
+ // margin: '0.00000000',
986
+ // misc: ''
987
+ // }
988
+ //
989
+ let timestamp = undefined;
990
+ let side = undefined;
991
+ let type = undefined;
992
+ let price = undefined;
993
+ let amount = undefined;
994
+ let id = undefined;
995
+ let orderId = undefined;
996
+ let fee = undefined;
997
+ let symbol = undefined;
998
+ if (Array.isArray (trade)) {
999
+ timestamp = this.safeTimestamp (trade, 2);
1000
+ side = (trade[3] === 's') ? 'sell' : 'buy';
1001
+ type = (trade[4] === 'l') ? 'limit' : 'market';
1002
+ price = this.safeString (trade, 0);
1003
+ amount = this.safeString (trade, 1);
1004
+ const tradeLength = trade.length;
1005
+ if (tradeLength > 6) {
1006
+ id = this.safeString (trade, 6); // artificially added as per #1794
1007
+ }
1008
+ } else if (typeof trade === 'string') {
1009
+ id = trade;
1010
+ } else if ('ordertxid' in trade) {
1011
+ const marketId = this.safeString (trade, 'pair');
1012
+ const foundMarket = this.findMarketByAltnameOrId (marketId);
1013
+ if (foundMarket !== undefined) {
1014
+ market = foundMarket;
1015
+ } else if (marketId !== undefined) {
1016
+ // delisted market ids go here
1017
+ market = this.getDelistedMarketById (marketId);
1018
+ }
1019
+ orderId = this.safeString (trade, 'ordertxid');
1020
+ id = this.safeString2 (trade, 'id', 'postxid');
1021
+ timestamp = this.safeTimestamp (trade, 'time');
1022
+ side = this.safeString (trade, 'type');
1023
+ type = this.safeString (trade, 'ordertype');
1024
+ price = this.safeString (trade, 'price');
1025
+ amount = this.safeString (trade, 'vol');
1026
+ if ('fee' in trade) {
1027
+ let currency = undefined;
1028
+ if (market !== undefined) {
1029
+ currency = market['quote'];
1030
+ }
1031
+ fee = {
1032
+ 'cost': this.safeString (trade, 'fee'),
1033
+ 'currency': currency,
1034
+ };
1035
+ }
1036
+ }
1037
+ if (market !== undefined) {
1038
+ symbol = market['symbol'];
1039
+ }
1040
+ const cost = this.safeString (trade, 'cost');
1041
+ return this.safeTrade ({
1042
+ 'id': id,
1043
+ 'order': orderId,
1044
+ 'info': trade,
1045
+ 'timestamp': timestamp,
1046
+ 'datetime': this.iso8601 (timestamp),
1047
+ 'symbol': symbol,
1048
+ 'type': type,
1049
+ 'side': side,
1050
+ 'takerOrMaker': undefined,
1051
+ 'price': price,
1052
+ 'amount': amount,
1053
+ 'cost': cost,
1054
+ 'fee': fee,
1055
+ }, market);
1056
+ }
1057
+
1058
+ async fetchTrades (symbol, since = undefined, limit = undefined, params = {}) {
1059
+ await this.loadMarkets ();
1060
+ const market = this.market (symbol);
1061
+ const id = market['id'];
1062
+ const request = {
1063
+ 'pair': id,
1064
+ };
1065
+ // https://support.kraken.com/hc/en-us/articles/218198197-How-to-pull-all-trade-data-using-the-Kraken-REST-API
1066
+ // https://github.com/ccxt/ccxt/issues/5677
1067
+ if (since !== undefined) {
1068
+ // php does not format it properly
1069
+ // therefore we use string concatenation here
1070
+ request['since'] = since * 1e6;
1071
+ request['since'] = since.toString () + '000000'; // expected to be in nanoseconds
1072
+ }
1073
+ // https://github.com/ccxt/ccxt/issues/5698
1074
+ if (limit !== undefined && limit !== 1000) {
1075
+ const fetchTradesWarning = this.safeValue (this.options, 'fetchTradesWarning', true);
1076
+ if (fetchTradesWarning) {
1077
+ throw new ExchangeError (this.id + ' fetchTrades() cannot serve ' + limit.toString () + " trades without breaking the pagination, see https://github.com/ccxt/ccxt/issues/5698 for more details. Set exchange.options['fetchTradesWarning'] to acknowledge this warning and silence it.");
1078
+ }
1079
+ }
1080
+ const response = await this.publicGetTrades (this.extend (request, params));
1081
+ //
1082
+ // {
1083
+ // "error": [],
1084
+ // "result": {
1085
+ // "XETHXXBT": [
1086
+ // ["0.032310","4.28169434",1541390792.763,"s","l",""]
1087
+ // ],
1088
+ // "last": "1541439421200678657"
1089
+ // }
1090
+ // }
1091
+ //
1092
+ const result = response['result'];
1093
+ const trades = result[id];
1094
+ // trades is a sorted array: last (most recent trade) goes last
1095
+ const length = trades.length;
1096
+ if (length <= 0) {
1097
+ return [];
1098
+ }
1099
+ const lastTrade = trades[length - 1];
1100
+ const lastTradeId = this.safeString (result, 'last');
1101
+ lastTrade.push (lastTradeId);
1102
+ return this.parseTrades (trades, market, since, limit);
1103
+ }
1104
+
1105
+ parseBalance (response) {
1106
+ const balances = this.safeValue (response, 'result', {});
1107
+ const result = {
1108
+ 'info': response,
1109
+ 'timestamp': undefined,
1110
+ 'datetime': undefined,
1111
+ };
1112
+ const currencyIds = Object.keys (balances);
1113
+ for (let i = 0; i < currencyIds.length; i++) {
1114
+ const currencyId = currencyIds[i];
1115
+ const code = this.safeCurrencyCode (currencyId);
1116
+ const account = this.account ();
1117
+ account['total'] = this.safeString (balances, currencyId);
1118
+ result[code] = account;
1119
+ }
1120
+ return this.safeBalance (result);
1121
+ }
1122
+
1123
+ async fetchBalance (params = {}) {
1124
+ await this.loadMarkets ();
1125
+ const response = await this.privatePostBalance (params);
1126
+ //
1127
+ // {
1128
+ // "error":[],
1129
+ // "result":{
1130
+ // "ZUSD":"58.8649",
1131
+ // "KFEE":"4399.43",
1132
+ // "XXBT":"0.0000034506",
1133
+ // }
1134
+ // }
1135
+ //
1136
+ return this.parseBalance (response);
1137
+ }
1138
+
1139
+ async createOrder (symbol, type, side, amount, price = undefined, params = {}) {
1140
+ await this.loadMarkets ();
1141
+ const market = this.market (symbol);
1142
+ const request = {
1143
+ 'pair': market['id'],
1144
+ 'type': side,
1145
+ 'ordertype': type,
1146
+ 'volume': this.amountToPrecision (symbol, amount),
1147
+ };
1148
+ const clientOrderId = this.safeString2 (params, 'userref', 'clientOrderId');
1149
+ params = this.omit (params, [ 'userref', 'clientOrderId' ]);
1150
+ if (clientOrderId !== undefined) {
1151
+ request['userref'] = clientOrderId;
1152
+ }
1153
+ //
1154
+ // market
1155
+ // limit (price = limit price)
1156
+ // stop-loss (price = stop loss price)
1157
+ // take-profit (price = take profit price)
1158
+ // stop-loss-limit (price = stop loss trigger price, price2 = triggered limit price)
1159
+ // take-profit-limit (price = take profit trigger price, price2 = triggered limit price)
1160
+ // settle-position
1161
+ //
1162
+ if (type === 'limit') {
1163
+ request['price'] = this.priceToPrecision (symbol, price);
1164
+ } else if ((type === 'stop-loss') || (type === 'take-profit')) {
1165
+ const stopPrice = this.safeNumber2 (params, 'price', 'stopPrice', price);
1166
+ if (stopPrice === undefined) {
1167
+ throw new ArgumentsRequired (this.id + ' createOrder() requires a price argument or a price/stopPrice parameter for a ' + type + ' order');
1168
+ } else {
1169
+ request['price'] = this.priceToPrecision (symbol, stopPrice);
1170
+ }
1171
+ } else if ((type === 'stop-loss-limit') || (type === 'take-profit-limit')) {
1172
+ const stopPrice = this.safeNumber2 (params, 'price', 'stopPrice');
1173
+ const limitPrice = this.safeNumber (params, 'price2');
1174
+ const stopPriceDefined = (stopPrice !== undefined);
1175
+ const limitPriceDefined = (limitPrice !== undefined);
1176
+ if (stopPriceDefined && limitPriceDefined) {
1177
+ request['price'] = this.priceToPrecision (symbol, stopPrice);
1178
+ request['price2'] = this.priceToPrecision (symbol, limitPrice);
1179
+ } else if ((price === undefined) || (!(stopPriceDefined || limitPriceDefined))) {
1180
+ throw new ArgumentsRequired (this.id + ' createOrder() requires a price argument and/or price/stopPrice/price2 parameters for a ' + type + ' order');
1181
+ } else {
1182
+ if (stopPriceDefined) {
1183
+ request['price'] = this.priceToPrecision (symbol, stopPrice);
1184
+ request['price2'] = this.priceToPrecision (symbol, price);
1185
+ } else if (limitPriceDefined) {
1186
+ request['price'] = this.priceToPrecision (symbol, price);
1187
+ request['price2'] = this.priceToPrecision (symbol, limitPrice);
1188
+ }
1189
+ }
1190
+ }
1191
+ let close = this.safeValue (params, 'close');
1192
+ if (close !== undefined) {
1193
+ close = this.extend ({}, close);
1194
+ const closePrice = this.safeValue (close, 'price');
1195
+ if (closePrice !== undefined) {
1196
+ close['price'] = this.priceToPrecision (symbol, closePrice);
1197
+ }
1198
+ const closePrice2 = this.safeValue (close, 'price2'); // stopPrice
1199
+ if (closePrice2 !== undefined) {
1200
+ close['price2'] = this.priceToPrecision (symbol, closePrice2);
1201
+ }
1202
+ request['close'] = close;
1203
+ }
1204
+ params = this.omit (params, [ 'price', 'stopPrice', 'price2', 'close' ]);
1205
+ const response = await this.privatePostAddOrder (this.extend (request, params));
1206
+ //
1207
+ // {
1208
+ // error: [],
1209
+ // result: {
1210
+ // descr: { order: 'buy 0.02100000 ETHUSDT @ limit 330.00' },
1211
+ // txid: [ 'OEKVV2-IH52O-TPL6GZ' ]
1212
+ // }
1213
+ // }
1214
+ //
1215
+ const result = this.safeValue (response, 'result');
1216
+ return this.parseOrder (result);
1217
+ }
1218
+
1219
+ findMarketByAltnameOrId (id) {
1220
+ if (id in this.marketsByAltname) {
1221
+ return this.marketsByAltname[id];
1222
+ } else if (id in this.markets_by_id) {
1223
+ return this.markets_by_id[id];
1224
+ }
1225
+ return undefined;
1226
+ }
1227
+
1228
+ getDelistedMarketById (id) {
1229
+ if (id === undefined) {
1230
+ return id;
1231
+ }
1232
+ let market = this.safeValue (this.options['delistedMarketsById'], id);
1233
+ if (market !== undefined) {
1234
+ return market;
1235
+ }
1236
+ const baseIdStart = 0;
1237
+ let baseIdEnd = 3;
1238
+ let quoteIdStart = 3;
1239
+ let quoteIdEnd = 6;
1240
+ if (id.length === 8) {
1241
+ baseIdEnd = 4;
1242
+ quoteIdStart = 4;
1243
+ quoteIdEnd = 8;
1244
+ } else if (id.length === 7) {
1245
+ baseIdEnd = 4;
1246
+ quoteIdStart = 4;
1247
+ quoteIdEnd = 7;
1248
+ }
1249
+ const baseId = id.slice (baseIdStart, baseIdEnd);
1250
+ const quoteId = id.slice (quoteIdStart, quoteIdEnd);
1251
+ const base = this.safeCurrencyCode (baseId);
1252
+ const quote = this.safeCurrencyCode (quoteId);
1253
+ const symbol = base + '/' + quote;
1254
+ market = {
1255
+ 'symbol': symbol,
1256
+ 'base': base,
1257
+ 'quote': quote,
1258
+ 'baseId': baseId,
1259
+ 'quoteId': quoteId,
1260
+ };
1261
+ this.options['delistedMarketsById'][id] = market;
1262
+ return market;
1263
+ }
1264
+
1265
+ parseOrderStatus (status) {
1266
+ const statuses = {
1267
+ 'pending': 'open', // order pending book entry
1268
+ 'open': 'open',
1269
+ 'closed': 'closed',
1270
+ 'canceled': 'canceled',
1271
+ 'expired': 'expired',
1272
+ };
1273
+ return this.safeString (statuses, status, status);
1274
+ }
1275
+
1276
+ parseOrder (order, market = undefined) {
1277
+ //
1278
+ // createOrder for regular orders
1279
+ //
1280
+ // {
1281
+ // descr: { order: 'buy 0.02100000 ETHUSDT @ limit 330.00' },
1282
+ // txid: [ 'OEKVV2-IH52O-TPL6GZ' ]
1283
+ // }
1284
+ // {
1285
+ // "txid": [ "TX_ID_HERE" ],
1286
+ // "descr": { "order":"buy 0.12345678 ETHEUR @ market" },
1287
+ // }
1288
+ //
1289
+ //
1290
+ // createOrder for stop orders
1291
+ //
1292
+ // {
1293
+ // "txid":["OSILNC-VQI5Q-775ZDQ"],
1294
+ // "descr":{"order":"sell 167.28002676 ADAXBT @ stop loss 0.00003280 -> limit 0.00003212"}
1295
+ // }
1296
+ //
1297
+ //
1298
+ // {
1299
+ // "txid":["OVHMJV-BZW2V-6NZFWF"],
1300
+ // "descr":{"order":"sell 0.00100000 ETHUSD @ stop loss 2677.00 -> limit 2577.00 with 5:1 leverage"}
1301
+ // }
1302
+ //
1303
+ const description = this.safeValue (order, 'descr', {});
1304
+ const orderDescription = this.safeString (description, 'order');
1305
+ let side = undefined;
1306
+ let type = undefined;
1307
+ let marketId = undefined;
1308
+ let price = undefined;
1309
+ let amount = undefined;
1310
+ let stopPrice = undefined;
1311
+ if (orderDescription !== undefined) {
1312
+ const parts = orderDescription.split (' ');
1313
+ side = this.safeString (parts, 0);
1314
+ amount = this.safeString (parts, 1);
1315
+ marketId = this.safeString (parts, 2);
1316
+ type = this.safeString (parts, 4);
1317
+ if (type === 'stop') {
1318
+ stopPrice = this.safeString (parts, 6);
1319
+ price = this.safeString (parts, 9);
1320
+ } else if (type === 'limit') {
1321
+ price = this.safeString (parts, 5);
1322
+ }
1323
+ }
1324
+ side = this.safeString (description, 'type', side);
1325
+ type = this.safeString (description, 'ordertype', type);
1326
+ marketId = this.safeString (description, 'pair', marketId);
1327
+ const foundMarket = this.findMarketByAltnameOrId (marketId);
1328
+ let symbol = undefined;
1329
+ if (foundMarket !== undefined) {
1330
+ market = foundMarket;
1331
+ } else if (marketId !== undefined) {
1332
+ // delisted market ids go here
1333
+ market = this.getDelistedMarketById (marketId);
1334
+ }
1335
+ const timestamp = this.safeTimestamp (order, 'opentm');
1336
+ amount = this.safeString (order, 'vol', amount);
1337
+ const filled = this.safeString (order, 'vol_exec');
1338
+ let fee = undefined;
1339
+ // kraken truncates the cost in the api response so we will ignore it and calculate it from average & filled
1340
+ // const cost = this.safeString (order, 'cost');
1341
+ price = this.safeString (description, 'price', price);
1342
+ if ((price === undefined) || Precise.stringEquals (price, '0')) {
1343
+ price = this.safeString (description, 'price2');
1344
+ }
1345
+ if ((price === undefined) || Precise.stringEquals (price, '0')) {
1346
+ price = this.safeString (order, 'price', price);
1347
+ }
1348
+ const average = this.safeNumber (order, 'price');
1349
+ if (market !== undefined) {
1350
+ symbol = market['symbol'];
1351
+ if ('fee' in order) {
1352
+ const flags = order['oflags'];
1353
+ const feeCost = this.safeString (order, 'fee');
1354
+ fee = {
1355
+ 'cost': feeCost,
1356
+ 'rate': undefined,
1357
+ };
1358
+ if (flags.indexOf ('fciq') >= 0) {
1359
+ fee['currency'] = market['quote'];
1360
+ } else if (flags.indexOf ('fcib') >= 0) {
1361
+ fee['currency'] = market['base'];
1362
+ }
1363
+ }
1364
+ }
1365
+ const status = this.parseOrderStatus (this.safeString (order, 'status'));
1366
+ let id = this.safeString (order, 'id');
1367
+ if (id === undefined) {
1368
+ const txid = this.safeValue (order, 'txid');
1369
+ id = this.safeString (txid, 0);
1370
+ }
1371
+ const clientOrderId = this.safeString (order, 'userref');
1372
+ const rawTrades = this.safeValue (order, 'trades');
1373
+ stopPrice = this.safeNumber (order, 'stopprice', stopPrice);
1374
+ return this.safeOrder ({
1375
+ 'id': id,
1376
+ 'clientOrderId': clientOrderId,
1377
+ 'info': order,
1378
+ 'timestamp': timestamp,
1379
+ 'datetime': this.iso8601 (timestamp),
1380
+ 'lastTradeTimestamp': undefined,
1381
+ 'status': status,
1382
+ 'symbol': symbol,
1383
+ 'type': type,
1384
+ 'timeInForce': undefined,
1385
+ 'postOnly': undefined,
1386
+ 'side': side,
1387
+ 'price': price,
1388
+ 'stopPrice': stopPrice,
1389
+ 'cost': undefined,
1390
+ 'amount': amount,
1391
+ 'filled': filled,
1392
+ 'average': average,
1393
+ 'remaining': undefined,
1394
+ 'fee': fee,
1395
+ 'trades': rawTrades,
1396
+ }, market);
1397
+ }
1398
+
1399
+ async fetchOrder (id, symbol = undefined, params = {}) {
1400
+ await this.loadMarkets ();
1401
+ const clientOrderId = this.safeValue2 (params, 'userref', 'clientOrderId');
1402
+ const request = {
1403
+ 'trades': true, // whether or not to include trades in output (optional, default false)
1404
+ // 'txid': id, // do not comma separate a list of ids - use fetchOrdersByIds instead
1405
+ // 'userref': 'optional', // restrict results to given user reference id (optional)
1406
+ };
1407
+ let query = params;
1408
+ if (clientOrderId !== undefined) {
1409
+ request['userref'] = clientOrderId;
1410
+ query = this.omit (params, [ 'userref', 'clientOrderId' ]);
1411
+ } else {
1412
+ request['txid'] = id;
1413
+ }
1414
+ const response = await this.privatePostQueryOrders (this.extend (request, query));
1415
+ //
1416
+ // {
1417
+ // "error":[],
1418
+ // "result":{
1419
+ // "OTLAS3-RRHUF-NDWH5A":{
1420
+ // "refid":null,
1421
+ // "userref":null,
1422
+ // "status":"closed",
1423
+ // "reason":null,
1424
+ // "opentm":1586822919.3342,
1425
+ // "closetm":1586822919.365,
1426
+ // "starttm":0,
1427
+ // "expiretm":0,
1428
+ // "descr":{
1429
+ // "pair":"XBTUSDT",
1430
+ // "type":"sell",
1431
+ // "ordertype":"market",
1432
+ // "price":"0",
1433
+ // "price2":"0",
1434
+ // "leverage":"none",
1435
+ // "order":"sell 0.21804000 XBTUSDT @ market",
1436
+ // "close":""
1437
+ // },
1438
+ // "vol":"0.21804000",
1439
+ // "vol_exec":"0.21804000",
1440
+ // "cost":"1493.9",
1441
+ // "fee":"3.8",
1442
+ // "price":"6851.5",
1443
+ // "stopprice":"0.00000",
1444
+ // "limitprice":"0.00000",
1445
+ // "misc":"",
1446
+ // "oflags":"fciq",
1447
+ // "trades":["TT5UC3-GOIRW-6AZZ6R"]
1448
+ // }
1449
+ // }
1450
+ // }
1451
+ //
1452
+ const result = this.safeValue (response, 'result', []);
1453
+ if (!(id in result)) {
1454
+ throw new OrderNotFound (this.id + ' fetchOrder() could not find order id ' + id);
1455
+ }
1456
+ const order = this.parseOrder (this.extend ({ 'id': id }, result[id]));
1457
+ return this.extend ({ 'info': response }, order);
1458
+ }
1459
+
1460
+ async fetchOrderTrades (id, symbol = undefined, since = undefined, limit = undefined, params = {}) {
1461
+ const orderTrades = this.safeValue (params, 'trades');
1462
+ const tradeIds = [];
1463
+ if (orderTrades === undefined) {
1464
+ throw new ArgumentsRequired (this.id + " fetchOrderTrades() requires a unified order structure in the params argument or a 'trades' param (an array of trade id strings)");
1465
+ } else {
1466
+ for (let i = 0; i < orderTrades.length; i++) {
1467
+ const orderTrade = orderTrades[i];
1468
+ if (typeof orderTrade === 'string') {
1469
+ tradeIds.push (orderTrade);
1470
+ } else {
1471
+ tradeIds.push (orderTrade['id']);
1472
+ }
1473
+ }
1474
+ }
1475
+ await this.loadMarkets ();
1476
+ const options = this.safeValue (this.options, 'fetchOrderTrades', {});
1477
+ const batchSize = this.safeInteger (options, 'batchSize', 20);
1478
+ const numTradeIds = tradeIds.length;
1479
+ let numBatches = parseInt (numTradeIds / batchSize);
1480
+ numBatches = this.sum (numBatches, 1);
1481
+ let result = [];
1482
+ for (let j = 0; j < numBatches; j++) {
1483
+ const requestIds = [];
1484
+ for (let k = 0; k < batchSize; k++) {
1485
+ const index = this.sum (j * batchSize, k);
1486
+ if (index < numTradeIds) {
1487
+ requestIds.push (tradeIds[index]);
1488
+ }
1489
+ }
1490
+ const request = {
1491
+ 'txid': requestIds.join (','),
1492
+ };
1493
+ const response = await this.privatePostQueryTrades (request);
1494
+ //
1495
+ // {
1496
+ // error: [],
1497
+ // result: {
1498
+ // 'TIMIRG-WUNNE-RRJ6GT': {
1499
+ // ordertxid: 'OQRPN2-LRHFY-HIFA7D',
1500
+ // postxid: 'TKH2SE-M7IF5-CFI7LT',
1501
+ // pair: 'USDCUSDT',
1502
+ // time: 1586340086.457,
1503
+ // type: 'sell',
1504
+ // ordertype: 'market',
1505
+ // price: '0.99860000',
1506
+ // cost: '22.16892001',
1507
+ // fee: '0.04433784',
1508
+ // vol: '22.20000000',
1509
+ // margin: '0.00000000',
1510
+ // misc: ''
1511
+ // }
1512
+ // }
1513
+ // }
1514
+ //
1515
+ const rawTrades = this.safeValue (response, 'result');
1516
+ const ids = Object.keys (rawTrades);
1517
+ for (let i = 0; i < ids.length; i++) {
1518
+ rawTrades[ids[i]]['id'] = ids[i];
1519
+ }
1520
+ const trades = this.parseTrades (rawTrades, undefined, since, limit);
1521
+ const tradesFilteredBySymbol = this.filterBySymbol (trades, symbol);
1522
+ result = this.arrayConcat (result, tradesFilteredBySymbol);
1523
+ }
1524
+ return result;
1525
+ }
1526
+
1527
+ async fetchOrdersByIds (ids, symbol = undefined, params = {}) {
1528
+ await this.loadMarkets ();
1529
+ const response = await this.privatePostQueryOrders (this.extend ({
1530
+ 'trades': true, // whether or not to include trades in output (optional, default false)
1531
+ 'txid': ids.join (','), // comma delimited list of transaction ids to query info about (20 maximum)
1532
+ }, params));
1533
+ const result = this.safeValue (response, 'result', {});
1534
+ const orders = [];
1535
+ const orderIds = Object.keys (result);
1536
+ for (let i = 0; i < orderIds.length; i++) {
1537
+ const id = orderIds[i];
1538
+ const item = result[id];
1539
+ const order = this.parseOrder (this.extend ({ 'id': id }, item));
1540
+ orders.push (order);
1541
+ }
1542
+ return orders;
1543
+ }
1544
+
1545
+ async fetchMyTrades (symbol = undefined, since = undefined, limit = undefined, params = {}) {
1546
+ await this.loadMarkets ();
1547
+ const request = {
1548
+ // 'type': 'all', // any position, closed position, closing position, no position
1549
+ // 'trades': false, // whether or not to include trades related to position in output
1550
+ // 'start': 1234567890, // starting unix timestamp or trade tx id of results (exclusive)
1551
+ // 'end': 1234567890, // ending unix timestamp or trade tx id of results (inclusive)
1552
+ // 'ofs' = result offset
1553
+ };
1554
+ if (since !== undefined) {
1555
+ request['start'] = parseInt (since / 1000);
1556
+ }
1557
+ const response = await this.privatePostTradesHistory (this.extend (request, params));
1558
+ //
1559
+ // {
1560
+ // "error": [],
1561
+ // "result": {
1562
+ // "trades": {
1563
+ // "GJ3NYQ-XJRTF-THZABF": {
1564
+ // "ordertxid": "TKH2SE-ZIF5E-CFI7LT",
1565
+ // "postxid": "OEN3VX-M7IF5-JNBJAM",
1566
+ // "pair": "XICNXETH",
1567
+ // "time": 1527213229.4491,
1568
+ // "type": "sell",
1569
+ // "ordertype": "limit",
1570
+ // "price": "0.001612",
1571
+ // "cost": "0.025792",
1572
+ // "fee": "0.000026",
1573
+ // "vol": "16.00000000",
1574
+ // "margin": "0.000000",
1575
+ // "misc": ""
1576
+ // },
1577
+ // ...
1578
+ // },
1579
+ // "count": 9760,
1580
+ // },
1581
+ // }
1582
+ //
1583
+ const trades = response['result']['trades'];
1584
+ const ids = Object.keys (trades);
1585
+ for (let i = 0; i < ids.length; i++) {
1586
+ trades[ids[i]]['id'] = ids[i];
1587
+ }
1588
+ let market = undefined;
1589
+ if (symbol !== undefined) {
1590
+ market = this.market (symbol);
1591
+ }
1592
+ return this.parseTrades (trades, market, since, limit);
1593
+ }
1594
+
1595
+ async cancelOrder (id, symbol = undefined, params = {}) {
1596
+ await this.loadMarkets ();
1597
+ let response = undefined;
1598
+ const clientOrderId = this.safeValue2 (params, 'userref', 'clientOrderId', id);
1599
+ const request = {
1600
+ 'txid': clientOrderId, // order id or userref
1601
+ };
1602
+ params = this.omit (params, [ 'userref', 'clientOrderId' ]);
1603
+ try {
1604
+ response = await this.privatePostCancelOrder (this.extend (request, params));
1605
+ } catch (e) {
1606
+ if (this.last_http_response) {
1607
+ if (this.last_http_response.indexOf ('EOrder:Unknown order') >= 0) {
1608
+ throw new OrderNotFound (this.id + ' cancelOrder() error ' + this.last_http_response);
1609
+ }
1610
+ }
1611
+ throw e;
1612
+ }
1613
+ return response;
1614
+ }
1615
+
1616
+ async cancelAllOrders (symbol = undefined, params = {}) {
1617
+ await this.loadMarkets ();
1618
+ return await this.privatePostCancelAll (params);
1619
+ }
1620
+
1621
+ async fetchOpenOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) {
1622
+ await this.loadMarkets ();
1623
+ const request = {};
1624
+ if (since !== undefined) {
1625
+ request['start'] = parseInt (since / 1000);
1626
+ }
1627
+ let query = params;
1628
+ const clientOrderId = this.safeValue2 (params, 'userref', 'clientOrderId');
1629
+ if (clientOrderId !== undefined) {
1630
+ request['userref'] = clientOrderId;
1631
+ query = this.omit (params, [ 'userref', 'clientOrderId' ]);
1632
+ }
1633
+ const response = await this.privatePostOpenOrders (this.extend (request, query));
1634
+ let market = undefined;
1635
+ if (symbol !== undefined) {
1636
+ market = this.market (symbol);
1637
+ }
1638
+ const result = this.safeValue (response, 'result', {});
1639
+ const orders = this.safeValue (result, 'open', []);
1640
+ return this.parseOrders (orders, market, since, limit);
1641
+ }
1642
+
1643
+ async fetchClosedOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) {
1644
+ await this.loadMarkets ();
1645
+ const request = {};
1646
+ if (since !== undefined) {
1647
+ request['start'] = parseInt (since / 1000);
1648
+ }
1649
+ let query = params;
1650
+ const clientOrderId = this.safeValue2 (params, 'userref', 'clientOrderId');
1651
+ if (clientOrderId !== undefined) {
1652
+ request['userref'] = clientOrderId;
1653
+ query = this.omit (params, [ 'userref', 'clientOrderId' ]);
1654
+ }
1655
+ const response = await this.privatePostClosedOrders (this.extend (request, query));
1656
+ //
1657
+ // {
1658
+ // "error":[],
1659
+ // "result":{
1660
+ // "closed":{
1661
+ // "OETZYO-UL524-QJMXCT":{
1662
+ // "refid":null,
1663
+ // "userref":null,
1664
+ // "status":"canceled",
1665
+ // "reason":"User requested",
1666
+ // "opentm":1601489313.3898,
1667
+ // "closetm":1601489346.5507,
1668
+ // "starttm":0,
1669
+ // "expiretm":0,
1670
+ // "descr":{
1671
+ // "pair":"ETHUSDT",
1672
+ // "type":"buy",
1673
+ // "ordertype":"limit",
1674
+ // "price":"330.00",
1675
+ // "price2":"0",
1676
+ // "leverage":"none",
1677
+ // "order":"buy 0.02100000 ETHUSDT @ limit 330.00",
1678
+ // "close":""
1679
+ // },
1680
+ // "vol":"0.02100000",
1681
+ // "vol_exec":"0.00000000",
1682
+ // "cost":"0.00000",
1683
+ // "fee":"0.00000",
1684
+ // "price":"0.00000",
1685
+ // "stopprice":"0.00000",
1686
+ // "limitprice":"0.00000",
1687
+ // "misc":"",
1688
+ // "oflags":"fciq"
1689
+ // },
1690
+ // },
1691
+ // "count":16
1692
+ // }
1693
+ // }
1694
+ //
1695
+ let market = undefined;
1696
+ if (symbol !== undefined) {
1697
+ market = this.market (symbol);
1698
+ }
1699
+ const result = this.safeValue (response, 'result', {});
1700
+ const orders = this.safeValue (result, 'closed', []);
1701
+ return this.parseOrders (orders, market, since, limit);
1702
+ }
1703
+
1704
+ parseTransactionStatus (status) {
1705
+ // IFEX transaction states
1706
+ const statuses = {
1707
+ 'Initial': 'pending',
1708
+ 'Pending': 'pending',
1709
+ 'Success': 'ok',
1710
+ 'Settled': 'pending',
1711
+ 'Failure': 'failed',
1712
+ 'Partial': 'ok',
1713
+ };
1714
+ return this.safeString (statuses, status, status);
1715
+ }
1716
+
1717
+ parseTransaction (transaction, currency = undefined) {
1718
+ //
1719
+ // fetchDeposits
1720
+ //
1721
+ // {
1722
+ // method: "Ether (Hex)",
1723
+ // aclass: "currency",
1724
+ // asset: "XETH",
1725
+ // refid: "Q2CANKL-LBFVEE-U4Y2WQ",
1726
+ // txid: "0x57fd704dab1a73c20e24c8696099b695d596924b401b261513cfdab23…",
1727
+ // info: "0x615f9ba7a9575b0ab4d571b2b36b1b324bd83290",
1728
+ // amount: "7.9999257900",
1729
+ // fee: "0.0000000000",
1730
+ // time: 1529223212,
1731
+ // status: "Success"
1732
+ // }
1733
+ //
1734
+ // there can be an additional 'status-prop' field present
1735
+ // deposit pending review by exchange => 'on-hold'
1736
+ // the deposit is initiated by the exchange => 'return'
1737
+ //
1738
+ // {
1739
+ // type: 'deposit',
1740
+ // method: 'Fidor Bank AG (Wire Transfer)',
1741
+ // aclass: 'currency',
1742
+ // asset: 'ZEUR',
1743
+ // refid: 'xxx-xxx-xxx',
1744
+ // txid: '12341234',
1745
+ // info: 'BANKCODEXXX',
1746
+ // amount: '38769.08',
1747
+ // fee: '0.0000',
1748
+ // time: 1644306552,
1749
+ // status: 'Success',
1750
+ // status-prop: 'on-hold'
1751
+ // }
1752
+ //
1753
+ //
1754
+ // fetchWithdrawals
1755
+ //
1756
+ // {
1757
+ // method: "Ether",
1758
+ // aclass: "currency",
1759
+ // asset: "XETH",
1760
+ // refid: "A2BF34S-O7LBNQ-UE4Y4O",
1761
+ // txid: "0x288b83c6b0904d8400ef44e1c9e2187b5c8f7ea3d838222d53f701a15b5c274d",
1762
+ // info: "0x7cb275a5e07ba943fee972e165d80daa67cb2dd0",
1763
+ // amount: "9.9950000000",
1764
+ // fee: "0.0050000000",
1765
+ // time: 1530481750,
1766
+ // status: "Success"
1767
+ // status-prop: 'on-hold' // this field might not be present in some cases
1768
+ // }
1769
+ //
1770
+ // withdraw
1771
+ //
1772
+ // {
1773
+ // "refid": "AGBSO6T-UFMTTQ-I7KGS6"
1774
+ // }
1775
+ //
1776
+ const id = this.safeString (transaction, 'refid');
1777
+ const txid = this.safeString (transaction, 'txid');
1778
+ const timestamp = this.safeTimestamp (transaction, 'time');
1779
+ const currencyId = this.safeString (transaction, 'asset');
1780
+ const code = this.safeCurrencyCode (currencyId, currency);
1781
+ const address = this.safeString (transaction, 'info');
1782
+ const amount = this.safeNumber (transaction, 'amount');
1783
+ let status = this.parseTransactionStatus (this.safeString (transaction, 'status'));
1784
+ const statusProp = this.safeString (transaction, 'status-prop');
1785
+ const isOnHoldDeposit = statusProp === 'on-hold';
1786
+ const isCancellationRequest = statusProp === 'cancel-pending';
1787
+ const isOnHoldWithdrawal = statusProp === 'onhold';
1788
+ if (isOnHoldDeposit || isCancellationRequest || isOnHoldWithdrawal) {
1789
+ status = 'pending';
1790
+ }
1791
+ const type = this.safeString (transaction, 'type'); // injected from the outside
1792
+ let feeCost = this.safeNumber (transaction, 'fee');
1793
+ if (feeCost === undefined) {
1794
+ if (type === 'deposit') {
1795
+ feeCost = 0;
1796
+ }
1797
+ }
1798
+ return {
1799
+ 'info': transaction,
1800
+ 'id': id,
1801
+ 'currency': code,
1802
+ 'amount': amount,
1803
+ 'network': undefined,
1804
+ 'address': address,
1805
+ 'addressTo': undefined,
1806
+ 'addressFrom': undefined,
1807
+ 'tag': undefined,
1808
+ 'tagTo': undefined,
1809
+ 'tagFrom': undefined,
1810
+ 'status': status,
1811
+ 'type': type,
1812
+ 'updated': undefined,
1813
+ 'txid': txid,
1814
+ 'timestamp': timestamp,
1815
+ 'datetime': this.iso8601 (timestamp),
1816
+ 'fee': {
1817
+ 'currency': code,
1818
+ 'cost': feeCost,
1819
+ },
1820
+ };
1821
+ }
1822
+
1823
+ parseTransactionsByType (type, transactions, code = undefined, since = undefined, limit = undefined) {
1824
+ const result = [];
1825
+ for (let i = 0; i < transactions.length; i++) {
1826
+ const transaction = this.parseTransaction (this.extend ({
1827
+ 'type': type,
1828
+ }, transactions[i]));
1829
+ result.push (transaction);
1830
+ }
1831
+ return this.filterByCurrencySinceLimit (result, code, since, limit);
1832
+ }
1833
+
1834
+ async fetchDeposits (code = undefined, since = undefined, limit = undefined, params = {}) {
1835
+ // https://www.kraken.com/en-us/help/api#deposit-status
1836
+ if (code === undefined) {
1837
+ throw new ArgumentsRequired (this.id + ' fetchDeposits() requires a currency code argument');
1838
+ }
1839
+ await this.loadMarkets ();
1840
+ const currency = this.currency (code);
1841
+ const request = {
1842
+ 'asset': currency['id'],
1843
+ };
1844
+ const response = await this.privatePostDepositStatus (this.extend (request, params));
1845
+ //
1846
+ // { error: [],
1847
+ // result: [ { method: "Ether (Hex)",
1848
+ // aclass: "currency",
1849
+ // asset: "XETH",
1850
+ // refid: "Q2CANKL-LBFVEE-U4Y2WQ",
1851
+ // txid: "0x57fd704dab1a73c20e24c8696099b695d596924b401b261513cfdab23…",
1852
+ // info: "0x615f9ba7a9575b0ab4d571b2b36b1b324bd83290",
1853
+ // amount: "7.9999257900",
1854
+ // fee: "0.0000000000",
1855
+ // time: 1529223212,
1856
+ // status: "Success" } ] }
1857
+ //
1858
+ return this.parseTransactionsByType ('deposit', response['result'], code, since, limit);
1859
+ }
1860
+
1861
+ async fetchTime (params = {}) {
1862
+ // https://www.kraken.com/en-us/features/api#get-server-time
1863
+ const response = await this.publicGetTime (params);
1864
+ //
1865
+ // {
1866
+ // "error": [],
1867
+ // "result": {
1868
+ // "unixtime": 1591502873,
1869
+ // "rfc1123": "Sun, 7 Jun 20 04:07:53 +0000"
1870
+ // }
1871
+ // }
1872
+ //
1873
+ const result = this.safeValue (response, 'result', {});
1874
+ return this.safeTimestamp (result, 'unixtime');
1875
+ }
1876
+
1877
+ async fetchWithdrawals (code = undefined, since = undefined, limit = undefined, params = {}) {
1878
+ // https://www.kraken.com/en-us/help/api#withdraw-status
1879
+ if (code === undefined) {
1880
+ throw new ArgumentsRequired (this.id + ' fetchWithdrawals() requires a currency code argument');
1881
+ }
1882
+ await this.loadMarkets ();
1883
+ const currency = this.currency (code);
1884
+ const request = {
1885
+ 'asset': currency['id'],
1886
+ };
1887
+ const response = await this.privatePostWithdrawStatus (this.extend (request, params));
1888
+ //
1889
+ // { error: [],
1890
+ // result: [ { method: "Ether",
1891
+ // aclass: "currency",
1892
+ // asset: "XETH",
1893
+ // refid: "A2BF34S-O7LBNQ-UE4Y4O",
1894
+ // txid: "0x298c83c7b0904d8400ef43e1c9e2287b518f7ea3d838822d53f704a1565c274d",
1895
+ // info: "0x7cb275a5e07ba943fee972e165d80daa67cb2dd0",
1896
+ // amount: "9.9950000000",
1897
+ // fee: "0.0050000000",
1898
+ // time: 1530481750,
1899
+ // status: "Success" } ] }
1900
+ //
1901
+ return this.parseTransactionsByType ('withdrawal', response['result'], code, since, limit);
1902
+ }
1903
+
1904
+ async createDepositAddress (code, params = {}) {
1905
+ const request = {
1906
+ 'new': 'true',
1907
+ };
1908
+ return await this.fetchDepositAddress (code, this.extend (request, params));
1909
+ }
1910
+
1911
+ async fetchDepositMethods (code, params = {}) {
1912
+ await this.loadMarkets ();
1913
+ const currency = this.currency (code);
1914
+ const request = {
1915
+ 'asset': currency['id'],
1916
+ };
1917
+ const response = await this.privatePostDepositMethods (this.extend (request, params));
1918
+ //
1919
+ // {
1920
+ // "error":[],
1921
+ // "result":[
1922
+ // {"method":"Ether (Hex)","limit":false,"gen-address":true}
1923
+ // ]
1924
+ // }
1925
+ //
1926
+ // {
1927
+ // "error":[],
1928
+ // "result":[
1929
+ // {"method":"Tether USD (ERC20)","limit":false,"address-setup-fee":"0.00000000","gen-address":true},
1930
+ // {"method":"Tether USD (TRC20)","limit":false,"address-setup-fee":"0.00000000","gen-address":true}
1931
+ // ]
1932
+ // }
1933
+ //
1934
+ // {
1935
+ // "error":[],
1936
+ // "result":[
1937
+ // {"method":"Bitcoin","limit":false,"fee":"0.0000000000","gen-address":true}
1938
+ // ]
1939
+ // }
1940
+ //
1941
+ return this.safeValue (response, 'result');
1942
+ }
1943
+
1944
+ async fetchDepositAddress (code, params = {}) {
1945
+ await this.loadMarkets ();
1946
+ const currency = this.currency (code);
1947
+ let network = this.safeStringUpper (params, 'network');
1948
+ const networks = this.safeValue (this.options, 'networks', {});
1949
+ network = this.safeString (networks, network, network); // support ETH > ERC20 aliases
1950
+ params = this.omit (params, 'network');
1951
+ if ((code === 'USDT') && (network === 'TRC20')) {
1952
+ code = code + '-' + network;
1953
+ }
1954
+ const defaultDepositMethods = this.safeValue (this.options, 'depositMethods', {});
1955
+ const defaultDepositMethod = this.safeString (defaultDepositMethods, code);
1956
+ let depositMethod = this.safeString (params, 'method', defaultDepositMethod);
1957
+ // if the user has specified an exchange-specific method in params
1958
+ // we pass it as is, otherwise we take the 'network' unified param
1959
+ if (depositMethod === undefined) {
1960
+ const depositMethods = await this.fetchDepositMethods (code);
1961
+ if (network !== undefined) {
1962
+ // find best matching deposit method, or fallback to the first one
1963
+ for (let i = 0; i < depositMethods.length; i++) {
1964
+ const entry = this.safeString (depositMethods[i], 'method');
1965
+ if (entry.indexOf (network) >= 0) {
1966
+ depositMethod = entry;
1967
+ break;
1968
+ }
1969
+ }
1970
+ }
1971
+ // if depositMethod was not specified, fallback to the first available deposit method
1972
+ if (depositMethod === undefined) {
1973
+ const firstDepositMethod = this.safeValue (depositMethods, 0, {});
1974
+ depositMethod = this.safeString (firstDepositMethod, 'method');
1975
+ }
1976
+ }
1977
+ const request = {
1978
+ 'asset': currency['id'],
1979
+ 'method': depositMethod,
1980
+ };
1981
+ const response = await this.privatePostDepositAddresses (this.extend (request, params));
1982
+ //
1983
+ // {
1984
+ // "error":[],
1985
+ // "result":[
1986
+ // {"address":"0x77b5051f97efa9cc52c9ad5b023a53fc15c200d3","expiretm":"0"}
1987
+ // ]
1988
+ // }
1989
+ //
1990
+ const result = this.safeValue (response, 'result', []);
1991
+ const firstResult = this.safeValue (result, 0, {});
1992
+ if (firstResult === undefined) {
1993
+ throw new InvalidAddress (this.id + ' privatePostDepositAddresses() returned no addresses for ' + code);
1994
+ }
1995
+ return this.parseDepositAddress (firstResult, currency);
1996
+ }
1997
+
1998
+ parseDepositAddress (depositAddress, currency = undefined) {
1999
+ //
2000
+ // {
2001
+ // "address":"0x77b5051f97efa9cc52c9ad5b023a53fc15c200d3",
2002
+ // "expiretm":"0"
2003
+ // }
2004
+ //
2005
+ const address = this.safeString (depositAddress, 'address');
2006
+ const tag = this.safeString (depositAddress, 'tag');
2007
+ currency = this.safeCurrency (undefined, currency);
2008
+ const code = currency['code'];
2009
+ this.checkAddress (address);
2010
+ return {
2011
+ 'currency': code,
2012
+ 'address': address,
2013
+ 'tag': tag,
2014
+ 'network': undefined,
2015
+ 'info': depositAddress,
2016
+ };
2017
+ }
2018
+
2019
+ async withdraw (code, amount, address, tag = undefined, params = {}) {
2020
+ [ tag, params ] = this.handleWithdrawTagAndParams (tag, params);
2021
+ this.checkAddress (address);
2022
+ if ('key' in params) {
2023
+ await this.loadMarkets ();
2024
+ const currency = this.currency (code);
2025
+ const request = {
2026
+ 'asset': currency['id'],
2027
+ 'amount': amount,
2028
+ // 'address': address, // they don't allow withdrawals to direct addresses
2029
+ };
2030
+ const response = await this.privatePostWithdraw (this.extend (request, params));
2031
+ //
2032
+ // {
2033
+ // "error": [],
2034
+ // "result": {
2035
+ // "refid": "AGBSO6T-UFMTTQ-I7KGS6"
2036
+ // }
2037
+ // }
2038
+ //
2039
+ const result = this.safeValue (response, 'result', {});
2040
+ return this.parseTransaction (result, currency);
2041
+ }
2042
+ throw new ExchangeError (this.id + " withdraw() requires a 'key' parameter (withdrawal key name, as set up on your account)");
2043
+ }
2044
+
2045
+ async fetchPositions (symbols = undefined, params = {}) {
2046
+ await this.loadMarkets ();
2047
+ const request = {
2048
+ // 'txid': 'comma delimited list of transaction ids to restrict output to',
2049
+ // 'docalcs': false, // whether or not to include profit/loss calculations
2050
+ // 'consolidation': 'market', // what to consolidate the positions data around, market will consolidate positions based on market pair
2051
+ };
2052
+ const response = await this.privatePostOpenPositions (this.extend (request, params));
2053
+ //
2054
+ // no consolidation
2055
+ //
2056
+ // {
2057
+ // error: [],
2058
+ // result: {
2059
+ // 'TGUFMY-FLESJ-VYIX3J': {
2060
+ // ordertxid: "O3LRNU-ZKDG5-XNCDFR",
2061
+ // posstatus: "open",
2062
+ // pair: "ETHUSDT",
2063
+ // time: 1611557231.4584,
2064
+ // type: "buy",
2065
+ // ordertype: "market",
2066
+ // cost: "28.49800",
2067
+ // fee: "0.07979",
2068
+ // vol: "0.02000000",
2069
+ // vol_closed: "0.00000000",
2070
+ // margin: "14.24900",
2071
+ // terms: "0.0200% per 4 hours",
2072
+ // rollovertm: "1611571631",
2073
+ // misc: "",
2074
+ // oflags: ""
2075
+ // }
2076
+ // }
2077
+ // }
2078
+ //
2079
+ // consolidation by market
2080
+ //
2081
+ // {
2082
+ // error: [],
2083
+ // result: [
2084
+ // {
2085
+ // pair: "ETHUSDT",
2086
+ // positions: "1",
2087
+ // type: "buy",
2088
+ // leverage: "2.00000",
2089
+ // cost: "28.49800",
2090
+ // fee: "0.07979",
2091
+ // vol: "0.02000000",
2092
+ // vol_closed: "0.00000000",
2093
+ // margin: "14.24900"
2094
+ // }
2095
+ // ]
2096
+ // }
2097
+ //
2098
+ const result = this.safeValue (response, 'result');
2099
+ // todo unify parsePosition/parsePositions
2100
+ return result;
2101
+ }
2102
+
2103
+ sign (path, api = 'public', method = 'GET', params = {}, headers = undefined, body = undefined) {
2104
+ let url = '/' + this.version + '/' + api + '/' + path;
2105
+ if (api === 'public') {
2106
+ if (Object.keys (params).length) {
2107
+ // urlencodeNested is used to address https://github.com/ccxt/ccxt/issues/12872
2108
+ url += '?' + this.urlencodeNested (params);
2109
+ }
2110
+ } else if (api === 'private') {
2111
+ this.checkRequiredCredentials ();
2112
+ const nonce = this.nonce ().toString ();
2113
+ // urlencodeNested is used to address https://github.com/ccxt/ccxt/issues/12872
2114
+ body = this.urlencodeNested (this.extend ({ 'nonce': nonce }, params));
2115
+ const auth = this.encode (nonce + body);
2116
+ const hash = this.hash (auth, 'sha256', 'binary');
2117
+ const binary = this.stringToBinary (this.encode (url));
2118
+ const binhash = this.binaryConcat (binary, hash);
2119
+ const secret = this.base64ToBinary (this.secret);
2120
+ const signature = this.hmac (binhash, secret, 'sha512', 'base64');
2121
+ headers = {
2122
+ 'API-Key': this.apiKey,
2123
+ 'API-Sign': signature,
2124
+ 'Content-Type': 'application/x-www-form-urlencoded',
2125
+ };
2126
+ } else {
2127
+ url = '/' + path;
2128
+ }
2129
+ url = this.urls['api'][api] + url;
2130
+ return { 'url': url, 'method': method, 'body': body, 'headers': headers };
2131
+ }
2132
+
2133
+ nonce () {
2134
+ return this.milliseconds ();
2135
+ }
2136
+
2137
+ handleErrors (code, reason, url, method, headers, body, response, requestHeaders, requestBody) {
2138
+ if (code === 520) {
2139
+ throw new ExchangeNotAvailable (this.id + ' ' + code.toString () + ' ' + reason);
2140
+ }
2141
+ // todo: rewrite this for "broad" exceptions matching
2142
+ if (body.indexOf ('Invalid order') >= 0) {
2143
+ throw new InvalidOrder (this.id + ' ' + body);
2144
+ }
2145
+ if (body.indexOf ('Invalid nonce') >= 0) {
2146
+ throw new InvalidNonce (this.id + ' ' + body);
2147
+ }
2148
+ if (body.indexOf ('Insufficient funds') >= 0) {
2149
+ throw new InsufficientFunds (this.id + ' ' + body);
2150
+ }
2151
+ if (body.indexOf ('Cancel pending') >= 0) {
2152
+ throw new CancelPending (this.id + ' ' + body);
2153
+ }
2154
+ if (body.indexOf ('Invalid arguments:volume') >= 0) {
2155
+ throw new InvalidOrder (this.id + ' ' + body);
2156
+ }
2157
+ if (body.indexOf ('Rate limit exceeded') >= 0) {
2158
+ throw new RateLimitExceeded (this.id + ' ' + body);
2159
+ }
2160
+ if (response === undefined) {
2161
+ return;
2162
+ }
2163
+ if (body[0] === '{') {
2164
+ if (typeof response !== 'string') {
2165
+ if ('error' in response) {
2166
+ const numErrors = response['error'].length;
2167
+ if (numErrors) {
2168
+ const message = this.id + ' ' + body;
2169
+ for (let i = 0; i < response['error'].length; i++) {
2170
+ const error = response['error'][i];
2171
+ this.throwExactlyMatchedException (this.exceptions, error, message);
2172
+ }
2173
+ throw new ExchangeError (message);
2174
+ }
2175
+ }
2176
+ }
2177
+ }
2178
+ }
2179
+ };