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/cex.js ADDED
@@ -0,0 +1,1410 @@
1
+ 'use strict';
2
+
3
+ // ---------------------------------------------------------------------------
4
+
5
+ const Exchange = require ('./base/Exchange');
6
+ const { ExchangeError, ArgumentsRequired, AuthenticationError, NullResponse, InvalidOrder, NotSupported, InsufficientFunds, InvalidNonce, OrderNotFound, RateLimitExceeded, DDoSProtection, BadSymbol } = require ('./base/errors');
7
+ const Precise = require ('./base/Precise');
8
+
9
+ // ---------------------------------------------------------------------------
10
+
11
+ module.exports = class cex extends Exchange {
12
+ describe () {
13
+ return this.deepExtend (super.describe (), {
14
+ 'id': 'cex',
15
+ 'name': 'CEX.IO',
16
+ 'countries': [ 'GB', 'EU', 'CY', 'RU' ],
17
+ 'rateLimit': 1500,
18
+ 'has': {
19
+ 'CORS': undefined,
20
+ 'spot': true,
21
+ 'margin': undefined, // has but unimplemented
22
+ 'swap': false,
23
+ 'future': false,
24
+ 'option': false,
25
+ 'cancelOrder': true,
26
+ 'createOrder': true,
27
+ 'editOrder': true,
28
+ 'fetchBalance': true,
29
+ 'fetchClosedOrders': true,
30
+ 'fetchCurrencies': true,
31
+ 'fetchDeposit': false,
32
+ 'fetchDepositAddress': true,
33
+ 'fetchDeposits': false,
34
+ 'fetchFundingHistory': false,
35
+ 'fetchFundingRate': false,
36
+ 'fetchFundingRateHistory': false,
37
+ 'fetchFundingRates': false,
38
+ 'fetchIndexOHLCV': false,
39
+ 'fetchMarkets': true,
40
+ 'fetchMarkOHLCV': false,
41
+ 'fetchOHLCV': true,
42
+ 'fetchOpenOrders': true,
43
+ 'fetchOrder': true,
44
+ 'fetchOrderBook': true,
45
+ 'fetchOrders': true,
46
+ 'fetchPremiumIndexOHLCV': false,
47
+ 'fetchTicker': true,
48
+ 'fetchTickers': true,
49
+ 'fetchTrades': true,
50
+ 'fetchTradingFee': false,
51
+ 'fetchTradingFees': true,
52
+ 'fetchTransfer': false,
53
+ 'fetchTransfers': false,
54
+ 'fetchWithdrawal': false,
55
+ 'fetchWithdrawals': false,
56
+ 'transfer': false,
57
+ 'withdraw': false,
58
+ },
59
+ 'timeframes': {
60
+ '1m': '1m',
61
+ '1h': '1h',
62
+ '1d': '1d',
63
+ },
64
+ 'urls': {
65
+ 'logo': 'https://user-images.githubusercontent.com/1294454/27766442-8ddc33b0-5ed8-11e7-8b98-f786aef0f3c9.jpg',
66
+ 'api': 'https://cex.io/api',
67
+ 'www': 'https://cex.io',
68
+ 'doc': 'https://cex.io/cex-api',
69
+ 'fees': [
70
+ 'https://cex.io/fee-schedule',
71
+ 'https://cex.io/limits-commissions',
72
+ ],
73
+ 'referral': 'https://cex.io/r/0/up105393824/0/',
74
+ },
75
+ 'requiredCredentials': {
76
+ 'apiKey': true,
77
+ 'secret': true,
78
+ 'uid': true,
79
+ },
80
+ 'api': {
81
+ 'public': {
82
+ 'get': [
83
+ 'currency_profile',
84
+ 'currency_limits/',
85
+ 'last_price/{pair}/',
86
+ 'last_prices/{currencies}/',
87
+ 'ohlcv/hd/{yyyymmdd}/{pair}',
88
+ 'order_book/{pair}/',
89
+ 'ticker/{pair}/',
90
+ 'tickers/{currencies}/',
91
+ 'trade_history/{pair}/',
92
+ ],
93
+ 'post': [
94
+ 'convert/{pair}',
95
+ 'price_stats/{pair}',
96
+ ],
97
+ },
98
+ 'private': {
99
+ 'post': [
100
+ 'active_orders_status/',
101
+ 'archived_orders/{pair}/',
102
+ 'balance/',
103
+ 'cancel_order/',
104
+ 'cancel_orders/{pair}/',
105
+ 'cancel_replace_order/{pair}/',
106
+ 'close_position/{pair}/',
107
+ 'get_address/',
108
+ 'get_myfee/',
109
+ 'get_order/',
110
+ 'get_order_tx/',
111
+ 'open_orders/{pair}/',
112
+ 'open_orders/',
113
+ 'open_position/{pair}/',
114
+ 'open_positions/{pair}/',
115
+ 'place_order/{pair}/',
116
+ 'raw_tx_history',
117
+ ],
118
+ },
119
+ },
120
+ 'fees': {
121
+ 'trading': {
122
+ 'maker': this.parseNumber ('0.0016'),
123
+ 'taker': this.parseNumber ('0.0025'),
124
+ },
125
+ 'funding': {
126
+ 'withdraw': {},
127
+ 'deposit': {
128
+ // 'USD': amount => amount * 0.035 + 0.25,
129
+ // 'EUR': amount => amount * 0.035 + 0.24,
130
+ // 'RUB': amount => amount * 0.05 + 15.57,
131
+ // 'GBP': amount => amount * 0.035 + 0.2,
132
+ 'BTC': 0.0,
133
+ 'ETH': 0.0,
134
+ 'BCH': 0.0,
135
+ 'DASH': 0.0,
136
+ 'BTG': 0.0,
137
+ 'ZEC': 0.0,
138
+ 'XRP': 0.0,
139
+ 'XLM': 0.0,
140
+ },
141
+ },
142
+ },
143
+ 'exceptions': {
144
+ 'exact': {},
145
+ 'broad': {
146
+ 'Insufficient funds': InsufficientFunds,
147
+ 'Nonce must be incremented': InvalidNonce,
148
+ 'Invalid Order': InvalidOrder,
149
+ 'Order not found': OrderNotFound,
150
+ 'limit exceeded': RateLimitExceeded, // {"error":"rate limit exceeded"}
151
+ 'Invalid API key': AuthenticationError,
152
+ 'There was an error while placing your order': InvalidOrder,
153
+ 'Sorry, too many clients already': DDoSProtection,
154
+ 'Invalid Symbols Pair': BadSymbol,
155
+ },
156
+ },
157
+ 'options': {
158
+ 'fetchOHLCVWarning': true,
159
+ 'createMarketBuyOrderRequiresPrice': true,
160
+ 'order': {
161
+ 'status': {
162
+ 'c': 'canceled',
163
+ 'd': 'closed',
164
+ 'cd': 'canceled',
165
+ 'a': 'open',
166
+ },
167
+ },
168
+ },
169
+ });
170
+ }
171
+
172
+ async fetchCurrenciesFromCache (params = {}) {
173
+ // this method is now redundant
174
+ // currencies are now fetched before markets
175
+ const options = this.safeValue (this.options, 'fetchCurrencies', {});
176
+ const timestamp = this.safeInteger (options, 'timestamp');
177
+ const expires = this.safeInteger (options, 'expires', 1000);
178
+ const now = this.milliseconds ();
179
+ if ((timestamp === undefined) || ((now - timestamp) > expires)) {
180
+ const response = await this.publicGetCurrencyProfile (params);
181
+ this.options['fetchCurrencies'] = this.extend (options, {
182
+ 'response': response,
183
+ 'timestamp': now,
184
+ });
185
+ }
186
+ return this.safeValue (this.options['fetchCurrencies'], 'response');
187
+ }
188
+
189
+ async fetchCurrencies (params = {}) {
190
+ const response = await this.fetchCurrenciesFromCache (params);
191
+ this.options['currencies'] = {
192
+ 'timestamp': this.milliseconds (),
193
+ 'response': response,
194
+ };
195
+ //
196
+ // {
197
+ // "e":"currency_profile",
198
+ // "ok":"ok",
199
+ // "data":{
200
+ // "symbols":[
201
+ // {
202
+ // "code":"GHS",
203
+ // "contract":true,
204
+ // "commodity":true,
205
+ // "fiat":false,
206
+ // "description":"CEX.IO doesn't provide cloud mining services anymore.",
207
+ // "precision":8,
208
+ // "scale":0,
209
+ // "minimumCurrencyAmount":"0.00000001",
210
+ // "minimalWithdrawalAmount":-1
211
+ // },
212
+ // {
213
+ // "code":"BTC",
214
+ // "contract":false,
215
+ // "commodity":false,
216
+ // "fiat":false,
217
+ // "description":"",
218
+ // "precision":8,
219
+ // "scale":0,
220
+ // "minimumCurrencyAmount":"0.00000001",
221
+ // "minimalWithdrawalAmount":0.002
222
+ // },
223
+ // {
224
+ // "code":"ETH",
225
+ // "contract":false,
226
+ // "commodity":false,
227
+ // "fiat":false,
228
+ // "description":"",
229
+ // "precision":8,
230
+ // "scale":2,
231
+ // "minimumCurrencyAmount":"0.00000100",
232
+ // "minimalWithdrawalAmount":0.01
233
+ // }
234
+ // ],
235
+ // "pairs":[
236
+ // {
237
+ // "symbol1":"BTC",
238
+ // "symbol2":"USD",
239
+ // "pricePrecision":1,
240
+ // "priceScale":"/1000000",
241
+ // "minLotSize":0.002,
242
+ // "minLotSizeS2":20
243
+ // },
244
+ // {
245
+ // "symbol1":"ETH",
246
+ // "symbol2":"USD",
247
+ // "pricePrecision":2,
248
+ // "priceScale":"/10000",
249
+ // "minLotSize":0.1,
250
+ // "minLotSizeS2":20
251
+ // }
252
+ // ]
253
+ // }
254
+ // }
255
+ //
256
+ const data = this.safeValue (response, 'data', []);
257
+ const currencies = this.safeValue (data, 'symbols', []);
258
+ const result = {};
259
+ for (let i = 0; i < currencies.length; i++) {
260
+ const currency = currencies[i];
261
+ const id = this.safeString (currency, 'code');
262
+ const code = this.safeCurrencyCode (id);
263
+ const precision = this.safeInteger (currency, 'precision');
264
+ const active = true;
265
+ result[code] = {
266
+ 'id': id,
267
+ 'code': code,
268
+ 'name': id,
269
+ 'active': active,
270
+ 'deposit': undefined,
271
+ 'withdraw': undefined,
272
+ 'precision': precision,
273
+ 'fee': undefined,
274
+ 'limits': {
275
+ 'amount': {
276
+ 'min': this.safeNumber (currency, 'minimumCurrencyAmount'),
277
+ 'max': undefined,
278
+ },
279
+ 'withdraw': {
280
+ 'min': this.safeNumber (currency, 'minimalWithdrawalAmount'),
281
+ 'max': undefined,
282
+ },
283
+ },
284
+ 'info': currency,
285
+ };
286
+ }
287
+ return result;
288
+ }
289
+
290
+ async fetchMarkets (params = {}) {
291
+ const currenciesResponse = await this.fetchCurrenciesFromCache (params);
292
+ const currenciesData = this.safeValue (currenciesResponse, 'data', {});
293
+ const currencies = this.safeValue (currenciesData, 'symbols', []);
294
+ const currenciesById = this.indexBy (currencies, 'code');
295
+ const pairs = this.safeValue (currenciesData, 'pairs', []);
296
+ const response = await this.publicGetCurrencyLimits (params);
297
+ //
298
+ // {
299
+ // "e":"currency_limits",
300
+ // "ok":"ok",
301
+ // "data": {
302
+ // "pairs":[
303
+ // {
304
+ // "symbol1":"BTC",
305
+ // "symbol2":"USD",
306
+ // "minLotSize":0.002,
307
+ // "minLotSizeS2":20,
308
+ // "maxLotSize":30,
309
+ // "minPrice":"1500",
310
+ // "maxPrice":"35000"
311
+ // },
312
+ // {
313
+ // "symbol1":"BCH",
314
+ // "symbol2":"EUR",
315
+ // "minLotSize":0.1,
316
+ // "minLotSizeS2":20,
317
+ // "maxLotSize":null,
318
+ // "minPrice":"25",
319
+ // "maxPrice":"8192"
320
+ // }
321
+ // ]
322
+ // }
323
+ // }
324
+ //
325
+ const result = [];
326
+ const markets = this.safeValue (response['data'], 'pairs');
327
+ for (let i = 0; i < markets.length; i++) {
328
+ const market = markets[i];
329
+ const baseId = this.safeString (market, 'symbol1');
330
+ const quoteId = this.safeString (market, 'symbol2');
331
+ const base = this.safeCurrencyCode (baseId);
332
+ const quote = this.safeCurrencyCode (quoteId);
333
+ const baseCurrency = this.safeValue (currenciesById, baseId, {});
334
+ const quoteCurrency = this.safeValue (currenciesById, quoteId, {});
335
+ let pricePrecision = this.safeInteger (quoteCurrency, 'precision', 8);
336
+ for (let j = 0; j < pairs.length; j++) {
337
+ const pair = pairs[j];
338
+ if ((pair['symbol1'] === baseId) && (pair['symbol2'] === quoteId)) {
339
+ // we might need to account for `priceScale` here
340
+ pricePrecision = this.safeInteger (pair, 'pricePrecision', pricePrecision);
341
+ }
342
+ }
343
+ const baseCcyPrecision = this.safeString (baseCurrency, 'precision', '8');
344
+ const baseCcyScale = this.safeString (baseCurrency, 'scale', '0');
345
+ result.push ({
346
+ 'id': baseId + '/' + quoteId,
347
+ 'symbol': base + '/' + quote,
348
+ 'base': base,
349
+ 'quote': quote,
350
+ 'settle': undefined,
351
+ 'baseId': baseId,
352
+ 'quoteId': quoteId,
353
+ 'settleId': undefined,
354
+ 'type': 'spot',
355
+ 'spot': true,
356
+ 'margin': undefined,
357
+ 'swap': false,
358
+ 'future': false,
359
+ 'option': false,
360
+ 'active': undefined,
361
+ 'contract': false,
362
+ 'linear': undefined,
363
+ 'inverse': undefined,
364
+ 'contractSize': undefined,
365
+ 'expiry': undefined,
366
+ 'expiryDatetime': undefined,
367
+ 'strike': undefined,
368
+ 'optionType': undefined,
369
+ 'precision': {
370
+ 'amount': parseInt (Precise.stringSub (baseCcyPrecision, baseCcyScale)),
371
+ 'price': pricePrecision,
372
+ },
373
+ 'limits': {
374
+ 'leverage': {
375
+ 'min': undefined,
376
+ 'max': undefined,
377
+ },
378
+ 'amount': {
379
+ 'min': this.safeNumber (market, 'minLotSize'),
380
+ 'max': this.safeNumber (market, 'maxLotSize'),
381
+ },
382
+ 'price': {
383
+ 'min': this.safeNumber (market, 'minPrice'),
384
+ 'max': this.safeNumber (market, 'maxPrice'),
385
+ },
386
+ 'cost': {
387
+ 'min': this.safeNumber (market, 'minLotSizeS2'),
388
+ 'max': undefined,
389
+ },
390
+ },
391
+ 'info': market,
392
+ });
393
+ }
394
+ return result;
395
+ }
396
+
397
+ parseBalance (response) {
398
+ const result = { 'info': response };
399
+ const ommited = [ 'username', 'timestamp' ];
400
+ const balances = this.omit (response, ommited);
401
+ const currencyIds = Object.keys (balances);
402
+ for (let i = 0; i < currencyIds.length; i++) {
403
+ const currencyId = currencyIds[i];
404
+ const balance = this.safeValue (balances, currencyId, {});
405
+ const account = this.account ();
406
+ account['free'] = this.safeString (balance, 'available');
407
+ // https://github.com/ccxt/ccxt/issues/5484
408
+ account['used'] = this.safeString (balance, 'orders', '0');
409
+ const code = this.safeCurrencyCode (currencyId);
410
+ result[code] = account;
411
+ }
412
+ return this.safeBalance (result);
413
+ }
414
+
415
+ async fetchBalance (params = {}) {
416
+ await this.loadMarkets ();
417
+ const response = await this.privatePostBalance (params);
418
+ return this.parseBalance (response);
419
+ }
420
+
421
+ async fetchOrderBook (symbol, limit = undefined, params = {}) {
422
+ await this.loadMarkets ();
423
+ const request = {
424
+ 'pair': this.marketId (symbol),
425
+ };
426
+ if (limit !== undefined) {
427
+ request['depth'] = limit;
428
+ }
429
+ const response = await this.publicGetOrderBookPair (this.extend (request, params));
430
+ const timestamp = this.safeTimestamp (response, 'timestamp');
431
+ return this.parseOrderBook (response, symbol, timestamp);
432
+ }
433
+
434
+ parseOHLCV (ohlcv, market = undefined) {
435
+ //
436
+ // [
437
+ // 1591403940,
438
+ // 0.024972,
439
+ // 0.024972,
440
+ // 0.024969,
441
+ // 0.024969,
442
+ // 0.49999900
443
+ // ]
444
+ //
445
+ return [
446
+ this.safeTimestamp (ohlcv, 0),
447
+ this.safeNumber (ohlcv, 1),
448
+ this.safeNumber (ohlcv, 2),
449
+ this.safeNumber (ohlcv, 3),
450
+ this.safeNumber (ohlcv, 4),
451
+ this.safeNumber (ohlcv, 5),
452
+ ];
453
+ }
454
+
455
+ async fetchOHLCV (symbol, timeframe = '1m', since = undefined, limit = undefined, params = {}) {
456
+ await this.loadMarkets ();
457
+ const market = this.market (symbol);
458
+ if (since === undefined) {
459
+ since = this.milliseconds () - 86400000; // yesterday
460
+ } else {
461
+ if (this.options['fetchOHLCVWarning']) {
462
+ throw new ExchangeError (this.id + " fetchOHLCV warning: CEX can return historical candles for a certain date only, this might produce an empty or null reply. Set exchange.options['fetchOHLCVWarning'] = false or add ({ 'options': { 'fetchOHLCVWarning': false }}) to constructor params to suppress this warning message.");
463
+ }
464
+ }
465
+ const request = {
466
+ 'pair': market['id'],
467
+ 'yyyymmdd': this.yyyymmdd (since, ''),
468
+ };
469
+ try {
470
+ const response = await this.publicGetOhlcvHdYyyymmddPair (this.extend (request, params));
471
+ //
472
+ // {
473
+ // "time":20200606,
474
+ // "data1m":"[[1591403940,0.024972,0.024972,0.024969,0.024969,0.49999900]]",
475
+ // }
476
+ //
477
+ const key = 'data' + this.timeframes[timeframe];
478
+ const data = this.safeString (response, key);
479
+ const ohlcvs = JSON.parse (data);
480
+ return this.parseOHLCVs (ohlcvs, market, timeframe, since, limit);
481
+ } catch (e) {
482
+ if (e instanceof NullResponse) {
483
+ return [];
484
+ }
485
+ }
486
+ }
487
+
488
+ parseTicker (ticker, market = undefined) {
489
+ const timestamp = this.safeTimestamp (ticker, 'timestamp');
490
+ const volume = this.safeString (ticker, 'volume');
491
+ const high = this.safeString (ticker, 'high');
492
+ const low = this.safeString (ticker, 'low');
493
+ const bid = this.safeString (ticker, 'bid');
494
+ const ask = this.safeString (ticker, 'ask');
495
+ const last = this.safeString (ticker, 'last');
496
+ const symbol = this.safeSymbol (undefined, market);
497
+ return this.safeTicker ({
498
+ 'symbol': symbol,
499
+ 'timestamp': timestamp,
500
+ 'datetime': this.iso8601 (timestamp),
501
+ 'high': high,
502
+ 'low': low,
503
+ 'bid': bid,
504
+ 'bidVolume': undefined,
505
+ 'ask': ask,
506
+ 'askVolume': undefined,
507
+ 'vwap': undefined,
508
+ 'open': undefined,
509
+ 'close': last,
510
+ 'last': last,
511
+ 'previousClose': undefined,
512
+ 'change': undefined,
513
+ 'percentage': undefined,
514
+ 'average': undefined,
515
+ 'baseVolume': volume,
516
+ 'quoteVolume': undefined,
517
+ 'info': ticker,
518
+ }, market, false);
519
+ }
520
+
521
+ async fetchTickers (symbols = undefined, params = {}) {
522
+ await this.loadMarkets ();
523
+ const currencies = Object.keys (this.currencies);
524
+ const request = {
525
+ 'currencies': currencies.join ('/'),
526
+ };
527
+ const response = await this.publicGetTickersCurrencies (this.extend (request, params));
528
+ const tickers = this.safeValue (response, 'data', []);
529
+ const result = {};
530
+ for (let t = 0; t < tickers.length; t++) {
531
+ const ticker = tickers[t];
532
+ const marketId = this.safeString (ticker, 'pair');
533
+ const market = this.safeMarket (marketId, undefined, ':');
534
+ const symbol = market['symbol'];
535
+ result[symbol] = this.parseTicker (ticker, market);
536
+ }
537
+ return this.filterByArray (result, 'symbol', symbols);
538
+ }
539
+
540
+ async fetchTicker (symbol, params = {}) {
541
+ await this.loadMarkets ();
542
+ const market = this.market (symbol);
543
+ const request = {
544
+ 'pair': market['id'],
545
+ };
546
+ const ticker = await this.publicGetTickerPair (this.extend (request, params));
547
+ return this.parseTicker (ticker, market);
548
+ }
549
+
550
+ parseTrade (trade, market = undefined) {
551
+ //
552
+ // fetchTrades (public)
553
+ //
554
+ // {
555
+ // "type": "sell",
556
+ // "date": "1638401878",
557
+ // "amount": "0.401000",
558
+ // "price": "249",
559
+ // "tid": "11922"
560
+ // }
561
+ //
562
+ const timestamp = this.safeTimestamp (trade, 'date');
563
+ const id = this.safeString (trade, 'tid');
564
+ const type = undefined;
565
+ const side = this.safeString (trade, 'type');
566
+ const priceString = this.safeString (trade, 'price');
567
+ const amountString = this.safeString (trade, 'amount');
568
+ market = this.safeMarket (undefined, market);
569
+ return this.safeTrade ({
570
+ 'info': trade,
571
+ 'id': id,
572
+ 'timestamp': timestamp,
573
+ 'datetime': this.iso8601 (timestamp),
574
+ 'symbol': market['symbol'],
575
+ 'type': type,
576
+ 'side': side,
577
+ 'order': undefined,
578
+ 'takerOrMaker': undefined,
579
+ 'price': priceString,
580
+ 'amount': amountString,
581
+ 'cost': undefined,
582
+ 'fee': undefined,
583
+ }, market);
584
+ }
585
+
586
+ async fetchTrades (symbol, since = undefined, limit = undefined, params = {}) {
587
+ await this.loadMarkets ();
588
+ const market = this.market (symbol);
589
+ const request = {
590
+ 'pair': market['id'],
591
+ };
592
+ const response = await this.publicGetTradeHistoryPair (this.extend (request, params));
593
+ return this.parseTrades (response, market, since, limit);
594
+ }
595
+
596
+ async fetchTradingFees (params = {}) {
597
+ await this.loadMarkets ();
598
+ const response = await this.privatePostGetMyfee (params);
599
+ //
600
+ // {
601
+ // e: 'get_myfee',
602
+ // ok: 'ok',
603
+ // data: {
604
+ // 'BTC:USD': { buy: '0.25', sell: '0.25', buyMaker: '0.15', sellMaker: '0.15' },
605
+ // 'ETH:USD': { buy: '0.25', sell: '0.25', buyMaker: '0.15', sellMaker: '0.15' },
606
+ // ..
607
+ // }
608
+ // }
609
+ //
610
+ const data = this.safeValue (response, 'data', {});
611
+ const result = {};
612
+ for (let i = 0; i < this.symbols.length; i++) {
613
+ const symbol = this.symbols[i];
614
+ const market = this.market (symbol);
615
+ const fee = this.safeValue (data, market['id'], {});
616
+ const makerString = this.safeString (fee, 'buyMaker');
617
+ const takerString = this.safeString (fee, 'buy');
618
+ const maker = this.parseNumber (Precise.stringDiv (makerString, '100'));
619
+ const taker = this.parseNumber (Precise.stringDiv (takerString, '100'));
620
+ result[symbol] = {
621
+ 'info': fee,
622
+ 'symbol': symbol,
623
+ 'maker': maker,
624
+ 'taker': taker,
625
+ 'percentage': true,
626
+ };
627
+ }
628
+ return result;
629
+ }
630
+
631
+ async createOrder (symbol, type, side, amount, price = undefined, params = {}) {
632
+ // for market buy it requires the amount of quote currency to spend
633
+ if ((type === 'market') && (side === 'buy')) {
634
+ if (this.options['createMarketBuyOrderRequiresPrice']) {
635
+ if (price === undefined) {
636
+ throw new InvalidOrder (this.id + " createOrder() requires the price argument with market buy orders to calculate total order cost (amount to spend), where cost = amount * price. Supply a price argument to createOrder() call if you want the cost to be calculated for you from price and amount, or, alternatively, add .options['createMarketBuyOrderRequiresPrice'] = false to supply the cost in the amount argument (the exchange-specific behaviour)");
637
+ } else {
638
+ amount = amount * price;
639
+ }
640
+ }
641
+ }
642
+ await this.loadMarkets ();
643
+ const request = {
644
+ 'pair': this.marketId (symbol),
645
+ 'type': side,
646
+ 'amount': amount,
647
+ };
648
+ if (type === 'limit') {
649
+ request['price'] = price;
650
+ } else {
651
+ request['order_type'] = type;
652
+ }
653
+ const response = await this.privatePostPlaceOrderPair (this.extend (request, params));
654
+ //
655
+ // {
656
+ // "id": "12978363524",
657
+ // "time": 1586610022259,
658
+ // "type": "buy",
659
+ // "price": "0.033934",
660
+ // "amount": "0.10722802",
661
+ // "pending": "0.10722802",
662
+ // "complete": false
663
+ // }
664
+ //
665
+ const placedAmount = this.safeNumber (response, 'amount');
666
+ const remaining = this.safeNumber (response, 'pending');
667
+ const timestamp = this.safeValue (response, 'time');
668
+ const complete = this.safeValue (response, 'complete');
669
+ const status = complete ? 'closed' : 'open';
670
+ let filled = undefined;
671
+ if ((placedAmount !== undefined) && (remaining !== undefined)) {
672
+ filled = Math.max (placedAmount - remaining, 0);
673
+ }
674
+ return {
675
+ 'id': this.safeString (response, 'id'),
676
+ 'info': response,
677
+ 'clientOrderId': undefined,
678
+ 'timestamp': timestamp,
679
+ 'datetime': this.iso8601 (timestamp),
680
+ 'lastTradeTimestamp': undefined,
681
+ 'type': type,
682
+ 'side': this.safeString (response, 'type'),
683
+ 'symbol': symbol,
684
+ 'status': status,
685
+ 'price': this.safeNumber (response, 'price'),
686
+ 'amount': placedAmount,
687
+ 'cost': undefined,
688
+ 'average': undefined,
689
+ 'remaining': remaining,
690
+ 'filled': filled,
691
+ 'fee': undefined,
692
+ 'trades': undefined,
693
+ };
694
+ }
695
+
696
+ async cancelOrder (id, symbol = undefined, params = {}) {
697
+ await this.loadMarkets ();
698
+ const request = {
699
+ 'id': id,
700
+ };
701
+ return await this.privatePostCancelOrder (this.extend (request, params));
702
+ }
703
+
704
+ parseOrder (order, market = undefined) {
705
+ // Depending on the call, 'time' can be a unix int, unix string or ISO string
706
+ // Yes, really
707
+ let timestamp = this.safeValue (order, 'time');
708
+ if (typeof timestamp === 'string' && timestamp.indexOf ('T') >= 0) {
709
+ // ISO8601 string
710
+ timestamp = this.parse8601 (timestamp);
711
+ } else {
712
+ // either integer or string integer
713
+ timestamp = parseInt (timestamp);
714
+ }
715
+ let symbol = undefined;
716
+ if (market === undefined) {
717
+ const baseId = this.safeString (order, 'symbol1');
718
+ const quoteId = this.safeString (order, 'symbol2');
719
+ const base = this.safeCurrencyCode (baseId);
720
+ const quote = this.safeCurrencyCode (quoteId);
721
+ symbol = base + '/' + quote;
722
+ if (symbol in this.markets) {
723
+ market = this.market (symbol);
724
+ }
725
+ }
726
+ const status = this.parseOrderStatus (this.safeString (order, 'status'));
727
+ const price = this.safeNumber (order, 'price');
728
+ let amount = this.safeNumber (order, 'amount');
729
+ // sell orders can have a negative amount
730
+ // https://github.com/ccxt/ccxt/issues/5338
731
+ if (amount !== undefined) {
732
+ amount = Math.abs (amount);
733
+ }
734
+ const remaining = this.safeNumber2 (order, 'pending', 'remains');
735
+ const filled = amount - remaining;
736
+ let fee = undefined;
737
+ let cost = undefined;
738
+ if (market !== undefined) {
739
+ symbol = market['symbol'];
740
+ const taCost = this.safeNumber (order, 'ta:' + market['quote']);
741
+ const ttaCost = this.safeNumber (order, 'tta:' + market['quote']);
742
+ cost = this.sum (taCost, ttaCost);
743
+ const baseFee = 'fa:' + market['base'];
744
+ const baseTakerFee = 'tfa:' + market['base'];
745
+ const quoteFee = 'fa:' + market['quote'];
746
+ const quoteTakerFee = 'tfa:' + market['quote'];
747
+ let feeRate = this.safeNumber (order, 'tradingFeeMaker');
748
+ if (!feeRate) {
749
+ feeRate = this.safeNumber (order, 'tradingFeeTaker', feeRate);
750
+ }
751
+ if (feeRate) {
752
+ feeRate /= 100.0; // convert to mathematically-correct percentage coefficients: 1.0 = 100%
753
+ }
754
+ if ((baseFee in order) || (baseTakerFee in order)) {
755
+ const baseFeeCost = this.safeNumber2 (order, baseFee, baseTakerFee);
756
+ fee = {
757
+ 'currency': market['base'],
758
+ 'rate': feeRate,
759
+ 'cost': baseFeeCost,
760
+ };
761
+ } else if ((quoteFee in order) || (quoteTakerFee in order)) {
762
+ const quoteFeeCost = this.safeNumber2 (order, quoteFee, quoteTakerFee);
763
+ fee = {
764
+ 'currency': market['quote'],
765
+ 'rate': feeRate,
766
+ 'cost': quoteFeeCost,
767
+ };
768
+ }
769
+ }
770
+ if (!cost) {
771
+ cost = price * filled;
772
+ }
773
+ const side = order['type'];
774
+ let trades = undefined;
775
+ const orderId = order['id'];
776
+ if ('vtx' in order) {
777
+ trades = [];
778
+ for (let i = 0; i < order['vtx'].length; i++) {
779
+ const item = order['vtx'][i];
780
+ const tradeSide = this.safeString (item, 'type');
781
+ if (tradeSide === 'cancel') {
782
+ // looks like this might represent the cancelled part of an order
783
+ // { id: '4426729543',
784
+ // type: 'cancel',
785
+ // time: '2017-09-22T00:24:30.476Z',
786
+ // user: 'up106404164',
787
+ // c: 'user:up106404164:a:BCH',
788
+ // d: 'order:4426728375:a:BCH',
789
+ // a: '0.09935956',
790
+ // amount: '0.09935956',
791
+ // balance: '0.42580261',
792
+ // symbol: 'BCH',
793
+ // order: '4426728375',
794
+ // buy: null,
795
+ // sell: null,
796
+ // pair: null,
797
+ // pos: null,
798
+ // cs: '0.42580261',
799
+ // ds: 0 }
800
+ continue;
801
+ }
802
+ const tradePrice = this.safeNumber (item, 'price');
803
+ if (tradePrice === undefined) {
804
+ // this represents the order
805
+ // {
806
+ // "a": "0.47000000",
807
+ // "c": "user:up106404164:a:EUR",
808
+ // "d": "order:6065499239:a:EUR",
809
+ // "cs": "1432.93",
810
+ // "ds": "476.72",
811
+ // "id": "6065499249",
812
+ // "buy": null,
813
+ // "pos": null,
814
+ // "pair": null,
815
+ // "sell": null,
816
+ // "time": "2018-04-22T13:07:22.152Z",
817
+ // "type": "buy",
818
+ // "user": "up106404164",
819
+ // "order": "6065499239",
820
+ // "amount": "-715.97000000",
821
+ // "symbol": "EUR",
822
+ // "balance": "1432.93000000" }
823
+ continue;
824
+ }
825
+ // todo: deal with these
826
+ if (tradeSide === 'costsNothing') {
827
+ continue;
828
+ }
829
+ // --
830
+ // if (side !== tradeSide)
831
+ // throw new Error (JSON.stringify (order, null, 2));
832
+ // if (orderId !== item['order'])
833
+ // throw new Error (JSON.stringify (order, null, 2));
834
+ // --
835
+ // partial buy trade
836
+ // {
837
+ // "a": "0.01589885",
838
+ // "c": "user:up106404164:a:BTC",
839
+ // "d": "order:6065499239:a:BTC",
840
+ // "cs": "0.36300000",
841
+ // "ds": 0,
842
+ // "id": "6067991213",
843
+ // "buy": "6065499239",
844
+ // "pos": null,
845
+ // "pair": null,
846
+ // "sell": "6067991206",
847
+ // "time": "2018-04-22T23:09:11.773Z",
848
+ // "type": "buy",
849
+ // "user": "up106404164",
850
+ // "order": "6065499239",
851
+ // "price": 7146.5,
852
+ // "amount": "0.01589885",
853
+ // "symbol": "BTC",
854
+ // "balance": "0.36300000",
855
+ // "symbol2": "EUR",
856
+ // "fee_amount": "0.19" }
857
+ // --
858
+ // trade with zero amount, but non-zero fee
859
+ // {
860
+ // "a": "0.00000000",
861
+ // "c": "user:up106404164:a:EUR",
862
+ // "d": "order:5840654423:a:EUR",
863
+ // "cs": 559744,
864
+ // "ds": 0,
865
+ // "id": "5840654429",
866
+ // "buy": "5807238573",
867
+ // "pos": null,
868
+ // "pair": null,
869
+ // "sell": "5840654423",
870
+ // "time": "2018-03-15T03:20:14.010Z",
871
+ // "type": "sell",
872
+ // "user": "up106404164",
873
+ // "order": "5840654423",
874
+ // "price": 730,
875
+ // "amount": "0.00000000",
876
+ // "symbol": "EUR",
877
+ // "balance": "5597.44000000",
878
+ // "symbol2": "BCH",
879
+ // "fee_amount": "0.01" }
880
+ // --
881
+ // trade which should have an amount of exactly 0.002BTC
882
+ // {
883
+ // "a": "16.70000000",
884
+ // "c": "user:up106404164:a:GBP",
885
+ // "d": "order:9927386681:a:GBP",
886
+ // "cs": "86.90",
887
+ // "ds": 0,
888
+ // "id": "9927401610",
889
+ // "buy": "9927401601",
890
+ // "pos": null,
891
+ // "pair": null,
892
+ // "sell": "9927386681",
893
+ // "time": "2019-08-21T15:25:37.777Z",
894
+ // "type": "sell",
895
+ // "user": "up106404164",
896
+ // "order": "9927386681",
897
+ // "price": 8365,
898
+ // "amount": "16.70000000",
899
+ // "office": "UK",
900
+ // "symbol": "GBP",
901
+ // "balance": "86.90000000",
902
+ // "symbol2": "BTC",
903
+ // "fee_amount": "0.03"
904
+ // }
905
+ const tradeTimestamp = this.parse8601 (this.safeString (item, 'time'));
906
+ const tradeAmount = this.safeNumber (item, 'amount');
907
+ const feeCost = this.safeNumber (item, 'fee_amount');
908
+ let absTradeAmount = (tradeAmount < 0) ? -tradeAmount : tradeAmount;
909
+ let tradeCost = undefined;
910
+ if (tradeSide === 'sell') {
911
+ tradeCost = absTradeAmount;
912
+ absTradeAmount = this.sum (feeCost, tradeCost) / tradePrice;
913
+ } else {
914
+ tradeCost = absTradeAmount * tradePrice;
915
+ }
916
+ trades.push ({
917
+ 'id': this.safeString (item, 'id'),
918
+ 'timestamp': tradeTimestamp,
919
+ 'datetime': this.iso8601 (tradeTimestamp),
920
+ 'order': orderId,
921
+ 'symbol': symbol,
922
+ 'price': tradePrice,
923
+ 'amount': absTradeAmount,
924
+ 'cost': tradeCost,
925
+ 'side': tradeSide,
926
+ 'fee': {
927
+ 'cost': feeCost,
928
+ 'currency': market['quote'],
929
+ },
930
+ 'info': item,
931
+ 'type': undefined,
932
+ 'takerOrMaker': undefined,
933
+ });
934
+ }
935
+ }
936
+ return {
937
+ 'id': orderId,
938
+ 'clientOrderId': undefined,
939
+ 'datetime': this.iso8601 (timestamp),
940
+ 'timestamp': timestamp,
941
+ 'lastTradeTimestamp': undefined,
942
+ 'status': status,
943
+ 'symbol': symbol,
944
+ 'type': (price === undefined) ? 'market' : 'limit',
945
+ 'timeInForce': undefined,
946
+ 'postOnly': undefined,
947
+ 'side': side,
948
+ 'price': price,
949
+ 'stopPrice': undefined,
950
+ 'cost': cost,
951
+ 'amount': amount,
952
+ 'filled': filled,
953
+ 'remaining': remaining,
954
+ 'trades': trades,
955
+ 'fee': fee,
956
+ 'info': order,
957
+ 'average': undefined,
958
+ };
959
+ }
960
+
961
+ async fetchOpenOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) {
962
+ await this.loadMarkets ();
963
+ const request = {};
964
+ let method = 'privatePostOpenOrders';
965
+ let market = undefined;
966
+ if (symbol !== undefined) {
967
+ market = this.market (symbol);
968
+ request['pair'] = market['id'];
969
+ method += 'Pair';
970
+ }
971
+ const orders = await this[method] (this.extend (request, params));
972
+ for (let i = 0; i < orders.length; i++) {
973
+ orders[i] = this.extend (orders[i], { 'status': 'open' });
974
+ }
975
+ return this.parseOrders (orders, market, since, limit);
976
+ }
977
+
978
+ async fetchClosedOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) {
979
+ await this.loadMarkets ();
980
+ const method = 'privatePostArchivedOrdersPair';
981
+ if (symbol === undefined) {
982
+ throw new ArgumentsRequired (this.id + ' fetchClosedOrders() requires a symbol argument');
983
+ }
984
+ const market = this.market (symbol);
985
+ const request = { 'pair': market['id'] };
986
+ const response = await this[method] (this.extend (request, params));
987
+ return this.parseOrders (response, market, since, limit);
988
+ }
989
+
990
+ async fetchOrder (id, symbol = undefined, params = {}) {
991
+ await this.loadMarkets ();
992
+ const request = {
993
+ 'id': id.toString (),
994
+ };
995
+ const response = await this.privatePostGetOrderTx (this.extend (request, params));
996
+ const data = this.safeValue (response, 'data', {});
997
+ //
998
+ // {
999
+ // "id": "5442731603",
1000
+ // "type": "sell",
1001
+ // "time": 1516132358071,
1002
+ // "lastTxTime": 1516132378452,
1003
+ // "lastTx": "5442734452",
1004
+ // "pos": null,
1005
+ // "user": "up106404164",
1006
+ // "status": "d",
1007
+ // "symbol1": "ETH",
1008
+ // "symbol2": "EUR",
1009
+ // "amount": "0.50000000",
1010
+ // "kind": "api",
1011
+ // "price": "923.3386",
1012
+ // "tfacf": "1",
1013
+ // "fa:EUR": "0.55",
1014
+ // "ta:EUR": "369.77",
1015
+ // "remains": "0.00000000",
1016
+ // "tfa:EUR": "0.22",
1017
+ // "tta:EUR": "91.95",
1018
+ // "a:ETH:cds": "0.50000000",
1019
+ // "a:EUR:cds": "461.72",
1020
+ // "f:EUR:cds": "0.77",
1021
+ // "tradingFeeMaker": "0.15",
1022
+ // "tradingFeeTaker": "0.23",
1023
+ // "tradingFeeStrategy": "userVolumeAmount",
1024
+ // "tradingFeeUserVolumeAmount": "2896912572",
1025
+ // "orderId": "5442731603",
1026
+ // "next": false,
1027
+ // "vtx": [
1028
+ // {
1029
+ // "id": "5442734452",
1030
+ // "type": "sell",
1031
+ // "time": "2018-01-16T19:52:58.452Z",
1032
+ // "user": "up106404164",
1033
+ // "c": "user:up106404164:a:EUR",
1034
+ // "d": "order:5442731603:a:EUR",
1035
+ // "a": "104.53000000",
1036
+ // "amount": "104.53000000",
1037
+ // "balance": "932.71000000",
1038
+ // "symbol": "EUR",
1039
+ // "order": "5442731603",
1040
+ // "buy": "5442734443",
1041
+ // "sell": "5442731603",
1042
+ // "pair": null,
1043
+ // "pos": null,
1044
+ // "office": null,
1045
+ // "cs": "932.71",
1046
+ // "ds": 0,
1047
+ // "price": 923.3386,
1048
+ // "symbol2": "ETH",
1049
+ // "fee_amount": "0.16"
1050
+ // },
1051
+ // {
1052
+ // "id": "5442731609",
1053
+ // "type": "sell",
1054
+ // "time": "2018-01-16T19:52:38.071Z",
1055
+ // "user": "up106404164",
1056
+ // "c": "user:up106404164:a:EUR",
1057
+ // "d": "order:5442731603:a:EUR",
1058
+ // "a": "91.73000000",
1059
+ // "amount": "91.73000000",
1060
+ // "balance": "563.49000000",
1061
+ // "symbol": "EUR",
1062
+ // "order": "5442731603",
1063
+ // "buy": "5442618127",
1064
+ // "sell": "5442731603",
1065
+ // "pair": null,
1066
+ // "pos": null,
1067
+ // "office": null,
1068
+ // "cs": "563.49",
1069
+ // "ds": 0,
1070
+ // "price": 924.0092,
1071
+ // "symbol2": "ETH",
1072
+ // "fee_amount": "0.22"
1073
+ // },
1074
+ // {
1075
+ // "id": "5442731604",
1076
+ // "type": "sell",
1077
+ // "time": "2018-01-16T19:52:38.071Z",
1078
+ // "user": "up106404164",
1079
+ // "c": "order:5442731603:a:ETH",
1080
+ // "d": "user:up106404164:a:ETH",
1081
+ // "a": "0.50000000",
1082
+ // "amount": "-0.50000000",
1083
+ // "balance": "15.80995000",
1084
+ // "symbol": "ETH",
1085
+ // "order": "5442731603",
1086
+ // "buy": null,
1087
+ // "sell": null,
1088
+ // "pair": null,
1089
+ // "pos": null,
1090
+ // "office": null,
1091
+ // "cs": "0.50000000",
1092
+ // "ds": "15.80995000"
1093
+ // }
1094
+ // ]
1095
+ // }
1096
+ //
1097
+ return this.parseOrder (data);
1098
+ }
1099
+
1100
+ async fetchOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) {
1101
+ await this.loadMarkets ();
1102
+ const market = this.market (symbol);
1103
+ const request = {
1104
+ 'limit': limit,
1105
+ 'pair': market['id'],
1106
+ 'dateFrom': since,
1107
+ };
1108
+ const response = await this.privatePostArchivedOrdersPair (this.extend (request, params));
1109
+ const results = [];
1110
+ for (let i = 0; i < response.length; i++) {
1111
+ // cancelled (unfilled):
1112
+ // { id: '4005785516',
1113
+ // type: 'sell',
1114
+ // time: '2017-07-18T19:08:34.223Z',
1115
+ // lastTxTime: '2017-07-18T19:08:34.396Z',
1116
+ // lastTx: '4005785522',
1117
+ // pos: null,
1118
+ // status: 'c',
1119
+ // symbol1: 'ETH',
1120
+ // symbol2: 'GBP',
1121
+ // amount: '0.20000000',
1122
+ // price: '200.5625',
1123
+ // remains: '0.20000000',
1124
+ // 'a:ETH:cds': '0.20000000',
1125
+ // tradingFeeMaker: '0',
1126
+ // tradingFeeTaker: '0.16',
1127
+ // tradingFeeUserVolumeAmount: '10155061217',
1128
+ // orderId: '4005785516' }
1129
+ // --
1130
+ // cancelled (partially filled buy):
1131
+ // { id: '4084911657',
1132
+ // type: 'buy',
1133
+ // time: '2017-08-05T03:18:39.596Z',
1134
+ // lastTxTime: '2019-03-19T17:37:46.404Z',
1135
+ // lastTx: '8459265833',
1136
+ // pos: null,
1137
+ // status: 'cd',
1138
+ // symbol1: 'BTC',
1139
+ // symbol2: 'GBP',
1140
+ // amount: '0.05000000',
1141
+ // price: '2241.4692',
1142
+ // tfacf: '1',
1143
+ // remains: '0.03910535',
1144
+ // 'tfa:GBP': '0.04',
1145
+ // 'tta:GBP': '24.39',
1146
+ // 'a:BTC:cds': '0.01089465',
1147
+ // 'a:GBP:cds': '112.26',
1148
+ // 'f:GBP:cds': '0.04',
1149
+ // tradingFeeMaker: '0',
1150
+ // tradingFeeTaker: '0.16',
1151
+ // tradingFeeUserVolumeAmount: '13336396963',
1152
+ // orderId: '4084911657' }
1153
+ // --
1154
+ // cancelled (partially filled sell):
1155
+ // { id: '4426728375',
1156
+ // type: 'sell',
1157
+ // time: '2017-09-22T00:24:20.126Z',
1158
+ // lastTxTime: '2017-09-22T00:24:30.476Z',
1159
+ // lastTx: '4426729543',
1160
+ // pos: null,
1161
+ // status: 'cd',
1162
+ // symbol1: 'BCH',
1163
+ // symbol2: 'BTC',
1164
+ // amount: '0.10000000',
1165
+ // price: '0.11757182',
1166
+ // tfacf: '1',
1167
+ // remains: '0.09935956',
1168
+ // 'tfa:BTC': '0.00000014',
1169
+ // 'tta:BTC': '0.00007537',
1170
+ // 'a:BCH:cds': '0.10000000',
1171
+ // 'a:BTC:cds': '0.00007537',
1172
+ // 'f:BTC:cds': '0.00000014',
1173
+ // tradingFeeMaker: '0',
1174
+ // tradingFeeTaker: '0.18',
1175
+ // tradingFeeUserVolumeAmount: '3466715450',
1176
+ // orderId: '4426728375' }
1177
+ // --
1178
+ // filled:
1179
+ // { id: '5342275378',
1180
+ // type: 'sell',
1181
+ // time: '2018-01-04T00:28:12.992Z',
1182
+ // lastTxTime: '2018-01-04T00:28:12.992Z',
1183
+ // lastTx: '5342275393',
1184
+ // pos: null,
1185
+ // status: 'd',
1186
+ // symbol1: 'BCH',
1187
+ // symbol2: 'BTC',
1188
+ // amount: '0.10000000',
1189
+ // kind: 'api',
1190
+ // price: '0.17',
1191
+ // remains: '0.00000000',
1192
+ // 'tfa:BTC': '0.00003902',
1193
+ // 'tta:BTC': '0.01699999',
1194
+ // 'a:BCH:cds': '0.10000000',
1195
+ // 'a:BTC:cds': '0.01699999',
1196
+ // 'f:BTC:cds': '0.00003902',
1197
+ // tradingFeeMaker: '0.15',
1198
+ // tradingFeeTaker: '0.23',
1199
+ // tradingFeeUserVolumeAmount: '1525951128',
1200
+ // orderId: '5342275378' }
1201
+ // --
1202
+ // market order (buy):
1203
+ // { "id": "6281946200",
1204
+ // "pos": null,
1205
+ // "time": "2018-05-23T11:55:43.467Z",
1206
+ // "type": "buy",
1207
+ // "amount": "0.00000000",
1208
+ // "lastTx": "6281946210",
1209
+ // "status": "d",
1210
+ // "amount2": "20.00",
1211
+ // "orderId": "6281946200",
1212
+ // "remains": "0.00000000",
1213
+ // "symbol1": "ETH",
1214
+ // "symbol2": "EUR",
1215
+ // "tfa:EUR": "0.05",
1216
+ // "tta:EUR": "19.94",
1217
+ // "a:ETH:cds": "0.03764100",
1218
+ // "a:EUR:cds": "20.00",
1219
+ // "f:EUR:cds": "0.05",
1220
+ // "lastTxTime": "2018-05-23T11:55:43.467Z",
1221
+ // "tradingFeeTaker": "0.25",
1222
+ // "tradingFeeUserVolumeAmount": "55998097" }
1223
+ // --
1224
+ // market order (sell):
1225
+ // { "id": "6282200948",
1226
+ // "pos": null,
1227
+ // "time": "2018-05-23T12:42:58.315Z",
1228
+ // "type": "sell",
1229
+ // "amount": "-0.05000000",
1230
+ // "lastTx": "6282200958",
1231
+ // "status": "d",
1232
+ // "orderId": "6282200948",
1233
+ // "remains": "0.00000000",
1234
+ // "symbol1": "ETH",
1235
+ // "symbol2": "EUR",
1236
+ // "tfa:EUR": "0.07",
1237
+ // "tta:EUR": "26.49",
1238
+ // "a:ETH:cds": "0.05000000",
1239
+ // "a:EUR:cds": "26.49",
1240
+ // "f:EUR:cds": "0.07",
1241
+ // "lastTxTime": "2018-05-23T12:42:58.315Z",
1242
+ // "tradingFeeTaker": "0.25",
1243
+ // "tradingFeeUserVolumeAmount": "56294576" }
1244
+ const order = response[i];
1245
+ const status = this.parseOrderStatus (this.safeString (order, 'status'));
1246
+ const baseId = this.safeString (order, 'symbol1');
1247
+ const quoteId = this.safeString (order, 'symbol2');
1248
+ const base = this.safeCurrencyCode (baseId);
1249
+ const quote = this.safeCurrencyCode (quoteId);
1250
+ const symbol = base + '/' + quote;
1251
+ const side = this.safeString (order, 'type');
1252
+ const baseAmount = this.safeNumber (order, 'a:' + baseId + ':cds');
1253
+ const quoteAmount = this.safeNumber (order, 'a:' + quoteId + ':cds');
1254
+ const fee = this.safeNumber (order, 'f:' + quoteId + ':cds');
1255
+ const amount = this.safeNumber (order, 'amount');
1256
+ const price = this.safeNumber (order, 'price');
1257
+ const remaining = this.safeNumber (order, 'remains');
1258
+ const filled = amount - remaining;
1259
+ let orderAmount = undefined;
1260
+ let cost = undefined;
1261
+ let average = undefined;
1262
+ let type = undefined;
1263
+ if (!price) {
1264
+ type = 'market';
1265
+ orderAmount = baseAmount;
1266
+ cost = quoteAmount;
1267
+ average = orderAmount / cost;
1268
+ } else {
1269
+ const ta = this.safeNumber (order, 'ta:' + quoteId, 0);
1270
+ const tta = this.safeNumber (order, 'tta:' + quoteId, 0);
1271
+ const fa = this.safeNumber (order, 'fa:' + quoteId, 0);
1272
+ const tfa = this.safeNumber (order, 'tfa:' + quoteId, 0);
1273
+ if (side === 'sell') {
1274
+ cost = this.sum (this.sum (ta, tta), this.sum (fa, tfa));
1275
+ } else {
1276
+ cost = this.sum (ta, tta) - this.sum (fa, tfa);
1277
+ }
1278
+ type = 'limit';
1279
+ orderAmount = amount;
1280
+ average = cost / filled;
1281
+ }
1282
+ const time = this.safeString (order, 'time');
1283
+ const lastTxTime = this.safeString (order, 'lastTxTime');
1284
+ const timestamp = this.parse8601 (time);
1285
+ results.push ({
1286
+ 'id': this.safeString (order, 'id'),
1287
+ 'timestamp': timestamp,
1288
+ 'datetime': this.iso8601 (timestamp),
1289
+ 'lastUpdated': this.parse8601 (lastTxTime),
1290
+ 'status': status,
1291
+ 'symbol': symbol,
1292
+ 'side': side,
1293
+ 'price': price,
1294
+ 'amount': orderAmount,
1295
+ 'average': average,
1296
+ 'type': type,
1297
+ 'filled': filled,
1298
+ 'cost': cost,
1299
+ 'remaining': remaining,
1300
+ 'fee': {
1301
+ 'cost': fee,
1302
+ 'currency': quote,
1303
+ },
1304
+ 'info': order,
1305
+ });
1306
+ }
1307
+ return results;
1308
+ }
1309
+
1310
+ parseOrderStatus (status) {
1311
+ return this.safeString (this.options['order']['status'], status, status);
1312
+ }
1313
+
1314
+ async editOrder (id, symbol, type, side, amount = undefined, price = undefined, params = {}) {
1315
+ if (amount === undefined) {
1316
+ throw new ArgumentsRequired (this.id + ' editOrder() requires a amount argument');
1317
+ }
1318
+ if (price === undefined) {
1319
+ throw new ArgumentsRequired (this.id + ' editOrder() requires a price argument');
1320
+ }
1321
+ await this.loadMarkets ();
1322
+ const market = this.market (symbol);
1323
+ // see: https://cex.io/rest-api#/definitions/CancelReplaceOrderRequest
1324
+ const request = {
1325
+ 'pair': market['id'],
1326
+ 'type': side,
1327
+ 'amount': amount,
1328
+ 'price': price,
1329
+ 'order_id': id,
1330
+ };
1331
+ const response = await this.privatePostCancelReplaceOrderPair (this.extend (request, params));
1332
+ return this.parseOrder (response, market);
1333
+ }
1334
+
1335
+ async fetchDepositAddress (code, params = {}) {
1336
+ if (code === 'XRP' || code === 'XLM') {
1337
+ // https://github.com/ccxt/ccxt/pull/2327#issuecomment-375204856
1338
+ throw new NotSupported (this.id + ' fetchDepositAddress() does not support XRP and XLM addresses yet (awaiting docs from CEX.io)');
1339
+ }
1340
+ await this.loadMarkets ();
1341
+ const currency = this.currency (code);
1342
+ const request = {
1343
+ 'currency': currency['id'],
1344
+ };
1345
+ const response = await this.privatePostGetAddress (this.extend (request, params));
1346
+ const address = this.safeString (response, 'data');
1347
+ this.checkAddress (address);
1348
+ return {
1349
+ 'currency': code,
1350
+ 'address': address,
1351
+ 'tag': undefined,
1352
+ 'network': undefined,
1353
+ 'info': response,
1354
+ };
1355
+ }
1356
+
1357
+ nonce () {
1358
+ return this.milliseconds ();
1359
+ }
1360
+
1361
+ sign (path, api = 'public', method = 'GET', params = {}, headers = undefined, body = undefined) {
1362
+ let url = this.urls['api'] + '/' + this.implodeParams (path, params);
1363
+ const query = this.omit (params, this.extractParams (path));
1364
+ if (api === 'public') {
1365
+ if (Object.keys (query).length) {
1366
+ url += '?' + this.urlencode (query);
1367
+ }
1368
+ } else {
1369
+ this.checkRequiredCredentials ();
1370
+ const nonce = this.nonce ().toString ();
1371
+ const auth = nonce + this.uid + this.apiKey;
1372
+ const signature = this.hmac (this.encode (auth), this.encode (this.secret));
1373
+ body = this.json (this.extend ({
1374
+ 'key': this.apiKey,
1375
+ 'signature': signature.toUpperCase (),
1376
+ 'nonce': nonce,
1377
+ }, query));
1378
+ headers = {
1379
+ 'Content-Type': 'application/json',
1380
+ };
1381
+ }
1382
+ return { 'url': url, 'method': method, 'body': body, 'headers': headers };
1383
+ }
1384
+
1385
+ handleErrors (code, reason, url, method, headers, body, response, requestHeaders, requestBody) {
1386
+ if (Array.isArray (response)) {
1387
+ return response; // public endpoints may return []-arrays
1388
+ }
1389
+ if (body === 'true') {
1390
+ return;
1391
+ }
1392
+ if (response === undefined) {
1393
+ throw new NullResponse (this.id + ' returned ' + this.json (response));
1394
+ }
1395
+ if ('e' in response) {
1396
+ if ('ok' in response) {
1397
+ if (response['ok'] === 'ok') {
1398
+ return;
1399
+ }
1400
+ }
1401
+ }
1402
+ if ('error' in response) {
1403
+ const message = this.safeString (response, 'error');
1404
+ const feedback = this.id + ' ' + body;
1405
+ this.throwExactlyMatchedException (this.exceptions['exact'], message, feedback);
1406
+ this.throwBroadlyMatchedException (this.exceptions['broad'], message, feedback);
1407
+ throw new ExchangeError (feedback);
1408
+ }
1409
+ }
1410
+ };