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/hollaex.js ADDED
@@ -0,0 +1,1486 @@
1
+ 'use strict';
2
+
3
+ // ---------------------------------------------------------------------------
4
+
5
+ const Exchange = require ('./base/Exchange');
6
+ const { BadRequest, AuthenticationError, NetworkError, ArgumentsRequired, OrderNotFound, InsufficientFunds } = require ('./base/errors');
7
+ const { TICK_SIZE } = require ('./base/functions/number');
8
+ const Precise = require ('./base/Precise');
9
+
10
+ // ---------------------------------------------------------------------------
11
+
12
+ module.exports = class hollaex extends Exchange {
13
+ describe () {
14
+ return this.deepExtend (super.describe (), {
15
+ 'id': 'hollaex',
16
+ 'name': 'HollaEx',
17
+ 'countries': [ 'KR' ],
18
+ // 4 requests per second => 1000ms / 4 = 250 ms between requests
19
+ 'rateLimit': 250,
20
+ 'version': 'v2',
21
+ 'pro': true,
22
+ 'has': {
23
+ 'CORS': undefined,
24
+ 'spot': true,
25
+ 'margin': undefined,
26
+ 'swap': false,
27
+ 'future': false,
28
+ 'option': false,
29
+ 'addMargin': false,
30
+ 'cancelAllOrders': true,
31
+ 'cancelOrder': true,
32
+ 'createLimitBuyOrder': true,
33
+ 'createLimitSellOrder': true,
34
+ 'createMarketBuyOrder': true,
35
+ 'createMarketSellOrder': true,
36
+ 'createOrder': true,
37
+ 'createReduceOnlyOrder': false,
38
+ 'createStopLimitOrder': true,
39
+ 'createStopMarketOrder': true,
40
+ 'createStopOrder': true,
41
+ 'fetchBalance': true,
42
+ 'fetchBorrowRate': false,
43
+ 'fetchBorrowRateHistories': false,
44
+ 'fetchBorrowRateHistory': false,
45
+ 'fetchBorrowRates': false,
46
+ 'fetchBorrowRatesPerSymbol': false,
47
+ 'fetchClosedOrders': true,
48
+ 'fetchCurrencies': true,
49
+ 'fetchDepositAddress': 'emulated',
50
+ 'fetchDepositAddresses': true,
51
+ 'fetchDeposits': true,
52
+ 'fetchFundingHistory': false,
53
+ 'fetchFundingRate': false,
54
+ 'fetchFundingRateHistory': false,
55
+ 'fetchFundingRates': false,
56
+ 'fetchIndexOHLCV': false,
57
+ 'fetchLeverage': false,
58
+ 'fetchMarkets': true,
59
+ 'fetchMarkOHLCV': false,
60
+ 'fetchMyTrades': true,
61
+ 'fetchOHLCV': true,
62
+ 'fetchOpenOrder': true,
63
+ 'fetchOpenOrders': true,
64
+ 'fetchOrder': true,
65
+ 'fetchOrderBook': true,
66
+ 'fetchOrderBooks': true,
67
+ 'fetchOrders': true,
68
+ 'fetchPosition': false,
69
+ 'fetchPositions': false,
70
+ 'fetchPositionsRisk': false,
71
+ 'fetchPremiumIndexOHLCV': false,
72
+ 'fetchTicker': true,
73
+ 'fetchTickers': true,
74
+ 'fetchTrades': true,
75
+ 'fetchTradingFee': false,
76
+ 'fetchTradingFees': true,
77
+ 'fetchTransactions': undefined,
78
+ 'fetchWithdrawals': true,
79
+ 'reduceMargin': false,
80
+ 'setLeverage': false,
81
+ 'setMarginMode': false,
82
+ 'setPositionMode': false,
83
+ 'withdraw': true,
84
+ },
85
+ 'timeframes': {
86
+ '1m': '1m',
87
+ '5m': '5m',
88
+ '15m': '15m',
89
+ '1h': '1h',
90
+ '4h': '4h',
91
+ '1d': '1d',
92
+ '1w': '1w',
93
+ },
94
+ 'urls': {
95
+ 'logo': 'https://user-images.githubusercontent.com/1294454/75841031-ca375180-5ddd-11ea-8417-b975674c23cb.jpg',
96
+ 'test': {
97
+ 'rest': 'https://api.sandbox.hollaex.com',
98
+ },
99
+ 'api': {
100
+ 'rest': 'https://api.hollaex.com',
101
+ },
102
+ 'www': 'https://hollaex.com',
103
+ 'doc': 'https://apidocs.hollaex.com',
104
+ 'referral': 'https://pro.hollaex.com/signup?affiliation_code=QSWA6G',
105
+ },
106
+ 'precisionMode': TICK_SIZE,
107
+ 'requiredCredentials': {
108
+ 'apiKey': true,
109
+ 'secret': true,
110
+ },
111
+ 'api': {
112
+ 'public': {
113
+ 'get': {
114
+ 'health': 1,
115
+ 'constants': 1,
116
+ 'kit': 1,
117
+ 'tiers': 1,
118
+ 'ticker': 1,
119
+ 'tickers': 1,
120
+ 'orderbook': 1,
121
+ 'orderbooks': 1,
122
+ 'trades': 1,
123
+ 'chart': 1,
124
+ 'charts': 1,
125
+ // TradingView
126
+ 'udf/config': 1,
127
+ 'udf/history': 1,
128
+ 'udf/symbols': 1,
129
+ },
130
+ },
131
+ 'private': {
132
+ 'get': {
133
+ 'user': 1,
134
+ 'user/balance': 1,
135
+ 'user/deposits': 1,
136
+ 'user/withdrawals': 1,
137
+ 'user/withdrawal/fee': 1,
138
+ 'user/trades': 1,
139
+ 'orders': 1,
140
+ 'order': 1,
141
+ },
142
+ 'post': {
143
+ 'user/withdrawal': 1,
144
+ 'order': 1,
145
+ },
146
+ 'delete': {
147
+ 'order/all': 1,
148
+ 'order': 1,
149
+ },
150
+ },
151
+ },
152
+ 'fees': {
153
+ 'trading': {
154
+ 'tierBased': true,
155
+ 'percentage': true,
156
+ 'taker': 0.001,
157
+ 'maker': 0.001,
158
+ },
159
+ },
160
+ 'exceptions': {
161
+ 'broad': {
162
+ 'Invalid token': AuthenticationError,
163
+ 'Order not found': OrderNotFound,
164
+ 'Insufficient balance': InsufficientFunds,
165
+ },
166
+ 'exact': {
167
+ '400': BadRequest,
168
+ '403': AuthenticationError,
169
+ '404': BadRequest,
170
+ '405': BadRequest,
171
+ '410': BadRequest,
172
+ '429': BadRequest,
173
+ '500': NetworkError,
174
+ '503': NetworkError,
175
+ },
176
+ },
177
+ 'options': {
178
+ // how many seconds before the authenticated request expires
179
+ 'api-expires': parseInt (this.timeout / 1000),
180
+ },
181
+ });
182
+ }
183
+
184
+ async fetchMarkets (params = {}) {
185
+ const response = await this.publicGetConstants (params);
186
+ //
187
+ // {
188
+ // coins: {
189
+ // xmr: {
190
+ // id: 7,
191
+ // fullname: "Monero",
192
+ // symbol: "xmr",
193
+ // active: true,
194
+ // allow_deposit: true,
195
+ // allow_withdrawal: true,
196
+ // withdrawal_fee: 0.02,
197
+ // min: 0.001,
198
+ // max: 100000,
199
+ // increment_unit: 0.001,
200
+ // deposit_limits: { '1': 0, '2': 0, '3': 0, '4': 0, '5': 0, '6': 0 },
201
+ // withdrawal_limits: { '1': 10, '2': 15, '3': 100, '4': 100, '5': 200, '6': 300, '7': 350, '8': 400, '9': 500, '10': -1 },
202
+ // created_at: "2019-12-09T07:14:02.720Z",
203
+ // updated_at: "2020-01-16T12:12:53.162Z"
204
+ // },
205
+ // // ...
206
+ // },
207
+ // pairs: {
208
+ // 'btc-usdt': {
209
+ // id: 2,
210
+ // name: "btc-usdt",
211
+ // pair_base: "btc",
212
+ // pair_2: "usdt",
213
+ // taker_fees: { '1': 0.3, '2': 0.25, '3': 0.2, '4': 0.18, '5': 0.1, '6': 0.09, '7': 0.08, '8': 0.06, '9': 0.04, '10': 0 },
214
+ // maker_fees: { '1': 0.1, '2': 0.08, '3': 0.05, '4': 0.03, '5': 0, '6': 0, '7': 0, '8': 0, '9': 0, '10': 0 },
215
+ // min_size: 0.0001,
216
+ // max_size: 1000,
217
+ // min_price: 100,
218
+ // max_price: 100000,
219
+ // increment_size: 0.0001,
220
+ // increment_price: 0.05,
221
+ // active: true,
222
+ // created_at: "2019-12-09T07:15:54.537Z",
223
+ // updated_at: "2019-12-09T07:15:54.537Z"
224
+ // },
225
+ // },
226
+ // config: { tiers: 10 },
227
+ // status: true
228
+ // }
229
+ //
230
+ const pairs = this.safeValue (response, 'pairs', {});
231
+ const keys = Object.keys (pairs);
232
+ const result = [];
233
+ for (let i = 0; i < keys.length; i++) {
234
+ const key = keys[i];
235
+ const market = pairs[key];
236
+ const baseId = this.safeString (market, 'pair_base');
237
+ const quoteId = this.safeString (market, 'pair_2');
238
+ const base = this.commonCurrencyCode (baseId.toUpperCase ());
239
+ const quote = this.commonCurrencyCode (quoteId.toUpperCase ());
240
+ result.push ({
241
+ 'id': this.safeString (market, 'name'),
242
+ 'symbol': base + '/' + quote,
243
+ 'base': base,
244
+ 'quote': quote,
245
+ 'settle': undefined,
246
+ 'baseId': baseId,
247
+ 'quoteId': quoteId,
248
+ 'settleId': undefined,
249
+ 'type': 'spot',
250
+ 'spot': true,
251
+ 'margin': false,
252
+ 'swap': false,
253
+ 'future': false,
254
+ 'option': false,
255
+ 'active': this.safeValue (market, 'active'),
256
+ 'contract': false,
257
+ 'linear': undefined,
258
+ 'inverse': undefined,
259
+ 'contractSize': undefined,
260
+ 'expiry': undefined,
261
+ 'expiryDatetime': undefined,
262
+ 'strike': undefined,
263
+ 'optionType': undefined,
264
+ 'precision': {
265
+ 'amount': this.safeNumber (market, 'increment_size'),
266
+ 'price': this.safeNumber (market, 'increment_price'),
267
+ },
268
+ 'limits': {
269
+ 'leverage': {
270
+ 'min': undefined,
271
+ 'max': undefined,
272
+ },
273
+ 'amount': {
274
+ 'min': this.safeNumber (market, 'min_size'),
275
+ 'max': this.safeNumber (market, 'max_size'),
276
+ },
277
+ 'price': {
278
+ 'min': this.safeNumber (market, 'min_price'),
279
+ 'max': this.safeNumber (market, 'max_price'),
280
+ },
281
+ 'cost': {
282
+ 'min': undefined,
283
+ 'max': undefined,
284
+ },
285
+ },
286
+ 'info': market,
287
+ });
288
+ }
289
+ return result;
290
+ }
291
+
292
+ async fetchCurrencies (params = {}) {
293
+ const response = await this.publicGetConstants (params);
294
+ //
295
+ // {
296
+ // "coins":{
297
+ // "bch":{
298
+ // "id":4,
299
+ // "fullname":"Bitcoin Cash",
300
+ // "symbol":"bch",
301
+ // "active":true,
302
+ // "verified":true,
303
+ // "allow_deposit":true,
304
+ // "allow_withdrawal":true,
305
+ // "withdrawal_fee":0.0001,
306
+ // "min":0.001,
307
+ // "max":100000,
308
+ // "increment_unit":0.001,
309
+ // "logo":"https://bitholla.s3.ap-northeast-2.amazonaws.com/icon/BCH-hollaex-asset-01.svg",
310
+ // "code":"bch",
311
+ // "is_public":true,
312
+ // "meta":{},
313
+ // "estimated_price":null,
314
+ // "description":null,
315
+ // "type":"blockchain",
316
+ // "network":null,
317
+ // "standard":null,
318
+ // "issuer":"HollaEx",
319
+ // "withdrawal_fees":null,
320
+ // "created_at":"2019-08-09T10:45:43.367Z",
321
+ // "updated_at":"2021-12-13T03:08:32.372Z",
322
+ // "created_by":1,
323
+ // "owner_id":1
324
+ // },
325
+ // },
326
+ // "network":"https://api.hollaex.network"
327
+ // }
328
+ //
329
+ const coins = this.safeValue (response, 'coins', {});
330
+ const keys = Object.keys (coins);
331
+ const result = {};
332
+ for (let i = 0; i < keys.length; i++) {
333
+ const key = keys[i];
334
+ const currency = coins[key];
335
+ const id = this.safeString (currency, 'symbol');
336
+ const numericId = this.safeInteger (currency, 'id');
337
+ const code = this.safeCurrencyCode (id);
338
+ const name = this.safeString (currency, 'fullname');
339
+ const depositEnabled = this.safeValue (currency, 'allow_deposit');
340
+ const withdrawEnabled = this.safeValue (currency, 'allow_withdrawal');
341
+ const isActive = this.safeValue (currency, 'active');
342
+ const active = isActive && depositEnabled && withdrawEnabled;
343
+ const fee = this.safeNumber (currency, 'withdrawal_fee');
344
+ const precision = this.safeNumber (currency, 'increment_unit');
345
+ const withdrawalLimits = this.safeValue (currency, 'withdrawal_limits', []);
346
+ result[code] = {
347
+ 'id': id,
348
+ 'numericId': numericId,
349
+ 'code': code,
350
+ 'info': currency,
351
+ 'name': name,
352
+ 'active': active,
353
+ 'deposit': depositEnabled,
354
+ 'withdraw': withdrawEnabled,
355
+ 'fee': fee,
356
+ 'precision': precision,
357
+ 'limits': {
358
+ 'amount': {
359
+ 'min': this.safeNumber (currency, 'min'),
360
+ 'max': this.safeNumber (currency, 'max'),
361
+ },
362
+ 'withdraw': {
363
+ 'min': undefined,
364
+ 'max': this.safeValue (withdrawalLimits, 0),
365
+ },
366
+ },
367
+ };
368
+ }
369
+ return result;
370
+ }
371
+
372
+ async fetchOrderBooks (symbols = undefined, limit = undefined, params = {}) {
373
+ await this.loadMarkets ();
374
+ const response = await this.publicGetOrderbooks (params);
375
+ const result = {};
376
+ const marketIds = Object.keys (response);
377
+ for (let i = 0; i < marketIds.length; i++) {
378
+ const marketId = marketIds[i];
379
+ const orderbook = response[marketId];
380
+ const symbol = this.safeSymbol (marketId, undefined, '-');
381
+ const timestamp = this.parse8601 (this.safeString (orderbook, 'timestamp'));
382
+ result[symbol] = this.parseOrderBook (response[marketId], timestamp);
383
+ }
384
+ return result;
385
+ }
386
+
387
+ async fetchOrderBook (symbol, limit = undefined, params = {}) {
388
+ await this.loadMarkets ();
389
+ const marketId = this.marketId (symbol);
390
+ const request = {
391
+ 'symbol': marketId,
392
+ };
393
+ const response = await this.publicGetOrderbooks (this.extend (request, params));
394
+ //
395
+ // {
396
+ // "btc-usdt": {
397
+ // "bids": [
398
+ // [ 8836.4, 1.022 ],
399
+ // [ 8800, 0.0668 ],
400
+ // [ 8797.75, 0.2398 ],
401
+ // ],
402
+ // "asks": [
403
+ // [ 8839.35, 1.5334 ],
404
+ // [ 8852.6, 0.0579 ],
405
+ // [ 8860.45, 0.1815 ],
406
+ // ],
407
+ // "timestamp": "2020-03-03T02:27:25.147Z"
408
+ // },
409
+ // "eth-usdt": {},
410
+ // // ...
411
+ // }
412
+ //
413
+ const orderbook = this.safeValue (response, marketId);
414
+ const timestamp = this.parse8601 (this.safeString (orderbook, 'timestamp'));
415
+ return this.parseOrderBook (orderbook, symbol, timestamp);
416
+ }
417
+
418
+ async fetchTicker (symbol, params = {}) {
419
+ await this.loadMarkets ();
420
+ const market = this.market (symbol);
421
+ const request = {
422
+ 'symbol': market['id'],
423
+ };
424
+ const response = await this.publicGetTicker (this.extend (request, params));
425
+ //
426
+ // {
427
+ // open: 8615.55,
428
+ // close: 8841.05,
429
+ // high: 8921.1,
430
+ // low: 8607,
431
+ // last: 8841.05,
432
+ // volume: 20.2802,
433
+ // timestamp: '2020-03-03T03:11:18.964Z'
434
+ // }
435
+ //
436
+ return this.parseTicker (response, market);
437
+ }
438
+
439
+ async fetchTickers (symbols = undefined, params = {}) {
440
+ await this.loadMarkets ();
441
+ const response = await this.publicGetTickers (this.extend (params));
442
+ //
443
+ // {
444
+ // "bch-usdt": {
445
+ // "time": "2020-03-02T04:29:45.011Z",
446
+ // "open": 341.65,
447
+ // "close":337.9,
448
+ // "high":341.65,
449
+ // "low":337.3,
450
+ // "last":337.9,
451
+ // "volume":0.054,
452
+ // "symbol":"bch-usdt"
453
+ // },
454
+ // // ...
455
+ // }
456
+ //
457
+ return this.parseTickers (response, symbols);
458
+ }
459
+
460
+ parseTickers (response, symbols = undefined, params = {}) {
461
+ const result = {};
462
+ const keys = Object.keys (response);
463
+ for (let i = 0; i < keys.length; i++) {
464
+ const key = keys[i];
465
+ const ticker = response[key];
466
+ const marketId = this.safeString (ticker, 'symbol', key);
467
+ const market = this.safeMarket (marketId, undefined, '-');
468
+ const symbol = market['symbol'];
469
+ result[symbol] = this.extend (this.parseTicker (ticker, market), params);
470
+ }
471
+ return this.filterByArray (result, 'symbol', symbols);
472
+ }
473
+
474
+ parseTicker (ticker, market = undefined) {
475
+ //
476
+ // fetchTicker
477
+ //
478
+ // {
479
+ // open: 8615.55,
480
+ // close: 8841.05,
481
+ // high: 8921.1,
482
+ // low: 8607,
483
+ // last: 8841.05,
484
+ // volume: 20.2802,
485
+ // timestamp: '2020-03-03T03:11:18.964Z',
486
+ // }
487
+ //
488
+ // fetchTickers
489
+ //
490
+ // {
491
+ // "time": "2020-03-02T04:29:45.011Z",
492
+ // "open": 341.65,
493
+ // "close": 337.9,
494
+ // "high": 341.65,
495
+ // "low": 337.3,
496
+ // "last": 337.9,
497
+ // "volume": 0.054,
498
+ // "symbol": "bch-usdt"
499
+ // }
500
+ //
501
+ const marketId = this.safeString (ticker, 'symbol');
502
+ market = this.safeMarket (marketId, market, '-');
503
+ const symbol = market['symbol'];
504
+ const timestamp = this.parse8601 (this.safeString2 (ticker, 'time', 'timestamp'));
505
+ const close = this.safeString (ticker, 'close');
506
+ return this.safeTicker ({
507
+ 'symbol': symbol,
508
+ 'info': ticker,
509
+ 'timestamp': timestamp,
510
+ 'datetime': this.iso8601 (timestamp),
511
+ 'high': this.safeString (ticker, 'high'),
512
+ 'low': this.safeString (ticker, 'low'),
513
+ 'bid': undefined,
514
+ 'bidVolume': undefined,
515
+ 'ask': undefined,
516
+ 'askVolume': undefined,
517
+ 'vwap': undefined,
518
+ 'open': this.safeString (ticker, 'open'),
519
+ 'close': close,
520
+ 'last': this.safeString (ticker, 'last', close),
521
+ 'previousClose': undefined,
522
+ 'change': undefined,
523
+ 'percentage': undefined,
524
+ 'average': undefined,
525
+ 'baseVolume': this.safeString (ticker, 'volume'),
526
+ 'quoteVolume': undefined,
527
+ }, market, false);
528
+ }
529
+
530
+ async fetchTrades (symbol, since = undefined, limit = undefined, params = {}) {
531
+ await this.loadMarkets ();
532
+ const market = this.market (symbol);
533
+ const request = {
534
+ 'symbol': market['id'],
535
+ };
536
+ const response = await this.publicGetTrades (this.extend (request, params));
537
+ //
538
+ // {
539
+ // "btc-usdt": [
540
+ // {
541
+ // "size": 0.5,
542
+ // "price": 8830,
543
+ // "side": "buy",
544
+ // "timestamp": "2020-03-03T04:44:33.034Z"
545
+ // },
546
+ // // ...
547
+ // ]
548
+ // }
549
+ //
550
+ const trades = this.safeValue (response, market['id'], []);
551
+ return this.parseTrades (trades, market, since, limit);
552
+ }
553
+
554
+ parseTrade (trade, market = undefined) {
555
+ //
556
+ // fetchTrades (public)
557
+ //
558
+ // {
559
+ // "size": 0.5,
560
+ // "price": 8830,
561
+ // "side": "buy",
562
+ // "timestamp": "2020-03-03T04:44:33.034Z"
563
+ // }
564
+ //
565
+ // fetchMyTrades (private)
566
+ // {
567
+ // "side":"sell",
568
+ // "symbol":"doge-usdt",
569
+ // "size":70,
570
+ // "price":0.147411,
571
+ // "timestamp":"2022-01-26T17:53:34.650Z",
572
+ // "order_id":"cba78ecb-4187-4da2-9d2f-c259aa693b5a",
573
+ // "fee":0.01031877,"fee_coin":"usdt"
574
+ // }
575
+ //
576
+ const marketId = this.safeString (trade, 'symbol');
577
+ market = this.safeMarket (marketId, market, '-');
578
+ const symbol = market['symbol'];
579
+ const datetime = this.safeString (trade, 'timestamp');
580
+ const timestamp = this.parse8601 (datetime);
581
+ const side = this.safeString (trade, 'side');
582
+ const orderId = this.safeString (trade, 'order_id');
583
+ const priceString = this.safeString (trade, 'price');
584
+ const amountString = this.safeString (trade, 'size');
585
+ const feeCostString = this.safeString (trade, 'fee');
586
+ let fee = undefined;
587
+ if (feeCostString !== undefined) {
588
+ fee = {
589
+ 'cost': feeCostString,
590
+ 'currency': market['quote'],
591
+ };
592
+ }
593
+ return this.safeTrade ({
594
+ 'info': trade,
595
+ 'id': undefined,
596
+ 'timestamp': timestamp,
597
+ 'datetime': datetime,
598
+ 'symbol': symbol,
599
+ 'order': orderId,
600
+ 'type': undefined,
601
+ 'side': side,
602
+ 'takerOrMaker': undefined,
603
+ 'price': priceString,
604
+ 'amount': amountString,
605
+ 'cost': undefined,
606
+ 'fee': fee,
607
+ }, market);
608
+ }
609
+
610
+ async fetchTradingFees (params = {}) {
611
+ await this.loadMarkets ();
612
+ const response = await this.publicGetTiers (params);
613
+ //
614
+ // {
615
+ // '1': {
616
+ // id: '1',
617
+ // name: 'Silver',
618
+ // icon: '',
619
+ // description: 'Your crypto journey starts here! Make your first deposit to start trading, and verify your account to level up!',
620
+ // deposit_limit: '0',
621
+ // withdrawal_limit: '1000',
622
+ // fees: {
623
+ // maker: {
624
+ // 'eth-btc': '0.1',
625
+ // 'ada-usdt': '0.1',
626
+ // ...
627
+ // },
628
+ // taker: {
629
+ // 'eth-btc': '0.1',
630
+ // 'ada-usdt': '0.1',
631
+ // ...
632
+ // }
633
+ // },
634
+ // note: '<ul>\n<li>Login and verify email</li>\n</ul>\n',
635
+ // created_at: '2021-03-22T03:51:39.129Z',
636
+ // updated_at: '2021-11-01T02:51:56.214Z'
637
+ // },
638
+ // ...
639
+ // }
640
+ //
641
+ const firstTier = this.safeValue (response, '1', {});
642
+ const fees = this.safeValue (firstTier, 'fees', {});
643
+ const makerFees = this.safeValue (fees, 'maker', {});
644
+ const takerFees = this.safeValue (fees, 'taker', {});
645
+ const result = {};
646
+ for (let i = 0; i < this.symbols.length; i++) {
647
+ const symbol = this.symbols[i];
648
+ const market = this.market (symbol);
649
+ const makerString = this.safeString (makerFees, market['id']);
650
+ const takerString = this.safeString (takerFees, market['id']);
651
+ result[symbol] = {
652
+ 'info': fees,
653
+ 'symbol': symbol,
654
+ 'maker': this.parseNumber (Precise.stringDiv (makerString, '100')),
655
+ 'taker': this.parseNumber (Precise.stringDiv (takerString, '100')),
656
+ 'percentage': true,
657
+ 'tierBased': true,
658
+ };
659
+ }
660
+ return result;
661
+ }
662
+
663
+ async fetchOHLCV (symbol, timeframe = '1h', since = undefined, limit = undefined, params = {}) {
664
+ await this.loadMarkets ();
665
+ const market = this.market (symbol);
666
+ const request = {
667
+ 'symbol': market['id'],
668
+ 'resolution': this.timeframes[timeframe],
669
+ };
670
+ const duration = this.parseTimeframe (timeframe);
671
+ if (since === undefined) {
672
+ if (limit === undefined) {
673
+ throw new ArgumentsRequired (this.id + " fetchOHLCV() requires a 'since' or a 'limit' argument");
674
+ } else {
675
+ const end = this.seconds ();
676
+ const start = end - duration * limit;
677
+ request['to'] = end;
678
+ request['from'] = start;
679
+ }
680
+ } else {
681
+ if (limit === undefined) {
682
+ request['from'] = parseInt (since / 1000);
683
+ request['to'] = this.seconds ();
684
+ } else {
685
+ const start = parseInt (since / 1000);
686
+ request['from'] = start;
687
+ request['to'] = this.sum (start, duration * limit);
688
+ }
689
+ }
690
+ const response = await this.publicGetChart (this.extend (request, params));
691
+ //
692
+ // [
693
+ // {
694
+ // "time":"2020-03-02T20:00:00.000Z",
695
+ // "close":8872.1,
696
+ // "high":8872.1,
697
+ // "low":8858.6,
698
+ // "open":8858.6,
699
+ // "symbol":"btc-usdt",
700
+ // "volume":1.2922
701
+ // },
702
+ // ]
703
+ //
704
+ return this.parseOHLCVs (response, market, timeframe, since, limit);
705
+ }
706
+
707
+ parseOHLCV (response, market = undefined, timeframe = '1h', since = undefined, limit = undefined) {
708
+ //
709
+ // {
710
+ // "time":"2020-03-02T20:00:00.000Z",
711
+ // "close":8872.1,
712
+ // "high":8872.1,
713
+ // "low":8858.6,
714
+ // "open":8858.6,
715
+ // "symbol":"btc-usdt",
716
+ // "volume":1.2922
717
+ // }
718
+ //
719
+ return [
720
+ this.parse8601 (this.safeString (response, 'time')),
721
+ this.safeNumber (response, 'open'),
722
+ this.safeNumber (response, 'high'),
723
+ this.safeNumber (response, 'low'),
724
+ this.safeNumber (response, 'close'),
725
+ this.safeNumber (response, 'volume'),
726
+ ];
727
+ }
728
+
729
+ parseBalance (response) {
730
+ const timestamp = this.parse8601 (this.safeString (response, 'updated_at'));
731
+ const result = {
732
+ 'info': response,
733
+ 'timestamp': timestamp,
734
+ 'datetime': this.iso8601 (timestamp),
735
+ };
736
+ const currencyIds = Object.keys (this.currencies_by_id);
737
+ for (let i = 0; i < currencyIds.length; i++) {
738
+ const currencyId = currencyIds[i];
739
+ const code = this.safeCurrencyCode (currencyId);
740
+ const account = this.account ();
741
+ account['free'] = this.safeString (response, currencyId + '_available');
742
+ account['total'] = this.safeString (response, currencyId + '_balance');
743
+ result[code] = account;
744
+ }
745
+ return this.safeBalance (result);
746
+ }
747
+
748
+ async fetchBalance (params = {}) {
749
+ await this.loadMarkets ();
750
+ const response = await this.privateGetUserBalance (params);
751
+ //
752
+ // {
753
+ // "updated_at": "2020-03-02T22:27:38.428Z",
754
+ // "btc_balance": 0,
755
+ // "btc_pending": 0,
756
+ // "btc_available": 0,
757
+ // "eth_balance": 0,
758
+ // "eth_pending": 0,
759
+ // "eth_available": 0,
760
+ // // ...
761
+ // }
762
+ //
763
+ return this.parseBalance (response);
764
+ }
765
+
766
+ async fetchOpenOrder (id, symbol = undefined, params = {}) {
767
+ await this.loadMarkets ();
768
+ const request = {
769
+ 'order_id': id,
770
+ };
771
+ const response = await this.privateGetOrder (this.extend (request, params));
772
+ //
773
+ // {
774
+ // "id": "string",
775
+ // "side": "sell",
776
+ // "symbol": "xht-usdt",
777
+ // "size": 0.1,
778
+ // "filled": 0,
779
+ // "stop": null,
780
+ // "fee": 0,
781
+ // "fee_coin": "usdt",
782
+ // "type": "limit",
783
+ // "price": 1.09,
784
+ // "status": "new",
785
+ // "created_by": 116,
786
+ // "created_at": "2021-02-17T02:32:38.910Z",
787
+ // "updated_at": "2021-02-17T02:32:38.910Z",
788
+ // "User": {
789
+ // "id": 116,
790
+ // "email": "fight@club.com",
791
+ // "username": "narrator",
792
+ // "exchange_id": 176
793
+ // }
794
+ // }
795
+ //
796
+ return this.parseOrder (response);
797
+ }
798
+
799
+ async fetchOpenOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) {
800
+ const request = {
801
+ 'open': true,
802
+ };
803
+ return await this.fetchOrders (symbol, since, limit, this.extend (request, params));
804
+ }
805
+
806
+ async fetchClosedOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) {
807
+ const request = {
808
+ 'open': false,
809
+ };
810
+ return await this.fetchOrders (symbol, since, limit, this.extend (request, params));
811
+ }
812
+
813
+ async fetchOrder (id, symbol = undefined, params = {}) {
814
+ await this.loadMarkets ();
815
+ const request = {
816
+ 'order_id': id,
817
+ };
818
+ const response = await this.privateGetOrder (this.extend (request, params));
819
+ // {
820
+ // "id": "string",
821
+ // "side": "sell",
822
+ // "symbol": "xht-usdt",
823
+ // "size": 0.1,
824
+ // "filled": 0,
825
+ // "stop": null,
826
+ // "fee": 0,
827
+ // "fee_coin": "usdt",
828
+ // "type": "limit",
829
+ // "price": 1.09,
830
+ // "status": "new",
831
+ // "created_by": 116,
832
+ // "created_at": "2021-02-17T02:32:38.910Z",
833
+ // "updated_at": "2021-02-17T02:32:38.910Z",
834
+ // "User": {
835
+ // "id": 116,
836
+ // "email": "fight@club.com",
837
+ // "username": "narrator",
838
+ // "exchange_id": 176
839
+ // }
840
+ // }
841
+ const order = response;
842
+ if (order === undefined) {
843
+ throw new OrderNotFound (this.id + ' fetchOrder() could not find order id ' + id);
844
+ }
845
+ return this.parseOrder (order);
846
+ }
847
+
848
+ async fetchOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) {
849
+ await this.loadMarkets ();
850
+ let market = undefined;
851
+ const request = {
852
+ // 'symbol': market['id'],
853
+ // 'side': 'buy', // 'sell'
854
+ // 'status': 'new', // 'filled', 'pfilled', 'canceled'
855
+ // 'open': true,
856
+ // 'limit': limit, // default 50, max 100
857
+ // 'page': 1,
858
+ // 'order_by': 'created_at', // id, ...
859
+ // 'order': 'asc', // 'desc'
860
+ // 'start_date': this.iso8601 (since),
861
+ // 'end_date': this.iso8601 (this.milliseconds ()),
862
+ };
863
+ if (symbol !== undefined) {
864
+ market = this.market (symbol);
865
+ request['symbol'] = market['id'];
866
+ }
867
+ if (since !== undefined) {
868
+ request['start_date'] = this.iso8601 (since);
869
+ }
870
+ if (limit !== undefined) {
871
+ request['limit'] = limit; // default 50, max 100
872
+ }
873
+ const response = await this.privateGetOrders (this.extend (request, params));
874
+ //
875
+ // {
876
+ // "count": 1,
877
+ // "data": [
878
+ // {
879
+ // "id": "string",
880
+ // "side": "sell",
881
+ // "symbol": "xht-usdt",
882
+ // "size": 0.1,
883
+ // "filled": 0,
884
+ // "stop": null,
885
+ // "fee": 0,
886
+ // "fee_coin": "usdt",
887
+ // "type": "limit",
888
+ // "price": 1.09,
889
+ // "status": "new",
890
+ // "created_by": 116,
891
+ // "created_at": "2021-02-17T02:32:38.910Z",
892
+ // "updated_at": "2021-02-17T02:32:38.910Z",
893
+ // "User": {
894
+ // "id": 116,
895
+ // "email": "fight@club.com",
896
+ // "username": "narrator",
897
+ // "exchange_id": 176
898
+ // }
899
+ // }
900
+ // ]
901
+ // }
902
+ //
903
+ const data = this.safeValue (response, 'data', []);
904
+ return this.parseOrders (data, market, since, limit);
905
+ }
906
+
907
+ parseOrderStatus (status) {
908
+ const statuses = {
909
+ 'new': 'open',
910
+ 'pfilled': 'open',
911
+ 'filled': 'closed',
912
+ 'canceled': 'canceled',
913
+ };
914
+ return this.safeString (statuses, status, status);
915
+ }
916
+
917
+ parseOrder (order, market = undefined) {
918
+ //
919
+ // createOrder, fetchOpenOrder, fetchOpenOrders
920
+ //
921
+ // {
922
+ // "id": "string",
923
+ // "side": "sell",
924
+ // "symbol": "xht-usdt",
925
+ // "size": 0.1,
926
+ // "filled": 0,
927
+ // "stop": null,
928
+ // "fee": 0,
929
+ // "fee_coin": "usdt",
930
+ // "type": "limit",
931
+ // "price": 1.09,
932
+ // "status": "new",
933
+ // "created_by": 116,
934
+ // "created_at": "2021-02-17T02:32:38.910Z",
935
+ // "updated_at": "2021-02-17T02:32:38.910Z",
936
+ // "User": {
937
+ // "id": 116,
938
+ // "email": "fight@club.com",
939
+ // "username": "narrator",
940
+ // "exchange_id": 176
941
+ // },
942
+ // "fee_structure": {
943
+ // "maker": 0.2,
944
+ // "taker": 0.2
945
+ // },
946
+ // }
947
+ //
948
+ const marketId = this.safeString (order, 'symbol');
949
+ const symbol = this.safeSymbol (marketId, market, '-');
950
+ const id = this.safeString (order, 'id');
951
+ const timestamp = this.parse8601 (this.safeString (order, 'created_at'));
952
+ const type = this.safeString (order, 'type');
953
+ const side = this.safeString (order, 'side');
954
+ const price = this.safeString (order, 'price');
955
+ const amount = this.safeString (order, 'size');
956
+ const filled = this.safeString (order, 'filled');
957
+ const status = this.parseOrderStatus (this.safeString (order, 'status'));
958
+ return this.safeOrder ({
959
+ 'id': id,
960
+ 'clientOrderId': undefined,
961
+ 'timestamp': timestamp,
962
+ 'datetime': this.iso8601 (timestamp),
963
+ 'lastTradeTimestamp': undefined,
964
+ 'status': status,
965
+ 'symbol': symbol,
966
+ 'type': type,
967
+ 'timeInForce': undefined,
968
+ 'postOnly': undefined,
969
+ 'side': side,
970
+ 'price': price,
971
+ 'stopPrice': undefined,
972
+ 'amount': amount,
973
+ 'filled': filled,
974
+ 'remaining': undefined,
975
+ 'cost': undefined,
976
+ 'trades': undefined,
977
+ 'fee': undefined,
978
+ 'info': order,
979
+ 'average': undefined,
980
+ }, market);
981
+ }
982
+
983
+ async createOrder (symbol, type, side, amount, price = undefined, params = {}) {
984
+ await this.loadMarkets ();
985
+ const market = this.market (symbol);
986
+ const request = {
987
+ 'symbol': market['id'],
988
+ 'side': side,
989
+ 'size': this.normalizeNumberIfNeeded (amount),
990
+ 'type': type,
991
+ // 'stop': parseFloat (this.priceToPrecision (symbol, stopPrice)),
992
+ // 'meta': {}, // other options such as post_only
993
+ };
994
+ if (type !== 'market') {
995
+ const convertedPrice = parseFloat (this.priceToPrecision (symbol, price));
996
+ request['price'] = this.normalizeNumberIfNeeded (convertedPrice);
997
+ }
998
+ const stopPrice = this.safeNumber2 (params, 'stopPrice', 'stop');
999
+ if (stopPrice !== undefined) {
1000
+ request['stop'] = this.normalizeNumberIfNeeded (parseFloat (this.priceToPrecision (symbol, stopPrice)));
1001
+ params = this.omit (params, [ 'stopPrice', 'stop' ]);
1002
+ }
1003
+ const response = await this.privatePostOrder (this.extend (request, params));
1004
+ //
1005
+ // {
1006
+ // "fee": 0,
1007
+ // "meta": {},
1008
+ // "symbol": "xht-usdt",
1009
+ // "side": "sell",
1010
+ // "size": 0.1,
1011
+ // "type": "limit",
1012
+ // "price": 1,
1013
+ // "fee_structure": {
1014
+ // "maker": 0.2,
1015
+ // "taker": 0.2
1016
+ // },
1017
+ // "fee_coin": "usdt",
1018
+ // "id": "string",
1019
+ // "created_by": 116,
1020
+ // "filled": 0,
1021
+ // "status": "new",
1022
+ // "updated_at": "2021-02-17T03:03:19.231Z",
1023
+ // "created_at": "2021-02-17T03:03:19.231Z",
1024
+ // "stop": null
1025
+ // }
1026
+ //
1027
+ return this.parseOrder (response, market);
1028
+ }
1029
+
1030
+ async cancelOrder (id, symbol = undefined, params = {}) {
1031
+ await this.loadMarkets ();
1032
+ const request = {
1033
+ 'order_id': id,
1034
+ };
1035
+ const response = await this.privateDeleteOrder (this.extend (request, params));
1036
+ //
1037
+ // {
1038
+ // "title": "string",
1039
+ // "symbol": "xht-usdt",
1040
+ // "side": "sell",
1041
+ // "size": 1,
1042
+ // "type": "limit",
1043
+ // "price": 0.1,
1044
+ // "id": "string",
1045
+ // "created_by": 34,
1046
+ // "filled": 0
1047
+ // }
1048
+ //
1049
+ return this.parseOrder (response);
1050
+ }
1051
+
1052
+ async cancelAllOrders (symbol = undefined, params = {}) {
1053
+ if (symbol === undefined) {
1054
+ throw new ArgumentsRequired (this.id + " cancelAllOrders() requires a 'symbol' argument");
1055
+ }
1056
+ await this.loadMarkets ();
1057
+ const request = {};
1058
+ let market = undefined;
1059
+ market = this.market (symbol);
1060
+ request['symbol'] = market['id'];
1061
+ const response = await this.privateDeleteOrderAll (this.extend (request, params));
1062
+ //
1063
+ // [
1064
+ // {
1065
+ // "title": "string",
1066
+ // "symbol": "xht-usdt",
1067
+ // "side": "sell",
1068
+ // "size": 1,
1069
+ // "type": "limit",
1070
+ // "price": 0.1,
1071
+ // "id": "string",
1072
+ // "created_by": 34,
1073
+ // "filled": 0
1074
+ // }
1075
+ // ]
1076
+ //
1077
+ return this.parseOrders (response, market);
1078
+ }
1079
+
1080
+ async fetchMyTrades (symbol = undefined, since = undefined, limit = undefined, params = {}) {
1081
+ await this.loadMarkets ();
1082
+ const request = {
1083
+ // 'symbol': market['id'],
1084
+ // 'limit': 50, // default 50, max 100
1085
+ // 'page': 1, // page of data to retrieve
1086
+ // 'order_by': 'timestamp', // field to order data
1087
+ // 'order': 'asc', // asc or desc
1088
+ // 'start_date': 123, // starting date of queried data
1089
+ // 'end_date': 321, // ending date of queried data
1090
+ };
1091
+ let market = undefined;
1092
+ if (symbol !== undefined) {
1093
+ market = this.market (symbol);
1094
+ request['symbol'] = market['id'];
1095
+ }
1096
+ if (limit !== undefined) {
1097
+ request['limit'] = limit; // default 50, max 100
1098
+ }
1099
+ if (since !== undefined) {
1100
+ request['start_date'] = this.iso8601 (since);
1101
+ }
1102
+ const response = await this.privateGetUserTrades (this.extend (request, params));
1103
+ //
1104
+ // {
1105
+ // "count": 1,
1106
+ // "data": [
1107
+ // {
1108
+ // "side": "buy",
1109
+ // "symbol": "eth-usdt",
1110
+ // "size": 0.086,
1111
+ // "price": 226.19,
1112
+ // "timestamp": "2020-03-03T08:03:55.459Z",
1113
+ // "fee": 0.1
1114
+ // }
1115
+ // ]
1116
+ // }
1117
+ //
1118
+ const data = this.safeValue (response, 'data', []);
1119
+ return this.parseTrades (data, market, since, limit);
1120
+ }
1121
+
1122
+ parseDepositAddress (depositAddress, currency = undefined) {
1123
+ //
1124
+ // {
1125
+ // "currency":"usdt",
1126
+ // "address":"TECLD9XBH31XpyykdHU3uEAeUK7E6Lrmik",
1127
+ // "network":"trx",
1128
+ // "standard":null,
1129
+ // "is_valid":true,
1130
+ // "created_at":"2021-05-12T02:43:05.446Z"
1131
+ // }
1132
+ //
1133
+ let address = this.safeString (depositAddress, 'address');
1134
+ let tag = undefined;
1135
+ if (address !== undefined) {
1136
+ const parts = address.split (':');
1137
+ address = this.safeString (parts, 0);
1138
+ tag = this.safeString (parts, 1);
1139
+ }
1140
+ this.checkAddress (address);
1141
+ const currencyId = this.safeString (depositAddress, 'currency');
1142
+ currency = this.safeCurrency (currencyId, currency);
1143
+ const network = this.safeString (depositAddress, 'network');
1144
+ return {
1145
+ 'currency': currency['code'],
1146
+ 'address': address,
1147
+ 'tag': tag,
1148
+ 'network': network,
1149
+ 'info': depositAddress,
1150
+ };
1151
+ }
1152
+
1153
+ async fetchDepositAddresses (codes = undefined, params = {}) {
1154
+ await this.loadMarkets ();
1155
+ const network = this.safeString (params, 'network');
1156
+ params = this.omit (params, 'network');
1157
+ const response = await this.privateGetUser (params);
1158
+ //
1159
+ // {
1160
+ // "id":620,
1161
+ // "email":"igor.kroitor@gmail.com",
1162
+ // "full_name":"",
1163
+ // "gender":false,
1164
+ // "nationality":"",
1165
+ // "dob":null,
1166
+ // "phone_number":"",
1167
+ // "address":{"city":"","address":"","country":"","postal_code":""},
1168
+ // "id_data":{"note":"","type":"","number":"","status":0,"issued_date":"","expiration_date":""},
1169
+ // "bank_account":[],
1170
+ // "crypto_wallet":{},
1171
+ // "verification_level":1,
1172
+ // "email_verified":true,
1173
+ // "otp_enabled":true,
1174
+ // "activated":true,
1175
+ // "username":"igor.kroitor",
1176
+ // "affiliation_code":"QSWA6G",
1177
+ // "settings":{
1178
+ // "chat":{"set_username":false},
1179
+ // "risk":{"popup_warning":false,"order_portfolio_percentage":20},
1180
+ // "audio":{"public_trade":false,"order_completed":true,"order_partially_completed":true},
1181
+ // "language":"en",
1182
+ // "interface":{"theme":"white","order_book_levels":10},
1183
+ // "notification":{"popup_order_completed":true,"popup_order_confirmation":true,"popup_order_partially_filled":true}
1184
+ // },
1185
+ // "affiliation_rate":0,
1186
+ // "network_id":10620,
1187
+ // "discount":0,
1188
+ // "created_at":"2021-03-24T02:37:57.379Z",
1189
+ // "updated_at":"2021-03-24T02:37:57.379Z",
1190
+ // "balance":{
1191
+ // "btc_balance":0,
1192
+ // "btc_available":0,
1193
+ // "eth_balance":0.000914,
1194
+ // "eth_available":0.000914,
1195
+ // "updated_at":"2020-03-04T04:03:27.174Z
1196
+ // "},
1197
+ // "wallet":[
1198
+ // {"currency":"usdt","address":"TECLD9XBH31XpyykdHU3uEAeUK7E6Lrmik","network":"trx","standard":null,"is_valid":true,"created_at":"2021-05-12T02:43:05.446Z"},
1199
+ // {"currency":"xrp","address":"rGcSzmuRx8qngPRnrvpCKkP9V4njeCPGCv:286741597","network":"xrp","standard":null,"is_valid":true,"created_at":"2021-05-12T02:49:01.273Z"}
1200
+ // ]
1201
+ // }
1202
+ //
1203
+ const wallet = this.safeValue (response, 'wallet', []);
1204
+ const addresses = (network === undefined) ? wallet : this.filterBy (wallet, 'network', network);
1205
+ return this.parseDepositAddresses (addresses, codes);
1206
+ }
1207
+
1208
+ async fetchDeposits (code = undefined, since = undefined, limit = undefined, params = {}) {
1209
+ await this.loadMarkets ();
1210
+ const request = {
1211
+ // 'currency': currency['id'],
1212
+ // 'limit': 50, // default 50, max 100
1213
+ // 'page': 1, // page of data to retrieve
1214
+ // 'order_by': 'timestamp', // field to order data
1215
+ // 'order': 'asc', // asc or desc
1216
+ // 'start_date': 123, // starting date of queried data
1217
+ // 'end_date': 321, // ending date of queried data
1218
+ };
1219
+ let currency = undefined;
1220
+ if (code !== undefined) {
1221
+ currency = this.currency (code);
1222
+ request['currency'] = currency['id'];
1223
+ }
1224
+ if (limit !== undefined) {
1225
+ request['limit'] = limit; // default 50, max 100
1226
+ }
1227
+ if (since !== undefined) {
1228
+ request['start_date'] = this.iso8601 (since);
1229
+ }
1230
+ const response = await this.privateGetUserDeposits (this.extend (request, params));
1231
+ //
1232
+ // {
1233
+ // "count": 1,
1234
+ // "data": [
1235
+ // {
1236
+ // "id": 539,
1237
+ // "amount": 20,
1238
+ // "fee": 0,
1239
+ // "address": "0x5c0cc98270d7089408fcbcc8e2131287f5be2306",
1240
+ // "transaction_id": "0xd4006327a5ec2c41adbdcf566eaaba6597c3d45906abe78ea1a4a022647c2e28",
1241
+ // "status": true,
1242
+ // "dismissed": false,
1243
+ // "rejected": false,
1244
+ // "description": "",
1245
+ // "type": "deposit",
1246
+ // "currency": "usdt",
1247
+ // "created_at": "2020-03-03T07:56:36.198Z",
1248
+ // "updated_at": "2020-03-03T08:00:05.674Z",
1249
+ // "user_id": 620
1250
+ // }
1251
+ // ]
1252
+ // }
1253
+ //
1254
+ const data = this.safeValue (response, 'data', []);
1255
+ return this.parseTransactions (data, currency, since, limit);
1256
+ }
1257
+
1258
+ async fetchWithdrawals (code = undefined, since = undefined, limit = undefined, params = {}) {
1259
+ await this.loadMarkets ();
1260
+ const request = {
1261
+ // 'currency': currency['id'],
1262
+ // 'limit': 50, // default 50, max 100
1263
+ // 'page': 1, // page of data to retrieve
1264
+ // 'order_by': 'timestamp', // field to order data
1265
+ // 'order': 'asc', // asc or desc
1266
+ // 'start_date': 123, // starting date of queried data
1267
+ // 'end_date': 321, // ending date of queried data
1268
+ };
1269
+ let currency = undefined;
1270
+ if (code !== undefined) {
1271
+ currency = this.currency (code);
1272
+ request['currency'] = currency['id'];
1273
+ }
1274
+ if (limit !== undefined) {
1275
+ request['limit'] = limit; // default 50, max 100
1276
+ }
1277
+ if (since !== undefined) {
1278
+ request['start_date'] = this.iso8601 (since);
1279
+ }
1280
+ const response = await this.privateGetUserWithdrawals (this.extend (request, params));
1281
+ //
1282
+ // {
1283
+ // "count": 1,
1284
+ // "data": [
1285
+ // {
1286
+ // "id": 539,
1287
+ // "amount": 20,
1288
+ // "fee": 0,
1289
+ // "address": "0x5c0cc98270d7089408fcbcc8e2131287f5be2306",
1290
+ // "transaction_id": "0xd4006327a5ec2c41adbdcf566eaaba6597c3d45906abe78ea1a4a022647c2e28",
1291
+ // "status": true,
1292
+ // "dismissed": false,
1293
+ // "rejected": false,
1294
+ // "description": "",
1295
+ // "type": "withdrawal",
1296
+ // "currency": "usdt",
1297
+ // "created_at": "2020-03-03T07:56:36.198Z",
1298
+ // "updated_at": "2020-03-03T08:00:05.674Z",
1299
+ // "user_id": 620
1300
+ // }
1301
+ // ]
1302
+ // }
1303
+ //
1304
+ const data = this.safeValue (response, 'data', []);
1305
+ return this.parseTransactions (data, currency, since, limit);
1306
+ }
1307
+
1308
+ parseTransaction (transaction, currency = undefined) {
1309
+ //
1310
+ // fetchWithdrawals, fetchDeposits
1311
+ //
1312
+ // {
1313
+ // "id": 539,
1314
+ // "amount": 20,
1315
+ // "fee": 0,
1316
+ // "address": "0x5c0cc98270d7089408fcbcc8e2131287f5be2306",
1317
+ // "transaction_id": "0xd4006327a5ec2c41adbdcf566eaaba6597c3d45906abe78ea1a4a022647c2e28",
1318
+ // "status": true,
1319
+ // "dismissed": false,
1320
+ // "rejected": false,
1321
+ // "description": "",
1322
+ // "type": "withdrawal",
1323
+ // "currency": "usdt",
1324
+ // "created_at": "2020-03-03T07:56:36.198Z",
1325
+ // "updated_at": "2020-03-03T08:00:05.674Z",
1326
+ // "user_id": 620
1327
+ // }
1328
+ //
1329
+ // withdraw
1330
+ //
1331
+ // {
1332
+ // message: 'Withdrawal request is in the queue and will be processed.',
1333
+ // transaction_id: '1d1683c3-576a-4d53-8ff5-27c93fd9758a',
1334
+ // amount: 1,
1335
+ // currency: 'xht',
1336
+ // fee: 0,
1337
+ // fee_coin: 'xht'
1338
+ // }
1339
+ //
1340
+ const id = this.safeString (transaction, 'id');
1341
+ const txid = this.safeString (transaction, 'transaction_id');
1342
+ const timestamp = this.parse8601 (this.safeString (transaction, 'created_at'));
1343
+ const updated = this.parse8601 (this.safeString (transaction, 'updated_at'));
1344
+ const type = this.safeString (transaction, 'type');
1345
+ const amount = this.safeNumber (transaction, 'amount');
1346
+ let address = this.safeString (transaction, 'address');
1347
+ let addressTo = undefined;
1348
+ const addressFrom = undefined;
1349
+ let tag = undefined;
1350
+ let tagTo = undefined;
1351
+ const tagFrom = undefined;
1352
+ if (address !== undefined) {
1353
+ const parts = address.split (':');
1354
+ address = this.safeString (parts, 0);
1355
+ tag = this.safeString (parts, 1);
1356
+ addressTo = address;
1357
+ tagTo = tag;
1358
+ }
1359
+ const currencyId = this.safeString (transaction, 'currency');
1360
+ currency = this.safeCurrency (currencyId, currency);
1361
+ let status = this.safeValue (transaction, 'status');
1362
+ const dismissed = this.safeValue (transaction, 'dismissed');
1363
+ const rejected = this.safeValue (transaction, 'rejected');
1364
+ if (status) {
1365
+ status = 'ok';
1366
+ } else if (dismissed) {
1367
+ status = 'canceled';
1368
+ } else if (rejected) {
1369
+ status = 'failed';
1370
+ } else {
1371
+ status = 'pending';
1372
+ }
1373
+ const feeCurrencyId = this.safeString (transaction, 'fee_coin');
1374
+ const feeCurrencyCode = this.safeCurrencyCode (feeCurrencyId, currency);
1375
+ const fee = {
1376
+ 'currency': feeCurrencyCode,
1377
+ 'cost': this.safeNumber (transaction, 'fee'),
1378
+ };
1379
+ return {
1380
+ 'info': transaction,
1381
+ 'id': id,
1382
+ 'txid': txid,
1383
+ 'timestamp': timestamp,
1384
+ 'datetime': this.iso8601 (timestamp),
1385
+ 'network': undefined,
1386
+ 'addressFrom': addressFrom,
1387
+ 'address': address,
1388
+ 'addressTo': addressTo,
1389
+ 'tagFrom': tagFrom,
1390
+ 'tag': tag,
1391
+ 'tagTo': tagTo,
1392
+ 'type': type,
1393
+ 'amount': amount,
1394
+ 'currency': currency['code'],
1395
+ 'status': status,
1396
+ 'updated': updated,
1397
+ 'fee': fee,
1398
+ };
1399
+ }
1400
+
1401
+ async withdraw (code, amount, address, tag = undefined, params = {}) {
1402
+ [ tag, params ] = this.handleWithdrawTagAndParams (tag, params);
1403
+ this.checkAddress (address);
1404
+ await this.loadMarkets ();
1405
+ const currency = this.currency (code);
1406
+ if (tag !== undefined) {
1407
+ address += ':' + tag;
1408
+ }
1409
+ const request = {
1410
+ 'currency': currency['id'],
1411
+ 'amount': amount,
1412
+ 'address': address,
1413
+ };
1414
+ const network = this.safeString (params, 'network');
1415
+ if (network !== undefined) {
1416
+ request['network'] = network;
1417
+ }
1418
+ const response = await this.privatePostUserWithdrawal (this.extend (request, params));
1419
+ //
1420
+ // {
1421
+ // message: 'Withdrawal request is in the queue and will be processed.',
1422
+ // transaction_id: '1d1683c3-576a-4d53-8ff5-27c93fd9758a',
1423
+ // amount: 1,
1424
+ // currency: 'xht',
1425
+ // fee: 0,
1426
+ // fee_coin: 'xht'
1427
+ // }
1428
+ //
1429
+ return this.parseTransaction (response, currency);
1430
+ }
1431
+
1432
+ normalizeNumberIfNeeded (number) {
1433
+ if (number % 1 === 0) {
1434
+ number = parseInt (number);
1435
+ }
1436
+ return number;
1437
+ }
1438
+
1439
+ sign (path, api = 'public', method = 'GET', params = {}, headers = undefined, body = undefined) {
1440
+ const query = this.omit (params, this.extractParams (path));
1441
+ path = '/' + this.version + '/' + this.implodeParams (path, params);
1442
+ if ((method === 'GET') || (method === 'DELETE')) {
1443
+ if (Object.keys (query).length) {
1444
+ path += '?' + this.urlencode (query);
1445
+ }
1446
+ }
1447
+ const url = this.urls['api']['rest'] + path;
1448
+ if (api === 'private') {
1449
+ this.checkRequiredCredentials ();
1450
+ const defaultExpires = this.safeInteger2 (this.options, 'api-expires', 'expires', parseInt (this.timeout / 1000));
1451
+ const expires = this.sum (this.seconds (), defaultExpires);
1452
+ const expiresString = expires.toString ();
1453
+ let auth = method + path + expiresString;
1454
+ headers = {
1455
+ 'api-key': this.apiKey,
1456
+ 'api-expires': expiresString,
1457
+ };
1458
+ if (method === 'POST') {
1459
+ headers['Content-type'] = 'application/json';
1460
+ if (Object.keys (query).length) {
1461
+ body = this.json (query);
1462
+ auth += body;
1463
+ }
1464
+ }
1465
+ const signature = this.hmac (this.encode (auth), this.encode (this.secret));
1466
+ headers['api-signature'] = signature;
1467
+ }
1468
+ return { 'url': url, 'method': method, 'body': body, 'headers': headers };
1469
+ }
1470
+
1471
+ handleErrors (code, reason, url, method, headers, body, response, requestHeaders, requestBody) {
1472
+ if (response === undefined) {
1473
+ return;
1474
+ }
1475
+ if ((code >= 400) && (code <= 503)) {
1476
+ //
1477
+ // { "message": "Invalid token" }
1478
+ //
1479
+ const feedback = this.id + ' ' + body;
1480
+ const message = this.safeString (response, 'message');
1481
+ this.throwBroadlyMatchedException (this.exceptions['broad'], message, feedback);
1482
+ const status = code.toString ();
1483
+ this.throwExactlyMatchedException (this.exceptions['exact'], status, feedback);
1484
+ }
1485
+ }
1486
+ };