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/bitrue.js ADDED
@@ -0,0 +1,1747 @@
1
+ 'use strict';
2
+
3
+ // ---------------------------------------------------------------------------
4
+
5
+ const Exchange = require ('./base/Exchange');
6
+ const { ExchangeError, ArgumentsRequired, ExchangeNotAvailable, InsufficientFunds, OrderNotFound, InvalidOrder, DDoSProtection, InvalidNonce, AuthenticationError, RateLimitExceeded, PermissionDenied, BadRequest, BadSymbol, AccountSuspended, OrderImmediatelyFillable, OnMaintenance } = require ('./base/errors');
7
+ const { TRUNCATE } = require ('./base/functions/number');
8
+ const Precise = require ('./base/Precise');
9
+
10
+ // ---------------------------------------------------------------------------
11
+
12
+ module.exports = class bitrue extends Exchange {
13
+ describe () {
14
+ return this.deepExtend (super.describe (), {
15
+ 'id': 'bitrue',
16
+ 'name': 'Bitrue',
17
+ 'countries': [ 'SG' ], // Singapore, Malta
18
+ 'rateLimit': 1000,
19
+ 'certified': false,
20
+ 'version': 'v1',
21
+ // new metainfo interface
22
+ 'has': {
23
+ 'CORS': undefined,
24
+ 'spot': true,
25
+ 'margin': false,
26
+ 'swap': undefined, // has but unimplemented
27
+ 'future': undefined,
28
+ 'option': false,
29
+ 'cancelAllOrders': false,
30
+ 'cancelOrder': true,
31
+ 'createOrder': true,
32
+ 'createStopLimitOrder': true,
33
+ 'createStopMarketOrder': true,
34
+ 'createStopOrder': true,
35
+ 'fetchBalance': true,
36
+ 'fetchBidsAsks': true,
37
+ 'fetchBorrowRate': false,
38
+ 'fetchBorrowRateHistories': false,
39
+ 'fetchBorrowRateHistory': false,
40
+ 'fetchBorrowRates': false,
41
+ 'fetchBorrowRatesPerSymbol': false,
42
+ 'fetchClosedOrders': true,
43
+ 'fetchCurrencies': true,
44
+ 'fetchDepositAddress': false,
45
+ 'fetchDeposits': true,
46
+ 'fetchFundingFees': false,
47
+ 'fetchMarkets': true,
48
+ 'fetchMyTrades': true,
49
+ 'fetchOHLCV': 'emulated',
50
+ 'fetchOpenOrders': true,
51
+ 'fetchOrder': true,
52
+ 'fetchOrderBook': true,
53
+ 'fetchOrders': false,
54
+ 'fetchStatus': true,
55
+ 'fetchTicker': true,
56
+ 'fetchTickers': true,
57
+ 'fetchTime': true,
58
+ 'fetchTrades': true,
59
+ 'fetchTradingFee': false,
60
+ 'fetchTradingFees': false,
61
+ 'fetchTransactions': false,
62
+ 'fetchTransfers': false,
63
+ 'fetchWithdrawals': true,
64
+ 'transfer': false,
65
+ 'withdraw': true,
66
+ },
67
+ 'timeframes': {
68
+ '1m': '1m',
69
+ '5m': '5m',
70
+ '15m': '15m',
71
+ '30m': '30m',
72
+ '1h': '1h',
73
+ '1d': '1d',
74
+ '1w': '1w',
75
+ '1M': '1M',
76
+ },
77
+ 'urls': {
78
+ 'logo': 'https://user-images.githubusercontent.com/1294454/139516488-243a830d-05dd-446b-91c6-c1f18fe30c63.jpg',
79
+ 'api': {
80
+ 'v1': 'https://www.bitrue.com/api/v1',
81
+ 'v2': 'https://www.bitrue.com/api/v2',
82
+ 'kline': 'https://www.bitrue.com/kline-api',
83
+ },
84
+ 'www': 'https://www.bitrue.com',
85
+ 'referral': 'https://www.bitrue.com/activity/task/task-landing?inviteCode=EZWETQE&cn=900000',
86
+ 'doc': [
87
+ 'https://github.com/Bitrue-exchange/bitrue-official-api-docs',
88
+ ],
89
+ 'fees': 'https://bitrue.zendesk.com/hc/en-001/articles/4405479952537',
90
+ },
91
+ 'api': {
92
+ 'kline': {
93
+ 'public': {
94
+ 'get': {
95
+ 'public.json': 1,
96
+ 'public{currency}.json': 1,
97
+ },
98
+ },
99
+ },
100
+ 'v1': {
101
+ 'public': {
102
+ 'get': {
103
+ 'ping': 1,
104
+ 'time': 1,
105
+ 'exchangeInfo': 1,
106
+ 'depth': { 'cost': 1, 'byLimit': [ [ 100, 1 ], [ 500, 5 ], [ 1000, 10 ] ] },
107
+ 'trades': 1,
108
+ 'historicalTrades': 5,
109
+ 'aggTrades': 1,
110
+ 'ticker/24hr': { 'cost': 1, 'noSymbol': 40 },
111
+ 'ticker/price': { 'cost': 1, 'noSymbol': 2 },
112
+ 'ticker/bookTicker': { 'cost': 1, 'noSymbol': 2 },
113
+ },
114
+ },
115
+ 'private': {
116
+ 'get': {
117
+ 'order': 1,
118
+ 'openOrders': 1,
119
+ 'allOrders': 5,
120
+ 'account': 5,
121
+ 'myTrades': { 'cost': 5, 'noSymbol': 40 },
122
+ 'etf/net-value/{symbol}': 1,
123
+ 'withdraw/history': 1,
124
+ 'deposit/history': 1,
125
+ },
126
+ 'post': {
127
+ 'order': 4,
128
+ 'withdraw/commit': 1,
129
+ },
130
+ 'delete': {
131
+ 'order': 1,
132
+ },
133
+ },
134
+ },
135
+ 'v2': {
136
+ 'private': {
137
+ 'get': {
138
+ 'myTrades': 5,
139
+ },
140
+ },
141
+ },
142
+ },
143
+ 'fees': {
144
+ 'trading': {
145
+ 'feeSide': 'get',
146
+ 'tierBased': false,
147
+ 'percentage': true,
148
+ 'taker': this.parseNumber ('0.00098'),
149
+ 'maker': this.parseNumber ('0.00098'),
150
+ },
151
+ 'future': {
152
+ 'trading': {
153
+ 'feeSide': 'quote',
154
+ 'tierBased': true,
155
+ 'percentage': true,
156
+ 'taker': this.parseNumber ('0.000400'),
157
+ 'maker': this.parseNumber ('0.000200'),
158
+ 'tiers': {
159
+ 'taker': [
160
+ [ this.parseNumber ('0'), this.parseNumber ('0.000400') ],
161
+ [ this.parseNumber ('250'), this.parseNumber ('0.000400') ],
162
+ [ this.parseNumber ('2500'), this.parseNumber ('0.000350') ],
163
+ [ this.parseNumber ('7500'), this.parseNumber ('0.000320') ],
164
+ [ this.parseNumber ('22500'), this.parseNumber ('0.000300') ],
165
+ [ this.parseNumber ('50000'), this.parseNumber ('0.000270') ],
166
+ [ this.parseNumber ('100000'), this.parseNumber ('0.000250') ],
167
+ [ this.parseNumber ('200000'), this.parseNumber ('0.000220') ],
168
+ [ this.parseNumber ('400000'), this.parseNumber ('0.000200') ],
169
+ [ this.parseNumber ('750000'), this.parseNumber ('0.000170') ],
170
+ ],
171
+ 'maker': [
172
+ [ this.parseNumber ('0'), this.parseNumber ('0.000200') ],
173
+ [ this.parseNumber ('250'), this.parseNumber ('0.000160') ],
174
+ [ this.parseNumber ('2500'), this.parseNumber ('0.000140') ],
175
+ [ this.parseNumber ('7500'), this.parseNumber ('0.000120') ],
176
+ [ this.parseNumber ('22500'), this.parseNumber ('0.000100') ],
177
+ [ this.parseNumber ('50000'), this.parseNumber ('0.000080') ],
178
+ [ this.parseNumber ('100000'), this.parseNumber ('0.000060') ],
179
+ [ this.parseNumber ('200000'), this.parseNumber ('0.000040') ],
180
+ [ this.parseNumber ('400000'), this.parseNumber ('0.000020') ],
181
+ [ this.parseNumber ('750000'), this.parseNumber ('0') ],
182
+ ],
183
+ },
184
+ },
185
+ },
186
+ 'delivery': {
187
+ 'trading': {
188
+ 'feeSide': 'base',
189
+ 'tierBased': true,
190
+ 'percentage': true,
191
+ 'taker': this.parseNumber ('0.000500'),
192
+ 'maker': this.parseNumber ('0.000100'),
193
+ 'tiers': {
194
+ 'taker': [
195
+ [ this.parseNumber ('0'), this.parseNumber ('0.000500') ],
196
+ [ this.parseNumber ('250'), this.parseNumber ('0.000450') ],
197
+ [ this.parseNumber ('2500'), this.parseNumber ('0.000400') ],
198
+ [ this.parseNumber ('7500'), this.parseNumber ('0.000300') ],
199
+ [ this.parseNumber ('22500'), this.parseNumber ('0.000250') ],
200
+ [ this.parseNumber ('50000'), this.parseNumber ('0.000240') ],
201
+ [ this.parseNumber ('100000'), this.parseNumber ('0.000240') ],
202
+ [ this.parseNumber ('200000'), this.parseNumber ('0.000240') ],
203
+ [ this.parseNumber ('400000'), this.parseNumber ('0.000240') ],
204
+ [ this.parseNumber ('750000'), this.parseNumber ('0.000240') ],
205
+ ],
206
+ 'maker': [
207
+ [ this.parseNumber ('0'), this.parseNumber ('0.000100') ],
208
+ [ this.parseNumber ('250'), this.parseNumber ('0.000080') ],
209
+ [ this.parseNumber ('2500'), this.parseNumber ('0.000050') ],
210
+ [ this.parseNumber ('7500'), this.parseNumber ('0.0000030') ],
211
+ [ this.parseNumber ('22500'), this.parseNumber ('0') ],
212
+ [ this.parseNumber ('50000'), this.parseNumber ('-0.000050') ],
213
+ [ this.parseNumber ('100000'), this.parseNumber ('-0.000060') ],
214
+ [ this.parseNumber ('200000'), this.parseNumber ('-0.000070') ],
215
+ [ this.parseNumber ('400000'), this.parseNumber ('-0.000080') ],
216
+ [ this.parseNumber ('750000'), this.parseNumber ('-0.000090') ],
217
+ ],
218
+ },
219
+ },
220
+ },
221
+ },
222
+ // exchange-specific options
223
+ 'options': {
224
+ // 'fetchTradesMethod': 'publicGetAggTrades', // publicGetTrades, publicGetHistoricalTrades
225
+ 'fetchMyTradesMethod': 'v2PrivateGetMyTrades', // v1PrivateGetMyTrades
226
+ 'hasAlreadyAuthenticatedSuccessfully': false,
227
+ 'recvWindow': 5 * 1000, // 5 sec, binance default
228
+ 'timeDifference': 0, // the difference between system clock and Binance clock
229
+ 'adjustForTimeDifference': false, // controls the adjustment logic upon instantiation
230
+ 'parseOrderToPrecision': false, // force amounts and costs in parseOrder to precision
231
+ 'newOrderRespType': {
232
+ 'market': 'FULL', // 'ACK' for order id, 'RESULT' for full order or 'FULL' for order with fills
233
+ 'limit': 'FULL', // we change it from 'ACK' by default to 'FULL' (returns immediately if limit is not hit)
234
+ },
235
+ 'networks': {
236
+ 'SPL': 'SOLANA',
237
+ 'SOL': 'SOLANA',
238
+ 'DOGE': 'dogecoin',
239
+ 'ADA': 'Cardano',
240
+ },
241
+ },
242
+ 'commonCurrencies': {
243
+ 'MIM': 'MIM Swarm',
244
+ },
245
+ // https://binance-docs.github.io/apidocs/spot/en/#error-codes-2
246
+ 'exceptions': {
247
+ 'exact': {
248
+ 'System is under maintenance.': OnMaintenance, // {"code":1,"msg":"System is under maintenance."}
249
+ 'System abnormality': ExchangeError, // {"code":-1000,"msg":"System abnormality"}
250
+ 'You are not authorized to execute this request.': PermissionDenied, // {"msg":"You are not authorized to execute this request."}
251
+ 'API key does not exist': AuthenticationError,
252
+ 'Order would trigger immediately.': OrderImmediatelyFillable,
253
+ 'Stop price would trigger immediately.': OrderImmediatelyFillable, // {"code":-2010,"msg":"Stop price would trigger immediately."}
254
+ 'Order would immediately match and take.': OrderImmediatelyFillable, // {"code":-2010,"msg":"Order would immediately match and take."}
255
+ 'Account has insufficient balance for requested action.': InsufficientFunds,
256
+ 'Rest API trading is not enabled.': ExchangeNotAvailable,
257
+ "You don't have permission.": PermissionDenied, // {"msg":"You don't have permission.","success":false}
258
+ 'Market is closed.': ExchangeNotAvailable, // {"code":-1013,"msg":"Market is closed."}
259
+ 'Too many requests. Please try again later.': DDoSProtection, // {"msg":"Too many requests. Please try again later.","success":false}
260
+ '-1000': ExchangeNotAvailable, // {"code":-1000,"msg":"An unknown error occured while processing the request."}
261
+ '-1001': ExchangeNotAvailable, // 'Internal error; unable to process your request. Please try again.'
262
+ '-1002': AuthenticationError, // 'You are not authorized to execute this request.'
263
+ '-1003': RateLimitExceeded, // {"code":-1003,"msg":"Too much request weight used, current limit is 1200 request weight per 1 MINUTE. Please use the websocket for live updates to avoid polling the API."}
264
+ '-1013': InvalidOrder, // createOrder -> 'invalid quantity'/'invalid price'/MIN_NOTIONAL
265
+ '-1015': RateLimitExceeded, // 'Too many new orders; current limit is %s orders per %s.'
266
+ '-1016': ExchangeNotAvailable, // 'This service is no longer available.',
267
+ '-1020': BadRequest, // 'This operation is not supported.'
268
+ '-1021': InvalidNonce, // 'your time is ahead of server'
269
+ '-1022': AuthenticationError, // {"code":-1022,"msg":"Signature for this request is not valid."}
270
+ '-1100': BadRequest, // createOrder(symbol, 1, asdf) -> 'Illegal characters found in parameter 'price'
271
+ '-1101': BadRequest, // Too many parameters; expected %s and received %s.
272
+ '-1102': BadRequest, // Param %s or %s must be sent, but both were empty
273
+ '-1103': BadRequest, // An unknown parameter was sent.
274
+ '-1104': BadRequest, // Not all sent parameters were read, read 8 parameters but was sent 9
275
+ '-1105': BadRequest, // Parameter %s was empty.
276
+ '-1106': BadRequest, // Parameter %s sent when not required.
277
+ '-1111': BadRequest, // Precision is over the maximum defined for this asset.
278
+ '-1112': InvalidOrder, // No orders on book for symbol.
279
+ '-1114': BadRequest, // TimeInForce parameter sent when not required.
280
+ '-1115': BadRequest, // Invalid timeInForce.
281
+ '-1116': BadRequest, // Invalid orderType.
282
+ '-1117': BadRequest, // Invalid side.
283
+ '-1118': BadRequest, // New client order ID was empty.
284
+ '-1119': BadRequest, // Original client order ID was empty.
285
+ '-1120': BadRequest, // Invalid interval.
286
+ '-1121': BadSymbol, // Invalid symbol.
287
+ '-1125': AuthenticationError, // This listenKey does not exist.
288
+ '-1127': BadRequest, // More than %s hours between startTime and endTime.
289
+ '-1128': BadRequest, // {"code":-1128,"msg":"Combination of optional parameters invalid."}
290
+ '-1130': BadRequest, // Data sent for paramter %s is not valid.
291
+ '-1131': BadRequest, // recvWindow must be less than 60000
292
+ '-2008': AuthenticationError, // {"code":-2008,"msg":"Invalid Api-Key ID."}
293
+ '-2010': ExchangeError, // generic error code for createOrder -> 'Account has insufficient balance for requested action.', {"code":-2010,"msg":"Rest API trading is not enabled."}, etc...
294
+ '-2011': OrderNotFound, // cancelOrder(1, 'BTC/USDT') -> 'UNKNOWN_ORDER'
295
+ '-2013': OrderNotFound, // fetchOrder (1, 'BTC/USDT') -> 'Order does not exist'
296
+ '-2014': AuthenticationError, // { "code":-2014, "msg": "API-key format invalid." }
297
+ '-2015': AuthenticationError, // "Invalid API-key, IP, or permissions for action."
298
+ '-2019': InsufficientFunds, // {"code":-2019,"msg":"Margin is insufficient."}
299
+ '-3005': InsufficientFunds, // {"code":-3005,"msg":"Transferring out not allowed. Transfer out amount exceeds max amount."}
300
+ '-3006': InsufficientFunds, // {"code":-3006,"msg":"Your borrow amount has exceed maximum borrow amount."}
301
+ '-3008': InsufficientFunds, // {"code":-3008,"msg":"Borrow not allowed. Your borrow amount has exceed maximum borrow amount."}
302
+ '-3010': ExchangeError, // {"code":-3010,"msg":"Repay not allowed. Repay amount exceeds borrow amount."}
303
+ '-3015': ExchangeError, // {"code":-3015,"msg":"Repay amount exceeds borrow amount."}
304
+ '-3022': AccountSuspended, // You account's trading is banned.
305
+ '-4028': BadRequest, // {"code":-4028,"msg":"Leverage 100 is not valid"}
306
+ '-3020': InsufficientFunds, // {"code":-3020,"msg":"Transfer out amount exceeds max amount."}
307
+ '-3041': InsufficientFunds, // {"code":-3041,"msg":"Balance is not enough"}
308
+ '-5013': InsufficientFunds, // Asset transfer failed: insufficient balance"
309
+ '-11008': InsufficientFunds, // {"code":-11008,"msg":"Exceeding the account's maximum borrowable limit."}
310
+ '-4051': InsufficientFunds, // {"code":-4051,"msg":"Isolated balance insufficient."}
311
+ },
312
+ 'broad': {
313
+ 'has no operation privilege': PermissionDenied,
314
+ 'MAX_POSITION': InvalidOrder, // {"code":-2010,"msg":"Filter failure: MAX_POSITION"}
315
+ },
316
+ },
317
+ });
318
+ }
319
+
320
+ costToPrecision (symbol, cost) {
321
+ return this.decimalToPrecision (cost, TRUNCATE, this.markets[symbol]['precision']['quote'], this.precisionMode, this.paddingMode);
322
+ }
323
+
324
+ currencyToPrecision (code, fee) {
325
+ // info is available in currencies only if the user has configured his api keys
326
+ if (this.safeValue (this.currencies[code], 'precision') !== undefined) {
327
+ return this.decimalToPrecision (fee, TRUNCATE, this.currencies[code]['precision'], this.precisionMode, this.paddingMode);
328
+ } else {
329
+ return this.numberToString (fee);
330
+ }
331
+ }
332
+
333
+ nonce () {
334
+ return this.milliseconds () - this.options['timeDifference'];
335
+ }
336
+
337
+ async fetchStatus (params = {}) {
338
+ const response = await this.v1PublicGetPing (params);
339
+ //
340
+ // empty means working status.
341
+ //
342
+ // {}
343
+ //
344
+ const keys = Object.keys (response);
345
+ const keysLength = keys.length;
346
+ const formattedStatus = keysLength ? 'maintenance' : 'ok';
347
+ return {
348
+ 'status': formattedStatus,
349
+ 'updated': this.milliseconds (),
350
+ 'eta': undefined,
351
+ 'url': undefined,
352
+ 'info': response,
353
+ };
354
+ }
355
+
356
+ async fetchTime (params = {}) {
357
+ const response = await this.v1PublicGetTime (params);
358
+ //
359
+ // {
360
+ // "serverTime":1635467280514
361
+ // }
362
+ //
363
+ return this.safeInteger (response, 'serverTime');
364
+ }
365
+
366
+ safeNetwork (networkId) {
367
+ const uppercaseNetworkId = networkId.toUpperCase ();
368
+ const networksById = {
369
+ 'Aeternity': 'Aeternity',
370
+ 'AION': 'AION',
371
+ 'Algorand': 'Algorand',
372
+ 'ASK': 'ASK',
373
+ 'ATOM': 'ATOM',
374
+ 'AVAX C-Chain': 'AVAX C-Chain',
375
+ 'bch': 'bch',
376
+ 'BCH': 'BCH',
377
+ 'BEP2': 'BEP2',
378
+ 'BEP20': 'BEP20',
379
+ 'Bitcoin': 'Bitcoin',
380
+ 'BRP20': 'BRP20',
381
+ 'Cardano': 'ADA',
382
+ 'CasinoCoin': 'CasinoCoin',
383
+ 'CasinoCoin XRPL': 'CasinoCoin XRPL',
384
+ 'Contentos': 'Contentos',
385
+ 'Dash': 'Dash',
386
+ 'Decoin': 'Decoin',
387
+ 'DeFiChain': 'DeFiChain',
388
+ 'DGB': 'DGB',
389
+ 'Divi': 'Divi',
390
+ 'dogecoin': 'DOGE',
391
+ 'EOS': 'EOS',
392
+ 'ERC20': 'ERC20',
393
+ 'ETC': 'ETC',
394
+ 'Filecoin': 'Filecoin',
395
+ 'FREETON': 'FREETON',
396
+ 'HBAR': 'HBAR',
397
+ 'Hedera Hashgraph': 'Hedera Hashgraph',
398
+ 'HRC20': 'HRC20',
399
+ 'ICON': 'ICON',
400
+ 'ICP': 'ICP',
401
+ 'Ignis': 'Ignis',
402
+ 'Internet Computer': 'Internet Computer',
403
+ 'IOTA': 'IOTA',
404
+ 'KAVA': 'KAVA',
405
+ 'KSM': 'KSM',
406
+ 'LiteCoin': 'LiteCoin',
407
+ 'Luna': 'Luna',
408
+ 'MATIC': 'MATIC',
409
+ 'Mobile Coin': 'Mobile Coin',
410
+ 'MonaCoin': 'MonaCoin',
411
+ 'Monero': 'Monero',
412
+ 'NEM': 'NEM',
413
+ 'NEP5': 'NEP5',
414
+ 'OMNI': 'OMNI',
415
+ 'PAC': 'PAC',
416
+ 'Polkadot': 'Polkadot',
417
+ 'Ravencoin': 'Ravencoin',
418
+ 'Safex': 'Safex',
419
+ 'SOLANA': 'SOL',
420
+ 'Songbird': 'Songbird',
421
+ 'Stellar Lumens': 'Stellar Lumens',
422
+ 'Symbol': 'Symbol',
423
+ 'Tezos': 'XTZ',
424
+ 'theta': 'theta',
425
+ 'THETA': 'THETA',
426
+ 'TRC20': 'TRC20',
427
+ 'VeChain': 'VeChain',
428
+ 'VECHAIN': 'VECHAIN',
429
+ 'Wanchain': 'Wanchain',
430
+ 'XinFin Network': 'XinFin Network',
431
+ 'XRP': 'XRP',
432
+ 'XRPL': 'XRPL',
433
+ 'ZIL': 'ZIL',
434
+ };
435
+ return this.safeString2 (networksById, networkId, uppercaseNetworkId, networkId);
436
+ }
437
+
438
+ async fetchCurrencies (params = {}) {
439
+ const response = await this.v1PublicGetExchangeInfo (params);
440
+ //
441
+ // {
442
+ // "timezone":"CTT",
443
+ // "serverTime":1635464889117,
444
+ // "rateLimits":[
445
+ // {"rateLimitType":"REQUESTS_WEIGHT","interval":"MINUTES","limit":6000},
446
+ // {"rateLimitType":"ORDERS","interval":"SECONDS","limit":150},
447
+ // {"rateLimitType":"ORDERS","interval":"DAYS","limit":288000},
448
+ // ],
449
+ // "exchangeFilters":[],
450
+ // "symbols":[
451
+ // {
452
+ // "symbol":"SHABTC",
453
+ // "status":"TRADING",
454
+ // "baseAsset":"sha",
455
+ // "baseAssetPrecision":0,
456
+ // "quoteAsset":"btc",
457
+ // "quotePrecision":10,
458
+ // "orderTypes":["MARKET","LIMIT"],
459
+ // "icebergAllowed":false,
460
+ // "filters":[
461
+ // {"filterType":"PRICE_FILTER","minPrice":"0.00000001349","maxPrice":"0.00000017537","priceScale":10},
462
+ // {"filterType":"LOT_SIZE","minQty":"1.0","minVal":"0.00020","maxQty":"1000000000","volumeScale":0},
463
+ // ],
464
+ // "defaultPrice":"0.0000006100",
465
+ // },
466
+ // ],
467
+ // "coins":[
468
+ // {
469
+ // "coin":"sbr",
470
+ // "coinFulName":"Saber",
471
+ // "enableWithdraw":true,
472
+ // "enableDeposit":true,
473
+ // "chains":["SOLANA"],
474
+ // "withdrawFee":"2.0",
475
+ // "minWithdraw":"5.0",
476
+ // "maxWithdraw":"1000000000000000",
477
+ // },
478
+ // ],
479
+ // }
480
+ //
481
+ const result = {};
482
+ const coins = this.safeValue (response, 'coins', []);
483
+ for (let i = 0; i < coins.length; i++) {
484
+ const currency = coins[i];
485
+ const id = this.safeString (currency, 'coin');
486
+ const name = this.safeString (currency, 'coinFulName');
487
+ const code = this.safeCurrencyCode (id);
488
+ const enableDeposit = this.safeValue (currency, 'enableDeposit');
489
+ const enableWithdraw = this.safeValue (currency, 'enableWithdraw');
490
+ const precision = undefined;
491
+ const networkIds = this.safeValue (currency, 'chains', []);
492
+ const networks = {};
493
+ for (let j = 0; j < networkIds.length; j++) {
494
+ const networkId = networkIds[j];
495
+ const network = this.safeNetwork (networkId);
496
+ networks[network] = {
497
+ 'info': networkId,
498
+ 'id': networkId,
499
+ 'network': network,
500
+ 'active': undefined,
501
+ 'fee': undefined,
502
+ 'precision': undefined,
503
+ 'limits': {
504
+ 'withdraw': {
505
+ 'min': undefined,
506
+ 'max': undefined,
507
+ },
508
+ },
509
+ };
510
+ }
511
+ const active = (enableWithdraw && enableDeposit);
512
+ result[code] = {
513
+ 'id': id,
514
+ 'name': name,
515
+ 'code': code,
516
+ 'precision': precision,
517
+ 'info': currency,
518
+ 'active': active,
519
+ 'deposit': enableDeposit,
520
+ 'withdraw': enableWithdraw,
521
+ 'networks': networks,
522
+ 'fee': this.safeNumber (currency, 'withdrawFee'),
523
+ // 'fees': fees,
524
+ 'limits': {
525
+ 'withdraw': {
526
+ 'min': this.safeNumber (currency, 'minWithdraw'),
527
+ 'max': this.safeNumber (currency, 'maxWithdraw'),
528
+ },
529
+ },
530
+ };
531
+ }
532
+ return result;
533
+ }
534
+
535
+ async fetchMarkets (params = {}) {
536
+ const response = await this.v1PublicGetExchangeInfo (params);
537
+ //
538
+ // {
539
+ // "timezone":"CTT",
540
+ // "serverTime":1635464889117,
541
+ // "rateLimits":[
542
+ // {"rateLimitType":"REQUESTS_WEIGHT","interval":"MINUTES","limit":6000},
543
+ // {"rateLimitType":"ORDERS","interval":"SECONDS","limit":150},
544
+ // {"rateLimitType":"ORDERS","interval":"DAYS","limit":288000},
545
+ // ],
546
+ // "exchangeFilters":[],
547
+ // "symbols":[
548
+ // {
549
+ // "symbol":"SHABTC",
550
+ // "status":"TRADING",
551
+ // "baseAsset":"sha",
552
+ // "baseAssetPrecision":0,
553
+ // "quoteAsset":"btc",
554
+ // "quotePrecision":10,
555
+ // "orderTypes":["MARKET","LIMIT"],
556
+ // "icebergAllowed":false,
557
+ // "filters":[
558
+ // {"filterType":"PRICE_FILTER","minPrice":"0.00000001349","maxPrice":"0.00000017537","priceScale":10},
559
+ // {"filterType":"LOT_SIZE","minQty":"1.0","minVal":"0.00020","maxQty":"1000000000","volumeScale":0},
560
+ // ],
561
+ // "defaultPrice":"0.0000006100",
562
+ // },
563
+ // ],
564
+ // "coins":[
565
+ // {
566
+ // "coin":"sbr",
567
+ // "coinFulName":"Saber",
568
+ // "enableWithdraw":true,
569
+ // "enableDeposit":true,
570
+ // "chains":["SOLANA"],
571
+ // "withdrawFee":"2.0",
572
+ // "minWithdraw":"5.0",
573
+ // "maxWithdraw":"1000000000000000",
574
+ // },
575
+ // ],
576
+ // }
577
+ //
578
+ if (this.options['adjustForTimeDifference']) {
579
+ await this.loadTimeDifference ();
580
+ }
581
+ const markets = this.safeValue (response, 'symbols', []);
582
+ const result = [];
583
+ for (let i = 0; i < markets.length; i++) {
584
+ const market = markets[i];
585
+ const id = this.safeString (market, 'symbol');
586
+ const lowercaseId = this.safeStringLower (market, 'symbol');
587
+ const baseId = this.safeString (market, 'baseAsset');
588
+ const quoteId = this.safeString (market, 'quoteAsset');
589
+ const base = this.safeCurrencyCode (baseId);
590
+ const quote = this.safeCurrencyCode (quoteId);
591
+ const filters = this.safeValue (market, 'filters', []);
592
+ const filtersByType = this.indexBy (filters, 'filterType');
593
+ const status = this.safeString (market, 'status');
594
+ const priceDefault = this.safeInteger (market, 'pricePrecision');
595
+ const amountDefault = this.safeInteger (market, 'quantityPrecision');
596
+ const priceFilter = this.safeValue (filtersByType, 'PRICE_FILTER', {});
597
+ const amountFilter = this.safeValue (filtersByType, 'LOT_SIZE', {});
598
+ const entry = {
599
+ 'id': id,
600
+ 'lowercaseId': lowercaseId,
601
+ 'symbol': base + '/' + quote,
602
+ 'base': base,
603
+ 'quote': quote,
604
+ 'settle': undefined,
605
+ 'baseId': baseId,
606
+ 'quoteId': quoteId,
607
+ 'settleId': undefined,
608
+ 'type': 'spot',
609
+ 'spot': true,
610
+ 'margin': false,
611
+ 'swap': false,
612
+ 'future': false,
613
+ 'option': false,
614
+ 'active': (status === 'TRADING'),
615
+ 'contract': false,
616
+ 'linear': undefined,
617
+ 'inverse': undefined,
618
+ 'contractSize': undefined,
619
+ 'expiry': undefined,
620
+ 'expiryDatetime': undefined,
621
+ 'strike': undefined,
622
+ 'optionType': undefined,
623
+ 'precision': {
624
+ 'amount': this.safeInteger (amountFilter, 'volumeScale', amountDefault),
625
+ 'price': this.safeInteger (priceFilter, 'priceScale', priceDefault),
626
+ 'base': this.safeInteger (market, 'baseAssetPrecision'),
627
+ 'quote': this.safeInteger (market, 'quotePrecision'),
628
+ },
629
+ 'limits': {
630
+ 'leverage': {
631
+ 'min': undefined,
632
+ 'max': undefined,
633
+ },
634
+ 'amount': {
635
+ 'min': this.safeNumber (amountFilter, 'minQty'),
636
+ 'max': this.safeNumber (amountFilter, 'maxQty'),
637
+ },
638
+ 'price': {
639
+ 'min': this.safeNumber (priceFilter, 'minPrice'),
640
+ 'max': this.safeNumber (priceFilter, 'maxPrice'),
641
+ },
642
+ 'cost': {
643
+ 'min': this.safeNumber (amountFilter, 'minVal'),
644
+ 'max': undefined,
645
+ },
646
+ },
647
+ 'info': market,
648
+ };
649
+ result.push (entry);
650
+ }
651
+ return result;
652
+ }
653
+
654
+ parseBalance (response) {
655
+ const result = {
656
+ 'info': response,
657
+ };
658
+ const timestamp = this.safeInteger (response, 'updateTime');
659
+ const balances = this.safeValue2 (response, 'balances', []);
660
+ for (let i = 0; i < balances.length; i++) {
661
+ const balance = balances[i];
662
+ const currencyId = this.safeString (balance, 'asset');
663
+ const code = this.safeCurrencyCode (currencyId);
664
+ const account = this.account ();
665
+ account['free'] = this.safeString (balance, 'free');
666
+ account['used'] = this.safeString (balance, 'locked');
667
+ result[code] = account;
668
+ }
669
+ result['timestamp'] = timestamp;
670
+ result['datetime'] = this.iso8601 (timestamp);
671
+ return this.safeBalance (result);
672
+ }
673
+
674
+ async fetchBalance (params = {}) {
675
+ await this.loadMarkets ();
676
+ const response = await this.v1PrivateGetAccount (params);
677
+ //
678
+ // {
679
+ // "makerCommission":0,
680
+ // "takerCommission":0,
681
+ // "buyerCommission":0,
682
+ // "sellerCommission":0,
683
+ // "updateTime":null,
684
+ // "balances":[
685
+ // {"asset":"sbr","free":"0","locked":"0"},
686
+ // {"asset":"ksm","free":"0","locked":"0"},
687
+ // {"asset":"neo3s","free":"0","locked":"0"},
688
+ // ],
689
+ // "canTrade":false,
690
+ // "canWithdraw":false,
691
+ // "canDeposit":false
692
+ // }
693
+ //
694
+ return this.parseBalance (response);
695
+ }
696
+
697
+ async fetchOrderBook (symbol, limit = undefined, params = {}) {
698
+ await this.loadMarkets ();
699
+ const market = this.market (symbol);
700
+ const request = {
701
+ 'symbol': market['id'],
702
+ };
703
+ if (limit !== undefined) {
704
+ request['limit'] = limit; // default 100, max 1000, see https://github.com/Bitrue-exchange/bitrue-official-api-docs#order-book
705
+ }
706
+ const response = await this.v1PublicGetDepth (this.extend (request, params));
707
+ //
708
+ // {
709
+ // "lastUpdateId":1635474910177,
710
+ // "bids":[
711
+ // ["61436.84","0.05",[]],
712
+ // ["61435.77","0.0124",[]],
713
+ // ["61434.88","0.012",[]],
714
+ // ],
715
+ // "asks":[
716
+ // ["61452.46","0.0001",[]],
717
+ // ["61452.47","0.0597",[]],
718
+ // ["61452.76","0.0713",[]],
719
+ // ]
720
+ // }
721
+ //
722
+ const orderbook = this.parseOrderBook (response, symbol);
723
+ orderbook['nonce'] = this.safeInteger (response, 'lastUpdateId');
724
+ return orderbook;
725
+ }
726
+
727
+ parseTicker (ticker, market = undefined) {
728
+ //
729
+ // fetchTicker
730
+ //
731
+ // {
732
+ // "id":397945892,
733
+ // "last":"1.143411",
734
+ // "lowestAsk":"1.144223",
735
+ // "highestBid":"1.141696",
736
+ // "percentChange":"-0.001432",
737
+ // "baseVolume":"338287",
738
+ // "quoteVolume":"415013.244366",
739
+ // "isFrozen":"0",
740
+ // "high24hr":"1.370087",
741
+ // "low24hr":"1.370087",
742
+ // }
743
+ //
744
+ const symbol = this.safeSymbol (undefined, market);
745
+ const last = this.safeString (ticker, 'last');
746
+ return this.safeTicker ({
747
+ 'symbol': symbol,
748
+ 'timestamp': undefined,
749
+ 'datetime': undefined,
750
+ 'high': this.safeString (ticker, 'high24hr'),
751
+ 'low': this.safeString (ticker, 'low24hr'),
752
+ 'bid': this.safeString (ticker, 'highestBid'),
753
+ 'bidVolume': undefined,
754
+ 'ask': this.safeString (ticker, 'lowestAsk'),
755
+ 'askVolume': undefined,
756
+ 'vwap': undefined,
757
+ 'open': undefined,
758
+ 'close': last,
759
+ 'last': last,
760
+ 'previousClose': undefined,
761
+ 'change': undefined,
762
+ 'percentage': this.safeString (ticker, 'percentChange'),
763
+ 'average': undefined,
764
+ 'baseVolume': this.safeString (ticker, 'baseVolume'),
765
+ 'quoteVolume': this.safeString (ticker, 'quoteVolume'),
766
+ 'info': ticker,
767
+ }, market, false);
768
+ }
769
+
770
+ async fetchTicker (symbol, params = {}) {
771
+ await this.loadMarkets ();
772
+ const market = this.market (symbol);
773
+ const uppercaseBaseId = this.safeStringUpper (market, 'baseId');
774
+ const uppercaseQuoteId = this.safeStringUpper (market, 'quoteId');
775
+ const request = {
776
+ 'currency': uppercaseQuoteId,
777
+ 'command': 'returnTicker',
778
+ };
779
+ const response = await this.klinePublicGetPublicCurrencyJson (this.extend (request, params));
780
+ //
781
+ // {
782
+ // "code":"200",
783
+ // "msg":"success",
784
+ // "data":{
785
+ // "DODO3S_USDT":{
786
+ // "id":397945892,
787
+ // "last":"1.143411",
788
+ // "lowestAsk":"1.144223",
789
+ // "highestBid":"1.141696",
790
+ // "percentChange":"-0.001432",
791
+ // "baseVolume":"338287",
792
+ // "quoteVolume":"415013.244366",
793
+ // "isFrozen":"0",
794
+ // "high24hr":"1.370087",
795
+ // "low24hr":"1.370087"
796
+ // }
797
+ // }
798
+ // }
799
+ //
800
+ const data = this.safeValue (response, 'data', {});
801
+ const id = uppercaseBaseId + '_' + uppercaseQuoteId;
802
+ const ticker = this.safeValue (data, id);
803
+ if (ticker === undefined) {
804
+ throw new ExchangeError (this.id + ' fetchTicker() could not find the ticker for ' + market['symbol']);
805
+ }
806
+ return this.parseTicker (ticker, market);
807
+ }
808
+
809
+ async fetchBidsAsks (symbols = undefined, params = {}) {
810
+ await this.loadMarkets ();
811
+ const defaultType = this.safeString2 (this.options, 'fetchBidsAsks', 'defaultType', 'spot');
812
+ const type = this.safeString (params, 'type', defaultType);
813
+ const query = this.omit (params, 'type');
814
+ let method = undefined;
815
+ if (type === 'future') {
816
+ method = 'fapiPublicGetTickerBookTicker';
817
+ } else if (type === 'delivery') {
818
+ method = 'dapiPublicGetTickerBookTicker';
819
+ } else {
820
+ method = 'publicGetTickerBookTicker';
821
+ }
822
+ const response = await this[method] (query);
823
+ return this.parseTickers (response, symbols);
824
+ }
825
+
826
+ async fetchTickers (symbols = undefined, params = {}) {
827
+ await this.loadMarkets ();
828
+ const request = {
829
+ 'command': 'returnTicker',
830
+ };
831
+ const response = await this.klinePublicGetPublicJson (this.extend (request, params));
832
+ //
833
+ // {
834
+ // "code":"200",
835
+ // "msg":"success",
836
+ // "data":{
837
+ // "DODO3S_USDT":{
838
+ // "id":397945892,
839
+ // "last":"1.143411",
840
+ // "lowestAsk":"1.144223",
841
+ // "highestBid":"1.141696",
842
+ // "percentChange":"-0.001432",
843
+ // "baseVolume":"338287",
844
+ // "quoteVolume":"415013.244366",
845
+ // "isFrozen":"0",
846
+ // "high24hr":"1.370087",
847
+ // "low24hr":"1.370087"
848
+ // }
849
+ // }
850
+ // }
851
+ //
852
+ const data = this.safeValue (response, 'data', {});
853
+ const ids = Object.keys (data);
854
+ const result = {};
855
+ for (let i = 0; i < ids.length; i++) {
856
+ const id = ids[i];
857
+ const [ baseId, quoteId ] = id.split ('_');
858
+ const marketId = baseId + quoteId;
859
+ const market = this.safeMarket (marketId);
860
+ const rawTicker = this.safeValue (data, id);
861
+ const ticker = this.parseTicker (rawTicker, market);
862
+ const symbol = ticker['symbol'];
863
+ result[symbol] = ticker;
864
+ }
865
+ return result;
866
+ }
867
+
868
+ parseTrade (trade, market = undefined) {
869
+ //
870
+ // aggregate trades
871
+ //
872
+ // {
873
+ // "a": 26129, // Aggregate tradeId
874
+ // "p": "0.01633102", // Price
875
+ // "q": "4.70443515", // Quantity
876
+ // "f": 27781, // First tradeId
877
+ // "l": 27781, // Last tradeId
878
+ // "T": 1498793709153, // Timestamp
879
+ // "m": true, // Was the buyer the maker?
880
+ // "M": true // Was the trade the best price match?
881
+ // }
882
+ //
883
+ // recent public trades and old public trades
884
+ //
885
+ // {
886
+ // "id": 28457,
887
+ // "price": "4.00000100",
888
+ // "qty": "12.00000000",
889
+ // "time": 1499865549590,
890
+ // "isBuyerMaker": true,
891
+ // "isBestMatch": true
892
+ // }
893
+ //
894
+ // private trades
895
+ //
896
+ // {
897
+ // "symbol":"USDCUSDT",
898
+ // "id":20725156,
899
+ // "orderId":2880918576,
900
+ // "origClientOrderId":null,
901
+ // "price":"0.9996000000000000",
902
+ // "qty":"100.0000000000000000",
903
+ // "commission":null,
904
+ // "commissionAssert":null,
905
+ // "time":1635558511000,
906
+ // "isBuyer":false,
907
+ // "isMaker":false,
908
+ // "isBestMatch":true
909
+ // }
910
+ //
911
+ const timestamp = this.safeInteger2 (trade, 'T', 'time');
912
+ const priceString = this.safeString2 (trade, 'p', 'price');
913
+ const amountString = this.safeString2 (trade, 'q', 'qty');
914
+ const marketId = this.safeString (trade, 'symbol');
915
+ const symbol = this.safeSymbol (marketId, market);
916
+ let id = this.safeString2 (trade, 't', 'a');
917
+ id = this.safeString2 (trade, 'id', 'tradeId', id);
918
+ let side = undefined;
919
+ const orderId = this.safeString (trade, 'orderId');
920
+ if ('m' in trade) {
921
+ side = trade['m'] ? 'sell' : 'buy'; // this is reversed intentionally
922
+ } else if ('isBuyerMaker' in trade) {
923
+ side = trade['isBuyerMaker'] ? 'sell' : 'buy';
924
+ } else if ('side' in trade) {
925
+ side = this.safeStringLower (trade, 'side');
926
+ } else {
927
+ if ('isBuyer' in trade) {
928
+ side = trade['isBuyer'] ? 'buy' : 'sell'; // this is a true side
929
+ }
930
+ }
931
+ let fee = undefined;
932
+ if ('commission' in trade) {
933
+ fee = {
934
+ 'cost': this.safeString (trade, 'commission'),
935
+ 'currency': this.safeCurrencyCode (this.safeString (trade, 'commissionAssert')),
936
+ };
937
+ }
938
+ let takerOrMaker = undefined;
939
+ if ('isMaker' in trade) {
940
+ takerOrMaker = trade['isMaker'] ? 'maker' : 'taker';
941
+ }
942
+ if ('maker' in trade) {
943
+ takerOrMaker = trade['maker'] ? 'maker' : 'taker';
944
+ }
945
+ return this.safeTrade ({
946
+ 'info': trade,
947
+ 'timestamp': timestamp,
948
+ 'datetime': this.iso8601 (timestamp),
949
+ 'symbol': symbol,
950
+ 'id': id,
951
+ 'order': orderId,
952
+ 'type': undefined,
953
+ 'side': side,
954
+ 'takerOrMaker': takerOrMaker,
955
+ 'price': priceString,
956
+ 'amount': amountString,
957
+ 'cost': undefined,
958
+ 'fee': fee,
959
+ }, market);
960
+ }
961
+
962
+ async fetchTrades (symbol, since = undefined, limit = undefined, params = {}) {
963
+ await this.loadMarkets ();
964
+ const market = this.market (symbol);
965
+ const request = {
966
+ 'symbol': market['id'],
967
+ // 'limit': 100, // default 100, max = 1000
968
+ };
969
+ const method = this.safeString (this.options, 'fetchTradesMethod', 'v1PublicGetAggTrades');
970
+ if (limit !== undefined) {
971
+ request['limit'] = limit; // default 100, max 1000
972
+ }
973
+ //
974
+ // Caveats:
975
+ // - default limit (500) applies only if no other parameters set, trades up
976
+ // to the maximum limit may be returned to satisfy other parameters
977
+ // - if both limit and time window is set and time window contains more
978
+ // trades than the limit then the last trades from the window are returned
979
+ // - 'tradeId' accepted and returned by this method is "aggregate" trade id
980
+ // which is different from actual trade id
981
+ // - setting both fromId and time window results in error
982
+ const response = await this[method] (this.extend (request, params));
983
+ //
984
+ // aggregate trades
985
+ //
986
+ // [
987
+ // {
988
+ // "a": 26129, // Aggregate tradeId
989
+ // "p": "0.01633102", // Price
990
+ // "q": "4.70443515", // Quantity
991
+ // "f": 27781, // First tradeId
992
+ // "l": 27781, // Last tradeId
993
+ // "T": 1498793709153, // Timestamp
994
+ // "m": true, // Was the buyer the maker?
995
+ // "M": true // Was the trade the best price match?
996
+ // }
997
+ // ]
998
+ //
999
+ // recent public trades and historical public trades
1000
+ //
1001
+ // [
1002
+ // {
1003
+ // "id": 28457,
1004
+ // "price": "4.00000100",
1005
+ // "qty": "12.00000000",
1006
+ // "time": 1499865549590,
1007
+ // "isBuyerMaker": true,
1008
+ // "isBestMatch": true
1009
+ // }
1010
+ // ]
1011
+ //
1012
+ return this.parseTrades (response, market, since, limit);
1013
+ }
1014
+
1015
+ parseOrderStatus (status) {
1016
+ const statuses = {
1017
+ 'NEW': 'open',
1018
+ 'PARTIALLY_FILLED': 'open',
1019
+ 'FILLED': 'closed',
1020
+ 'CANCELED': 'canceled',
1021
+ 'PENDING_CANCEL': 'canceling', // currently unused
1022
+ 'REJECTED': 'rejected',
1023
+ 'EXPIRED': 'expired',
1024
+ };
1025
+ return this.safeString (statuses, status, status);
1026
+ }
1027
+
1028
+ parseOrder (order, market = undefined) {
1029
+ //
1030
+ // createOrder
1031
+ //
1032
+ // {
1033
+ // "symbol":"USDCUSDT",
1034
+ // "orderId":2878854881,
1035
+ // "clientOrderId":"",
1036
+ // "transactTime":1635551031276
1037
+ // }
1038
+ //
1039
+ // fetchOpenOrders
1040
+ //
1041
+ // {
1042
+ // "symbol":"USDCUSDT",
1043
+ // "orderId":"2878854881",
1044
+ // "clientOrderId":"",
1045
+ // "price":"1.1000000000000000",
1046
+ // "origQty":"100.0000000000000000",
1047
+ // "executedQty":"0.0000000000000000",
1048
+ // "cummulativeQuoteQty":"0.0000000000000000",
1049
+ // "status":"NEW",
1050
+ // "timeInForce":"",
1051
+ // "type":"LIMIT",
1052
+ // "side":"SELL",
1053
+ // "stopPrice":"",
1054
+ // "icebergQty":"",
1055
+ // "time":1635551031000,
1056
+ // "updateTime":1635551031000,
1057
+ // "isWorking":false
1058
+ // }
1059
+ //
1060
+ const status = this.parseOrderStatus (this.safeString (order, 'status'));
1061
+ const marketId = this.safeString (order, 'symbol');
1062
+ const symbol = this.safeSymbol (marketId, market);
1063
+ const filled = this.safeString (order, 'executedQty');
1064
+ let timestamp = undefined;
1065
+ let lastTradeTimestamp = undefined;
1066
+ if ('time' in order) {
1067
+ timestamp = this.safeInteger (order, 'time');
1068
+ } else if ('transactTime' in order) {
1069
+ timestamp = this.safeInteger (order, 'transactTime');
1070
+ } else if ('updateTime' in order) {
1071
+ if (status === 'open') {
1072
+ if (Precise.stringGt (filled, '0')) {
1073
+ lastTradeTimestamp = this.safeInteger (order, 'updateTime');
1074
+ } else {
1075
+ timestamp = this.safeInteger (order, 'updateTime');
1076
+ }
1077
+ }
1078
+ }
1079
+ const average = this.safeString (order, 'avgPrice');
1080
+ const price = this.safeString (order, 'price');
1081
+ const amount = this.safeString (order, 'origQty');
1082
+ // - Spot/Margin market: cummulativeQuoteQty
1083
+ // - Futures market: cumQuote.
1084
+ // Note this is not the actual cost, since Binance futures uses leverage to calculate margins.
1085
+ const cost = this.safeString2 (order, 'cummulativeQuoteQty', 'cumQuote');
1086
+ const id = this.safeString (order, 'orderId');
1087
+ let type = this.safeStringLower (order, 'type');
1088
+ const side = this.safeStringLower (order, 'side');
1089
+ const fills = this.safeValue (order, 'fills', []);
1090
+ let clientOrderId = this.safeString (order, 'clientOrderId');
1091
+ if (clientOrderId === '') {
1092
+ clientOrderId = undefined;
1093
+ }
1094
+ const timeInForce = this.safeString (order, 'timeInForce');
1095
+ const postOnly = (type === 'limit_maker') || (timeInForce === 'GTX');
1096
+ if (type === 'limit_maker') {
1097
+ type = 'limit';
1098
+ }
1099
+ const stopPriceString = this.safeString (order, 'stopPrice');
1100
+ const stopPrice = this.parseNumber (this.omitZero (stopPriceString));
1101
+ return this.safeOrder ({
1102
+ 'info': order,
1103
+ 'id': id,
1104
+ 'clientOrderId': clientOrderId,
1105
+ 'timestamp': timestamp,
1106
+ 'datetime': this.iso8601 (timestamp),
1107
+ 'lastTradeTimestamp': lastTradeTimestamp,
1108
+ 'symbol': symbol,
1109
+ 'type': type,
1110
+ 'timeInForce': timeInForce,
1111
+ 'postOnly': postOnly,
1112
+ 'side': side,
1113
+ 'price': price,
1114
+ 'stopPrice': stopPrice,
1115
+ 'amount': amount,
1116
+ 'cost': cost,
1117
+ 'average': average,
1118
+ 'filled': filled,
1119
+ 'remaining': undefined,
1120
+ 'status': status,
1121
+ 'fee': undefined,
1122
+ 'trades': fills,
1123
+ }, market);
1124
+ }
1125
+
1126
+ async createOrder (symbol, type, side, amount, price = undefined, params = {}) {
1127
+ await this.loadMarkets ();
1128
+ const market = this.market (symbol);
1129
+ const uppercaseType = type.toUpperCase ();
1130
+ const validOrderTypes = this.safeValue (market['info'], 'orderTypes');
1131
+ if (!this.inArray (uppercaseType, validOrderTypes)) {
1132
+ throw new InvalidOrder (this.id + ' ' + type + ' is not a valid order type in market ' + symbol);
1133
+ }
1134
+ const request = {
1135
+ 'symbol': market['id'],
1136
+ 'side': side.toUpperCase (),
1137
+ 'type': uppercaseType,
1138
+ // 'timeInForce': '',
1139
+ 'quantity': this.amountToPrecision (symbol, amount),
1140
+ // 'price': this.priceToPrecision (symbol, price),
1141
+ // 'newClientOrderId': clientOrderId, // automatically generated if not sent
1142
+ // 'stopPrice': this.priceToPrecision (symbol, 'stopPrice'),
1143
+ // 'icebergQty': this.amountToPrecision (symbol, icebergQty),
1144
+ };
1145
+ const clientOrderId = this.safeString2 (params, 'newClientOrderId', 'clientOrderId');
1146
+ if (clientOrderId !== undefined) {
1147
+ params = this.omit (params, [ 'newClientOrderId', 'clientOrderId' ]);
1148
+ request['newClientOrderId'] = clientOrderId;
1149
+ }
1150
+ if (uppercaseType === 'LIMIT') {
1151
+ if (price === undefined) {
1152
+ throw new InvalidOrder (this.id + ' createOrder() requires a price argument');
1153
+ }
1154
+ request['price'] = this.priceToPrecision (symbol, price);
1155
+ }
1156
+ const stopPrice = this.safeNumber (params, 'stopPrice');
1157
+ if (stopPrice !== undefined) {
1158
+ params = this.omit (params, 'stopPrice');
1159
+ request['stopPrice'] = this.priceToPrecision (symbol, stopPrice);
1160
+ }
1161
+ const response = await this.v1PrivatePostOrder (this.extend (request, params));
1162
+ //
1163
+ // {
1164
+ // "symbol":"USDCUSDT",
1165
+ // "orderId":2878854881,
1166
+ // "clientOrderId":"",
1167
+ // "transactTime":1635551031276
1168
+ // }
1169
+ //
1170
+ return this.parseOrder (response, market);
1171
+ }
1172
+
1173
+ async fetchOrder (id, symbol = undefined, params = {}) {
1174
+ if (symbol === undefined) {
1175
+ throw new ArgumentsRequired (this.id + ' fetchOrder() requires a symbol argument');
1176
+ }
1177
+ await this.loadMarkets ();
1178
+ const market = this.market (symbol);
1179
+ const request = {
1180
+ 'symbol': market['id'],
1181
+ };
1182
+ const clientOrderId = this.safeValue2 (params, 'origClientOrderId', 'clientOrderId');
1183
+ if (clientOrderId !== undefined) {
1184
+ request['origClientOrderId'] = clientOrderId;
1185
+ } else {
1186
+ request['orderId'] = id;
1187
+ }
1188
+ const query = this.omit (params, [ 'type', 'clientOrderId', 'origClientOrderId' ]);
1189
+ const response = await this.v1PrivateGetOrder (this.extend (request, query));
1190
+ return this.parseOrder (response, market);
1191
+ }
1192
+
1193
+ async fetchClosedOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) {
1194
+ if (symbol === undefined) {
1195
+ throw new ArgumentsRequired (this.id + ' fetchOrders() requires a symbol argument');
1196
+ }
1197
+ await this.loadMarkets ();
1198
+ const market = this.market (symbol);
1199
+ const request = {
1200
+ 'symbol': market['id'],
1201
+ // 'orderId': 123445, // long
1202
+ // 'startTime': since,
1203
+ // 'endTime': this.milliseconds (),
1204
+ // 'limit': limit, // default 100, max 1000
1205
+ };
1206
+ if (since !== undefined) {
1207
+ request['startTime'] = since;
1208
+ }
1209
+ if (limit !== undefined) {
1210
+ request['limit'] = limit; // default 100, max 1000
1211
+ }
1212
+ const response = await this.v1PrivateGetAllOrders (this.extend (request, params));
1213
+ //
1214
+ // [
1215
+ // {
1216
+ // "symbol": "LTCBTC",
1217
+ // "orderId": 1,
1218
+ // "clientOrderId": "myOrder1",
1219
+ // "price": "0.1",
1220
+ // "origQty": "1.0",
1221
+ // "executedQty": "0.0",
1222
+ // "cummulativeQuoteQty": "0.0",
1223
+ // "status": "NEW",
1224
+ // "timeInForce": "GTC",
1225
+ // "type": "LIMIT",
1226
+ // "side": "BUY",
1227
+ // "stopPrice": "0.0",
1228
+ // "icebergQty": "0.0",
1229
+ // "time": 1499827319559,
1230
+ // "updateTime": 1499827319559,
1231
+ // "isWorking": true
1232
+ // }
1233
+ // ]
1234
+ //
1235
+ return this.parseOrders (response, market, since, limit);
1236
+ }
1237
+
1238
+ async fetchOpenOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) {
1239
+ if (symbol === undefined) {
1240
+ throw new ArgumentsRequired (this.id + ' fetchOpenOrders() requires a symbol argument');
1241
+ }
1242
+ await this.loadMarkets ();
1243
+ const market = this.market (symbol);
1244
+ const request = {
1245
+ 'symbol': market['id'],
1246
+ };
1247
+ const response = await this.v1PrivateGetOpenOrders (this.extend (request, params));
1248
+ //
1249
+ // [
1250
+ // {
1251
+ // "symbol":"USDCUSDT",
1252
+ // "orderId":"2878854881",
1253
+ // "clientOrderId":"",
1254
+ // "price":"1.1000000000000000",
1255
+ // "origQty":"100.0000000000000000",
1256
+ // "executedQty":"0.0000000000000000",
1257
+ // "cummulativeQuoteQty":"0.0000000000000000",
1258
+ // "status":"NEW",
1259
+ // "timeInForce":"",
1260
+ // "type":"LIMIT",
1261
+ // "side":"SELL",
1262
+ // "stopPrice":"",
1263
+ // "icebergQty":"",
1264
+ // "time":1635551031000,
1265
+ // "updateTime":1635551031000,
1266
+ // "isWorking":false
1267
+ // }
1268
+ // ]
1269
+ //
1270
+ return this.parseOrders (response, market, since, limit);
1271
+ }
1272
+
1273
+ async cancelOrder (id, symbol = undefined, params = {}) {
1274
+ if (symbol === undefined) {
1275
+ throw new ArgumentsRequired (this.id + ' cancelOrder() requires a symbol argument');
1276
+ }
1277
+ await this.loadMarkets ();
1278
+ const market = this.market (symbol);
1279
+ const origClientOrderId = this.safeValue2 (params, 'origClientOrderId', 'clientOrderId');
1280
+ const request = {
1281
+ 'symbol': market['id'],
1282
+ // 'orderId': id,
1283
+ // 'origClientOrderId': id,
1284
+ // 'newClientOrderId': id,
1285
+ };
1286
+ if (origClientOrderId === undefined) {
1287
+ request['orderId'] = id;
1288
+ } else {
1289
+ request['origClientOrderId'] = origClientOrderId;
1290
+ }
1291
+ const query = this.omit (params, [ 'type', 'origClientOrderId', 'clientOrderId' ]);
1292
+ const response = await this.v1PrivateDeleteOrder (this.extend (request, query));
1293
+ //
1294
+ // {
1295
+ // "symbol": "LTCBTC",
1296
+ // "origClientOrderId": "myOrder1",
1297
+ // "orderId": 1,
1298
+ // "clientOrderId": "cancelMyOrder1"
1299
+ // }
1300
+ //
1301
+ return this.parseOrder (response, market);
1302
+ }
1303
+
1304
+ async fetchMyTrades (symbol = undefined, since = undefined, limit = undefined, params = {}) {
1305
+ const method = this.safeString (this.options, 'fetchMyTradesMethod', 'v2PrivateGetMyTrades');
1306
+ if ((symbol === undefined) && (method === 'v2PrivateGetMyTrades')) {
1307
+ throw new ArgumentsRequired (this.id + ' v2PrivateGetMyTrades() requires a symbol argument');
1308
+ }
1309
+ await this.loadMarkets ();
1310
+ const request = {
1311
+ // 'symbol': market['id'],
1312
+ // 'startTime': since,
1313
+ // 'endTime': this.milliseconds (),
1314
+ // 'fromId': 12345, // trade id to fetch from, most recent trades by default
1315
+ // 'limit': limit, // default 100, max 1000
1316
+ };
1317
+ let market = undefined;
1318
+ if (symbol !== undefined) {
1319
+ market = this.market (symbol);
1320
+ request['symbol'] = market['id'];
1321
+ }
1322
+ if (since !== undefined) {
1323
+ request['startTime'] = since;
1324
+ }
1325
+ if (limit !== undefined) {
1326
+ request['limit'] = limit;
1327
+ }
1328
+ const response = await this[method] (this.extend (request, params));
1329
+ //
1330
+ // [
1331
+ // {
1332
+ // "symbol":"USDCUSDT",
1333
+ // "id":20725156,
1334
+ // "orderId":2880918576,
1335
+ // "origClientOrderId":null,
1336
+ // "price":"0.9996000000000000",
1337
+ // "qty":"100.0000000000000000",
1338
+ // "commission":null,
1339
+ // "commissionAssert":null,
1340
+ // "time":1635558511000,
1341
+ // "isBuyer":false,
1342
+ // "isMaker":false,
1343
+ // "isBestMatch":true
1344
+ // }
1345
+ // ]
1346
+ //
1347
+ return this.parseTrades (response, market, since, limit);
1348
+ }
1349
+
1350
+ async fetchDeposits (code = undefined, since = undefined, limit = undefined, params = {}) {
1351
+ if (code === undefined) {
1352
+ throw new ArgumentsRequired (this.id + ' fetchDeposits() requires a code argument');
1353
+ }
1354
+ await this.loadMarkets ();
1355
+ const currency = this.currency (code);
1356
+ const request = {
1357
+ 'coin': currency['id'],
1358
+ 'status': 1, // 0 init, 1 finished, default 0
1359
+ // 'offset': 0,
1360
+ // 'limit': limit, // default 10, max 1000
1361
+ // 'startTime': since,
1362
+ // 'endTime': this.milliseconds (),
1363
+ };
1364
+ if (since !== undefined) {
1365
+ request['startTime'] = since;
1366
+ // request['endTime'] = this.sum (since, 7776000000);
1367
+ }
1368
+ if (limit !== undefined) {
1369
+ request['limit'] = limit;
1370
+ }
1371
+ const response = await this.v1PrivateGetDepositHistory (this.extend (request, params));
1372
+ //
1373
+ // {
1374
+ // "code":200,
1375
+ // "msg":"succ",
1376
+ // "data":[
1377
+ // {
1378
+ // "id":2659137,
1379
+ // "symbol":"USDC",
1380
+ // "amount":"200.0000000000000000",
1381
+ // "fee":"0.0E-15",
1382
+ // "createdAt":1635503169000,
1383
+ // "updatedAt":1635503202000,
1384
+ // "addressFrom":"0x2faf487a4414fe77e2327f0bf4ae2a264a776ad2",
1385
+ // "addressTo":"0x190ceccb1f8bfbec1749180f0ba8922b488d865b",
1386
+ // "txid":"0x9970aec41099ac385568859517308707bc7d716df8dabae7b52f5b17351c3ed0",
1387
+ // "confirmations":5,
1388
+ // "status":0,
1389
+ // "tagType":null,
1390
+ // },
1391
+ // {
1392
+ // "id":2659137,
1393
+ // "symbol": "XRP",
1394
+ // "amount": "20.0000000000000000",
1395
+ // "fee": "0.0E-15",
1396
+ // "createdAt": 1544669393000,
1397
+ // "updatedAt": 1544669413000,
1398
+ // "addressFrom": "",
1399
+ // "addressTo": "raLPjTYeGezfdb6crXZzcC8RkLBEwbBHJ5_18113641",
1400
+ // "txid": "515B23E1F9864D3AF7F5B4C4FCBED784BAE861854FAB95F4031922B6AAEFC7AC",
1401
+ // "confirmations": 7,
1402
+ // "status": 1,
1403
+ // "tagType": "Tag"
1404
+ // }
1405
+ // ]
1406
+ // }
1407
+ //
1408
+ const data = this.safeValue (response, 'data', []);
1409
+ return this.parseTransactions (data, currency, since, limit);
1410
+ }
1411
+
1412
+ async fetchWithdrawals (code = undefined, since = undefined, limit = undefined, params = {}) {
1413
+ if (code === undefined) {
1414
+ throw new ArgumentsRequired (this.id + ' fetchWithdrawals() requires a code argument');
1415
+ }
1416
+ await this.loadMarkets ();
1417
+ const currency = this.currency (code);
1418
+ const request = {
1419
+ 'coin': currency['id'],
1420
+ 'status': 5, // 0 init, 5 finished, 6 canceled, default 0
1421
+ // 'offset': 0,
1422
+ // 'limit': limit, // default 10, max 1000
1423
+ // 'startTime': since,
1424
+ // 'endTime': this.milliseconds (),
1425
+ };
1426
+ if (since !== undefined) {
1427
+ request['startTime'] = since;
1428
+ // request['endTime'] = this.sum (since, 7776000000);
1429
+ }
1430
+ if (limit !== undefined) {
1431
+ request['limit'] = limit;
1432
+ }
1433
+ const response = await this.v1PrivateGetWithdrawHistory (this.extend (request, params));
1434
+ //
1435
+ // {
1436
+ // "code": 200,
1437
+ // "msg": "succ",
1438
+ // "data": {
1439
+ // "msg": null,
1440
+ // "amount": 1000,
1441
+ // "fee": 1,
1442
+ // "ctime": null,
1443
+ // "coin": "usdt_erc20",
1444
+ // "addressTo": "0x2edfae3878d7b6db70ce4abed177ab2636f60c83"
1445
+ // }
1446
+ // }
1447
+ //
1448
+ const data = this.safeValue (response, 'data', {});
1449
+ return this.parseTransactions (data, currency);
1450
+ }
1451
+
1452
+ parseTransactionStatusByType (status, type = undefined) {
1453
+ const statusesByType = {
1454
+ 'deposit': {
1455
+ '0': 'pending',
1456
+ '1': 'ok',
1457
+ },
1458
+ 'withdrawal': {
1459
+ '0': 'pending', // Email Sent
1460
+ '5': 'ok', // Failure
1461
+ '6': 'canceled',
1462
+ },
1463
+ };
1464
+ const statuses = this.safeValue (statusesByType, type, {});
1465
+ return this.safeString (statuses, status, status);
1466
+ }
1467
+
1468
+ parseTransaction (transaction, currency = undefined) {
1469
+ //
1470
+ // fetchDeposits
1471
+ //
1472
+ // {
1473
+ // "symbol": "XRP",
1474
+ // "amount": "261.3361000000000000",
1475
+ // "fee": "0.0E-15",
1476
+ // "createdAt": 1548816979000,
1477
+ // "updatedAt": 1548816999000,
1478
+ // "addressFrom": "",
1479
+ // "addressTo": "raLPjTYeGezfdb6crXZzcC8RkLBEwbBHJ5_18113641",
1480
+ // "txid": "86D6EB68A7A28938BCE06BD348F8C07DEF500C5F7FE92069EF8C0551CE0F2C7D",
1481
+ // "confirmations": 8,
1482
+ // "status": 1,
1483
+ // "tagType": "Tag"
1484
+ // },
1485
+ // {
1486
+ // "symbol": "XRP",
1487
+ // "amount": "20.0000000000000000",
1488
+ // "fee": "0.0E-15",
1489
+ // "createdAt": 1544669393000,
1490
+ // "updatedAt": 1544669413000,
1491
+ // "addressFrom": "",
1492
+ // "addressTo": "raLPjTYeGezfdb6crXZzcC8RkLBEwbBHJ5_18113641",
1493
+ // "txid": "515B23E1F9864D3AF7F5B4C4FCBED784BAE861854FAB95F4031922B6AAEFC7AC",
1494
+ // "confirmations": 7,
1495
+ // "status": 1,
1496
+ // "tagType": "Tag"
1497
+ // }
1498
+ //
1499
+ // fetchWithdrawals
1500
+ //
1501
+ // {
1502
+ // "id": 183745,
1503
+ // "symbol": "usdt_erc20",
1504
+ // "amount": "8.4000000000000000",
1505
+ // "fee": "1.6000000000000000",
1506
+ // "payAmount": "0.0000000000000000",
1507
+ // "createdAt": 1595336441000,
1508
+ // "updatedAt": 1595336576000,
1509
+ // "addressFrom": "",
1510
+ // "addressTo": "0x2edfae3878d7b6db70ce4abed177ab2636f60c83",
1511
+ // "txid": "",
1512
+ // "confirmations": 0,
1513
+ // "status": 6,
1514
+ // "tagType": null
1515
+ // }
1516
+ //
1517
+ // withdraw
1518
+ //
1519
+ // {
1520
+ // "msg": null,
1521
+ // "amount": 1000,
1522
+ // "fee": 1,
1523
+ // "ctime": null,
1524
+ // "coin": "usdt_erc20",
1525
+ // "addressTo": "0x2edfae3878d7b6db70ce4abed177ab2636f60c83"
1526
+ // }
1527
+ //
1528
+ const id = this.safeString (transaction, 'id');
1529
+ const tagType = this.safeString (transaction, 'tagType');
1530
+ let addressTo = this.safeString (transaction, 'addressTo');
1531
+ if (addressTo === '') {
1532
+ addressTo = undefined;
1533
+ }
1534
+ let addressFrom = this.safeString (transaction, 'addressFrom');
1535
+ if (addressFrom === '') {
1536
+ addressFrom = undefined;
1537
+ }
1538
+ let tagTo = undefined;
1539
+ let tagFrom = undefined;
1540
+ if (tagType !== undefined) {
1541
+ if (addressTo !== undefined) {
1542
+ const parts = addressTo.split ('_');
1543
+ addressTo = this.safeString (parts, 0);
1544
+ tagTo = this.safeString (parts, 1);
1545
+ }
1546
+ if (addressFrom !== undefined) {
1547
+ const parts = addressFrom.split ('_');
1548
+ addressFrom = this.safeString (parts, 0);
1549
+ tagFrom = this.safeString (parts, 1);
1550
+ }
1551
+ }
1552
+ let txid = this.safeString (transaction, 'txid');
1553
+ if (txid === '') {
1554
+ txid = undefined;
1555
+ }
1556
+ const timestamp = this.safeInteger (transaction, 'createdAt');
1557
+ const updated = this.safeInteger (transaction, 'updatedAt');
1558
+ const payAmount = ('payAmount' in transaction);
1559
+ const ctime = ('ctime' in transaction);
1560
+ const type = (payAmount || ctime) ? 'withdrawal' : 'deposit';
1561
+ const status = this.parseTransactionStatusByType (this.safeString (transaction, 'status'), type);
1562
+ const amount = this.safeNumber (transaction, 'amount');
1563
+ let network = undefined;
1564
+ let currencyId = this.safeString (transaction, 'symbol');
1565
+ if (currencyId !== undefined) {
1566
+ const parts = currencyId.split ('_');
1567
+ currencyId = this.safeString (parts, 0);
1568
+ const networkId = this.safeString (parts, 1);
1569
+ if (networkId !== undefined) {
1570
+ network = networkId.toUpperCase ();
1571
+ }
1572
+ }
1573
+ const code = this.safeCurrencyCode (currencyId, currency);
1574
+ const feeCost = this.safeNumber (transaction, 'fee');
1575
+ let fee = undefined;
1576
+ if (feeCost !== undefined) {
1577
+ fee = { 'currency': code, 'cost': feeCost };
1578
+ }
1579
+ return {
1580
+ 'info': transaction,
1581
+ 'id': id,
1582
+ 'txid': txid,
1583
+ 'timestamp': timestamp,
1584
+ 'datetime': this.iso8601 (timestamp),
1585
+ 'network': network,
1586
+ 'address': addressTo,
1587
+ 'addressTo': addressTo,
1588
+ 'addressFrom': addressFrom,
1589
+ 'tag': tagTo,
1590
+ 'tagTo': tagTo,
1591
+ 'tagFrom': tagFrom,
1592
+ 'type': type,
1593
+ 'amount': amount,
1594
+ 'currency': code,
1595
+ 'status': status,
1596
+ 'updated': updated,
1597
+ 'internal': false,
1598
+ 'fee': fee,
1599
+ };
1600
+ }
1601
+
1602
+ async withdraw (code, amount, address, tag = undefined, params = {}) {
1603
+ [ tag, params ] = this.handleWithdrawTagAndParams (tag, params);
1604
+ this.checkAddress (address);
1605
+ await this.loadMarkets ();
1606
+ const currency = this.currency (code);
1607
+ let chainName = this.safeString (params, 'chainName');
1608
+ if (chainName === undefined) {
1609
+ const networks = this.safeValue (currency, 'networks', {});
1610
+ const network = this.safeStringUpper (params, 'network'); // this line allows the user to specify either ERC20 or ETH
1611
+ const networkEntry = this.safeValue (networks, network, {});
1612
+ chainName = this.safeString (networkEntry, 'id'); // handle ERC20>ETH alias
1613
+ if (chainName === undefined) {
1614
+ throw new ArgumentsRequired (this.id + ' withdraw() requires a network parameter or a chainName parameter');
1615
+ }
1616
+ params = this.omit (params, 'network');
1617
+ }
1618
+ const request = {
1619
+ 'coin': currency['id'].toUpperCase (),
1620
+ 'amount': amount,
1621
+ 'addressTo': address,
1622
+ 'chainName': chainName, // 'ERC20', 'TRC20', 'SOL'
1623
+ // 'addressMark': '', // mark of address
1624
+ // 'addrType': '', // type of address
1625
+ // 'tag': tag,
1626
+ };
1627
+ if (tag !== undefined) {
1628
+ request['tag'] = tag;
1629
+ }
1630
+ const response = await this.v1PrivatePostWithdrawCommit (this.extend (request, params));
1631
+ // { id: '9a67628b16ba4988ae20d329333f16bc' }
1632
+ return this.parseTransaction (response, currency);
1633
+ }
1634
+
1635
+ sign (path, api = 'public', method = 'GET', params = {}, headers = undefined, body = undefined) {
1636
+ const [ version, access ] = api;
1637
+ let url = this.urls['api'][version] + '/' + this.implodeParams (path, params);
1638
+ params = this.omit (params, this.extractParams (path));
1639
+ if (access === 'private') {
1640
+ this.checkRequiredCredentials ();
1641
+ const recvWindow = this.safeInteger (this.options, 'recvWindow', 5000);
1642
+ let query = this.urlencode (this.extend ({
1643
+ 'timestamp': this.nonce (),
1644
+ 'recvWindow': recvWindow,
1645
+ }, params));
1646
+ const signature = this.hmac (this.encode (query), this.encode (this.secret));
1647
+ query += '&' + 'signature=' + signature;
1648
+ headers = {
1649
+ 'X-MBX-APIKEY': this.apiKey,
1650
+ };
1651
+ if ((method === 'GET') || (method === 'DELETE')) {
1652
+ url += '?' + query;
1653
+ } else {
1654
+ body = query;
1655
+ headers['Content-Type'] = 'application/x-www-form-urlencoded';
1656
+ }
1657
+ } else {
1658
+ if (Object.keys (params).length) {
1659
+ url += '?' + this.urlencode (params);
1660
+ }
1661
+ }
1662
+ return { 'url': url, 'method': method, 'body': body, 'headers': headers };
1663
+ }
1664
+
1665
+ handleErrors (code, reason, url, method, headers, body, response, requestHeaders, requestBody) {
1666
+ if ((code === 418) || (code === 429)) {
1667
+ throw new DDoSProtection (this.id + ' ' + code.toString () + ' ' + reason + ' ' + body);
1668
+ }
1669
+ // error response in a form: { "code": -1013, "msg": "Invalid quantity." }
1670
+ // following block cointains legacy checks against message patterns in "msg" property
1671
+ // will switch "code" checks eventually, when we know all of them
1672
+ if (code >= 400) {
1673
+ if (body.indexOf ('Price * QTY is zero or less') >= 0) {
1674
+ throw new InvalidOrder (this.id + ' order cost = amount * price is zero or less ' + body);
1675
+ }
1676
+ if (body.indexOf ('LOT_SIZE') >= 0) {
1677
+ throw new InvalidOrder (this.id + ' order amount should be evenly divisible by lot size ' + body);
1678
+ }
1679
+ if (body.indexOf ('PRICE_FILTER') >= 0) {
1680
+ throw new InvalidOrder (this.id + ' order price is invalid, i.e. exceeds allowed price precision, exceeds min price or max price limits or is invalid float value in general, use this.priceToPrecision (symbol, amount) ' + body);
1681
+ }
1682
+ }
1683
+ if (response === undefined) {
1684
+ return; // fallback to default error handler
1685
+ }
1686
+ // check success value for wapi endpoints
1687
+ // response in format {'msg': 'The coin does not exist.', 'success': true/false}
1688
+ const success = this.safeValue (response, 'success', true);
1689
+ if (!success) {
1690
+ const message = this.safeString (response, 'msg');
1691
+ let parsedMessage = undefined;
1692
+ if (message !== undefined) {
1693
+ try {
1694
+ parsedMessage = JSON.parse (message);
1695
+ } catch (e) {
1696
+ // do nothing
1697
+ parsedMessage = undefined;
1698
+ }
1699
+ if (parsedMessage !== undefined) {
1700
+ response = parsedMessage;
1701
+ }
1702
+ }
1703
+ }
1704
+ const message = this.safeString (response, 'msg');
1705
+ if (message !== undefined) {
1706
+ this.throwExactlyMatchedException (this.exceptions['exact'], message, this.id + ' ' + message);
1707
+ this.throwBroadlyMatchedException (this.exceptions['broad'], message, this.id + ' ' + message);
1708
+ }
1709
+ // checks against error codes
1710
+ const error = this.safeString (response, 'code');
1711
+ if (error !== undefined) {
1712
+ // https://github.com/ccxt/ccxt/issues/6501
1713
+ // https://github.com/ccxt/ccxt/issues/7742
1714
+ if ((error === '200') || Precise.stringEquals (error, '0')) {
1715
+ return;
1716
+ }
1717
+ // a workaround for {"code":-2015,"msg":"Invalid API-key, IP, or permissions for action."}
1718
+ // despite that their message is very confusing, it is raised by Binance
1719
+ // on a temporary ban, the API key is valid, but disabled for a while
1720
+ if ((error === '-2015') && this.options['hasAlreadyAuthenticatedSuccessfully']) {
1721
+ throw new DDoSProtection (this.id + ' temporary banned: ' + body);
1722
+ }
1723
+ const feedback = this.id + ' ' + body;
1724
+ this.throwExactlyMatchedException (this.exceptions['exact'], error, feedback);
1725
+ throw new ExchangeError (feedback);
1726
+ }
1727
+ if (!success) {
1728
+ throw new ExchangeError (this.id + ' ' + body);
1729
+ }
1730
+ }
1731
+
1732
+ calculateRateLimiterCost (api, method, path, params, config = {}, context = {}) {
1733
+ if (('noSymbol' in config) && !('symbol' in params)) {
1734
+ return config['noSymbol'];
1735
+ } else if (('byLimit' in config) && ('limit' in params)) {
1736
+ const limit = params['limit'];
1737
+ const byLimit = config['byLimit'];
1738
+ for (let i = 0; i < byLimit.length; i++) {
1739
+ const entry = byLimit[i];
1740
+ if (limit <= entry[0]) {
1741
+ return entry[1];
1742
+ }
1743
+ }
1744
+ }
1745
+ return this.safeInteger (config, 'cost', 1);
1746
+ }
1747
+ };