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/kucoin.js ADDED
@@ -0,0 +1,2571 @@
1
+ 'use strict';
2
+
3
+ // ---------------------------------------------------------------------------
4
+
5
+ const Exchange = require ('./base/Exchange');
6
+ const { ExchangeError, ExchangeNotAvailable, InsufficientFunds, OrderNotFound, InvalidOrder, AccountSuspended, InvalidNonce, NotSupported, BadRequest, AuthenticationError, BadSymbol, RateLimitExceeded, PermissionDenied, InvalidAddress } = require ('./base/errors');
7
+ const Precise = require ('./base/Precise');
8
+
9
+ // ---------------------------------------------------------------------------
10
+
11
+ module.exports = class kucoin extends Exchange {
12
+ describe () {
13
+ return this.deepExtend (super.describe (), {
14
+ 'id': 'kucoin',
15
+ 'name': 'KuCoin',
16
+ 'countries': [ 'SC' ],
17
+ // note "only some endpoints are rate-limited"
18
+ // so I set the 'ratelimit' on those which supposedly 'arent ratelimited'
19
+ // to the limit of the cheapest endpoint
20
+ // 60 requests in 3 seconds = 20 requests per second => ( 1000ms / 20 ) = 50 ms between requests on average
21
+ 'rateLimit': 50,
22
+ 'version': 'v2',
23
+ 'certified': false,
24
+ 'pro': true,
25
+ 'comment': 'Platform 2.0',
26
+ 'quoteJsonNumbers': false,
27
+ 'has': {
28
+ 'CORS': undefined,
29
+ 'spot': true,
30
+ 'margin': undefined,
31
+ 'swap': false,
32
+ 'future': false,
33
+ 'option': undefined,
34
+ 'cancelAllOrders': true,
35
+ 'cancelOrder': true,
36
+ 'createDepositAddress': true,
37
+ 'createOrder': true,
38
+ 'createStopLimitOrder': true,
39
+ 'createStopMarketOrder': true,
40
+ 'createStopOrder': true,
41
+ 'fetchAccounts': true,
42
+ 'fetchBalance': true,
43
+ 'fetchBorrowRate': false,
44
+ 'fetchBorrowRates': false,
45
+ 'fetchClosedOrders': true,
46
+ 'fetchCurrencies': true,
47
+ 'fetchDepositAddress': true,
48
+ 'fetchDeposits': true,
49
+ 'fetchFundingFee': true,
50
+ 'fetchFundingHistory': false,
51
+ 'fetchFundingRate': false,
52
+ 'fetchFundingRateHistory': false,
53
+ 'fetchFundingRates': false,
54
+ 'fetchIndexOHLCV': false,
55
+ 'fetchL3OrderBook': true,
56
+ 'fetchLedger': true,
57
+ 'fetchMarkets': true,
58
+ 'fetchMarkOHLCV': false,
59
+ 'fetchMyTrades': true,
60
+ 'fetchOHLCV': true,
61
+ 'fetchOpenOrders': true,
62
+ 'fetchOrder': true,
63
+ 'fetchOrderBook': true,
64
+ 'fetchOrdersByStatus': true,
65
+ 'fetchPremiumIndexOHLCV': false,
66
+ 'fetchStatus': true,
67
+ 'fetchTicker': true,
68
+ 'fetchTickers': true,
69
+ 'fetchTime': true,
70
+ 'fetchTrades': true,
71
+ 'fetchTradingFee': true,
72
+ 'fetchTradingFees': false,
73
+ 'fetchWithdrawals': true,
74
+ 'transfer': true,
75
+ 'withdraw': true,
76
+ },
77
+ 'urls': {
78
+ 'logo': 'https://user-images.githubusercontent.com/51840849/87295558-132aaf80-c50e-11ea-9801-a2fb0c57c799.jpg',
79
+ 'referral': 'https://www.kucoin.com/?rcode=E5wkqe',
80
+ 'api': {
81
+ 'public': 'https://api.kucoin.com',
82
+ 'private': 'https://api.kucoin.com',
83
+ 'futuresPrivate': 'https://api-futures.kucoin.com',
84
+ 'futuresPublic': 'https://api-futures.kucoin.com',
85
+ },
86
+ 'test': {
87
+ 'public': 'https://openapi-sandbox.kucoin.com',
88
+ 'private': 'https://openapi-sandbox.kucoin.com',
89
+ 'futuresPrivate': 'https://api-sandbox-futures.kucoin.com',
90
+ 'futuresPublic': 'https://api-sandbox-futures.kucoin.com',
91
+ },
92
+ 'www': 'https://www.kucoin.com',
93
+ 'doc': [
94
+ 'https://docs.kucoin.com',
95
+ ],
96
+ },
97
+ 'requiredCredentials': {
98
+ 'apiKey': true,
99
+ 'secret': true,
100
+ 'password': true,
101
+ },
102
+ 'api': {
103
+ 'public': {
104
+ 'get': {
105
+ 'timestamp': 1,
106
+ 'status': 1,
107
+ 'symbols': 1,
108
+ 'markets': 1,
109
+ 'market/allTickers': 1,
110
+ 'market/orderbook/level{level}_{limit}': 1,
111
+ 'market/orderbook/level2_20': 1,
112
+ 'market/orderbook/level2_100': 1,
113
+ 'market/histories': 1,
114
+ 'market/candles': 1,
115
+ 'market/stats': 1,
116
+ 'currencies': 1,
117
+ 'currencies/{currency}': 1,
118
+ 'prices': 1,
119
+ 'mark-price/{symbol}/current': 1,
120
+ 'margin/config': 1,
121
+ },
122
+ 'post': {
123
+ 'bullet-public': 1,
124
+ },
125
+ },
126
+ 'private': {
127
+ 'get': {
128
+ 'market/orderbook/level{level}': 1,
129
+ 'market/orderbook/level2': { 'v3': 2 }, // 30/3s = 10/s => cost = 20 / 10 = 2
130
+ 'market/orderbook/level3': 1,
131
+ 'accounts': 1,
132
+ 'accounts/{accountId}': 1,
133
+ // 'accounts/{accountId}/ledgers': 1, Deprecated endpoint
134
+ 'accounts/ledgers': 3.333, // 18/3s = 6/s => cost = 20 / 6 = 3.333
135
+ 'accounts/{accountId}/holds': 1,
136
+ 'accounts/transferable': 1,
137
+ 'base-fee': 1,
138
+ 'sub/user': 1,
139
+ 'sub-accounts': 1,
140
+ 'sub-accounts/{subUserId}': 1,
141
+ 'deposit-addresses': 1,
142
+ 'deposits': 10, // 6/3s = 2/s => cost = 20 / 2 = 10
143
+ 'hist-deposits': 10, // 6/3 = 2/s => cost = 20 / 2 = 10
144
+ 'hist-orders': 1,
145
+ 'hist-withdrawals': 10, // 6/3 = 2/s => cost = 20 / 2 = 10
146
+ 'withdrawals': 10, // 6/3 = 2/s => cost = 20 / 2 = 10
147
+ 'withdrawals/quotas': 1,
148
+ 'orders': 2, // 30/3s = 10/s => cost = 20 / 10 = 2
149
+ 'order/client-order/{clientOid}': 1,
150
+ 'orders/{orderId}': 1,
151
+ 'limit/orders': 1,
152
+ 'fills': 6.66667, // 9/3s = 3/s => cost = 20 / 3 = 6.666667
153
+ 'limit/fills': 1,
154
+ 'margin/account': 1,
155
+ 'margin/borrow': 1,
156
+ 'margin/borrow/outstanding': 1,
157
+ 'margin/borrow/borrow/repaid': 1,
158
+ 'margin/lend/active': 1,
159
+ 'margin/lend/done': 1,
160
+ 'margin/lend/trade/unsettled': 1,
161
+ 'margin/lend/trade/settled': 1,
162
+ 'margin/lend/assets': 1,
163
+ 'margin/market': 1,
164
+ 'margin/trade/last': 1,
165
+ 'stop-order/{orderId}': 1,
166
+ 'stop-order': 1,
167
+ 'stop-order/queryOrderByClientOid': 1,
168
+ 'trade-fees': 1.3333, // 45/3s = 15/s => cost = 20 / 15 = 1.333
169
+ },
170
+ 'post': {
171
+ 'accounts': 1,
172
+ 'accounts/inner-transfer': { 'v2': 1 },
173
+ 'accounts/sub-transfer': { 'v2': 25 }, // bad docs
174
+ 'deposit-addresses': 1,
175
+ 'withdrawals': 1,
176
+ 'orders': 4, // 45/3s = 15/s => cost = 20 / 15 = 1.333333
177
+ 'orders/multi': 20, // 3/3s = 1/s => cost = 20 / 1 = 20
178
+ 'margin/borrow': 1,
179
+ 'margin/order': 1,
180
+ 'margin/repay/all': 1,
181
+ 'margin/repay/single': 1,
182
+ 'margin/lend': 1,
183
+ 'margin/toggle-auto-lend': 1,
184
+ 'bullet-private': 1,
185
+ 'stop-order': 1,
186
+ },
187
+ 'delete': {
188
+ 'withdrawals/{withdrawalId}': 1,
189
+ 'orders': 20, // 3/3s = 1/s => cost = 20/1
190
+ 'orders/client-order/{clientOid}': 1,
191
+ 'orders/{orderId}': 1, // rateLimit: 60/3s = 20/s => cost = 1
192
+ 'margin/lend/{orderId}': 1,
193
+ 'stop-order/cancelOrderByClientOid': 1,
194
+ 'stop-order/{orderId}': 1,
195
+ 'stop-order/cancel': 1,
196
+ },
197
+ },
198
+ 'futuresPublic': {
199
+ // cheapest futures 'limited' endpoint is 40 requests per 3 seconds = 14.333 per second => cost = 20/14.333 = 1.3953
200
+ 'get': {
201
+ 'contracts/active': 1.3953,
202
+ 'contracts/{symbol}': 1.3953,
203
+ 'ticker': 1.3953,
204
+ 'level2/snapshot': 2, // 30 requests per 3 seconds = 10 requests per second => cost = 20/10 = 2
205
+ 'level2/depth20': 1.3953,
206
+ 'level2/depth100': 1.3953,
207
+ 'level2/message/query': 1.3953,
208
+ 'level3/message/query': 1.3953, // deprecated,level3/snapshot is suggested
209
+ 'level3/snapshot': 1.3953, // v2
210
+ 'trade/history': 1.3953,
211
+ 'interest/query': 1.3953,
212
+ 'index/query': 1.3953,
213
+ 'mark-price/{symbol}/current': 1.3953,
214
+ 'premium/query': 1.3953,
215
+ 'funding-rate/{symbol}/current': 1.3953,
216
+ 'timestamp': 1.3953,
217
+ 'status': 1.3953,
218
+ 'kline/query': 1.3953,
219
+ },
220
+ 'post': {
221
+ 'bullet-public': 1.3953,
222
+ },
223
+ },
224
+ 'futuresPrivate': {
225
+ 'get': {
226
+ 'account-overview': 2, // 30 requests per 3 seconds = 10 per second => cost = 20/10 = 2
227
+ 'transaction-history': 6.666, // 9 requests per 3 seconds = 3 per second => cost = 20/3 = 6.666
228
+ 'deposit-address': 1.3953,
229
+ 'deposit-list': 1.3953,
230
+ 'withdrawals/quotas': 1.3953,
231
+ 'withdrawal-list': 1.3953,
232
+ 'transfer-list': 1.3953,
233
+ 'orders': 1.3953,
234
+ 'stopOrders': 1.3953,
235
+ 'recentDoneOrders': 1.3953,
236
+ 'orders/{order-id}': 1.3953, // ?clientOid={client-order-id} // get order by orderId
237
+ 'orders/byClientOid': 1.3953, // ?clientOid=eresc138b21023a909e5ad59 // get order by clientOid
238
+ 'fills': 6.666, // 9 requests per 3 seconds = 3 per second => cost = 20/3 = 6.666
239
+ 'recentFills': 6.666, // 9 requests per 3 seconds = 3 per second => cost = 20/3 = 6.666
240
+ 'openOrderStatistics': 1.3953,
241
+ 'position': 1.3953,
242
+ 'positions': 6.666, // 9 requests per 3 seconds = 3 per second => cost = 20/3 = 6.666
243
+ 'funding-history': 6.666, // 9 requests per 3 seconds = 3 per second => cost = 20/3 = 6.666
244
+ },
245
+ 'post': {
246
+ 'withdrawals': 1.3953,
247
+ 'transfer-out': 1.3953, // v2
248
+ 'orders': 1.3953,
249
+ 'position/margin/auto-deposit-status': 1.3953,
250
+ 'position/margin/deposit-margin': 1.3953,
251
+ 'bullet-private': 1.3953,
252
+ },
253
+ 'delete': {
254
+ 'withdrawals/{withdrawalId}': 1.3953,
255
+ 'cancel/transfer-out': 1.3953,
256
+ 'orders/{order-id}': 1.3953, // 40 requests per 3 seconds = 14.333 per second => cost = 20/14.333 = 1.395
257
+ 'orders': 6.666, // 9 requests per 3 seconds = 3 per second => cost = 20/3 = 6.666
258
+ 'stopOrders': 1.3953,
259
+ },
260
+ },
261
+ },
262
+ 'timeframes': {
263
+ '1m': '1min',
264
+ '3m': '3min',
265
+ '5m': '5min',
266
+ '15m': '15min',
267
+ '30m': '30min',
268
+ '1h': '1hour',
269
+ '2h': '2hour',
270
+ '4h': '4hour',
271
+ '6h': '6hour',
272
+ '8h': '8hour',
273
+ '12h': '12hour',
274
+ '1d': '1day',
275
+ '1w': '1week',
276
+ },
277
+ 'exceptions': {
278
+ 'exact': {
279
+ 'order not exist': OrderNotFound,
280
+ 'order not exist.': OrderNotFound, // duplicated error temporarily
281
+ 'order_not_exist': OrderNotFound, // {"code":"order_not_exist","msg":"order_not_exist"} ¯\_(ツ)_/¯
282
+ 'order_not_exist_or_not_allow_to_cancel': InvalidOrder, // {"code":"400100","msg":"order_not_exist_or_not_allow_to_cancel"}
283
+ 'Order size below the minimum requirement.': InvalidOrder, // {"code":"400100","msg":"Order size below the minimum requirement."}
284
+ 'The withdrawal amount is below the minimum requirement.': ExchangeError, // {"code":"400100","msg":"The withdrawal amount is below the minimum requirement."}
285
+ 'Unsuccessful! Exceeded the max. funds out-transfer limit': InsufficientFunds, // {"code":"200000","msg":"Unsuccessful! Exceeded the max. funds out-transfer limit"}
286
+ '400': BadRequest,
287
+ '401': AuthenticationError,
288
+ '403': NotSupported,
289
+ '404': NotSupported,
290
+ '405': NotSupported,
291
+ '429': RateLimitExceeded,
292
+ '500': ExchangeNotAvailable, // Internal Server Error -- We had a problem with our server. Try again later.
293
+ '503': ExchangeNotAvailable,
294
+ '101030': PermissionDenied, // {"code":"101030","msg":"You haven't yet enabled the margin trading"}
295
+ '200004': InsufficientFunds,
296
+ '230003': InsufficientFunds, // {"code":"230003","msg":"Balance insufficient!"}
297
+ '260100': InsufficientFunds, // {"code":"260100","msg":"account.noBalance"}
298
+ '300000': InvalidOrder,
299
+ '400000': BadSymbol,
300
+ '400001': AuthenticationError,
301
+ '400002': InvalidNonce,
302
+ '400003': AuthenticationError,
303
+ '400004': AuthenticationError,
304
+ '400005': AuthenticationError,
305
+ '400006': AuthenticationError,
306
+ '400007': AuthenticationError,
307
+ '400008': NotSupported,
308
+ '400100': BadRequest,
309
+ '400200': InvalidOrder, // {"code":"400200","msg":"Forbidden to place an order"}
310
+ '400350': InvalidOrder, // {"code":"400350","msg":"Upper limit for holding: 10,000USDT, you can still buy 10,000USDT worth of coin."}
311
+ '400370': InvalidOrder, // {"code":"400370","msg":"Max. price: 0.02500000000000000000"}
312
+ '400500': InvalidOrder, // {"code":"400500","msg":"Your located country/region is currently not supported for the trading of this token"}
313
+ '400600': BadSymbol, // {"code":"400600","msg":"validation.createOrder.symbolNotAvailable"}
314
+ '401000': BadRequest, // {"code":"401000","msg":"The interface has been deprecated"}
315
+ '411100': AccountSuspended,
316
+ '415000': BadRequest, // {"code":"415000","msg":"Unsupported Media Type"}
317
+ '500000': ExchangeNotAvailable, // {"code":"500000","msg":"Internal Server Error"}
318
+ '260220': InvalidAddress, // { "code": "260220", "msg": "deposit.address.not.exists" }
319
+ },
320
+ 'broad': {
321
+ 'Exceeded the access frequency': RateLimitExceeded,
322
+ 'require more permission': PermissionDenied,
323
+ },
324
+ },
325
+ 'fees': {
326
+ 'trading': {
327
+ 'tierBased': true,
328
+ 'percentage': true,
329
+ 'taker': this.parseNumber ('0.001'),
330
+ 'maker': this.parseNumber ('0.001'),
331
+ 'tiers': {
332
+ 'taker': [
333
+ [ this.parseNumber ('0'), this.parseNumber ('0.001') ],
334
+ [ this.parseNumber ('50'), this.parseNumber ('0.001') ],
335
+ [ this.parseNumber ('200'), this.parseNumber ('0.0009') ],
336
+ [ this.parseNumber ('500'), this.parseNumber ('0.0008') ],
337
+ [ this.parseNumber ('1000'), this.parseNumber ('0.0007') ],
338
+ [ this.parseNumber ('2000'), this.parseNumber ('0.0007') ],
339
+ [ this.parseNumber ('4000'), this.parseNumber ('0.0006') ],
340
+ [ this.parseNumber ('8000'), this.parseNumber ('0.0005') ],
341
+ [ this.parseNumber ('15000'), this.parseNumber ('0.00045') ],
342
+ [ this.parseNumber ('25000'), this.parseNumber ('0.0004') ],
343
+ [ this.parseNumber ('40000'), this.parseNumber ('0.00035') ],
344
+ [ this.parseNumber ('60000'), this.parseNumber ('0.0003') ],
345
+ [ this.parseNumber ('80000'), this.parseNumber ('0.00025') ],
346
+ ],
347
+ 'maker': [
348
+ [ this.parseNumber ('0'), this.parseNumber ('0.001') ],
349
+ [ this.parseNumber ('50'), this.parseNumber ('0.0009') ],
350
+ [ this.parseNumber ('200'), this.parseNumber ('0.0007') ],
351
+ [ this.parseNumber ('500'), this.parseNumber ('0.0005') ],
352
+ [ this.parseNumber ('1000'), this.parseNumber ('0.0003') ],
353
+ [ this.parseNumber ('2000'), this.parseNumber ('0') ],
354
+ [ this.parseNumber ('4000'), this.parseNumber ('0') ],
355
+ [ this.parseNumber ('8000'), this.parseNumber ('0') ],
356
+ [ this.parseNumber ('15000'), this.parseNumber ('-0.00005') ],
357
+ [ this.parseNumber ('25000'), this.parseNumber ('-0.00005') ],
358
+ [ this.parseNumber ('40000'), this.parseNumber ('-0.00005') ],
359
+ [ this.parseNumber ('60000'), this.parseNumber ('-0.00005') ],
360
+ [ this.parseNumber ('80000'), this.parseNumber ('-0.00005') ],
361
+ ],
362
+ },
363
+ },
364
+ 'funding': {
365
+ 'tierBased': false,
366
+ 'percentage': false,
367
+ 'withdraw': {},
368
+ 'deposit': {},
369
+ },
370
+ },
371
+ 'commonCurrencies': {
372
+ 'HOT': 'HOTNOW',
373
+ 'EDGE': 'DADI', // https://github.com/ccxt/ccxt/issues/5756
374
+ 'WAX': 'WAXP',
375
+ 'TRY': 'Trias',
376
+ 'VAI': 'VAIOT',
377
+ },
378
+ 'options': {
379
+ 'version': 'v1',
380
+ 'symbolSeparator': '-',
381
+ 'fetchMyTradesMethod': 'private_get_fills',
382
+ 'fetchBalance': 'trade',
383
+ 'fetchMarkets': {
384
+ 'fetchTickersFees': true,
385
+ },
386
+ // endpoint versions
387
+ 'versions': {
388
+ 'public': {
389
+ 'GET': {
390
+ 'status': 'v1',
391
+ 'market/orderbook/level2_20': 'v1',
392
+ 'market/orderbook/level2_100': 'v1',
393
+ 'market/orderbook/level{level}_{limit}': 'v1',
394
+ },
395
+ },
396
+ 'private': {
397
+ 'GET': {
398
+ 'market/orderbook/level2': 'v3',
399
+ 'market/orderbook/level3': 'v3',
400
+ 'market/orderbook/level{level}': 'v3',
401
+ },
402
+ 'POST': {
403
+ 'accounts/inner-transfer': 'v2',
404
+ 'accounts/sub-transfer': 'v2',
405
+ },
406
+ },
407
+ 'futuresPrivate': {
408
+ 'GET': {
409
+ 'account-overview': 'v1',
410
+ 'positions': 'v1',
411
+ },
412
+ 'POST': {
413
+ 'transfer-out': 'v2',
414
+ },
415
+ },
416
+ 'futuresPublic': {
417
+ 'GET': {
418
+ 'level3/snapshot': 'v2',
419
+ },
420
+ },
421
+ },
422
+ 'accountsByType': {
423
+ 'spot': 'trade',
424
+ 'margin': 'margin',
425
+ 'main': 'main',
426
+ 'funding': 'main',
427
+ 'future': 'contract',
428
+ 'mining': 'pool',
429
+ },
430
+ 'networks': {
431
+ 'ETH': 'eth',
432
+ 'ERC20': 'eth',
433
+ 'TRX': 'trx',
434
+ 'TRC20': 'trx',
435
+ 'KCC': 'kcc',
436
+ 'TERRA': 'luna',
437
+ },
438
+ },
439
+ });
440
+ }
441
+
442
+ nonce () {
443
+ return this.milliseconds ();
444
+ }
445
+
446
+ async fetchTime (params = {}) {
447
+ const response = await this.publicGetTimestamp (params);
448
+ //
449
+ // {
450
+ // "code":"200000",
451
+ // "msg":"success",
452
+ // "data":1546837113087
453
+ // }
454
+ //
455
+ return this.safeInteger (response, 'data');
456
+ }
457
+
458
+ async fetchStatus (params = {}) {
459
+ const response = await this.publicGetStatus (params);
460
+ //
461
+ // {
462
+ // "code":"200000",
463
+ // "data":{
464
+ // "status":"open", //open, close, cancelonly
465
+ // "msg":"upgrade match engine" //remark for operation
466
+ // }
467
+ // }
468
+ //
469
+ const data = this.safeValue (response, 'data', {});
470
+ const status = this.safeString (data, 'status');
471
+ return {
472
+ 'status': (status === 'open') ? 'ok' : 'maintenance',
473
+ 'updated': this.milliseconds (),
474
+ 'eta': undefined,
475
+ 'url': undefined,
476
+ 'info': response,
477
+ };
478
+ }
479
+
480
+ async fetchMarkets (params = {}) {
481
+ const response = await this.publicGetSymbols (params);
482
+ //
483
+ // {
484
+ // "code": "200000",
485
+ // "data": [
486
+ // {
487
+ // "symbol": "XLM-USDT",
488
+ // "name": "XLM-USDT",
489
+ // "baseCurrency": "XLM",
490
+ // "quoteCurrency": "USDT",
491
+ // "feeCurrency": "USDT",
492
+ // "market": "USDS",
493
+ // "baseMinSize": "0.1",
494
+ // "quoteMinSize": "0.01",
495
+ // "baseMaxSize": "10000000000",
496
+ // "quoteMaxSize": "99999999",
497
+ // "baseIncrement": "0.0001",
498
+ // "quoteIncrement": "0.000001",
499
+ // "priceIncrement": "0.000001",
500
+ // "priceLimitRate": "0.1",
501
+ // "isMarginEnabled": true,
502
+ // "enableTrading": true
503
+ // },
504
+ // ]
505
+ // }
506
+ //
507
+ const data = this.safeValue (response, 'data');
508
+ const options = this.safeValue (this.options, 'fetchMarkets', {});
509
+ const fetchTickersFees = this.safeValue (options, 'fetchTickersFees', true);
510
+ let tickersResponse = {};
511
+ if (fetchTickersFees) {
512
+ tickersResponse = await this.publicGetMarketAllTickers (params);
513
+ }
514
+ //
515
+ // {
516
+ // "code": "200000",
517
+ // "data": {
518
+ // "time":1602832092060,
519
+ // "ticker":[
520
+ // {
521
+ // "symbol": "BTC-USDT", // symbol
522
+ // "symbolName":"BTC-USDT", // Name of trading pairs, it would change after renaming
523
+ // "buy": "11328.9", // bestAsk
524
+ // "sell": "11329", // bestBid
525
+ // "changeRate": "-0.0055", // 24h change rate
526
+ // "changePrice": "-63.6", // 24h change price
527
+ // "high": "11610", // 24h highest price
528
+ // "low": "11200", // 24h lowest price
529
+ // "vol": "2282.70993217", // 24h volume,the aggregated trading volume in BTC
530
+ // "volValue": "25984946.157790431", // 24h total, the trading volume in quote currency of last 24 hours
531
+ // "last": "11328.9", // last price
532
+ // "averagePrice": "11360.66065903", // 24h average transaction price yesterday
533
+ // "takerFeeRate": "0.001", // Basic Taker Fee
534
+ // "makerFeeRate": "0.001", // Basic Maker Fee
535
+ // "takerCoefficient": "1", // Taker Fee Coefficient
536
+ // "makerCoefficient": "1" // Maker Fee Coefficient
537
+ // }
538
+ // ]
539
+ // }
540
+ // }
541
+ //
542
+ const tickersData = this.safeValue (tickersResponse, 'data', {});
543
+ const tickers = this.safeValue (tickersData, 'ticker', []);
544
+ const tickersByMarketId = this.indexBy (tickers, 'symbol');
545
+ const result = [];
546
+ for (let i = 0; i < data.length; i++) {
547
+ const market = data[i];
548
+ const id = this.safeString (market, 'symbol');
549
+ const [ baseId, quoteId ] = id.split ('-');
550
+ const base = this.safeCurrencyCode (baseId);
551
+ const quote = this.safeCurrencyCode (quoteId);
552
+ const baseMaxSize = this.safeNumber (market, 'baseMaxSize');
553
+ const baseMinSizeString = this.safeString (market, 'baseMinSize');
554
+ const quoteMaxSizeString = this.safeString (market, 'quoteMaxSize');
555
+ const baseMinSize = this.parseNumber (baseMinSizeString);
556
+ const quoteMaxSize = this.parseNumber (quoteMaxSizeString);
557
+ const quoteMinSize = this.safeNumber (market, 'quoteMinSize');
558
+ // const quoteIncrement = this.safeNumber (market, 'quoteIncrement');
559
+ const ticker = this.safeValue (tickersByMarketId, id, {});
560
+ const makerFeeRate = this.safeString (ticker, 'makerFeeRate');
561
+ const takerFeeRate = this.safeString (ticker, 'makerFeeRate');
562
+ const makerCoefficient = this.safeString (ticker, 'makerCoefficient');
563
+ const takerCoefficient = this.safeString (ticker, 'takerCoefficient');
564
+ result.push ({
565
+ 'id': id,
566
+ 'symbol': base + '/' + quote,
567
+ 'base': base,
568
+ 'quote': quote,
569
+ 'settle': undefined,
570
+ 'baseId': baseId,
571
+ 'quoteId': quoteId,
572
+ 'settleId': undefined,
573
+ 'type': 'spot',
574
+ 'spot': true,
575
+ 'margin': this.safeValue (market, 'isMarginEnabled'),
576
+ 'swap': false,
577
+ 'future': false,
578
+ 'option': false,
579
+ 'active': this.safeValue (market, 'enableTrading'),
580
+ 'contract': false,
581
+ 'linear': undefined,
582
+ 'inverse': undefined,
583
+ 'taker': this.parseNumber (Precise.stringMul (takerFeeRate, takerCoefficient)),
584
+ 'maker': this.parseNumber (Precise.stringMul (makerFeeRate, makerCoefficient)),
585
+ 'contractSize': undefined,
586
+ 'expiry': undefined,
587
+ 'expiryDatetime': undefined,
588
+ 'strike': undefined,
589
+ 'optionType': undefined,
590
+ 'precision': {
591
+ 'amount': this.precisionFromString (this.safeString (market, 'baseIncrement')),
592
+ 'price': this.precisionFromString (this.safeString (market, 'priceIncrement')),
593
+ },
594
+ 'limits': {
595
+ 'leverage': {
596
+ 'min': undefined,
597
+ 'max': undefined,
598
+ },
599
+ 'amount': {
600
+ 'min': baseMinSize,
601
+ 'max': baseMaxSize,
602
+ },
603
+ 'price': {
604
+ 'min': undefined,
605
+ 'max': undefined,
606
+ },
607
+ 'cost': {
608
+ 'min': quoteMinSize,
609
+ 'max': quoteMaxSize,
610
+ },
611
+ },
612
+ 'info': market,
613
+ });
614
+ }
615
+ return result;
616
+ }
617
+
618
+ async fetchCurrencies (params = {}) {
619
+ const response = await this.publicGetCurrencies (params);
620
+ //
621
+ // {
622
+ // "currency": "OMG",
623
+ // "name": "OMG",
624
+ // "fullName": "OmiseGO",
625
+ // "precision": 8,
626
+ // "confirms": 12,
627
+ // "withdrawalMinSize": "4",
628
+ // "withdrawalMinFee": "1.25",
629
+ // "isWithdrawEnabled": false,
630
+ // "isDepositEnabled": false,
631
+ // "isMarginEnabled": false,
632
+ // "isDebitEnabled": false
633
+ // }
634
+ //
635
+ const data = this.safeValue (response, 'data', []);
636
+ const result = {};
637
+ for (let i = 0; i < data.length; i++) {
638
+ const entry = data[i];
639
+ const id = this.safeString (entry, 'currency');
640
+ const name = this.safeString (entry, 'fullName');
641
+ const code = this.safeCurrencyCode (id);
642
+ const precision = this.safeInteger (entry, 'precision');
643
+ const isWithdrawEnabled = this.safeValue (entry, 'isWithdrawEnabled', false);
644
+ const isDepositEnabled = this.safeValue (entry, 'isDepositEnabled', false);
645
+ const fee = this.safeNumber (entry, 'withdrawalMinFee');
646
+ const active = (isWithdrawEnabled && isDepositEnabled);
647
+ result[code] = {
648
+ 'id': id,
649
+ 'name': name,
650
+ 'code': code,
651
+ 'precision': precision,
652
+ 'info': entry,
653
+ 'active': active,
654
+ 'deposit': isDepositEnabled,
655
+ 'withdraw': isWithdrawEnabled,
656
+ 'fee': fee,
657
+ 'limits': this.limits,
658
+ };
659
+ }
660
+ return result;
661
+ }
662
+
663
+ async fetchAccounts (params = {}) {
664
+ const response = await this.privateGetAccounts (params);
665
+ //
666
+ // {
667
+ // code: "200000",
668
+ // data: [
669
+ // {
670
+ // balance: "0.00009788",
671
+ // available: "0.00009788",
672
+ // holds: "0",
673
+ // currency: "BTC",
674
+ // id: "5c6a4fd399a1d81c4f9cc4d0",
675
+ // type: "trade"
676
+ // },
677
+ // {
678
+ // balance: "0.00000001",
679
+ // available: "0.00000001",
680
+ // holds: "0",
681
+ // currency: "ETH",
682
+ // id: "5c6a49ec99a1d819392e8e9f",
683
+ // type: "trade"
684
+ // }
685
+ // ]
686
+ // }
687
+ //
688
+ const data = this.safeValue (response, 'data');
689
+ const result = [];
690
+ for (let i = 0; i < data.length; i++) {
691
+ const account = data[i];
692
+ const accountId = this.safeString (account, 'id');
693
+ const currencyId = this.safeString (account, 'currency');
694
+ const code = this.safeCurrencyCode (currencyId);
695
+ const type = this.safeString (account, 'type'); // main or trade
696
+ result.push ({
697
+ 'id': accountId,
698
+ 'type': type,
699
+ 'currency': code,
700
+ 'info': account,
701
+ });
702
+ }
703
+ return result;
704
+ }
705
+
706
+ async fetchFundingFee (code, params = {}) {
707
+ await this.loadMarkets ();
708
+ const currency = this.currency (code);
709
+ const request = {
710
+ 'currency': currency['id'],
711
+ };
712
+ const response = await this.privateGetWithdrawalsQuotas (this.extend (request, params));
713
+ const data = response['data'];
714
+ const withdrawFees = {};
715
+ withdrawFees[code] = this.safeNumber (data, 'withdrawMinFee');
716
+ return {
717
+ 'info': response,
718
+ 'withdraw': withdrawFees,
719
+ 'deposit': {},
720
+ };
721
+ }
722
+
723
+ isFuturesMethod (methodName, params) {
724
+ //
725
+ // Helper
726
+ // @methodName (string): The name of the method
727
+ // @params (dict): The parameters passed into {methodName}
728
+ // @return: true if the method used is meant for futures trading, false otherwise
729
+ //
730
+ const defaultType = this.safeString2 (this.options, methodName, 'defaultType', 'trade');
731
+ const requestedType = this.safeString (params, 'type', defaultType);
732
+ const accountsByType = this.safeValue (this.options, 'accountsByType');
733
+ const type = this.safeString (accountsByType, requestedType);
734
+ if (type === undefined) {
735
+ const keys = Object.keys (accountsByType);
736
+ throw new ExchangeError (this.id + ' isFuturesMethod() type must be one of ' + keys.join (', '));
737
+ }
738
+ params = this.omit (params, 'type');
739
+ return (type === 'contract') || (type === 'future') || (type === 'futures'); // * (type === 'futures') deprecated, use (type === 'future')
740
+ }
741
+
742
+ parseTicker (ticker, market = undefined) {
743
+ //
744
+ // {
745
+ // "symbol": "BTC-USDT", // symbol
746
+ // "symbolName":"BTC-USDT", // Name of trading pairs, it would change after renaming
747
+ // "buy": "11328.9", // bestAsk
748
+ // "sell": "11329", // bestBid
749
+ // "changeRate": "-0.0055", // 24h change rate
750
+ // "changePrice": "-63.6", // 24h change price
751
+ // "high": "11610", // 24h highest price
752
+ // "low": "11200", // 24h lowest price
753
+ // "vol": "2282.70993217", // 24h volume,the aggregated trading volume in BTC
754
+ // "volValue": "25984946.157790431", // 24h total, the trading volume in quote currency of last 24 hours
755
+ // "last": "11328.9", // last price
756
+ // "averagePrice": "11360.66065903", // 24h average transaction price yesterday
757
+ // "takerFeeRate": "0.001", // Basic Taker Fee
758
+ // "makerFeeRate": "0.001", // Basic Maker Fee
759
+ // "takerCoefficient": "1", // Taker Fee Coefficient
760
+ // "makerCoefficient": "1" // Maker Fee Coefficient
761
+ // }
762
+ //
763
+ // {
764
+ // "trading": true,
765
+ // "symbol": "KCS-BTC",
766
+ // "buy": 0.00011,
767
+ // "sell": 0.00012,
768
+ // "sort": 100,
769
+ // "volValue": 3.13851792584, //total
770
+ // "baseCurrency": "KCS",
771
+ // "market": "BTC",
772
+ // "quoteCurrency": "BTC",
773
+ // "symbolCode": "KCS-BTC",
774
+ // "datetime": 1548388122031,
775
+ // "high": 0.00013,
776
+ // "vol": 27514.34842,
777
+ // "low": 0.0001,
778
+ // "changePrice": -1.0e-5,
779
+ // "changeRate": -0.0769,
780
+ // "lastTradedPrice": 0.00012,
781
+ // "board": 0,
782
+ // "mark": 0
783
+ // }
784
+ //
785
+ // market/ticker ws subscription
786
+ //
787
+ // {
788
+ // bestAsk: '62258.9',
789
+ // bestAskSize: '0.38579986',
790
+ // bestBid: '62258.8',
791
+ // bestBidSize: '0.0078381',
792
+ // price: '62260.7',
793
+ // sequence: '1621383297064',
794
+ // size: '0.00002841',
795
+ // time: 1634641777363
796
+ // }
797
+ //
798
+ let percentage = this.safeString (ticker, 'changeRate');
799
+ if (percentage !== undefined) {
800
+ percentage = Precise.stringMul (percentage, '100');
801
+ }
802
+ let last = this.safeString2 (ticker, 'last', 'lastTradedPrice');
803
+ last = this.safeString (ticker, 'price', last);
804
+ const marketId = this.safeString (ticker, 'symbol');
805
+ market = this.safeMarket (marketId, market, '-');
806
+ const symbol = market['symbol'];
807
+ const baseVolume = this.safeString (ticker, 'vol');
808
+ const quoteVolume = this.safeString (ticker, 'volValue');
809
+ const timestamp = this.safeInteger2 (ticker, 'time', 'datetime');
810
+ return this.safeTicker ({
811
+ 'symbol': symbol,
812
+ 'timestamp': timestamp,
813
+ 'datetime': this.iso8601 (timestamp),
814
+ 'high': this.safeString (ticker, 'high'),
815
+ 'low': this.safeString (ticker, 'low'),
816
+ 'bid': this.safeString2 (ticker, 'buy', 'bestBid'),
817
+ 'bidVolume': this.safeString (ticker, 'bestBidSize'),
818
+ 'ask': this.safeString2 (ticker, 'sell', 'bestAsk'),
819
+ 'askVolume': this.safeString (ticker, 'bestAskSize'),
820
+ 'vwap': undefined,
821
+ 'open': this.safeString (ticker, 'open'),
822
+ 'close': last,
823
+ 'last': last,
824
+ 'previousClose': undefined,
825
+ 'change': this.safeString (ticker, 'changePrice'),
826
+ 'percentage': percentage,
827
+ 'average': this.safeString (ticker, 'averagePrice'),
828
+ 'baseVolume': baseVolume,
829
+ 'quoteVolume': quoteVolume,
830
+ 'info': ticker,
831
+ }, market, false);
832
+ }
833
+
834
+ async fetchTickers (symbols = undefined, params = {}) {
835
+ await this.loadMarkets ();
836
+ const response = await this.publicGetMarketAllTickers (params);
837
+ //
838
+ // {
839
+ // "code": "200000",
840
+ // "data": {
841
+ // "time":1602832092060,
842
+ // "ticker":[
843
+ // {
844
+ // "symbol": "BTC-USDT", // symbol
845
+ // "symbolName":"BTC-USDT", // Name of trading pairs, it would change after renaming
846
+ // "buy": "11328.9", // bestAsk
847
+ // "sell": "11329", // bestBid
848
+ // "changeRate": "-0.0055", // 24h change rate
849
+ // "changePrice": "-63.6", // 24h change price
850
+ // "high": "11610", // 24h highest price
851
+ // "low": "11200", // 24h lowest price
852
+ // "vol": "2282.70993217", // 24h volume,the aggregated trading volume in BTC
853
+ // "volValue": "25984946.157790431", // 24h total, the trading volume in quote currency of last 24 hours
854
+ // "last": "11328.9", // last price
855
+ // "averagePrice": "11360.66065903", // 24h average transaction price yesterday
856
+ // "takerFeeRate": "0.001", // Basic Taker Fee
857
+ // "makerFeeRate": "0.001", // Basic Maker Fee
858
+ // "takerCoefficient": "1", // Taker Fee Coefficient
859
+ // "makerCoefficient": "1" // Maker Fee Coefficient
860
+ // }
861
+ // ]
862
+ // }
863
+ // }
864
+ //
865
+ const data = this.safeValue (response, 'data', {});
866
+ const tickers = this.safeValue (data, 'ticker', []);
867
+ const time = this.safeInteger (data, 'time');
868
+ const result = {};
869
+ for (let i = 0; i < tickers.length; i++) {
870
+ tickers[i]['time'] = time;
871
+ const ticker = this.parseTicker (tickers[i]);
872
+ const symbol = this.safeString (ticker, 'symbol');
873
+ if (symbol !== undefined) {
874
+ result[symbol] = ticker;
875
+ }
876
+ }
877
+ return this.filterByArray (result, 'symbol', symbols);
878
+ }
879
+
880
+ async fetchTicker (symbol, params = {}) {
881
+ await this.loadMarkets ();
882
+ const market = this.market (symbol);
883
+ const request = {
884
+ 'symbol': market['id'],
885
+ };
886
+ const response = await this.publicGetMarketStats (this.extend (request, params));
887
+ //
888
+ // {
889
+ // "code": "200000",
890
+ // "data": {
891
+ // "time": 1602832092060, // time
892
+ // "symbol": "BTC-USDT", // symbol
893
+ // "buy": "11328.9", // bestAsk
894
+ // "sell": "11329", // bestBid
895
+ // "changeRate": "-0.0055", // 24h change rate
896
+ // "changePrice": "-63.6", // 24h change price
897
+ // "high": "11610", // 24h highest price
898
+ // "low": "11200", // 24h lowest price
899
+ // "vol": "2282.70993217", // 24h volume,the aggregated trading volume in BTC
900
+ // "volValue": "25984946.157790431", // 24h total, the trading volume in quote currency of last 24 hours
901
+ // "last": "11328.9", // last price
902
+ // "averagePrice": "11360.66065903", // 24h average transaction price yesterday
903
+ // "takerFeeRate": "0.001", // Basic Taker Fee
904
+ // "makerFeeRate": "0.001", // Basic Maker Fee
905
+ // "takerCoefficient": "1", // Taker Fee Coefficient
906
+ // "makerCoefficient": "1" // Maker Fee Coefficient
907
+ // }
908
+ // }
909
+ //
910
+ return this.parseTicker (response['data'], market);
911
+ }
912
+
913
+ parseOHLCV (ohlcv, market = undefined) {
914
+ //
915
+ // [
916
+ // "1545904980", // Start time of the candle cycle
917
+ // "0.058", // opening price
918
+ // "0.049", // closing price
919
+ // "0.058", // highest price
920
+ // "0.049", // lowest price
921
+ // "0.018", // base volume
922
+ // "0.000945", // quote volume
923
+ // ]
924
+ //
925
+ return [
926
+ this.safeTimestamp (ohlcv, 0),
927
+ this.safeNumber (ohlcv, 1),
928
+ this.safeNumber (ohlcv, 3),
929
+ this.safeNumber (ohlcv, 4),
930
+ this.safeNumber (ohlcv, 2),
931
+ this.safeNumber (ohlcv, 5),
932
+ ];
933
+ }
934
+
935
+ async fetchOHLCV (symbol, timeframe = '15m', since = undefined, limit = undefined, params = {}) {
936
+ await this.loadMarkets ();
937
+ const market = this.market (symbol);
938
+ const marketId = market['id'];
939
+ const request = {
940
+ 'symbol': marketId,
941
+ 'type': this.timeframes[timeframe],
942
+ };
943
+ const duration = this.parseTimeframe (timeframe) * 1000;
944
+ let endAt = this.milliseconds (); // required param
945
+ if (since !== undefined) {
946
+ request['startAt'] = parseInt (Math.floor (since / 1000));
947
+ if (limit === undefined) {
948
+ // https://docs.kucoin.com/#get-klines
949
+ // https://docs.kucoin.com/#details
950
+ // For each query, the system would return at most 1500 pieces of data.
951
+ // To obtain more data, please page the data by time.
952
+ limit = this.safeInteger (this.options, 'fetchOHLCVLimit', 1500);
953
+ }
954
+ endAt = this.sum (since, limit * duration);
955
+ } else if (limit !== undefined) {
956
+ since = endAt - limit * duration;
957
+ request['startAt'] = parseInt (Math.floor (since / 1000));
958
+ }
959
+ request['endAt'] = parseInt (Math.floor (endAt / 1000));
960
+ const response = await this.publicGetMarketCandles (this.extend (request, params));
961
+ //
962
+ // {
963
+ // "code":"200000",
964
+ // "data":[
965
+ // ["1591517700","0.025078","0.025069","0.025084","0.025064","18.9883256","0.4761861079404"],
966
+ // ["1591516800","0.025089","0.025079","0.025089","0.02506","99.4716622","2.494143499081"],
967
+ // ["1591515900","0.025079","0.02509","0.025091","0.025068","59.83701271","1.50060885172798"],
968
+ // ]
969
+ // }
970
+ //
971
+ const data = this.safeValue (response, 'data', []);
972
+ return this.parseOHLCVs (data, market, timeframe, since, limit);
973
+ }
974
+
975
+ async createDepositAddress (code, params = {}) {
976
+ await this.loadMarkets ();
977
+ const currency = this.currency (code);
978
+ const request = { 'currency': currency['id'] };
979
+ const response = await this.privatePostDepositAddresses (this.extend (request, params));
980
+ // BCH {"code":"200000","data":{"address":"bitcoincash:qza3m4nj9rx7l9r0cdadfqxts6f92shvhvr5ls4q7z","memo":""}}
981
+ // BTC {"code":"200000","data":{"address":"36SjucKqQpQSvsak9A7h6qzFjrVXpRNZhE","memo":""}}
982
+ const data = this.safeValue (response, 'data', {});
983
+ let address = this.safeString (data, 'address');
984
+ // BCH/BSV is returned with a "bitcoincash:" prefix, which we cut off here and only keep the address
985
+ if (address !== undefined) {
986
+ address = address.replace ('bitcoincash:', '');
987
+ }
988
+ const tag = this.safeString (data, 'memo');
989
+ if (code !== 'NIM') {
990
+ // contains spaces
991
+ this.checkAddress (address);
992
+ }
993
+ return {
994
+ 'info': response,
995
+ 'currency': code,
996
+ 'address': address,
997
+ 'tag': tag,
998
+ };
999
+ }
1000
+
1001
+ async fetchDepositAddress (code, params = {}) {
1002
+ await this.loadMarkets ();
1003
+ const currency = this.currency (code);
1004
+ const request = {
1005
+ 'currency': currency['id'],
1006
+ // for USDT - OMNI, ERC20, TRC20, default is ERC20
1007
+ // for BTC - Native, Segwit, TRC20, the parameters are bech32, btc, trx, default is Native
1008
+ // 'chain': 'ERC20', // optional
1009
+ };
1010
+ // same as for withdraw
1011
+ const networks = this.safeValue (this.options, 'networks', {});
1012
+ let network = this.safeStringUpper (params, 'network'); // this line allows the user to specify either ERC20 or ETH
1013
+ network = this.safeStringLower (networks, network, network); // handle ERC20>ETH alias
1014
+ if (network !== undefined) {
1015
+ request['chain'] = network;
1016
+ params = this.omit (params, 'network');
1017
+ }
1018
+ const response = await this.privateGetDepositAddresses (this.extend (request, params));
1019
+ // BCH {"code":"200000","data":{"address":"bitcoincash:qza3m4nj9rx7l9r0cdadfqxts6f92shvhvr5ls4q7z","memo":""}}
1020
+ // BTC {"code":"200000","data":{"address":"36SjucKqQpQSvsak9A7h6qzFjrVXpRNZhE","memo":""}}
1021
+ const data = this.safeValue (response, 'data', {});
1022
+ const address = this.safeString (data, 'address');
1023
+ const tag = this.safeString (data, 'memo');
1024
+ if (code !== 'NIM') {
1025
+ // contains spaces
1026
+ this.checkAddress (address);
1027
+ }
1028
+ return {
1029
+ 'info': response,
1030
+ 'currency': code,
1031
+ 'address': address,
1032
+ 'tag': tag,
1033
+ 'network': undefined,
1034
+ };
1035
+ }
1036
+
1037
+ async fetchOrderBook (symbol, limit = undefined, params = {}) {
1038
+ await this.loadMarkets ();
1039
+ const marketId = this.marketId (symbol);
1040
+ const level = this.safeInteger (params, 'level', 2);
1041
+ const request = { 'symbol': marketId };
1042
+ let method = 'publicGetMarketOrderbookLevelLevelLimit';
1043
+ const isAuthenticated = this.checkRequiredCredentials (false);
1044
+ let response = undefined;
1045
+ if (!isAuthenticated) {
1046
+ if (level === 2) {
1047
+ request['level'] = level;
1048
+ if (limit !== undefined) {
1049
+ if ((limit === 20) || (limit === 100)) {
1050
+ request['limit'] = limit;
1051
+ } else {
1052
+ throw new ExchangeError (this.id + ' fetchOrderBook() limit argument must be 20 or 100');
1053
+ }
1054
+ }
1055
+ request['limit'] = limit ? limit : 100;
1056
+ method = 'publicGetMarketOrderbookLevelLevelLimit';
1057
+ response = await this[method] (this.extend (request, params));
1058
+ }
1059
+ } else {
1060
+ method = 'privateGetMarketOrderbookLevel2'; // recommended (v3)
1061
+ response = await this[method] (this.extend (request, params));
1062
+ }
1063
+ //
1064
+ // public (v1) market/orderbook/level2_20 and market/orderbook/level2_100
1065
+ //
1066
+ // {
1067
+ // "sequence": "3262786978",
1068
+ // "time": 1550653727731,
1069
+ // "bids": [
1070
+ // ["6500.12", "0.45054140"],
1071
+ // ["6500.11", "0.45054140"],
1072
+ // ],
1073
+ // "asks": [
1074
+ // ["6500.16", "0.57753524"],
1075
+ // ["6500.15", "0.57753524"],
1076
+ // ]
1077
+ // }
1078
+ //
1079
+ // private (v3) market/orderbook/level2
1080
+ //
1081
+ // {
1082
+ // "sequence": "3262786978",
1083
+ // "time": 1550653727731,
1084
+ // "bids": [
1085
+ // ["6500.12", "0.45054140"],
1086
+ // ["6500.11", "0.45054140"],
1087
+ // ],
1088
+ // "asks": [
1089
+ // ["6500.16", "0.57753524"],
1090
+ // ["6500.15", "0.57753524"],
1091
+ // ]
1092
+ // }
1093
+ //
1094
+ const data = this.safeValue (response, 'data', {});
1095
+ const timestamp = this.safeInteger (data, 'time');
1096
+ const orderbook = this.parseOrderBook (data, symbol, timestamp, 'bids', 'asks', level - 2, level - 1);
1097
+ orderbook['nonce'] = this.safeInteger (data, 'sequence');
1098
+ return orderbook;
1099
+ }
1100
+
1101
+ async createOrder (symbol, type, side, amount, price = undefined, params = {}) {
1102
+ /**
1103
+ * @method
1104
+ * @name kucoin#createOrder
1105
+ * @description Create an order on the exchange
1106
+ * @param {str} symbol Unified CCXT market symbol
1107
+ * @param {str} type "limit" or "market"
1108
+ * @param {str} side "buy" or "sell"
1109
+ * @param {float} amount the amount of currency to trade
1110
+ * @param {float} price *ignored in "market" orders* the price at which the order is to be fullfilled at in units of the quote currency
1111
+ * @param {dict} params Extra parameters specific to the exchange API endpoint
1112
+ * @param {str} params.clientOid client order id, defaults to uuid if not passed
1113
+ * @param {str} params.remark remark for the order, length cannot exceed 100 utf8 characters
1114
+ * @param {str} params.tradeType 'TRADE', // TRADE, MARGIN_TRADE // not used with margin orders
1115
+ * limit orders ---------------------------------------------------
1116
+ * @param {str} params.timeInForce GTC, GTT, IOC, or FOK, default is GTC, limit orders only
1117
+ * @param {float} params.cancelAfter long, // cancel after n seconds, requires timeInForce to be GTT
1118
+ * @param {str} params.postOnly Post only flag, invalid when timeInForce is IOC or FOK
1119
+ * @param {bool} params.hidden false, // Order will not be displayed in the order book
1120
+ * @param {bool} params.iceberg false, // Only a portion of the order is displayed in the order book
1121
+ * @param {str} params.visibleSize this.amountToPrecision (symbol, visibleSize), // The maximum visible size of an iceberg order
1122
+ * market orders --------------------------------------------------
1123
+ * @param {str} params.funds // Amount of quote currency to use
1124
+ * stop orders ----------------------------------------------------
1125
+ * @param {str} params.stop Either loss or entry, the default is loss. Requires stopPrice to be defined
1126
+ * @param {float} params.stopPrice The price at which a trigger order is triggered at
1127
+ * margin orders --------------------------------------------------
1128
+ * @param {float} params.leverage Leverage size of the order
1129
+ * @param {str} params.stp '', // self trade prevention, CN, CO, CB or DC
1130
+ * @param {str} params.marginMode 'cross', // cross (cross mode) and isolated (isolated mode), set to cross by default, the isolated mode will be released soon, stay tuned
1131
+ * @param {bool} params.autoBorrow false, // The system will first borrow you funds at the optimal interest rate and then place an order for you
1132
+ * @returns an [order structure]{@link https://docs.ccxt.com/en/latest/manual.html#order-structure}
1133
+ */
1134
+ await this.loadMarkets ();
1135
+ const marketId = this.marketId (symbol);
1136
+ // required param, cannot be used twice
1137
+ const clientOrderId = this.safeString2 (params, 'clientOid', 'clientOrderId', this.uuid ());
1138
+ params = this.omit (params, [ 'clientOid', 'clientOrderId' ]);
1139
+ const request = {
1140
+ 'clientOid': clientOrderId,
1141
+ 'side': side,
1142
+ 'symbol': marketId,
1143
+ 'type': type, // limit or market
1144
+ };
1145
+ const quoteAmount = this.safeNumber2 (params, 'cost', 'funds');
1146
+ let amountString = undefined;
1147
+ let costString = undefined;
1148
+ if (type === 'market') {
1149
+ if (quoteAmount !== undefined) {
1150
+ params = this.omit (params, [ 'cost', 'funds' ]);
1151
+ // kucoin uses base precision even for quote values
1152
+ costString = this.amountToPrecision (symbol, quoteAmount);
1153
+ request['funds'] = costString;
1154
+ } else {
1155
+ amountString = this.amountToPrecision (symbol, amount);
1156
+ request['size'] = this.amountToPrecision (symbol, amount);
1157
+ }
1158
+ } else {
1159
+ amountString = this.amountToPrecision (symbol, amount);
1160
+ request['size'] = amountString;
1161
+ request['price'] = this.priceToPrecision (symbol, price);
1162
+ }
1163
+ const stopPrice = this.safeString (params, 'stopPrice');
1164
+ const tradeType = this.safeString (params, 'tradeType');
1165
+ params = this.omit (params, 'stopPrice');
1166
+ let method = 'privatePostOrders';
1167
+ if (stopPrice !== undefined) {
1168
+ request['stopPrice'] = this.priceToPrecision (symbol, stopPrice);
1169
+ request['stop'] = 'loss';
1170
+ method = 'privatePostStopOrder';
1171
+ } else if (tradeType === 'MARGIN_TRADE') {
1172
+ method = 'privatePostMarginOrder';
1173
+ }
1174
+ const response = await this[method] (this.extend (request, params));
1175
+ //
1176
+ // {
1177
+ // code: '200000',
1178
+ // data: {
1179
+ // "orderId": "5bd6e9286d99522a52e458de"
1180
+ // }
1181
+ // }
1182
+ //
1183
+ const data = this.safeValue (response, 'data', {});
1184
+ const timestamp = this.milliseconds ();
1185
+ const id = this.safeString (data, 'orderId');
1186
+ const order = {
1187
+ 'id': id,
1188
+ 'clientOrderId': clientOrderId,
1189
+ 'info': data,
1190
+ 'timestamp': timestamp,
1191
+ 'datetime': this.iso8601 (timestamp),
1192
+ 'lastTradeTimestamp': undefined,
1193
+ 'symbol': symbol,
1194
+ 'type': type,
1195
+ 'side': side,
1196
+ 'price': price,
1197
+ 'amount': this.parseNumber (amountString),
1198
+ 'cost': this.parseNumber (costString),
1199
+ 'average': undefined,
1200
+ 'filled': undefined,
1201
+ 'remaining': undefined,
1202
+ 'status': undefined,
1203
+ 'fee': undefined,
1204
+ 'trades': undefined,
1205
+ };
1206
+ return order;
1207
+ }
1208
+
1209
+ async cancelOrder (id, symbol = undefined, params = {}) {
1210
+ /**
1211
+ * @method
1212
+ * @name kucoin#cancelOrder
1213
+ * @description Cancels an order
1214
+ * @param {str} id Order id
1215
+ * @param {str} symbol Not used by kucoin
1216
+ * @param {dict} params Exchange specific parameters
1217
+ * @param {bool} params.stop True if cancelling a stop order
1218
+ * @returns Response fromt the exchange
1219
+ */
1220
+ await this.loadMarkets ();
1221
+ const request = {};
1222
+ const clientOrderId = this.safeString2 (params, 'clientOid', 'clientOrderId');
1223
+ const stop = this.safeValue (params, 'stop');
1224
+ let method = 'privateDeleteOrdersOrderId';
1225
+ if (clientOrderId !== undefined) {
1226
+ request['clientOid'] = clientOrderId;
1227
+ if (stop) {
1228
+ method = 'privateDeleteStopOrderCancelOrderByClientOid';
1229
+ } else {
1230
+ method = 'privateDeleteOrdersClientOrderClientOid';
1231
+ }
1232
+ } else {
1233
+ if (stop) {
1234
+ method = 'privateDeleteStopOrderOrderId';
1235
+ }
1236
+ request['orderId'] = id;
1237
+ }
1238
+ params = this.omit (params, [ 'clientOid', 'clientOrderId', 'stop' ]);
1239
+ return await this[method] (this.extend (request, params));
1240
+ }
1241
+
1242
+ async cancelAllOrders (symbol = undefined, params = {}) {
1243
+ /**
1244
+ * @method
1245
+ * @name kucoin#cancelAllOrders
1246
+ * @description Cancels all open orders, or cancels all orders in a market for one symbol, stop orders must be cancelled separately
1247
+ * @param {str} symbol Unified symbol indicating the market to cancel orders in
1248
+ * @param {dict} params Exchange specific parameters
1249
+ * @param {bool} params.stop true if cancelling all stop orders
1250
+ * @param {str} params.tradeType The type of trading, "TRADE" for Spot Trading, "MARGIN_TRADE" for Margin Trading
1251
+ * @param {str} params.orderIds *stop orders only* Comma seperated order IDs
1252
+ * @returns Response from the exchange
1253
+ */
1254
+ await this.loadMarkets ();
1255
+ const request = {};
1256
+ let market = undefined;
1257
+ if (symbol !== undefined) {
1258
+ market = this.market (symbol);
1259
+ request['symbol'] = market['id'];
1260
+ }
1261
+ let method = 'privateDeleteOrders';
1262
+ const stop = this.safeValue (params, 'stop');
1263
+ if (stop) {
1264
+ method = 'privateDeleteStopOrderCancel';
1265
+ }
1266
+ return await this[method] (this.extend (request, params));
1267
+ }
1268
+
1269
+ async fetchOrdersByStatus (status, symbol = undefined, since = undefined, limit = undefined, params = {}) {
1270
+ /**
1271
+ * @method
1272
+ * @name kucoin#fetchOrdersByStatus
1273
+ * @description fetch a list of orders
1274
+ * @param {str} status *not used for stop orders* 'open' or 'closed'
1275
+ * @param {str} symbol unified market symbol
1276
+ * @param {int} since timestamp in ms of the earliest order
1277
+ * @param {int} limit max number of orders to return
1278
+ * @param {dict} params exchange specific params
1279
+ * @param {int} params.till end time in ms
1280
+ * @param {bool} params.stop true if fetching stop orders
1281
+ * @param {str} params.side buy or sell
1282
+ * @param {str} params.type limit, market, limit_stop or market_stop
1283
+ * @param {str} params.tradeType TRADE for spot trading, MARGIN_TRADE for Margin Trading
1284
+ * @param {int} params.currentPage *stop orders only* current page
1285
+ * @param {str} params.orderIds *stop orders only* comma seperated order ID list
1286
+ * @returns An [array of order structures]{@link https://docs.ccxt.com/en/latest/manual.html#order-structure}
1287
+ */
1288
+ await this.loadMarkets ();
1289
+ let lowercaseStatus = status.toLowerCase ();
1290
+ if (lowercaseStatus === 'open') {
1291
+ lowercaseStatus = 'active';
1292
+ } else if (lowercaseStatus === 'closed') {
1293
+ lowercaseStatus = 'done';
1294
+ }
1295
+ const request = {
1296
+ 'status': lowercaseStatus,
1297
+ };
1298
+ let market = undefined;
1299
+ if (symbol !== undefined) {
1300
+ market = this.market (symbol);
1301
+ request['symbol'] = market['id'];
1302
+ }
1303
+ if (since !== undefined) {
1304
+ request['startAt'] = since;
1305
+ }
1306
+ if (limit !== undefined) {
1307
+ request['pageSize'] = limit;
1308
+ }
1309
+ const till = this.safeInteger (params, 'till');
1310
+ if (till) {
1311
+ request['endAt'] = till;
1312
+ }
1313
+ const stop = this.safeValue (params, 'stop');
1314
+ params = this.omit (params, 'stop');
1315
+ let method = 'privateGetOrders';
1316
+ if (stop) {
1317
+ method = 'privateGetStopOrder';
1318
+ }
1319
+ const response = await this[method] (this.extend (request, params));
1320
+ //
1321
+ // {
1322
+ // code: '200000',
1323
+ // data: {
1324
+ // "currentPage": 1,
1325
+ // "pageSize": 1,
1326
+ // "totalNum": 153408,
1327
+ // "totalPage": 153408,
1328
+ // "items": [
1329
+ // {
1330
+ // "id": "5c35c02703aa673ceec2a168", //orderid
1331
+ // "symbol": "BTC-USDT", //symbol
1332
+ // "opType": "DEAL", // operation type,deal is pending order,cancel is cancel order
1333
+ // "type": "limit", // order type,e.g. limit,markrt,stop_limit.
1334
+ // "side": "buy", // transaction direction,include buy and sell
1335
+ // "price": "10", // order price
1336
+ // "size": "2", // order quantity
1337
+ // "funds": "0", // order funds
1338
+ // "dealFunds": "0.166", // deal funds
1339
+ // "dealSize": "2", // deal quantity
1340
+ // "fee": "0", // fee
1341
+ // "feeCurrency": "USDT", // charge fee currency
1342
+ // "stp": "", // self trade prevention,include CN,CO,DC,CB
1343
+ // "stop": "", // stop type
1344
+ // "stopTriggered": false, // stop order is triggered
1345
+ // "stopPrice": "0", // stop price
1346
+ // "timeInForce": "GTC", // time InForce,include GTC,GTT,IOC,FOK
1347
+ // "postOnly": false, // postOnly
1348
+ // "hidden": false, // hidden order
1349
+ // "iceberg": false, // iceberg order
1350
+ // "visibleSize": "0", // display quantity for iceberg order
1351
+ // "cancelAfter": 0, // cancel orders time,requires timeInForce to be GTT
1352
+ // "channel": "IOS", // order source
1353
+ // "clientOid": "", // user-entered order unique mark
1354
+ // "remark": "", // remark
1355
+ // "tags": "", // tag order source
1356
+ // "isActive": false, // status before unfilled or uncancelled
1357
+ // "cancelExist": false, // order cancellation transaction record
1358
+ // "createdAt": 1547026471000 // time
1359
+ // },
1360
+ // ]
1361
+ // }
1362
+ // }
1363
+ const responseData = this.safeValue (response, 'data', {});
1364
+ const orders = this.safeValue (responseData, 'items', []);
1365
+ return this.parseOrders (orders, market, since, limit);
1366
+ }
1367
+
1368
+ async fetchClosedOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) {
1369
+ /**
1370
+ * @method
1371
+ * @name kucoin#fetchClosedOrders
1372
+ * @description fetch a list of orders
1373
+ * @param {str} symbol unified market symbol
1374
+ * @param {int} since timestamp in ms of the earliest order
1375
+ * @param {int} limit max number of orders to return
1376
+ * @param {dict} params exchange specific params
1377
+ * @param {int} params.till end time in ms
1378
+ * @param {str} params.side buy or sell
1379
+ * @param {str} params.type limit, market, limit_stop or market_stop
1380
+ * @param {str} params.tradeType TRADE for spot trading, MARGIN_TRADE for Margin Trading
1381
+ * @returns An [array of order structures]{@link https://docs.ccxt.com/en/latest/manual.html#order-structure}
1382
+ */
1383
+ return await this.fetchOrdersByStatus ('done', symbol, since, limit, params);
1384
+ }
1385
+
1386
+ async fetchOpenOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) {
1387
+ /**
1388
+ * @method
1389
+ * @name kucoin#fetchOrdersByStatus
1390
+ * @description fetch a list of orders
1391
+ * @param {str} symbol unified market symbol
1392
+ * @param {int} since timestamp in ms of the earliest order
1393
+ * @param {int} limit max number of orders to return
1394
+ * @param {dict} params exchange specific params
1395
+ * @param {int} params.till end time in ms
1396
+ * @param {bool} params.stop true if fetching stop orders
1397
+ * @param {str} params.side buy or sell
1398
+ * @param {str} params.type limit, market, limit_stop or market_stop
1399
+ * @param {str} params.tradeType TRADE for spot trading, MARGIN_TRADE for Margin Trading
1400
+ * @param {int} params.currentPage *stop orders only* current page
1401
+ * @param {str} params.orderIds *stop orders only* comma seperated order ID list
1402
+ * @returns An [array of order structures]{@link https://docs.ccxt.com/en/latest/manual.html#order-structure}
1403
+ */
1404
+ return await this.fetchOrdersByStatus ('active', symbol, since, limit, params);
1405
+ }
1406
+
1407
+ async fetchOrder (id, symbol = undefined, params = {}) {
1408
+ /**
1409
+ * @method
1410
+ * @name kucoin#fetchOrder
1411
+ * @description fetch an order
1412
+ * @param {str} id Order id
1413
+ * @param {str} symbol not sent to exchange except for stop orders with clientOid, but used internally by CCXT to filter
1414
+ * @param {dict} params exchange specific parameters
1415
+ * @param {bool} params.stop true if fetching a stop order
1416
+ * @param {bool} params.clientOid unique order id created by users to identify their orders
1417
+ * @returns An [order structure]{@link https://docs.ccxt.com/en/latest/manual.html#order-structure}
1418
+ */
1419
+ await this.loadMarkets ();
1420
+ const request = {};
1421
+ const clientOrderId = this.safeString2 (params, 'clientOid', 'clientOrderId');
1422
+ const stop = this.safeValue (params, 'stop');
1423
+ let market = undefined;
1424
+ if (symbol !== undefined) {
1425
+ market = this.market (symbol);
1426
+ }
1427
+ params = this.omit (params, 'stop');
1428
+ let method = 'privateGetOrdersOrderId';
1429
+ if (clientOrderId !== undefined) {
1430
+ request['clientOid'] = clientOrderId;
1431
+ if (stop) {
1432
+ method = 'privateGetStopOrderQueryOrderByClientOid';
1433
+ if (symbol !== undefined) {
1434
+ request['symbol'] = market['id'];
1435
+ }
1436
+ } else {
1437
+ method = 'privateGetOrderClientOrderClientOid';
1438
+ }
1439
+ } else {
1440
+ // a special case for undefined ids
1441
+ // otherwise a wrong endpoint for all orders will be triggered
1442
+ // https://github.com/ccxt/ccxt/issues/7234
1443
+ if (id === undefined) {
1444
+ throw new InvalidOrder (this.id + ' fetchOrder() requires an order id');
1445
+ }
1446
+ if (stop) {
1447
+ method = 'privateGetStopOrderOrderId';
1448
+ }
1449
+ request['orderId'] = id;
1450
+ }
1451
+ params = this.omit (params, [ 'clientOid', 'clientOrderId' ]);
1452
+ const response = await this[method] (this.extend (request, params));
1453
+ let responseData = this.safeValue (response, 'data');
1454
+ if (method === 'privateGetStopOrderQueryOrderByClientOid') {
1455
+ responseData = this.safeValue (responseData, 0);
1456
+ }
1457
+ return this.parseOrder (responseData, market);
1458
+ }
1459
+
1460
+ parseOrder (order, market = undefined) {
1461
+ //
1462
+ // fetchOpenOrders, fetchClosedOrders
1463
+ //
1464
+ // {
1465
+ // "id": "5c35c02703aa673ceec2a168", //orderid
1466
+ // "symbol": "BTC-USDT", //symbol
1467
+ // "opType": "DEAL", // operation type,deal is pending order,cancel is cancel order
1468
+ // "type": "limit", // order type,e.g. limit,markrt,stop_limit.
1469
+ // "side": "buy", // transaction direction,include buy and sell
1470
+ // "price": "10", // order price
1471
+ // "size": "2", // order quantity
1472
+ // "funds": "0", // order funds
1473
+ // "dealFunds": "0.166", // deal funds
1474
+ // "dealSize": "2", // deal quantity
1475
+ // "fee": "0", // fee
1476
+ // "feeCurrency": "USDT", // charge fee currency
1477
+ // "stp": "", // self trade prevention,include CN,CO,DC,CB
1478
+ // "stop": "", // stop type
1479
+ // "stopTriggered": false, // stop order is triggered
1480
+ // "stopPrice": "0", // stop price
1481
+ // "timeInForce": "GTC", // time InForce,include GTC,GTT,IOC,FOK
1482
+ // "postOnly": false, // postOnly
1483
+ // "hidden": false, // hidden order
1484
+ // "iceberg": false, // iceberg order
1485
+ // "visibleSize": "0", // display quantity for iceberg order
1486
+ // "cancelAfter": 0, // cancel orders time,requires timeInForce to be GTT
1487
+ // "channel": "IOS", // order source
1488
+ // "clientOid": "", // user-entered order unique mark
1489
+ // "remark": "", // remark
1490
+ // "tags": "", // tag order source
1491
+ // "isActive": false, // status before unfilled or uncancelled
1492
+ // "cancelExist": false, // order cancellation transaction record
1493
+ // "createdAt": 1547026471000 // time
1494
+ // }
1495
+ //
1496
+ const marketId = this.safeString (order, 'symbol');
1497
+ const symbol = this.safeSymbol (marketId, market, '-');
1498
+ const orderId = this.safeString (order, 'id');
1499
+ const type = this.safeString (order, 'type');
1500
+ const timestamp = this.safeInteger (order, 'createdAt');
1501
+ const datetime = this.iso8601 (timestamp);
1502
+ const price = this.safeString (order, 'price');
1503
+ // price is zero for market order
1504
+ // omitZero is called in safeOrder2
1505
+ const side = this.safeString (order, 'side');
1506
+ const feeCurrencyId = this.safeString (order, 'feeCurrency');
1507
+ const feeCurrency = this.safeCurrencyCode (feeCurrencyId);
1508
+ const feeCost = this.safeNumber (order, 'fee');
1509
+ const amount = this.safeString (order, 'size');
1510
+ const filled = this.safeString (order, 'dealSize');
1511
+ const cost = this.safeString (order, 'dealFunds');
1512
+ // bool
1513
+ const isActive = this.safeValue (order, 'isActive', false);
1514
+ const cancelExist = this.safeValue (order, 'cancelExist', false);
1515
+ const stop = this.safeString (order, 'stop');
1516
+ const stopTriggered = this.safeValue (order, 'stopTriggered', false);
1517
+ let status = isActive ? 'open' : 'closed';
1518
+ const cancelExistWithStop = cancelExist || (!isActive && stop && !stopTriggered);
1519
+ status = cancelExistWithStop ? 'canceled' : status;
1520
+ const fee = {
1521
+ 'currency': feeCurrency,
1522
+ 'cost': feeCost,
1523
+ };
1524
+ const clientOrderId = this.safeString (order, 'clientOid');
1525
+ const timeInForce = this.safeString (order, 'timeInForce');
1526
+ const stopPrice = this.safeNumber (order, 'stopPrice');
1527
+ const postOnly = this.safeValue (order, 'postOnly');
1528
+ return this.safeOrder ({
1529
+ 'id': orderId,
1530
+ 'clientOrderId': clientOrderId,
1531
+ 'symbol': symbol,
1532
+ 'type': type,
1533
+ 'timeInForce': timeInForce,
1534
+ 'postOnly': postOnly,
1535
+ 'side': side,
1536
+ 'amount': amount,
1537
+ 'price': price,
1538
+ 'stopPrice': stopPrice,
1539
+ 'cost': cost,
1540
+ 'filled': filled,
1541
+ 'remaining': undefined,
1542
+ 'timestamp': timestamp,
1543
+ 'datetime': datetime,
1544
+ 'fee': fee,
1545
+ 'status': status,
1546
+ 'info': order,
1547
+ 'lastTradeTimestamp': undefined,
1548
+ 'average': undefined,
1549
+ 'trades': undefined,
1550
+ }, market);
1551
+ }
1552
+
1553
+ async fetchMyTrades (symbol = undefined, since = undefined, limit = undefined, params = {}) {
1554
+ await this.loadMarkets ();
1555
+ const request = {};
1556
+ let market = undefined;
1557
+ if (symbol !== undefined) {
1558
+ market = this.market (symbol);
1559
+ request['symbol'] = market['id'];
1560
+ }
1561
+ if (limit !== undefined) {
1562
+ request['pageSize'] = limit;
1563
+ }
1564
+ const method = this.options['fetchMyTradesMethod'];
1565
+ let parseResponseData = false;
1566
+ if (method === 'private_get_fills') {
1567
+ // does not return trades earlier than 2019-02-18T00:00:00Z
1568
+ if (since !== undefined) {
1569
+ // only returns trades up to one week after the since param
1570
+ request['startAt'] = since;
1571
+ }
1572
+ } else if (method === 'private_get_limit_fills') {
1573
+ // does not return trades earlier than 2019-02-18T00:00:00Z
1574
+ // takes no params
1575
+ // only returns first 1000 trades (not only "in the last 24 hours" as stated in the docs)
1576
+ parseResponseData = true;
1577
+ } else if (method === 'private_get_hist_orders') {
1578
+ // despite that this endpoint is called `HistOrders`
1579
+ // it returns historical trades instead of orders
1580
+ // returns trades earlier than 2019-02-18T00:00:00Z only
1581
+ if (since !== undefined) {
1582
+ request['startAt'] = parseInt (since / 1000);
1583
+ }
1584
+ } else {
1585
+ throw new ExchangeError (this.id + ' fetchMyTradesMethod() invalid method');
1586
+ }
1587
+ const response = await this[method] (this.extend (request, params));
1588
+ //
1589
+ // {
1590
+ // "currentPage": 1,
1591
+ // "pageSize": 50,
1592
+ // "totalNum": 1,
1593
+ // "totalPage": 1,
1594
+ // "items": [
1595
+ // {
1596
+ // "symbol":"BTC-USDT", // symbol
1597
+ // "tradeId":"5c35c02709e4f67d5266954e", // trade id
1598
+ // "orderId":"5c35c02703aa673ceec2a168", // order id
1599
+ // "counterOrderId":"5c1ab46003aa676e487fa8e3", // counter order id
1600
+ // "side":"buy", // transaction direction,include buy and sell
1601
+ // "liquidity":"taker", // include taker and maker
1602
+ // "forceTaker":true, // forced to become taker
1603
+ // "price":"0.083", // order price
1604
+ // "size":"0.8424304", // order quantity
1605
+ // "funds":"0.0699217232", // order funds
1606
+ // "fee":"0", // fee
1607
+ // "feeRate":"0", // fee rate
1608
+ // "feeCurrency":"USDT", // charge fee currency
1609
+ // "stop":"", // stop type
1610
+ // "type":"limit", // order type, e.g. limit, market, stop_limit.
1611
+ // "createdAt":1547026472000 // time
1612
+ // },
1613
+ // //------------------------------------------------------
1614
+ // // v1 (historical) trade response structure
1615
+ // {
1616
+ // "symbol": "SNOV-ETH",
1617
+ // "dealPrice": "0.0000246",
1618
+ // "dealValue": "0.018942",
1619
+ // "amount": "770",
1620
+ // "fee": "0.00001137",
1621
+ // "side": "sell",
1622
+ // "createdAt": 1540080199
1623
+ // "id":"5c4d389e4c8c60413f78e2e5",
1624
+ // }
1625
+ // ]
1626
+ // }
1627
+ //
1628
+ const data = this.safeValue (response, 'data', {});
1629
+ let trades = undefined;
1630
+ if (parseResponseData) {
1631
+ trades = data;
1632
+ } else {
1633
+ trades = this.safeValue (data, 'items', []);
1634
+ }
1635
+ return this.parseTrades (trades, market, since, limit);
1636
+ }
1637
+
1638
+ async fetchTrades (symbol, since = undefined, limit = undefined, params = {}) {
1639
+ await this.loadMarkets ();
1640
+ const market = this.market (symbol);
1641
+ const request = {
1642
+ 'symbol': market['id'],
1643
+ };
1644
+ // pagination is not supported on the exchange side anymore
1645
+ // if (since !== undefined) {
1646
+ // request['startAt'] = Math.floor (since / 1000);
1647
+ // }
1648
+ // if (limit !== undefined) {
1649
+ // request['pageSize'] = limit;
1650
+ // }
1651
+ const response = await this.publicGetMarketHistories (this.extend (request, params));
1652
+ //
1653
+ // {
1654
+ // "code": "200000",
1655
+ // "data": [
1656
+ // {
1657
+ // "sequence": "1548764654235",
1658
+ // "side": "sell",
1659
+ // "size":"0.6841354",
1660
+ // "price":"0.03202",
1661
+ // "time":1548848575203567174
1662
+ // }
1663
+ // ]
1664
+ // }
1665
+ //
1666
+ const trades = this.safeValue (response, 'data', []);
1667
+ return this.parseTrades (trades, market, since, limit);
1668
+ }
1669
+
1670
+ parseTrade (trade, market = undefined) {
1671
+ //
1672
+ // fetchTrades (public)
1673
+ //
1674
+ // {
1675
+ // "sequence": "1548764654235",
1676
+ // "side": "sell",
1677
+ // "size":"0.6841354",
1678
+ // "price":"0.03202",
1679
+ // "time":1548848575203567174
1680
+ // }
1681
+ //
1682
+ // {
1683
+ // sequence: '1568787654360',
1684
+ // symbol: 'BTC-USDT',
1685
+ // side: 'buy',
1686
+ // size: '0.00536577',
1687
+ // price: '9345',
1688
+ // takerOrderId: '5e356c4a9f1a790008f8d921',
1689
+ // time: '1580559434436443257',
1690
+ // type: 'match',
1691
+ // makerOrderId: '5e356bffedf0010008fa5d7f',
1692
+ // tradeId: '5e356c4aeefabd62c62a1ece'
1693
+ // }
1694
+ //
1695
+ // fetchMyTrades (private) v2
1696
+ //
1697
+ // {
1698
+ // "symbol":"BTC-USDT",
1699
+ // "tradeId":"5c35c02709e4f67d5266954e",
1700
+ // "orderId":"5c35c02703aa673ceec2a168",
1701
+ // "counterOrderId":"5c1ab46003aa676e487fa8e3",
1702
+ // "side":"buy",
1703
+ // "liquidity":"taker",
1704
+ // "forceTaker":true,
1705
+ // "price":"0.083",
1706
+ // "size":"0.8424304",
1707
+ // "funds":"0.0699217232",
1708
+ // "fee":"0",
1709
+ // "feeRate":"0",
1710
+ // "feeCurrency":"USDT",
1711
+ // "stop":"",
1712
+ // "type":"limit",
1713
+ // "createdAt":1547026472000
1714
+ // }
1715
+ //
1716
+ // fetchMyTrades v2 alternative format since 2019-05-21 https://github.com/ccxt/ccxt/pull/5162
1717
+ //
1718
+ // {
1719
+ // symbol: "OPEN-BTC",
1720
+ // forceTaker: false,
1721
+ // orderId: "5ce36420054b4663b1fff2c9",
1722
+ // fee: "0",
1723
+ // feeCurrency: "",
1724
+ // type: "",
1725
+ // feeRate: "0",
1726
+ // createdAt: 1558417615000,
1727
+ // size: "12.8206",
1728
+ // stop: "",
1729
+ // price: "0",
1730
+ // funds: "0",
1731
+ // tradeId: "5ce390cf6e0db23b861c6e80"
1732
+ // }
1733
+ //
1734
+ // fetchMyTrades (private) v1 (historical)
1735
+ //
1736
+ // {
1737
+ // "symbol": "SNOV-ETH",
1738
+ // "dealPrice": "0.0000246",
1739
+ // "dealValue": "0.018942",
1740
+ // "amount": "770",
1741
+ // "fee": "0.00001137",
1742
+ // "side": "sell",
1743
+ // "createdAt": 1540080199
1744
+ // "id":"5c4d389e4c8c60413f78e2e5",
1745
+ // }
1746
+ //
1747
+ const marketId = this.safeString (trade, 'symbol');
1748
+ market = this.safeMarket (marketId, market, '-');
1749
+ const id = this.safeString2 (trade, 'tradeId', 'id');
1750
+ const orderId = this.safeString (trade, 'orderId');
1751
+ const takerOrMaker = this.safeString (trade, 'liquidity');
1752
+ let timestamp = this.safeInteger (trade, 'time');
1753
+ if (timestamp !== undefined) {
1754
+ timestamp = parseInt (timestamp / 1000000);
1755
+ } else {
1756
+ timestamp = this.safeInteger (trade, 'createdAt');
1757
+ // if it's a historical v1 trade, the exchange returns timestamp in seconds
1758
+ if (('dealValue' in trade) && (timestamp !== undefined)) {
1759
+ timestamp = timestamp * 1000;
1760
+ }
1761
+ }
1762
+ const priceString = this.safeString2 (trade, 'price', 'dealPrice');
1763
+ const amountString = this.safeString2 (trade, 'size', 'amount');
1764
+ const side = this.safeString (trade, 'side');
1765
+ let fee = undefined;
1766
+ const feeCostString = this.safeString (trade, 'fee');
1767
+ if (feeCostString !== undefined) {
1768
+ const feeCurrencyId = this.safeString (trade, 'feeCurrency');
1769
+ let feeCurrency = this.safeCurrencyCode (feeCurrencyId);
1770
+ if (feeCurrency === undefined) {
1771
+ feeCurrency = (side === 'sell') ? market['quote'] : market['base'];
1772
+ }
1773
+ fee = {
1774
+ 'cost': feeCostString,
1775
+ 'currency': feeCurrency,
1776
+ 'rate': this.safeString (trade, 'feeRate'),
1777
+ };
1778
+ }
1779
+ let type = this.safeString (trade, 'type');
1780
+ if (type === 'match') {
1781
+ type = undefined;
1782
+ }
1783
+ const costString = this.safeString2 (trade, 'funds', 'dealValue');
1784
+ return this.safeTrade ({
1785
+ 'info': trade,
1786
+ 'id': id,
1787
+ 'order': orderId,
1788
+ 'timestamp': timestamp,
1789
+ 'datetime': this.iso8601 (timestamp),
1790
+ 'symbol': market['symbol'],
1791
+ 'type': type,
1792
+ 'takerOrMaker': takerOrMaker,
1793
+ 'side': side,
1794
+ 'price': priceString,
1795
+ 'amount': amountString,
1796
+ 'cost': costString,
1797
+ 'fee': fee,
1798
+ }, market);
1799
+ }
1800
+
1801
+ async fetchTradingFee (symbol, params = {}) {
1802
+ await this.loadMarkets ();
1803
+ const market = this.market (symbol);
1804
+ const request = {
1805
+ 'symbols': market['id'],
1806
+ };
1807
+ const response = await this.privateGetTradeFees (this.extend (request, params));
1808
+ //
1809
+ // {
1810
+ // code: '200000',
1811
+ // data: [
1812
+ // {
1813
+ // symbol: 'BTC-USDT',
1814
+ // takerFeeRate: '0.001',
1815
+ // makerFeeRate: '0.001'
1816
+ // }
1817
+ // ]
1818
+ // }
1819
+ //
1820
+ const data = this.safeValue (response, 'data', []);
1821
+ const first = this.safeValue (data, 0);
1822
+ const marketId = this.safeString (first, 'symbol');
1823
+ return {
1824
+ 'info': response,
1825
+ 'symbol': this.safeSymbol (marketId, market),
1826
+ 'maker': this.safeNumber (first, 'makerFeeRate'),
1827
+ 'taker': this.safeNumber (first, 'takerFeeRate'),
1828
+ 'percentage': true,
1829
+ 'tierBased': true,
1830
+ };
1831
+ }
1832
+
1833
+ async withdraw (code, amount, address, tag = undefined, params = {}) {
1834
+ [ tag, params ] = this.handleWithdrawTagAndParams (tag, params);
1835
+ await this.loadMarkets ();
1836
+ this.checkAddress (address);
1837
+ const currency = this.currency (code);
1838
+ const request = {
1839
+ 'currency': currency['id'],
1840
+ 'address': address,
1841
+ 'amount': amount,
1842
+ // 'memo': tag,
1843
+ // 'isInner': false, // internal transfer or external withdrawal
1844
+ // 'remark': 'optional',
1845
+ // 'chain': 'OMNI', // 'ERC20', 'TRC20', default is ERC20
1846
+ };
1847
+ if (tag !== undefined) {
1848
+ request['memo'] = tag;
1849
+ }
1850
+ const networks = this.safeValue (this.options, 'networks', {});
1851
+ let network = this.safeStringUpper (params, 'network'); // this line allows the user to specify either ERC20 or ETH
1852
+ network = this.safeStringLower (networks, network, network); // handle ERC20>ETH alias
1853
+ if (network !== undefined) {
1854
+ request['chain'] = network;
1855
+ params = this.omit (params, 'network');
1856
+ }
1857
+ const response = await this.privatePostWithdrawals (this.extend (request, params));
1858
+ //
1859
+ // https://github.com/ccxt/ccxt/issues/5558
1860
+ //
1861
+ // {
1862
+ // "code": 200000,
1863
+ // "data": {
1864
+ // "withdrawalId": "5bffb63303aa675e8bbe18f9"
1865
+ // }
1866
+ // }
1867
+ //
1868
+ const data = this.safeValue (response, 'data', {});
1869
+ return this.parseTransaction (data, currency);
1870
+ }
1871
+
1872
+ parseTransactionStatus (status) {
1873
+ const statuses = {
1874
+ 'SUCCESS': 'ok',
1875
+ 'PROCESSING': 'ok',
1876
+ 'FAILURE': 'failed',
1877
+ };
1878
+ return this.safeString (statuses, status);
1879
+ }
1880
+
1881
+ parseTransaction (transaction, currency = undefined) {
1882
+ //
1883
+ // fetchDeposits
1884
+ //
1885
+ // {
1886
+ // "address": "0x5f047b29041bcfdbf0e4478cdfa753a336ba6989",
1887
+ // "memo": "5c247c8a03aa677cea2a251d",
1888
+ // "amount": 1,
1889
+ // "fee": 0.0001,
1890
+ // "currency": "KCS",
1891
+ // "isInner": false,
1892
+ // "walletTxId": "5bbb57386d99522d9f954c5a@test004",
1893
+ // "status": "SUCCESS",
1894
+ // "createdAt": 1544178843000,
1895
+ // "updatedAt": 1544178891000
1896
+ // "remark":"foobar"
1897
+ // }
1898
+ //
1899
+ // fetchWithdrawals
1900
+ //
1901
+ // {
1902
+ // "id": "5c2dc64e03aa675aa263f1ac",
1903
+ // "address": "0x5bedb060b8eb8d823e2414d82acce78d38be7fe9",
1904
+ // "memo": "",
1905
+ // "currency": "ETH",
1906
+ // "amount": 1.0000000,
1907
+ // "fee": 0.0100000,
1908
+ // "walletTxId": "3e2414d82acce78d38be7fe9",
1909
+ // "isInner": false,
1910
+ // "status": "FAILURE",
1911
+ // "createdAt": 1546503758000,
1912
+ // "updatedAt": 1546504603000
1913
+ // "remark":"foobar"
1914
+ // }
1915
+ //
1916
+ // withdraw
1917
+ //
1918
+ // {
1919
+ // "withdrawalId": "5bffb63303aa675e8bbe18f9"
1920
+ // }
1921
+ //
1922
+ const currencyId = this.safeString (transaction, 'currency');
1923
+ const code = this.safeCurrencyCode (currencyId, currency);
1924
+ let address = this.safeString (transaction, 'address');
1925
+ const amount = this.safeNumber (transaction, 'amount');
1926
+ let txid = this.safeString (transaction, 'walletTxId');
1927
+ if (txid !== undefined) {
1928
+ const txidParts = txid.split ('@');
1929
+ const numTxidParts = txidParts.length;
1930
+ if (numTxidParts > 1) {
1931
+ if (address === undefined) {
1932
+ if (txidParts[1].length > 1) {
1933
+ address = txidParts[1];
1934
+ }
1935
+ }
1936
+ }
1937
+ txid = txidParts[0];
1938
+ }
1939
+ let type = (txid === undefined) ? 'withdrawal' : 'deposit';
1940
+ const rawStatus = this.safeString (transaction, 'status');
1941
+ const status = this.parseTransactionStatus (rawStatus);
1942
+ let fee = undefined;
1943
+ const feeCost = this.safeNumber (transaction, 'fee');
1944
+ if (feeCost !== undefined) {
1945
+ let rate = undefined;
1946
+ if (amount !== undefined) {
1947
+ rate = feeCost / amount;
1948
+ }
1949
+ fee = {
1950
+ 'cost': feeCost,
1951
+ 'rate': rate,
1952
+ 'currency': code,
1953
+ };
1954
+ }
1955
+ const tag = this.safeString (transaction, 'memo');
1956
+ let timestamp = this.safeInteger2 (transaction, 'createdAt', 'createAt');
1957
+ const id = this.safeString2 (transaction, 'id', 'withdrawalId');
1958
+ let updated = this.safeInteger (transaction, 'updatedAt');
1959
+ const isV1 = !('createdAt' in transaction);
1960
+ // if it's a v1 structure
1961
+ if (isV1) {
1962
+ type = ('address' in transaction) ? 'withdrawal' : 'deposit';
1963
+ if (timestamp !== undefined) {
1964
+ timestamp = timestamp * 1000;
1965
+ }
1966
+ if (updated !== undefined) {
1967
+ updated = updated * 1000;
1968
+ }
1969
+ }
1970
+ const comment = this.safeString (transaction, 'remark');
1971
+ return {
1972
+ 'id': id,
1973
+ 'info': transaction,
1974
+ 'timestamp': timestamp,
1975
+ 'datetime': this.iso8601 (timestamp),
1976
+ 'network': undefined,
1977
+ 'address': address,
1978
+ 'addressTo': address,
1979
+ 'addressFrom': undefined,
1980
+ 'tag': tag,
1981
+ 'tagTo': tag,
1982
+ 'tagFrom': undefined,
1983
+ 'currency': code,
1984
+ 'amount': amount,
1985
+ 'txid': txid,
1986
+ 'type': type,
1987
+ 'status': status,
1988
+ 'comment': comment,
1989
+ 'fee': fee,
1990
+ 'updated': updated,
1991
+ };
1992
+ }
1993
+
1994
+ async fetchDeposits (code = undefined, since = undefined, limit = undefined, params = {}) {
1995
+ await this.loadMarkets ();
1996
+ const request = {};
1997
+ let currency = undefined;
1998
+ if (code !== undefined) {
1999
+ currency = this.currency (code);
2000
+ request['currency'] = currency['id'];
2001
+ }
2002
+ if (limit !== undefined) {
2003
+ request['pageSize'] = limit;
2004
+ }
2005
+ let method = 'privateGetDeposits';
2006
+ if (since !== undefined) {
2007
+ // if since is earlier than 2019-02-18T00:00:00Z
2008
+ if (since < 1550448000000) {
2009
+ request['startAt'] = parseInt (since / 1000);
2010
+ method = 'privateGetHistDeposits';
2011
+ } else {
2012
+ request['startAt'] = since;
2013
+ }
2014
+ }
2015
+ const response = await this[method] (this.extend (request, params));
2016
+ //
2017
+ // {
2018
+ // code: '200000',
2019
+ // data: {
2020
+ // "currentPage": 1,
2021
+ // "pageSize": 5,
2022
+ // "totalNum": 2,
2023
+ // "totalPage": 1,
2024
+ // "items": [
2025
+ // //--------------------------------------------------
2026
+ // // version 2 deposit response structure
2027
+ // {
2028
+ // "address": "0x5f047b29041bcfdbf0e4478cdfa753a336ba6989",
2029
+ // "memo": "5c247c8a03aa677cea2a251d",
2030
+ // "amount": 1,
2031
+ // "fee": 0.0001,
2032
+ // "currency": "KCS",
2033
+ // "isInner": false,
2034
+ // "walletTxId": "5bbb57386d99522d9f954c5a@test004",
2035
+ // "status": "SUCCESS",
2036
+ // "createdAt": 1544178843000,
2037
+ // "updatedAt": 1544178891000
2038
+ // "remark":"foobar"
2039
+ // },
2040
+ // //--------------------------------------------------
2041
+ // // version 1 (historical) deposit response structure
2042
+ // {
2043
+ // "currency": "BTC",
2044
+ // "createAt": 1528536998,
2045
+ // "amount": "0.03266638",
2046
+ // "walletTxId": "55c643bc2c68d6f17266383ac1be9e454038864b929ae7cee0bc408cc5c869e8@12ffGWmMMD1zA1WbFm7Ho3JZ1w6NYXjpFk@234",
2047
+ // "isInner": false,
2048
+ // "status": "SUCCESS",
2049
+ // }
2050
+ // ]
2051
+ // }
2052
+ // }
2053
+ //
2054
+ const responseData = response['data']['items'];
2055
+ return this.parseTransactions (responseData, currency, since, limit, { 'type': 'deposit' });
2056
+ }
2057
+
2058
+ async fetchWithdrawals (code = undefined, since = undefined, limit = undefined, params = {}) {
2059
+ await this.loadMarkets ();
2060
+ const request = {};
2061
+ let currency = undefined;
2062
+ if (code !== undefined) {
2063
+ currency = this.currency (code);
2064
+ request['currency'] = currency['id'];
2065
+ }
2066
+ if (limit !== undefined) {
2067
+ request['pageSize'] = limit;
2068
+ }
2069
+ let method = 'privateGetWithdrawals';
2070
+ if (since !== undefined) {
2071
+ // if since is earlier than 2019-02-18T00:00:00Z
2072
+ if (since < 1550448000000) {
2073
+ request['startAt'] = parseInt (since / 1000);
2074
+ method = 'privateGetHistWithdrawals';
2075
+ } else {
2076
+ request['startAt'] = since;
2077
+ }
2078
+ }
2079
+ const response = await this[method] (this.extend (request, params));
2080
+ //
2081
+ // {
2082
+ // code: '200000',
2083
+ // data: {
2084
+ // "currentPage": 1,
2085
+ // "pageSize": 5,
2086
+ // "totalNum": 2,
2087
+ // "totalPage": 1,
2088
+ // "items": [
2089
+ // //--------------------------------------------------
2090
+ // // version 2 withdrawal response structure
2091
+ // {
2092
+ // "id": "5c2dc64e03aa675aa263f1ac",
2093
+ // "address": "0x5bedb060b8eb8d823e2414d82acce78d38be7fe9",
2094
+ // "memo": "",
2095
+ // "currency": "ETH",
2096
+ // "amount": 1.0000000,
2097
+ // "fee": 0.0100000,
2098
+ // "walletTxId": "3e2414d82acce78d38be7fe9",
2099
+ // "isInner": false,
2100
+ // "status": "FAILURE",
2101
+ // "createdAt": 1546503758000,
2102
+ // "updatedAt": 1546504603000
2103
+ // },
2104
+ // //--------------------------------------------------
2105
+ // // version 1 (historical) withdrawal response structure
2106
+ // {
2107
+ // "currency": "BTC",
2108
+ // "createAt": 1526723468,
2109
+ // "amount": "0.534",
2110
+ // "address": "33xW37ZSW4tQvg443Pc7NLCAs167Yc2XUV",
2111
+ // "walletTxId": "aeacea864c020acf58e51606169240e96774838dcd4f7ce48acf38e3651323f4",
2112
+ // "isInner": false,
2113
+ // "status": "SUCCESS"
2114
+ // }
2115
+ // ]
2116
+ // }
2117
+ // }
2118
+ //
2119
+ const responseData = response['data']['items'];
2120
+ return this.parseTransactions (responseData, currency, since, limit, { 'type': 'withdrawal' });
2121
+ }
2122
+
2123
+ async fetchBalance (params = {}) {
2124
+ await this.loadMarkets ();
2125
+ const defaultType = this.safeString2 (this.options, 'fetchBalance', 'defaultType', 'spot');
2126
+ const requestedType = this.safeString (params, 'type', defaultType);
2127
+ const accountsByType = this.safeValue (this.options, 'accountsByType');
2128
+ const type = this.safeString (accountsByType, requestedType, requestedType);
2129
+ params = this.omit (params, 'type');
2130
+ const request = {
2131
+ 'type': type,
2132
+ };
2133
+ const response = await this.privateGetAccounts (this.extend (request, params));
2134
+ //
2135
+ // {
2136
+ // "code":"200000",
2137
+ // "data":[
2138
+ // {"balance":"0.00009788","available":"0.00009788","holds":"0","currency":"BTC","id":"5c6a4fd399a1d81c4f9cc4d0","type":"trade"},
2139
+ // {"balance":"3.41060034","available":"3.41060034","holds":"0","currency":"SOUL","id":"5c6a4d5d99a1d8182d37046d","type":"trade"},
2140
+ // {"balance":"0.01562641","available":"0.01562641","holds":"0","currency":"NEO","id":"5c6a4f1199a1d8165a99edb1","type":"trade"},
2141
+ // ]
2142
+ // }
2143
+ //
2144
+ const data = this.safeValue (response, 'data', []);
2145
+ const result = {
2146
+ 'info': response,
2147
+ 'timestamp': undefined,
2148
+ 'datetime': undefined,
2149
+ };
2150
+ for (let i = 0; i < data.length; i++) {
2151
+ const balance = data[i];
2152
+ const balanceType = this.safeString (balance, 'type');
2153
+ if (balanceType === type) {
2154
+ const currencyId = this.safeString (balance, 'currency');
2155
+ const code = this.safeCurrencyCode (currencyId);
2156
+ const account = this.account ();
2157
+ account['total'] = this.safeString (balance, 'balance');
2158
+ account['free'] = this.safeString (balance, 'available');
2159
+ account['used'] = this.safeString (balance, 'holds');
2160
+ result[code] = account;
2161
+ }
2162
+ }
2163
+ return this.safeBalance (result);
2164
+ }
2165
+
2166
+ async transfer (code, amount, fromAccount, toAccount, params = {}) {
2167
+ await this.loadMarkets ();
2168
+ const currency = this.currency (code);
2169
+ const requestedAmount = this.currencyToPrecision (code, amount);
2170
+ const accountsById = this.safeValue (this.options, 'accountsByType', {});
2171
+ const fromId = this.safeString (accountsById, fromAccount, fromAccount);
2172
+ const toId = this.safeString (accountsById, toAccount, toAccount);
2173
+ if (fromId === 'contract') {
2174
+ if (toId !== 'main') {
2175
+ throw new ExchangeError (this.id + ' transfer() only supports transferring from futures account to main account');
2176
+ }
2177
+ const request = {
2178
+ 'currency': currency['id'],
2179
+ 'amount': requestedAmount,
2180
+ };
2181
+ if (!('bizNo' in params)) {
2182
+ // it doesn't like more than 24 characters
2183
+ request['bizNo'] = this.uuid22 ();
2184
+ }
2185
+ const response = await this.futuresPrivatePostTransferOut (this.extend (request, params));
2186
+ //
2187
+ // {
2188
+ // 'code': '200000',
2189
+ // 'data': {
2190
+ // 'applyId': '605a87217dff1500063d485d',
2191
+ // 'bizNo': 'bcd6e5e1291f4905af84dc',
2192
+ // 'payAccountType': 'CONTRACT',
2193
+ // 'payTag': 'DEFAULT',
2194
+ // 'remark': '',
2195
+ // 'recAccountType': 'MAIN',
2196
+ // 'recTag': 'DEFAULT',
2197
+ // 'recRemark': '',
2198
+ // 'recSystem': 'KUCOIN',
2199
+ // 'status': 'PROCESSING',
2200
+ // 'currency': 'XBT',
2201
+ // 'amount': '0.00001',
2202
+ // 'fee': '0',
2203
+ // 'sn': '573688685663948',
2204
+ // 'reason': '',
2205
+ // 'createdAt': 1616545569000,
2206
+ // 'updatedAt': 1616545569000
2207
+ // }
2208
+ // }
2209
+ //
2210
+ const data = this.safeValue (response, 'data');
2211
+ return this.parseTransfer (data, currency);
2212
+ } else {
2213
+ const request = {
2214
+ 'currency': currency['id'],
2215
+ 'from': fromId,
2216
+ 'to': toId,
2217
+ 'amount': requestedAmount,
2218
+ };
2219
+ if (!('clientOid' in params)) {
2220
+ request['clientOid'] = this.uuid ();
2221
+ }
2222
+ const response = await this.privatePostAccountsInnerTransfer (this.extend (request, params));
2223
+ //
2224
+ // {
2225
+ // 'code': '200000',
2226
+ // 'data': {
2227
+ // 'orderId': '605a6211e657f00006ad0ad6'
2228
+ // }
2229
+ // }
2230
+ //
2231
+ const data = this.safeValue (response, 'data');
2232
+ return this.parseTransfer (data, currency);
2233
+ }
2234
+ }
2235
+
2236
+ parseTransfer (transfer, currency = undefined) {
2237
+ //
2238
+ // transfer (spot)
2239
+ //
2240
+ // {
2241
+ // 'orderId': '605a6211e657f00006ad0ad6'
2242
+ // }
2243
+ //
2244
+ //
2245
+ // transfer (futures)
2246
+ //
2247
+ // {
2248
+ // 'applyId': '605a87217dff1500063d485d',
2249
+ // 'bizNo': 'bcd6e5e1291f4905af84dc',
2250
+ // 'payAccountType': 'CONTRACT',
2251
+ // 'payTag': 'DEFAULT',
2252
+ // 'remark': '',
2253
+ // 'recAccountType': 'MAIN',
2254
+ // 'recTag': 'DEFAULT',
2255
+ // 'recRemark': '',
2256
+ // 'recSystem': 'KUCOIN',
2257
+ // 'status': 'PROCESSING',
2258
+ // 'currency': 'XBT',
2259
+ // 'amount': '0.00001',
2260
+ // 'fee': '0',
2261
+ // 'sn': '573688685663948',
2262
+ // 'reason': '',
2263
+ // 'createdAt': 1616545569000,
2264
+ // 'updatedAt': 1616545569000
2265
+ // }
2266
+ //
2267
+ const timestamp = this.safeInteger (transfer, 'createdAt');
2268
+ const currencyId = this.safeString (transfer, 'currency');
2269
+ const rawStatus = this.safeString (transfer, 'status');
2270
+ const accountFromRaw = this.safeString (transfer, 'payAccountType');
2271
+ const accountToRaw = this.safeString (transfer, 'recAccountType');
2272
+ const accountsByType = this.safeValue (this.options, 'accountsByType');
2273
+ const accountFrom = this.safeString (accountsByType, accountFromRaw.toLowerCase ());
2274
+ const accountTo = this.safeString (accountsByType, accountToRaw.toLowerCase ());
2275
+ return {
2276
+ 'id': this.safeString2 (transfer, 'applyId', 'orderId'),
2277
+ 'currency': this.safeCurrencyCode (currencyId, currency),
2278
+ 'timestamp': timestamp,
2279
+ 'datetime': this.iso8601 (timestamp),
2280
+ 'amount': this.safeNumber (transfer, 'amount'),
2281
+ 'fromAccount': accountFrom,
2282
+ 'toAccount': accountTo,
2283
+ 'status': this.parseTransferStatus (rawStatus),
2284
+ 'info': transfer,
2285
+ };
2286
+ }
2287
+
2288
+ parseTransferStatus (status) {
2289
+ const statuses = {
2290
+ 'PROCESSING': 'pending',
2291
+ };
2292
+ return this.safeString (statuses, status, status);
2293
+ }
2294
+
2295
+ parseLedgerEntryType (type) {
2296
+ const types = {
2297
+ 'Assets Transferred in After Upgrading': 'transfer', // Assets Transferred in After V1 to V2 Upgrading
2298
+ 'Deposit': 'transaction', // Deposit
2299
+ 'Withdrawal': 'transaction', // Withdrawal
2300
+ 'Transfer': 'transfer', // Transfer
2301
+ 'Trade_Exchange': 'trade', // Trade
2302
+ // 'Vote for Coin': 'Vote for Coin', // Vote for Coin
2303
+ 'KuCoin Bonus': 'bonus', // KuCoin Bonus
2304
+ 'Referral Bonus': 'referral', // Referral Bonus
2305
+ 'Rewards': 'bonus', // Activities Rewards
2306
+ // 'Distribution': 'Distribution', // Distribution, such as get GAS by holding NEO
2307
+ 'Airdrop/Fork': 'airdrop', // Airdrop/Fork
2308
+ 'Other rewards': 'bonus', // Other rewards, except Vote, Airdrop, Fork
2309
+ 'Fee Rebate': 'rebate', // Fee Rebate
2310
+ 'Buy Crypto': 'trade', // Use credit card to buy crypto
2311
+ 'Sell Crypto': 'sell', // Use credit card to sell crypto
2312
+ 'Public Offering Purchase': 'trade', // Public Offering Purchase for Spotlight
2313
+ // 'Send red envelope': 'Send red envelope', // Send red envelope
2314
+ // 'Open red envelope': 'Open red envelope', // Open red envelope
2315
+ // 'Staking': 'Staking', // Staking
2316
+ // 'LockDrop Vesting': 'LockDrop Vesting', // LockDrop Vesting
2317
+ // 'Staking Profits': 'Staking Profits', // Staking Profits
2318
+ // 'Redemption': 'Redemption', // Redemption
2319
+ 'Refunded Fees': 'fee', // Refunded Fees
2320
+ 'KCS Pay Fees': 'fee', // KCS Pay Fees
2321
+ 'Margin Trade': 'trade', // Margin Trade
2322
+ 'Loans': 'Loans', // Loans
2323
+ // 'Borrowings': 'Borrowings', // Borrowings
2324
+ // 'Debt Repayment': 'Debt Repayment', // Debt Repayment
2325
+ // 'Loans Repaid': 'Loans Repaid', // Loans Repaid
2326
+ // 'Lendings': 'Lendings', // Lendings
2327
+ // 'Pool transactions': 'Pool transactions', // Pool-X transactions
2328
+ 'Instant Exchange': 'trade', // Instant Exchange
2329
+ 'Sub-account transfer': 'transfer', // Sub-account transfer
2330
+ 'Liquidation Fees': 'fee', // Liquidation Fees
2331
+ // 'Soft Staking Profits': 'Soft Staking Profits', // Soft Staking Profits
2332
+ // 'Voting Earnings': 'Voting Earnings', // Voting Earnings on Pool-X
2333
+ // 'Redemption of Voting': 'Redemption of Voting', // Redemption of Voting on Pool-X
2334
+ // 'Voting': 'Voting', // Voting on Pool-X
2335
+ // 'Convert to KCS': 'Convert to KCS', // Convert to KCS
2336
+ };
2337
+ return this.safeString (types, type, type);
2338
+ }
2339
+
2340
+ parseLedgerEntry (item, currency = undefined) {
2341
+ //
2342
+ // {
2343
+ // "id": "611a1e7c6a053300067a88d9", //unique key for each ledger entry
2344
+ // "currency": "USDT", //Currency
2345
+ // "amount": "10.00059547", //The total amount of assets (fees included) involved in assets changes such as transaction, withdrawal and bonus distribution.
2346
+ // "fee": "0", //Deposit or withdrawal fee
2347
+ // "balance": "0", //Total assets of a currency remaining funds after transaction
2348
+ // "accountType": "MAIN", //Account Type
2349
+ // "bizType": "Loans Repaid", //business type
2350
+ // "direction": "in", //side, in or out
2351
+ // "createdAt": 1629101692950, //Creation time
2352
+ // "context": "{\"borrowerUserId\":\"601ad03e50dc810006d242ea\",\"loanRepayDetailNo\":\"611a1e7cc913d000066cf7ec\"}" //Business core parameters
2353
+ // }
2354
+ //
2355
+ const id = this.safeString (item, 'id');
2356
+ const currencyId = this.safeString (item, 'currency');
2357
+ const code = this.safeCurrencyCode (currencyId, currency);
2358
+ const amount = this.safeNumber (item, 'amount');
2359
+ const balanceAfter = undefined;
2360
+ // const balanceAfter = this.safeNumber (item, 'balance'); only returns zero string
2361
+ const bizType = this.safeString (item, 'bizType');
2362
+ const type = this.parseLedgerEntryType (bizType);
2363
+ const direction = this.safeString (item, 'direction');
2364
+ const timestamp = this.safeInteger (item, 'createdAt');
2365
+ const datetime = this.iso8601 (timestamp);
2366
+ const account = this.safeString (item, 'accountType'); // MAIN, TRADE, MARGIN, or CONTRACT
2367
+ const context = this.safeString (item, 'context'); // contains other information about the ledger entry
2368
+ //
2369
+ // withdrawal transaction
2370
+ //
2371
+ // "{\"orderId\":\"617bb2d09e7b3b000196dac8\",\"txId\":\"0x79bb9855f86b351a45cab4dc69d78ca09586a94c45dde49475722b98f401b054\"}"
2372
+ //
2373
+ // deposit to MAIN, trade via MAIN
2374
+ //
2375
+ // "{\"orderId\":\"617ab9949e7b3b0001948081\",\"txId\":\"0x7a06b16bbd6b03dbc3d96df5683b15229fc35e7184fd7179a5f3a310bd67d1fa@default@0\"}"
2376
+ //
2377
+ // sell trade
2378
+ //
2379
+ // "{\"symbol\":\"ETH-USDT\",\"orderId\":\"617adcd1eb3fa20001dd29a1\",\"tradeId\":\"617adcd12e113d2b91222ff9\"}"
2380
+ //
2381
+ let referenceId = undefined;
2382
+ if (context !== undefined && context !== '') {
2383
+ const parsed = JSON.parse (context);
2384
+ const orderId = this.safeString (parsed, 'orderId');
2385
+ const tradeId = this.safeString (parsed, 'tradeId');
2386
+ // transactions only have an orderId but for trades we wish to use tradeId
2387
+ if (tradeId !== undefined) {
2388
+ referenceId = tradeId;
2389
+ } else {
2390
+ referenceId = orderId;
2391
+ }
2392
+ }
2393
+ let fee = undefined;
2394
+ const feeCost = this.safeNumber (item, 'fee');
2395
+ let feeCurrency = undefined;
2396
+ if (feeCost !== 0) {
2397
+ feeCurrency = code;
2398
+ fee = { 'cost': feeCost, 'currency': feeCurrency };
2399
+ }
2400
+ return {
2401
+ 'id': id,
2402
+ 'direction': direction,
2403
+ 'account': account,
2404
+ 'referenceId': referenceId,
2405
+ 'referenceAccount': account,
2406
+ 'type': type,
2407
+ 'currency': code,
2408
+ 'amount': amount,
2409
+ 'timestamp': timestamp,
2410
+ 'datetime': datetime,
2411
+ 'before': undefined,
2412
+ 'after': balanceAfter, // undefined
2413
+ 'status': undefined,
2414
+ 'fee': fee,
2415
+ 'info': item,
2416
+ };
2417
+ }
2418
+
2419
+ async fetchLedger (code = undefined, since = undefined, limit = undefined, params = {}) {
2420
+ await this.loadMarkets ();
2421
+ await this.loadAccounts ();
2422
+ const request = {
2423
+ // 'currency': currency['id'], // can choose up to 10, if not provided returns for all currencies by default
2424
+ // 'direction': 'in', // 'out'
2425
+ // 'bizType': 'DEPOSIT', // DEPOSIT, WITHDRAW, TRANSFER, SUB_TRANSFER,TRADE_EXCHANGE, MARGIN_EXCHANGE, KUCOIN_BONUS (optional)
2426
+ // 'startAt': since,
2427
+ // 'endAt': exchange.milliseconds (),
2428
+ };
2429
+ if (since !== undefined) {
2430
+ request['startAt'] = since;
2431
+ }
2432
+ // atm only single currency retrieval is supported
2433
+ let currency = undefined;
2434
+ if (code !== undefined) {
2435
+ currency = this.currency (code);
2436
+ request['currency'] = currency['id'];
2437
+ }
2438
+ const response = await this.privateGetAccountsLedgers (this.extend (request, params));
2439
+ //
2440
+ // {
2441
+ // "code":"200000",
2442
+ // "data":{
2443
+ // "currentPage":1,
2444
+ // "pageSize":50,
2445
+ // "totalNum":1,
2446
+ // "totalPage":1,
2447
+ // "items":[
2448
+ // {
2449
+ // "id":"617cc528729f5f0001c03ceb",
2450
+ // "currency":"GAS",
2451
+ // "amount":"0.00000339",
2452
+ // "fee":"0",
2453
+ // "balance":"0",
2454
+ // "accountType":"MAIN",
2455
+ // "bizType":"Distribution",
2456
+ // "direction":"in",
2457
+ // "createdAt":1635566888183,
2458
+ // "context":"{\"orderId\":\"617cc47a1c47ed0001ce3606\",\"description\":\"Holding NEO,distribute GAS(2021/10/30)\"}"
2459
+ // }
2460
+ // {
2461
+ // "id": "611a1e7c6a053300067a88d9",//unique key
2462
+ // "currency": "USDT", //Currency
2463
+ // "amount": "10.00059547", //Change amount of the funds
2464
+ // "fee": "0", //Deposit or withdrawal fee
2465
+ // "balance": "0", //Total assets of a currency
2466
+ // "accountType": "MAIN", //Account Type
2467
+ // "bizType": "Loans Repaid", //business type
2468
+ // "direction": "in", //side, in or out
2469
+ // "createdAt": 1629101692950, //Creation time
2470
+ // "context": "{\"borrowerUserId\":\"601ad03e50dc810006d242ea\",\"loanRepayDetailNo\":\"611a1e7cc913d000066cf7ec\"}"
2471
+ // },
2472
+ // ]
2473
+ // }
2474
+ // }
2475
+ //
2476
+ const data = this.safeValue (response, 'data');
2477
+ const items = this.safeValue (data, 'items');
2478
+ return this.parseLedger (items, currency, since, limit);
2479
+ }
2480
+
2481
+ calculateRateLimiterCost (api, method, path, params, config = {}, context = {}) {
2482
+ const versions = this.safeValue (this.options, 'versions', {});
2483
+ const apiVersions = this.safeValue (versions, api, {});
2484
+ const methodVersions = this.safeValue (apiVersions, method, {});
2485
+ const defaultVersion = this.safeString (methodVersions, path, this.options['version']);
2486
+ const version = this.safeString (params, 'version', defaultVersion);
2487
+ if (version === 'v3' && ('v3' in config)) {
2488
+ return config['v3'];
2489
+ } else if (version === 'v2' && ('v2' in config)) {
2490
+ return config['v2'];
2491
+ } else if (version === 'v1' && ('v1' in config)) {
2492
+ return config['v1'];
2493
+ }
2494
+ return this.safeInteger (config, 'cost', 1);
2495
+ }
2496
+
2497
+ sign (path, api = 'public', method = 'GET', params = {}, headers = undefined, body = undefined) {
2498
+ //
2499
+ // the v2 URL is https://openapi-v2.kucoin.com/api/v1/endpoint
2500
+ // † ↑
2501
+ //
2502
+ const versions = this.safeValue (this.options, 'versions', {});
2503
+ const apiVersions = this.safeValue (versions, api, {});
2504
+ const methodVersions = this.safeValue (apiVersions, method, {});
2505
+ const defaultVersion = this.safeString (methodVersions, path, this.options['version']);
2506
+ const version = this.safeString (params, 'version', defaultVersion);
2507
+ params = this.omit (params, 'version');
2508
+ let endpoint = '/api/' + version + '/' + this.implodeParams (path, params);
2509
+ const query = this.omit (params, this.extractParams (path));
2510
+ let endpart = '';
2511
+ headers = (headers !== undefined) ? headers : {};
2512
+ if (Object.keys (query).length) {
2513
+ if ((method === 'GET') || (method === 'DELETE')) {
2514
+ endpoint += '?' + this.urlencode (query);
2515
+ } else {
2516
+ body = this.json (query);
2517
+ endpart = body;
2518
+ headers['Content-Type'] = 'application/json';
2519
+ }
2520
+ }
2521
+ const url = this.urls['api'][api] + endpoint;
2522
+ if ((api === 'private') || (api === 'futuresPrivate')) {
2523
+ this.checkRequiredCredentials ();
2524
+ const timestamp = this.nonce ().toString ();
2525
+ headers = this.extend ({
2526
+ 'KC-API-KEY-VERSION': '2',
2527
+ 'KC-API-KEY': this.apiKey,
2528
+ 'KC-API-TIMESTAMP': timestamp,
2529
+ }, headers);
2530
+ const apiKeyVersion = this.safeString (headers, 'KC-API-KEY-VERSION');
2531
+ if (apiKeyVersion === '2') {
2532
+ const passphrase = this.hmac (this.encode (this.password), this.encode (this.secret), 'sha256', 'base64');
2533
+ headers['KC-API-PASSPHRASE'] = passphrase;
2534
+ } else {
2535
+ headers['KC-API-PASSPHRASE'] = this.password;
2536
+ }
2537
+ const payload = timestamp + method + endpoint + endpart;
2538
+ const signature = this.hmac (this.encode (payload), this.encode (this.secret), 'sha256', 'base64');
2539
+ headers['KC-API-SIGN'] = signature;
2540
+ const partner = this.safeValue (this.options, 'partner', {});
2541
+ const partnerId = this.safeString (partner, 'id');
2542
+ const partnerSecret = this.safeString (partner, 'secret');
2543
+ if ((partnerId !== undefined) && (partnerSecret !== undefined)) {
2544
+ const partnerPayload = timestamp + partnerId + this.apiKey;
2545
+ const partnerSignature = this.hmac (this.encode (partnerPayload), this.encode (partnerSecret), 'sha256', 'base64');
2546
+ headers['KC-API-PARTNER-SIGN'] = partnerSignature;
2547
+ headers['KC-API-PARTNER'] = partnerId;
2548
+ }
2549
+ }
2550
+ return { 'url': url, 'method': method, 'body': body, 'headers': headers };
2551
+ }
2552
+
2553
+ handleErrors (code, reason, url, method, headers, body, response, requestHeaders, requestBody) {
2554
+ if (!response) {
2555
+ this.throwBroadlyMatchedException (this.exceptions['broad'], body, body);
2556
+ return;
2557
+ }
2558
+ //
2559
+ // bad
2560
+ // { "code": "400100", "msg": "validation.createOrder.clientOidIsRequired" }
2561
+ // good
2562
+ // { code: '200000', data: { ... }}
2563
+ //
2564
+ const errorCode = this.safeString (response, 'code');
2565
+ const message = this.safeString (response, 'msg', '');
2566
+ const feedback = this.id + ' ' + message;
2567
+ this.throwExactlyMatchedException (this.exceptions['exact'], message, feedback);
2568
+ this.throwExactlyMatchedException (this.exceptions['exact'], errorCode, feedback);
2569
+ this.throwBroadlyMatchedException (this.exceptions['broad'], body, feedback);
2570
+ }
2571
+ };