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/woo.js ADDED
@@ -0,0 +1,1577 @@
1
+ 'use strict';
2
+
3
+ // ---------------------------------------------------------------------------
4
+
5
+ const Exchange = require ('./base/Exchange');
6
+ const { ArgumentsRequired, AuthenticationError, RateLimitExceeded, BadRequest, ExchangeError, InvalidOrder } = require ('./base/errors');
7
+ const Precise = require ('./base/Precise');
8
+ const { TICK_SIZE } = require ('./base/functions/number');
9
+
10
+ // ---------------------------------------------------------------------------
11
+
12
+ module.exports = class woo extends Exchange {
13
+ describe () {
14
+ return this.deepExtend (super.describe (), {
15
+ 'id': 'woo',
16
+ 'name': 'WOO X',
17
+ 'countries': [ 'KY' ], // Cayman Islands
18
+ 'rateLimit': 100,
19
+ 'version': 'v1',
20
+ 'certified': false,
21
+ 'hostname': 'woo.org',
22
+ 'has': {
23
+ 'CORS': undefined,
24
+ 'spot': true,
25
+ 'margin': true,
26
+ 'swap': false,
27
+ 'future': false,
28
+ 'option': false,
29
+ 'cancelAllOrders': false,
30
+ 'cancelOrder': true,
31
+ 'cancelOrders': true,
32
+ 'cancelWithdraw': false, // exchange have that endpoint disabled atm, but was once implemented in ccxt per old docs: https://kronosresearch.github.io/wootrade-documents/#cancel-withdraw-request
33
+ 'createMarketOrder': false,
34
+ 'createOrder': true,
35
+ 'fetchBalance': true,
36
+ 'fetchCanceledOrders': false,
37
+ 'fetchClosedOrder': false,
38
+ 'fetchClosedOrders': false,
39
+ 'fetchCurrencies': true,
40
+ 'fetchDepositAddress': false,
41
+ 'fetchDeposits': true,
42
+ 'fetchFundingHistory': false,
43
+ 'fetchFundingRate': false,
44
+ 'fetchFundingRateHistory': false,
45
+ 'fetchFundingRates': false,
46
+ 'fetchIndexOHLCV': false,
47
+ 'fetchLedger': true,
48
+ 'fetchMarkets': true,
49
+ 'fetchMarkOHLCV': false,
50
+ 'fetchMyTrades': true,
51
+ 'fetchOHLCV': true,
52
+ 'fetchOpenOrder': false,
53
+ 'fetchOpenOrders': false,
54
+ 'fetchOrder': true,
55
+ 'fetchOrderBook': true,
56
+ 'fetchOrders': true,
57
+ 'fetchOrderTrades': true,
58
+ 'fetchPremiumIndexOHLCV': false,
59
+ 'fetchStatus': false,
60
+ 'fetchTicker': false,
61
+ 'fetchTickers': false,
62
+ 'fetchTime': false,
63
+ 'fetchTrades': true,
64
+ 'fetchTradingFee': false,
65
+ 'fetchTradingFees': true,
66
+ 'fetchTransactions': true,
67
+ 'fetchTransfers': true,
68
+ 'fetchWithdrawals': true,
69
+ 'transfer': true,
70
+ 'withdraw': false, // exchange have that endpoint disabled atm, but was once implemented in ccxt per old docs: https://kronosresearch.github.io/wootrade-documents/#token-withdraw
71
+ },
72
+ 'timeframes': {
73
+ '1m': '1m',
74
+ '5m': '5m',
75
+ '15m': '15m',
76
+ '30m': '30m',
77
+ '1h': '1h',
78
+ '4h': '4h',
79
+ '12h': '12h',
80
+ '1d': '1d',
81
+ '1w': '1w',
82
+ '1M': '1mon',
83
+ '1y': '1y',
84
+ },
85
+ 'urls': {
86
+ 'logo': 'https://user-images.githubusercontent.com/1294454/150730761-1a00e5e0-d28c-480f-9e65-089ce3e6ef3b.jpg',
87
+ 'api': {
88
+ 'public': 'https://api.{hostname}',
89
+ 'private': 'https://api.{hostname}',
90
+ },
91
+ // TEST (stating) api ( https://support.woo.org/hc/en-001/articles/4406352945305--Institutional-Account-Welcome-Packet-V-2) doesn't work at this moment, even thou
92
+ // 'test': {
93
+ // 'public': 'http://api.staging.woo.org',
94
+ // 'private': 'http://api.staging.woo.org',
95
+ // },
96
+ 'www': 'https://woo.org/',
97
+ 'doc': [
98
+ 'https://docs.woo.org/',
99
+ ],
100
+ 'fees': [
101
+ 'https://support.woo.org/hc/en-001/articles/4404611795353--Trading-Fees',
102
+ ],
103
+ 'referral': 'https://referral.woo.org/BAJS6oNmZb3vi3RGA',
104
+ },
105
+ 'api': {
106
+ 'v1': {
107
+ 'public': {
108
+ 'get': {
109
+ 'info': 1,
110
+ 'info/{symbol}': 1,
111
+ 'market_trades': 1,
112
+ 'token': 1,
113
+ 'token_network': 1,
114
+ },
115
+ },
116
+ 'private': {
117
+ 'get': {
118
+ 'client/token': 1,
119
+ 'order/{oid}': 1,
120
+ 'client/order/{client_order_id}': 1,
121
+ 'orders': 1,
122
+ 'orderbook/{symbol}': 1,
123
+ 'kline': 1,
124
+ 'client/trade/{tid}': 1,
125
+ 'order/{oid}/trades': 1,
126
+ 'client/trades': 1,
127
+ 'client/info': 60,
128
+ 'asset/deposit': 120,
129
+ 'asset/history': 60,
130
+ 'token_interest': 60,
131
+ 'token_interest/{token}': 60,
132
+ 'interest/history': 60,
133
+ 'interest/repay': 60,
134
+ },
135
+ 'post': {
136
+ 'order': 5, // 2 requests per 1 second per symbol
137
+ 'asset/main_sub_transfer': 30, // 20 requests per 60 seconds
138
+ 'asset/withdraw': 120, // implemented in ccxt, disabled on the exchange side https://kronosresearch.github.io/wootrade-documents/#token-withdraw
139
+ },
140
+ 'delete': {
141
+ 'order': 1,
142
+ 'client/order': 1,
143
+ 'orders': 1,
144
+ 'asset/withdraw': 120, // implemented in ccxt, disabled on the exchange side https://kronosresearch.github.io/wootrade-documents/#cancel-withdraw-request
145
+ },
146
+ },
147
+ },
148
+ 'v2': {
149
+ 'private': {
150
+ 'get': {
151
+ 'client/holding': 1,
152
+ },
153
+ },
154
+ },
155
+ },
156
+ 'fees': {
157
+ 'trading': {
158
+ 'tierBased': true,
159
+ 'percentage': true,
160
+ 'maker': this.parseNumber ('0.0002'),
161
+ 'taker': this.parseNumber ('0.0005'),
162
+ },
163
+ },
164
+ 'options': {
165
+ 'createMarketBuyOrderRequiresPrice': true,
166
+ 'network-aliases': {
167
+ 'ALGO': 'ALGO',
168
+ 'ATOM': 'ATOM',
169
+ 'AVAXC': 'AVAXC',
170
+ 'BNB': 'BEP2',
171
+ 'BSC': 'BEP20',
172
+ 'BTC': 'BTC',
173
+ 'BCHSV': 'BSV',
174
+ 'EOS': 'EOS',
175
+ 'ETH': 'ERC20',
176
+ 'HECO': 'HRC20',
177
+ 'MATIC': 'POLYGON',
178
+ 'ONT': 'ONT',
179
+ 'SOL': 'SPL',
180
+ 'TERRA': 'TERRA',
181
+ 'TRON': 'TRC20',
182
+ },
183
+ // network-aliases for titles are removed (just in case, if needed: pastebin.com/raw/BvgKViPN )
184
+ 'network-aliases-for-protocol': {
185
+ 'ALGO': 'ALGO',
186
+ 'ATOM': 'ATOM',
187
+ 'C Chain': 'AVAXC',
188
+ 'BEP2': 'BEP2',
189
+ 'BEP20': 'BEP20',
190
+ 'BTC': 'BTC',
191
+ 'BSV': 'BSV',
192
+ 'EOS': 'EOS',
193
+ 'ERC20': 'ERC20',
194
+ 'HECO': 'HRC20',
195
+ 'Polygon': 'POLYGON',
196
+ 'ONT': 'ONT',
197
+ 'SOL': 'SPL',
198
+ 'TERRA': 'TERRA',
199
+ 'TRON': 'TRC20',
200
+ },
201
+ // these network aliases require manual mapping here
202
+ 'network-aliases-for-tokens': {
203
+ 'HT': 'ERC20',
204
+ 'OMG': 'ERC20',
205
+ 'UATOM': 'ATOM',
206
+ 'ZRX': 'ZRX',
207
+ },
208
+ 'defaultNetworkCodePriorities': [
209
+ 'TRC20',
210
+ 'ERC20',
211
+ 'BSC20',
212
+ ],
213
+ // override defaultNetworkCodePriorities for a specific currency
214
+ 'defaultNetworkCodeForCurrencies': {
215
+ // 'USDT': 'TRC20',
216
+ // 'BTC': 'BTC',
217
+ },
218
+ 'transfer': {
219
+ 'fillResponseFromRequest': true,
220
+ },
221
+ },
222
+ 'commonCurrencies': {},
223
+ 'exceptions': {
224
+ 'exact': {
225
+ '-1000': ExchangeError, // { "code": -1000, "message": "An unknown error occurred while processing the request" }
226
+ '-1001': AuthenticationError, // { "code": -1001, "message": "The api key or secret is in wrong format" }
227
+ '-1002': AuthenticationError, // { "code": -1002, "message": "API key or secret is invalid, it may because key have insufficient permission or the key is expired/revoked." }
228
+ '-1003': RateLimitExceeded, // { "code": -1003, "message": "Rate limit exceed." }
229
+ '-1004': BadRequest, // { "code": -1004, "message": "An unknown parameter was sent." }
230
+ '-1005': BadRequest, // { "code": -1005, "message": "Some parameters are in wrong format for api." }
231
+ '-1006': BadRequest, // { "code": -1006, "message": "The data is not found in server." }
232
+ '-1007': BadRequest, // { "code": -1007, "message": "The data is already exists or your request is duplicated." }
233
+ '-1008': InvalidOrder, // { "code": -1008, "message": "The quantity of settlement is too high than you can request." }
234
+ '-1009': BadRequest, // { "code": -1009, "message": "Can not request withdrawal settlement, you need to deposit other arrears first." }
235
+ '-1011': ExchangeError, // { "code": -1011, "message": "Can not place/cancel orders, it may because internal network error. Please try again in a few seconds." }
236
+ '-1012': BadRequest, // { "code": -1012, "message": "Amount is required for buy market orders when margin disabled."} The place/cancel order request is rejected by internal module, it may because the account is in liquidation or other internal errors. Please try again in a few seconds." }
237
+ '-1101': InvalidOrder, // { "code": -1101, "message": "The risk exposure for client is too high, it may cause by sending too big order or the leverage is too low. please refer to client info to check the current exposure." }
238
+ '-1102': InvalidOrder, // { "code": -1102, "message": "The order value (price * size) is too small." }
239
+ '-1103': InvalidOrder, // { "code": -1103, "message": "The order price is not following the tick size rule for the symbol." }
240
+ '-1104': InvalidOrder, // { "code": -1104, "message": "The order quantity is not following the step size rule for the symbol." }
241
+ '-1105': InvalidOrder, // { "code": -1105, "message": "Price is X% too high or X% too low from the mid price." }
242
+ },
243
+ 'broad': {
244
+ 'symbol must not be blank': BadRequest, // when sending 'cancelOrder' without symbol [-1005]
245
+ 'The token is not supported': BadRequest, // when getting incorrect token's deposit address [-1005]
246
+ 'Your order and symbol are not valid or already canceled': BadRequest, // actual response whensending 'cancelOrder' for already canceled id [-1006]
247
+ 'Insufficient WOO. Please enable margin trading for leverage trading': BadRequest, // when selling insufficent token [-1012]
248
+ },
249
+ },
250
+ 'precisionMode': TICK_SIZE,
251
+ });
252
+ }
253
+
254
+ async fetchMarkets (params = {}) {
255
+ const [ marketType, query ] = this.handleMarketTypeAndParams ('fetchMarkets', undefined, params);
256
+ const method = this.getSupportedMapping (marketType, {
257
+ 'spot': 'v1PublicGetInfo',
258
+ });
259
+ const response = await this[method] (query);
260
+ //
261
+ // {
262
+ // rows: [
263
+ // {
264
+ // symbol: "SPOT_AAVE_USDT",
265
+ // quote_min: 0,
266
+ // quote_max: 100000,
267
+ // quote_tick: 0.01,
268
+ // base_min: 0.01,
269
+ // base_max: 7284,
270
+ // base_tick: 0.0001,
271
+ // min_notional: 10,
272
+ // price_range: 0.1,
273
+ // created_time: "0",
274
+ // updated_time: "1639107647.988",
275
+ // is_stable: 0
276
+ // },
277
+ // ...
278
+ // success: true
279
+ // }
280
+ //
281
+ const data = this.safeValue (response, 'rows', []);
282
+ const result = [];
283
+ for (let i = 0; i < data.length; i++) {
284
+ const market = data[i];
285
+ const marketId = this.safeString (market, 'symbol');
286
+ const parts = marketId.split ('_');
287
+ const marketTypeVal = this.safeStringLower (parts, 0);
288
+ const isSpot = marketTypeVal === 'spot';
289
+ const isSwap = false;
290
+ const isFuture = false;
291
+ const isOption = false;
292
+ const baseId = this.safeString (parts, 1);
293
+ const quoteId = this.safeString (parts, 2);
294
+ const base = this.safeCurrencyCode (baseId);
295
+ const quote = this.safeCurrencyCode (quoteId);
296
+ const symbol = base + '/' + quote;
297
+ const minQuote = this.safeNumber (market, 'quote_min');
298
+ const maxQuote = this.safeNumber (market, 'quote_max');
299
+ const minBase = this.safeNumber (market, 'base_min');
300
+ const maxBase = this.safeNumber (market, 'base_max');
301
+ const priceScale = this.safeNumber (market, 'quote_tick');
302
+ const quantityScale = this.safeNumber (market, 'base_tick');
303
+ const minCost = this.safeNumber (market, 'min_notional');
304
+ result.push ({
305
+ 'id': marketId,
306
+ 'symbol': symbol,
307
+ 'base': base,
308
+ 'quote': quote,
309
+ 'settle': undefined,
310
+ 'baseId': baseId,
311
+ 'quoteId': quoteId,
312
+ 'settleId': undefined,
313
+ 'type': marketTypeVal,
314
+ 'spot': isSpot,
315
+ 'margin': true,
316
+ 'swap': false,
317
+ 'future': false,
318
+ 'option': false,
319
+ 'active': undefined,
320
+ 'contract': isSwap || isFuture || isOption,
321
+ 'linear': undefined,
322
+ 'inverse': undefined,
323
+ 'contractSize': undefined,
324
+ 'expiry': undefined,
325
+ 'expiryDatetime': undefined,
326
+ 'strike': undefined,
327
+ 'optionType': undefined,
328
+ 'precision': {
329
+ 'amount': quantityScale,
330
+ 'price': priceScale,
331
+ },
332
+ 'limits': {
333
+ 'leverage': {
334
+ 'min': undefined,
335
+ 'max': undefined,
336
+ },
337
+ 'amount': {
338
+ 'min': minBase,
339
+ 'max': maxBase,
340
+ },
341
+ 'price': {
342
+ 'min': minQuote,
343
+ 'max': maxQuote,
344
+ },
345
+ 'cost': {
346
+ 'min': minCost,
347
+ 'max': undefined,
348
+ },
349
+ },
350
+ 'info': market,
351
+ });
352
+ }
353
+ return result;
354
+ }
355
+
356
+ async fetchTrades (symbol, since = undefined, limit = undefined, params = {}) {
357
+ if (symbol === undefined) {
358
+ throw new ArgumentsRequired (this.id + ' fetchTrades() requires a symbol argument');
359
+ }
360
+ await this.loadMarkets ();
361
+ const market = this.market (symbol);
362
+ const request = {
363
+ 'symbol': market['id'],
364
+ };
365
+ if (limit !== undefined) {
366
+ request['limit'] = limit;
367
+ }
368
+ const [ marketType, query ] = this.handleMarketTypeAndParams ('fetchTrades', market, params);
369
+ const method = this.getSupportedMapping (marketType, {
370
+ 'spot': 'v1PublicGetMarketTrades',
371
+ });
372
+ const response = await this[method] (this.extend (request, query));
373
+ //
374
+ // {
375
+ // success: true,
376
+ // rows: [
377
+ // {
378
+ // symbol: "SPOT_BTC_USDT",
379
+ // side: "SELL",
380
+ // executed_price: 46222.35,
381
+ // executed_quantity: 0.0012,
382
+ // executed_timestamp: "1641241162.329"
383
+ // },
384
+ // {
385
+ // symbol: "SPOT_BTC_USDT",
386
+ // side: "SELL",
387
+ // executed_price: 46222.35,
388
+ // executed_quantity: 0.0012,
389
+ // executed_timestamp: "1641241162.329"
390
+ // },
391
+ // {
392
+ // symbol: "SPOT_BTC_USDT",
393
+ // side: "BUY",
394
+ // executed_price: 46224.32,
395
+ // executed_quantity: 0.00039,
396
+ // executed_timestamp: "1641241162.287"
397
+ // },
398
+ // ...
399
+ // ]
400
+ // }
401
+ //
402
+ const resultResponse = this.safeValue (response, 'rows', {});
403
+ return this.parseTrades (resultResponse, market, since, limit);
404
+ }
405
+
406
+ parseTrade (trade, market = undefined) {
407
+ //
408
+ // public/market_trades
409
+ //
410
+ // {
411
+ // symbol: "SPOT_BTC_USDT",
412
+ // side: "SELL",
413
+ // executed_price: 46222.35,
414
+ // executed_quantity: 0.0012,
415
+ // executed_timestamp: "1641241162.329"
416
+ // }
417
+ //
418
+ // fetchOrderTrades, fetchOrder
419
+ //
420
+ // {
421
+ // id: '99119876',
422
+ // symbol: 'SPOT_WOO_USDT',
423
+ // fee: '0.0024',
424
+ // side: 'BUY',
425
+ // executed_timestamp: '1641481113.084',
426
+ // order_id: '87001234',
427
+ // order_tag: 'default', <-- this param only in "fetchOrderTrades"
428
+ // executed_price: '1',
429
+ // executed_quantity: '12',
430
+ // fee_asset: 'WOO',
431
+ // is_maker: '1'
432
+ // }
433
+ //
434
+ const isFromFetchOrder = ('id' in trade);
435
+ const timestamp = this.safeTimestamp (trade, 'executed_timestamp');
436
+ const marketId = this.safeString (trade, 'symbol');
437
+ market = this.safeMarket (marketId, market);
438
+ const symbol = market['symbol'];
439
+ const price = this.safeString (trade, 'executed_price');
440
+ const amount = this.safeString (trade, 'executed_quantity');
441
+ const order_id = this.safeString (trade, 'order_id');
442
+ const fee = this.parseTokenAndFeeTemp (trade, 'fee_asset', 'fee');
443
+ const cost = Precise.stringMul (price, amount);
444
+ const side = this.safeStringLower (trade, 'side');
445
+ let id = this.safeString (trade, 'id');
446
+ if (id === undefined) { // reconstruct artificially, if it doesn't exist
447
+ if (timestamp !== undefined) {
448
+ const amountStr = (amount === undefined) ? '' : amount;
449
+ const sideStr = (side === undefined) ? '' : side;
450
+ const priceStr = (price === undefined) ? '' : price;
451
+ const marketIdStr = this.safeString (market, 'id', '');
452
+ id = this.numberToString (timestamp) + '-' + marketIdStr + '-' + sideStr + '-' + amountStr + '-' + priceStr;
453
+ }
454
+ }
455
+ let takerOrMaker = undefined;
456
+ if (isFromFetchOrder) {
457
+ const isMaker = this.safeString (trade, 'is_maker') === '1';
458
+ takerOrMaker = isMaker ? 'maker' : 'taker';
459
+ }
460
+ return this.safeTrade ({
461
+ 'id': id,
462
+ 'timestamp': timestamp,
463
+ 'datetime': this.iso8601 (timestamp),
464
+ 'symbol': symbol,
465
+ 'side': side,
466
+ 'price': price,
467
+ 'amount': amount,
468
+ 'cost': cost,
469
+ 'order': order_id,
470
+ 'takerOrMaker': takerOrMaker,
471
+ 'type': undefined,
472
+ 'fee': fee,
473
+ 'info': trade,
474
+ }, market);
475
+ }
476
+
477
+ parseTokenAndFeeTemp (item, feeTokenKey, feeAmountKey) {
478
+ const feeCost = this.safeString (item, feeAmountKey);
479
+ let fee = undefined;
480
+ if (feeCost !== undefined) {
481
+ const feeCurrencyId = this.safeString (item, feeTokenKey);
482
+ const feeCurrencyCode = this.safeCurrencyCode (feeCurrencyId);
483
+ fee = {
484
+ 'cost': feeCost,
485
+ 'currency': feeCurrencyCode,
486
+ };
487
+ }
488
+ return fee;
489
+ }
490
+
491
+ async fetchTradingFees (params = {}) {
492
+ await this.loadMarkets ();
493
+ const response = await this.v1PrivateGetClientInfo (params);
494
+ //
495
+ // {
496
+ // "application":{
497
+ // "id":45585,
498
+ // "leverage":3.00,
499
+ // "otpauth":false,
500
+ // "alias":"email@address.com",
501
+ // "application_id":"c2cc4d74-c8cb-4e10-84db-af2089b8c68a",
502
+ // "account":"email@address.com",
503
+ // "account_mode":"PURE_SPOT",
504
+ // "taker_fee_rate":5.00,
505
+ // "maker_fee_rate":2.00,
506
+ // "interest_rate":0.00,
507
+ // "futures_leverage":1.00,
508
+ // "futures_taker_fee_rate":5.00,
509
+ // "futures_maker_fee_rate":2.00
510
+ // },
511
+ // "margin_rate":1000,
512
+ // "success":true
513
+ // }
514
+ //
515
+ const application = this.safeValue (response, 'application', {});
516
+ const maker = this.safeString (application, 'maker_fee_rate');
517
+ const taker = this.safeString (application, 'taker_fee_rate');
518
+ const result = {};
519
+ for (let i = 0; i < this.symbols.length; i++) {
520
+ const symbol = this.symbols[i];
521
+ result[symbol] = {
522
+ 'info': response,
523
+ 'symbol': symbol,
524
+ 'maker': this.parseNumber (Precise.stringDiv (maker, '10000')),
525
+ 'taker': this.parseNumber (Precise.stringDiv (taker, '10000')),
526
+ 'percentage': true,
527
+ 'tierBased': true,
528
+ };
529
+ }
530
+ return result;
531
+ }
532
+
533
+ async fetchCurrencies (params = {}) {
534
+ let method = undefined;
535
+ const result = {};
536
+ const [ marketType, query ] = this.handleMarketTypeAndParams ('fetchCurrencies', undefined, params);
537
+ method = this.getSupportedMapping (marketType, {
538
+ 'spot': 'v1PublicGetToken',
539
+ });
540
+ const tokenResponse = await this[method] (query);
541
+ //
542
+ // {
543
+ // rows: [
544
+ // {
545
+ // token: "ETH_USDT",
546
+ // fullname: "Tether",
547
+ // decimals: 6,
548
+ // balance_token: "USDT",
549
+ // created_time: "0",
550
+ // updated_time: "0"
551
+ // },
552
+ // {
553
+ // token: "BSC_USDT",
554
+ // fullname: "Tether",
555
+ // decimals: 18,
556
+ // balance_token: "USDT",
557
+ // created_time: "0",
558
+ // updated_time: "0"
559
+ // },
560
+ // {
561
+ // token: "ZEC",
562
+ // fullname: "ZCash",
563
+ // decimals: 8,
564
+ // balance_token: "ZEC",
565
+ // created_time: "0",
566
+ // updated_time: "0"
567
+ // },
568
+ // ...
569
+ // ],
570
+ // success: true
571
+ // }
572
+ //
573
+ method = this.getSupportedMapping (marketType, {
574
+ 'spot': 'v1PublicGetTokenNetwork',
575
+ });
576
+ const tokenNetworkResponse = await this[method] (query);
577
+ //
578
+ // {
579
+ // rows: [
580
+ // {
581
+ // protocol: "ERC20",
582
+ // token: "USDT",
583
+ // name: "Ethereum",
584
+ // minimum_withdrawal: 30,
585
+ // withdrawal_fee: 25,
586
+ // allow_deposit: 1,
587
+ // allow_withdraw: 1
588
+ // },
589
+ // {
590
+ // protocol: "TRC20",
591
+ // token: "USDT",
592
+ // name: "Tron",
593
+ // minimum_withdrawal: 30,
594
+ // withdrawal_fee: 1,
595
+ // allow_deposit: 1,
596
+ // allow_withdraw: 1
597
+ // },
598
+ // ...
599
+ // ],
600
+ // success: true
601
+ // }
602
+ //
603
+ const tokenRows = this.safeValue (tokenResponse, 'rows', []);
604
+ const tokenNetworkRows = this.safeValue (tokenNetworkResponse, 'rows', []);
605
+ const networksByCurrencyId = this.groupBy (tokenNetworkRows, 'token');
606
+ for (let i = 0; i < tokenRows.length; i++) {
607
+ const currency = tokenRows[i];
608
+ const id = this.safeString (currency, 'balance_token');
609
+ const code = this.safeCurrencyCode (id);
610
+ const name = this.safeString (currency, 'fullname');
611
+ const decimals = this.safeInteger (currency, 'decimals');
612
+ const chainedTokenCode = this.safeString (currency, 'token');
613
+ const parts = chainedTokenCode.split ('_');
614
+ const chainNameId = this.safeString (parts, 0, chainedTokenCode);
615
+ const chainCode = this.safeString (this.options['network-aliases'], chainNameId, chainNameId);
616
+ if (!(code in result)) {
617
+ const networks = this.safeValue (networksByCurrencyId, id, []);
618
+ const resultingNetworks = {};
619
+ for (let j = 0; j < networks.length; j++) {
620
+ const networkEntry = networks[j];
621
+ const networkId = this.safeString (networkEntry, 'protocol');
622
+ const networkIdManualMatched = this.safeString (this.options['network-aliases-for-tokens'], networkId, networkId);
623
+ const networkCode = this.safeString2 (this.options['network-aliases-for-protocol'], chainNameId, chainNameId, networkIdManualMatched);
624
+ const depositEnabled = this.safeInteger (networkEntry, 'allow_deposit', 0);
625
+ const withdrawEnabled = this.safeInteger (networkEntry, 'allow_withdraw', 0);
626
+ resultingNetworks[networkCode] = {
627
+ 'id': networkId,
628
+ 'network': networkCode,
629
+ 'limits': {
630
+ 'withdraw': {
631
+ 'min': this.safeNumber (networkEntry, 'minimum_withdrawal'),
632
+ 'max': undefined,
633
+ },
634
+ 'deposit': {
635
+ 'min': undefined,
636
+ 'max': undefined,
637
+ },
638
+ },
639
+ 'active': undefined,
640
+ 'deposit': depositEnabled,
641
+ 'withdraw': withdrawEnabled,
642
+ 'fee': this.safeNumber (networkEntry, 'withdrawal_fee'),
643
+ 'precision': undefined, // will be filled down below
644
+ 'info': networkEntry,
645
+ };
646
+ }
647
+ const networksKeys = Object.keys (resultingNetworks);
648
+ const firstNetworkKey = networksKeys[0];
649
+ const networkLength = networksKeys.length;
650
+ result[code] = {
651
+ 'id': id,
652
+ 'name': name,
653
+ 'code': code,
654
+ 'precision': (networkLength === 1) ? decimals : undefined, // will be filled down below
655
+ 'active': undefined,
656
+ 'fee': (networkLength === 1) ? resultingNetworks[firstNetworkKey]['fee'] : undefined,
657
+ 'networks': resultingNetworks,
658
+ 'limits': {
659
+ 'deposit': {
660
+ 'min': undefined,
661
+ 'max': undefined,
662
+ },
663
+ 'withdraw': {
664
+ 'min': (networkLength === 1) ? resultingNetworks[firstNetworkKey]['limits']['withdraw']['min'] : undefined,
665
+ 'max': undefined,
666
+ },
667
+ },
668
+ 'info': {}, // will be filled down below
669
+ };
670
+ }
671
+ const networkKeys = Object.keys (result[code]['networks']);
672
+ const firstNetworkKey = this.safeString (networkKeys, 0);
673
+ // now add the precision info from token-object
674
+ if (chainCode in result[code]['networks']) {
675
+ result[code]['networks'][chainCode]['precision'] = decimals;
676
+ } else {
677
+ // else chainCode will be the only token slug, which has only 1 supported network
678
+ result[code]['networks'][firstNetworkKey]['precision'] = decimals;
679
+ }
680
+ // now add the info object specifically for the item
681
+ result[code]['info'][chainedTokenCode] = currency;
682
+ }
683
+ return result;
684
+ }
685
+
686
+ async createOrder (symbol, type, side, amount, price = undefined, params = {}) {
687
+ await this.loadMarkets ();
688
+ const market = this.market (symbol);
689
+ const request = {
690
+ 'symbol': market['id'],
691
+ 'order_type': type.toUpperCase (),
692
+ 'side': side.toUpperCase (),
693
+ };
694
+ if (price !== undefined) {
695
+ request['order_price'] = this.priceToPrecision (symbol, price);
696
+ }
697
+ if (type === 'market') {
698
+ // for market buy it requires the amount of quote currency to spend
699
+ if (side === 'buy') {
700
+ const cost = this.safeNumber (params, 'cost');
701
+ if (this.safeValue (this.options, 'createMarketBuyOrderRequiresPrice', true)) {
702
+ if (cost === undefined) {
703
+ if (price === undefined) {
704
+ throw new InvalidOrder (this.id + " createOrder() requires the price argument for market buy orders to calculate total order cost. Supply a price argument to createOrder() call if you want the cost to be calculated for you from price and amount, or alternatively, supply the total cost value in the 'order_amount' in exchange-specific parameters");
705
+ } else {
706
+ request['order_amount'] = this.costToPrecision (symbol, amount * price);
707
+ }
708
+ } else {
709
+ request['order_amount'] = this.costToPrecision (symbol, cost);
710
+ }
711
+ }
712
+ } else {
713
+ request['order_quantity'] = this.amountToPrecision (symbol, amount);
714
+ }
715
+ } else {
716
+ request['order_quantity'] = this.amountToPrecision (symbol, amount);
717
+ }
718
+ const clientOrderId = this.safeString2 (params, 'clOrdID', 'clientOrderId');
719
+ if (clientOrderId !== undefined) {
720
+ request['client_order_id'] = clientOrderId;
721
+ }
722
+ params = this.omit (params, [ 'clOrdID', 'clientOrderId' ]);
723
+ const [ marketType, query ] = this.handleMarketTypeAndParams ('createOrder', market, params);
724
+ const method = this.getSupportedMapping (marketType, {
725
+ 'spot': 'v1PrivatePostOrder',
726
+ });
727
+ const response = await this[method] (this.extend (request, query));
728
+ // {
729
+ // success: true,
730
+ // timestamp: '1641383206.489',
731
+ // order_id: '86980774',
732
+ // order_type: 'LIMIT',
733
+ // order_price: '1', // null for 'MARKET' order
734
+ // order_quantity: '12', // null for 'MARKET' order
735
+ // order_amount: null, // NOT-null for 'MARKET' order
736
+ // client_order_id: '0'
737
+ // }
738
+ return this.extend (
739
+ this.parseOrder (response, market),
740
+ { 'type': type }
741
+ );
742
+ }
743
+
744
+ async cancelOrder (id, symbol = undefined, params = {}) {
745
+ if (symbol === undefined) {
746
+ throw new ArgumentsRequired (this.id + ' cancelOrder() requires a symbol argument');
747
+ }
748
+ await this.loadMarkets ();
749
+ const request = undefined;
750
+ const clientOrderIdUnified = this.safeString2 (params, 'clOrdID', 'clientOrderId');
751
+ const clientOrderIdExchangeSpecific = this.safeString2 (params, 'client_order_id', clientOrderIdUnified);
752
+ const isByClientOrder = clientOrderIdExchangeSpecific !== undefined;
753
+ if (isByClientOrder) {
754
+ request['client_order_id'] = clientOrderIdExchangeSpecific;
755
+ params = this.omit (params, [ 'clOrdID', 'clientOrderId', 'client_order_id' ]);
756
+ } else {
757
+ request['order_id'] = id;
758
+ }
759
+ let market = undefined;
760
+ if (symbol !== undefined) {
761
+ market = this.market (symbol);
762
+ }
763
+ request['symbol'] = market['id'];
764
+ const [ marketType, query ] = this.handleMarketTypeAndParams ('cancelOrder', market, params);
765
+ const method = this.getSupportedMapping (marketType, {
766
+ 'spot': 'v1PrivateDeleteOrder',
767
+ });
768
+ const response = await this[method] (this.extend (request, query));
769
+ //
770
+ // { success: true, status: 'CANCEL_SENT' }
771
+ //
772
+ const extendParams = { 'symbol': symbol };
773
+ if (isByClientOrder) {
774
+ extendParams['client_order_id'] = clientOrderIdExchangeSpecific;
775
+ } else {
776
+ extendParams['id'] = id;
777
+ }
778
+ return this.extend (this.parseOrder (response), extendParams);
779
+ }
780
+
781
+ async cancelOrders (ids, symbol = undefined, params = {}) {
782
+ if (symbol === undefined) {
783
+ throw new ArgumentsRequired (this.id + ' canelOrders() requires a symbol argument');
784
+ }
785
+ await this.loadMarkets ();
786
+ const market = this.market (symbol);
787
+ const request = {
788
+ 'symbol': market['id'],
789
+ };
790
+ const [ marketType, query ] = this.handleMarketTypeAndParams ('cancelOrders', market, params);
791
+ const method = this.getSupportedMapping (marketType, {
792
+ 'spot': 'v1PrivateDeleteOrders',
793
+ });
794
+ const response = await this[method] (this.extend (request, query));
795
+ return response;
796
+ }
797
+
798
+ async fetchOrder (id, symbol = undefined, params = {}) {
799
+ await this.loadMarkets ();
800
+ const market = (symbol !== undefined) ? this.market (symbol) : undefined;
801
+ const request = {};
802
+ const [ marketType, query ] = this.handleMarketTypeAndParams ('fetchOrder', market, params);
803
+ const clientOrderId = this.safeString2 (params, 'clOrdID', 'clientOrderId');
804
+ let chosenSpotMethod = undefined;
805
+ if (clientOrderId) {
806
+ chosenSpotMethod = 'v1PrivateGetClientOrderClientOrderId';
807
+ request['client_order_id'] = clientOrderId;
808
+ } else {
809
+ chosenSpotMethod = 'v1PrivateGetOrderOid';
810
+ request['oid'] = id;
811
+ }
812
+ const method = this.getSupportedMapping (marketType, {
813
+ 'spot': chosenSpotMethod,
814
+ });
815
+ const response = await this[method] (this.extend (request, query));
816
+ //
817
+ // {
818
+ // success: true,
819
+ // symbol: 'SPOT_WOO_USDT',
820
+ // status: 'FILLED', // FILLED, NEW
821
+ // side: 'BUY',
822
+ // created_time: '1641480933.000',
823
+ // order_id: '87541111',
824
+ // order_tag: 'default',
825
+ // price: '1',
826
+ // type: 'LIMIT',
827
+ // quantity: '12',
828
+ // amount: null,
829
+ // visible: '12',
830
+ // executed: '12', // or any partial amount
831
+ // total_fee: '0.0024',
832
+ // fee_asset: 'WOO',
833
+ // client_order_id: null,
834
+ // average_executed_price: '1',
835
+ // Transactions: [
836
+ // {
837
+ // id: '99111647',
838
+ // symbol: 'SPOT_WOO_USDT',
839
+ // fee: '0.0024',
840
+ // side: 'BUY',
841
+ // executed_timestamp: '1641482113.084',
842
+ // order_id: '87541111',
843
+ // executed_price: '1',
844
+ // executed_quantity: '12',
845
+ // fee_asset: 'WOO',
846
+ // is_maker: '1'
847
+ // }
848
+ // ]
849
+ // }
850
+ //
851
+ return this.parseOrder (response);
852
+ }
853
+
854
+ async fetchOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) {
855
+ await this.loadMarkets ();
856
+ const request = {};
857
+ let market = undefined;
858
+ if (symbol !== undefined) {
859
+ market = this.market (symbol);
860
+ request['symbol'] = market['id'];
861
+ }
862
+ if (since !== undefined) {
863
+ request['start_t'] = since;
864
+ }
865
+ const [ marketType, query ] = this.handleMarketTypeAndParams ('fetchOrders', market, params);
866
+ const method = this.getSupportedMapping (marketType, {
867
+ 'spot': 'v1PrivateGetOrders',
868
+ });
869
+ const response = await this[method] (this.extend (request, query));
870
+ const data = this.safeValue (response, 'rows');
871
+ return this.parseOrders (data, market, since, limit, params);
872
+ }
873
+
874
+ parseOrder (order, market = undefined) {
875
+ //
876
+ // Possible input functions:
877
+ // * createOrder
878
+ // * cancelOrder
879
+ // * fetchOrder
880
+ // * fetchOrders
881
+ // const isFromFetchOrder = ('order_tag' in order); TO_DO
882
+ const timestamp = this.safeTimestamp2 (order, 'timestamp', 'created_time');
883
+ const orderId = this.safeInteger (order, 'order_id');
884
+ const clientOrderId = this.safeTimestamp (order, 'client_order_id'); // Somehow, this always returns 0 for limit order
885
+ const marketId = this.safeString (order, 'symbol');
886
+ market = this.safeMarket (marketId, market);
887
+ const symbol = market['symbol'];
888
+ const price = this.safeString2 (order, 'order_price', 'price');
889
+ const amount = this.safeString2 (order, 'order_quantity', 'quantity'); // This is base amount
890
+ const cost = this.safeString2 (order, 'order_amount', 'amount'); // This is quote amount
891
+ const orderType = this.safeStringLower2 (order, 'order_type', 'type');
892
+ const status = this.safeValue (order, 'status');
893
+ const side = this.safeStringLower2 (order, 'side');
894
+ const filled = this.safeValue (order, 'executed');
895
+ const remaining = Precise.stringSub (cost, filled);
896
+ const fee = this.safeValue (order, 'total_fee');
897
+ const feeCurrency = this.safeString (order, 'fee_asset');
898
+ const transactions = this.safeValue (order, 'Transactions');
899
+ return this.safeOrder ({
900
+ 'id': orderId,
901
+ 'clientOrderId': clientOrderId,
902
+ 'timestamp': timestamp,
903
+ 'datetime': this.iso8601 (timestamp),
904
+ 'lastTradeTimestamp': undefined,
905
+ 'status': this.parseOrderStatus (status),
906
+ 'symbol': symbol,
907
+ 'type': orderType,
908
+ 'timeInForce': undefined,
909
+ 'postOnly': undefined, // TO_DO
910
+ 'side': side,
911
+ 'price': price,
912
+ 'stopPrice': undefined,
913
+ 'average': undefined,
914
+ 'amount': amount,
915
+ 'filled': filled,
916
+ 'remaining': remaining, // TO_DO
917
+ 'cost': cost,
918
+ 'trades': transactions,
919
+ 'fee': {
920
+ 'cost': fee,
921
+ 'currency': feeCurrency,
922
+ },
923
+ 'info': order,
924
+ }, market);
925
+ }
926
+
927
+ parseOrderStatus (status) {
928
+ if (status !== undefined) {
929
+ const statuses = {
930
+ 'NEW': 'open',
931
+ 'FILLED': 'closed',
932
+ 'CANCEL_SENT': 'canceled',
933
+ 'CANCEL_ALL_SENT': 'canceled',
934
+ };
935
+ return this.safeString (statuses, status, status);
936
+ }
937
+ return status;
938
+ }
939
+
940
+ async fetchOrderBook (symbol, limit = undefined, params = {}) {
941
+ await this.loadMarkets ();
942
+ const market = this.market (symbol);
943
+ const request = {
944
+ 'symbol': market['id'],
945
+ };
946
+ if (limit !== undefined) {
947
+ limit = Math.min (limit, 1000);
948
+ request['max_level'] = limit;
949
+ }
950
+ const [ marketType, query ] = this.handleMarketTypeAndParams ('fetchOrderBook', market, params);
951
+ const method = this.getSupportedMapping (marketType, {
952
+ 'spot': 'v1PrivateGetOrderbookSymbol',
953
+ });
954
+ const response = await this[method] (this.extend (request, query));
955
+ //
956
+ // {
957
+ // success: true,
958
+ // timestamp: '1641562961192',
959
+ // asks: [
960
+ // { price: '0.921', quantity: '76.01' },
961
+ // { price: '0.933', quantity: '477.10' },
962
+ // ...
963
+ // ],
964
+ // bids: [
965
+ // { price: '0.940', quantity: '13502.47' },
966
+ // { price: '0.932', quantity: '43.91' },
967
+ // ...
968
+ // ]
969
+ // }
970
+ //
971
+ const timestamp = this.safeInteger (response, 'timestamp');
972
+ return this.parseOrderBook (response, symbol, timestamp, 'bids', 'asks', 'price', 'quantity');
973
+ }
974
+
975
+ async fetchOHLCV (symbol, timeframe = '1h', since = undefined, limit = undefined, params = {}) {
976
+ await this.loadMarkets ();
977
+ const market = this.market (symbol);
978
+ const request = {
979
+ 'symbol': market['id'],
980
+ 'type': this.timeframes[timeframe],
981
+ };
982
+ if (limit !== undefined) {
983
+ request['limit'] = Math.min (limit, 1000);
984
+ }
985
+ const [ marketType, query ] = this.handleMarketTypeAndParams ('fetchOHLCV', market, params);
986
+ const method = this.getSupportedMapping (marketType, {
987
+ 'spot': 'v1PrivateGetKline',
988
+ });
989
+ const response = await this[method] (this.extend (request, query));
990
+ // {
991
+ // success: true,
992
+ // rows: [
993
+ // {
994
+ // open: '0.94238',
995
+ // close: '0.94271',
996
+ // low: '0.94238',
997
+ // high: '0.94296',
998
+ // volume: '73.55',
999
+ // amount: '69.32040520',
1000
+ // symbol: 'SPOT_WOO_USDT',
1001
+ // type: '1m',
1002
+ // start_timestamp: '1641584700000',
1003
+ // end_timestamp: '1641584760000'
1004
+ // },
1005
+ // {
1006
+ // open: '0.94186',
1007
+ // close: '0.94186',
1008
+ // low: '0.94186',
1009
+ // high: '0.94186',
1010
+ // volume: '64.00',
1011
+ // amount: '60.27904000',
1012
+ // symbol: 'SPOT_WOO_USDT',
1013
+ // type: '1m',
1014
+ // start_timestamp: '1641584640000',
1015
+ // end_timestamp: '1641584700000'
1016
+ // },
1017
+ // ...
1018
+ // ]
1019
+ // }
1020
+ const data = this.safeValue (response, 'rows', []);
1021
+ return this.parseOHLCVs (data, market, timeframe, since, limit);
1022
+ }
1023
+
1024
+ parseOHLCV (ohlcv, market = undefined) {
1025
+ // example response in fetchOHLCV
1026
+ return [
1027
+ this.safeInteger (ohlcv, 'start_timestamp'),
1028
+ this.safeNumber (ohlcv, 'open'),
1029
+ this.safeNumber (ohlcv, 'high'),
1030
+ this.safeNumber (ohlcv, 'low'),
1031
+ this.safeNumber (ohlcv, 'close'),
1032
+ this.safeNumber (ohlcv, 'volume'),
1033
+ ];
1034
+ }
1035
+
1036
+ async fetchOrderTrades (id, symbol = undefined, since = undefined, limit = undefined, params = {}) {
1037
+ await this.loadMarkets ();
1038
+ let market = undefined;
1039
+ if (symbol !== undefined) {
1040
+ market = this.market (symbol);
1041
+ }
1042
+ const request = {
1043
+ 'oid': id,
1044
+ };
1045
+ const [ marketType, query ] = this.handleMarketTypeAndParams ('fetchOrderTrades', market, params);
1046
+ const method = this.getSupportedMapping (marketType, {
1047
+ 'spot': 'v1PrivateGetOrderOidTrades',
1048
+ });
1049
+ const response = await this[method] (this.extend (request, query));
1050
+ // {
1051
+ // success: true,
1052
+ // rows: [
1053
+ // {
1054
+ // id: '99111647',
1055
+ // symbol: 'SPOT_WOO_USDT',
1056
+ // fee: '0.0024',
1057
+ // side: 'BUY',
1058
+ // executed_timestamp: '1641482113.084',
1059
+ // order_id: '87541111',
1060
+ // order_tag: 'default',
1061
+ // executed_price: '1',
1062
+ // executed_quantity: '12',
1063
+ // fee_asset: 'WOO',
1064
+ // is_maker: '1'
1065
+ // }
1066
+ // ]
1067
+ // }
1068
+ const trades = this.safeValue (response, 'rows', []);
1069
+ return this.parseTrades (trades, market, since, limit, params);
1070
+ }
1071
+
1072
+ async fetchMyTrades (symbol = undefined, since = undefined, limit = undefined, params = {}) {
1073
+ await this.loadMarkets ();
1074
+ const request = {};
1075
+ let market = undefined;
1076
+ if (symbol !== undefined) {
1077
+ market = this.market (symbol);
1078
+ request['symbol'] = market['id'];
1079
+ }
1080
+ if (since !== undefined) {
1081
+ request['start_t'] = since;
1082
+ }
1083
+ const [ marketType, query ] = this.handleMarketTypeAndParams ('fetchMyTrades', market, params);
1084
+ const method = this.getSupportedMapping (marketType, {
1085
+ 'spot': 'v1PrivateGetClientTrades',
1086
+ });
1087
+ const response = await this[method] (this.extend (request, query));
1088
+ // {
1089
+ // "success": true,
1090
+ // "meta": {
1091
+ // "records_per_page": 25,
1092
+ // "current_page": 1
1093
+ // },
1094
+ // "rows": [
1095
+ // {
1096
+ // "id": 5,
1097
+ // "symbol": "SPOT_BTC_USDT",
1098
+ // "order_id": 211,
1099
+ // "order_tag": "default",
1100
+ // "executed_price": 10892.84,
1101
+ // "executed_quantity": 0.002,
1102
+ // "is_maker": 0,
1103
+ // "side": "SELL",
1104
+ // "fee": 0,
1105
+ // "fee_asset": "USDT",
1106
+ // "executed_timestamp": "1566264290.250"
1107
+ // },
1108
+ // ...
1109
+ // ]
1110
+ // }
1111
+ const trades = this.safeValue (response, 'rows', []);
1112
+ return this.parseTrades (trades, market, since, limit, params);
1113
+ }
1114
+
1115
+ async fetchBalance (params = {}) {
1116
+ await this.loadMarkets ();
1117
+ const [ marketType, query ] = this.handleMarketTypeAndParams ('fetchBalance', undefined, params);
1118
+ const method = this.getSupportedMapping (marketType, {
1119
+ 'spot': 'v2PrivateGetClientHolding',
1120
+ });
1121
+ const response = await this[method] (query);
1122
+ //
1123
+ // {
1124
+ // holding: [
1125
+ // {
1126
+ // token: 'USDT',
1127
+ // holding: '23.56', // free balance
1128
+ // frozen: '888.0', // i.e. if in processing withdrawal
1129
+ // interest: '0.0',
1130
+ // outstanding_holding: '-56.7', // this value is set (negative number) if there is an open limit order, and this is QUOTE currency of order
1131
+ // pending_exposure: '333.45', // this value is set (positive number) if there is an open limit order, and this is BASE currency of order
1132
+ // opening_cost: '0.00000000',
1133
+ // holding_cost: '0.00000000',
1134
+ // realised_pnl: '0.00000000',
1135
+ // settled_pnl: '0.00000000',
1136
+ // fee_24_h: '0',
1137
+ // settled_pnl_24_h: '0',
1138
+ // updated_time: '1641370779'
1139
+ // },
1140
+ // ...
1141
+ // ],
1142
+ // success: true
1143
+ // }
1144
+ //
1145
+ return this.parseBalance (response);
1146
+ }
1147
+
1148
+ parseBalance (response) {
1149
+ const result = {
1150
+ 'info': response,
1151
+ };
1152
+ const balances = this.safeValue (response, 'holding', []);
1153
+ for (let i = 0; i < balances.length; i++) {
1154
+ const balance = balances[i];
1155
+ const code = this.safeCurrencyCode (this.safeString (balance, 'token'));
1156
+ const account = this.account ();
1157
+ account['total'] = this.safeString (balance, 'holding');
1158
+ const used = this.safeString (balance, 'outstanding_holding');
1159
+ account['used'] = Precise.stringNeg (used);
1160
+ result[code] = account;
1161
+ }
1162
+ return this.safeBalance (result);
1163
+ }
1164
+
1165
+ async fetchDepositAddress (code, params = {}) {
1166
+ // this method is TODO because of networks unification
1167
+ await this.loadMarkets ();
1168
+ const currency = this.currency (code);
1169
+ const networkCodeDefault = this.defaultNetworkCodeForCurrency (code);
1170
+ const networkCode = this.safeValue (params, 'network', networkCodeDefault);
1171
+ params = this.omit (params, 'network');
1172
+ const networkAliases = this.safeValue (this.options, 'network-aliases', {});
1173
+ const networkId = this.getKeyByValue (networkAliases, networkCode);
1174
+ const codeForExchange = networkId + '_' + currency['code'];
1175
+ const request = {
1176
+ 'token': codeForExchange,
1177
+ };
1178
+ const [ marketType, query ] = this.handleMarketTypeAndParams ('fetchDepositAddress', undefined, params);
1179
+ const method = this.getSupportedMapping (marketType, {
1180
+ 'spot': 'v1PrivateGetAssetDeposit',
1181
+ });
1182
+ const response = await this[method] (this.extend (request, query));
1183
+ // {
1184
+ // success: true,
1185
+ // address: '3Jmtjx5544T4smrit9Eroe4PCrRkpDeKjP',
1186
+ // extra: ''
1187
+ // }
1188
+ let tag = this.safeString (response, 'extra');
1189
+ if (tag === '') {
1190
+ tag = undefined;
1191
+ }
1192
+ const address = this.safeString (response, 'address');
1193
+ this.checkAddress (address);
1194
+ return {
1195
+ 'currency': code,
1196
+ 'address': address,
1197
+ 'tag': tag,
1198
+ 'network': networkCode,
1199
+ 'info': response,
1200
+ };
1201
+ }
1202
+
1203
+ async getAssetHistoryRows (code = undefined, since = undefined, limit = undefined, params = {}) {
1204
+ await this.loadMarkets ();
1205
+ const request = { };
1206
+ let currency = undefined;
1207
+ if (code !== undefined) {
1208
+ currency = this.currency (code);
1209
+ request['balance_token'] = currency['id'];
1210
+ }
1211
+ if (since !== undefined) {
1212
+ request['start_t'] = since;
1213
+ }
1214
+ if (limit !== undefined) {
1215
+ request['pageSize'] = limit;
1216
+ }
1217
+ const transactionType = this.safeString (params, 'type');
1218
+ params = this.omit (params, 'type');
1219
+ if (transactionType !== undefined) {
1220
+ request['type'] = transactionType;
1221
+ }
1222
+ const response = await this.v1PrivateGetAssetHistory (this.extend (request, params));
1223
+ // {
1224
+ // rows: [
1225
+ // {
1226
+ // id: '22010508193900165',
1227
+ // token: 'TRON_USDT',
1228
+ // extra: '',
1229
+ // amount: '13.75848500',
1230
+ // status: 'COMPLETED',
1231
+ // account: null,
1232
+ // description: null,
1233
+ // user_id: '42222',
1234
+ // application_id: '6ad2b303-f354-45c0-8105-9f5f19d0e335',
1235
+ // external_id: '220105081900134',
1236
+ // target_address: 'TXnyFSnAYad3YCaqtwMw9jvXKkeU39NLnK',
1237
+ // source_address: 'TYDzsYUEpvnYmQk4zGP9sWWcTEd2MiAtW6',
1238
+ // type: 'BALANCE',
1239
+ // token_side: 'DEPOSIT',
1240
+ // tx_id: '35b0004022f6b3ad07f39a0b7af199f6b258c2c3e2c7cdc93c67efa74fd625ee',
1241
+ // fee_token: '',
1242
+ // fee_amount: '0.00000000',
1243
+ // created_time: '1641370779.442',
1244
+ // updated_time: '1641370779.465',
1245
+ // is_new_target_address: null,
1246
+ // confirmed_number: '29',
1247
+ // confirming_threshold: '27',
1248
+ // audit_tag: '1',
1249
+ // audit_result: '0',
1250
+ // balance_token: null, // TODO -write to support, that this seems broken. here should be the token id
1251
+ // network_name: null // TODO -write to support, that this seems broken. here should be the network id
1252
+ // }
1253
+ // ],
1254
+ // meta: { total: '1', records_per_page: '25', current_page: '1' },
1255
+ // success: true
1256
+ // }
1257
+ return [ currency, this.safeValue (response, 'rows', {}) ];
1258
+ }
1259
+
1260
+ async fetchLedger (code = undefined, since = undefined, limit = undefined, params = {}) {
1261
+ const [ currency, rows ] = await this.getAssetHistoryRows (code, since, limit, params);
1262
+ return this.parseLedger (rows, currency, since, limit, params);
1263
+ }
1264
+
1265
+ parseLedgerEntry (item, currency = undefined) {
1266
+ const networkizedCode = this.safeString (item, 'token');
1267
+ const currencyDefined = this.getCurrencyFromChaincode (networkizedCode, currency);
1268
+ const code = currencyDefined['code'];
1269
+ const amount = this.safeNumber (item, 'amount');
1270
+ const side = this.safeNumber (item, 'token_side');
1271
+ const direction = (side === 'DEPOSIT') ? 'in' : 'out';
1272
+ const timestamp = this.safeTimestamp (item, 'created_time');
1273
+ const fee = this.parseTokenAndFeeTemp (item, 'fee_token', 'fee_amount');
1274
+ return {
1275
+ 'id': this.safeString (item, 'id'),
1276
+ 'currency': code,
1277
+ 'account': this.safeString (item, 'account'),
1278
+ 'referenceAccount': undefined,
1279
+ 'referenceId': this.safeString (item, 'tx_id'),
1280
+ 'status': this.parseTransactionStatus (item, 'status'),
1281
+ 'amount': amount,
1282
+ 'before': undefined,
1283
+ 'after': undefined,
1284
+ 'fee': fee,
1285
+ 'direction': direction,
1286
+ 'timestamp': timestamp,
1287
+ 'datetime': this.iso8601 (timestamp),
1288
+ 'type': this.parseLedgerEntryType (this.safeString (item, 'type')),
1289
+ 'info': item,
1290
+ };
1291
+ }
1292
+
1293
+ parseLedgerEntryType (type) {
1294
+ const types = {
1295
+ 'BALANCE': 'transaction', // Funds moved in/out wallet
1296
+ 'COLLATERAL': 'transfer', // Funds moved between portfolios
1297
+ };
1298
+ return this.safeString (types, type, type);
1299
+ }
1300
+
1301
+ getCurrencyFromChaincode (networkizedCode, currency) {
1302
+ if (currency !== undefined) {
1303
+ return currency;
1304
+ } else {
1305
+ const parts = networkizedCode.split ('_');
1306
+ const partsLength = parts.length;
1307
+ const firstPart = this.safeString (parts, 0);
1308
+ let currencyId = this.safeString (parts, 1, firstPart);
1309
+ if (partsLength > 2) {
1310
+ currencyId += '_' + this.safeString (parts, 2);
1311
+ }
1312
+ currency = this.safeCurrency (currencyId);
1313
+ }
1314
+ return currency;
1315
+ }
1316
+
1317
+ async fetchDeposits (code = undefined, since = undefined, limit = undefined, params = {}) {
1318
+ const request = {
1319
+ 'token_side': 'DEPOSIT',
1320
+ };
1321
+ return await this.fetchTransactions (code, since, limit, this.extend (request, params));
1322
+ }
1323
+
1324
+ async fetchWithdrawals (code = undefined, since = undefined, limit = undefined, params = {}) {
1325
+ const request = {
1326
+ 'token_side': 'WITHDRAW',
1327
+ };
1328
+ return await this.fetchTransactions (code, since, limit, this.extend (request, params));
1329
+ }
1330
+
1331
+ async fetchTransactions (code = undefined, since = undefined, limit = undefined, params = {}) {
1332
+ const request = {
1333
+ 'type': 'BALANCE',
1334
+ };
1335
+ const [ currency, rows ] = await this.getAssetHistoryRows (code, since, limit, this.extend (request, params));
1336
+ return this.parseTransactions (rows, currency, since, limit, params);
1337
+ }
1338
+
1339
+ parseTransaction (transaction, currency = undefined) {
1340
+ // example in fetchLedger
1341
+ const networkizedCode = this.safeString (transaction, 'token');
1342
+ const currencyDefined = this.getCurrencyFromChaincode (networkizedCode, currency);
1343
+ const code = currencyDefined['code'];
1344
+ let movementDirection = this.safeStringLower (transaction, 'token_side');
1345
+ if (movementDirection === 'withdraw') {
1346
+ movementDirection = 'withdrawal';
1347
+ }
1348
+ const fee = this.parseTokenAndFeeTemp (transaction, 'fee_token', 'fee_amount');
1349
+ fee['rate'] = undefined;
1350
+ const addressTo = this.safeString (transaction, 'target_address');
1351
+ const addressFrom = this.safeString (transaction, 'source_address');
1352
+ const timestamp = this.safeTimestamp (transaction, 'created_time');
1353
+ return {
1354
+ 'id': this.safeString (transaction, 'id'),
1355
+ 'txid': this.safeString (transaction, 'tx_id'),
1356
+ 'timestamp': timestamp,
1357
+ 'datetime': this.iso8601 (timestamp),
1358
+ 'address': undefined,
1359
+ 'addressFrom': addressFrom,
1360
+ 'addressTo': addressTo,
1361
+ 'tag': this.safeString (transaction, 'extra'),
1362
+ 'type': movementDirection,
1363
+ 'amount': this.safeNumber (transaction, 'amount'),
1364
+ 'currency': code,
1365
+ 'status': this.parseTransactionStatus (this.safeString (transaction, 'status')),
1366
+ 'updated': this.safeTimestamp (transaction, 'updated_time'),
1367
+ 'fee': fee,
1368
+ 'info': transaction,
1369
+ };
1370
+ }
1371
+
1372
+ parseTransactionStatus (status) {
1373
+ const statuses = {
1374
+ 'NEW': 'pending',
1375
+ 'CONFIRMING': 'pending',
1376
+ 'PROCESSING': 'pending',
1377
+ 'COMPLETED': 'ok',
1378
+ 'CANCELED': 'canceled',
1379
+ };
1380
+ return this.safeString (statuses, status, status);
1381
+ }
1382
+
1383
+ async transfer (code, amount, fromAccount, toAccount, params = {}) {
1384
+ await this.loadMarkets ();
1385
+ const currency = this.currency (code);
1386
+ const request = {
1387
+ 'token': currency['id'],
1388
+ 'amount': this.parseNumber (amount),
1389
+ 'from_application_id': fromAccount,
1390
+ 'to_application_id': toAccount,
1391
+ };
1392
+ const response = await this.v1PrivatePostAssetMainSubTransfer (this.extend (request, params));
1393
+ //
1394
+ // {
1395
+ // "success": true,
1396
+ // "id": 200
1397
+ // }
1398
+ //
1399
+ const transfer = this.parseTransfer (response, currency);
1400
+ const transferOptions = this.safeValue (this.options, 'transfer', {});
1401
+ const fillResponseFromRequest = this.safeValue (transferOptions, 'fillResponseFromRequest', true);
1402
+ if (fillResponseFromRequest) {
1403
+ transfer['amount'] = amount;
1404
+ transfer['fromAccount'] = fromAccount;
1405
+ transfer['toAccount'] = toAccount;
1406
+ }
1407
+ return transfer;
1408
+ }
1409
+
1410
+ async fetchTransfers (code = undefined, since = undefined, limit = undefined, params = {}) {
1411
+ const request = {
1412
+ 'type': 'COLLATERAL',
1413
+ };
1414
+ const [ currency, rows ] = await this.getAssetHistoryRows (code, since, limit, this.extend (request, params));
1415
+ return this.parseTransfers (rows, currency, since, limit, params);
1416
+ }
1417
+
1418
+ parseTransfer (transfer, currency = undefined) {
1419
+ //
1420
+ // getAssetHistoryRows
1421
+ // {
1422
+ // "created_time": "1579399877.041", // Unix epoch time in seconds
1423
+ // "updated_time": "1579399877.041", // Unix epoch time in seconds
1424
+ // "id": "202029292829292",
1425
+ // "external_id": "202029292829292",
1426
+ // "application_id": null,
1427
+ // "token": "ETH",
1428
+ // "target_address": "0x31d64B3230f8baDD91dE1710A65DF536aF8f7cDa",
1429
+ // "source_address": "0x70fd25717f769c7f9a46b319f0f9103c0d887af0",
1430
+ // "extra": "",
1431
+ // "type": "BALANCE",
1432
+ // "token_side": "DEPOSIT",
1433
+ // "amount": 1000,
1434
+ // "tx_id": "0x8a74c517bc104c8ebad0c3c3f64b1f302ed5f8bca598ae4459c63419038106b6",
1435
+ // "fee_token": null,
1436
+ // "fee_amount": null,
1437
+ // "status": "CONFIRMING"
1438
+ // }
1439
+ //
1440
+ // v1PrivatePostAssetMainSubTransfer
1441
+ // {
1442
+ // "success": true,
1443
+ // "id": 200
1444
+ // }
1445
+ //
1446
+ const networkizedCode = this.safeString (transfer, 'token');
1447
+ const currencyDefined = this.getCurrencyFromChaincode (networkizedCode, currency);
1448
+ const code = currencyDefined['code'];
1449
+ let movementDirection = this.safeStringLower (transfer, 'token_side');
1450
+ if (movementDirection === 'withdraw') {
1451
+ movementDirection = 'withdrawal';
1452
+ }
1453
+ let fromAccount = undefined;
1454
+ let toAccount = undefined;
1455
+ if (movementDirection === 'withdraw') {
1456
+ fromAccount = undefined;
1457
+ toAccount = 'spot';
1458
+ } else if (movementDirection === 'deposit') {
1459
+ fromAccount = 'spot';
1460
+ toAccount = undefined;
1461
+ }
1462
+ const timestamp = this.safeTimestamp (transfer, 'created_time');
1463
+ const success = this.safeValue (transfer, 'success');
1464
+ let status = undefined;
1465
+ if (success !== undefined) {
1466
+ status = success ? 'ok' : 'failed';
1467
+ }
1468
+ return {
1469
+ 'id': this.safeString (transfer, 'id'),
1470
+ 'timestamp': timestamp,
1471
+ 'datetime': this.iso8601 (timestamp),
1472
+ 'currency': code,
1473
+ 'amount': this.safeNumber (transfer, 'amount'),
1474
+ 'fromAccount': fromAccount,
1475
+ 'toAccount': toAccount,
1476
+ 'status': this.parseTransferStatus (this.safeString (transfer, 'status', status)),
1477
+ 'info': transfer,
1478
+ };
1479
+ }
1480
+
1481
+ parseTransferStatus (status) {
1482
+ const statuses = {
1483
+ 'NEW': 'pending',
1484
+ 'CONFIRMING': 'pending',
1485
+ 'PROCESSING': 'pending',
1486
+ 'COMPLETED': 'ok',
1487
+ 'CANCELED': 'canceled',
1488
+ };
1489
+ return this.safeString (statuses, status, status);
1490
+ }
1491
+
1492
+ nonce () {
1493
+ return this.milliseconds ();
1494
+ }
1495
+
1496
+ sign (path, section = 'public', method = 'GET', params = {}, headers = undefined, body = undefined) {
1497
+ const version = section[0];
1498
+ const access = section[1];
1499
+ let url = this.implodeHostname (this.urls['api'][access]);
1500
+ url += '/' + version + '/';
1501
+ path = this.implodeParams (path, params);
1502
+ params = this.omit (params, this.extractParams (path));
1503
+ params = this.keysort (params);
1504
+ if (access === 'public') {
1505
+ url += access + '/' + path;
1506
+ if (Object.keys (params).length) {
1507
+ url += '?' + this.urlencode (params);
1508
+ }
1509
+ } else {
1510
+ this.checkRequiredCredentials ();
1511
+ url += path;
1512
+ const ts = this.nonce ().toString ();
1513
+ let auth = this.urlencode (params);
1514
+ if (method === 'POST' || method === 'DELETE') {
1515
+ body = auth;
1516
+ } else {
1517
+ url += '?' + auth;
1518
+ }
1519
+ auth += '|' + ts;
1520
+ const signature = this.hmac (this.encode (auth), this.encode (this.secret), 'sha256');
1521
+ headers = {
1522
+ 'x-api-key': this.apiKey,
1523
+ 'x-api-signature': signature,
1524
+ 'x-api-timestamp': ts,
1525
+ 'Content-Type': 'application/x-www-form-urlencoded',
1526
+ };
1527
+ }
1528
+ return { 'url': url, 'method': method, 'body': body, 'headers': headers };
1529
+ }
1530
+
1531
+ handleErrors (httpCode, reason, url, method, headers, body, response, requestHeaders, requestBody) {
1532
+ if (!response) {
1533
+ return; // fallback to default error handler
1534
+ }
1535
+ //
1536
+ // 400 Bad Request {"success":false,"code":-1012,"message":"Amount is required for buy market orders when margin disabled."}
1537
+ //
1538
+ const success = this.safeValue (response, 'success');
1539
+ const errorCode = this.safeString (response, 'code');
1540
+ if (!success) {
1541
+ const feedback = this.id + ' ' + this.json (response);
1542
+ this.throwBroadlyMatchedException (this.exceptions['broad'], body, feedback);
1543
+ this.throwExactlyMatchedException (this.exceptions['exact'], errorCode, feedback);
1544
+ }
1545
+ }
1546
+
1547
+ defaultNetworkCodeForCurrency (code) { // TODO: can be moved into base as an unified method
1548
+ // at first, try to find if user or exchange has defined default networks for the specific currency
1549
+ const defaultNetworkCodeForCurrencies = this.safeValue (this.options, 'defaultNetworkCodeForCurrencies');
1550
+ if (defaultNetworkCodeForCurrencies !== undefined) {
1551
+ const defaultNetworkCode = this.safeStringUpper (defaultNetworkCodeForCurrencies, code);
1552
+ if (defaultNetworkCode !== undefined) {
1553
+ return defaultNetworkCode;
1554
+ }
1555
+ }
1556
+ // if not found by above 'defaultNetworkCodeForCurrencies' for specific currency, then try with `defaultNetworkCodePriorities`
1557
+ const currencyItem = this.currency (code);
1558
+ const networks = currencyItem['networks'];
1559
+ const defaultNetworkCodePriorities = this.safeValue (this.options, 'defaultNetworkCodePriorities');
1560
+ if (defaultNetworkCodePriorities !== undefined) {
1561
+ // itterate according to priority networks
1562
+ const networksKeys = Object.keys (networks);
1563
+ const networksKeysLength = networksKeys.length;
1564
+ if (networksKeysLength > 0) {
1565
+ for (let i = 0; i < defaultNetworkCodePriorities.length; i++) {
1566
+ const networkCode = defaultNetworkCodePriorities[i];
1567
+ if (networkCode in networks) {
1568
+ return networkCode;
1569
+ }
1570
+ }
1571
+ }
1572
+ }
1573
+ // if it was not returned according to above options, then return the first network of currency
1574
+ const networkKeys = Object.keys (networks);
1575
+ return this.safeValue (networkKeys, 0);
1576
+ }
1577
+ };