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/hitbtc.js ADDED
@@ -0,0 +1,1343 @@
1
+ 'use strict';
2
+
3
+ // ---------------------------------------------------------------------------
4
+
5
+ const Exchange = require ('./base/Exchange');
6
+ const { BadSymbol, PermissionDenied, ExchangeError, ExchangeNotAvailable, OrderNotFound, InsufficientFunds, InvalidOrder, RequestTimeout, AuthenticationError } = require ('./base/errors');
7
+ const { TRUNCATE, DECIMAL_PLACES, TICK_SIZE } = require ('./base/functions/number');
8
+ const Precise = require ('./base/Precise');
9
+
10
+ // ---------------------------------------------------------------------------
11
+
12
+ module.exports = class hitbtc extends Exchange {
13
+ describe () {
14
+ return this.deepExtend (super.describe (), {
15
+ 'id': 'hitbtc',
16
+ 'name': 'HitBTC',
17
+ 'countries': [ 'HK' ],
18
+ // 300 requests per second => 1000ms / 300 = 3.333ms between requests on average (Trading)
19
+ // 100 requests per second => ( 1000ms / rateLimit ) / 100 => cost = 3.0003 (Market Data)
20
+ // 10 requests per second => ( 1000ms / rateLimit ) / 10 => cost = 30.003 (Other Requests)
21
+ 'rateLimit': 3.333,
22
+ 'version': '2',
23
+ 'pro': true,
24
+ 'has': {
25
+ 'CORS': undefined,
26
+ 'spot': true,
27
+ 'margin': false,
28
+ 'swap': false,
29
+ 'future': false,
30
+ 'option': false,
31
+ 'addMargin': false,
32
+ 'cancelOrder': true,
33
+ 'createDepositAddress': true,
34
+ 'createOrder': true,
35
+ 'createReduceOnlyOrder': false,
36
+ 'editOrder': true,
37
+ 'fetchBalance': true,
38
+ 'fetchBorrowRate': false,
39
+ 'fetchBorrowRateHistories': false,
40
+ 'fetchBorrowRateHistory': false,
41
+ 'fetchBorrowRates': false,
42
+ 'fetchBorrowRatesPerSymbol': false,
43
+ 'fetchClosedOrders': true,
44
+ 'fetchCurrencies': true,
45
+ 'fetchDepositAddress': true,
46
+ 'fetchDeposits': undefined,
47
+ 'fetchFundingHistory': false,
48
+ 'fetchFundingRate': false,
49
+ 'fetchFundingRateHistory': false,
50
+ 'fetchFundingRates': false,
51
+ 'fetchIndexOHLCV': false,
52
+ 'fetchLeverage': false,
53
+ 'fetchLeverageTiers': false,
54
+ 'fetchMarkets': true,
55
+ 'fetchMarkOHLCV': false,
56
+ 'fetchMyTrades': true,
57
+ 'fetchOHLCV': true,
58
+ 'fetchOpenOrder': true,
59
+ 'fetchOpenOrders': true,
60
+ 'fetchOrder': true,
61
+ 'fetchOrderBook': true,
62
+ 'fetchOrders': undefined,
63
+ 'fetchOrderTrades': true,
64
+ 'fetchPosition': false,
65
+ 'fetchPositions': false,
66
+ 'fetchPositionsRisk': false,
67
+ 'fetchPremiumIndexOHLCV': false,
68
+ 'fetchTicker': true,
69
+ 'fetchTickers': true,
70
+ 'fetchTrades': true,
71
+ 'fetchTradingFee': true,
72
+ 'fetchTradingFees': false,
73
+ 'fetchTransactions': true,
74
+ 'fetchWithdrawals': undefined,
75
+ 'reduceMargin': false,
76
+ 'setLeverage': false,
77
+ 'setMarginMode': false,
78
+ 'setPositionMode': false,
79
+ 'transfer': true,
80
+ 'withdraw': true,
81
+ },
82
+ 'timeframes': {
83
+ '1m': 'M1',
84
+ '3m': 'M3',
85
+ '5m': 'M5',
86
+ '15m': 'M15',
87
+ '30m': 'M30', // default
88
+ '1h': 'H1',
89
+ '4h': 'H4',
90
+ '1d': 'D1',
91
+ '1w': 'D7',
92
+ '1M': '1M',
93
+ },
94
+ 'urls': {
95
+ 'logo': 'https://user-images.githubusercontent.com/1294454/27766555-8eaec20e-5edc-11e7-9c5b-6dc69fc42f5e.jpg',
96
+ 'test': {
97
+ 'public': 'https://api.demo.hitbtc.com',
98
+ 'private': 'https://api.demo.hitbtc.com',
99
+ },
100
+ 'api': {
101
+ 'public': 'https://api.hitbtc.com',
102
+ 'private': 'https://api.hitbtc.com',
103
+ },
104
+ 'www': 'https://hitbtc.com',
105
+ 'referral': 'https://hitbtc.com/?ref_id=5a5d39a65d466',
106
+ 'doc': [
107
+ 'https://api.hitbtc.com/v2',
108
+ ],
109
+ 'fees': [
110
+ 'https://hitbtc.com/fees-and-limits',
111
+ 'https://support.hitbtc.com/hc/en-us/articles/115005148605-Fees-and-limits',
112
+ ],
113
+ },
114
+ 'api': {
115
+ 'public': {
116
+ 'get': {
117
+ 'currency': 3, // Available Currencies
118
+ 'currency/{currency}': 3, // Get currency info
119
+ 'symbol': 3, // Available Currency Symbols
120
+ 'symbol/{symbol}': 3, // Get symbol info
121
+ 'ticker': 3, // Ticker list for all symbols
122
+ 'ticker/{symbol}': 3, // Ticker for symbol
123
+ 'trades': 3,
124
+ 'trades/{symbol}': 3, // Trades
125
+ 'orderbook': 3,
126
+ 'orderbook/{symbol}': 3, // Orderbook
127
+ 'candles': 3,
128
+ 'candles/{symbol}': 3, // Candles
129
+ },
130
+ },
131
+ 'private': {
132
+ 'get': {
133
+ 'trading/balance': 30, // Get trading balance
134
+ 'order': 30, // List your current open orders
135
+ 'order/{clientOrderId}': 30, // Get a single order by clientOrderId
136
+ 'trading/fee/all': 30, // Get trading fee rate
137
+ 'trading/fee/{symbol}': 30, // Get trading fee rate
138
+ 'margin/account': 30,
139
+ 'margin/account/{symbol}': 30,
140
+ 'margin/position': 30,
141
+ 'margin/position/{symbol}': 30,
142
+ 'margin/order': 30,
143
+ 'margin/order/{clientOrderId}': 30,
144
+ 'history/order': 30, // Get historical orders
145
+ 'history/trades': 30, // Get historical trades
146
+ 'history/order/{orderId}/trades': 30, // Get historical trades by specified order
147
+ 'account/balance': 30, // Get main acccount balance
148
+ 'account/crypto/address/{currency}': 30, // Get current address
149
+ 'account/crypto/addresses/{currency}': 30, // Get last 10 deposit addresses for currency
150
+ 'account/crypto/used-addresses/{currency}': 30, // Get last 10 unique addresses used for withdraw by currency
151
+ 'account/crypto/estimate-withdraw': 30,
152
+ 'account/crypto/is-mine/{address}': 30,
153
+ 'account/transactions': 30, // Get account transactions
154
+ 'account/transactions/{id}': 30, // Get account transaction by id
155
+ 'sub-acc': 30,
156
+ 'sub-acc/acl': 30,
157
+ 'sub-acc/balance/{subAccountUserID}': 30,
158
+ 'sub-acc/deposit-address/{subAccountUserId}/{currency}': 30,
159
+ },
160
+ 'post': {
161
+ 'order': 1, // Create new order
162
+ 'margin/order': 1,
163
+ 'account/crypto/address/{currency}': 1, // Create new crypto deposit address
164
+ 'account/crypto/withdraw': 1, // Withdraw crypto
165
+ 'account/crypto/transfer-convert': 1,
166
+ 'account/transfer': 1, // Transfer amount to trading account or to main account
167
+ 'account/transfer/internal': 1,
168
+ 'sub-acc/freeze': 1,
169
+ 'sub-acc/activate': 1,
170
+ 'sub-acc/transfer': 1,
171
+ },
172
+ 'put': {
173
+ 'order/{clientOrderId}': 1, // Create new order
174
+ 'margin/account/{symbol}': 1,
175
+ 'margin/order/{clientOrderId}': 1,
176
+ 'account/crypto/withdraw/{id}': 1, // Commit crypto withdrawal
177
+ 'sub-acc/acl/{subAccountUserId}': 1,
178
+ },
179
+ 'delete': {
180
+ 'order': 1, // Cancel all open orders
181
+ 'order/{clientOrderId}': 1, // Cancel order
182
+ 'margin/account': 1,
183
+ 'margin/account/{symbol}': 1,
184
+ 'margin/position': 1,
185
+ 'margin/position/{symbol}': 1,
186
+ 'margin/order': 1,
187
+ 'margin/order/{clientOrderId}': 1,
188
+ 'account/crypto/withdraw/{id}': 1, // Rollback crypto withdrawal
189
+ },
190
+ // outdated?
191
+ 'patch': {
192
+ 'order/{clientOrderId}': 1, // Cancel Replace order
193
+ },
194
+ },
195
+ },
196
+ 'precisionMode': TICK_SIZE,
197
+ 'fees': {
198
+ 'trading': {
199
+ 'tierBased': false,
200
+ 'percentage': true,
201
+ 'maker': 0.1 / 100,
202
+ 'taker': 0.2 / 100,
203
+ },
204
+ },
205
+ 'options': {
206
+ 'networks': {
207
+ 'ETH': 'T20',
208
+ 'ERC20': 'T20',
209
+ 'TRX': 'TTRX',
210
+ 'TRC20': 'TTRX',
211
+ 'OMNI': '',
212
+ },
213
+ 'defaultTimeInForce': 'FOK',
214
+ 'accountsByType': {
215
+ 'funding': 'bank',
216
+ 'spot': 'exchange',
217
+ },
218
+ 'fetchBalanceMethod': {
219
+ 'account': 'account',
220
+ 'bank': 'account',
221
+ 'main': 'account',
222
+ 'funding': 'account',
223
+ 'exchange': 'trading',
224
+ 'spot': 'trading',
225
+ 'trade': 'trading',
226
+ 'trading': 'trading',
227
+ },
228
+ },
229
+ 'commonCurrencies': {
230
+ 'AUTO': 'Cube',
231
+ 'BCC': 'BCC', // initial symbol for Bitcoin Cash, now inactive
232
+ 'BDP': 'BidiPass',
233
+ 'BET': 'DAO.Casino',
234
+ 'BIT': 'BitRewards',
235
+ 'BOX': 'BOX Token',
236
+ 'CPT': 'Cryptaur', // conflict with CPT = Contents Protocol https://github.com/ccxt/ccxt/issues/4920 and https://github.com/ccxt/ccxt/issues/6081
237
+ 'GET': 'Themis',
238
+ 'GMT': 'GMT Token',
239
+ 'HSR': 'HC',
240
+ 'IQ': 'IQ.Cash',
241
+ 'LNC': 'LinkerCoin',
242
+ 'PLA': 'PlayChip',
243
+ 'PNT': 'Penta',
244
+ 'SBTC': 'Super Bitcoin',
245
+ 'STEPN': 'GMT',
246
+ 'STX': 'STOX',
247
+ 'TV': 'Tokenville',
248
+ 'USD': 'USDT',
249
+ 'XMT': 'MTL',
250
+ 'XPNT': 'PNT',
251
+ },
252
+ 'exceptions': {
253
+ '504': RequestTimeout, // {"error":{"code":504,"message":"Gateway Timeout"}}
254
+ '1002': AuthenticationError, // {"error":{"code":1002,"message":"Authorization failed","description":""}}
255
+ '1003': PermissionDenied, // "Action is forbidden for this API key"
256
+ '2010': InvalidOrder, // "Quantity not a valid number"
257
+ '2001': BadSymbol, // "Symbol not found"
258
+ '2011': InvalidOrder, // "Quantity too low"
259
+ '2020': InvalidOrder, // "Price not a valid number"
260
+ '20002': OrderNotFound, // canceling non-existent order
261
+ '20001': InsufficientFunds, // {"error":{"code":20001,"message":"Insufficient funds","description":"Check that the funds are sufficient, given commissions"}}
262
+ '20010': BadSymbol, // {"error":{"code":20010,"message":"Exchange temporary closed","description":"Exchange market for this symbol is temporary closed"}}
263
+ '20045': InvalidOrder, // {"error":{"code":20045,"message":"Fat finger limit exceeded"}}
264
+ },
265
+ });
266
+ }
267
+
268
+ feeToPrecision (symbol, fee) {
269
+ return this.decimalToPrecision (fee, TRUNCATE, 8, DECIMAL_PLACES);
270
+ }
271
+
272
+ async fetchMarkets (params = {}) {
273
+ const response = await this.publicGetSymbol (params);
274
+ //
275
+ // [
276
+ // {
277
+ // "id":"BCNBTC",
278
+ // "baseCurrency":"BCN",
279
+ // "quoteCurrency":"BTC",
280
+ // "quantityIncrement":"100",
281
+ // "tickSize":"0.00000000001",
282
+ // "takeLiquidityRate":"0.002",
283
+ // "provideLiquidityRate":"0.001",
284
+ // "feeCurrency":"BTC"
285
+ // }
286
+ // ]
287
+ //
288
+ const result = [];
289
+ for (let i = 0; i < response.length; i++) {
290
+ const market = response[i];
291
+ const id = this.safeString (market, 'id');
292
+ const baseId = this.safeString (market, 'baseCurrency');
293
+ const quoteId = this.safeString (market, 'quoteCurrency');
294
+ const base = this.safeCurrencyCode (baseId);
295
+ const quote = this.safeCurrencyCode (quoteId);
296
+ // bequant fix
297
+ let symbol = base + '/' + quote;
298
+ if (id.indexOf ('_') >= 0) {
299
+ symbol = id;
300
+ }
301
+ const lotString = this.safeString (market, 'quantityIncrement');
302
+ const stepString = this.safeString (market, 'tickSize');
303
+ const lot = this.parseNumber (lotString);
304
+ const step = this.parseNumber (stepString);
305
+ const feeCurrencyId = this.safeString (market, 'feeCurrency');
306
+ result.push (this.extend (this.fees['trading'], {
307
+ 'id': id,
308
+ 'symbol': symbol,
309
+ 'base': base,
310
+ 'quote': quote,
311
+ 'settle': undefined,
312
+ 'baseId': baseId,
313
+ 'quoteId': quoteId,
314
+ 'settleId': undefined,
315
+ 'type': 'spot',
316
+ 'spot': true,
317
+ 'margin': false,
318
+ 'swap': false,
319
+ 'future': false,
320
+ 'option': false,
321
+ 'active': true,
322
+ 'contract': false,
323
+ 'linear': undefined,
324
+ 'inverse': undefined,
325
+ 'taker': this.safeNumber (market, 'takeLiquidityRate'),
326
+ 'maker': this.safeNumber (market, 'provideLiquidityRate'),
327
+ 'contractSize': undefined,
328
+ 'expiry': undefined,
329
+ 'expiryDatetime': undefined,
330
+ 'strike': undefined,
331
+ 'optionType': undefined,
332
+ 'feeCurrency': this.safeCurrencyCode (feeCurrencyId),
333
+ 'precision': {
334
+ 'amount': lot,
335
+ 'price': step,
336
+ },
337
+ 'limits': {
338
+ 'leverage': {
339
+ 'min': undefined,
340
+ 'max': undefined,
341
+ },
342
+ 'amount': {
343
+ 'min': lot,
344
+ 'max': undefined,
345
+ },
346
+ 'price': {
347
+ 'min': step,
348
+ 'max': undefined,
349
+ },
350
+ 'cost': {
351
+ 'min': this.parseNumber (Precise.stringMul (lotString, stepString)),
352
+ 'max': undefined,
353
+ },
354
+ },
355
+ 'info': market,
356
+ }));
357
+ }
358
+ return result;
359
+ }
360
+
361
+ async transfer (code, amount, fromAccount, toAccount, params = {}) {
362
+ // account can be "exchange" or "bank", with aliases "main" or "trading" respectively
363
+ await this.loadMarkets ();
364
+ const currency = this.currency (code);
365
+ const requestAmount = this.currencyToPrecision (code, amount);
366
+ const request = {
367
+ 'currency': currency['id'],
368
+ 'amount': requestAmount,
369
+ };
370
+ let type = this.safeString (params, 'type');
371
+ if (type === undefined) {
372
+ const accountsByType = this.safeValue (this.options, 'accountsByType', {});
373
+ const fromId = this.safeString (accountsByType, fromAccount, fromAccount);
374
+ const toId = this.safeString (accountsByType, toAccount, toAccount);
375
+ if (fromId === toId) {
376
+ throw new ExchangeError (this.id + ' transfer() from and to cannot be the same account');
377
+ }
378
+ type = fromId + 'To' + this.capitalize (toId);
379
+ }
380
+ request['type'] = type;
381
+ const response = await this.privatePostAccountTransfer (this.extend (request, params));
382
+ //
383
+ // {
384
+ // 'id': '2db6ebab-fb26-4537-9ef8-1a689472d236'
385
+ // }
386
+ //
387
+ const transfer = this.parseTransfer (response, currency);
388
+ return this.extend (transfer, {
389
+ 'fromAccount': fromAccount,
390
+ 'toAccount': toAccount,
391
+ 'amount': this.parseNumber (requestAmount),
392
+ });
393
+ }
394
+
395
+ parseTransfer (transfer, currency = undefined) {
396
+ //
397
+ // {
398
+ // 'id': '2db6ebab-fb26-4537-9ef8-1a689472d236'
399
+ // }
400
+ //
401
+ const timestamp = this.milliseconds ();
402
+ return {
403
+ 'id': this.safeString (transfer, 'id'),
404
+ 'timestamp': timestamp,
405
+ 'datetime': this.iso8601 (timestamp),
406
+ 'currency': this.safeCurrencyCode (undefined, currency),
407
+ 'amount': undefined,
408
+ 'fromAccount': undefined,
409
+ 'toAccount': undefined,
410
+ 'status': undefined,
411
+ 'info': transfer,
412
+ };
413
+ }
414
+
415
+ async fetchCurrencies (params = {}) {
416
+ const response = await this.publicGetCurrency (params);
417
+ //
418
+ // [
419
+ // {
420
+ // "id":"XPNT",
421
+ // "fullName":"pToken",
422
+ // "crypto":true,
423
+ // "payinEnabled":true,
424
+ // "payinPaymentId":false,
425
+ // "payinConfirmations":9,
426
+ // "payoutEnabled":true,
427
+ // "payoutIsPaymentId":false,
428
+ // "transferEnabled":true,
429
+ // "delisted":false,
430
+ // "payoutFee":"26.510000000000",
431
+ // "precisionPayout":18,
432
+ // "precisionTransfer":8
433
+ // }
434
+ // ]
435
+ //
436
+ const result = {};
437
+ for (let i = 0; i < response.length; i++) {
438
+ const currency = response[i];
439
+ const id = this.safeString (currency, 'id');
440
+ // todo: will need to rethink the fees
441
+ // to add support for multiple withdrawal/deposit methods and
442
+ // differentiated fees for each particular method
443
+ const decimals = this.safeInteger (currency, 'precisionTransfer', 8);
444
+ const precision = 1 / Math.pow (10, decimals);
445
+ const code = this.safeCurrencyCode (id);
446
+ const payin = this.safeValue (currency, 'payinEnabled');
447
+ const payout = this.safeValue (currency, 'payoutEnabled');
448
+ const transfer = this.safeValue (currency, 'transferEnabled');
449
+ let active = payin && payout && transfer;
450
+ if ('disabled' in currency) {
451
+ if (currency['disabled']) {
452
+ active = false;
453
+ }
454
+ }
455
+ let type = 'fiat';
456
+ if (('crypto' in currency) && currency['crypto']) {
457
+ type = 'crypto';
458
+ }
459
+ const name = this.safeString (currency, 'fullName');
460
+ result[code] = {
461
+ 'id': id,
462
+ 'code': code,
463
+ 'type': type,
464
+ 'payin': payin,
465
+ 'payout': payout,
466
+ 'transfer': transfer,
467
+ 'info': currency,
468
+ 'name': name,
469
+ 'active': active,
470
+ 'deposit': payin,
471
+ 'withdraw': payout,
472
+ 'fee': this.safeNumber (currency, 'payoutFee'), // todo: redesign
473
+ 'precision': precision,
474
+ 'limits': {
475
+ 'amount': {
476
+ 'min': 1 / Math.pow (10, decimals),
477
+ 'max': Math.pow (10, decimals),
478
+ },
479
+ 'withdraw': {
480
+ 'min': undefined,
481
+ 'max': Math.pow (10, precision),
482
+ },
483
+ },
484
+ };
485
+ }
486
+ return result;
487
+ }
488
+
489
+ parseTradingFee (fee, market = undefined) {
490
+ //
491
+ //
492
+ // {
493
+ // takeLiquidityRate: '0.001',
494
+ // provideLiquidityRate: '-0.0001'
495
+ // }
496
+ //
497
+ return {
498
+ 'info': fee,
499
+ 'symbol': this.safeSymbol (undefined, market),
500
+ 'maker': this.safeNumber (fee, 'provideLiquidityRate'),
501
+ 'taker': this.safeNumber (fee, 'takeLiquidityRate'),
502
+ 'percentage': true,
503
+ 'tierBased': true,
504
+ };
505
+ }
506
+
507
+ async fetchTradingFee (symbol, params = {}) {
508
+ await this.loadMarkets ();
509
+ const market = this.market (symbol);
510
+ const request = {
511
+ 'symbol': market['id'],
512
+ };
513
+ const response = await this.privateGetTradingFeeSymbol (request);
514
+ //
515
+ // {
516
+ // takeLiquidityRate: '0.001',
517
+ // provideLiquidityRate: '-0.0001'
518
+ // }
519
+ //
520
+ return this.parseTradingFee (response, market);
521
+ }
522
+
523
+ parseBalance (response) {
524
+ const result = {
525
+ 'info': response,
526
+ 'timestamp': undefined,
527
+ 'datetime': undefined,
528
+ };
529
+ for (let i = 0; i < response.length; i++) {
530
+ const balance = response[i];
531
+ const currencyId = this.safeString (balance, 'currency');
532
+ const code = this.safeCurrencyCode (currencyId);
533
+ const account = this.account ();
534
+ account['free'] = this.safeString (balance, 'available');
535
+ account['used'] = this.safeString (balance, 'reserved');
536
+ result[code] = account;
537
+ }
538
+ return this.safeBalance (result);
539
+ }
540
+
541
+ async fetchBalance (params = {}) {
542
+ await this.loadMarkets ();
543
+ const type = this.safeString (params, 'type', 'trading');
544
+ const fetchBalanceAccounts = this.safeValue (this.options, 'fetchBalanceMethod', {});
545
+ const typeId = this.safeString (fetchBalanceAccounts, type);
546
+ if (typeId === undefined) {
547
+ throw new ExchangeError (this.id + ' fetchBalance() account type must be either main or trading');
548
+ }
549
+ const method = 'privateGet' + this.capitalize (typeId) + 'Balance';
550
+ const query = this.omit (params, 'type');
551
+ const response = await this[method] (query);
552
+ //
553
+ // [
554
+ // {"currency":"SPI","available":"0","reserved":"0"},
555
+ // {"currency":"GRPH","available":"0","reserved":"0"},
556
+ // {"currency":"DGTX","available":"0","reserved":"0"},
557
+ // ]
558
+ //
559
+ return this.parseBalance (response);
560
+ }
561
+
562
+ parseOHLCV (ohlcv, market = undefined) {
563
+ //
564
+ // {
565
+ // "timestamp":"2015-08-20T19:01:00.000Z",
566
+ // "open":"0.006",
567
+ // "close":"0.006",
568
+ // "min":"0.006",
569
+ // "max":"0.006",
570
+ // "volume":"0.003",
571
+ // "volumeQuote":"0.000018"
572
+ // }
573
+ //
574
+ return [
575
+ this.parse8601 (this.safeString (ohlcv, 'timestamp')),
576
+ this.safeNumber (ohlcv, 'open'),
577
+ this.safeNumber (ohlcv, 'max'),
578
+ this.safeNumber (ohlcv, 'min'),
579
+ this.safeNumber (ohlcv, 'close'),
580
+ this.safeNumber (ohlcv, 'volume'),
581
+ ];
582
+ }
583
+
584
+ async fetchOHLCV (symbol, timeframe = '1m', since = undefined, limit = undefined, params = {}) {
585
+ await this.loadMarkets ();
586
+ const market = this.market (symbol);
587
+ const request = {
588
+ 'symbol': market['id'],
589
+ 'period': this.timeframes[timeframe],
590
+ };
591
+ if (since !== undefined) {
592
+ request['from'] = this.iso8601 (since);
593
+ }
594
+ if (limit !== undefined) {
595
+ request['limit'] = limit;
596
+ }
597
+ const response = await this.publicGetCandlesSymbol (this.extend (request, params));
598
+ //
599
+ // [
600
+ // {"timestamp":"2015-08-20T19:01:00.000Z","open":"0.006","close":"0.006","min":"0.006","max":"0.006","volume":"0.003","volumeQuote":"0.000018"},
601
+ // {"timestamp":"2015-08-20T19:03:00.000Z","open":"0.006","close":"0.006","min":"0.006","max":"0.006","volume":"0.013","volumeQuote":"0.000078"},
602
+ // {"timestamp":"2015-08-20T19:06:00.000Z","open":"0.0055","close":"0.005","min":"0.005","max":"0.0055","volume":"0.003","volumeQuote":"0.0000155"},
603
+ // ]
604
+ //
605
+ return this.parseOHLCVs (response, market, timeframe, since, limit);
606
+ }
607
+
608
+ async fetchOrderBook (symbol, limit = undefined, params = {}) {
609
+ await this.loadMarkets ();
610
+ const request = {
611
+ 'symbol': this.marketId (symbol),
612
+ };
613
+ if (limit !== undefined) {
614
+ request['limit'] = limit; // default = 100, 0 = unlimited
615
+ }
616
+ const response = await this.publicGetOrderbookSymbol (this.extend (request, params));
617
+ return this.parseOrderBook (response, symbol, undefined, 'bid', 'ask', 'price', 'size');
618
+ }
619
+
620
+ parseTicker (ticker, market = undefined) {
621
+ const timestamp = this.parse8601 (ticker['timestamp']);
622
+ const symbol = this.safeSymbol (undefined, market);
623
+ const baseVolume = this.safeString (ticker, 'volume');
624
+ const quoteVolume = this.safeString (ticker, 'volumeQuote');
625
+ const open = this.safeString (ticker, 'open');
626
+ const last = this.safeString (ticker, 'last');
627
+ return this.safeTicker ({
628
+ 'symbol': symbol,
629
+ 'timestamp': timestamp,
630
+ 'datetime': this.iso8601 (timestamp),
631
+ 'high': this.safeString (ticker, 'high'),
632
+ 'low': this.safeString (ticker, 'low'),
633
+ 'bid': this.safeString (ticker, 'bid'),
634
+ 'bidVolume': undefined,
635
+ 'ask': this.safeString (ticker, 'ask'),
636
+ 'askVolume': undefined,
637
+ 'vwap': undefined,
638
+ 'open': open,
639
+ 'close': last,
640
+ 'last': last,
641
+ 'previousClose': undefined,
642
+ 'change': undefined,
643
+ 'percentage': undefined,
644
+ 'average': undefined,
645
+ 'baseVolume': baseVolume,
646
+ 'quoteVolume': quoteVolume,
647
+ 'info': ticker,
648
+ }, market, false);
649
+ }
650
+
651
+ async fetchTickers (symbols = undefined, params = {}) {
652
+ await this.loadMarkets ();
653
+ const response = await this.publicGetTicker (params);
654
+ const result = {};
655
+ for (let i = 0; i < response.length; i++) {
656
+ const ticker = response[i];
657
+ const marketId = this.safeString (ticker, 'symbol');
658
+ const market = this.safeMarket (marketId);
659
+ const symbol = market['symbol'];
660
+ result[symbol] = this.parseTicker (ticker, market);
661
+ }
662
+ return this.filterByArray (result, 'symbol', symbols);
663
+ }
664
+
665
+ async fetchTicker (symbol, params = {}) {
666
+ await this.loadMarkets ();
667
+ const market = this.market (symbol);
668
+ const request = {
669
+ 'symbol': market['id'],
670
+ };
671
+ const response = await this.publicGetTickerSymbol (this.extend (request, params));
672
+ if ('message' in response) {
673
+ throw new ExchangeError (this.id + ' ' + response['message']);
674
+ }
675
+ return this.parseTicker (response, market);
676
+ }
677
+
678
+ parseTrade (trade, market = undefined) {
679
+ // createMarketOrder
680
+ //
681
+ // { fee: "0.0004644",
682
+ // id: 386394956,
683
+ // price: "0.4644",
684
+ // quantity: "1",
685
+ // timestamp: "2018-10-25T16:41:44.780Z" }
686
+ //
687
+ // fetchTrades
688
+ //
689
+ // { id: 974786185,
690
+ // price: '0.032462',
691
+ // quantity: '0.3673',
692
+ // side: 'buy',
693
+ // timestamp: '2020-10-16T12:57:39.846Z' }
694
+ //
695
+ // fetchMyTrades
696
+ //
697
+ // { id: 277210397,
698
+ // clientOrderId: '6e102f3e7f3f4e04aeeb1cdc95592f1a',
699
+ // orderId: 28102855393,
700
+ // symbol: 'ETHBTC',
701
+ // side: 'sell',
702
+ // quantity: '0.002',
703
+ // price: '0.073365',
704
+ // fee: '0.000000147',
705
+ // timestamp: '2018-04-28T18:39:55.345Z' }
706
+ //
707
+ // {
708
+ // "id":1568938909,
709
+ // "orderId":793293348428,
710
+ // "clientOrderId":"fbc5c5b753e8476cb14697458cb928ef",
711
+ // "symbol":"DOGEUSD",
712
+ // "side":"sell",
713
+ // "quantity":"100",
714
+ // "price":"0.03904191",
715
+ // "fee":"0.009760477500",
716
+ // "timestamp":"2022-01-25T15:15:41.353Z",
717
+ // "taker":true
718
+ // }
719
+ //
720
+ const timestamp = this.parse8601 (trade['timestamp']);
721
+ const marketId = this.safeString (trade, 'symbol');
722
+ market = this.safeMarket (marketId, market);
723
+ const symbol = market['symbol'];
724
+ let fee = undefined;
725
+ const feeCostString = this.safeString (trade, 'fee');
726
+ if (feeCostString !== undefined) {
727
+ const feeCurrencyCode = market ? market['feeCurrency'] : undefined;
728
+ fee = {
729
+ 'cost': feeCostString,
730
+ 'currency': feeCurrencyCode,
731
+ };
732
+ }
733
+ // we use clientOrderId as the order id with this exchange intentionally
734
+ // because most of their endpoints will require clientOrderId
735
+ // explained here: https://github.com/ccxt/ccxt/issues/5674
736
+ const orderId = this.safeString (trade, 'clientOrderId');
737
+ const priceString = this.safeString (trade, 'price');
738
+ const amountString = this.safeString (trade, 'quantity');
739
+ const side = this.safeString (trade, 'side');
740
+ const id = this.safeString (trade, 'id');
741
+ return this.safeTrade ({
742
+ 'info': trade,
743
+ 'id': id,
744
+ 'order': orderId,
745
+ 'timestamp': timestamp,
746
+ 'datetime': this.iso8601 (timestamp),
747
+ 'symbol': symbol,
748
+ 'type': undefined,
749
+ 'side': side,
750
+ 'takerOrMaker': undefined,
751
+ 'price': priceString,
752
+ 'amount': amountString,
753
+ 'cost': undefined,
754
+ 'fee': fee,
755
+ }, market);
756
+ }
757
+
758
+ async fetchTransactions (code = undefined, since = undefined, limit = undefined, params = {}) {
759
+ await this.loadMarkets ();
760
+ let currency = undefined;
761
+ const request = {};
762
+ if (code !== undefined) {
763
+ currency = this.currency (code);
764
+ request['asset'] = currency['id'];
765
+ }
766
+ if (since !== undefined) {
767
+ request['startTime'] = since;
768
+ }
769
+ const response = await this.privateGetAccountTransactions (this.extend (request, params));
770
+ return this.parseTransactions (response, currency, since, limit);
771
+ }
772
+
773
+ parseTransaction (transaction, currency = undefined) {
774
+ //
775
+ // transactions
776
+ //
777
+ // {
778
+ // id: 'd53ee9df-89bf-4d09-886e-849f8be64647',
779
+ // index: 1044718371,
780
+ // type: 'payout', // payout, payin
781
+ // status: 'success',
782
+ // currency: 'ETH',
783
+ // amount: '4.522683200000000000000000',
784
+ // createdAt: '2018-06-07T00:43:32.426Z',
785
+ // updatedAt: '2018-06-07T00:45:36.447Z',
786
+ // hash: '0x973e5683dfdf80a1fb1e0b96e19085b6489221d2ddf864daa46903c5ec283a0f',
787
+ // address: '0xC5a59b21948C1d230c8C54f05590000Eb3e1252c',
788
+ // fee: '0.00958',
789
+ // },
790
+ // {
791
+ // id: 'e6c63331-467e-4922-9edc-019e75d20ba3',
792
+ // index: 1044714672,
793
+ // type: 'exchangeToBank', // exchangeToBank, bankToExchange, withdraw
794
+ // status: 'success',
795
+ // currency: 'ETH',
796
+ // amount: '4.532263200000000000',
797
+ // createdAt: '2018-06-07T00:42:39.543Z',
798
+ // updatedAt: '2018-06-07T00:42:39.683Z',
799
+ // },
800
+ //
801
+ // withdraw
802
+ //
803
+ // {
804
+ // "id": "d2ce578f-647d-4fa0-b1aa-4a27e5ee597b"
805
+ // }
806
+ //
807
+ const id = this.safeString (transaction, 'id');
808
+ const timestamp = this.parse8601 (this.safeString (transaction, 'createdAt'));
809
+ const updated = this.parse8601 (this.safeString (transaction, 'updatedAt'));
810
+ const currencyId = this.safeString (transaction, 'currency');
811
+ const code = this.safeCurrencyCode (currencyId, currency);
812
+ const status = this.parseTransactionStatus (this.safeString (transaction, 'status'));
813
+ const amount = this.safeNumber (transaction, 'amount');
814
+ const address = this.safeString (transaction, 'address');
815
+ const txid = this.safeString (transaction, 'hash');
816
+ let fee = undefined;
817
+ const feeCost = this.safeNumber (transaction, 'fee');
818
+ if (feeCost !== undefined) {
819
+ fee = {
820
+ 'cost': feeCost,
821
+ 'currency': code,
822
+ };
823
+ }
824
+ const type = this.parseTransactionType (this.safeString (transaction, 'type'));
825
+ return {
826
+ 'info': transaction,
827
+ 'id': id,
828
+ 'txid': txid,
829
+ 'timestamp': timestamp,
830
+ 'datetime': this.iso8601 (timestamp),
831
+ 'network': undefined,
832
+ 'address': address,
833
+ 'addressTo': undefined,
834
+ 'addressFrom': undefined,
835
+ 'tag': undefined,
836
+ 'tagTo': undefined,
837
+ 'tagFrom': undefined,
838
+ 'type': type,
839
+ 'amount': amount,
840
+ 'currency': code,
841
+ 'status': status,
842
+ 'updated': updated,
843
+ 'fee': fee,
844
+ };
845
+ }
846
+
847
+ parseTransactionStatus (status) {
848
+ const statuses = {
849
+ 'pending': 'pending',
850
+ 'failed': 'failed',
851
+ 'success': 'ok',
852
+ };
853
+ return this.safeString (statuses, status, status);
854
+ }
855
+
856
+ parseTransactionType (type) {
857
+ const types = {
858
+ 'payin': 'deposit',
859
+ 'payout': 'withdrawal',
860
+ 'withdraw': 'withdrawal',
861
+ };
862
+ return this.safeString (types, type, type);
863
+ }
864
+
865
+ async fetchTrades (symbol, since = undefined, limit = undefined, params = {}) {
866
+ await this.loadMarkets ();
867
+ const market = this.market (symbol);
868
+ const request = {
869
+ 'symbol': market['id'],
870
+ };
871
+ if (limit !== undefined) {
872
+ request['limit'] = limit;
873
+ }
874
+ if (since !== undefined) {
875
+ request['sort'] = 'ASC';
876
+ request['from'] = this.iso8601 (since);
877
+ }
878
+ const response = await this.publicGetTradesSymbol (this.extend (request, params));
879
+ return this.parseTrades (response, market, since, limit);
880
+ }
881
+
882
+ async createOrder (symbol, type, side, amount, price = undefined, params = {}) {
883
+ await this.loadMarkets ();
884
+ const market = this.market (symbol);
885
+ // we use clientOrderId as the order id with this exchange intentionally
886
+ // because most of their endpoints will require clientOrderId
887
+ // explained here: https://github.com/ccxt/ccxt/issues/5674
888
+ // their max accepted length is 32 characters
889
+ const uuid = this.uuid ();
890
+ const parts = uuid.split ('-');
891
+ let clientOrderId = parts.join ('');
892
+ clientOrderId = clientOrderId.slice (0, 32);
893
+ amount = parseFloat (amount);
894
+ const request = {
895
+ 'clientOrderId': clientOrderId,
896
+ 'symbol': market['id'],
897
+ 'side': side,
898
+ 'quantity': this.amountToPrecision (symbol, amount),
899
+ 'type': type,
900
+ };
901
+ if (type === 'limit') {
902
+ request['price'] = this.priceToPrecision (symbol, price);
903
+ } else {
904
+ request['timeInForce'] = this.options['defaultTimeInForce'];
905
+ }
906
+ const response = await this.privatePostOrder (this.extend (request, params));
907
+ const order = this.parseOrder (response);
908
+ if (order['status'] === 'rejected') {
909
+ throw new InvalidOrder (this.id + ' order was rejected by the exchange ' + this.json (order));
910
+ }
911
+ return order;
912
+ }
913
+
914
+ async editOrder (id, symbol, type, side, amount = undefined, price = undefined, params = {}) {
915
+ await this.loadMarkets ();
916
+ // we use clientOrderId as the order id with this exchange intentionally
917
+ // because most of their endpoints will require clientOrderId
918
+ // explained here: https://github.com/ccxt/ccxt/issues/5674
919
+ // their max accepted length is 32 characters
920
+ const uuid = this.uuid ();
921
+ const parts = uuid.split ('-');
922
+ let requestClientId = parts.join ('');
923
+ requestClientId = requestClientId.slice (0, 32);
924
+ const request = {
925
+ 'clientOrderId': id,
926
+ 'requestClientId': requestClientId,
927
+ };
928
+ if (amount !== undefined) {
929
+ request['quantity'] = this.amountToPrecision (symbol, amount);
930
+ }
931
+ if (price !== undefined) {
932
+ request['price'] = this.priceToPrecision (symbol, price);
933
+ }
934
+ const response = await this.privatePatchOrderClientOrderId (this.extend (request, params));
935
+ return this.parseOrder (response);
936
+ }
937
+
938
+ async cancelOrder (id, symbol = undefined, params = {}) {
939
+ await this.loadMarkets ();
940
+ // we use clientOrderId as the order id with this exchange intentionally
941
+ // because most of their endpoints will require clientOrderId
942
+ // explained here: https://github.com/ccxt/ccxt/issues/5674
943
+ const request = {
944
+ 'clientOrderId': id,
945
+ };
946
+ const response = await this.privateDeleteOrderClientOrderId (this.extend (request, params));
947
+ return this.parseOrder (response);
948
+ }
949
+
950
+ parseOrderStatus (status) {
951
+ const statuses = {
952
+ 'new': 'open',
953
+ 'suspended': 'open',
954
+ 'partiallyFilled': 'open',
955
+ 'filled': 'closed',
956
+ 'canceled': 'canceled',
957
+ 'expired': 'failed',
958
+ };
959
+ return this.safeString (statuses, status, status);
960
+ }
961
+
962
+ parseOrder (order, market = undefined) {
963
+ //
964
+ // createMarketOrder
965
+ //
966
+ // {
967
+ // clientOrderId: "fe36aa5e190149bf9985fb673bbb2ea0",
968
+ // createdAt: "2018-10-25T16:41:44.780Z",
969
+ // cumQuantity: "1",
970
+ // id: "66799540063",
971
+ // quantity: "1",
972
+ // side: "sell",
973
+ // status: "filled",
974
+ // symbol: "XRPUSDT",
975
+ // timeInForce: "FOK",
976
+ // tradesReport: [
977
+ // {
978
+ // fee: "0.0004644",
979
+ // id: 386394956,
980
+ // price: "0.4644",
981
+ // quantity: "1",
982
+ // timestamp: "2018-10-25T16:41:44.780Z"
983
+ // }
984
+ // ],
985
+ // type: "market",
986
+ // updatedAt: "2018-10-25T16:41:44.780Z"
987
+ // }
988
+ //
989
+ // {
990
+ // "id": 119499457455,
991
+ // "clientOrderId": "87baab109d58401b9202fa0749cb8288",
992
+ // "symbol": "ETHUSD",
993
+ // "side": "buy",
994
+ // "status": "filled",
995
+ // "type": "market",
996
+ // "timeInForce": "FOK",
997
+ // "quantity": "0.0007",
998
+ // "price": "181.487",
999
+ // "avgPrice": "164.989",
1000
+ // "cumQuantity": "0.0007",
1001
+ // "createdAt": "2019-04-17T13:27:38.062Z",
1002
+ // "updatedAt": "2019-04-17T13:27:38.062Z"
1003
+ // }
1004
+ //
1005
+ const created = this.parse8601 (this.safeString (order, 'createdAt'));
1006
+ const updated = this.parse8601 (this.safeString (order, 'updatedAt'));
1007
+ const marketId = this.safeString (order, 'symbol');
1008
+ market = this.safeMarket (marketId, market);
1009
+ const symbol = market['symbol'];
1010
+ const amount = this.safeString (order, 'quantity');
1011
+ const filled = this.safeString (order, 'cumQuantity');
1012
+ const status = this.parseOrderStatus (this.safeString (order, 'status'));
1013
+ // we use clientOrderId as the order id with this exchange intentionally
1014
+ // because most of their endpoints will require clientOrderId
1015
+ // explained here: https://github.com/ccxt/ccxt/issues/5674
1016
+ const id = this.safeString (order, 'clientOrderId');
1017
+ const clientOrderId = id;
1018
+ const price = this.safeString (order, 'price');
1019
+ const type = this.safeString (order, 'type');
1020
+ const side = this.safeString (order, 'side');
1021
+ const trades = this.safeValue (order, 'tradesReport');
1022
+ const fee = undefined;
1023
+ const average = this.safeString (order, 'avgPrice');
1024
+ const timeInForce = this.safeString (order, 'timeInForce');
1025
+ return this.safeOrder ({
1026
+ 'id': id,
1027
+ 'clientOrderId': clientOrderId, // https://github.com/ccxt/ccxt/issues/5674
1028
+ 'timestamp': created,
1029
+ 'datetime': this.iso8601 (created),
1030
+ 'lastTradeTimestamp': updated,
1031
+ 'status': status,
1032
+ 'symbol': symbol,
1033
+ 'type': type,
1034
+ 'timeInForce': timeInForce,
1035
+ 'side': side,
1036
+ 'price': price,
1037
+ 'stopPrice': undefined,
1038
+ 'average': average,
1039
+ 'amount': amount,
1040
+ 'cost': undefined,
1041
+ 'filled': filled,
1042
+ 'remaining': undefined,
1043
+ 'fee': fee,
1044
+ 'trades': trades,
1045
+ 'info': order,
1046
+ }, market);
1047
+ }
1048
+
1049
+ async fetchOrder (id, symbol = undefined, params = {}) {
1050
+ await this.loadMarkets ();
1051
+ // we use clientOrderId as the order id with this exchange intentionally
1052
+ // because most of their endpoints will require clientOrderId
1053
+ // explained here: https://github.com/ccxt/ccxt/issues/5674
1054
+ const request = {
1055
+ 'clientOrderId': id,
1056
+ };
1057
+ const response = await this.privateGetHistoryOrder (this.extend (request, params));
1058
+ const numOrders = response.length;
1059
+ if (numOrders > 0) {
1060
+ return this.parseOrder (response[0]);
1061
+ }
1062
+ throw new OrderNotFound (this.id + ' order ' + id + ' not found');
1063
+ }
1064
+
1065
+ async fetchOpenOrder (id, symbol = undefined, params = {}) {
1066
+ await this.loadMarkets ();
1067
+ // we use clientOrderId as the order id with this exchange intentionally
1068
+ // because most of their endpoints will require clientOrderId
1069
+ // explained here: https://github.com/ccxt/ccxt/issues/5674
1070
+ const request = {
1071
+ 'clientOrderId': id,
1072
+ };
1073
+ const response = await this.privateGetOrderClientOrderId (this.extend (request, params));
1074
+ return this.parseOrder (response);
1075
+ }
1076
+
1077
+ async fetchOpenOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) {
1078
+ await this.loadMarkets ();
1079
+ let market = undefined;
1080
+ const request = {};
1081
+ if (symbol !== undefined) {
1082
+ market = this.market (symbol);
1083
+ request['symbol'] = market['id'];
1084
+ }
1085
+ const response = await this.privateGetOrder (this.extend (request, params));
1086
+ return this.parseOrders (response, market, since, limit);
1087
+ }
1088
+
1089
+ async fetchClosedOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) {
1090
+ await this.loadMarkets ();
1091
+ let market = undefined;
1092
+ const request = {};
1093
+ if (symbol !== undefined) {
1094
+ market = this.market (symbol);
1095
+ request['symbol'] = market['id'];
1096
+ }
1097
+ if (limit !== undefined) {
1098
+ request['limit'] = limit;
1099
+ }
1100
+ if (since !== undefined) {
1101
+ request['from'] = this.iso8601 (since);
1102
+ }
1103
+ const response = await this.privateGetHistoryOrder (this.extend (request, params));
1104
+ const parsedOrders = this.parseOrders (response, market);
1105
+ const orders = [];
1106
+ for (let i = 0; i < parsedOrders.length; i++) {
1107
+ const order = parsedOrders[i];
1108
+ const status = order['status'];
1109
+ if ((status === 'closed') || (status === 'canceled')) {
1110
+ orders.push (order);
1111
+ }
1112
+ }
1113
+ return this.filterBySinceLimit (orders, since, limit);
1114
+ }
1115
+
1116
+ async fetchMyTrades (symbol = undefined, since = undefined, limit = undefined, params = {}) {
1117
+ await this.loadMarkets ();
1118
+ const request = {
1119
+ // 'symbol': 'BTC/USD', // optional
1120
+ // 'sort': 'DESC', // or 'ASC'
1121
+ // 'by': 'timestamp', // or 'id' String timestamp by default, or id
1122
+ // 'from': 'Datetime or Number', // ISO 8601
1123
+ // 'till': 'Datetime or Number',
1124
+ // 'limit': 100,
1125
+ // 'offset': 0,
1126
+ };
1127
+ let market = undefined;
1128
+ if (symbol !== undefined) {
1129
+ market = this.market (symbol);
1130
+ request['symbol'] = market['id'];
1131
+ }
1132
+ if (since !== undefined) {
1133
+ request['from'] = this.iso8601 (since);
1134
+ }
1135
+ if (limit !== undefined) {
1136
+ request['limit'] = limit;
1137
+ }
1138
+ const response = await this.privateGetHistoryTrades (this.extend (request, params));
1139
+ //
1140
+ // [
1141
+ // {
1142
+ // "id": 9535486,
1143
+ // "clientOrderId": "f8dbaab336d44d5ba3ff578098a68454",
1144
+ // "orderId": 816088377,
1145
+ // "symbol": "ETHBTC",
1146
+ // "side": "sell",
1147
+ // "quantity": "0.061",
1148
+ // "price": "0.045487",
1149
+ // "fee": "0.000002775",
1150
+ // "timestamp": "2017-05-17T12:32:57.848Z"
1151
+ // },
1152
+ // {
1153
+ // "id": 9535437,
1154
+ // "clientOrderId": "27b9bfc068b44194b1f453c7af511ed6",
1155
+ // "orderId": 816088021,
1156
+ // "symbol": "ETHBTC",
1157
+ // "side": "buy",
1158
+ // "quantity": "0.038",
1159
+ // "price": "0.046000",
1160
+ // "fee": "-0.000000174",
1161
+ // "timestamp": "2017-05-17T12:30:57.848Z"
1162
+ // }
1163
+ // ]
1164
+ //
1165
+ return this.parseTrades (response, market, since, limit);
1166
+ }
1167
+
1168
+ async fetchOrderTrades (id, symbol = undefined, since = undefined, limit = undefined, params = {}) {
1169
+ // The id needed here is the exchange's id, and not the clientOrderID,
1170
+ // which is the id that is stored in the unified order id
1171
+ // To get the exchange's id you need to grab it from order['info']['id']
1172
+ await this.loadMarkets ();
1173
+ let market = undefined;
1174
+ if (symbol !== undefined) {
1175
+ market = this.market (symbol);
1176
+ }
1177
+ const request = {
1178
+ 'orderId': id,
1179
+ };
1180
+ const response = await this.privateGetHistoryOrderOrderIdTrades (this.extend (request, params));
1181
+ const numOrders = response.length;
1182
+ if (numOrders > 0) {
1183
+ return this.parseTrades (response, market, since, limit);
1184
+ }
1185
+ throw new OrderNotFound (this.id + ' order ' + id + ' not found, ' + this.id + '.fetchOrderTrades() requires an exchange-specific order id, you need to grab it from order["info"]["id"]');
1186
+ }
1187
+
1188
+ async createDepositAddress (code, params = {}) {
1189
+ await this.loadMarkets ();
1190
+ const currency = this.currency (code);
1191
+ const request = {
1192
+ 'currency': currency['id'],
1193
+ };
1194
+ const response = await this.privatePostAccountCryptoAddressCurrency (this.extend (request, params));
1195
+ const address = this.safeString (response, 'address');
1196
+ this.checkAddress (address);
1197
+ const tag = this.safeString (response, 'paymentId');
1198
+ return {
1199
+ 'currency': currency,
1200
+ 'address': address,
1201
+ 'tag': tag,
1202
+ 'info': response,
1203
+ };
1204
+ }
1205
+
1206
+ async fetchDepositAddress (code, params = {}) {
1207
+ await this.loadMarkets ();
1208
+ const currency = this.currency (code);
1209
+ const request = {
1210
+ 'currency': currency['id'],
1211
+ };
1212
+ const network = this.safeString (params, 'network');
1213
+ if (network !== undefined) {
1214
+ params = this.omit (params, 'network');
1215
+ const networks = this.safeValue (this.options, 'networks');
1216
+ const endpart = this.safeString (networks, network, network);
1217
+ request['currency'] += endpart;
1218
+ }
1219
+ const response = await this.privateGetAccountCryptoAddressCurrency (this.extend (request, params));
1220
+ const address = this.safeString (response, 'address');
1221
+ this.checkAddress (address);
1222
+ const tag = this.safeString (response, 'paymentId');
1223
+ return {
1224
+ 'currency': currency['code'],
1225
+ 'address': address,
1226
+ 'tag': tag,
1227
+ 'network': undefined,
1228
+ 'info': response,
1229
+ };
1230
+ }
1231
+
1232
+ async convertCurrencyNetwork (code, amount, fromNetwork, toNetwork, params) {
1233
+ await this.loadMarkets ();
1234
+ const currency = this.currency (code);
1235
+ const networks = this.safeValue (this.options, 'networks', {});
1236
+ fromNetwork = this.safeString (networks, fromNetwork, fromNetwork); // handle ETH>ERC20 alias
1237
+ toNetwork = this.safeString (networks, toNetwork, toNetwork); // handle ETH>ERC20 alias
1238
+ if (fromNetwork === toNetwork) {
1239
+ throw new ExchangeError (this.id + ' convertCurrencyNetwork() fromNetwork cannot be the same as toNetwork');
1240
+ }
1241
+ const request = {
1242
+ 'fromCurrency': currency['id'] + fromNetwork,
1243
+ 'toCurrency': currency['id'] + toNetwork,
1244
+ 'amount': parseFloat (this.currencyToPrecision (code, amount)),
1245
+ };
1246
+ const response = await this.privatePostAccountCryptoTransferConvert (this.extend (request, params));
1247
+ return {
1248
+ 'info': response,
1249
+ };
1250
+ }
1251
+
1252
+ async withdraw (code, amount, address, tag = undefined, params = {}) {
1253
+ [ tag, params ] = this.handleWithdrawTagAndParams (tag, params);
1254
+ await this.loadMarkets ();
1255
+ this.checkAddress (address);
1256
+ const currency = this.currency (code);
1257
+ const request = {
1258
+ 'currency': currency['id'],
1259
+ 'amount': parseFloat (amount),
1260
+ 'address': address,
1261
+ };
1262
+ if (tag) {
1263
+ request['paymentId'] = tag;
1264
+ }
1265
+ const networks = this.safeValue (this.options, 'networks', {});
1266
+ let network = this.safeStringUpper (params, 'network'); // this line allows the user to specify either ERC20 or ETH
1267
+ network = this.safeString (networks, network, network); // handle ERC20>ETH alias
1268
+ if (network !== undefined) {
1269
+ request['currency'] += network; // when network the currency need to be changed to currency + network
1270
+ params = this.omit (params, 'network');
1271
+ }
1272
+ const response = await this.privatePostAccountCryptoWithdraw (this.extend (request, params));
1273
+ //
1274
+ // {
1275
+ // "id": "d2ce578f-647d-4fa0-b1aa-4a27e5ee597b"
1276
+ // }
1277
+ //
1278
+ return this.parseTransaction (response, currency);
1279
+ }
1280
+
1281
+ nonce () {
1282
+ return this.milliseconds ();
1283
+ }
1284
+
1285
+ sign (path, api = 'public', method = 'GET', params = {}, headers = undefined, body = undefined) {
1286
+ let url = '/api/' + this.version + '/';
1287
+ const query = this.omit (params, this.extractParams (path));
1288
+ if (api === 'public') {
1289
+ url += api + '/' + this.implodeParams (path, params);
1290
+ if (Object.keys (query).length) {
1291
+ url += '?' + this.urlencode (query);
1292
+ }
1293
+ } else {
1294
+ this.checkRequiredCredentials ();
1295
+ url += this.implodeParams (path, params);
1296
+ if (method === 'GET') {
1297
+ if (Object.keys (query).length) {
1298
+ url += '?' + this.urlencode (query);
1299
+ }
1300
+ } else if (Object.keys (query).length) {
1301
+ body = this.json (query);
1302
+ }
1303
+ const payload = this.encode (this.apiKey + ':' + this.secret);
1304
+ const auth = this.stringToBase64 (payload);
1305
+ headers = {
1306
+ 'Authorization': 'Basic ' + this.decode (auth),
1307
+ 'Content-Type': 'application/json',
1308
+ };
1309
+ }
1310
+ url = this.urls['api'][api] + url;
1311
+ return { 'url': url, 'method': method, 'body': body, 'headers': headers };
1312
+ }
1313
+
1314
+ handleErrors (code, reason, url, method, headers, body, response, requestHeaders, requestBody) {
1315
+ if (response === undefined) {
1316
+ return;
1317
+ }
1318
+ if (code >= 400) {
1319
+ const feedback = this.id + ' ' + body;
1320
+ // {"code":504,"message":"Gateway Timeout","description":""}
1321
+ if ((code === 503) || (code === 504)) {
1322
+ throw new ExchangeNotAvailable (feedback);
1323
+ }
1324
+ // fallback to default error handler on rate limit errors
1325
+ // {"code":429,"message":"Too many requests","description":"Too many requests"}
1326
+ if (code === 429) {
1327
+ return;
1328
+ }
1329
+ // {"error":{"code":20002,"message":"Order not found","description":""}}
1330
+ if (body[0] === '{') {
1331
+ if ('error' in response) {
1332
+ const errorCode = this.safeString (response['error'], 'code');
1333
+ this.throwExactlyMatchedException (this.exceptions, errorCode, feedback);
1334
+ const message = this.safeString (response['error'], 'message');
1335
+ if (message === 'Duplicate clientOrderId') {
1336
+ throw new InvalidOrder (feedback);
1337
+ }
1338
+ }
1339
+ }
1340
+ throw new ExchangeError (feedback);
1341
+ }
1342
+ }
1343
+ };