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/bitmart.js ADDED
@@ -0,0 +1,2516 @@
1
+ 'use strict';
2
+
3
+ // ---------------------------------------------------------------------------
4
+
5
+ const Exchange = require ('./base/Exchange');
6
+ const { AuthenticationError, ExchangeNotAvailable, AccountSuspended, PermissionDenied, RateLimitExceeded, InvalidNonce, InvalidAddress, ArgumentsRequired, ExchangeError, InvalidOrder, InsufficientFunds, BadRequest, OrderNotFound, BadSymbol, NotSupported } = require ('./base/errors');
7
+ const { TICK_SIZE, TRUNCATE } = require ('./base/functions/number');
8
+ const Precise = require ('./base/Precise');
9
+
10
+ // ---------------------------------------------------------------------------
11
+
12
+ module.exports = class bitmart extends Exchange {
13
+ describe () {
14
+ return this.deepExtend (super.describe (), {
15
+ 'id': 'bitmart',
16
+ 'name': 'BitMart',
17
+ 'countries': [ 'US', 'CN', 'HK', 'KR' ],
18
+ 'rateLimit': 250, // a bit slower than 50 times per second ~40 times per second
19
+ 'version': 'v1',
20
+ 'certified': true,
21
+ 'pro': true,
22
+ 'has': {
23
+ 'CORS': undefined,
24
+ 'spot': true,
25
+ 'margin': undefined, // has but unimplemented
26
+ 'swap': undefined, // has but unimplemented
27
+ 'future': undefined, // has but unimplemented
28
+ 'option': undefined,
29
+ 'cancelAllOrders': true,
30
+ 'cancelOrder': true,
31
+ 'cancelOrders': true,
32
+ 'createOrder': true,
33
+ 'fetchBalance': true,
34
+ 'fetchCanceledOrders': true,
35
+ 'fetchClosedOrders': true,
36
+ 'fetchCurrencies': true,
37
+ 'fetchDeposit': true,
38
+ 'fetchDepositAddress': true,
39
+ 'fetchDepositAddresses': false,
40
+ 'fetchDepositAddressesByNetwork': false,
41
+ 'fetchDeposits': true,
42
+ 'fetchFundingFee': true,
43
+ 'fetchFundingFees': false,
44
+ 'fetchFundingHistory': undefined,
45
+ 'fetchMarkets': true,
46
+ 'fetchMyTrades': true,
47
+ 'fetchOHLCV': true,
48
+ 'fetchOpenOrders': true,
49
+ 'fetchOrder': true,
50
+ 'fetchOrderBook': true,
51
+ 'fetchOrders': true,
52
+ 'fetchOrderTrades': true,
53
+ 'fetchStatus': true,
54
+ 'fetchTicker': true,
55
+ 'fetchTickers': true,
56
+ 'fetchTime': true,
57
+ 'fetchTrades': true,
58
+ 'fetchTradingFee': false,
59
+ 'fetchTradingFees': false,
60
+ 'fetchTransfer': false,
61
+ 'fetchTransfers': false,
62
+ 'fetchWithdrawAddressesByNetwork': false,
63
+ 'fetchWithdrawal': true,
64
+ 'fetchWithdrawals': true,
65
+ 'reduceMargin': false,
66
+ 'setLeverage': false,
67
+ 'setMarginMode': false,
68
+ 'transfer': false,
69
+ 'withdraw': true,
70
+ },
71
+ 'hostname': 'bitmart.com', // bitmart.info, bitmart.news for Hong Kong users
72
+ 'urls': {
73
+ 'logo': 'https://user-images.githubusercontent.com/1294454/129991357-8f47464b-d0f4-41d6-8a82-34122f0d1398.jpg',
74
+ 'api': {
75
+ 'rest': 'https://api-cloud.{hostname}', // bitmart.info for Hong Kong users
76
+ },
77
+ 'www': 'https://www.bitmart.com/',
78
+ 'doc': 'https://developer-pro.bitmart.com/',
79
+ 'referral': {
80
+ 'url': 'http://www.bitmart.com/?r=rQCFLh',
81
+ 'discount': 0.3,
82
+ },
83
+ 'fees': 'https://www.bitmart.com/fee/en',
84
+ },
85
+ 'requiredCredentials': {
86
+ 'apiKey': true,
87
+ 'secret': true,
88
+ 'uid': true,
89
+ },
90
+ 'api': {
91
+ 'public': {
92
+ 'system': {
93
+ 'get': {
94
+ 'time': 5, // https://api-cloud.bitmart.com/system/time
95
+ 'service': 5, // https://api-cloud.bitmart.com/system/service
96
+ },
97
+ },
98
+ 'account': {
99
+ 'get': {
100
+ 'currencies': 10, // https://api-cloud.bitmart.com/account/v1/currencies
101
+ },
102
+ },
103
+ 'spot': {
104
+ 'get': {
105
+ 'currencies': 1,
106
+ 'symbols': 1,
107
+ 'symbols/details': 1,
108
+ 'ticker': 1, // ?symbol=BTC_USDT
109
+ 'steps': 1, // ?symbol=BMX_ETH
110
+ 'symbols/kline': 1, // ?symbol=BMX_ETH&step=15&from=1525760116&to=1525769116
111
+ 'symbols/book': 1, // ?symbol=BMX_ETH&precision=6
112
+ 'symbols/trades': 1, // ?symbol=BMX_ETH
113
+ },
114
+ },
115
+ 'contract': {
116
+ 'get': {
117
+ 'tickers': 0.5,
118
+ },
119
+ },
120
+ },
121
+ 'private': {
122
+ 'account': {
123
+ 'get': {
124
+ 'wallet': 0.5, // ?account_type=1
125
+ 'deposit/address': 1, // ?currency=USDT-TRC20
126
+ 'withdraw/charge': 1, // ?currency=BTC
127
+ 'deposit-withdraw/history': 1, // ?limit=10&offset=1&operationType=withdraw
128
+ 'deposit-withdraw/detail': 1, // ?id=1679952
129
+ },
130
+ 'post': {
131
+ 'withdraw/apply': 1,
132
+ },
133
+ },
134
+ 'spot': {
135
+ 'get': {
136
+ 'wallet': 0.5,
137
+ 'order_detail': 0.1,
138
+ 'orders': 0.5,
139
+ 'trades': 0.5,
140
+ },
141
+ 'post': {
142
+ 'submit_order': 0.1, // https://api-cloud.bitmart.com/spot/v1/submit_order
143
+ 'cancel_order': 0.1, // https://api-cloud.bitmart.com/spot/v2/cancel_order
144
+ 'cancel_orders': 0.1,
145
+ },
146
+ },
147
+ },
148
+ },
149
+ 'timeframes': {
150
+ '1m': 1,
151
+ '3m': 3,
152
+ '5m': 5,
153
+ '15m': 15,
154
+ '30m': 30,
155
+ '45m': 45,
156
+ '1h': 60,
157
+ '2h': 120,
158
+ '3h': 180,
159
+ '4h': 240,
160
+ '1d': 1440,
161
+ '1w': 10080,
162
+ '1M': 43200,
163
+ },
164
+ 'fees': {
165
+ 'trading': {
166
+ 'tierBased': true,
167
+ 'percentage': true,
168
+ 'taker': this.parseNumber ('0.0025'),
169
+ 'maker': this.parseNumber ('0.0025'),
170
+ 'tiers': {
171
+ 'taker': [
172
+ [ this.parseNumber ('0'), this.parseNumber ('0.0020') ],
173
+ [ this.parseNumber ('10'), this.parseNumber ('0.18') ],
174
+ [ this.parseNumber ('50'), this.parseNumber ('0.0016') ],
175
+ [ this.parseNumber ('250'), this.parseNumber ('0.0014') ],
176
+ [ this.parseNumber ('1000'), this.parseNumber ('0.0012') ],
177
+ [ this.parseNumber ('5000'), this.parseNumber ('0.0010') ],
178
+ [ this.parseNumber ('25000'), this.parseNumber ('0.0008') ],
179
+ [ this.parseNumber ('50000'), this.parseNumber ('0.0006') ],
180
+ ],
181
+ 'maker': [
182
+ [ this.parseNumber ('0'), this.parseNumber ('0.001') ],
183
+ [ this.parseNumber ('10'), this.parseNumber ('0.0009') ],
184
+ [ this.parseNumber ('50'), this.parseNumber ('0.0008') ],
185
+ [ this.parseNumber ('250'), this.parseNumber ('0.0007') ],
186
+ [ this.parseNumber ('1000'), this.parseNumber ('0.0006') ],
187
+ [ this.parseNumber ('5000'), this.parseNumber ('0.0005') ],
188
+ [ this.parseNumber ('25000'), this.parseNumber ('0.0004') ],
189
+ [ this.parseNumber ('50000'), this.parseNumber ('0.0003') ],
190
+ ],
191
+ },
192
+ },
193
+ },
194
+ 'precisionMode': TICK_SIZE,
195
+ 'exceptions': {
196
+ 'exact': {
197
+ // general errors
198
+ '30000': ExchangeError, // 404, Not found
199
+ '30001': AuthenticationError, // 401, Header X-BM-KEY is empty
200
+ '30002': AuthenticationError, // 401, Header X-BM-KEY not found
201
+ '30003': AccountSuspended, // 401, Header X-BM-KEY has frozen
202
+ '30004': AuthenticationError, // 401, Header X-BM-SIGN is empty
203
+ '30005': AuthenticationError, // 401, Header X-BM-SIGN is wrong
204
+ '30006': AuthenticationError, // 401, Header X-BM-TIMESTAMP is empty
205
+ '30007': AuthenticationError, // 401, Header X-BM-TIMESTAMP range. Within a minute
206
+ '30008': AuthenticationError, // 401, Header X-BM-TIMESTAMP invalid format
207
+ '30010': PermissionDenied, // 403, IP is forbidden. We recommend enabling IP whitelist for API trading. After that reauth your account
208
+ '30011': AuthenticationError, // 403, Header X-BM-KEY over expire time
209
+ '30012': AuthenticationError, // 403, Header X-BM-KEY is forbidden to request it
210
+ '30013': RateLimitExceeded, // 429, Request too many requests
211
+ '30014': ExchangeNotAvailable, // 503, Service unavailable
212
+ // funding account errors
213
+ '60000': BadRequest, // 400, Invalid request (maybe the body is empty, or the int parameter passes string data)
214
+ '60001': BadRequest, // 400, Asset account type does not exist
215
+ '60002': BadRequest, // 400, currency does not exist
216
+ '60003': ExchangeError, // 400, Currency has been closed recharge channel, if there is any problem, please consult customer service
217
+ '60004': ExchangeError, // 400, Currency has been closed withdraw channel, if there is any problem, please consult customer service
218
+ '60005': ExchangeError, // 400, Minimum amount is %s
219
+ '60006': ExchangeError, // 400, Maximum withdraw precision is %d
220
+ '60007': InvalidAddress, // 400, Only withdrawals from added addresses are allowed
221
+ '60008': InsufficientFunds, // 400, Balance not enough
222
+ '60009': ExchangeError, // 400, Beyond the limit
223
+ '60010': ExchangeError, // 400, Withdraw id or deposit id not found
224
+ '60011': InvalidAddress, // 400, Address is not valid
225
+ '60012': ExchangeError, // 400, This action is not supported in this currency(If IOTA, HLX recharge and withdraw calls are prohibited)
226
+ '60020': PermissionDenied, // 403, Your account is not allowed to recharge
227
+ '60021': PermissionDenied, // 403, Your account is not allowed to withdraw
228
+ '60022': PermissionDenied, // 403, No withdrawals for 24 hours
229
+ '60030': BadRequest, // 405, Method Not Allowed
230
+ '60031': BadRequest, // 415, Unsupported Media Type
231
+ '60050': ExchangeError, // 500, User account not found
232
+ '60051': ExchangeError, // 500, Internal Server Error
233
+ // spot errors
234
+ '50000': BadRequest, // 400, Bad Request
235
+ '50001': BadSymbol, // 400, Symbol not found
236
+ '50002': BadRequest, // 400, From Or To format error
237
+ '50003': BadRequest, // 400, Step format error
238
+ '50004': BadRequest, // 400, Kline size over 500
239
+ '50005': OrderNotFound, // 400, Order Id not found
240
+ '50006': InvalidOrder, // 400, Minimum size is %s
241
+ '50007': InvalidOrder, // 400, Maximum size is %s
242
+ '50008': InvalidOrder, // 400, Minimum price is %s
243
+ '50009': InvalidOrder, // 400, Minimum count*price is %s
244
+ '50010': InvalidOrder, // 400, RequestParam size is required
245
+ '50011': InvalidOrder, // 400, RequestParam price is required
246
+ '50012': InvalidOrder, // 400, RequestParam notional is required
247
+ '50013': InvalidOrder, // 400, Maximum limit*offset is %d
248
+ '50014': BadRequest, // 400, RequestParam limit is required
249
+ '50015': BadRequest, // 400, Minimum limit is 1
250
+ '50016': BadRequest, // 400, Maximum limit is %d
251
+ '50017': BadRequest, // 400, RequestParam offset is required
252
+ '50018': BadRequest, // 400, Minimum offset is 1
253
+ '50019': BadRequest, // 400, Maximum price is %s
254
+ // '50019': ExchangeError, // 400, Invalid status. validate status is [1=Failed, 2=Success, 3=Frozen Failed, 4=Frozen Success, 5=Partially Filled, 6=Fully Fulled, 7=Canceling, 8=Canceled
255
+ '50020': InsufficientFunds, // 400, Balance not enough
256
+ '50021': BadRequest, // 400, Invalid %s
257
+ '50022': ExchangeNotAvailable, // 400, Service unavailable
258
+ '50023': BadSymbol, // 400, This Symbol can't place order by api
259
+ '50029': InvalidOrder, // {"message":"param not match : size * price >=1000","code":50029,"trace":"f931f030-b692-401b-a0c5-65edbeadc598","data":{}}
260
+ '50030': InvalidOrder, // {"message":"Order is already canceled","code":50030,"trace":"8d6f64ee-ad26-45a4-9efd-1080f9fca1fa","data":{}}
261
+ // below Error codes used interchangeably for both failed postOnly and IOC orders depending on market price and order side
262
+ '50035': InvalidOrder, // {"message":"The price is low and there is no matching depth","code":50035,"trace":"677f01c7-8b88-4346-b097-b4226c75c90e","data":{}}
263
+ '50034': InvalidOrder, // {"message":"The price is high and there is no matching depth","code":50034,"trace":"ebfae59a-ba69-4735-86b2-0ed7b9ca14ea","data":{}}
264
+ '53000': AccountSuspended, // 403, Your account is frozen due to security policies. Please contact customer service
265
+ '53001': AccountSuspended, // {"message":"Your kyc country is restricted. Please contact customer service.","code":53001,"trace":"8b445940-c123-4de9-86d7-73c5be2e7a24","data":{}}
266
+ '57001': BadRequest, // 405, Method Not Allowed
267
+ '58001': BadRequest, // 415, Unsupported Media Type
268
+ '59001': ExchangeError, // 500, User account not found
269
+ '59002': ExchangeError, // 500, Internal Server Error
270
+ // contract errors
271
+ '40001': ExchangeError, // 400, Cloud account not found
272
+ '40002': ExchangeError, // 400, out_trade_no not found
273
+ '40003': ExchangeError, // 400, out_trade_no already existed
274
+ '40004': ExchangeError, // 400, Cloud account count limit
275
+ '40005': ExchangeError, // 400, Transfer vol precision error
276
+ '40006': PermissionDenied, // 400, Invalid ip error
277
+ '40007': BadRequest, // 400, Parse parameter error
278
+ '40008': InvalidNonce, // 400, Check nonce error
279
+ '40009': BadRequest, // 400, Check ver error
280
+ '40010': BadRequest, // 400, Not found func error
281
+ '40011': BadRequest, // 400, Invalid request
282
+ '40012': ExchangeError, // 500, System error
283
+ '40013': ExchangeError, // 400, Access too often" CLIENT_TIME_INVALID, "Please check your system time.
284
+ '40014': BadSymbol, // 400, This contract is offline
285
+ '40015': BadSymbol, // 400, This contract's exchange has been paused
286
+ '40016': InvalidOrder, // 400, This order would trigger user position liquidate
287
+ '40017': InvalidOrder, // 400, It is not possible to open and close simultaneously in the same position
288
+ '40018': InvalidOrder, // 400, Your position is closed
289
+ '40019': ExchangeError, // 400, Your position is in liquidation delegating
290
+ '40020': InvalidOrder, // 400, Your position volume is not enough
291
+ '40021': ExchangeError, // 400, The position is not exsit
292
+ '40022': ExchangeError, // 400, The position is not isolated
293
+ '40023': ExchangeError, // 400, The position would liquidate when sub margin
294
+ '40024': ExchangeError, // 400, The position would be warnning of liquidation when sub margin
295
+ '40025': ExchangeError, // 400, The position’s margin shouldn’t be lower than the base limit
296
+ '40026': ExchangeError, // 400, You cross margin position is in liquidation delegating
297
+ '40027': InsufficientFunds, // 400, You contract account available balance not enough
298
+ '40028': PermissionDenied, // 400, Your plan order's count is more than system maximum limit.
299
+ '40029': InvalidOrder, // 400, The order's leverage is too large.
300
+ '40030': InvalidOrder, // 400, The order's leverage is too small.
301
+ '40031': InvalidOrder, // 400, The deviation between current price and trigger price is too large.
302
+ '40032': InvalidOrder, // 400, The plan order's life cycle is too long.
303
+ '40033': InvalidOrder, // 400, The plan order's life cycle is too short.
304
+ '40034': BadSymbol, // 400, This contract is not found
305
+ '53002': PermissionDenied, // 403, Your account has not yet completed the kyc advanced certification, please complete first
306
+ },
307
+ 'broad': {},
308
+ },
309
+ 'commonCurrencies': {
310
+ '$GM': 'GOLDMINER',
311
+ '$HERO': 'Step Hero',
312
+ '$PAC': 'PAC',
313
+ 'AUR': 'Aurum',
314
+ 'BP': 'BEYOND',
315
+ 'COT': 'Community Coin',
316
+ 'CPC': 'CPCoin',
317
+ 'DMS': 'DimSum', // conflict with Dragon Mainland Shards
318
+ 'FOX': 'Fox Finance',
319
+ 'GDT': 'Gorilla Diamond',
320
+ 'GLD': 'Goldario',
321
+ 'MIM': 'MIM Swarm',
322
+ 'MVP': 'MVP Coin',
323
+ 'ONE': 'Menlo One',
324
+ 'PLA': 'Plair',
325
+ 'TCT': 'TacoCat Token',
326
+ 'TRU': 'Truebit', // conflict with TrueFi
327
+ 'ULT': 'Ultiledger',
328
+ },
329
+ 'options': {
330
+ 'networks': {
331
+ 'TRX': 'TRC20',
332
+ 'ETH': 'ERC20',
333
+ },
334
+ 'defaultNetworks': {
335
+ 'USDT': 'ERC20',
336
+ },
337
+ 'defaultType': 'spot', // 'spot', 'swap'
338
+ 'fetchBalance': {
339
+ 'type': 'spot', // 'spot', 'swap', 'contract', 'account'
340
+ },
341
+ 'createMarketBuyOrderRequiresPrice': true,
342
+ },
343
+ });
344
+ }
345
+
346
+ async fetchTime (params = {}) {
347
+ const response = await this.publicSystemGetTime (params);
348
+ //
349
+ // {
350
+ // "message":"OK",
351
+ // "code":1000,
352
+ // "trace":"c4e5e5b7-fe9f-4191-89f7-53f6c5bf9030",
353
+ // "data":{
354
+ // "server_time":1599843709578
355
+ // }
356
+ // }
357
+ //
358
+ const data = this.safeValue (response, 'data', {});
359
+ return this.safeInteger (data, 'server_time');
360
+ }
361
+
362
+ async fetchStatus (params = {}) {
363
+ const options = this.safeValue (this.options, 'fetchBalance', {});
364
+ const defaultType = this.safeString (this.options, 'defaultType');
365
+ let type = this.safeString (options, 'type', defaultType);
366
+ type = this.safeString (params, 'type', type);
367
+ params = this.omit (params, 'type');
368
+ const response = await this.publicSystemGetService (params);
369
+ //
370
+ // {
371
+ // "message": "OK",
372
+ // "code": 1000,
373
+ // "trace": "1d3f28b0-763e-4f78-90c4-5e3ad19dc595",
374
+ // "data": {
375
+ // "service": [
376
+ // {
377
+ // "title": "Spot API Stop",
378
+ // "service_type": "spot",
379
+ // "status": 2,
380
+ // "start_time": 1648639069125,
381
+ // "end_time": 1648639069125
382
+ // },
383
+ // {
384
+ // "title": "Contract API Stop",
385
+ // "service_type": "contract",
386
+ // "status": 2,
387
+ // "start_time": 1648639069125,
388
+ // "end_time": 1648639069125
389
+ // }
390
+ // ]
391
+ // }
392
+ // }
393
+ //
394
+ const data = this.safeValue (response, 'data', {});
395
+ const services = this.safeValue (data, 'service', []);
396
+ const servicesByType = this.indexBy (services, 'service_type');
397
+ if ((type === 'swap') || (type === 'future')) {
398
+ type = 'contract';
399
+ }
400
+ const service = this.safeValue (servicesByType, type);
401
+ let status = undefined;
402
+ let eta = undefined;
403
+ if (service !== undefined) {
404
+ const statusCode = this.safeInteger (service, 'status');
405
+ if (statusCode === 2) {
406
+ status = 'ok';
407
+ } else {
408
+ status = 'maintenance';
409
+ eta = this.safeInteger (service, 'end_time');
410
+ }
411
+ }
412
+ return {
413
+ 'status': status,
414
+ 'updated': this.milliseconds (),
415
+ 'eta': eta,
416
+ 'url': undefined,
417
+ 'info': response,
418
+ };
419
+ }
420
+
421
+ async fetchSpotMarkets (params = {}) {
422
+ const response = await this.publicSpotGetSymbolsDetails (params);
423
+ //
424
+ // {
425
+ // "message":"OK",
426
+ // "code":1000,
427
+ // "trace":"a67c9146-086d-4d3f-9897-5636a9bb26e1",
428
+ // "data":{
429
+ // "symbols":[
430
+ // {
431
+ // "symbol":"PRQ_BTC",
432
+ // "symbol_id":1232,
433
+ // "base_currency":"PRQ",
434
+ // "quote_currency":"BTC",
435
+ // "quote_increment":"1.0000000000",
436
+ // "base_min_size":"1.0000000000",
437
+ // "base_max_size":"10000000.0000000000",
438
+ // "price_min_precision":8,
439
+ // "price_max_precision":10,
440
+ // "expiration":"NA",
441
+ // "min_buy_amount":"0.0001000000",
442
+ // "min_sell_amount":"0.0001000000"
443
+ // },
444
+ // ]
445
+ // }
446
+ // }
447
+ //
448
+ const data = this.safeValue (response, 'data', {});
449
+ const symbols = this.safeValue (data, 'symbols', []);
450
+ const result = [];
451
+ for (let i = 0; i < symbols.length; i++) {
452
+ const market = symbols[i];
453
+ const id = this.safeString (market, 'symbol');
454
+ const numericId = this.safeInteger (market, 'symbol_id');
455
+ const baseId = this.safeString (market, 'base_currency');
456
+ const quoteId = this.safeString (market, 'quote_currency');
457
+ const base = this.safeCurrencyCode (baseId);
458
+ const quote = this.safeCurrencyCode (quoteId);
459
+ const symbol = base + '/' + quote;
460
+ //
461
+ // https://github.com/bitmartexchange/bitmart-official-api-docs/blob/master/rest/public/symbols_details.md#response-details
462
+ // from the above API doc:
463
+ // quote_increment Minimum order price as well as the price increment
464
+ // price_min_precision Minimum price precision (digit) used to query price and kline
465
+ // price_max_precision Maximum price precision (digit) used to query price and kline
466
+ //
467
+ // the docs are wrong: https://github.com/ccxt/ccxt/issues/5612
468
+ //
469
+ const minBuyCost = this.safeString (market, 'min_buy_amount');
470
+ const minSellCost = this.safeString (market, 'min_sell_amount');
471
+ const minCost = Precise.stringMax (minBuyCost, minSellCost);
472
+ const pricePrecision = this.parsePrecision (this.safeString (market, 'price_max_precision'));
473
+ result.push ({
474
+ 'id': id,
475
+ 'numericId': numericId,
476
+ 'symbol': symbol,
477
+ 'base': base,
478
+ 'quote': quote,
479
+ 'settle': undefined,
480
+ 'baseId': baseId,
481
+ 'quoteId': quoteId,
482
+ 'settleId': undefined,
483
+ 'type': 'spot',
484
+ 'spot': true,
485
+ 'margin': false,
486
+ 'swap': false,
487
+ 'future': false,
488
+ 'option': false,
489
+ 'active': true,
490
+ 'contract': false,
491
+ 'linear': undefined,
492
+ 'inverse': undefined,
493
+ 'contractSize': undefined,
494
+ 'expiry': undefined,
495
+ 'expiryDatetime': undefined,
496
+ 'strike': undefined,
497
+ 'optionType': undefined,
498
+ 'precision': {
499
+ 'amount': this.safeNumber (market, 'base_min_size'),
500
+ 'price': this.parseNumber (pricePrecision),
501
+ },
502
+ 'limits': {
503
+ 'leverage': {
504
+ 'min': undefined,
505
+ 'max': undefined,
506
+ },
507
+ 'amount': {
508
+ 'min': this.safeNumber (market, 'base_min_size'),
509
+ 'max': this.safeNumber (market, 'base_max_size'),
510
+ },
511
+ 'price': {
512
+ 'min': undefined,
513
+ 'max': undefined,
514
+ },
515
+ 'cost': {
516
+ 'min': this.parseNumber (minCost),
517
+ 'max': undefined,
518
+ },
519
+ },
520
+ 'info': market,
521
+ });
522
+ }
523
+ return result;
524
+ }
525
+
526
+ async fetchContractMarkets (params = {}) {
527
+ const response = await this.publicContractGetTickers (params);
528
+ //
529
+ // {
530
+ // "message": "OK",
531
+ // "code": 1000,
532
+ // "trace": "045d13a8-4bc7-4974-9748-97d0ea183ef0",
533
+ // "data": {
534
+ // "tickers": [
535
+ // {
536
+ // "contract_symbol": "RAYUSDT",
537
+ // "last_price": "3.893",
538
+ // "index_price": "3.90248043",
539
+ // "last_funding_rate": "-0.00054285",
540
+ // "price_change_percent_24h": "-6.955",
541
+ // "volume_24h": "10450969.34602996",
542
+ // "url": "https://futures.bitmart.com/en?symbol=RAYUSDT",
543
+ // "high_price": "4.299",
544
+ // "low_price": "3.887",
545
+ // "legal_coin_price": "3.893056"
546
+ // },
547
+ // ...
548
+ // ]
549
+ // }
550
+ // }
551
+ //
552
+ const data = this.safeValue (response, 'data', {});
553
+ const tickers = this.safeValue (data, 'tickers', []);
554
+ const result = [];
555
+ for (let i = 0; i < tickers.length; i++) {
556
+ const market = tickers[i];
557
+ const id = this.safeString (market, 'contract_symbol');
558
+ const baseId = id.slice (0, -4);
559
+ const quoteId = id.slice (-4);
560
+ const base = this.safeCurrencyCode (baseId);
561
+ const quote = this.safeCurrencyCode (quoteId);
562
+ const splitId = id.split ('_');
563
+ const splitIdEnding = this.safeString (splitId, 1);
564
+ let settle = 'USDT';
565
+ let symbol = base + '/' + quote + ':' + settle;
566
+ let type = 'swap';
567
+ let swap = true;
568
+ let future = false;
569
+ let expiry = undefined;
570
+ if (splitIdEnding !== undefined) {
571
+ settle = 'BTC';
572
+ symbol = base + '/' + quote + ':' + settle;
573
+ if (splitIdEnding !== 'PERP') {
574
+ const date = this.iso8601 (this.milliseconds ());
575
+ const splitDate = date.split ('-');
576
+ const year = splitDate[0];
577
+ const shortYear = year.slice (0, 2);
578
+ const expiryMonth = splitIdEnding.slice (0, 2);
579
+ const expiryDay = splitIdEnding.slice (2, 4);
580
+ expiry = this.parse8601 (year + '-' + expiryMonth + '-' + expiryDay + 'T00:00:00Z');
581
+ symbol = symbol + '-' + shortYear + splitIdEnding;
582
+ type = 'future';
583
+ swap = false;
584
+ future = true;
585
+ }
586
+ }
587
+ result.push ({
588
+ 'id': id,
589
+ 'numericId': undefined,
590
+ 'symbol': symbol,
591
+ 'base': base,
592
+ 'quote': quote,
593
+ 'settle': settle,
594
+ 'baseId': baseId,
595
+ 'quoteId': quoteId,
596
+ 'settleId': undefined,
597
+ 'type': type,
598
+ 'spot': false,
599
+ 'margin': false,
600
+ 'swap': swap,
601
+ 'future': future,
602
+ 'option': false,
603
+ 'active': true,
604
+ 'contract': true,
605
+ 'linear': true,
606
+ 'inverse': false,
607
+ 'contractSize': undefined,
608
+ 'expiry': expiry,
609
+ 'expiryDatetime': this.iso8601 (expiry),
610
+ 'strike': undefined,
611
+ 'optionType': undefined,
612
+ 'precision': {
613
+ 'amount': undefined,
614
+ 'price': undefined,
615
+ },
616
+ 'limits': {
617
+ 'leverage': {
618
+ 'min': undefined,
619
+ 'max': undefined,
620
+ },
621
+ 'amount': {
622
+ 'min': undefined,
623
+ 'max': undefined,
624
+ },
625
+ 'price': {
626
+ 'min': undefined,
627
+ 'max': undefined,
628
+ },
629
+ 'cost': {
630
+ 'min': undefined,
631
+ 'max': undefined,
632
+ },
633
+ },
634
+ 'info': market,
635
+ });
636
+ }
637
+ return result;
638
+ }
639
+
640
+ async fetchMarkets (params = {}) {
641
+ const spot = await this.fetchSpotMarkets (params);
642
+ const contract = await this.fetchContractMarkets (params);
643
+ return this.arrayConcat (spot, contract);
644
+ }
645
+
646
+ async fetchFundingFee (code, params = {}) {
647
+ await this.loadMarkets ();
648
+ const currency = this.currency (code);
649
+ const request = {
650
+ 'currency': currency['id'],
651
+ };
652
+ const response = await this.privateAccountGetWithdrawCharge (this.extend (request, params));
653
+ //
654
+ // {
655
+ // message: 'OK',
656
+ // code: '1000',
657
+ // trace: '3ecc0adf-91bd-4de7-aca1-886c1122f54f',
658
+ // data: {
659
+ // today_available_withdraw_BTC: '100.0000',
660
+ // min_withdraw: '0.005',
661
+ // withdraw_precision: '8',
662
+ // withdraw_fee: '0.000500000000000000000000000000'
663
+ // }
664
+ // }
665
+ //
666
+ const data = response['data'];
667
+ const withdrawFees = {};
668
+ withdrawFees[code] = this.safeNumber (data, 'withdraw_fee');
669
+ return {
670
+ 'info': response,
671
+ 'withdraw': withdrawFees,
672
+ 'deposit': {},
673
+ };
674
+ }
675
+
676
+ parseTicker (ticker, market = undefined) {
677
+ //
678
+ // spot
679
+ //
680
+ // {
681
+ // "symbol":"DOGE_USDT",
682
+ // "last_price":"0.128300",
683
+ // "quote_volume_24h":"2296619.060420",
684
+ // "base_volume_24h":"17508866.000000000000000000000000000000",
685
+ // "high_24h":"0.133900",
686
+ // "low_24h":"0.127799",
687
+ // "open_24h":"0.133100",
688
+ // "close_24h":"0.128300",
689
+ // "best_ask":"0.128530",
690
+ // "best_ask_size":"15170",
691
+ // "best_bid":"0.128200",
692
+ // "best_bid_size":"21232",
693
+ // "fluctuation":"-0.0361",
694
+ // "s_t": 1610936002, // ws only
695
+ // "url":"https://www.bitmart.com/trade?symbol=DOGE_USDT"
696
+ // }
697
+ //
698
+ // contract
699
+ //
700
+ // {
701
+ // "contract_symbol":"DOGEUSDT",
702
+ // "last_price":"0.130340",
703
+ // "index_price":"0.13048245",
704
+ // "last_funding_rate":"0.00002287",
705
+ // "price_change_percent_24h":"-2.074",
706
+ // "volume_24h":"113705028.59482228",
707
+ // "url":"https://futures.bitmart.com/en?symbol=DOGEUSDT",
708
+ // "high_price":"0.134520",
709
+ // "low_price":"0.128570",
710
+ // "legal_coin_price":"0.1302699"
711
+ // }
712
+ //
713
+ const timestamp = this.safeTimestamp2 (ticker, 'timestamp', 's_t', this.milliseconds ());
714
+ const marketId = this.safeString2 (ticker, 'symbol', 'contract_symbol');
715
+ market = this.safeMarket (marketId, market);
716
+ const symbol = market['symbol'];
717
+ const last = this.safeString2 (ticker, 'close_24h', 'last_price');
718
+ let percentage = this.safeString (ticker, 'price_change_percent_24h');
719
+ if (percentage === undefined) {
720
+ const percentageRaw = this.safeString (ticker, 'fluctuation');
721
+ if ((percentageRaw !== undefined) && (percentageRaw !== '0')) { // a few tickers show strictly '0' in fluctuation field
722
+ const direction = percentageRaw[0];
723
+ percentage = direction + Precise.stringMul (percentageRaw.replace (direction, ''), '100');
724
+ } else if (percentageRaw === '0') {
725
+ percentage = '0';
726
+ }
727
+ }
728
+ const baseVolume = this.safeString (ticker, 'base_volume_24h');
729
+ let quoteVolume = this.safeString (ticker, 'quote_volume_24h');
730
+ quoteVolume = this.safeString (ticker, 'volume_24h', quoteVolume);
731
+ const average = this.safeString2 (ticker, 'avg_price', 'index_price');
732
+ const price = this.safeString (ticker, 'depth_price', ticker);
733
+ const high = this.safeString2 (ticker, 'high_24h', 'high_price');
734
+ const low = this.safeString2 (ticker, 'low_24h', 'low_price');
735
+ return this.safeTicker ({
736
+ 'symbol': symbol,
737
+ 'timestamp': timestamp,
738
+ 'datetime': this.iso8601 (timestamp),
739
+ 'high': high,
740
+ 'low': low,
741
+ 'bid': this.safeString (price, 'best_bid'),
742
+ 'bidVolume': this.safeString (ticker, 'best_bid_size'),
743
+ 'ask': this.safeString (price, 'best_ask'),
744
+ 'askVolume': this.safeString (ticker, 'best_ask_size'),
745
+ 'vwap': undefined,
746
+ 'open': this.safeString (ticker, 'open_24h'),
747
+ 'close': last,
748
+ 'last': last,
749
+ 'previousClose': undefined,
750
+ 'change': undefined,
751
+ 'percentage': percentage,
752
+ 'average': average,
753
+ 'baseVolume': baseVolume,
754
+ 'quoteVolume': quoteVolume,
755
+ 'info': ticker,
756
+ }, market, false);
757
+ }
758
+
759
+ async fetchTicker (symbol, params = {}) {
760
+ await this.loadMarkets ();
761
+ const market = this.market (symbol);
762
+ const request = {};
763
+ let method = undefined;
764
+ if (market['swap'] || market['future']) {
765
+ method = 'publicContractGetTickers';
766
+ request['contract_symbol'] = market['id'];
767
+ } else if (market['spot']) {
768
+ method = 'publicSpotGetTicker';
769
+ request['symbol'] = market['id'];
770
+ }
771
+ const response = await this[method] (this.extend (request, params));
772
+ //
773
+ // spot
774
+ //
775
+ // {
776
+ // "message":"OK",
777
+ // "code":1000,
778
+ // "trace":"6aa5b923-2f57-46e3-876d-feca190e0b82",
779
+ // "data":{
780
+ // "tickers":[
781
+ // {
782
+ // "symbol":"ETH_BTC",
783
+ // "last_price":"0.036037",
784
+ // "quote_volume_24h":"4380.6660000000",
785
+ // "base_volume_24h":"159.3582006712",
786
+ // "high_24h":"0.036972",
787
+ // "low_24h":"0.035524",
788
+ // "open_24h":"0.036561",
789
+ // "close_24h":"0.036037",
790
+ // "best_ask":"0.036077",
791
+ // "best_ask_size":"9.9500",
792
+ // "best_bid":"0.035983",
793
+ // "best_bid_size":"4.2792",
794
+ // "fluctuation":"-0.0143",
795
+ // "url":"https://www.bitmart.com/trade?symbol=ETH_BTC"
796
+ // }
797
+ // ]
798
+ // }
799
+ // }
800
+ //
801
+ // contract
802
+ //
803
+ // {
804
+ // "message":"OK",
805
+ // "code":1000,
806
+ // "trace":"4a0ebceb-d3f7-45a3-8feb-f61e230e24cd",
807
+ // "data":{
808
+ // "tickers":[
809
+ // {
810
+ // "contract_symbol":"DOGEUSDT",
811
+ // "last_price":"0.130180",
812
+ // "index_price":"0.13028635",
813
+ // "last_funding_rate":"0.00002025",
814
+ // "price_change_percent_24h":"-2.326",
815
+ // "volume_24h":"116789313.01797258",
816
+ // "url":"https://futures.bitmart.com/en?symbol=DOGEUSDT",
817
+ // "high_price":"0.134520",
818
+ // "low_price":"0.128570",
819
+ // "legal_coin_price":"0.13017401"
820
+ // }
821
+ // ]
822
+ // }
823
+ // }
824
+ //
825
+ const data = this.safeValue (response, 'data', {});
826
+ const tickers = this.safeValue (data, 'tickers', []);
827
+ // fails in naming for contract tickers 'contract_symbol'
828
+ let tickersById = undefined;
829
+ if (market['spot']) {
830
+ tickersById = this.indexBy (tickers, 'symbol');
831
+ } else if (market['swap'] || market['future']) {
832
+ tickersById = this.indexBy (tickers, 'contract_symbol');
833
+ }
834
+ const ticker = this.safeValue (tickersById, market['id']);
835
+ return this.parseTicker (ticker, market);
836
+ }
837
+
838
+ async fetchTickers (symbols = undefined, params = {}) {
839
+ await this.loadMarkets ();
840
+ const [ marketType, query ] = this.handleMarketTypeAndParams ('fetchTickers', undefined, params);
841
+ const method = this.getSupportedMapping (marketType, {
842
+ 'spot': 'publicSpotGetTicker',
843
+ 'swap': 'publicContractGetTickers',
844
+ 'future': 'publicContractGetTickers',
845
+ });
846
+ const response = await this[method] (query);
847
+ const data = this.safeValue (response, 'data', {});
848
+ const tickers = this.safeValue (data, 'tickers', []);
849
+ const result = {};
850
+ for (let i = 0; i < tickers.length; i++) {
851
+ const ticker = this.parseTicker (tickers[i]);
852
+ const symbol = ticker['symbol'];
853
+ result[symbol] = ticker;
854
+ }
855
+ return this.filterByArray (result, 'symbol', symbols);
856
+ }
857
+
858
+ async fetchCurrencies (params = {}) {
859
+ const response = await this.publicAccountGetCurrencies (params);
860
+ //
861
+ // {
862
+ // "message":"OK",
863
+ // "code":1000,
864
+ // "trace":"8c768b3c-025f-413f-bec5-6d6411d46883",
865
+ // "data":{
866
+ // "currencies":[
867
+ // {"currency":"MATIC","name":"Matic Network","withdraw_enabled":true,"deposit_enabled":true},
868
+ // {"currency":"KTN","name":"Kasoutuuka News","withdraw_enabled":true,"deposit_enabled":false},
869
+ // {"currency":"BRT","name":"Berith","withdraw_enabled":true,"deposit_enabled":true},
870
+ // ]
871
+ // }
872
+ // }
873
+ //
874
+ const data = this.safeValue (response, 'data', {});
875
+ const currencies = this.safeValue (data, 'currencies', []);
876
+ const result = {};
877
+ for (let i = 0; i < currencies.length; i++) {
878
+ const currency = currencies[i];
879
+ const id = this.safeString (currency, 'currency');
880
+ const code = this.safeCurrencyCode (id);
881
+ const name = this.safeString (currency, 'name');
882
+ const withdrawEnabled = this.safeValue (currency, 'withdraw_enabled');
883
+ const depositEnabled = this.safeValue (currency, 'deposit_enabled');
884
+ const active = withdrawEnabled && depositEnabled;
885
+ result[code] = {
886
+ 'id': id,
887
+ 'code': code,
888
+ 'name': name,
889
+ 'info': currency, // the original payload
890
+ 'active': active,
891
+ 'deposit': depositEnabled,
892
+ 'withdraw': withdrawEnabled,
893
+ 'fee': undefined,
894
+ 'precision': undefined,
895
+ 'limits': {
896
+ 'amount': { 'min': undefined, 'max': undefined },
897
+ 'withdraw': { 'min': undefined, 'max': undefined },
898
+ },
899
+ };
900
+ }
901
+ return result;
902
+ }
903
+
904
+ async fetchOrderBook (symbol, limit = undefined, params = {}) {
905
+ await this.loadMarkets ();
906
+ const market = this.market (symbol);
907
+ const request = {};
908
+ let method = undefined;
909
+ if (market['spot']) {
910
+ method = 'publicSpotGetSymbolsBook';
911
+ request['symbol'] = market['id'];
912
+ if (limit !== undefined) {
913
+ request['size'] = limit; // default 50, max 200
914
+ }
915
+ // request['precision'] = 4; // optional price precision / depth level whose range is defined in symbol details
916
+ } else if (market['swap'] || market['future']) {
917
+ method = 'publicContractGetDepth';
918
+ request['contractID'] = market['id'];
919
+ if (limit !== undefined) {
920
+ request['count'] = limit; // returns all records if size is omitted
921
+ }
922
+ }
923
+ const response = await this[method] (this.extend (request, params));
924
+ //
925
+ // spot
926
+ //
927
+ // {
928
+ // "message":"OK",
929
+ // "code":1000,
930
+ // "trace":"8254f8fc-431d-404f-ad9a-e716339f66c7",
931
+ // "data":{
932
+ // "buys":[
933
+ // {"amount":"4.7091","total":"4.71","price":"0.034047","count":"1"},
934
+ // {"amount":"5.7439","total":"10.45","price":"0.034039","count":"1"},
935
+ // {"amount":"2.5249","total":"12.98","price":"0.032937","count":"1"},
936
+ // ],
937
+ // "sells":[
938
+ // {"amount":"41.4365","total":"41.44","price":"0.034174","count":"1"},
939
+ // {"amount":"4.2317","total":"45.67","price":"0.034183","count":"1"},
940
+ // {"amount":"0.3000","total":"45.97","price":"0.034240","count":"1"},
941
+ // ]
942
+ // }
943
+ // }
944
+ //
945
+ // contract
946
+ //
947
+ // {
948
+ // "errno":"OK",
949
+ // "message":"OK",
950
+ // "code":1000,
951
+ // "trace":"c330dfca-ca5b-4f15-b350-9fef3f049b4f",
952
+ // "data":{
953
+ // "sells":[
954
+ // {"price":"347.6","vol":"6678"},
955
+ // {"price":"347.7","vol":"3452"},
956
+ // {"price":"347.8","vol":"6331"},
957
+ // ],
958
+ // "buys":[
959
+ // {"price":"347.5","vol":"6222"},
960
+ // {"price":"347.4","vol":"20979"},
961
+ // {"price":"347.3","vol":"15179"},
962
+ // ]
963
+ // }
964
+ // }
965
+ //
966
+ const data = this.safeValue (response, 'data', {});
967
+ if (market['spot']) {
968
+ return this.parseOrderBook (data, symbol, undefined, 'buys', 'sells', 'price', 'amount');
969
+ } else if (market['swap'] || market['future']) {
970
+ return this.parseOrderBook (data, symbol, undefined, 'buys', 'sells', 'price', 'vol');
971
+ }
972
+ }
973
+
974
+ parseTrade (trade, market = undefined) {
975
+ //
976
+ // public fetchTrades spot ( amount = count * price )
977
+ //
978
+ // {
979
+ // "amount": "818.94",
980
+ // "order_time": "1637601839035", // ETH/USDT
981
+ // "price": "4221.99",
982
+ // "count": "0.19397",
983
+ // "type": "buy"
984
+ // }
985
+ //
986
+ // public fetchTrades contract, private fetchMyTrades contract
987
+ //
988
+ // {
989
+ // "order_id":109159616160,
990
+ // "trade_id":109159616197,
991
+ // "contract_id":2,
992
+ // "deal_price":"347.6",
993
+ // "deal_vol":"5623",
994
+ // "make_fee":"-5.8636644",
995
+ // "take_fee":"9.772774",
996
+ // "created_at":"2020-09-09T11:49:50.749170536Z",
997
+ // "way":1,
998
+ // "fluctuation":"0"
999
+ // }
1000
+ //
1001
+ // private fetchMyTrades spot
1002
+ //
1003
+ // {
1004
+ // "detail_id":256348632,
1005
+ // "order_id":2147484350,
1006
+ // "symbol":"BTC_USDT",
1007
+ // "create_time":1590462303000,
1008
+ // "side":"buy",
1009
+ // "fees":"0.00001350",
1010
+ // "fee_coin_name":"BTC",
1011
+ // "notional":"88.00000000",
1012
+ // "price_avg":"8800.00",
1013
+ // "size":"0.01000",
1014
+ // "exec_type":"M"
1015
+ // }
1016
+ //
1017
+ const id = this.safeString2 (trade, 'trade_id', 'detail_id');
1018
+ let timestamp = this.safeInteger2 (trade, 'order_time', 'create_time');
1019
+ if (timestamp === undefined) {
1020
+ timestamp = this.safeTimestamp (trade, 's_t');
1021
+ }
1022
+ if (timestamp === undefined) {
1023
+ timestamp = this.parse8601 (this.safeString (trade, 'created_at'));
1024
+ }
1025
+ const type = undefined;
1026
+ const way = this.safeInteger (trade, 'way');
1027
+ let side = this.safeStringLower2 (trade, 'type', 'side');
1028
+ if ((side === undefined) && (way !== undefined)) {
1029
+ if (way < 5) {
1030
+ side = 'buy';
1031
+ } else {
1032
+ side = 'sell';
1033
+ }
1034
+ }
1035
+ let takerOrMaker = undefined;
1036
+ const execType = this.safeString (trade, 'exec_type');
1037
+ if (execType !== undefined) {
1038
+ takerOrMaker = (execType === 'M') ? 'maker' : 'taker';
1039
+ }
1040
+ let priceString = this.safeString2 (trade, 'price', 'deal_price');
1041
+ priceString = this.safeString (trade, 'price_avg', priceString);
1042
+ let amountString = this.safeString2 (trade, 'count', 'deal_vol');
1043
+ amountString = this.safeString (trade, 'size', amountString);
1044
+ const costString = this.safeString2 (trade, 'amount', 'notional');
1045
+ const orderId = this.safeInteger (trade, 'order_id');
1046
+ const marketId = this.safeString2 (trade, 'contract_id', 'symbol');
1047
+ market = this.safeMarket (marketId, market, '_');
1048
+ const feeCostString = this.safeString (trade, 'fees');
1049
+ let fee = undefined;
1050
+ if (feeCostString !== undefined) {
1051
+ const feeCurrencyId = this.safeString (trade, 'fee_coin_name');
1052
+ let feeCurrencyCode = this.safeCurrencyCode (feeCurrencyId);
1053
+ if (feeCurrencyCode === undefined) {
1054
+ feeCurrencyCode = (side === 'buy') ? market['base'] : market['quote'];
1055
+ }
1056
+ fee = {
1057
+ 'cost': feeCostString,
1058
+ 'currency': feeCurrencyCode,
1059
+ };
1060
+ }
1061
+ return this.safeTrade ({
1062
+ 'info': trade,
1063
+ 'id': id,
1064
+ 'order': orderId,
1065
+ 'timestamp': timestamp,
1066
+ 'datetime': this.iso8601 (timestamp),
1067
+ 'symbol': market['symbol'],
1068
+ 'type': type,
1069
+ 'side': side,
1070
+ 'price': priceString,
1071
+ 'amount': amountString,
1072
+ 'cost': costString,
1073
+ 'takerOrMaker': takerOrMaker,
1074
+ 'fee': fee,
1075
+ }, market);
1076
+ }
1077
+
1078
+ async fetchTrades (symbol, since = undefined, limit = undefined, params = {}) {
1079
+ await this.loadMarkets ();
1080
+ const market = this.market (symbol);
1081
+ const request = {
1082
+ 'symbol': market['id'],
1083
+ };
1084
+ let method = undefined;
1085
+ if (market['spot']) {
1086
+ request['symbol'] = market['id'];
1087
+ method = 'publicSpotGetSymbolsTrades';
1088
+ } else if (market['swap'] || market['future']) {
1089
+ method = 'publicContractGetTrades';
1090
+ request['contractID'] = market['id'];
1091
+ }
1092
+ const response = await this[method] (this.extend (request, params));
1093
+ //
1094
+ // spot
1095
+ //
1096
+ // {
1097
+ // "message":"OK",
1098
+ // "code":1000,
1099
+ // "trace":"222d74c0-8f6d-49d9-8e1b-98118c50eeba",
1100
+ // "data":{
1101
+ // "trades":[
1102
+ // {
1103
+ // "amount":"0.005703",
1104
+ // "order_time":1599652045394,
1105
+ // "price":"0.034029",
1106
+ // "count":"0.1676",
1107
+ // "type":"sell"
1108
+ // },
1109
+ // ]
1110
+ // }
1111
+ // }
1112
+ //
1113
+ // contract
1114
+ //
1115
+ // {
1116
+ // "errno":"OK",
1117
+ // "message":"OK",
1118
+ // "code":1000,
1119
+ // "trace":"782bc746-b86e-43bf-8d1a-c68b479c9bdd",
1120
+ // "data":{
1121
+ // "trades":[
1122
+ // {
1123
+ // "order_id":109159616160,
1124
+ // "trade_id":109159616197,
1125
+ // "contract_id":2,
1126
+ // "deal_price":"347.6",
1127
+ // "deal_vol":"5623",
1128
+ // "make_fee":"-5.8636644",
1129
+ // "take_fee":"9.772774",
1130
+ // "created_at":"2020-09-09T11:49:50.749170536Z",
1131
+ // "way":1,
1132
+ // "fluctuation":"0"
1133
+ // }
1134
+ // ]
1135
+ // }
1136
+ // }
1137
+ //
1138
+ const data = this.safeValue (response, 'data', {});
1139
+ const trades = this.safeValue (data, 'trades', []);
1140
+ return this.parseTrades (trades, market, since, limit);
1141
+ }
1142
+
1143
+ parseOHLCV (ohlcv, market = undefined) {
1144
+ //
1145
+ // spot
1146
+ //
1147
+ // {
1148
+ // "last_price":"0.034987",
1149
+ // "timestamp":1598787420,
1150
+ // "volume":"1.0198",
1151
+ // "open":"0.035007",
1152
+ // "close":"0.034987",
1153
+ // "high":"0.035007",
1154
+ // "low":"0.034986"
1155
+ // }
1156
+ //
1157
+ // contract
1158
+ //
1159
+ // {
1160
+ // "low":"404.4",
1161
+ // "high":"404.4",
1162
+ // "open":"404.4",
1163
+ // "close":"404.4",
1164
+ // "last_price":"404.4",
1165
+ // "avg_price":"404.4",
1166
+ // "volume":"7670",
1167
+ // "timestamp":1598758441,
1168
+ // "rise_fall_rate":"0",
1169
+ // "rise_fall_value":"0",
1170
+ // "base_coin_volume":"76.7",
1171
+ // "quote_coin_volume":"31017.48"
1172
+ // }
1173
+ //
1174
+ // ws
1175
+ //
1176
+ // [
1177
+ // 1631056350, // timestamp
1178
+ // '46532.83', // oopen
1179
+ // '46555.71', // high
1180
+ // '46511.41', // low
1181
+ // '46555.71', // close
1182
+ // '0.25', // volume
1183
+ // ]
1184
+ //
1185
+ if (Array.isArray (ohlcv)) {
1186
+ return [
1187
+ this.safeTimestamp (ohlcv, 0),
1188
+ this.safeNumber (ohlcv, 1),
1189
+ this.safeNumber (ohlcv, 2),
1190
+ this.safeNumber (ohlcv, 3),
1191
+ this.safeNumber (ohlcv, 4),
1192
+ this.safeNumber (ohlcv, 5),
1193
+ ];
1194
+ } else {
1195
+ return [
1196
+ this.safeTimestamp (ohlcv, 'timestamp'),
1197
+ this.safeNumber (ohlcv, 'open'),
1198
+ this.safeNumber (ohlcv, 'high'),
1199
+ this.safeNumber (ohlcv, 'low'),
1200
+ this.safeNumber (ohlcv, 'close'),
1201
+ this.safeNumber (ohlcv, 'volume'),
1202
+ ];
1203
+ }
1204
+ }
1205
+
1206
+ async fetchOHLCV (symbol, timeframe = '1m', since = undefined, limit = undefined, params = {}) {
1207
+ await this.loadMarkets ();
1208
+ const market = this.market (symbol);
1209
+ const type = market['type'];
1210
+ let method = undefined;
1211
+ const request = {};
1212
+ const duration = this.parseTimeframe (timeframe);
1213
+ if (type === 'spot') {
1214
+ method = 'publicSpotGetSymbolsKline';
1215
+ request['symbol'] = market['id'];
1216
+ request['step'] = this.timeframes[timeframe];
1217
+ // the exchange will return an empty array if more than 500 candles is requested
1218
+ const maxLimit = 500;
1219
+ if (limit === undefined) {
1220
+ limit = maxLimit;
1221
+ }
1222
+ limit = Math.min (maxLimit, limit);
1223
+ if (since === undefined) {
1224
+ const end = parseInt (this.milliseconds () / 1000);
1225
+ const start = end - limit * duration;
1226
+ request['from'] = start;
1227
+ request['to'] = end;
1228
+ } else {
1229
+ const start = parseInt (since / 1000) - 1;
1230
+ const end = this.sum (start, limit * duration);
1231
+ request['from'] = start;
1232
+ request['to'] = end;
1233
+ }
1234
+ } else if ((type === 'swap') || (type === 'future')) {
1235
+ method = 'publicContractGetQuote';
1236
+ request['contractID'] = market['id'];
1237
+ const defaultLimit = 500;
1238
+ if (limit === undefined) {
1239
+ limit = defaultLimit;
1240
+ }
1241
+ if (since === undefined) {
1242
+ const end = parseInt (this.milliseconds () / 1000);
1243
+ const start = end - limit * duration;
1244
+ request['startTime'] = start;
1245
+ request['endTime'] = end;
1246
+ } else {
1247
+ const start = parseInt (since / 1000) - 1;
1248
+ const end = this.sum (start, limit * duration);
1249
+ request['startTime'] = start;
1250
+ request['endTime'] = end;
1251
+ }
1252
+ request['unit'] = this.timeframes[timeframe];
1253
+ request['resolution'] = 'M';
1254
+ }
1255
+ const response = await this[method] (this.extend (request, params));
1256
+ //
1257
+ // spot
1258
+ //
1259
+ // {
1260
+ // "message":"OK",
1261
+ // "code":1000,
1262
+ // "trace":"80d86378-ab4e-4c70-819e-b42146cf87ad",
1263
+ // "data":{
1264
+ // "klines":[
1265
+ // {"last_price":"0.034987","timestamp":1598787420,"volume":"1.0198","open":"0.035007","close":"0.034987","high":"0.035007","low":"0.034986"},
1266
+ // {"last_price":"0.034986","timestamp":1598787480,"volume":"0.3959","open":"0.034982","close":"0.034986","high":"0.034986","low":"0.034980"},
1267
+ // {"last_price":"0.034978","timestamp":1598787540,"volume":"0.3259","open":"0.034987","close":"0.034978","high":"0.034987","low":"0.034977"},
1268
+ // ]
1269
+ // }
1270
+ // }
1271
+ //
1272
+ // swap
1273
+ //
1274
+ // {
1275
+ // "errno":"OK",
1276
+ // "message":"OK",
1277
+ // "code":1000,
1278
+ // "trace":"32965074-5804-4655-b693-e953e36026a0",
1279
+ // "data":[
1280
+ // {"low":"404.4","high":"404.4","open":"404.4","close":"404.4","last_price":"404.4","avg_price":"404.4","volume":"7670","timestamp":1598758441,"rise_fall_rate":"0","rise_fall_value":"0","base_coin_volume":"76.7","quote_coin_volume":"31017.48"},
1281
+ // {"low":"404.1","high":"404.4","open":"404.4","close":"404.1","last_price":"404.1","avg_price":"404.15881086","volume":"12076","timestamp":1598758501,"rise_fall_rate":"-0.000741839762611276","rise_fall_value":"-0.3","base_coin_volume":"120.76","quote_coin_volume":"48806.2179994536"},
1282
+ // {"low":"404","high":"404.3","open":"404.1","close":"404","last_price":"404","avg_price":"404.08918918","volume":"740","timestamp":1598758561,"rise_fall_rate":"-0.000247463499133878","rise_fall_value":"-0.1","base_coin_volume":"7.4","quote_coin_volume":"2990.259999932"},
1283
+ // ]
1284
+ // }
1285
+ //
1286
+ const data = this.safeValue (response, 'data', {});
1287
+ if (Array.isArray (data)) {
1288
+ return this.parseOHLCVs (data, market, timeframe, since, limit);
1289
+ } else {
1290
+ const klines = this.safeValue (data, 'klines', []);
1291
+ return this.parseOHLCVs (klines, market, timeframe, since, limit);
1292
+ }
1293
+ }
1294
+
1295
+ async fetchMyTrades (symbol = undefined, since = undefined, limit = undefined, params = {}) {
1296
+ if (symbol === undefined) {
1297
+ throw new ArgumentsRequired (this.id + ' fetchMyTrades() requires a symbol argument');
1298
+ }
1299
+ await this.loadMarkets ();
1300
+ const market = this.market (symbol);
1301
+ const [ marketType, query ] = this.handleMarketTypeAndParams ('fetchMyTrades', market, params);
1302
+ const request = {};
1303
+ if (market['spot']) {
1304
+ request['symbol'] = market['id'];
1305
+ request['offset'] = 1; // max offset * limit < 500
1306
+ if (limit === undefined) {
1307
+ limit = 100; // max 100
1308
+ }
1309
+ request['limit'] = limit;
1310
+ } else if (market['swap'] || market['future']) {
1311
+ request['contractID'] = market['id'];
1312
+ // request['offset'] = 1;
1313
+ if (limit !== undefined) {
1314
+ request['size'] = limit; // max 60
1315
+ }
1316
+ }
1317
+ const method = this.getSupportedMapping (marketType, {
1318
+ 'spot': 'privateSpotGetTrades',
1319
+ 'swap': 'privateContractGetUserTrades',
1320
+ 'future': 'privateContractGetUserTrades',
1321
+ });
1322
+ const response = await this[method] (this.extend (request, query));
1323
+ //
1324
+ // spot
1325
+ //
1326
+ // {
1327
+ // "message":"OK",
1328
+ // "code":1000,
1329
+ // "trace":"a06a5c53-8e6f-42d6-8082-2ff4718d221c",
1330
+ // "data":{
1331
+ // "current_page":1,
1332
+ // "trades":[
1333
+ // {
1334
+ // "detail_id":256348632,
1335
+ // "order_id":2147484350,
1336
+ // "symbol":"BTC_USDT",
1337
+ // "create_time":1590462303000,
1338
+ // "side":"buy",
1339
+ // "fees":"0.00001350",
1340
+ // "fee_coin_name":"BTC",
1341
+ // "notional":"88.00000000",
1342
+ // "price_avg":"8800.00",
1343
+ // "size":"0.01000",
1344
+ // "exec_type":"M"
1345
+ // },
1346
+ // ]
1347
+ // }
1348
+ // }
1349
+ //
1350
+ // contract
1351
+ //
1352
+ // {
1353
+ // "code": 1000,
1354
+ // "trace":"886fb6ae-456b-4654-b4e0-d681ac05cea1",
1355
+ // "message": "OK",
1356
+ // "data": {
1357
+ // "trades": [
1358
+ // {
1359
+ // "order_id": 10116361,
1360
+ // "trade_id": 10116363,
1361
+ // "contract_id": 1,
1362
+ // "deal_price": "16",
1363
+ // "deal_vol": "10",
1364
+ // "make_fee": "0.04",
1365
+ // "take_fee": "0.12",
1366
+ // "created_at": null,
1367
+ // "way": 5,
1368
+ // "fluctuation": "0"
1369
+ // }
1370
+ // ]
1371
+ // }
1372
+ // }
1373
+ //
1374
+ const data = this.safeValue (response, 'data', {});
1375
+ const trades = this.safeValue (data, 'trades', []);
1376
+ return this.parseTrades (trades, market, since, limit);
1377
+ }
1378
+
1379
+ async fetchOrderTrades (id, symbol = undefined, since = undefined, limit = undefined, params = {}) {
1380
+ if (symbol === undefined) {
1381
+ throw new ArgumentsRequired (this.id + ' fetchOrderTrades() requires a symbol argument');
1382
+ }
1383
+ await this.loadMarkets ();
1384
+ const market = this.market (symbol);
1385
+ const [ marketType, query ] = this.handleMarketTypeAndParams ('fetchOrderTrades', market, params);
1386
+ const request = {};
1387
+ if (market['spot']) {
1388
+ request['symbol'] = market['id'];
1389
+ request['order_id'] = id;
1390
+ } else if (market['swap'] || market['future']) {
1391
+ request['contractID'] = market['id'];
1392
+ request['orderID'] = id;
1393
+ }
1394
+ const method = this.getSupportedMapping (marketType, {
1395
+ 'spot': 'privateSpotGetTrades',
1396
+ 'swap': 'privateContractGetOrderTrades',
1397
+ 'future': 'privateContractGetOrderTrades',
1398
+ });
1399
+ const response = await this[method] (this.extend (request, query));
1400
+ //
1401
+ // spot
1402
+ //
1403
+ // {
1404
+ // "message":"OK",
1405
+ // "code":1000,
1406
+ // "trace":"a06a5c53-8e6f-42d6-8082-2ff4718d221c",
1407
+ // "data":{
1408
+ // "current_page":1,
1409
+ // "trades":[
1410
+ // {
1411
+ // "detail_id":256348632,
1412
+ // "order_id":2147484350,
1413
+ // "symbol":"BTC_USDT",
1414
+ // "create_time":1590462303000,
1415
+ // "side":"buy",
1416
+ // "fees":"0.00001350",
1417
+ // "fee_coin_name":"BTC",
1418
+ // "notional":"88.00000000",
1419
+ // "price_avg":"8800.00",
1420
+ // "size":"0.01000",
1421
+ // "exec_type":"M"
1422
+ // },
1423
+ // ]
1424
+ // }
1425
+ // }
1426
+ //
1427
+ // contract
1428
+ //
1429
+ // {
1430
+ // "code": 1000,
1431
+ // "trace":"886fb6ae-456b-4654-b4e0-d681ac05cea1",
1432
+ // "message": "OK",
1433
+ // "data": {
1434
+ // "trades": [
1435
+ // {
1436
+ // "order_id": 10116361,
1437
+ // "trade_id": 10116363,
1438
+ // "contract_id": 1,
1439
+ // "deal_price": "16",
1440
+ // "deal_vol": "10",
1441
+ // "make_fee": "0.04",
1442
+ // "take_fee": "0.12",
1443
+ // "created_at": null,
1444
+ // "way": 5,
1445
+ // "fluctuation": "0"
1446
+ // }
1447
+ // ]
1448
+ // }
1449
+ // }
1450
+ //
1451
+ const data = this.safeValue (response, 'data', {});
1452
+ const trades = this.safeValue (data, 'trades', []);
1453
+ return this.parseTrades (trades, market, since, limit);
1454
+ }
1455
+
1456
+ parseBalance (response) {
1457
+ const data = this.safeValue (response, 'data', {});
1458
+ const wallet = this.safeValue2 (data, 'wallet', 'accounts', []);
1459
+ const result = { 'info': response };
1460
+ for (let i = 0; i < wallet.length; i++) {
1461
+ const balance = wallet[i];
1462
+ let currencyId = this.safeString2 (balance, 'id', 'currency');
1463
+ currencyId = this.safeString (balance, 'coin_code', currencyId);
1464
+ const code = this.safeCurrencyCode (currencyId);
1465
+ const account = this.account ();
1466
+ account['free'] = this.safeString2 (balance, 'available', 'available_vol');
1467
+ account['used'] = this.safeString2 (balance, 'frozen', 'freeze_vol');
1468
+ result[code] = account;
1469
+ }
1470
+ return this.safeBalance (result);
1471
+ }
1472
+
1473
+ async fetchBalance (params = {}) {
1474
+ await this.loadMarkets ();
1475
+ const [ marketType, query ] = this.handleMarketTypeAndParams ('fetchBalance', undefined, params);
1476
+ const method = this.getSupportedMapping (marketType, {
1477
+ 'spot': 'privateSpotGetWallet',
1478
+ 'swap': 'privateContractGetAccounts',
1479
+ 'future': 'privateContractGetAccounts',
1480
+ 'contract': 'privateContractGetAccounts',
1481
+ 'account': 'privateAccountGetWallet',
1482
+ });
1483
+ const response = await this[method] (query);
1484
+ //
1485
+ // spot
1486
+ //
1487
+ // {
1488
+ // "message":"OK",
1489
+ // "code":1000,
1490
+ // "trace":"39069916-72f9-44c7-acde-2ad5afd21cad",
1491
+ // "data":{
1492
+ // "wallet":[
1493
+ // {"id":"BTC","name":"Bitcoin","available":"0.00000062","frozen":"0.00000000"},
1494
+ // {"id":"ETH","name":"Ethereum","available":"0.00002277","frozen":"0.00000000"},
1495
+ // {"id":"BMX","name":"BitMart Token","available":"0.00000000","frozen":"0.00000000"}
1496
+ // ]
1497
+ // }
1498
+ // }
1499
+ //
1500
+ // account
1501
+ //
1502
+ // {
1503
+ // "message":"OK",
1504
+ // "code":1000,
1505
+ // "trace":"5c3b7fc7-93b2-49ef-bb59-7fdc56915b59",
1506
+ // "data":{
1507
+ // "wallet":[
1508
+ // {"currency":"BTC","name":"Bitcoin","available":"0.00000062","frozen":"0.00000000"},
1509
+ // {"currency":"ETH","name":"Ethereum","available":"0.00002277","frozen":"0.00000000"}
1510
+ // ]
1511
+ // }
1512
+ // }
1513
+ //
1514
+ // contract
1515
+ //
1516
+ // {
1517
+ // "code": 1000,
1518
+ // "trace":"886fb6ae-456b-4654-b4e0-d681ac05cea1",
1519
+ // "message": "OK",
1520
+ // "data": {
1521
+ // "accounts": [
1522
+ // {
1523
+ // "account_id": 10,
1524
+ // "coin_code": "USDT",
1525
+ // "freeze_vol": "1201.8",
1526
+ // "available_vol": "8397.65",
1527
+ // "cash_vol": "0",
1528
+ // "realised_vol": "-0.5",
1529
+ // "unrealised_vol": "-0.5",
1530
+ // "earnings_vol": "-0.5",
1531
+ // "created_at": "2018-07-13T16:48:49+08:00",
1532
+ // "updated_at": "2018-07-13T18:34:45.900387+08:00"
1533
+ // }
1534
+ // ]
1535
+ // }
1536
+ // }
1537
+ //
1538
+ return this.parseBalance (response);
1539
+ }
1540
+
1541
+ parseOrder (order, market = undefined) {
1542
+ //
1543
+ // createOrder
1544
+ //
1545
+ // {
1546
+ // "order_id": 2707217580
1547
+ // }
1548
+ //
1549
+ // cancelOrder
1550
+ //
1551
+ // '2707217580' // order id
1552
+ //
1553
+ // spot fetchOrder, fetchOrdersByStatus, fetchOpenOrders, fetchClosedOrders
1554
+ //
1555
+ // {
1556
+ // "order_id":1736871726781,
1557
+ // "symbol":"BTC_USDT",
1558
+ // "create_time":1591096004000,
1559
+ // "side":"sell",
1560
+ // "type":"market",
1561
+ // "price":"0.00",
1562
+ // "price_avg":"0.00",
1563
+ // "size":"0.02000",
1564
+ // "notional":"0.00000000",
1565
+ // "filled_notional":"0.00000000",
1566
+ // "filled_size":"0.00000",
1567
+ // "status":"8"
1568
+ // }
1569
+ //
1570
+ // contract fetchOrder, fetchOrdersByStatus, fetchOpenOrders, fetchClosedOrders, fetchOrders
1571
+ //
1572
+ // {
1573
+ // "order_id": 10539098,
1574
+ // "contract_id": 1,
1575
+ // "position_id": 10539088,
1576
+ // "account_id": 10,
1577
+ // "price": "16",
1578
+ // "vol": "1",
1579
+ // "done_avg_price": "16",
1580
+ // "done_vol": "1",
1581
+ // "way": 3,
1582
+ // "category": 1,
1583
+ // "open_type": 2,
1584
+ // "make_fee": "0.00025",
1585
+ // "take_fee": "0.012",
1586
+ // "origin": "",
1587
+ // "created_at": "2018-07-23T11:55:56.715305Z",
1588
+ // "finished_at": "2018-07-23T11:55:56.763941Z",
1589
+ // "status": 4,
1590
+ // "errno": 0
1591
+ // }
1592
+ //
1593
+ let id = undefined;
1594
+ if (typeof order === 'string') {
1595
+ id = order;
1596
+ order = {};
1597
+ }
1598
+ id = this.safeString (order, 'order_id', id);
1599
+ let timestamp = this.parse8601 (this.safeString (order, 'created_at'));
1600
+ timestamp = this.safeInteger (order, 'create_time', timestamp);
1601
+ const marketId = this.safeString2 (order, 'symbol', 'contract_id');
1602
+ const symbol = this.safeSymbol (marketId, market, '_');
1603
+ let status = undefined;
1604
+ if (market !== undefined) {
1605
+ status = this.parseOrderStatusByType (market['type'], this.safeString (order, 'status'));
1606
+ }
1607
+ const amount = this.safeString2 (order, 'size', 'vol');
1608
+ const filled = this.safeString2 (order, 'filled_size', 'done_vol');
1609
+ const average = this.safeString2 (order, 'price_avg', 'done_avg_price');
1610
+ const price = this.safeString (order, 'price');
1611
+ const side = this.safeString2 (order, 'way', 'side');
1612
+ // 1 = Open long
1613
+ // 2 = Close short
1614
+ // 3 = Close long
1615
+ // 4 = Open short
1616
+ const category = this.safeInteger (order, 'category');
1617
+ let type = this.safeString (order, 'type');
1618
+ if (category === 1) {
1619
+ type = 'limit';
1620
+ } else if (category === 2) {
1621
+ type = 'market';
1622
+ }
1623
+ return this.safeOrder ({
1624
+ 'id': id,
1625
+ 'clientOrderId': undefined,
1626
+ 'info': order,
1627
+ 'timestamp': timestamp,
1628
+ 'datetime': this.iso8601 (timestamp),
1629
+ 'lastTradeTimestamp': undefined,
1630
+ 'symbol': symbol,
1631
+ 'type': type,
1632
+ 'timeInForce': undefined,
1633
+ 'postOnly': undefined,
1634
+ 'side': side,
1635
+ 'price': price,
1636
+ 'stopPrice': undefined,
1637
+ 'amount': amount,
1638
+ 'cost': undefined,
1639
+ 'average': average,
1640
+ 'filled': filled,
1641
+ 'remaining': undefined,
1642
+ 'status': status,
1643
+ 'fee': undefined,
1644
+ 'trades': undefined,
1645
+ }, market);
1646
+ }
1647
+
1648
+ parseOrderStatusByType (type, status) {
1649
+ const statusesByType = {
1650
+ 'spot': {
1651
+ '1': 'failed', // Order failure
1652
+ '2': 'open', // Placing order
1653
+ '3': 'failed', // Order failure, Freeze failure
1654
+ '4': 'open', // Order success, Pending for fulfilment
1655
+ '5': 'open', // Partially filled
1656
+ '6': 'closed', // Fully filled
1657
+ '7': 'canceling', // Canceling
1658
+ '8': 'canceled', // Canceled
1659
+ },
1660
+ 'swap': {
1661
+ '1': 'open', // Submitting
1662
+ '2': 'open', // Commissioned
1663
+ '4': 'closed', // Completed
1664
+ },
1665
+ };
1666
+ const statuses = this.safeValue (statusesByType, type, {});
1667
+ return this.safeString (statuses, status, status);
1668
+ }
1669
+
1670
+ async createOrder (symbol, type, side, amount, price = undefined, params = {}) {
1671
+ await this.loadMarkets ();
1672
+ const market = this.market (symbol);
1673
+ const request = {};
1674
+ let method = undefined;
1675
+ if (market['spot']) {
1676
+ request['symbol'] = market['id'];
1677
+ request['side'] = side;
1678
+ request['type'] = type;
1679
+ method = 'privateSpotPostSubmitOrder';
1680
+ if (type === 'limit') {
1681
+ request['size'] = this.amountToPrecision (symbol, amount);
1682
+ request['price'] = this.priceToPrecision (symbol, price);
1683
+ } else if (type === 'market') {
1684
+ // for market buy it requires the amount of quote currency to spend
1685
+ if (side === 'buy') {
1686
+ let notional = this.safeNumber (params, 'notional');
1687
+ const createMarketBuyOrderRequiresPrice = this.safeValue (this.options, 'createMarketBuyOrderRequiresPrice', true);
1688
+ if (createMarketBuyOrderRequiresPrice) {
1689
+ if (price !== undefined) {
1690
+ if (notional === undefined) {
1691
+ notional = amount * price;
1692
+ }
1693
+ } else if (notional === undefined) {
1694
+ throw new InvalidOrder (this.id + " createOrder() requires the price argument with market buy orders to calculate total order cost (amount to spend), where cost = amount * price. Supply a price argument to createOrder() call if you want the cost to be calculated for you from price and amount, or, alternatively, add .options['createMarketBuyOrderRequiresPrice'] = false and supply the total cost value in the 'amount' argument or in the 'notional' extra parameter (the exchange-specific behaviour)");
1695
+ }
1696
+ } else {
1697
+ notional = (notional === undefined) ? amount : notional;
1698
+ }
1699
+ const precision = market['precision']['price'];
1700
+ request['notional'] = this.decimalToPrecision (notional, TRUNCATE, precision, this.precisionMode);
1701
+ } else if (side === 'sell') {
1702
+ request['size'] = this.amountToPrecision (symbol, amount);
1703
+ }
1704
+ }
1705
+ } else if (market['swap'] || market['future']) {
1706
+ method = 'privateContractPostSubmitOrder';
1707
+ request['contractID'] = market['id'];
1708
+ if (type === 'limit') {
1709
+ request['category'] = 1;
1710
+ } else if (type === 'market') {
1711
+ request['category'] = 2;
1712
+ }
1713
+ request['way'] = side; // 1 = open long, 2 = close short, 3 = close long, 4 = open short
1714
+ request['custom_id'] = this.nonce ();
1715
+ request['open_type'] = 1; // 1 = cross margin, 2 = fixed margin
1716
+ request['leverage'] = 1; // must meet the effective range of leverage configured in the contract
1717
+ request['price'] = this.priceToPrecision (symbol, price);
1718
+ request['vol'] = this.amountToPrecision (symbol, amount);
1719
+ }
1720
+ const timeInForce = this.safeString (params, 'timeInForce');
1721
+ const postOnly = this.safeValue (params, 'postOnly', false);
1722
+ if ((timeInForce !== undefined) || postOnly || (type === 'limit_maker') || (type === 'ioc')) {
1723
+ if (timeInForce === 'FOK') {
1724
+ throw new InvalidOrder (this.id + ' createOrder() only accepts timeInForce parameter values of IOC or PO');
1725
+ }
1726
+ const maker = ((timeInForce === 'PO') || postOnly || (type === 'limit_maker'));
1727
+ const ioc = ((timeInForce === 'IOC') || (type === 'ioc'));
1728
+ if (maker && ioc) {
1729
+ throw new InvalidOrder (this.id + ' createOrder() does not accept IOC postOnly orders, the order cannot be both postOnly and IOC');
1730
+ }
1731
+ if (type === 'market') {
1732
+ throw new InvalidOrder (this.id + ' createOrder() does not accept market postOnly orders or market IOC orders, only limit postOnly order or limit IOC orders are allowed');
1733
+ }
1734
+ if (maker) {
1735
+ request['type'] = 'limit_maker';
1736
+ } else if (ioc) {
1737
+ request['type'] = 'ioc';
1738
+ }
1739
+ params = this.omit (params, [ 'timeInForce', 'postOnly' ]);
1740
+ }
1741
+ const response = await this[method] (this.extend (request, params));
1742
+ //
1743
+ // spot and contract
1744
+ //
1745
+ // {
1746
+ // "code": 1000,
1747
+ // "trace":"886fb6ae-456b-4654-b4e0-d681ac05cea1",
1748
+ // "message": "OK",
1749
+ // "data": {
1750
+ // "order_id": 2707217580
1751
+ // }
1752
+ // }
1753
+ //
1754
+ const data = this.safeValue (response, 'data', {});
1755
+ return this.parseOrder (data, market);
1756
+ }
1757
+
1758
+ async cancelOrder (id, symbol = undefined, params = {}) {
1759
+ if (symbol === undefined) {
1760
+ throw new ArgumentsRequired (this.id + ' cancelOrder() requires a symbol argument');
1761
+ }
1762
+ await this.loadMarkets ();
1763
+ const market = this.market (symbol);
1764
+ const request = {};
1765
+ let method = undefined;
1766
+ if (market['spot']) {
1767
+ method = 'privateSpotPostCancelOrder';
1768
+ request['order_id'] = parseInt (id);
1769
+ request['symbol'] = market['id'];
1770
+ } else if (market['swap'] || market['future']) {
1771
+ method = 'privateContractPostCancelOrders';
1772
+ request['contractID'] = market['id'];
1773
+ request['orders'] = [ parseInt (id) ];
1774
+ }
1775
+ const response = await this[method] (this.extend (request, params));
1776
+ //
1777
+ // spot
1778
+ //
1779
+ // {
1780
+ // "code": 1000,
1781
+ // "trace":"886fb6ae-456b-4654-b4e0-d681ac05cea1",
1782
+ // "message": "OK",
1783
+ // "data": {
1784
+ // "result": true
1785
+ // }
1786
+ // }
1787
+ //
1788
+ // spot alternative
1789
+ //
1790
+ // {
1791
+ // "code": 1000,
1792
+ // "trace":"886fb6ae-456b-4654-b4e0-d681ac05cea1",
1793
+ // "message": "OK",
1794
+ // "data": true
1795
+ // }
1796
+ //
1797
+ // contract
1798
+ //
1799
+ // {
1800
+ // "code": 1000,
1801
+ // "trace":"886fb6ae-456b-4654-b4e0-d681ac05cea1",
1802
+ // "message": "OK",
1803
+ // "data": {
1804
+ // "succeed": [
1805
+ // 2707219612
1806
+ // ],
1807
+ // "failed": []
1808
+ // }
1809
+ // }
1810
+ //
1811
+ const data = this.safeValue (response, 'data');
1812
+ if (data === true) {
1813
+ return this.parseOrder (id, market);
1814
+ }
1815
+ const succeeded = this.safeValue (data, 'succeed');
1816
+ if (succeeded !== undefined) {
1817
+ id = this.safeString (succeeded, 0);
1818
+ if (id === undefined) {
1819
+ throw new InvalidOrder (this.id + ' cancelOrder() failed to cancel ' + symbol + ' order id ' + id);
1820
+ }
1821
+ } else {
1822
+ const result = this.safeValue (data, 'result');
1823
+ if (!result) {
1824
+ throw new InvalidOrder (this.id + ' cancelOrder() ' + symbol + ' order id ' + id + ' is filled or canceled');
1825
+ }
1826
+ }
1827
+ const order = this.parseOrder (id, market);
1828
+ return this.extend (order, { 'id': id });
1829
+ }
1830
+
1831
+ async cancelAllOrders (symbol = undefined, params = {}) {
1832
+ if (symbol === undefined) {
1833
+ throw new ArgumentsRequired (this.id + ' cancelAllOrders() requires a symbol argument');
1834
+ }
1835
+ const side = this.safeString (params, 'side');
1836
+ if (side === undefined) {
1837
+ throw new ArgumentsRequired (this.id + " cancelAllOrders() requires a `side` parameter ('buy' or 'sell')");
1838
+ }
1839
+ await this.loadMarkets ();
1840
+ const market = this.market (symbol);
1841
+ if (!market['spot']) {
1842
+ throw new NotSupported (this.id + ' cancelAllOrders() does not support ' + market['type'] + ' orders, only spot orders are accepted');
1843
+ }
1844
+ const request = {
1845
+ 'symbol': market['id'],
1846
+ 'side': side, // 'buy' or 'sell'
1847
+ };
1848
+ const response = await this.privateSpotPostCancelOrders (this.extend (request, params));
1849
+ //
1850
+ // {
1851
+ // "code": 1000,
1852
+ // "trace":"886fb6ae-456b-4654-b4e0-d681ac05cea1",
1853
+ // "message": "OK",
1854
+ // "data": {}
1855
+ // }
1856
+ //
1857
+ return response;
1858
+ }
1859
+
1860
+ async cancelOrders (ids, symbol = undefined, params = {}) {
1861
+ if (symbol === undefined) {
1862
+ throw new ArgumentsRequired (this.id + ' canelOrders() requires a symbol argument');
1863
+ }
1864
+ await this.loadMarkets ();
1865
+ const market = this.market (symbol);
1866
+ if (!market['contract']) {
1867
+ throw new NotSupported (this.id + ' cancelOrders() does not support ' + market['type'] + ' orders, only contract orders are accepted');
1868
+ }
1869
+ const orders = [];
1870
+ for (let i = 0; i < ids.length; i++) {
1871
+ orders.push (parseInt (ids[i]));
1872
+ }
1873
+ const request = {
1874
+ 'orders': orders,
1875
+ };
1876
+ const response = await this.privateContractPostCancelOrders (this.extend (request, params));
1877
+ //
1878
+ // spot
1879
+ //
1880
+ // {
1881
+ // "code": 1000,
1882
+ // "trace":"886fb6ae-456b-4654-b4e0-d681ac05cea1",
1883
+ // "message": "OK",
1884
+ // "data": {
1885
+ // "result": true
1886
+ // }
1887
+ // }
1888
+ //
1889
+ // contract
1890
+ //
1891
+ // {
1892
+ // "code": 1000,
1893
+ // "trace":"886fb6ae-456b-4654-b4e0-d681ac05cea1",
1894
+ // "message": "OK",
1895
+ // "data": {
1896
+ // "succeed": [
1897
+ // 2707219612
1898
+ // ],
1899
+ // "failed": []
1900
+ // }
1901
+ // }
1902
+ //
1903
+ return response;
1904
+ }
1905
+
1906
+ async fetchOrdersByStatus (status, symbol = undefined, since = undefined, limit = undefined, params = {}) {
1907
+ if (symbol === undefined) {
1908
+ throw new ArgumentsRequired (this.id + ' fetchOrdersByStatus() requires a symbol argument');
1909
+ }
1910
+ await this.loadMarkets ();
1911
+ const market = this.market (symbol);
1912
+ const [ marketType, query ] = this.handleMarketTypeAndParams ('fetchOrdersByStatus', market, params);
1913
+ const request = {};
1914
+ if (market['spot']) {
1915
+ request['symbol'] = market['id'];
1916
+ request['offset'] = 1; // max offset * limit < 500
1917
+ request['limit'] = 100; // max limit is 100
1918
+ // 1 = Order failure
1919
+ // 2 = Placing order
1920
+ // 3 = Order failure, Freeze failure
1921
+ // 4 = Order success, Pending for fulfilment
1922
+ // 5 = Partially filled
1923
+ // 6 = Fully filled
1924
+ // 7 = Canceling
1925
+ // 8 = Canceled
1926
+ // 9 = Outstanding (4 and 5)
1927
+ // 10 = 6 and 8
1928
+ if (status === 'open') {
1929
+ request['status'] = 9;
1930
+ } else if (status === 'closed') {
1931
+ request['status'] = 6;
1932
+ } else if (status === 'canceled') {
1933
+ request['status'] = 8;
1934
+ } else {
1935
+ request['status'] = status;
1936
+ }
1937
+ } else if (market['swap'] || market['future']) {
1938
+ request['contractID'] = market['id'];
1939
+ // request['offset'] = 1;
1940
+ if (limit !== undefined) {
1941
+ request['size'] = limit; // max 60
1942
+ }
1943
+ // 0 = All
1944
+ // 1 = Submitting
1945
+ // 2 = Commissioned
1946
+ // 3 = 1 and 2
1947
+ // 4 = Completed
1948
+ if (status === 'open') {
1949
+ request['status'] = 3;
1950
+ } else if (status === 'closed') {
1951
+ request['status'] = 4;
1952
+ } else {
1953
+ request['status'] = status;
1954
+ }
1955
+ }
1956
+ const method = this.getSupportedMapping (marketType, {
1957
+ 'spot': 'privateSpotGetOrders',
1958
+ 'swap': 'privateContractGetUserOrders',
1959
+ 'future': 'privateContractGetUserOrders',
1960
+ });
1961
+ const response = await this[method] (this.extend (request, query));
1962
+ //
1963
+ // spot
1964
+ //
1965
+ // {
1966
+ // "message":"OK",
1967
+ // "code":1000,
1968
+ // "trace":"70e7d427-7436-4fb8-8cdd-97e1f5eadbe9",
1969
+ // "data":{
1970
+ // "current_page":1,
1971
+ // "orders":[
1972
+ // {
1973
+ // "order_id":2147601241,
1974
+ // "symbol":"BTC_USDT",
1975
+ // "create_time":1591099963000,
1976
+ // "side":"sell",
1977
+ // "type":"limit",
1978
+ // "price":"9000.00",
1979
+ // "price_avg":"0.00",
1980
+ // "size":"1.00000",
1981
+ // "notional":"9000.00000000",
1982
+ // "filled_notional":"0.00000000",
1983
+ // "filled_size":"0.00000",
1984
+ // "status":"4"
1985
+ // }
1986
+ // ]
1987
+ // }
1988
+ // }
1989
+ //
1990
+ // contract
1991
+ //
1992
+ // {
1993
+ // "code": 1000,
1994
+ // "trace":"886fb6ae-456b-4654-b4e0-d681ac05cea1",
1995
+ // "message": "OK",
1996
+ // "data": {
1997
+ // "orders": [
1998
+ // {
1999
+ // "order_id": 10284160,
2000
+ // "contract_id": 1,
2001
+ // "price": "8",
2002
+ // "vol": "4",
2003
+ // "done_avg_price": "0",
2004
+ // "done_vol": "0",
2005
+ // "way": 1,
2006
+ // "category": 1,
2007
+ // "open_type": 2,
2008
+ // "make_fee": "0",
2009
+ // "take_fee": "0",
2010
+ // "origin": "",
2011
+ // "created_at": "2018-07-17T07:24:13.410507Z",
2012
+ // "finished_at": null,
2013
+ // "status": 2,
2014
+ // "errno": 0
2015
+ // }
2016
+ // ]
2017
+ // }
2018
+ // }
2019
+ //
2020
+ const data = this.safeValue (response, 'data', {});
2021
+ const orders = this.safeValue (data, 'orders', []);
2022
+ return this.parseOrders (orders, market, since, limit);
2023
+ }
2024
+
2025
+ async fetchOpenOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) {
2026
+ return await this.fetchOrdersByStatus ('open', symbol, since, limit, params);
2027
+ }
2028
+
2029
+ async fetchClosedOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) {
2030
+ return await this.fetchOrdersByStatus ('closed', symbol, since, limit, params);
2031
+ }
2032
+
2033
+ async fetchCanceledOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) {
2034
+ return await this.fetchOrdersByStatus ('canceled', symbol, since, limit, params);
2035
+ }
2036
+
2037
+ async fetchOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) {
2038
+ if (symbol === undefined) {
2039
+ throw new ArgumentsRequired (this.id + ' fetchOrders() requires a symbol argument');
2040
+ }
2041
+ await this.loadMarkets ();
2042
+ const market = this.market (symbol);
2043
+ if (!(market['swap'] || market['future'])) {
2044
+ throw new NotSupported (this.id + ' fetchOrders() does not support ' + market['type'] + ' markets, only contracts are supported');
2045
+ }
2046
+ return await this.fetchOrdersByStatus (0, symbol, since, limit, params);
2047
+ }
2048
+
2049
+ async fetchOrder (id, symbol = undefined, params = {}) {
2050
+ if (symbol === undefined) {
2051
+ throw new ArgumentsRequired (this.id + ' fetchOrder() requires a symbol argument');
2052
+ }
2053
+ await this.loadMarkets ();
2054
+ const request = {};
2055
+ const market = this.market (symbol);
2056
+ if (typeof id !== 'string') {
2057
+ id = id.toString ();
2058
+ }
2059
+ const [ marketType, query ] = this.handleMarketTypeAndParams ('fetchOrder', market, params);
2060
+ if (market['spot']) {
2061
+ request['symbol'] = market['id'];
2062
+ request['order_id'] = id;
2063
+ } else if (market['swap'] || market['future']) {
2064
+ request['contractID'] = market['id'];
2065
+ request['orderID'] = id;
2066
+ }
2067
+ const method = this.getSupportedMapping (marketType, {
2068
+ 'spot': 'privateSpotGetOrderDetail',
2069
+ 'swap': 'privateContractGetUserOrderInfo',
2070
+ 'future': 'privateContractGetUserOrderInfo',
2071
+ });
2072
+ const response = await this[method] (this.extend (request, query));
2073
+ //
2074
+ // spot
2075
+ //
2076
+ // {
2077
+ // "message":"OK",
2078
+ // "code":1000,
2079
+ // "trace":"a27c2cb5-ead4-471d-8455-1cfeda054ea6",
2080
+ // "data": {
2081
+ // "order_id":1736871726781,
2082
+ // "symbol":"BTC_USDT",
2083
+ // "create_time":1591096004000,
2084
+ // "side":"sell",
2085
+ // "type":"market",
2086
+ // "price":"0.00",
2087
+ // "price_avg":"0.00",
2088
+ // "size":"0.02000",
2089
+ // "notional":"0.00000000",
2090
+ // "filled_notional":"0.00000000",
2091
+ // "filled_size":"0.00000",
2092
+ // "status":"8"
2093
+ // }
2094
+ // }
2095
+ //
2096
+ // contract
2097
+ //
2098
+ // {
2099
+ // "code": 1000,
2100
+ // "trace":"886fb6ae-456b-4654-b4e0-d681ac05cea1",
2101
+ // "message": "OK",
2102
+ // "data": {
2103
+ // "orders": [
2104
+ // {
2105
+ // "order_id": 10539098,
2106
+ // "contract_id": 1,
2107
+ // "position_id": 10539088,
2108
+ // "account_id": 10,
2109
+ // "price": "16",
2110
+ // "vol": "1",
2111
+ // "done_avg_price": "16",
2112
+ // "done_vol": "1",
2113
+ // "way": 3,
2114
+ // "category": 1,
2115
+ // "make_fee": "0.00025",
2116
+ // "take_fee": "0.012",
2117
+ // "origin": "",
2118
+ // "created_at": "2018-07-23T11:55:56.715305Z",
2119
+ // "finished_at": "2018-07-23T11:55:56.763941Z",
2120
+ // "status": 4,
2121
+ // "errno": 0
2122
+ // }
2123
+ // ]
2124
+ // }
2125
+ // }
2126
+ //
2127
+ const data = this.safeValue (response, 'data');
2128
+ if ('orders' in data) {
2129
+ const orders = this.safeValue (data, 'orders', []);
2130
+ const firstOrder = this.safeValue (orders, 0);
2131
+ if (firstOrder === undefined) {
2132
+ throw new OrderNotFound (this.id + ' fetchOrder() could not find ' + symbol + ' order id ' + id);
2133
+ }
2134
+ return this.parseOrder (firstOrder, market);
2135
+ } else {
2136
+ return this.parseOrder (data, market);
2137
+ }
2138
+ }
2139
+
2140
+ async fetchDepositAddress (code, params = {}) {
2141
+ await this.loadMarkets ();
2142
+ const currency = this.currency (code);
2143
+ const request = {
2144
+ 'currency': currency['id'],
2145
+ };
2146
+ if (code === 'USDT') {
2147
+ const defaultNetworks = this.safeValue (this.options, 'defaultNetworks');
2148
+ const defaultNetwork = this.safeStringUpper (defaultNetworks, code);
2149
+ const networks = this.safeValue (this.options, 'networks', {});
2150
+ let network = this.safeStringUpper (params, 'network', defaultNetwork); // this line allows the user to specify either ERC20 or ETH
2151
+ network = this.safeString (networks, network, network); // handle ERC20>ETH alias
2152
+ if (network !== undefined) {
2153
+ request['currency'] += '-' + network; // when network the currency need to be changed to currency + '-' + network https://developer-pro.bitmart.com/en/account/withdraw_apply.html on the end of page
2154
+ params = this.omit (params, 'network');
2155
+ }
2156
+ }
2157
+ const response = await this.privateAccountGetDepositAddress (this.extend (request, params));
2158
+ //
2159
+ // {
2160
+ // "message":"OK",
2161
+ // "code":1000,
2162
+ // "trace":"0e6edd79-f77f-4251-abe5-83ba75d06c1a",
2163
+ // "data":{
2164
+ // "currency":"USDT-TRC20",
2165
+ // "chain":"USDT-TRC20",
2166
+ // "address":"TGR3ghy2b5VLbyAYrmiE15jasR6aPHTvC5",
2167
+ // "address_memo":""
2168
+ // }
2169
+ // }
2170
+ //
2171
+ const data = this.safeValue (response, 'data', {});
2172
+ const address = this.safeString (data, 'address');
2173
+ const tag = this.safeString (data, 'address_memo');
2174
+ const chain = this.safeString (data, 'chain');
2175
+ let network = undefined;
2176
+ if (chain !== undefined) {
2177
+ const parts = chain.split ('-');
2178
+ const networkId = this.safeString (parts, 1);
2179
+ network = this.safeNetwork (networkId);
2180
+ }
2181
+ this.checkAddress (address);
2182
+ return {
2183
+ 'currency': code,
2184
+ 'address': address,
2185
+ 'tag': tag,
2186
+ 'network': network,
2187
+ 'info': response,
2188
+ };
2189
+ }
2190
+
2191
+ safeNetwork (networkId) {
2192
+ // TODO: parse
2193
+ return networkId;
2194
+ }
2195
+
2196
+ async withdraw (code, amount, address, tag = undefined, params = {}) {
2197
+ [ tag, params ] = this.handleWithdrawTagAndParams (tag, params);
2198
+ this.checkAddress (address);
2199
+ await this.loadMarkets ();
2200
+ const currency = this.currency (code);
2201
+ const request = {
2202
+ 'currency': currency['id'],
2203
+ 'amount': amount,
2204
+ 'destination': 'To Digital Address', // To Digital Address, To Binance, To OKEX
2205
+ 'address': address,
2206
+ };
2207
+ if (tag !== undefined) {
2208
+ request['address_memo'] = tag;
2209
+ }
2210
+ if (code === 'USDT') {
2211
+ const defaultNetworks = this.safeValue (this.options, 'defaultNetworks');
2212
+ const defaultNetwork = this.safeStringUpper (defaultNetworks, code);
2213
+ const networks = this.safeValue (this.options, 'networks', {});
2214
+ let network = this.safeStringUpper (params, 'network', defaultNetwork); // this line allows the user to specify either ERC20 or ETH
2215
+ network = this.safeString (networks, network, network); // handle ERC20>ETH alias
2216
+ if (network !== undefined) {
2217
+ request['currency'] += '-' + network; // when network the currency need to be changed to currency + '-' + network https://developer-pro.bitmart.com/en/account/withdraw_apply.html on the end of page
2218
+ params = this.omit (params, 'network');
2219
+ }
2220
+ }
2221
+ const response = await this.privateAccountPostWithdrawApply (this.extend (request, params));
2222
+ //
2223
+ // {
2224
+ // "code": 1000,
2225
+ // "trace":"886fb6ae-456b-4654-b4e0-d681ac05cea1",
2226
+ // "message": "OK",
2227
+ // "data": {
2228
+ // "withdraw_id": "121212"
2229
+ // }
2230
+ // }
2231
+ //
2232
+ const data = this.safeValue (response, 'data');
2233
+ const transaction = this.parseTransaction (data, currency);
2234
+ return this.extend (transaction, {
2235
+ 'code': code,
2236
+ 'address': address,
2237
+ 'tag': tag,
2238
+ });
2239
+ }
2240
+
2241
+ async fetchTransactionsByType (type, code = undefined, since = undefined, limit = undefined, params = {}) {
2242
+ await this.loadMarkets ();
2243
+ if (limit === undefined) {
2244
+ limit = 50; // max 50
2245
+ }
2246
+ const request = {
2247
+ 'operation_type': type, // deposit or withdraw
2248
+ 'offset': 1,
2249
+ 'limit': limit,
2250
+ };
2251
+ let currency = undefined;
2252
+ if (code !== undefined) {
2253
+ currency = this.currency (code);
2254
+ request['currency'] = currency['id'];
2255
+ }
2256
+ const response = await this.privateAccountGetDepositWithdrawHistory (this.extend (request, params));
2257
+ //
2258
+ // {
2259
+ // "message":"OK",
2260
+ // "code":1000,
2261
+ // "trace":"142bf92a-fc50-4689-92b6-590886f90b97",
2262
+ // "data":{
2263
+ // "records":[
2264
+ // {
2265
+ // "withdraw_id":"1679952",
2266
+ // "deposit_id":"",
2267
+ // "operation_type":"withdraw",
2268
+ // "currency":"BMX",
2269
+ // "apply_time":1588867374000,
2270
+ // "arrival_amount":"59.000000000000",
2271
+ // "fee":"1.000000000000",
2272
+ // "status":0,
2273
+ // "address":"0xe57b69a8776b37860407965B73cdFFBDFe668Bb5",
2274
+ // "address_memo":"",
2275
+ // "tx_id":""
2276
+ // },
2277
+ // ]
2278
+ // }
2279
+ // }
2280
+ //
2281
+ const data = this.safeValue (response, 'data', {});
2282
+ const records = this.safeValue (data, 'records', []);
2283
+ return this.parseTransactions (records, currency, since, limit);
2284
+ }
2285
+
2286
+ async fetchDeposit (id, code = undefined, params = {}) {
2287
+ await this.loadMarkets ();
2288
+ const request = {
2289
+ 'id': id,
2290
+ };
2291
+ const response = await this.privateAccountGetDepositWithdrawDetail (this.extend (request, params));
2292
+ //
2293
+ // {
2294
+ // "message":"OK",
2295
+ // "code":1000,
2296
+ // "trace":"f7f74924-14da-42a6-b7f2-d3799dd9a612",
2297
+ // "data":{
2298
+ // "record":{
2299
+ // "withdraw_id":"",
2300
+ // "deposit_id":"1679952",
2301
+ // "operation_type":"deposit",
2302
+ // "currency":"BMX",
2303
+ // "apply_time":1588867374000,
2304
+ // "arrival_amount":"59.000000000000",
2305
+ // "fee":"1.000000000000",
2306
+ // "status":0,
2307
+ // "address":"0xe57b69a8776b37860407965B73cdFFBDFe668Bb5",
2308
+ // "address_memo":"",
2309
+ // "tx_id":""
2310
+ // }
2311
+ // }
2312
+ // }
2313
+ //
2314
+ const data = this.safeValue (response, 'data', {});
2315
+ const record = this.safeValue (data, 'record', {});
2316
+ return this.parseTransaction (record);
2317
+ }
2318
+
2319
+ async fetchDeposits (code = undefined, since = undefined, limit = undefined, params = {}) {
2320
+ return await this.fetchTransactionsByType ('deposit', code, since, limit, params);
2321
+ }
2322
+
2323
+ async fetchWithdrawal (id, code = undefined, params = {}) {
2324
+ await this.loadMarkets ();
2325
+ const request = {
2326
+ 'id': id,
2327
+ };
2328
+ const response = await this.privateAccountGetDepositWithdrawDetail (this.extend (request, params));
2329
+ //
2330
+ // {
2331
+ // "message":"OK",
2332
+ // "code":1000,
2333
+ // "trace":"f7f74924-14da-42a6-b7f2-d3799dd9a612",
2334
+ // "data":{
2335
+ // "record":{
2336
+ // "withdraw_id":"1679952",
2337
+ // "deposit_id":"",
2338
+ // "operation_type":"withdraw",
2339
+ // "currency":"BMX",
2340
+ // "apply_time":1588867374000,
2341
+ // "arrival_amount":"59.000000000000",
2342
+ // "fee":"1.000000000000",
2343
+ // "status":0,
2344
+ // "address":"0xe57b69a8776b37860407965B73cdFFBDFe668Bb5",
2345
+ // "address_memo":"",
2346
+ // "tx_id":""
2347
+ // }
2348
+ // }
2349
+ // }
2350
+ //
2351
+ const data = this.safeValue (response, 'data', {});
2352
+ const record = this.safeValue (data, 'record', {});
2353
+ return this.parseTransaction (record);
2354
+ }
2355
+
2356
+ async fetchWithdrawals (code = undefined, since = undefined, limit = undefined, params = {}) {
2357
+ return await this.fetchTransactionsByType ('withdraw', code, since, limit, params);
2358
+ }
2359
+
2360
+ parseTransactionStatus (status) {
2361
+ const statuses = {
2362
+ '0': 'pending', // Create
2363
+ '1': 'pending', // Submitted, waiting for withdrawal
2364
+ '2': 'pending', // Processing
2365
+ '3': 'ok', // Success
2366
+ '4': 'canceled', // Cancel
2367
+ '5': 'failed', // Fail
2368
+ };
2369
+ return this.safeString (statuses, status, status);
2370
+ }
2371
+
2372
+ parseTransaction (transaction, currency = undefined) {
2373
+ //
2374
+ // withdraw
2375
+ //
2376
+ // {
2377
+ // "withdraw_id": "121212"
2378
+ // }
2379
+ //
2380
+ // fetchDeposits, fetchWithdrawals, fetchWithdrawal
2381
+ //
2382
+ // {
2383
+ // "withdraw_id":"1679952",
2384
+ // "deposit_id":"",
2385
+ // "operation_type":"withdraw",
2386
+ // "currency":"BMX",
2387
+ // "apply_time":1588867374000,
2388
+ // "arrival_amount":"59.000000000000",
2389
+ // "fee":"1.000000000000",
2390
+ // "status":0,
2391
+ // "address":"0xe57b69a8776b37860407965B73cdFFBDFe668Bb5",
2392
+ // "address_memo":"",
2393
+ // "tx_id":""
2394
+ // }
2395
+ //
2396
+ let id = undefined;
2397
+ const withdrawId = this.safeString (transaction, 'withdraw_id');
2398
+ const depositId = this.safeString (transaction, 'deposit_id');
2399
+ let type = undefined;
2400
+ if ((withdrawId !== undefined) && (withdrawId !== '')) {
2401
+ type = 'withdraw';
2402
+ id = withdrawId;
2403
+ } else if ((depositId !== undefined) && (depositId !== '')) {
2404
+ type = 'deposit';
2405
+ id = depositId;
2406
+ }
2407
+ const amount = this.safeNumber (transaction, 'arrival_amount');
2408
+ const timestamp = this.safeInteger (transaction, 'apply_time');
2409
+ const currencyId = this.safeString (transaction, 'currency');
2410
+ const code = this.safeCurrencyCode (currencyId, currency);
2411
+ const status = this.parseTransactionStatus (this.safeString (transaction, 'status'));
2412
+ const feeCost = this.safeNumber (transaction, 'fee');
2413
+ let fee = undefined;
2414
+ if (feeCost !== undefined) {
2415
+ fee = {
2416
+ 'cost': feeCost,
2417
+ 'currency': code,
2418
+ };
2419
+ }
2420
+ let txid = this.safeString (transaction, 'tx_id');
2421
+ if (txid === '') {
2422
+ txid = undefined;
2423
+ }
2424
+ const address = this.safeString (transaction, 'address');
2425
+ const tag = this.safeString (transaction, 'address_memo');
2426
+ return {
2427
+ 'info': transaction,
2428
+ 'id': id,
2429
+ 'currency': code,
2430
+ 'amount': amount,
2431
+ 'network': undefined,
2432
+ 'address': address,
2433
+ 'addressFrom': undefined,
2434
+ 'addressTo': undefined,
2435
+ 'tag': tag,
2436
+ 'tagFrom': undefined,
2437
+ 'tagTo': undefined,
2438
+ 'status': status,
2439
+ 'type': type,
2440
+ 'updated': undefined,
2441
+ 'txid': txid,
2442
+ 'timestamp': timestamp,
2443
+ 'datetime': this.iso8601 (timestamp),
2444
+ 'fee': fee,
2445
+ };
2446
+ }
2447
+
2448
+ nonce () {
2449
+ return this.milliseconds ();
2450
+ }
2451
+
2452
+ sign (path, api = 'public', method = 'GET', params = {}, headers = undefined, body = undefined) {
2453
+ const access = this.safeString (api, 0);
2454
+ const type = this.safeString (api, 1);
2455
+ const baseUrl = this.implodeHostname (this.urls['api']['rest']);
2456
+ let url = baseUrl + '/' + type;
2457
+ if (type !== 'system') {
2458
+ url += '/' + this.version;
2459
+ }
2460
+ url += '/' + this.implodeParams (path, params);
2461
+ const query = this.omit (params, this.extractParams (path));
2462
+ let queryString = '';
2463
+ const getOrDelete = (method === 'GET') || (method === 'DELETE');
2464
+ if (getOrDelete) {
2465
+ if (Object.keys (query).length) {
2466
+ queryString = this.urlencode (query);
2467
+ url += '?' + queryString;
2468
+ }
2469
+ }
2470
+ if (access === 'private') {
2471
+ this.checkRequiredCredentials ();
2472
+ const timestamp = this.milliseconds ().toString ();
2473
+ headers = {
2474
+ 'X-BM-KEY': this.apiKey,
2475
+ 'X-BM-TIMESTAMP': timestamp,
2476
+ 'Content-Type': 'application/json',
2477
+ };
2478
+ if (!getOrDelete) {
2479
+ body = this.json (query);
2480
+ queryString = body;
2481
+ }
2482
+ const auth = timestamp + '#' + this.uid + '#' + queryString;
2483
+ const signature = this.hmac (this.encode (auth), this.encode (this.secret));
2484
+ headers['X-BM-SIGN'] = signature;
2485
+ }
2486
+ return { 'url': url, 'method': method, 'body': body, 'headers': headers };
2487
+ }
2488
+
2489
+ handleErrors (code, reason, url, method, headers, body, response, requestHeaders, requestBody) {
2490
+ if (response === undefined) {
2491
+ return;
2492
+ }
2493
+ //
2494
+ // spot
2495
+ //
2496
+ // {"message":"Bad Request [to is empty]","code":50000,"trace":"f9d46e1b-4edb-4d07-a06e-4895fb2fc8fc","data":{}}
2497
+ // {"message":"Bad Request [from is empty]","code":50000,"trace":"579986f7-c93a-4559-926b-06ba9fa79d76","data":{}}
2498
+ // {"message":"Kline size over 500","code":50004,"trace":"d625caa8-e8ca-4bd2-b77c-958776965819","data":{}}
2499
+ // {"message":"Balance not enough","code":50020,"trace":"7c709d6a-3292-462c-98c5-32362540aeef","data":{}}
2500
+ //
2501
+ // contract
2502
+ //
2503
+ // {"errno":"OK","message":"INVALID_PARAMETER","code":49998,"trace":"eb5ebb54-23cd-4de2-9064-e090b6c3b2e3","data":null}
2504
+ //
2505
+ const message = this.safeString (response, 'message');
2506
+ const errorCode = this.safeString (response, 'code');
2507
+ if (((errorCode !== undefined) && (errorCode !== '1000')) || ((message !== undefined) && (message !== 'OK'))) {
2508
+ const feedback = this.id + ' ' + body;
2509
+ this.throwExactlyMatchedException (this.exceptions['exact'], errorCode, feedback);
2510
+ this.throwBroadlyMatchedException (this.exceptions['broad'], errorCode, feedback);
2511
+ this.throwExactlyMatchedException (this.exceptions['exact'], message, feedback);
2512
+ this.throwBroadlyMatchedException (this.exceptions['broad'], message, feedback);
2513
+ throw new ExchangeError (feedback); // unknown message
2514
+ }
2515
+ }
2516
+ };