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/xena.js ADDED
@@ -0,0 +1,1948 @@
1
+ 'use strict';
2
+
3
+ const Exchange = require ('./base/Exchange');
4
+ const { ExchangeError, ArgumentsRequired, BadRequest, InsufficientFunds, InvalidAddress, BadSymbol, InvalidOrder } = require ('./base/errors');
5
+ const Precise = require ('./base/Precise');
6
+
7
+ module.exports = class xena extends Exchange {
8
+ describe () {
9
+ return this.deepExtend (super.describe (), {
10
+ 'id': 'xena',
11
+ 'name': 'Xena Exchange',
12
+ 'countries': [ 'VC', 'UK' ],
13
+ // per second rate limits are far lower than the equivalent hourly
14
+ // requests per second rounded down (3dp)
15
+ // relative weight costs rounded up (3dp)
16
+ // 1 hour = 3600 seconds
17
+ // Order Cancellations: 100k per hour => 100 000 / 3600 = 27.777 requests per second => rateLimit = 1000ms / 27.777 = 36.001008 ms between requests => 36.1 (safety)
18
+ // New Orders: 30k per hour => 30 000 / 3600 = 8.333 requests per second => cost = 27.777 / 8.333 = 3.333373335 => 3.334
19
+ // Heartbeat: 30k per hour => 30 000 / 3600 = 8.333 requests per second => cost = 27.777 / 8.333 = 3.333373335 => 3.334
20
+ // Candles: 5000 per hour => 5000 / 3600 = 1.388 requests per second => cost = 27.777 / 1.388 = 20.01224784 => 20.013
21
+ // Dom (market data): 5000 per hour => 5000 / 3600 = 1.388 requests per second => cost = 27.777 / 1.388 = 20.01224784 => 20.013
22
+ // All snapshot requests (balances, active orders and trade history, positions): 500 per hour => 0.138 requests per second => cost = 27.777 / 0.138 = 201.2826087 => 201.283
23
+ 'rateLimit': 36.1,
24
+ 'has': {
25
+ 'CORS': undefined,
26
+ 'spot': false,
27
+ 'margin': false,
28
+ 'swap': undefined, // has but not fully implemented
29
+ 'future': undefined, // has but not fully implemented
30
+ 'option': false,
31
+ 'cancelAllOrders': true,
32
+ 'cancelOrder': true,
33
+ 'createDepositAddress': true,
34
+ 'createOrder': true,
35
+ 'editOrder': true,
36
+ 'fetchAccounts': 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': true,
47
+ 'fetchLedger': true,
48
+ 'fetchLeverageTiers': true,
49
+ 'fetchMarketLeverageTiers': 'emulated',
50
+ 'fetchMarkets': true,
51
+ 'fetchMyTrades': true,
52
+ 'fetchOHLCV': true,
53
+ 'fetchOpenOrders': true,
54
+ 'fetchOrderBook': true,
55
+ 'fetchTicker': true,
56
+ 'fetchTickers': true,
57
+ 'fetchTime': true,
58
+ 'fetchTrades': true,
59
+ 'fetchTradingFee': false,
60
+ 'fetchTradingFees': false,
61
+ 'fetchWithdrawals': true,
62
+ 'withdraw': true,
63
+ },
64
+ 'urls': {
65
+ 'logo': 'https://user-images.githubusercontent.com/51840849/87489843-bb469280-c64c-11ea-91aa-69c6326506af.jpg',
66
+ 'test': {
67
+ 'public': 'https://trading.demo.xena.io/api',
68
+ 'private': 'https://api.demo.xena.io',
69
+ },
70
+ 'api': {
71
+ 'public': 'https://trading.xena.exchange/api',
72
+ 'private': 'https://api.xena.exchange',
73
+ },
74
+ 'www': 'https://xena.exchange',
75
+ 'doc': 'https://support.xena.exchange/support/solutions/44000808700',
76
+ 'fees': 'https://trading.xena.exchange/en/contracts/terms-and-condition',
77
+ },
78
+ 'timeframes': {
79
+ '1m': '1m',
80
+ '5m': '5m',
81
+ '15m': '15m',
82
+ '30m': '30m',
83
+ '1h': '1h',
84
+ '4h': '4h',
85
+ '12h': '12h',
86
+ '1d': '1d',
87
+ '1w': '1w',
88
+ },
89
+ 'api': {
90
+ 'public': {
91
+ 'get': {
92
+ 'common/currencies': 20.013,
93
+ 'common/instruments': 20.013,
94
+ 'common/features': 20.013,
95
+ 'common/commissions': 20.013,
96
+ 'common/news': 20.013,
97
+ 'market-data/candles/{marketId}/{timeframe}': 20.013,
98
+ 'market-data/market-watch': 20.013,
99
+ 'market-data/dom/{symbol}': 20.013,
100
+ 'market-data/candles/{symbol}/{timeframe}': 20.013,
101
+ 'market-data/trades/{symbol}': 20.013,
102
+ 'market-data/server-time': 20.013,
103
+ 'market-data/v2/candles/{symbol}/{timeframe}': 20.013,
104
+ 'market-data/v2/trades/{symbol}': 20.013,
105
+ 'market-data/v2/dom/{symbol}/': 20.013,
106
+ 'market-data/v2/server-time': 20.013,
107
+ },
108
+ },
109
+ 'private': {
110
+ 'get': {
111
+ 'trading/accounts/{accountId}/order': 50,
112
+ 'trading/accounts/{accountId}/active-orders': 50,
113
+ 'trading/accounts/{accountId}/last-order-statuses': 50,
114
+ 'trading/accounts/{accountId}/positions': 50,
115
+ 'trading/accounts/{accountId}/positions-history': 50,
116
+ 'trading/accounts/{accountId}/margin-requirements': 50,
117
+ 'trading/accounts': 50,
118
+ 'trading/accounts/{accountId}/balance': 50, // TESTING (50 works)
119
+ 'trading/accounts/{accountId}/trade-history': 50,
120
+ // 'trading/accounts/{accountId}/trade-history?symbol=BTC/USDT&client_order_id=EMBB8Veke&trade_id=2205043254': 50,
121
+ 'transfers/accounts': 50,
122
+ 'transfers/accounts/{accountId}': 50,
123
+ 'transfers/accounts/{accountId}/deposit-address/{currency}': 50,
124
+ 'transfers/accounts/{accountId}/deposits': 100, // TESTING
125
+ 'transfers/accounts/{accountId}/trusted-addresses': 50,
126
+ 'transfers/accounts/{accountId}/withdrawals': 50,
127
+ 'transfers/accounts/{accountId}/balance-history': 50,
128
+ // 'transfers/accounts/{accountId}/balance-history?currency={currency}&from={time}&to={time}&kind={kind}&kind={kind}': 50,
129
+ // 'transfers/accounts/{accountId}/balance-history?page={page}&limit={limit}': 50,
130
+ // 'transfers/accounts/{accountId}/balance-history?txid=3e50db982c4eed2d6355e276c5bae01a52a27c9cef61574b0e8c67ee05fc26ccf': 50,
131
+ },
132
+ 'post': {
133
+ 'trading/order/new': 3.334,
134
+ 'trading/order/heartbeat': 3.334,
135
+ 'trading/order/cancel': 1,
136
+ 'trading/order/mass-cancel': 1,
137
+ 'trading/order/replace': 3.334,
138
+ 'trading/position/maintenance': 3.334,
139
+ 'transfers/accounts/{accountId}/withdrawals': 3.334,
140
+ 'transfers/accounts/{accountId}/deposit-address/{currency}': 3.334,
141
+ },
142
+ },
143
+ },
144
+ 'fees': {
145
+ 'trading': {
146
+ 'maker': 0.0005,
147
+ 'taker': 0.001,
148
+ 'tierBased': true,
149
+ 'percentage': true,
150
+ },
151
+ 'funding': {
152
+ 'tierBased': false,
153
+ 'percentage': false,
154
+ 'withdraw': {},
155
+ 'deposit': {},
156
+ },
157
+ },
158
+ 'exceptions': {
159
+ 'exact': {
160
+ 'Validation failed': BadRequest,
161
+ 'Unknown derivative symbol': BadSymbol, // {"error":"Unknown derivative symbol"}
162
+ 'Unknown account': BadRequest, // {"error":"Unknown account"}
163
+ 'Wrong TransactTime': BadRequest, // {"error":"Wrong TransactTime"}
164
+ 'ClOrdId is empty': BadRequest, // {"error":"ClOrdId is empty"}
165
+ },
166
+ 'broad': {
167
+ 'Invalid aggregation ratio or depth': BadRequest,
168
+ 'address': InvalidAddress,
169
+ 'Money not enough': InsufficientFunds,
170
+ 'parse error': BadRequest,
171
+ 'Not enough': InsufficientFunds, // {"error":"Not enough free margin"}
172
+ },
173
+ },
174
+ 'options': {
175
+ 'defaultType': 'margin', // 'margin',
176
+ 'accountId': undefined, // '1012838157',
177
+ },
178
+ });
179
+ }
180
+
181
+ async fetchTime (params = {}) {
182
+ const response = await this.publicGetMarketDataV2ServerTime (params);
183
+ //
184
+ // {
185
+ // "msgType":"0",
186
+ // "transactTime":1594774454112817637
187
+ // }
188
+ //
189
+ const transactTime = this.safeInteger (response, 'transactTime');
190
+ return parseInt (transactTime / 1000000);
191
+ }
192
+
193
+ async fetchMarkets (params = {}) {
194
+ const response = await this.publicGetCommonInstruments (params);
195
+ //
196
+ // [
197
+ // {
198
+ // "type": "Index",
199
+ // "symbol": ".ADAUSD",
200
+ // "tickSize": 4,
201
+ // "enabled": true
202
+ // },
203
+ // {
204
+ // "id":"ETHUSD_3M_250920",
205
+ // "type":"Margin",
206
+ // "marginType":"XenaFuture",
207
+ // "symbol":"ETHUSD_3M_250920",
208
+ // "baseCurrency":"ETH",
209
+ // "quoteCurrency":"USD",
210
+ // "settlCurrency":"BTC",
211
+ // "tickSize":2,
212
+ // "minOrderQuantity":"1",
213
+ // "orderQtyStep":"1",
214
+ // "limitOrderMaxDistance":"10",
215
+ // "priceInputMask":"0000.00",
216
+ // "enabled":true,
217
+ // "liquidationMaxDistance":"0.01",
218
+ // "contractValue":"1",
219
+ // "contractCurrency":"BTC",
220
+ // "lotSize":"1",
221
+ // "tickValue":"0.00000001", // linear contracts only
222
+ // "maxOrderQty":"175000",
223
+ // "maxPosVolume":"1750000",
224
+ // "mark":".ETHUSD_3M_250920",
225
+ // "underlying":".ETHUSD_TWAP",
226
+ // "openInterest":".ETHUSD_3M_250920_OpenInterest",
227
+ // "floatingPL":"BidAsk", // perpetual contracts only
228
+ // "addUvmToFreeMargin":"ProfitAndLoss",
229
+ // "margin":{
230
+ // "netting":"PositionsAndOrders",
231
+ // "rates":[
232
+ // {"maxVolume":"175000","initialRate":"0.05","maintenanceRate":"0.0125"},
233
+ // {"maxVolume":"350000","initialRate":"0.1","maintenanceRate":"0.025"},
234
+ // {"maxVolume":"500000","initialRate":"0.2","maintenanceRate":"0.05"},
235
+ // {"maxVolume":"750000","initialRate":"0.3","maintenanceRate":"0.075"},
236
+ // {"maxVolume":"1050000","initialRate":"0.4","maintenanceRate":"0.1"},
237
+ // {"maxVolume":"1400000","initialRate":"0.5","maintenanceRate":"0.125"},
238
+ // {"maxVolume":"1750000","initialRate":"1","maintenanceRate":"0.25"}
239
+ // ],
240
+ // "rateMultipliers":{
241
+ // "LimitBuy":"1",
242
+ // "LimitSell":"1",
243
+ // "Long":"1",
244
+ // "MarketBuy":"1",
245
+ // "MarketSell":"1",
246
+ // "Short":"1",
247
+ // "StopBuy":"0",
248
+ // "StopSell":"0"
249
+ // }
250
+ // },
251
+ // "clearing":{"enabled":true,"index":".ETHUSD_3M_250920"},
252
+ // "premium":{"enabled":true,"index":".XBTUSD_Premium_IR_Corrected"}, // perpetual contracts only
253
+ // "riskAdjustment":{"enabled":true,"index":".RiskAdjustment_IR"},
254
+ // "expiration":{"enabled":true,"index":".ETHUSD_TWAP"}, // futures only
255
+ // "pricePrecision":3,
256
+ // "priceRange":{
257
+ // "enabled":true,
258
+ // "distance":"0.03",
259
+ // "movingBoundary":"0",
260
+ // "lowIndex":".ETHUSD_3M_250920_LOWRANGE",
261
+ // "highIndex":".ETHUSD_3M_250920_HIGHRANGE"
262
+ // },
263
+ // "priceLimits":{
264
+ // "enabled":true,
265
+ // "distance":"0.5",
266
+ // "movingBoundary":"0",
267
+ // "lowIndex":".ETHUSD_3M_250920_LOWLIMIT",
268
+ // "highIndex":".ETHUSD_3M_250920_HIGHLIMIT"
269
+ // },
270
+ // "inverse":true, // inverse contracts only
271
+ // "serie":"ETHUSD", // futures only
272
+ // "tradingStartDate":"2020-03-27 07:00:00",
273
+ // "expiryDate":"2020-09-25 08:00:00" // futures only
274
+ // },
275
+ // {
276
+ // "type":"Index",
277
+ // "symbol":".ETHUSD_Premium_IR_Corrected",
278
+ // "tickSize":6,
279
+ // "enabled":true,
280
+ // "basis":365
281
+ // },
282
+ // ]
283
+ //
284
+ const result = [];
285
+ for (let i = 0; i < response.length; i++) {
286
+ const market = response[i];
287
+ let type = this.safeStringLower (market, 'type');
288
+ const id = this.safeString (market, 'symbol');
289
+ const numericId = this.safeString (market, 'id');
290
+ const marginType = this.safeString (market, 'marginType');
291
+ const baseId = this.safeString (market, 'baseCurrency');
292
+ const quoteId = this.safeString (market, 'quoteCurrency');
293
+ const settleId = this.safeString (market, 'settlCurrency');
294
+ const base = this.safeCurrencyCode (baseId);
295
+ const quote = this.safeCurrencyCode (quoteId);
296
+ const settle = this.safeCurrencyCode (settleId);
297
+ const expiryDate = this.safeString (market, 'expiryDate');
298
+ const expiryTimestamp = this.parse8601 (expiryDate);
299
+ let symbol = id;
300
+ let future = false;
301
+ let swap = false;
302
+ if (type === 'margin') {
303
+ symbol = base + '/' + quote + ':' + settle;
304
+ if (marginType === 'XenaFuture') {
305
+ symbol = symbol + '-' + this.yymmdd (expiryTimestamp);
306
+ type = 'future';
307
+ future = true;
308
+ } else if (marginType === 'XenaListedPerpetual') {
309
+ type = 'swap';
310
+ swap = true;
311
+ }
312
+ }
313
+ const inverse = this.safeValue (market, 'inverse', false);
314
+ const contract = swap || future;
315
+ result.push ({
316
+ 'id': id,
317
+ 'symbol': symbol,
318
+ 'base': base,
319
+ 'quote': quote,
320
+ 'settle': settle,
321
+ 'baseId': baseId,
322
+ 'quoteId': quoteId,
323
+ 'settleId': settleId,
324
+ 'numericId': numericId,
325
+ 'type': type,
326
+ 'spot': false,
327
+ 'margin': false,
328
+ 'swap': swap,
329
+ 'future': future,
330
+ 'option': false,
331
+ 'active': this.safeValue (market, 'enabled', false),
332
+ 'contract': contract,
333
+ 'linear': contract ? !inverse : undefined,
334
+ 'inverse': contract ? inverse : undefined,
335
+ 'contractSize': this.safeNumber (market, 'contractValue'),
336
+ 'expiry': expiryTimestamp,
337
+ 'expiryDatetime': this.iso8601 (expiryTimestamp),
338
+ 'strike': undefined,
339
+ 'optionType': undefined,
340
+ 'precision': {
341
+ 'amount': parseInt ('0'),
342
+ 'price': this.safeInteger2 (market, 'tickSize', 'pricePrecision'),
343
+ },
344
+ 'limits': {
345
+ 'leverage': {
346
+ 'min': undefined,
347
+ 'max': undefined,
348
+ },
349
+ 'amount': {
350
+ 'min': undefined,
351
+ 'max': undefined,
352
+ },
353
+ 'price': {
354
+ 'min': undefined,
355
+ 'max': undefined,
356
+ },
357
+ 'cost': {
358
+ 'min': this.safeNumber (market, 'minOrderQuantity'),
359
+ 'max': this.safeNumber (market, 'maxOrderQty'),
360
+ },
361
+ },
362
+ 'info': market,
363
+ });
364
+ }
365
+ return result;
366
+ }
367
+
368
+ async fetchCurrencies (params = {}) {
369
+ const response = await this.publicGetCommonCurrencies (params);
370
+ //
371
+ // {
372
+ // "BAB": {
373
+ // "name":"BAB",
374
+ // "title":"Bitcoin ABC",
375
+ // "blockchain":{
376
+ // "name":"BAB",
377
+ // "title":"Bitcoin ABC",
378
+ // "deposit":{"confirmations":6},
379
+ // "withdraw":{"confirmations":1},
380
+ // "addressReuseAllowed":false,
381
+ // "view":{
382
+ // "uriTemplate":"bitcoinabc:%s?message=Xena Exchange",
383
+ // "recommendedFee":"0.00001",
384
+ // "transactionUrl":"https://blockchair.com/bitcoin-cash/transaction/${txId}",
385
+ // "walletUrl":"https://blockchair.com/bitcoin-cash/address/${walletId}"
386
+ // }
387
+ // },
388
+ // "precision":5,
389
+ // "withdraw":{"minAmount":"0.01","commission":"0.001"},
390
+ // "view":{
391
+ // "color":"#DC7C08",
392
+ // "site":"https://www.bitcoinabc.org"
393
+ // },
394
+ // "enabled":true
395
+ // },
396
+ // }
397
+ const ids = Object.keys (response);
398
+ const result = {};
399
+ for (let i = 0; i < ids.length; i++) {
400
+ const id = ids[i];
401
+ const currency = response[id];
402
+ const code = this.safeCurrencyCode (id);
403
+ const name = this.safeString (currency, 'title');
404
+ const precision = this.safeInteger (currency, 'precision');
405
+ const enabled = this.safeValue (currency, 'enabled');
406
+ const active = (enabled === true);
407
+ const withdraw = this.safeValue (currency, 'withdraw', {});
408
+ result[code] = {
409
+ 'id': id,
410
+ 'code': code,
411
+ 'info': currency,
412
+ 'name': name,
413
+ 'active': active,
414
+ 'deposit': undefined,
415
+ 'withdraw': undefined,
416
+ 'fee': this.safeNumber (withdraw, 'commission'),
417
+ 'precision': precision,
418
+ 'limits': {
419
+ 'amount': {
420
+ 'min': undefined,
421
+ 'max': undefined,
422
+ },
423
+ 'withdraw': {
424
+ 'min': this.safeNumber (withdraw, 'minAmount'),
425
+ 'max': undefined,
426
+ },
427
+ },
428
+ };
429
+ }
430
+ return result;
431
+ }
432
+
433
+ parseTicker (ticker, market = undefined) {
434
+ //
435
+ // fetchTicker, fetchTickers
436
+ //
437
+ // {
438
+ // "symbol":".XBTUSD_3M_250920_MID",
439
+ // "firstPx":"9337.49",
440
+ // "lastPx":"9355.81",
441
+ // "highPx":"9579.42",
442
+ // "lowPx":"9157.63",
443
+ // "buyVolume":"0",
444
+ // "sellVolume":"0",
445
+ // "bid":"0",
446
+ // "ask":"0"
447
+ // }
448
+ //
449
+ const timestamp = this.milliseconds ();
450
+ const marketId = this.safeString (ticker, 'symbol');
451
+ const symbol = this.safeSymbol (marketId, market);
452
+ const last = this.safeString (ticker, 'lastPx');
453
+ const open = this.safeString (ticker, 'firstPx');
454
+ const buyVolume = this.safeString (ticker, 'buyVolume');
455
+ const sellVolume = this.safeString (ticker, 'sellVolume');
456
+ const baseVolume = this.sum (buyVolume, sellVolume);
457
+ return this.safeTicker ({
458
+ 'symbol': symbol,
459
+ 'timestamp': timestamp,
460
+ 'datetime': this.iso8601 (timestamp),
461
+ 'high': this.safeString (ticker, 'highPx'),
462
+ 'low': this.safeString (ticker, 'lowPx'),
463
+ 'bid': this.safeString (ticker, 'bid'),
464
+ 'bidVolume': undefined,
465
+ 'ask': this.safeString (ticker, 'ask'),
466
+ 'askVolume': undefined,
467
+ 'vwap': undefined,
468
+ 'open': open,
469
+ 'close': last,
470
+ 'last': last,
471
+ 'previousClose': undefined,
472
+ 'change': undefined,
473
+ 'percentage': undefined,
474
+ 'average': undefined,
475
+ 'baseVolume': baseVolume,
476
+ 'quoteVolume': undefined,
477
+ 'info': ticker,
478
+ }, market, false);
479
+ }
480
+
481
+ async fetchTicker (symbol, params = {}) {
482
+ await this.loadMarkets ();
483
+ const tickers = await this.fetchTickers (undefined, params);
484
+ if (symbol in tickers) {
485
+ return tickers[symbol];
486
+ }
487
+ throw new BadSymbol (this.id + ' fetchTicker() could not find a ticker with symbol ' + symbol);
488
+ }
489
+
490
+ async fetchTickers (symbols = undefined, params = {}) {
491
+ await this.loadMarkets ();
492
+ const tickers = await this.publicGetMarketDataMarketWatch (params);
493
+ //
494
+ // [
495
+ // {
496
+ // "symbol":".XBTUSD_3M_250920_MID",
497
+ // "firstPx":"9337.49",
498
+ // "lastPx":"9355.81",
499
+ // "highPx":"9579.42",
500
+ // "lowPx":"9157.63",
501
+ // "buyVolume":"0",
502
+ // "sellVolume":"0",
503
+ // "bid":"0",
504
+ // "ask":"0"
505
+ // }
506
+ // ]
507
+ //
508
+ const result = {};
509
+ for (let i = 0; i < tickers.length; i++) {
510
+ const ticker = this.parseTicker (tickers[i]);
511
+ const symbol = ticker['symbol'];
512
+ result[symbol] = ticker;
513
+ }
514
+ return this.filterByArray (result, 'symbol', symbols);
515
+ }
516
+
517
+ async fetchOrderBook (symbol, limit = undefined, params = {}) {
518
+ await this.loadMarkets ();
519
+ const request = {
520
+ 'symbol': this.marketId (symbol),
521
+ };
522
+ if (limit !== undefined) {
523
+ request['depth'] = limit;
524
+ }
525
+ const response = await this.publicGetMarketDataV2DomSymbol (this.extend (request, params));
526
+ //
527
+ // {
528
+ // "msgType":"W",
529
+ // "mdStreamId":"DOM:XBTUSD:aggregated",
530
+ // "lastUpdateTime":1594772683037691997,
531
+ // "mdBookType":"2",
532
+ // "symbol":"XBTUSD",
533
+ // "lowRangePx":"9132.24",
534
+ // "highRangePx":"9410.36",
535
+ // "lowLimitPx":"9132.24",
536
+ // "highLimitPx":"9410.36",
537
+ // "clearingPx":"9253.4",
538
+ // "bestBid":"9269.8",
539
+ // "bestAsk":"9275.9",
540
+ // "mdEntry":[
541
+ // {"mdEntryType":"1","mdEntryPx":"9275.9","mdEntrySize":"3000","numberOfOrders":1},
542
+ // {"mdEntryType":"1","mdEntryPx":"9277.7","mdEntrySize":"50000","numberOfOrders":1},
543
+ // {"mdEntryType":"1","mdEntryPx":"9277.8","mdEntrySize":"2000","numberOfOrders":1},
544
+ // {"mdEntryType":"0","mdEntryPx":"9269.8","mdEntrySize":"2000","numberOfOrders":1},
545
+ // {"mdEntryType":"0","mdEntryPx":"9267.9","mdEntrySize":"3000","numberOfOrders":1},
546
+ // {"mdEntryType":"0","mdEntryPx":"9267.8","mdEntrySize":"50000","numberOfOrders":1},
547
+ // ]
548
+ // }
549
+ //
550
+ const mdEntry = this.safeValue (response, 'mdEntry', []);
551
+ const mdEntriesByType = this.groupBy (mdEntry, 'mdEntryType');
552
+ const lastUpdateTime = this.safeInteger (response, 'lastUpdateTime');
553
+ let timestamp = undefined;
554
+ if (lastUpdateTime !== undefined) {
555
+ timestamp = parseInt (lastUpdateTime / 1000000);
556
+ }
557
+ return this.parseOrderBook (mdEntriesByType, symbol, timestamp, '0', '1', 'mdEntryPx', 'mdEntrySize');
558
+ }
559
+
560
+ async fetchAccounts (params = {}) {
561
+ const response = await this.privateGetTradingAccounts (params);
562
+ //
563
+ // {
564
+ // "accounts": [
565
+ // { "id":8273231, "kind": "Spot" },
566
+ // { "id":10012833469, "kind": "Margin", "currency": "BTC" }
567
+ // ]
568
+ // }
569
+ //
570
+ const accounts = this.safeValue (response, 'accounts');
571
+ const result = [];
572
+ for (let i = 0; i < accounts.length; i++) {
573
+ const account = accounts[i];
574
+ const accountId = this.safeString (account, 'id');
575
+ const currencyId = this.safeString (account, 'currency');
576
+ const code = this.safeCurrencyCode (currencyId);
577
+ const type = this.safeStringLower (account, 'kind');
578
+ result.push ({
579
+ 'id': accountId,
580
+ 'type': type,
581
+ 'currency': code,
582
+ 'info': account,
583
+ });
584
+ }
585
+ return result;
586
+ }
587
+
588
+ async findAccountByType (type) {
589
+ await this.loadMarkets ();
590
+ await this.loadAccounts ();
591
+ const accountsByType = this.groupBy (this.accounts, 'type');
592
+ const accounts = this.safeValue (accountsByType, type);
593
+ if (accounts === undefined) {
594
+ throw new ExchangeError (this.id + " findAccountByType() could not find an accountId with type '" + type + "', specify the 'accountId' parameter instead"); // eslint-disable-line quotes
595
+ }
596
+ const numAccounts = accounts.length;
597
+ if (numAccounts > 1) {
598
+ throw new ExchangeError (this.id + " findAccountByType() found more than one accountId with type '" + type + "', specify the 'accountId' parameter instead"); // eslint-disable-line quotes
599
+ }
600
+ return accounts[0];
601
+ }
602
+
603
+ async getAccountId (params) {
604
+ await this.loadMarkets ();
605
+ await this.loadAccounts ();
606
+ const defaultAccountId = this.safeString (this.options, 'accountId');
607
+ const accountId = this.safeString (params, 'accountId', defaultAccountId);
608
+ if (accountId !== undefined) {
609
+ return accountId;
610
+ }
611
+ const defaultType = this.safeString (this.options, 'defaultType', 'margin');
612
+ const type = this.safeString (params, 'type', defaultType);
613
+ params = this.omit (params, 'type');
614
+ if (type === undefined) {
615
+ throw new ArgumentsRequired (this.id + " requires an 'accountId' parameter or a 'type' parameter ('spot' or 'margin')");
616
+ }
617
+ const account = await this.findAccountByType (type);
618
+ return account['id'];
619
+ }
620
+
621
+ parseBalance (response) {
622
+ const result = { 'info': response };
623
+ let timestamp = undefined;
624
+ const balances = this.safeValue (response, 'balances', []);
625
+ for (let i = 0; i < balances.length; i++) {
626
+ const balance = balances[i];
627
+ const lastUpdateTime = this.safeString (balance, 'lastUpdateTime');
628
+ const lastUpdated = lastUpdateTime.slice (0, 13);
629
+ const currentTimestamp = parseInt (lastUpdated);
630
+ timestamp = (timestamp === undefined) ? currentTimestamp : Math.max (timestamp, currentTimestamp);
631
+ const currencyId = this.safeString (balance, 'currency');
632
+ const code = this.safeCurrencyCode (currencyId);
633
+ const account = this.account ();
634
+ account['free'] = this.safeString (balance, 'available');
635
+ account['used'] = this.safeString (balance, 'onHold');
636
+ result[code] = account;
637
+ }
638
+ result['timestamp'] = timestamp;
639
+ result['datetime'] = this.iso8601 (timestamp);
640
+ return this.safeBalance (result);
641
+ }
642
+
643
+ async fetchBalance (params = {}) {
644
+ await this.loadMarkets ();
645
+ await this.loadAccounts ();
646
+ const accountId = await this.getAccountId (params);
647
+ const request = {
648
+ 'accountId': accountId,
649
+ };
650
+ const response = await this.privateGetTradingAccountsAccountIdBalance (this.extend (request, params));
651
+ //
652
+ // {
653
+ // "msgType":"XAR",
654
+ // "balances":[
655
+ // {
656
+ // "currency":"BTC",
657
+ // "lastUpdateTime":1619384111905916598,
658
+ // "available":"0.00549964",
659
+ // "onHold":"0",
660
+ // "settled":"0.00549964",
661
+ // "equity":"0.00549964"
662
+ // }
663
+ // ]
664
+ // }
665
+ //
666
+ return this.parseBalance (response);
667
+ }
668
+
669
+ parseTrade (trade, market = undefined) {
670
+ //
671
+ // fetchTrades (public)
672
+ //
673
+ // {
674
+ // "mdUpdateAction":"0",
675
+ // "mdEntryType":"2",
676
+ // "mdEntryPx":"9225.16",
677
+ // "mdEntrySize":"10000",
678
+ // "transactTime":1594728504524977655,
679
+ // "tradeId":"6ac51bb7-7505-4f35-85ef-61eb738cb4d9",
680
+ // "aggressorSide":"1"
681
+ // }
682
+ //
683
+ // fetchMyTrades (private)
684
+ //
685
+ // {
686
+ // "msgType":"8",
687
+ // "account":1012838158,
688
+ // "clOrdId":"xXWKLQVl3",
689
+ // "orderId":"89eee8bd-98ae-4d06-97dc-ee2d12997fe7",
690
+ // "symbol":"ETHUSD",
691
+ // "transactTime":1595143349089739000,
692
+ // "execId":"c4bd0ee2330930924e0f6fdde4630e56751692a4",
693
+ // "tradeId":"30a394b2-6d53-4bc4-b276-d8e19f470ba1",
694
+ // "side":"2",
695
+ // "lastQty":"1",
696
+ // "lastPx":"234.58",
697
+ // "avgPx":"234.58",
698
+ // "calculatedCcyLastQty":"0",
699
+ // "netMoney":"0",
700
+ // "lastLiquidityInd":"2",
701
+ // "commission":"0.00000011",
702
+ // "commRate":"0.00045",
703
+ // "commCurrency":"BTC",
704
+ // "positionId":132162662,
705
+ // "positionEffect":"C"
706
+ // }
707
+ //
708
+ const id = this.safeString (trade, 'tradeId');
709
+ let timestamp = this.safeInteger (trade, 'transactTime');
710
+ if (timestamp !== undefined) {
711
+ timestamp = parseInt (timestamp / 1000000);
712
+ }
713
+ let side = this.safeStringLower2 (trade, 'side', 'aggressorSide');
714
+ if (side === '1') {
715
+ side = 'buy';
716
+ } else if (side === '2') {
717
+ side = 'sell';
718
+ }
719
+ const orderId = this.safeString (trade, 'orderId');
720
+ const marketId = this.safeString (trade, 'symbol');
721
+ const symbol = this.safeSymbol (marketId, market);
722
+ const priceString = this.safeString2 (trade, 'lastPx', 'mdEntryPx');
723
+ const amountString = this.safeString2 (trade, 'lastQty', 'mdEntrySize');
724
+ let fee = undefined;
725
+ const feeCostString = this.safeString (trade, 'commission');
726
+ if (feeCostString !== undefined) {
727
+ const feeCurrencyId = this.safeString (trade, 'commCurrency');
728
+ const feeCurrencyCode = this.safeCurrencyCode (feeCurrencyId);
729
+ const feeRateString = this.safeString (trade, 'commRate');
730
+ fee = {
731
+ 'cost': feeCostString,
732
+ 'rate': feeRateString,
733
+ 'currency': feeCurrencyCode,
734
+ };
735
+ }
736
+ return this.safeTrade ({
737
+ 'id': id,
738
+ 'info': trade,
739
+ 'timestamp': timestamp,
740
+ 'datetime': this.iso8601 (timestamp),
741
+ 'symbol': symbol,
742
+ 'type': undefined,
743
+ 'order': orderId,
744
+ 'side': side,
745
+ 'takerOrMaker': undefined,
746
+ 'price': priceString,
747
+ 'amount': amountString,
748
+ 'cost': undefined,
749
+ 'fee': fee,
750
+ }, market);
751
+ }
752
+
753
+ async fetchMyTrades (symbol = undefined, since = undefined, limit = undefined, params = {}) {
754
+ await this.loadMarkets ();
755
+ await this.loadAccounts ();
756
+ const accountId = await this.getAccountId (params);
757
+ const request = {
758
+ 'accountId': accountId,
759
+ // 'page': 1,
760
+ // 'limit': integer,
761
+ // 'from': time,
762
+ // 'to': time,
763
+ // 'symbol': currency['id'],
764
+ // 'trade_id': id,
765
+ // 'client_order_id': id,
766
+ };
767
+ let market = undefined;
768
+ if (symbol !== undefined) {
769
+ market = this.market (symbol);
770
+ request['symbol'] = market['id'];
771
+ }
772
+ if (since !== undefined) {
773
+ request['from'] = since * 1000000;
774
+ }
775
+ if (limit !== undefined) {
776
+ request['limit'] = limit;
777
+ }
778
+ const response = await this.privateGetTradingAccountsAccountIdTradeHistory (this.extend (request, params));
779
+ //
780
+ // [
781
+ // {
782
+ // "msgType":"8",
783
+ // "account":1012838158,
784
+ // "clOrdId":"xXWKLQVl3",
785
+ // "orderId":"89eee8bd-98ae-4d06-97dc-ee2d12997fe7",
786
+ // "symbol":"ETHUSD",
787
+ // "transactTime":1595143349089739000,
788
+ // "execId":"c4bd0ee2330930924e0f6fdde4630e56751692a4",
789
+ // "tradeId":"30a394b2-6d53-4bc4-b276-d8e19f470ba1",
790
+ // "side":"2",
791
+ // "lastQty":"1",
792
+ // "lastPx":"234.58",
793
+ // "avgPx":"234.58",
794
+ // "calculatedCcyLastQty":"0",
795
+ // "netMoney":"0",
796
+ // "lastLiquidityInd":"2",
797
+ // "commission":"0.00000011",
798
+ // "commRate":"0.00045",
799
+ // "commCurrency":"BTC",
800
+ // "positionId":132162662,
801
+ // "positionEffect":"C"
802
+ // },
803
+ // {
804
+ // "msgType":"8",
805
+ // "account":1012838158,
806
+ // "clOrdId":"3ce8c305-9936-4e97-9206-71ae3ff40305",
807
+ // "orderId":"a93c686d-990e-44d9-9cbe-61107744b990",
808
+ // "symbol":"ETHUSD",
809
+ // "transactTime":1595143315369226000,
810
+ // "execId":"1c745881722ad966a4ce71600cd058d59da0d1c3",
811
+ // "tradeId":"77f75bd8-27c4-4b1a-a5e8-0d59239ce216",
812
+ // "side":"1",
813
+ // "lastQty":"1",
814
+ // "lastPx":"234.72",
815
+ // "avgPx":"234.72",
816
+ // "calculatedCcyLastQty":"0",
817
+ // "netMoney":"0",
818
+ // "lastLiquidityInd":"2",
819
+ // "commission":"0.00000011",
820
+ // "commRate":"0.00045",
821
+ // "commCurrency":"BTC",
822
+ // "positionId":132162662,
823
+ // "positionEffect":"O"
824
+ // }
825
+ // ]
826
+ //
827
+ return this.parseTrades (response, market, since, limit);
828
+ }
829
+
830
+ parseOHLCV (ohlcv, market = undefined) {
831
+ //
832
+ // {
833
+ // "transactTime":1594784700000000000,
834
+ // "firstPx":"9246.3",
835
+ // "lastPx":"9232.8",
836
+ // "highPx":"9246.3",
837
+ // "lowPx":"9232.8",
838
+ // "buyVolume":"0",
839
+ // "sellVolume":"0"
840
+ // }
841
+ //
842
+ const transactTime = this.safeInteger (ohlcv, 'transactTime');
843
+ const timestamp = parseInt (transactTime / 1000000);
844
+ const buyVolume = this.safeNumber (ohlcv, 'buyVolume');
845
+ const sellVolume = this.safeNumber (ohlcv, 'sellVolume');
846
+ const volume = this.sum (buyVolume, sellVolume);
847
+ return [
848
+ timestamp,
849
+ this.safeNumber (ohlcv, 'firstPx'),
850
+ this.safeNumber (ohlcv, 'highPx'),
851
+ this.safeNumber (ohlcv, 'lowPx'),
852
+ this.safeNumber (ohlcv, 'lastPx'),
853
+ volume,
854
+ ];
855
+ }
856
+
857
+ async fetchOHLCV (symbol, timeframe = '1m', since = undefined, limit = undefined, params = {}) {
858
+ await this.loadMarkets ();
859
+ const market = this.market (symbol);
860
+ const request = {
861
+ 'symbol': market['id'],
862
+ 'timeframe': this.timeframes[timeframe],
863
+ };
864
+ const durationInSeconds = this.parseTimeframe (timeframe);
865
+ const duration = durationInSeconds * 1000;
866
+ if (since !== undefined) {
867
+ request['from'] = since * 1000000;
868
+ if (limit !== undefined) {
869
+ request['to'] = this.sum (since, limit * duration) * 1000000;
870
+ }
871
+ } else {
872
+ const now = this.milliseconds ();
873
+ // max limit is 1000
874
+ if (limit !== undefined) {
875
+ request['from'] = (now - limit * duration) * 1000000;
876
+ }
877
+ }
878
+ const response = await this.publicGetMarketDataV2CandlesSymbolTimeframe (this.extend (request, params));
879
+ //
880
+ // {
881
+ // "mdEntry":[
882
+ // {"transactTime":1594784700000000000,"firstPx":"9246.3","lastPx":"9232.8","highPx":"9246.3","lowPx":"9232.8","buyVolume":"0","sellVolume":"0"},
883
+ // {"transactTime":1594785600000000000,"firstPx":"9231.8","lastPx":"9227.3","highPx":"9232.8","lowPx":"9227.3","buyVolume":"0","sellVolume":"0"},
884
+ // {"transactTime":1594786500000000000,"firstPx":"9226.3","lastPx":"9230.3","highPx":"9230.3","lowPx":"9220.6","buyVolume":"0","sellVolume":"0"}
885
+ // ]
886
+ // }
887
+ //
888
+ const mdEntry = this.safeValue (response, 'mdEntry', []);
889
+ return this.parseOHLCVs (mdEntry, market, timeframe, since, limit);
890
+ }
891
+
892
+ async fetchTrades (symbol, since = undefined, limit = undefined, params = {}) {
893
+ await this.loadMarkets ();
894
+ const market = this.market (symbol);
895
+ const request = {
896
+ 'symbol': market['id'],
897
+ // 'from': this.iso8601 (since),
898
+ // 'to': this.iso8601 (this.milliseconds ()),
899
+ // 'page': 1,
900
+ // 'limit': limit,
901
+ };
902
+ if (since !== undefined) {
903
+ request['from'] = this.iso8601 (since);
904
+ }
905
+ if (limit !== undefined) {
906
+ request['limit'] = limit;
907
+ }
908
+ const response = await this.publicGetMarketDataV2TradesSymbol (this.extend (request, params));
909
+ //
910
+ // {
911
+ // "msgType":"W",
912
+ // "lastUpdateTime":1594737830902223803,
913
+ // "symbol":"XBTUSD",
914
+ // "mdEntry":[
915
+ // {
916
+ // "mdUpdateAction":"0",
917
+ // "mdEntryType":"2",
918
+ // "mdEntryPx":"9225.16",
919
+ // "mdEntrySize":"10000",
920
+ // "transactTime":1594728504524977655,
921
+ // "tradeId":"6ac51bb7-7505-4f35-85ef-61eb738cb4d9",
922
+ // "aggressorSide":"1"
923
+ // },
924
+ // ]
925
+ // }
926
+ //
927
+ const mdEntry = this.safeValue (response, 'mdEntry', []);
928
+ return this.parseTrades (mdEntry, market, since, limit);
929
+ }
930
+
931
+ parseOrderStatus (status) {
932
+ const statuses = {
933
+ 'A': 'open', // PendingNew
934
+ '0': 'open', // New
935
+ '1': 'open', // PartiallyFilled
936
+ '2': 'closed', // Filled
937
+ '6': 'canceled', // PendingCancel
938
+ '4': 'canceled', // Cancelled
939
+ 'E': 'open', // PendingReplace
940
+ '8': 'rejected', // Rejected
941
+ };
942
+ return this.safeString (statuses, status, status);
943
+ }
944
+
945
+ parseOrder (order, market = undefined) {
946
+ //
947
+ // createOrder
948
+ //
949
+ // {
950
+ // "msgType":"8",
951
+ // "account":1012838720,
952
+ // "clOrdId":"XAq0pRQ1g",
953
+ // "orderId":"64d7a06a-27e5-422e-99d9-3cadc04f5a35",
954
+ // "symbol":"XBTUSD",
955
+ // "ordType":"2",
956
+ // "price":"9000",
957
+ // "transactTime":1593778763271127920,
958
+ // "execId":"ff5fb8153652f0516bf07b6979255bed053c84b9",
959
+ // "execType":"I",
960
+ // "ordStatus":"0",
961
+ // "side":"1",
962
+ // "orderQty":"1",
963
+ // "leavesQty":"1",
964
+ // "cumQty":"0",
965
+ // "positionEffect":"O",
966
+ // "marginAmt":"0.00000556",
967
+ // "marginAmtType":"11"
968
+ // }
969
+ //
970
+ const id = this.safeString (order, 'orderId');
971
+ const clientOrderId = this.safeString (order, 'clOrdId');
972
+ const transactTime = this.safeInteger (order, 'transactTime');
973
+ const timestamp = parseInt (transactTime / 1000000);
974
+ const status = this.parseOrderStatus (this.safeString (order, 'ordStatus'));
975
+ const marketId = this.safeString (order, 'symbol');
976
+ const symbol = this.safeSymbol (marketId, market);
977
+ const price = this.safeString (order, 'price');
978
+ const amount = this.safeString (order, 'orderQty');
979
+ const filled = this.safeString (order, 'cumQty');
980
+ const remaining = this.safeString (order, 'leavesQty');
981
+ let side = this.safeString (order, 'side');
982
+ if (side === '1') {
983
+ side = 'buy';
984
+ } else if (side === '2') {
985
+ side = 'sell';
986
+ }
987
+ let type = this.safeString (order, 'ordType');
988
+ if (type === '1') {
989
+ type = 'market';
990
+ } else if (type === '2') {
991
+ type = 'limit';
992
+ } else if (type === '3') {
993
+ type = 'stop';
994
+ } else if (type === '4') {
995
+ type = 'stop-limit';
996
+ }
997
+ return this.safeOrder ({
998
+ 'id': id,
999
+ 'clientOrderId': clientOrderId,
1000
+ 'info': order,
1001
+ 'timestamp': timestamp,
1002
+ 'datetime': this.iso8601 (timestamp),
1003
+ 'lastTradeTimestamp': undefined,
1004
+ 'symbol': symbol,
1005
+ 'type': type,
1006
+ 'timeInForce': undefined,
1007
+ 'postOnly': undefined,
1008
+ 'side': side,
1009
+ 'price': price,
1010
+ 'stopPrice': undefined,
1011
+ 'amount': amount,
1012
+ 'cost': undefined,
1013
+ 'average': undefined,
1014
+ 'filled': filled,
1015
+ 'remaining': remaining,
1016
+ 'status': status,
1017
+ 'fee': undefined,
1018
+ 'trades': undefined,
1019
+ }, market);
1020
+ }
1021
+
1022
+ async createOrder (symbol, type, side, amount, price = undefined, params = {}) {
1023
+ await this.loadMarkets ();
1024
+ await this.loadAccounts ();
1025
+ const accountId = await this.getAccountId (params);
1026
+ const orderTypes = {
1027
+ 'market': '1',
1028
+ 'limit': '2',
1029
+ 'stop': '3',
1030
+ 'stop-limit': '4',
1031
+ };
1032
+ const orderType = this.safeString (orderTypes, type);
1033
+ if (orderType === undefined) {
1034
+ throw new InvalidOrder (this.id + ' createOrder() does not support order type ' + type + ', supported order types are market, limit, stop, stop-limit');
1035
+ }
1036
+ const orderSides = {
1037
+ 'buy': '1',
1038
+ 'sell': '2',
1039
+ };
1040
+ const orderSide = this.safeString (orderSides, side);
1041
+ if (orderSide === undefined) {
1042
+ throw new InvalidOrder (this.id + ' createOrder() does not support order side ' + side + ', supported order sides are buy, sell');
1043
+ }
1044
+ const market = this.market (symbol);
1045
+ const request = {
1046
+ 'account': parseInt (accountId),
1047
+ 'symbol': market['id'],
1048
+ 'ordType': orderType,
1049
+ 'side': orderSide,
1050
+ 'orderQty': this.amountToPrecision (symbol, amount),
1051
+ 'transactTime': this.milliseconds () * 1000000,
1052
+ // 'clOrdId': this.uuid (), // required
1053
+ // 'price': this.priceToPrecision (symbol, price), // required for limit and stop-limit orders
1054
+ // 'stopPx': this.priceToPrecision (symbol, stopPx), // required for stop and stop-limit orders
1055
+ // 'timeInForce': '1', // default '1' = GoodTillCancelled, '3' = ImmediateOrCancel, '4' = FillOrKill
1056
+ // 'execInst': '0',
1057
+ // '0' = StayOnOfferSide, maker only, reject instead of aggressive execution
1058
+ // '9' = PegToOfferSide, maker only, best available level instead of aggressive execution
1059
+ // 'o' = CancelOnConnectionLoss
1060
+ // 'positionID': 1013838923, // required when positionEffect == 'C' with hedged accounting
1061
+ // 'positionEffect': 'O', // 'C' = Close, 'O' = Open, send C along with the positionID if the order must close a position with hedged accounting mode
1062
+ // 'text': 'comment', // optional
1063
+ // 'grpID': 'group-identifier', // group identifier for cancel on disconnect orders
1064
+ };
1065
+ if ((type === 'limit') || (type === 'stop-limit')) {
1066
+ if (price === undefined) {
1067
+ throw new InvalidOrder (this.id + ' createOrder() requires a price argument for order type ' + type);
1068
+ }
1069
+ request['price'] = this.priceToPrecision (symbol, price);
1070
+ }
1071
+ if ((type === 'stop') || (type === 'stop-limit')) {
1072
+ const stopPx = this.safeNumber (params, 'stopPx');
1073
+ if (stopPx === undefined) {
1074
+ throw new InvalidOrder (this.id + ' createOrder() requires a stopPx param for order type ' + type);
1075
+ }
1076
+ request['stopPx'] = this.priceToPrecision (symbol, stopPx);
1077
+ params = this.omit (params, 'stopPx');
1078
+ }
1079
+ const clientOrderId = this.safeString2 (params, 'clientOrderId', 'clOrdId', this.uuid ());
1080
+ if (clientOrderId !== undefined) {
1081
+ request['clOrdId'] = clientOrderId;
1082
+ params = this.omit (params, [ 'clientOrderId', 'clOrdId' ]);
1083
+ }
1084
+ const response = await this.privatePostTradingOrderNew (this.extend (request, params));
1085
+ //
1086
+ // {
1087
+ // "msgType":"8",
1088
+ // "account":1012838720,
1089
+ // "clOrdId":"XAq0pRQ1g",
1090
+ // "orderId":"64d7a06a-27e5-422e-99d9-3cadc04f5a35",
1091
+ // "symbol":"XBTUSD",
1092
+ // "ordType":"2",
1093
+ // "price":"9000",
1094
+ // "transactTime":1593778763271127920,
1095
+ // "execId":"ff5fb8153652f0516bf07b6979255bed053c84b9",
1096
+ // "execType":"I",
1097
+ // "ordStatus":"0",
1098
+ // "side":"1",
1099
+ // "orderQty":"1",
1100
+ // "leavesQty":"1",
1101
+ // "cumQty":"0",
1102
+ // "positionEffect":"O",
1103
+ // "marginAmt":"0.00000556",
1104
+ // "marginAmtType":"11"
1105
+ // }
1106
+ //
1107
+ return this.parseOrder (response, market);
1108
+ }
1109
+
1110
+ async editOrder (id, symbol, type, side, amount = undefined, price = undefined, params = {}) {
1111
+ if (symbol === undefined) {
1112
+ throw new ArgumentsRequired (this.id + ' cancelOrder() requires a symbol argument');
1113
+ }
1114
+ await this.loadMarkets ();
1115
+ await this.loadAccounts ();
1116
+ const accountId = await this.getAccountId (params);
1117
+ const market = this.market (symbol);
1118
+ const request = {
1119
+ 'account': parseInt (accountId),
1120
+ 'clOrdId': this.uuid (),
1121
+ 'symbol': market['id'],
1122
+ 'transactTime': this.milliseconds () * 1000000,
1123
+ // 'origClOrdId': this.uuid (), // one of orderId or origClOrdId is required
1124
+ // 'orderId': id,
1125
+ // 'side': '1', // 1 = buy, 2 = sell
1126
+ // 'execInst': '0',
1127
+ // '0' = StayOnOfferSide, maker only, reject instead of aggressive execution
1128
+ // '9' = PegToOfferSide, maker only, best available level instead of aggressive execution
1129
+ // 'o' = CancelOnConnectionLoss
1130
+ // 'orderQty': 38 M decimal
1131
+ // 'price': this.priceToPrecision (symbol, price), // required for limit and stop-limit orders
1132
+ // 'stopPx': this.priceToPrecision (symbol, stopPx), // required for stop and stop-limit orders
1133
+ // 'capPrice': this.priceToPrecision (symbol, capPrice), // the price beyond which the order will not move for trailing stop and attempt-zero-loss
1134
+ // 'pegPriceType': '8', // '8' = TrailingStopPeg, identifies a trailing stop or an attempt-zero-loss order
1135
+ // 'pegOffsetType': '2', // '2' = BasisPoints, the unit of the distance to the stop price for a trailing stop or an attempt-zero-loss order
1136
+ // 'pegOffsetValue': 123, // distance to the trailing stop or attempt-zero-loss
1137
+ };
1138
+ const clientOrderId = this.safeString2 (params, 'clientOrderId', 'origClOrdId');
1139
+ if (clientOrderId !== undefined) {
1140
+ request['origClOrdId'] = clientOrderId;
1141
+ params = this.omit (params, [ 'clientOrderId', 'origClOrdId' ]);
1142
+ } else {
1143
+ request['orderId'] = id;
1144
+ }
1145
+ if (amount !== undefined) {
1146
+ request['orderQty'] = this.amountToPrecision (symbol, amount);
1147
+ }
1148
+ if (price !== undefined) {
1149
+ request['price'] = this.priceToPrecision (symbol, price);
1150
+ }
1151
+ const stopPx = this.safeNumber (params, 'stopPx');
1152
+ if (stopPx !== undefined) {
1153
+ request['stopPx'] = this.priceToPrecision (symbol, stopPx);
1154
+ params = this.omit (params, 'stopPx');
1155
+ }
1156
+ const capPrice = this.safeNumber (params, 'capPrice');
1157
+ if (capPrice !== undefined) {
1158
+ request['capPrice'] = this.priceToPrecision (symbol, capPrice);
1159
+ params = this.omit (params, 'capPrice');
1160
+ }
1161
+ const response = await this.privatePostTradingOrderReplace (this.extend (request, params));
1162
+ return this.parseOrder (response, market);
1163
+ }
1164
+
1165
+ async cancelOrder (id, symbol = undefined, params = {}) {
1166
+ if (symbol === undefined) {
1167
+ throw new ArgumentsRequired (this.id + ' cancelOrder() requires a symbol argument');
1168
+ }
1169
+ await this.loadMarkets ();
1170
+ await this.loadAccounts ();
1171
+ const accountId = await this.getAccountId (params);
1172
+ const clientOrderId = this.safeString2 (params, 'clientOrderId', 'origClOrdId');
1173
+ params = this.omit (params, [ 'clientOrderId', 'origClOrdId' ]);
1174
+ const market = this.market (symbol);
1175
+ const request = {
1176
+ 'account': parseInt (accountId),
1177
+ 'symbol': market['id'],
1178
+ 'clOrdId': this.uuid (),
1179
+ 'transactTime': this.milliseconds () * 1000000,
1180
+ };
1181
+ if (clientOrderId !== undefined) {
1182
+ request['origClOrdId'] = clientOrderId;
1183
+ } else {
1184
+ request['orderId'] = id;
1185
+ }
1186
+ const response = await this.privatePostTradingOrderCancel (this.extend (request, params));
1187
+ //
1188
+ // {
1189
+ // "msgType":"8",
1190
+ // "account":1012838158,
1191
+ // "clOrdId":"0fa3fb55-9dc0-4cfc-a1db-6aa8b7dd2d98",
1192
+ // "origClOrdId":"3b2878bb-24d8-4922-9d2a-5b8009416677",
1193
+ // "orderId":"665b418e-9d09-4461-b733-d317f6bff43f",
1194
+ // "symbol":"ETHUSD",
1195
+ // "ordType":"2",
1196
+ // "price":"640",
1197
+ // "transactTime":1595060080941618739,
1198
+ // "execId":"c541c0ca437c0e6501c3a50a9d4dc8f575f49972",
1199
+ // "execType":"6",
1200
+ // "ordStatus":"6",
1201
+ // "side":"2",
1202
+ // "orderQty":"1",
1203
+ // "leavesQty":"0",
1204
+ // "cumQty":"0",
1205
+ // "positionEffect":"O",
1206
+ // "marginAmt":"0.000032",
1207
+ // "marginAmtType":"11"
1208
+ // }
1209
+ //
1210
+ return this.parseOrder (response, market);
1211
+ }
1212
+
1213
+ async cancelAllOrders (symbol = undefined, params = {}) {
1214
+ await this.loadMarkets ();
1215
+ await this.loadAccounts ();
1216
+ const accountId = await this.getAccountId (params);
1217
+ const request = {
1218
+ 'account': parseInt (accountId),
1219
+ 'clOrdId': this.uuid (),
1220
+ // 'side': '1', // 1 = buy, 2 = sell, optional filter, cancel only orders with the given side
1221
+ // 'positionEffect': 'C', // C = Close, O = Open, optional filter, cancel only orders with the given positionEffect, applicable only for accounts with hedged accounting
1222
+ };
1223
+ if (symbol !== undefined) {
1224
+ const market = this.market (symbol);
1225
+ request['symbol'] = market['id'];
1226
+ request['massCancelRequestType'] = '1'; // CancelOrdersForASecurity
1227
+ } else {
1228
+ request['massCancelRequestType'] = '7'; // CancelAllOrders
1229
+ }
1230
+ const response = await this.privatePostTradingOrderMassCancel (this.extend (request, params));
1231
+ //
1232
+ // {
1233
+ // "msgType":"r",
1234
+ // "clOrdId":"b3e95759-e43e-4b3a-b664-a4d213e281a7",
1235
+ // "massActionReportID":"e915b6f4-a7ca-4c5c-b8d6-e39862530248",
1236
+ // "massCancelResponse":"1",
1237
+ // "symbol":"ETHUSD",
1238
+ // "transactTime":1595065630133756426,
1239
+ // "totalAffectedOrders":2,
1240
+ // "account":1012838158
1241
+ // }
1242
+ //
1243
+ return response;
1244
+ }
1245
+
1246
+ async fetchOpenOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) {
1247
+ await this.loadMarkets ();
1248
+ await this.loadAccounts ();
1249
+ const accountId = await this.getAccountId (params);
1250
+ const request = {
1251
+ 'accountId': accountId,
1252
+ // 'symbol': market['id'],
1253
+ };
1254
+ let market = undefined;
1255
+ if (symbol !== undefined) {
1256
+ market = this.market (symbol);
1257
+ request['symbol'] = market['id'];
1258
+ }
1259
+ const response = await this.privateGetTradingAccountsAccountIdActiveOrders (this.extend (request, params));
1260
+ //
1261
+ // [
1262
+ // {
1263
+ // "msgType":"8",
1264
+ // "account":1012838720,
1265
+ // "clOrdId":"XAq0pRQ1g",
1266
+ // "orderId":"64d7a06a-27e5-422e-99d9-3cadc04f5a35",
1267
+ // "symbol":"XBTUSD",
1268
+ // "ordType":"2",
1269
+ // "price":"9000",
1270
+ // "transactTime":1593778763271127920,
1271
+ // "execId":"ff5fb8153652f0516bf07b6979255bed053c84b9",
1272
+ // "execType":"I",
1273
+ // "ordStatus":"0",
1274
+ // "side":"1",
1275
+ // "orderQty":"1",
1276
+ // "leavesQty":"1",
1277
+ // "cumQty":"0",
1278
+ // "positionEffect":"O",
1279
+ // "marginAmt":"0.00000556",
1280
+ // "marginAmtType":"11"
1281
+ // }
1282
+ // ]
1283
+ //
1284
+ return this.parseOrders (response, market, since, limit);
1285
+ }
1286
+
1287
+ async fetchClosedOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) {
1288
+ await this.loadMarkets ();
1289
+ await this.loadAccounts ();
1290
+ const accountId = await this.getAccountId (params);
1291
+ const request = {
1292
+ 'accountId': accountId,
1293
+ // 'from': this.iso8601 (since) * 1000000,
1294
+ // 'to': this.iso8601 (this.milliseconds ()) * 1000000, // max range is 7 days
1295
+ // 'symbol': market['id'],
1296
+ // 'limit': 100,
1297
+ };
1298
+ let market = undefined;
1299
+ if (symbol !== undefined) {
1300
+ market = this.market (symbol);
1301
+ request['symbol'] = market['id'];
1302
+ }
1303
+ if (since !== undefined) {
1304
+ request['from'] = this.iso8601 (since) * 1000000;
1305
+ }
1306
+ if (limit !== undefined) {
1307
+ request['limit'] = limit;
1308
+ }
1309
+ const response = await this.privateGetTradingAccountsAccountIdLastOrderStatuses (this.extend (request, params));
1310
+ //
1311
+ // [
1312
+ // {
1313
+ // "msgType":"8",
1314
+ // "account":1012838720,
1315
+ // "clOrdId":"XAq0pRQ1g",
1316
+ // "orderId":"64d7a06a-27e5-422e-99d9-3cadc04f5a35",
1317
+ // "symbol":"XBTUSD",
1318
+ // "ordType":"2",
1319
+ // "price":"9000",
1320
+ // "transactTime":1593778763271127920,
1321
+ // "execId":"ff5fb8153652f0516bf07b6979255bed053c84b9",
1322
+ // "execType":"I",
1323
+ // "ordStatus":"0",
1324
+ // "side":"1",
1325
+ // "orderQty":"1",
1326
+ // "leavesQty":"1",
1327
+ // "cumQty":"0",
1328
+ // "positionEffect":"O",
1329
+ // "marginAmt":"0.00000556",
1330
+ // "marginAmtType":"11"
1331
+ // }
1332
+ // ]
1333
+ //
1334
+ return this.parseOrders (response, market, since, limit);
1335
+ }
1336
+
1337
+ async createDepositAddress (code, params = {}) {
1338
+ await this.loadMarkets ();
1339
+ await this.loadAccounts ();
1340
+ const accountId = await this.getAccountId (params);
1341
+ const currency = this.currency (code);
1342
+ const request = {
1343
+ 'accountId': accountId,
1344
+ 'currency': currency['id'],
1345
+ };
1346
+ const response = await this.privatePostTransfersAccountsAccountIdDepositAddressCurrency (this.extend (request, params));
1347
+ //
1348
+ // {
1349
+ // "address": "mu5GceHFAG38mGRYCFqafe5ZiNKLX3rKk9",
1350
+ // "uri": "bitcoin:mu5GceHFAG38mGRYCFqafe5ZiNKLX3rKk9?message=Xena Exchange",
1351
+ // "allowsRenewal": true
1352
+ // }
1353
+ //
1354
+ const address = this.safeValue (response, 'address');
1355
+ const tag = undefined;
1356
+ this.checkAddress (address);
1357
+ return {
1358
+ 'currency': code,
1359
+ 'address': address,
1360
+ 'tag': tag,
1361
+ 'info': response,
1362
+ };
1363
+ }
1364
+
1365
+ async fetchDepositAddress (code, params = {}) {
1366
+ await this.loadMarkets ();
1367
+ await this.loadAccounts ();
1368
+ const accountId = await this.getAccountId (params);
1369
+ const currency = this.currency (code);
1370
+ const request = {
1371
+ 'accountId': accountId,
1372
+ 'currency': currency['id'],
1373
+ };
1374
+ const response = await this.privateGetTransfersAccountsAccountIdDepositAddressCurrency (this.extend (request, params));
1375
+ //
1376
+ // {
1377
+ // "address": "mu5GceHFAG38mGRYCFqafe5ZiNKLX3rKk9",
1378
+ // "uri": "bitcoin:mu5GceHFAG38mGRYCFqafe5ZiNKLX3rKk9?message=Xena Exchange",
1379
+ // "allowsRenewal": true
1380
+ // }
1381
+ //
1382
+ const address = this.safeValue (response, 'address');
1383
+ const tag = undefined;
1384
+ this.checkAddress (address);
1385
+ return {
1386
+ 'currency': code,
1387
+ 'address': address,
1388
+ 'tag': tag,
1389
+ 'network': undefined,
1390
+ 'info': response,
1391
+ };
1392
+ }
1393
+
1394
+ async fetchTransactionsByType (type, code = undefined, since = undefined, limit = undefined, params = {}) {
1395
+ if (code === undefined) {
1396
+ throw new ArgumentsRequired (this.id + ' fetchTransactions() requires a currency `code` argument');
1397
+ }
1398
+ await this.loadMarkets ();
1399
+ await this.loadAccounts ();
1400
+ const accountId = await this.getAccountId (params);
1401
+ const currency = this.currency (code);
1402
+ const request = {
1403
+ 'currency': currency['id'],
1404
+ 'accountId': accountId,
1405
+ };
1406
+ if (since !== undefined) {
1407
+ request['since'] = parseInt (since / 1000);
1408
+ }
1409
+ const method = 'privateGetTransfersAccountsAccountId' + this.capitalize (type);
1410
+ const response = await this[method] (this.extend (request, params));
1411
+ //
1412
+ // {
1413
+ // "withdrawals": [
1414
+ // {
1415
+ // "withdrawalRequestId": 47383243,
1416
+ // "externalId": "...", // external ID submitted by the client when creating the request
1417
+ // "status": 1,
1418
+ // "statusMessage": "Pending confirmation",
1419
+ // "amount": "10.2",
1420
+ // "currency": "BTC",
1421
+ // "lastUpdated": <UNIX nanoseconds>,
1422
+ // "blockchain": "Bitcoin",
1423
+ // "address": "mu5GceHFAG38mGRYCFqafe5ZiNKLX3rKk9",
1424
+ // "txId": "0xfbb1b73c4f0bda4f67dca266ce6ef42f520fbb98"
1425
+ // }
1426
+ // ]
1427
+ // }
1428
+ //
1429
+ // {
1430
+ // "deposits": [
1431
+ // {
1432
+ // "currency": "BTC",
1433
+ // "amount": "1.2",
1434
+ // "status": 1,
1435
+ // "statusMessage": "Processing",
1436
+ // "blockchain": "Bitcoin",
1437
+ // "txId": "0xfbb1b73c4f0bda4f67dca266ce6ef42f520fbb98",
1438
+ // "address": "mu5GceHFAG38mGRYCFqafe5ZiNKLX3rKk9",
1439
+ // "lastUpdated": <UNIX nanoseconds>
1440
+ // "confirmations": 2,
1441
+ // "requiredConfirmations": 6
1442
+ // }
1443
+ // ]
1444
+ // }
1445
+ //
1446
+ //
1447
+ const transactions = this.safeValue (response, type, []);
1448
+ return this.parseTransactions (transactions, currency, since, limit);
1449
+ }
1450
+
1451
+ async fetchWithdrawals (code = undefined, since = undefined, limit = undefined, params = {}) {
1452
+ return await this.fetchTransactionsByType ('withdrawals', code, since, limit, params);
1453
+ }
1454
+
1455
+ async fetchDeposits (code = undefined, since = undefined, limit = undefined, params = {}) {
1456
+ return await this.fetchTransactionsByType ('deposits', code, since, limit, params);
1457
+ }
1458
+
1459
+ parseTransaction (transaction, currency = undefined) {
1460
+ //
1461
+ // withdraw()
1462
+ //
1463
+ // {
1464
+ // "withdrawalRequestId": 47383243,
1465
+ // "status": 1,
1466
+ // "statusMessage": "Pending confirmation"
1467
+ // }
1468
+ //
1469
+ // fetchWithdrawals
1470
+ //
1471
+ // {
1472
+ // "withdrawalRequestId": 47383243,
1473
+ // "externalId": "...", // external ID submitted by the client when creating the request
1474
+ // "status": 1,
1475
+ // "statusMessage": "Pending confirmation",
1476
+ // "amount": "10.2",
1477
+ // "currency": "BTC",
1478
+ // "lastUpdated": <UNIX nanoseconds>,
1479
+ // "blockchain": "Bitcoin",
1480
+ // "address": "mu5GceHFAG38mGRYCFqafe5ZiNKLX3rKk9",
1481
+ // "txId": "0xfbb1b73c4f0bda4f67dca266ce6ef42f520fbb98"
1482
+ // }
1483
+ //
1484
+ // fetchDeposits
1485
+ //
1486
+ // {
1487
+ // "currency": "BTC",
1488
+ // "amount": "1.2",
1489
+ // "status": 1,
1490
+ // "statusMessage": "Processing",
1491
+ // "blockchain": "Bitcoin",
1492
+ // "txId": "0xfbb1b73c4f0bda4f67dca266ce6ef42f520fbb98",
1493
+ // "address": "mu5GceHFAG38mGRYCFqafe5ZiNKLX3rKk9",
1494
+ // "lastUpdated": <UNIX nanoseconds>
1495
+ // "confirmations": 2,
1496
+ // "requiredConfirmations": 6
1497
+ // }
1498
+ //
1499
+ const id = this.safeString (transaction, 'withdrawalRequestId');
1500
+ const type = (id === undefined) ? 'deposit' : 'withdrawal';
1501
+ let updated = this.safeInteger (transaction, 'lastUpdated');
1502
+ if (updated !== undefined) {
1503
+ updated = parseInt (updated / 1000000);
1504
+ }
1505
+ const timestamp = undefined;
1506
+ const txid = this.safeString (transaction, 'txId');
1507
+ const currencyId = this.safeString (transaction, 'currency');
1508
+ const code = this.safeCurrencyCode (currencyId, currency);
1509
+ const address = this.safeString (transaction, 'address');
1510
+ const addressFrom = undefined;
1511
+ const addressTo = address;
1512
+ const amount = this.safeNumber (transaction, 'amount');
1513
+ const status = this.parseTransactionStatus (this.safeString (transaction, 'status'));
1514
+ const fee = undefined;
1515
+ const network = this.safeString (transaction, 'blockchain');
1516
+ return {
1517
+ 'info': transaction,
1518
+ 'id': id,
1519
+ 'txid': txid,
1520
+ 'timestamp': timestamp,
1521
+ 'datetime': this.iso8601 (timestamp),
1522
+ 'network': network,
1523
+ 'addressFrom': addressFrom,
1524
+ 'addressTo': addressTo,
1525
+ 'address': address,
1526
+ 'tagFrom': undefined,
1527
+ 'tagTo': undefined,
1528
+ 'tag': undefined,
1529
+ 'type': type,
1530
+ 'amount': amount,
1531
+ 'currency': code,
1532
+ 'status': status,
1533
+ 'updated': updated,
1534
+ 'fee': fee,
1535
+ };
1536
+ }
1537
+
1538
+ parseTransactionStatus (status) {
1539
+ const statuses = {
1540
+ '1': 'pending', // new
1541
+ '2': 'ok', // completed
1542
+ '3': 'failed', // duplicate
1543
+ '4': 'failed', // not enough money
1544
+ '5': 'pending', // waiting for manual approval from XENA
1545
+ '100': 'pending', // request is being processed
1546
+ '101': 'pending', // request is being processed
1547
+ '102': 'pending', // request is being processed
1548
+ '103': 'pending', // request is being processed
1549
+ };
1550
+ return this.safeString (statuses, status, status);
1551
+ }
1552
+
1553
+ async withdraw (code, amount, address, tag = undefined, params = {}) {
1554
+ [ tag, params ] = this.handleWithdrawTagAndParams (tag, params);
1555
+ this.checkAddress (address);
1556
+ await this.loadMarkets ();
1557
+ await this.loadAccounts ();
1558
+ const accountId = await this.getAccountId (params);
1559
+ const currency = this.currency (code);
1560
+ let uuid = this.uuid ();
1561
+ uuid = uuid.split ('-');
1562
+ uuid = uuid.join ('');
1563
+ const request = {
1564
+ 'currency': currency['id'],
1565
+ 'accountId': accountId,
1566
+ 'amount': this.currencyToPrecision (code, amount),
1567
+ 'address': address,
1568
+ 'id': uuid, // mandatory external ID (string), used by the client to identify his request
1569
+ };
1570
+ const response = await this.privatePostTransfersAccountsAccountIdWithdrawals (this.extend (request, params));
1571
+ //
1572
+ // {
1573
+ // "withdrawalRequestId": 47383243,
1574
+ // "status": 1,
1575
+ // "statusMessage": "Pending confirmation"
1576
+ // }
1577
+ //
1578
+ return this.parseTransaction (response, currency);
1579
+ }
1580
+
1581
+ parseLedgerEntryType (type) {
1582
+ const types = {
1583
+ 'deposit': 'transaction',
1584
+ 'withdrawal': 'transaction',
1585
+ 'internal deposit': 'transfer',
1586
+ 'internal withdrawal': 'transfer',
1587
+ 'rebate': 'rebate',
1588
+ 'reward': 'reward',
1589
+ };
1590
+ return this.safeString (types, type, type);
1591
+ }
1592
+
1593
+ parseLedgerEntry (item, currency = undefined) {
1594
+ //
1595
+ // {
1596
+ // "accountId":8263118,
1597
+ // "ts":1551974415000000000,
1598
+ // "amount":"-1",
1599
+ // "currency":"BTC",
1600
+ // "kind":"internal withdrawal",
1601
+ // "commission":"0",
1602
+ // "id":96
1603
+ // }
1604
+ //
1605
+ const id = this.safeString (item, 'id');
1606
+ let direction = undefined;
1607
+ const account = this.safeString (item, 'accountId');
1608
+ const referenceId = undefined;
1609
+ const referenceAccount = undefined;
1610
+ const type = this.parseLedgerEntryType (this.safeString (item, 'kind'));
1611
+ const code = this.safeCurrencyCode (this.safeString (item, 'currency'), currency);
1612
+ let amount = this.safeNumber (item, 'amount');
1613
+ if (amount < 0) {
1614
+ direction = 'out';
1615
+ amount = Math.abs (amount);
1616
+ } else {
1617
+ direction = 'in';
1618
+ }
1619
+ let timestamp = this.safeInteger (item, 'ts');
1620
+ if (timestamp !== undefined) {
1621
+ timestamp = parseInt (timestamp / 1000000);
1622
+ }
1623
+ const fee = {
1624
+ 'cost': this.safeNumber (item, 'commission'),
1625
+ 'currency': code,
1626
+ };
1627
+ const before = undefined;
1628
+ const after = this.safeNumber (item, 'balance');
1629
+ const status = 'ok';
1630
+ return {
1631
+ 'info': item,
1632
+ 'id': id,
1633
+ 'direction': direction,
1634
+ 'account': account,
1635
+ 'referenceId': referenceId,
1636
+ 'referenceAccount': referenceAccount,
1637
+ 'type': type,
1638
+ 'currency': code,
1639
+ 'amount': amount,
1640
+ 'before': before,
1641
+ 'after': after,
1642
+ 'status': status,
1643
+ 'timestamp': timestamp,
1644
+ 'datetime': this.iso8601 (timestamp),
1645
+ 'fee': fee,
1646
+ };
1647
+ }
1648
+
1649
+ async fetchLedger (code = undefined, since = undefined, limit = undefined, params = {}) {
1650
+ await this.loadMarkets ();
1651
+ await this.loadAccounts ();
1652
+ const accountId = await this.getAccountId (params);
1653
+ const request = {
1654
+ 'accountId': accountId,
1655
+ // 'page': 1,
1656
+ // 'limit': 5000, // max 5000
1657
+ // 'from': time,
1658
+ // 'to': time,
1659
+ // 'symbol': currency['id'],
1660
+ // 'trade_id': id,
1661
+ // 'client_order_id': id,
1662
+ // 'txid': txid,
1663
+ // 'kind': 'deposit', // 'withdrawal, 'internal deposit', 'internal withdrawal', 'rebate', 'reward'
1664
+ };
1665
+ let currency = undefined;
1666
+ if (code !== undefined) {
1667
+ currency = this.currency (code);
1668
+ request['symbol'] = currency['id'];
1669
+ }
1670
+ if (since !== undefined) {
1671
+ request['from'] = since * 1000000;
1672
+ }
1673
+ if (limit !== undefined) {
1674
+ request['limit'] = limit; // max 5000
1675
+ }
1676
+ const response = await this.privateGetTransfersAccountsAccountIdBalanceHistory (this.extend (request, params));
1677
+ //
1678
+ // [
1679
+ // {
1680
+ // "accountId":8263118,
1681
+ // "ts":1551974415000000000,
1682
+ // "amount":"-1",
1683
+ // "currency":"BTC",
1684
+ // "kind":"internal withdrawal",
1685
+ // "commission":"0",
1686
+ // "id":96
1687
+ // },
1688
+ // {
1689
+ // "accountId":8263118,
1690
+ // "ts":1551964677000000000,
1691
+ // "amount":"-1",
1692
+ // "currency":"BTC",
1693
+ // "kind":"internal deposit",
1694
+ // "commission":"0",
1695
+ // "id":95
1696
+ // }
1697
+ // ]
1698
+ //
1699
+ return this.parseLedger (response, currency, since, limit);
1700
+ }
1701
+
1702
+ async fetchLeverageTiers (symbols = undefined, params = {}) {
1703
+ await this.loadMarkets ();
1704
+ const response = await this.publicGetCommonInstruments (params);
1705
+ //
1706
+ // [
1707
+ // {
1708
+ // "id": "XBTUSD_3M_240622",
1709
+ // "type": "Margin",
1710
+ // "marginType": "XenaFuture",
1711
+ // "symbol": "XBTUSD_3M_240622",
1712
+ // "baseCurrency": "BTC",
1713
+ // "quoteCurrency": "USD",
1714
+ // "settlCurrency": "USDC",
1715
+ // "tickSize": 0,
1716
+ // "minOrderQuantity": "0.0001",
1717
+ // "orderQtyStep": "0.0001",
1718
+ // "limitOrderMaxDistance": "10",
1719
+ // "priceInputMask": "00000.0",
1720
+ // "enabled": true,
1721
+ // "liquidationMaxDistance": "0.01",
1722
+ // "contractValue": "1",
1723
+ // "contractCurrency": "BTC",
1724
+ // "lotSize": "1",
1725
+ // "maxOrderQty": "10",
1726
+ // "maxPosVolume": "200",
1727
+ // "mark": ".XBTUSD_3M_240622",
1728
+ // "underlying": ".BTC3_TWAP",
1729
+ // "openInterest": ".XBTUSD_3M_240622_OpenInterest",
1730
+ // "addUvmToFreeMargin": "ProfitAndLoss",
1731
+ // "margin": {
1732
+ // "netting": "PositionsAndOrders",
1733
+ // "rates": [
1734
+ // { "maxVolume": "10", "initialRate": "0.05", "maintenanceRate": "0.025" },
1735
+ // { "maxVolume": "20", "initialRate": "0.1", "maintenanceRate": "0.05" },
1736
+ // { "maxVolume": "30", "initialRate": "0.2", "maintenanceRate": "0.1" },
1737
+ // { "maxVolume": "40", "initialRate": "0.3", "maintenanceRate": "0.15" },
1738
+ // { "maxVolume": "60", "initialRate": "0.4", "maintenanceRate": "0.2" },
1739
+ // { "maxVolume": "150", "initialRate": "0.5", "maintenanceRate": "0.25" },
1740
+ // { "maxVolume": "200", "initialRate": "1", "maintenanceRate": "0.5" }
1741
+ // ],
1742
+ // "rateMultipliers": {
1743
+ // "LimitBuy": "1",
1744
+ // "LimitSell": "1",
1745
+ // "Long": "1",
1746
+ // "MarketBuy": "1",
1747
+ // "MarketSell": "1",
1748
+ // "Short": "1",
1749
+ // "StopBuy": "0",
1750
+ // "StopSell": "0"
1751
+ // }
1752
+ // },
1753
+ // "clearing": { "enabled": true, "index": ".XBTUSD_3M_240622" },
1754
+ // "riskAdjustment": { "enabled": true, "index": ".RiskAdjustment_IR" },
1755
+ // "expiration": { "enabled": true, "index": ".BTC3_TWAP" },
1756
+ // "pricePrecision": 1,
1757
+ // "priceRange": {
1758
+ // "enabled": true,
1759
+ // "distance": "0.2",
1760
+ // "movingBoundary": "0",
1761
+ // "lowIndex": ".XBTUSD_3M_240622_LOWRANGE",
1762
+ // "highIndex": ".XBTUSD_3M_240622_HIGHRANGE"
1763
+ // },
1764
+ // "priceLimits": {
1765
+ // "enabled": true,
1766
+ // "distance": "0.5",
1767
+ // "movingBoundary": "0",
1768
+ // "lowIndex": ".XBTUSD_3M_240622_LOWLIMIT",
1769
+ // "highIndex": ".XBTUSD_3M_240622_HIGHLIMIT"
1770
+ // },
1771
+ // "serie": "XBTUSD",
1772
+ // "tradingStartDate": "2021-12-31 07:00:00",
1773
+ // "expiryDate": "2022-06-24 08:00:00"
1774
+ // },
1775
+ // ...
1776
+ // ]
1777
+ //
1778
+ return this.parseLeverageTiers (response, symbols, 'symbol');
1779
+ }
1780
+
1781
+ parseMarketLeverageTiers (info, market) {
1782
+ /**
1783
+ * @ignore
1784
+ * @method
1785
+ * @param {dict} info Exchange market response for 1 market
1786
+ * @param {dict} market CCXT market
1787
+ */
1788
+ //
1789
+ // {
1790
+ // "id": "XBTUSD_3M_240622",
1791
+ // "type": "Margin",
1792
+ // "marginType": "XenaFuture",
1793
+ // "symbol": "XBTUSD_3M_240622",
1794
+ // "baseCurrency": "BTC",
1795
+ // "quoteCurrency": "USD",
1796
+ // "settlCurrency": "USDC",
1797
+ // "tickSize": 0,
1798
+ // "minOrderQuantity": "0.0001",
1799
+ // "orderQtyStep": "0.0001",
1800
+ // "limitOrderMaxDistance": "10",
1801
+ // "priceInputMask": "00000.0",
1802
+ // "enabled": true,
1803
+ // "liquidationMaxDistance": "0.01",
1804
+ // "contractValue": "1",
1805
+ // "contractCurrency": "BTC",
1806
+ // "lotSize": "1",
1807
+ // "maxOrderQty": "10",
1808
+ // "maxPosVolume": "200",
1809
+ // "mark": ".XBTUSD_3M_240622",
1810
+ // "underlying": ".BTC3_TWAP",
1811
+ // "openInterest": ".XBTUSD_3M_240622_OpenInterest",
1812
+ // "addUvmToFreeMargin": "ProfitAndLoss",
1813
+ // "margin": {
1814
+ // "netting": "PositionsAndOrders",
1815
+ // "rates": [
1816
+ // { "maxVolume": "10", "initialRate": "0.05", "maintenanceRate": "0.025" },
1817
+ // { "maxVolume": "20", "initialRate": "0.1", "maintenanceRate": "0.05" },
1818
+ // { "maxVolume": "30", "initialRate": "0.2", "maintenanceRate": "0.1" },
1819
+ // { "maxVolume": "40", "initialRate": "0.3", "maintenanceRate": "0.15" },
1820
+ // { "maxVolume": "60", "initialRate": "0.4", "maintenanceRate": "0.2" },
1821
+ // { "maxVolume": "150", "initialRate": "0.5", "maintenanceRate": "0.25" },
1822
+ // { "maxVolume": "200", "initialRate": "1", "maintenanceRate": "0.5" }
1823
+ // ],
1824
+ // "rateMultipliers": {
1825
+ // "LimitBuy": "1",
1826
+ // "LimitSell": "1",
1827
+ // "Long": "1",
1828
+ // "MarketBuy": "1",
1829
+ // "MarketSell": "1",
1830
+ // "Short": "1",
1831
+ // "StopBuy": "0",
1832
+ // "StopSell": "0"
1833
+ // }
1834
+ // },
1835
+ // "clearing": { "enabled": true, "index": ".XBTUSD_3M_240622" },
1836
+ // "riskAdjustment": { "enabled": true, "index": ".RiskAdjustment_IR" },
1837
+ // "expiration": { "enabled": true, "index": ".BTC3_TWAP" },
1838
+ // "pricePrecision": 1,
1839
+ // "priceRange": {
1840
+ // "enabled": true,
1841
+ // "distance": "0.2",
1842
+ // "movingBoundary": "0",
1843
+ // "lowIndex": ".XBTUSD_3M_240622_LOWRANGE",
1844
+ // "highIndex": ".XBTUSD_3M_240622_HIGHRANGE"
1845
+ // },
1846
+ // "priceLimits": {
1847
+ // "enabled": true,
1848
+ // "distance": "0.5",
1849
+ // "movingBoundary": "0",
1850
+ // "lowIndex": ".XBTUSD_3M_240622_LOWLIMIT",
1851
+ // "highIndex": ".XBTUSD_3M_240622_HIGHLIMIT"
1852
+ // },
1853
+ // "serie": "XBTUSD",
1854
+ // "tradingStartDate": "2021-12-31 07:00:00",
1855
+ // "expiryDate": "2022-06-24 08:00:00"
1856
+ // }
1857
+ //
1858
+ const margin = this.safeValue (info, 'margin');
1859
+ const rates = this.safeValue (margin, 'rates');
1860
+ let floor = 0;
1861
+ const id = this.safeString (info, 'symbol');
1862
+ market = this.safeMarket (id, market);
1863
+ const tiers = [];
1864
+ if (rates !== undefined) {
1865
+ for (let j = 0; j < rates.length; j++) {
1866
+ const tier = rates[j];
1867
+ const cap = this.safeNumber (tier, 'maxVolume');
1868
+ const initialRate = this.safeString (tier, 'initialRate');
1869
+ tiers.push ({
1870
+ 'tier': this.sum (j, 1),
1871
+ 'currency': market['base'],
1872
+ 'minNotional': floor,
1873
+ 'maxNotional': cap,
1874
+ 'maintenanceMarginRate': this.safeNumber (tier, 'maintenanceRate'),
1875
+ 'maxLeverage': this.parseNumber (Precise.stringDiv ('1', initialRate)),
1876
+ 'info': tier,
1877
+ });
1878
+ floor = cap;
1879
+ }
1880
+ }
1881
+ return tiers;
1882
+ }
1883
+
1884
+ nonce () {
1885
+ return this.milliseconds ();
1886
+ }
1887
+
1888
+ sign (path, api = 'public', method = 'GET', params = {}, headers = undefined, body = undefined) {
1889
+ let url = this.urls['api'][api] + '/' + this.implodeParams (path, params);
1890
+ const query = this.omit (params, this.extractParams (path));
1891
+ if (api === 'public') {
1892
+ if (Object.keys (query).length) {
1893
+ url += '?' + this.urlencode (query);
1894
+ }
1895
+ } else if (api === 'private') {
1896
+ this.checkRequiredCredentials ();
1897
+ let nonce = this.nonce ();
1898
+ // php does not format it properly
1899
+ // therefore we use string concatenation here
1900
+ // nonce *= 1000000;
1901
+ nonce = nonce.toString ();
1902
+ nonce = nonce + '000000'; // see the comment a few lines above
1903
+ const payload = 'AUTH' + nonce;
1904
+ const secret = this.secret.slice (14, 78);
1905
+ const ecdsa = this.ecdsa (payload, secret, 'p256', 'sha256');
1906
+ const signature = ecdsa['r'] + ecdsa['s'];
1907
+ headers = {
1908
+ 'X-AUTH-API-KEY': this.apiKey,
1909
+ 'X-AUTH-API-PAYLOAD': payload,
1910
+ 'X-AUTH-API-SIGNATURE': signature,
1911
+ 'X-AUTH-API-NONCE': nonce,
1912
+ };
1913
+ if (method === 'GET') {
1914
+ if (Object.keys (query).length) {
1915
+ url += '?' + this.urlencode (query);
1916
+ }
1917
+ } else if (method === 'POST') {
1918
+ body = this.json (query);
1919
+ headers['Content-Type'] = 'application/json';
1920
+ }
1921
+ }
1922
+ return { 'url': url, 'method': method, 'body': body, 'headers': headers };
1923
+ }
1924
+
1925
+ handleErrors (code, reason, url, method, headers, body, response, requestHeaders, requestBody) {
1926
+ if (response === undefined) {
1927
+ return;
1928
+ }
1929
+ //
1930
+ // {"error":"Validation failed","fields":["address"]}
1931
+ // {"error":"Money not enough. You have only: 0 ETH","fields":["amount"]}
1932
+ //
1933
+ if (code >= 400) {
1934
+ const feedback = this.id + ' ' + this.json (response);
1935
+ const message = this.safeString (response, 'error');
1936
+ const exact = this.exceptions['exact'];
1937
+ if (message in exact) {
1938
+ throw new exact[message] (feedback);
1939
+ }
1940
+ const broad = this.exceptions['broad'];
1941
+ const broadKey = this.findBroadlyMatchedKey (broad, body);
1942
+ if (broadKey !== undefined) {
1943
+ throw new broad[broadKey] (feedback);
1944
+ }
1945
+ throw new ExchangeError (feedback); // unknown message
1946
+ }
1947
+ }
1948
+ };