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/phemex.js ADDED
@@ -0,0 +1,2957 @@
1
+ 'use strict';
2
+
3
+ // ----------------------------------------------------------------------------
4
+
5
+ const Exchange = require ('./base/Exchange');
6
+ const { ExchangeError, BadSymbol, AuthenticationError, InsufficientFunds, InvalidOrder, ArgumentsRequired, OrderNotFound, BadRequest, PermissionDenied, AccountSuspended, CancelPending, DDoSProtection, DuplicateOrderId, RateLimitExceeded } = require ('./base/errors');
7
+ const { TICK_SIZE } = require ('./base/functions/number');
8
+ const Precise = require ('./base/Precise');
9
+
10
+ // ----------------------------------------------------------------------------
11
+
12
+ module.exports = class phemex extends Exchange {
13
+ describe () {
14
+ return this.deepExtend (super.describe (), {
15
+ 'id': 'phemex',
16
+ 'name': 'Phemex',
17
+ 'countries': [ 'CN' ], // China
18
+ 'rateLimit': 100,
19
+ 'version': 'v1',
20
+ 'certified': false,
21
+ 'pro': true,
22
+ 'hostname': 'api.phemex.com',
23
+ 'has': {
24
+ 'CORS': undefined,
25
+ 'spot': true,
26
+ 'margin': false,
27
+ 'swap': undefined, // has but not fully implemented
28
+ 'future': false,
29
+ 'option': false,
30
+ 'cancelAllOrders': true,
31
+ 'cancelOrder': true,
32
+ 'createOrder': true,
33
+ 'createStopLimitOrder': true,
34
+ 'createStopMarketOrder': true,
35
+ 'createStopOrder': true,
36
+ 'editOrder': true,
37
+ 'fetchBalance': true,
38
+ 'fetchBorrowRate': false,
39
+ 'fetchBorrowRateHistories': false,
40
+ 'fetchBorrowRateHistory': false,
41
+ 'fetchBorrowRates': false,
42
+ 'fetchBorrowRatesPerSymbol': false,
43
+ 'fetchClosedOrders': true,
44
+ 'fetchCurrencies': true,
45
+ 'fetchDepositAddress': true,
46
+ 'fetchDeposits': true,
47
+ 'fetchIndexOHLCV': false,
48
+ 'fetchLeverageTiers': false,
49
+ 'fetchMarkets': true,
50
+ 'fetchMarkOHLCV': false,
51
+ 'fetchMyTrades': true,
52
+ 'fetchOHLCV': true,
53
+ 'fetchOpenOrders': true,
54
+ 'fetchOrder': true,
55
+ 'fetchOrderBook': true,
56
+ 'fetchOrders': true,
57
+ 'fetchPositions': true,
58
+ 'fetchPremiumIndexOHLCV': false,
59
+ 'fetchTicker': true,
60
+ 'fetchTrades': true,
61
+ 'fetchTradingFee': false,
62
+ 'fetchTradingFees': false,
63
+ 'fetchWithdrawals': true,
64
+ 'setLeverage': true,
65
+ 'transfer': true,
66
+ 'withdraw': undefined,
67
+ },
68
+ 'urls': {
69
+ 'logo': 'https://user-images.githubusercontent.com/1294454/85225056-221eb600-b3d7-11ea-930d-564d2690e3f6.jpg',
70
+ 'test': {
71
+ 'v1': 'https://testnet-api.phemex.com/v1',
72
+ 'public': 'https://testnet-api.phemex.com/exchange/public',
73
+ 'private': 'https://testnet-api.phemex.com',
74
+ },
75
+ 'api': {
76
+ 'v1': 'https://{hostname}/v1',
77
+ 'public': 'https://{hostname}/exchange/public',
78
+ 'private': 'https://{hostname}',
79
+ },
80
+ 'www': 'https://phemex.com',
81
+ 'doc': 'https://github.com/phemex/phemex-api-docs',
82
+ 'fees': 'https://phemex.com/fees-conditions',
83
+ 'referral': {
84
+ 'url': 'https://phemex.com/register?referralCode=EDNVJ',
85
+ 'discount': 0.1,
86
+ },
87
+ },
88
+ 'timeframes': {
89
+ '1m': '60',
90
+ '3m': '180',
91
+ '5m': '300',
92
+ '15m': '900',
93
+ '30m': '1800',
94
+ '1h': '3600',
95
+ '2h': '7200',
96
+ '3h': '10800',
97
+ '4h': '14400',
98
+ '6h': '21600',
99
+ '12h': '43200',
100
+ '1d': '86400',
101
+ '1w': '604800',
102
+ '1M': '2592000',
103
+ },
104
+ 'api': {
105
+ 'public': {
106
+ 'get': [
107
+ 'cfg/v2/products', // spot + contracts
108
+ 'cfg/fundingRates',
109
+ 'products', // contracts only
110
+ 'nomics/trades', // ?market=<symbol>&since=<since>
111
+ 'md/kline', // ?from=1589811875&resolution=1800&symbol=sBTCUSDT&to=1592457935
112
+ ],
113
+ },
114
+ 'v1': {
115
+ 'get': [
116
+ 'md/orderbook', // ?symbol=<symbol>&id=<id>
117
+ 'md/trade', // ?symbol=<symbol>&id=<id>
118
+ 'md/ticker/24hr', // ?symbol=<symbol>&id=<id>
119
+ 'md/ticker/24hr/all', // ?id=<id>
120
+ 'md/spot/ticker/24hr', // ?symbol=<symbol>&id=<id>
121
+ 'md/spot/ticker/24hr/all', // ?symbol=<symbol>&id=<id>
122
+ 'exchange/public/products', // contracts only
123
+ ],
124
+ },
125
+ 'private': {
126
+ 'get': [
127
+ // spot
128
+ 'spot/orders/active', // ?symbol=<symbol>&orderID=<orderID>
129
+ // 'spot/orders/active', // ?symbol=<symbol>&clOrDID=<clOrdID>
130
+ 'spot/orders', // ?symbol=<symbol>
131
+ 'spot/wallets', // ?currency=<currency>
132
+ 'exchange/spot/order', // ?symbol=<symbol>&ordStatus=<ordStatus1,orderStatus2>ordType=<ordType1,orderType2>&start=<start>&end=<end>&limit=<limit>&offset=<offset>
133
+ 'exchange/spot/order/trades', // ?symbol=<symbol>&start=<start>&end=<end>&limit=<limit>&offset=<offset>
134
+ // swap
135
+ 'accounts/accountPositions', // ?currency=<currency>
136
+ 'accounts/positions', // ?currency=<currency>
137
+ 'orders/activeList', // ?symbol=<symbol>
138
+ 'exchange/order/list', // ?symbol=<symbol>&start=<start>&end=<end>&offset=<offset>&limit=<limit>&ordStatus=<ordStatus>&withCount=<withCount>
139
+ 'exchange/order', // ?symbol=<symbol>&orderID=<orderID1,orderID2>
140
+ // 'exchange/order', // ?symbol=<symbol>&clOrdID=<clOrdID1,clOrdID2>
141
+ 'exchange/order/trade', // ?symbol=<symbol>&start=<start>&end=<end>&limit=<limit>&offset=<offset>&withCount=<withCount>
142
+ 'phemex-user/users/children', // ?offset=<offset>&limit=<limit>&withCount=<withCount>
143
+ 'phemex-user/wallets/v2/depositAddress', // ?_t=1592722635531&currency=USDT
144
+ 'phemex-user/wallets/tradeAccountDetail', // ?bizCode=&currency=&end=1642443347321&limit=10&offset=0&side=&start=1&type=4&withCount=true
145
+ 'phemex-user/order/closedPositionList', // ?currency=USD&limit=10&offset=0&symbol=&withCount=true
146
+ 'exchange/margins/transfer', // ?start=<start>&end=<end>&offset=<offset>&limit=<limit>&withCount=<withCount>
147
+ 'exchange/wallets/confirm/withdraw', // ?code=<withdrawConfirmCode>
148
+ 'exchange/wallets/withdrawList', // ?currency=<currency>&limit=<limit>&offset=<offset>&withCount=<withCount>
149
+ 'exchange/wallets/depositList', // ?currency=<currency>&offset=<offset>&limit=<limit>
150
+ 'exchange/wallets/v2/depositAddress', // ?currency=<currency>
151
+ 'api-data/spots/funds', // ?currency=<currency>&start=<start>&end=<end>&limit=<limit>&offset=<offset>
152
+ 'assets/convert', // ?startTime=<startTime>&endTime=<endTime>&limit=<limit>&offset=<offset>
153
+ // transfer
154
+ 'assets/transfer', // ?currency=<currency>&start=<start>&end=<end>&limit=<limit>&offset=<offset>
155
+ 'assets/spots/sub-accounts/transfer', // ?currency=<currency>&start=<start>&end=<end>&limit=<limit>&offset=<offset>
156
+ 'assets/futures/sub-accounts/transfer', // ?currency=<currency>&start=<start>&end=<end>&limit=<limit>&offset=<offset>
157
+ 'assets/quote', // ?fromCurrency=<currency>&toCurrency=<currency>&amountEv=<amount>
158
+ 'assets/convert', // ?fromCurrency=<currency>&toCurrency=<currency>&startTime=<start>&endTime=<end>&limit=<limit>&offset=<offset>
159
+ ],
160
+ 'post': [
161
+ // spot
162
+ 'spot/orders',
163
+ // swap
164
+ 'orders',
165
+ 'positions/assign', // ?symbol=<symbol>&posBalance=<posBalance>&posBalanceEv=<posBalanceEv>
166
+ 'exchange/wallets/transferOut',
167
+ 'exchange/wallets/transferIn',
168
+ 'exchange/margins',
169
+ 'exchange/wallets/createWithdraw', // ?otpCode=<otpCode>
170
+ 'exchange/wallets/cancelWithdraw',
171
+ 'exchange/wallets/createWithdrawAddress', // ?otpCode={optCode}
172
+ // transfer
173
+ 'assets/transfer',
174
+ 'assets/spots/sub-accounts/transfer', // for sub-account only
175
+ 'assets/futures/sub-accounts/transfer', // for sub-account only
176
+ 'assets/universal-transfer', // for Main account only
177
+ 'assets/convert',
178
+ ],
179
+ 'put': [
180
+ // spot
181
+ 'spot/orders', // ?symbol=<symbol>&orderID=<orderID>&origClOrdID=<origClOrdID>&clOrdID=<clOrdID>&priceEp=<priceEp>&baseQtyEV=<baseQtyEV>&quoteQtyEv=<quoteQtyEv>&stopPxEp=<stopPxEp>
182
+ // swap
183
+ 'orders/replace', // ?symbol=<symbol>&orderID=<orderID>&origClOrdID=<origClOrdID>&clOrdID=<clOrdID>&price=<price>&priceEp=<priceEp>&orderQty=<orderQty>&stopPx=<stopPx>&stopPxEp=<stopPxEp>&takeProfit=<takeProfit>&takeProfitEp=<takeProfitEp>&stopLoss=<stopLoss>&stopLossEp=<stopLossEp>&pegOffsetValueEp=<pegOffsetValueEp>&pegPriceType=<pegPriceType>
184
+ 'positions/leverage', // ?symbol=<symbol>&leverage=<leverage>&leverageEr=<leverageEr>
185
+ 'positions/riskLimit', // ?symbol=<symbol>&riskLimit=<riskLimit>&riskLimitEv=<riskLimitEv>
186
+ ],
187
+ 'delete': [
188
+ // spot
189
+ 'spot/orders', // ?symbol=<symbol>&orderID=<orderID>
190
+ 'spot/orders/all', // ?symbol=<symbol>&untriggered=<untriggered>
191
+ // 'spot/orders', // ?symbol=<symbol>&clOrdID=<clOrdID>
192
+ // swap
193
+ 'orders/cancel', // ?symbol=<symbol>&orderID=<orderID>
194
+ 'orders', // ?symbol=<symbol>&orderID=<orderID1>,<orderID2>,<orderID3>
195
+ 'orders/all', // ?symbol=<symbol>&untriggered=<untriggered>&text=<text>
196
+ ],
197
+ },
198
+ },
199
+ 'precisionMode': TICK_SIZE,
200
+ 'fees': {
201
+ 'trading': {
202
+ 'tierBased': false,
203
+ 'percentage': true,
204
+ 'taker': this.parseNumber ('0.001'),
205
+ 'maker': this.parseNumber ('0.001'),
206
+ },
207
+ },
208
+ 'requiredCredentials': {
209
+ 'apiKey': true,
210
+ 'secret': true,
211
+ },
212
+ 'exceptions': {
213
+ 'exact': {
214
+ // not documented
215
+ '412': BadRequest, // {"code":412,"msg":"Missing parameter - resolution","data":null}
216
+ '6001': BadRequest, // {"error":{"code":6001,"message":"invalid argument"},"id":null,"result":null}
217
+ // documented
218
+ '19999': BadRequest, // REQUEST_IS_DUPLICATED Duplicated request ID
219
+ '10001': DuplicateOrderId, // OM_DUPLICATE_ORDERID Duplicated order ID
220
+ '10002': OrderNotFound, // OM_ORDER_NOT_FOUND Cannot find order ID
221
+ '10003': CancelPending, // OM_ORDER_PENDING_CANCEL Cannot cancel while order is already in pending cancel status
222
+ '10004': CancelPending, // OM_ORDER_PENDING_REPLACE Cannot cancel while order is already in pending cancel status
223
+ '10005': CancelPending, // OM_ORDER_PENDING Cannot cancel while order is already in pending cancel status
224
+ '11001': InsufficientFunds, // TE_NO_ENOUGH_AVAILABLE_BALANCE Insufficient available balance
225
+ '11002': InvalidOrder, // TE_INVALID_RISK_LIMIT Invalid risk limit value
226
+ '11003': InsufficientFunds, // TE_NO_ENOUGH_BALANCE_FOR_NEW_RISK_LIMIT Insufficient available balance
227
+ '11004': InvalidOrder, // TE_INVALID_LEVERAGE invalid input or new leverage is over maximum allowed leverage
228
+ '11005': InsufficientFunds, // TE_NO_ENOUGH_BALANCE_FOR_NEW_LEVERAGE Insufficient available balance
229
+ '11006': ExchangeError, // TE_CANNOT_CHANGE_POSITION_MARGIN_WITHOUT_POSITION Position size is zero. Cannot change margin
230
+ '11007': ExchangeError, // TE_CANNOT_CHANGE_POSITION_MARGIN_FOR_CROSS_MARGIN Cannot change margin under CrossMargin
231
+ '11008': ExchangeError, // TE_CANNOT_REMOVE_POSITION_MARGIN_MORE_THAN_ADDED exceeds the maximum removable Margin
232
+ '11009': ExchangeError, // TE_CANNOT_REMOVE_POSITION_MARGIN_DUE_TO_UNREALIZED_PNL exceeds the maximum removable Margin
233
+ '11010': InsufficientFunds, // TE_CANNOT_ADD_POSITION_MARGIN_DUE_TO_NO_ENOUGH_AVAILABLE_BALANCE Insufficient available balance
234
+ '11011': InvalidOrder, // TE_REDUCE_ONLY_ABORT Cannot accept reduce only order
235
+ '11012': InvalidOrder, // TE_REPLACE_TO_INVALID_QTY Order quantity Error
236
+ '11013': InvalidOrder, // TE_CONDITIONAL_NO_POSITION Position size is zero. Cannot determine conditional order's quantity
237
+ '11014': InvalidOrder, // TE_CONDITIONAL_CLOSE_POSITION_WRONG_SIDE Close position conditional order has the same side
238
+ '11015': InvalidOrder, // TE_CONDITIONAL_TRIGGERED_OR_CANCELED
239
+ '11016': BadRequest, // TE_ADL_NOT_TRADING_REQUESTED_ACCOUNT Request is routed to the wrong trading engine
240
+ '11017': ExchangeError, // TE_ADL_CANNOT_FIND_POSITION Cannot find requested position on current account
241
+ '11018': ExchangeError, // TE_NO_NEED_TO_SETTLE_FUNDING The current account does not need to pay a funding fee
242
+ '11019': ExchangeError, // TE_FUNDING_ALREADY_SETTLED The current account already pays the funding fee
243
+ '11020': ExchangeError, // TE_CANNOT_TRANSFER_OUT_DUE_TO_BONUS Withdraw to wallet needs to remove all remaining bonus. However if bonus is used by position or order cost, withdraw fails.
244
+ '11021': ExchangeError, // TE_INVALID_BONOUS_AMOUNT // Grpc command cannot be negative number Invalid bonus amount
245
+ '11022': AccountSuspended, // TE_REJECT_DUE_TO_BANNED Account is banned
246
+ '11023': ExchangeError, // TE_REJECT_DUE_TO_IN_PROCESS_OF_LIQ Account is in the process of liquidation
247
+ '11024': ExchangeError, // TE_REJECT_DUE_TO_IN_PROCESS_OF_ADL Account is in the process of auto-deleverage
248
+ '11025': BadRequest, // TE_ROUTE_ERROR Request is routed to the wrong trading engine
249
+ '11026': ExchangeError, // TE_UID_ACCOUNT_MISMATCH
250
+ '11027': BadSymbol, // TE_SYMBOL_INVALID Invalid number ID or name
251
+ '11028': BadSymbol, // TE_CURRENCY_INVALID Invalid currency ID or name
252
+ '11029': ExchangeError, // TE_ACTION_INVALID Unrecognized request type
253
+ '11030': ExchangeError, // TE_ACTION_BY_INVALID
254
+ '11031': DDoSProtection, // TE_SO_NUM_EXCEEDS Number of total conditional orders exceeds the max limit
255
+ '11032': DDoSProtection, // TE_AO_NUM_EXCEEDS Number of total active orders exceeds the max limit
256
+ '11033': DuplicateOrderId, // TE_ORDER_ID_DUPLICATE Duplicated order ID
257
+ '11034': InvalidOrder, // TE_SIDE_INVALID Invalid side
258
+ '11035': InvalidOrder, // TE_ORD_TYPE_INVALID Invalid OrderType
259
+ '11036': InvalidOrder, // TE_TIME_IN_FORCE_INVALID Invalid TimeInForce
260
+ '11037': InvalidOrder, // TE_EXEC_INST_INVALID Invalid ExecType
261
+ '11038': InvalidOrder, // TE_TRIGGER_INVALID Invalid trigger type
262
+ '11039': InvalidOrder, // TE_STOP_DIRECTION_INVALID Invalid stop direction type
263
+ '11040': InvalidOrder, // TE_NO_MARK_PRICE Cannot get valid mark price to create conditional order
264
+ '11041': InvalidOrder, // TE_NO_INDEX_PRICE Cannot get valid index price to create conditional order
265
+ '11042': InvalidOrder, // TE_NO_LAST_PRICE Cannot get valid last market price to create conditional order
266
+ '11043': InvalidOrder, // TE_RISING_TRIGGER_DIRECTLY Conditional order would be triggered immediately
267
+ '11044': InvalidOrder, // TE_FALLING_TRIGGER_DIRECTLY Conditional order would be triggered immediately
268
+ '11045': InvalidOrder, // TE_TRIGGER_PRICE_TOO_LARGE Conditional order trigger price is too high
269
+ '11046': InvalidOrder, // TE_TRIGGER_PRICE_TOO_SMALL Conditional order trigger price is too low
270
+ '11047': InvalidOrder, // TE_BUY_TP_SHOULD_GT_BASE TakeProfile BUY conditional order trigger price needs to be greater than reference price
271
+ '11048': InvalidOrder, // TE_BUY_SL_SHOULD_LT_BASE StopLoss BUY condition order price needs to be less than the reference price
272
+ '11049': InvalidOrder, // TE_BUY_SL_SHOULD_GT_LIQ StopLoss BUY condition order price needs to be greater than liquidation price or it will not trigger
273
+ '11050': InvalidOrder, // TE_SELL_TP_SHOULD_LT_BASE TakeProfile SELL conditional order trigger price needs to be less than reference price
274
+ '11051': InvalidOrder, // TE_SELL_SL_SHOULD_LT_LIQ StopLoss SELL condition order price needs to be less than liquidation price or it will not trigger
275
+ '11052': InvalidOrder, // TE_SELL_SL_SHOULD_GT_BASE StopLoss SELL condition order price needs to be greater than the reference price
276
+ '11053': InvalidOrder, // TE_PRICE_TOO_LARGE
277
+ '11054': InvalidOrder, // TE_PRICE_WORSE_THAN_BANKRUPT Order price cannot be more aggressive than bankrupt price if this order has instruction to close a position
278
+ '11055': InvalidOrder, // TE_PRICE_TOO_SMALL Order price is too low
279
+ '11056': InvalidOrder, // TE_QTY_TOO_LARGE Order quantity is too large
280
+ '11057': InvalidOrder, // TE_QTY_NOT_MATCH_REDUCE_ONLY Does not allow ReduceOnly order without position
281
+ '11058': InvalidOrder, // TE_QTY_TOO_SMALL Order quantity is too small
282
+ '11059': InvalidOrder, // TE_TP_SL_QTY_NOT_MATCH_POS Position size is zero. Cannot accept any TakeProfit or StopLoss order
283
+ '11060': InvalidOrder, // TE_SIDE_NOT_CLOSE_POS TakeProfit or StopLoss order has wrong side. Cannot close position
284
+ '11061': CancelPending, // TE_ORD_ALREADY_PENDING_CANCEL Repeated cancel request
285
+ '11062': InvalidOrder, // TE_ORD_ALREADY_CANCELED Order is already canceled
286
+ '11063': InvalidOrder, // TE_ORD_STATUS_CANNOT_CANCEL Order is not able to be canceled under current status
287
+ '11064': InvalidOrder, // TE_ORD_ALREADY_PENDING_REPLACE Replace request is rejected because order is already in pending replace status
288
+ '11065': InvalidOrder, // TE_ORD_REPLACE_NOT_MODIFIED Replace request does not modify any parameters of the order
289
+ '11066': InvalidOrder, // TE_ORD_STATUS_CANNOT_REPLACE Order is not able to be replaced under current status
290
+ '11067': InvalidOrder, // TE_CANNOT_REPLACE_PRICE Market conditional order cannot change price
291
+ '11068': InvalidOrder, // TE_CANNOT_REPLACE_QTY Condtional order for closing position cannot change order quantity, since the order quantity is determined by position size already
292
+ '11069': ExchangeError, // TE_ACCOUNT_NOT_IN_RANGE The account ID in the request is not valid or is not in the range of the current process
293
+ '11070': BadSymbol, // TE_SYMBOL_NOT_IN_RANGE The symbol is invalid
294
+ '11071': InvalidOrder, // TE_ORD_STATUS_CANNOT_TRIGGER
295
+ '11072': InvalidOrder, // TE_TKFR_NOT_IN_RANGE The fee value is not valid
296
+ '11073': InvalidOrder, // TE_MKFR_NOT_IN_RANGE The fee value is not valid
297
+ '11074': InvalidOrder, // TE_CANNOT_ATTACH_TP_SL Order request cannot contain TP/SL parameters when the account already has positions
298
+ '11075': InvalidOrder, // TE_TP_TOO_LARGE TakeProfit price is too large
299
+ '11076': InvalidOrder, // TE_TP_TOO_SMALL TakeProfit price is too small
300
+ '11077': InvalidOrder, // TE_TP_TRIGGER_INVALID Invalid trigger type
301
+ '11078': InvalidOrder, // TE_SL_TOO_LARGE StopLoss price is too large
302
+ '11079': InvalidOrder, // TE_SL_TOO_SMALL StopLoss price is too small
303
+ '11080': InvalidOrder, // TE_SL_TRIGGER_INVALID Invalid trigger type
304
+ '11081': InvalidOrder, // TE_RISK_LIMIT_EXCEEDS Total potential position breaches current risk limit
305
+ '11082': InsufficientFunds, // TE_CANNOT_COVER_ESTIMATE_ORDER_LOSS The remaining balance cannot cover the potential unrealized PnL for this new order
306
+ '11083': InvalidOrder, // TE_TAKE_PROFIT_ORDER_DUPLICATED TakeProfit order already exists
307
+ '11084': InvalidOrder, // TE_STOP_LOSS_ORDER_DUPLICATED StopLoss order already exists
308
+ '11085': DuplicateOrderId, // TE_CL_ORD_ID_DUPLICATE ClOrdId is duplicated
309
+ '11086': InvalidOrder, // TE_PEG_PRICE_TYPE_INVALID PegPriceType is invalid
310
+ '11087': InvalidOrder, // TE_BUY_TS_SHOULD_LT_BASE The trailing order's StopPrice should be less than the current last price
311
+ '11088': InvalidOrder, // TE_BUY_TS_SHOULD_GT_LIQ The traling order's StopPrice should be greater than the current liquidation price
312
+ '11089': InvalidOrder, // TE_SELL_TS_SHOULD_LT_LIQ The traling order's StopPrice should be greater than the current last price
313
+ '11090': InvalidOrder, // TE_SELL_TS_SHOULD_GT_BASE The traling order's StopPrice should be less than the current liquidation price
314
+ '11091': InvalidOrder, // TE_BUY_REVERT_VALUE_SHOULD_LT_ZERO The PegOffset should be less than zero
315
+ '11092': InvalidOrder, // TE_SELL_REVERT_VALUE_SHOULD_GT_ZERO The PegOffset should be greater than zero
316
+ '11093': InvalidOrder, // TE_BUY_TTP_SHOULD_ACTIVATE_ABOVE_BASE The activation price should be greater than the current last price
317
+ '11094': InvalidOrder, // TE_SELL_TTP_SHOULD_ACTIVATE_BELOW_BASE The activation price should be less than the current last price
318
+ '11095': InvalidOrder, // TE_TRAILING_ORDER_DUPLICATED A trailing order exists already
319
+ '11096': InvalidOrder, // TE_CLOSE_ORDER_CANNOT_ATTACH_TP_SL An order to close position cannot have trailing instruction
320
+ '11097': BadRequest, // TE_CANNOT_FIND_WALLET_OF_THIS_CURRENCY This crypto is not supported
321
+ '11098': BadRequest, // TE_WALLET_INVALID_ACTION Invalid action on wallet
322
+ '11099': ExchangeError, // TE_WALLET_VID_UNMATCHED Wallet operation request has a wrong wallet vid
323
+ '11100': InsufficientFunds, // TE_WALLET_INSUFFICIENT_BALANCE Wallet has insufficient balance
324
+ '11101': InsufficientFunds, // TE_WALLET_INSUFFICIENT_LOCKED_BALANCE Locked balance in wallet is not enough for unlock/withdraw request
325
+ '11102': BadRequest, // TE_WALLET_INVALID_DEPOSIT_AMOUNT Deposit amount must be greater than zero
326
+ '11103': BadRequest, // TE_WALLET_INVALID_WITHDRAW_AMOUNT Withdraw amount must be less than zero
327
+ '11104': BadRequest, // TE_WALLET_REACHED_MAX_AMOUNT Deposit makes wallet exceed max amount allowed
328
+ '11105': InsufficientFunds, // TE_PLACE_ORDER_INSUFFICIENT_BASE_BALANCE Insufficient funds in base wallet
329
+ '11106': InsufficientFunds, // TE_PLACE_ORDER_INSUFFICIENT_QUOTE_BALANCE Insufficient funds in quote wallet
330
+ '11107': ExchangeError, // TE_CANNOT_CONNECT_TO_REQUEST_SEQ TradingEngine failed to connect with CrossEngine
331
+ '11108': InvalidOrder, // TE_CANNOT_REPLACE_OR_CANCEL_MARKET_ORDER Cannot replace/amend market order
332
+ '11109': InvalidOrder, // TE_CANNOT_REPLACE_OR_CANCEL_IOC_ORDER Cannot replace/amend ImmediateOrCancel order
333
+ '11110': InvalidOrder, // TE_CANNOT_REPLACE_OR_CANCEL_FOK_ORDER Cannot replace/amend FillOrKill order
334
+ '11111': InvalidOrder, // TE_MISSING_ORDER_ID OrderId is missing
335
+ '11112': InvalidOrder, // TE_QTY_TYPE_INVALID QtyType is invalid
336
+ '11113': BadRequest, // TE_USER_ID_INVALID UserId is invalid
337
+ '11114': InvalidOrder, // TE_ORDER_VALUE_TOO_LARGE Order value is too large
338
+ '11115': InvalidOrder, // TE_ORDER_VALUE_TOO_SMALL Order value is too small
339
+ '11116': InvalidOrder, // TE_BO_NUM_EXCEEDS Details: the total count of brakcet orders should equal or less than 5
340
+ '11117': InvalidOrder, // TE_BO_CANNOT_HAVE_BO_WITH_DIFF_SIDE Details: all bracket orders should have the same Side.
341
+ '11118': InvalidOrder, // TE_BO_TP_PRICE_INVALID Details: bracker order take profit price is invalid
342
+ '11119': InvalidOrder, // TE_BO_SL_PRICE_INVALID Details: bracker order stop loss price is invalid
343
+ '11120': InvalidOrder, // TE_BO_SL_TRIGGER_PRICE_INVALID Details: bracker order stop loss trigger price is invalid
344
+ '11121': InvalidOrder, // TE_BO_CANNOT_REPLACE Details: cannot replace bracket order.
345
+ '11122': InvalidOrder, // TE_BO_BOTP_STATUS_INVALID Details: bracket take profit order status is invalid
346
+ '11123': InvalidOrder, // TE_BO_CANNOT_PLACE_BOTP_OR_BOSL_ORDER Details: cannot place bracket take profit order
347
+ '11124': InvalidOrder, // TE_BO_CANNOT_REPLACE_BOTP_OR_BOSL_ORDER Details: cannot place bracket stop loss order
348
+ '11125': InvalidOrder, // TE_BO_CANNOT_CANCEL_BOTP_OR_BOSL_ORDER Details: cannot cancel bracket sl/tp order
349
+ '11126': InvalidOrder, // TE_BO_DONOT_SUPPORT_API Details: doesn't support bracket order via API
350
+ '11128': InvalidOrder, // TE_BO_INVALID_EXECINST Details: ExecInst value is invalid
351
+ '11129': InvalidOrder, // TE_BO_MUST_BE_SAME_SIDE_AS_POS Details: bracket order should have the same side as position's side
352
+ '11130': InvalidOrder, // TE_BO_WRONG_SL_TRIGGER_TYPE Details: bracket stop loss order trigger type is invalid
353
+ '11131': InvalidOrder, // TE_BO_WRONG_TP_TRIGGER_TYPE Details: bracket take profit order trigger type is invalid
354
+ '11132': InvalidOrder, // TE_BO_ABORT_BOSL_DUE_BOTP_CREATE_FAILED Details: cancel bracket stop loss order due failed to create take profit order.
355
+ '11133': InvalidOrder, // TE_BO_ABORT_BOSL_DUE_BOPO_CANCELED Details: cancel bracket stop loss order due main order canceled.
356
+ '11134': InvalidOrder, // TE_BO_ABORT_BOTP_DUE_BOPO_CANCELED Details: cancel bracket take profit order due main order canceled.
357
+ // not documented
358
+ '30000': BadRequest, // {"code":30000,"msg":"Please double check input arguments","data":null}
359
+ '30018': BadRequest, // {"code":30018,"msg":"phemex.data.size.uplimt","data":null}
360
+ '34003': PermissionDenied, // {"code":34003,"msg":"Access forbidden","data":null}
361
+ '35104': InsufficientFunds, // {"code":35104,"msg":"phemex.spot.wallet.balance.notenough","data":null}
362
+ '39995': RateLimitExceeded, // {"code": "39995","msg": "Too many requests."}
363
+ '39996': PermissionDenied, // {"code": "39996","msg": "Access denied."}
364
+ },
365
+ 'broad': {
366
+ '401 Insufficient privilege': PermissionDenied, // {"code": "401","msg": "401 Insufficient privilege."}
367
+ '401 Request IP mismatch': PermissionDenied, // {"code": "401","msg": "401 Request IP mismatch."}
368
+ 'Failed to find api-key': AuthenticationError, // {"msg":"Failed to find api-key 1c5ec63fd-660d-43ea-847a-0d3ba69e106e","code":10500}
369
+ 'Missing required parameter': BadRequest, // {"msg":"Missing required parameter","code":10500}
370
+ 'API Signature verification failed': AuthenticationError, // {"msg":"API Signature verification failed.","code":10500}
371
+ 'Api key not found': AuthenticationError, // {"msg":"Api key not found 698dc9e3-6faa-4910-9476-12857e79e198","code":"10500"}
372
+ },
373
+ },
374
+ 'options': {
375
+ 'x-phemex-request-expiry': 60, // in seconds
376
+ 'createOrderByQuoteRequiresPrice': true,
377
+ 'networks': {
378
+ 'TRC20': 'TRX',
379
+ 'ERC20': 'ETH',
380
+ },
381
+ 'defaultNetworks': {
382
+ 'USDT': 'ETH',
383
+ },
384
+ 'defaultSubType': 'linear',
385
+ 'accountsByType': {
386
+ 'spot': 'spot',
387
+ 'future': 'future',
388
+ },
389
+ 'transfer': {
390
+ 'fillResponseFromRequest': true,
391
+ },
392
+ },
393
+ });
394
+ }
395
+
396
+ parseSafeNumber (value = undefined) {
397
+ if (value === undefined) {
398
+ return value;
399
+ }
400
+ let parts = value.split (',');
401
+ value = parts.join ('');
402
+ parts = value.split (' ');
403
+ return this.safeNumber (parts, 0);
404
+ }
405
+
406
+ parseSwapMarket (market) {
407
+ //
408
+ // {
409
+ // "symbol":"BTCUSD",
410
+ // "displaySymbol":"BTC / USD",
411
+ // "indexSymbol":".BTC",
412
+ // "markSymbol":".MBTC",
413
+ // "fundingRateSymbol":".BTCFR",
414
+ // "fundingRate8hSymbol":".BTCFR8H",
415
+ // "contractUnderlyingAssets":"USD",
416
+ // "settleCurrency":"BTC",
417
+ // "quoteCurrency":"USD",
418
+ // "contractSize":"1 USD",
419
+ // "lotSize":1,
420
+ // "tickSize":0.5,
421
+ // "priceScale":4,
422
+ // "ratioScale":8,
423
+ // "pricePrecision":1,
424
+ // "minPriceEp":5000,
425
+ // "maxPriceEp":10000000000,
426
+ // "maxOrderQty":1000000,
427
+ // "type":"Perpetual",
428
+ // "status":"Listed",
429
+ // "tipOrderQty":1000000,
430
+ // "steps":"50",
431
+ // "riskLimits":[
432
+ // {"limit":100,"initialMargin":"1.0%","initialMarginEr":1000000,"maintenanceMargin":"0.5%","maintenanceMarginEr":500000},
433
+ // {"limit":150,"initialMargin":"1.5%","initialMarginEr":1500000,"maintenanceMargin":"1.0%","maintenanceMarginEr":1000000},
434
+ // {"limit":200,"initialMargin":"2.0%","initialMarginEr":2000000,"maintenanceMargin":"1.5%","maintenanceMarginEr":1500000},
435
+ // ],
436
+ // "underlyingSymbol":".BTC",
437
+ // "baseCurrency":"BTC",
438
+ // "settlementCurrency":"BTC",
439
+ // "valueScale":8,
440
+ // "defaultLeverage":0,
441
+ // "maxLeverage":100,
442
+ // "initMarginEr":"1000000",
443
+ // "maintMarginEr":"500000",
444
+ // "defaultRiskLimitEv":10000000000,
445
+ // "deleverage":true,
446
+ // "makerFeeRateEr":-250000,
447
+ // "takerFeeRateEr":750000,
448
+ // "fundingInterval":8,
449
+ // "marketUrl":"https://phemex.com/trade/BTCUSD",
450
+ // "description":"BTCUSD is a BTC/USD perpetual contract priced on the .BTC Index. Each contract is worth 1 USD of Bitcoin. Funding is paid and received every 8 hours. At UTC time: 00:00, 08:00, 16:00.",
451
+ // }
452
+ //
453
+ const id = this.safeString (market, 'symbol');
454
+ const baseId = this.safeString2 (market, 'baseCurrency', 'contractUnderlyingAssets');
455
+ const quoteId = this.safeString (market, 'quoteCurrency');
456
+ const settleId = this.safeString (market, 'settleCurrency');
457
+ const base = this.safeCurrencyCode (baseId);
458
+ const quote = this.safeCurrencyCode (quoteId);
459
+ const settle = this.safeCurrencyCode (settleId);
460
+ let inverse = false;
461
+ if (settleId !== quoteId) {
462
+ inverse = true;
463
+ }
464
+ const priceScale = this.safeInteger (market, 'priceScale');
465
+ const ratioScale = this.safeInteger (market, 'ratioScale');
466
+ const valueScale = this.safeInteger (market, 'valueScale');
467
+ const minPriceEp = this.safeString (market, 'minPriceEp');
468
+ const maxPriceEp = this.safeString (market, 'maxPriceEp');
469
+ const makerFeeRateEr = this.safeString (market, 'makerFeeRateEr');
470
+ const takerFeeRateEr = this.safeString (market, 'takerFeeRateEr');
471
+ const status = this.safeString (market, 'status');
472
+ const contractSizeString = this.safeString (market, 'contractSize', ' ');
473
+ let contractSize = undefined;
474
+ if (contractSizeString.indexOf (' ')) {
475
+ // "1 USD"
476
+ // "0.005 ETH"
477
+ const parts = contractSizeString.split (' ');
478
+ contractSize = this.parseNumber (parts[0]);
479
+ } else {
480
+ // "1.0"
481
+ contractSize = this.parseNumber (contractSizeString);
482
+ }
483
+ return {
484
+ 'id': id,
485
+ 'symbol': base + '/' + quote + ':' + settle,
486
+ 'base': base,
487
+ 'quote': quote,
488
+ 'settle': settle,
489
+ 'baseId': baseId,
490
+ 'quoteId': quoteId,
491
+ 'settleId': settleId,
492
+ 'type': 'swap',
493
+ 'spot': false,
494
+ 'margin': false,
495
+ 'swap': true,
496
+ 'future': false,
497
+ 'option': false,
498
+ 'active': status === 'Listed',
499
+ 'contract': true,
500
+ 'linear': !inverse,
501
+ 'inverse': inverse,
502
+ 'taker': this.parseNumber (this.fromEn (takerFeeRateEr, ratioScale)),
503
+ 'maker': this.parseNumber (this.fromEn (makerFeeRateEr, ratioScale)),
504
+ 'contractSize': contractSize,
505
+ 'expiry': undefined,
506
+ 'expiryDatetime': undefined,
507
+ 'strike': undefined,
508
+ 'optionType': undefined,
509
+ 'priceScale': priceScale,
510
+ 'valueScale': valueScale,
511
+ 'ratioScale': ratioScale,
512
+ 'precision': {
513
+ 'amount': this.safeNumber (market, 'lotSize'),
514
+ 'price': this.safeNumber (market, 'tickSize'),
515
+ },
516
+ 'limits': {
517
+ 'leverage': {
518
+ 'min': this.parseNumber ('1'),
519
+ 'max': this.safeNumber (market, 'maxLeverage'),
520
+ },
521
+ 'amount': {
522
+ 'min': undefined,
523
+ 'max': undefined,
524
+ },
525
+ 'price': {
526
+ 'min': this.parseNumber (this.fromEn (minPriceEp, priceScale)),
527
+ 'max': this.parseNumber (this.fromEn (maxPriceEp, priceScale)),
528
+ },
529
+ 'cost': {
530
+ 'min': undefined,
531
+ 'max': this.parseNumber (this.safeString (market, 'maxOrderQty')),
532
+ },
533
+ },
534
+ 'info': market,
535
+ };
536
+ }
537
+
538
+ parseSpotMarket (market) {
539
+ //
540
+ // {
541
+ // "symbol":"sBTCUSDT",
542
+ // "displaySymbol":"BTC / USDT",
543
+ // "quoteCurrency":"USDT",
544
+ // "pricePrecision":2,
545
+ // "type":"Spot",
546
+ // "baseCurrency":"BTC",
547
+ // "baseTickSize":"0.000001 BTC",
548
+ // "baseTickSizeEv":100,
549
+ // "quoteTickSize":"0.01 USDT",
550
+ // "quoteTickSizeEv":1000000,
551
+ // "minOrderValue":"10 USDT",
552
+ // "minOrderValueEv":1000000000,
553
+ // "maxBaseOrderSize":"1000 BTC",
554
+ // "maxBaseOrderSizeEv":100000000000,
555
+ // "maxOrderValue":"5,000,000 USDT",
556
+ // "maxOrderValueEv":500000000000000,
557
+ // "defaultTakerFee":"0.001",
558
+ // "defaultTakerFeeEr":100000,
559
+ // "defaultMakerFee":"0.001",
560
+ // "defaultMakerFeeEr":100000,
561
+ // "baseQtyPrecision":6,
562
+ // "quoteQtyPrecision":2,
563
+ // "status":"Listed",
564
+ // "tipOrderQty":20
565
+ // }
566
+ //
567
+ const type = this.safeStringLower (market, 'type');
568
+ const id = this.safeString (market, 'symbol');
569
+ const quoteId = this.safeString (market, 'quoteCurrency');
570
+ const baseId = this.safeString (market, 'baseCurrency');
571
+ const base = this.safeCurrencyCode (baseId);
572
+ const quote = this.safeCurrencyCode (quoteId);
573
+ const status = this.safeString (market, 'status');
574
+ const precisionAmount = this.parseSafeNumber (this.safeString (market, 'baseTickSize'));
575
+ const precisionPrice = this.parseSafeNumber (this.safeString (market, 'quoteTickSize'));
576
+ return {
577
+ 'id': id,
578
+ 'symbol': base + '/' + quote,
579
+ 'base': base,
580
+ 'quote': quote,
581
+ 'settle': undefined,
582
+ 'baseId': baseId,
583
+ 'quoteId': quoteId,
584
+ 'settleId': undefined,
585
+ 'type': type,
586
+ 'spot': true,
587
+ 'margin': false,
588
+ 'swap': false,
589
+ 'future': false,
590
+ 'option': false,
591
+ 'active': status === 'Listed',
592
+ 'contract': false,
593
+ 'linear': undefined,
594
+ 'inverse': undefined,
595
+ 'taker': this.safeNumber (market, 'defaultTakerFee'),
596
+ 'maker': this.safeNumber (market, 'defaultMakerFee'),
597
+ 'contractSize': undefined,
598
+ 'expiry': undefined,
599
+ 'expiryDatetime': undefined,
600
+ 'strike': undefined,
601
+ 'optionType': undefined,
602
+ 'priceScale': 8,
603
+ 'valueScale': 8,
604
+ 'ratioScale': 8,
605
+ 'precision': {
606
+ 'amount': precisionAmount,
607
+ 'price': precisionPrice,
608
+ },
609
+ 'limits': {
610
+ 'leverage': {
611
+ 'min': undefined,
612
+ 'max': undefined,
613
+ },
614
+ 'amount': {
615
+ 'min': precisionAmount,
616
+ 'max': this.parseSafeNumber (this.safeString (market, 'maxBaseOrderSize')),
617
+ },
618
+ 'price': {
619
+ 'min': precisionPrice,
620
+ 'max': undefined,
621
+ },
622
+ 'cost': {
623
+ 'min': this.parseSafeNumber (this.safeString (market, 'minOrderValue')),
624
+ 'max': this.parseSafeNumber (this.safeString (market, 'maxOrderValue')),
625
+ },
626
+ },
627
+ 'info': market,
628
+ };
629
+ }
630
+
631
+ async fetchMarkets (params = {}) {
632
+ const v2Products = await this.publicGetCfgV2Products (params);
633
+ //
634
+ // {
635
+ // "code":0,
636
+ // "msg":"OK",
637
+ // "data":{
638
+ // "ratioScale":8,
639
+ // "currencies":[
640
+ // {"currency":"BTC","valueScale":8,"minValueEv":1,"maxValueEv":5000000000000000000,"name":"Bitcoin"},
641
+ // {"currency":"USD","valueScale":4,"minValueEv":1,"maxValueEv":500000000000000,"name":"USD"},
642
+ // {"currency":"USDT","valueScale":8,"minValueEv":1,"maxValueEv":5000000000000000000,"name":"TetherUS"},
643
+ // ],
644
+ // "products":[
645
+ // {
646
+ // "symbol":"BTCUSD",
647
+ // "displaySymbol":"BTC / USD",
648
+ // "indexSymbol":".BTC",
649
+ // "markSymbol":".MBTC",
650
+ // "fundingRateSymbol":".BTCFR",
651
+ // "fundingRate8hSymbol":".BTCFR8H",
652
+ // "contractUnderlyingAssets":"USD",
653
+ // "settleCurrency":"BTC",
654
+ // "quoteCurrency":"USD",
655
+ // "contractSize":1.0,
656
+ // "lotSize":1,
657
+ // "tickSize":0.5,
658
+ // "priceScale":4,
659
+ // "ratioScale":8,
660
+ // "pricePrecision":1,
661
+ // "minPriceEp":5000,
662
+ // "maxPriceEp":10000000000,
663
+ // "maxOrderQty":1000000,
664
+ // "type":"Perpetual"
665
+ // },
666
+ // {
667
+ // "symbol":"sBTCUSDT",
668
+ // "displaySymbol":"BTC / USDT",
669
+ // "quoteCurrency":"USDT",
670
+ // "pricePrecision":2,
671
+ // "type":"Spot",
672
+ // "baseCurrency":"BTC",
673
+ // "baseTickSize":"0.000001 BTC",
674
+ // "baseTickSizeEv":100,
675
+ // "quoteTickSize":"0.01 USDT",
676
+ // "quoteTickSizeEv":1000000,
677
+ // "minOrderValue":"10 USDT",
678
+ // "minOrderValueEv":1000000000,
679
+ // "maxBaseOrderSize":"1000 BTC",
680
+ // "maxBaseOrderSizeEv":100000000000,
681
+ // "maxOrderValue":"5,000,000 USDT",
682
+ // "maxOrderValueEv":500000000000000,
683
+ // "defaultTakerFee":"0.001",
684
+ // "defaultTakerFeeEr":100000,
685
+ // "defaultMakerFee":"0.001",
686
+ // "defaultMakerFeeEr":100000,
687
+ // "baseQtyPrecision":6,
688
+ // "quoteQtyPrecision":2
689
+ // },
690
+ // ],
691
+ // "riskLimits":[
692
+ // {
693
+ // "symbol":"BTCUSD",
694
+ // "steps":"50",
695
+ // "riskLimits":[
696
+ // {"limit":100,"initialMargin":"1.0%","initialMarginEr":1000000,"maintenanceMargin":"0.5%","maintenanceMarginEr":500000},
697
+ // {"limit":150,"initialMargin":"1.5%","initialMarginEr":1500000,"maintenanceMargin":"1.0%","maintenanceMarginEr":1000000},
698
+ // {"limit":200,"initialMargin":"2.0%","initialMarginEr":2000000,"maintenanceMargin":"1.5%","maintenanceMarginEr":1500000},
699
+ // ]
700
+ // },
701
+ // ],
702
+ // "leverages":[
703
+ // {"initialMargin":"1.0%","initialMarginEr":1000000,"options":[1,2,3,5,10,25,50,100]},
704
+ // {"initialMargin":"1.5%","initialMarginEr":1500000,"options":[1,2,3,5,10,25,50,66]},
705
+ // {"initialMargin":"2.0%","initialMarginEr":2000000,"options":[1,2,3,5,10,25,33,50]},
706
+ // ]
707
+ // }
708
+ // }
709
+ //
710
+ const v1Products = await this.v1GetExchangePublicProducts (params);
711
+ const v1ProductsData = this.safeValue (v1Products, 'data', []);
712
+ //
713
+ // {
714
+ // "code":0,
715
+ // "msg":"OK",
716
+ // "data":[
717
+ // {
718
+ // "symbol":"BTCUSD",
719
+ // "underlyingSymbol":".BTC",
720
+ // "quoteCurrency":"USD",
721
+ // "baseCurrency":"BTC",
722
+ // "settlementCurrency":"BTC",
723
+ // "maxOrderQty":1000000,
724
+ // "maxPriceEp":100000000000000,
725
+ // "lotSize":1,
726
+ // "tickSize":"0.5",
727
+ // "contractSize":"1 USD",
728
+ // "priceScale":4,
729
+ // "ratioScale":8,
730
+ // "valueScale":8,
731
+ // "defaultLeverage":0,
732
+ // "maxLeverage":100,
733
+ // "initMarginEr":"1000000",
734
+ // "maintMarginEr":"500000",
735
+ // "defaultRiskLimitEv":10000000000,
736
+ // "deleverage":true,
737
+ // "makerFeeRateEr":-250000,
738
+ // "takerFeeRateEr":750000,
739
+ // "fundingInterval":8,
740
+ // "marketUrl":"https://phemex.com/trade/BTCUSD",
741
+ // "description":"BTCUSD is a BTC/USD perpetual contract priced on the .BTC Index. Each contract is worth 1 USD of Bitcoin. Funding is paid and received every 8 hours. At UTC time: 00:00, 08:00, 16:00.",
742
+ // "type":"Perpetual"
743
+ // },
744
+ // ]
745
+ // }
746
+ //
747
+ const v2ProductsData = this.safeValue (v2Products, 'data', {});
748
+ const products = this.safeValue (v2ProductsData, 'products', []);
749
+ const riskLimits = this.safeValue (v2ProductsData, 'riskLimits', []);
750
+ const riskLimitsById = this.indexBy (riskLimits, 'symbol');
751
+ const v1ProductsById = this.indexBy (v1ProductsData, 'symbol');
752
+ const result = [];
753
+ for (let i = 0; i < products.length; i++) {
754
+ let market = products[i];
755
+ const type = this.safeStringLower (market, 'type');
756
+ if (type === 'perpetual') {
757
+ const id = this.safeString (market, 'symbol');
758
+ const riskLimitValues = this.safeValue (riskLimitsById, id, {});
759
+ market = this.extend (market, riskLimitValues);
760
+ const v1ProductsValues = this.safeValue (v1ProductsById, id, {});
761
+ market = this.extend (market, v1ProductsValues);
762
+ market = this.parseSwapMarket (market);
763
+ } else {
764
+ market = this.parseSpotMarket (market);
765
+ }
766
+ result.push (market);
767
+ }
768
+ return result;
769
+ }
770
+
771
+ async fetchCurrencies (params = {}) {
772
+ const response = await this.publicGetCfgV2Products (params);
773
+ //
774
+ // {
775
+ // "code":0,
776
+ // "msg":"OK",
777
+ // "data":{
778
+ // ...,
779
+ // "currencies":[
780
+ // {"currency":"BTC","valueScale":8,"minValueEv":1,"maxValueEv":5000000000000000000,"name":"Bitcoin"},
781
+ // {"currency":"USD","valueScale":4,"minValueEv":1,"maxValueEv":500000000000000,"name":"USD"},
782
+ // {"currency":"USDT","valueScale":8,"minValueEv":1,"maxValueEv":5000000000000000000,"name":"TetherUS"},
783
+ // ],
784
+ // ...
785
+ // }
786
+ // }
787
+ const data = this.safeValue (response, 'data', {});
788
+ const currencies = this.safeValue (data, 'currencies', []);
789
+ const result = {};
790
+ for (let i = 0; i < currencies.length; i++) {
791
+ const currency = currencies[i];
792
+ const id = this.safeString (currency, 'currency');
793
+ const name = this.safeString (currency, 'name');
794
+ const code = this.safeCurrencyCode (id);
795
+ const valueScaleString = this.safeString (currency, 'valueScale');
796
+ const valueScale = parseInt (valueScaleString);
797
+ const minValueEv = this.safeString (currency, 'minValueEv');
798
+ const maxValueEv = this.safeString (currency, 'maxValueEv');
799
+ let minAmount = undefined;
800
+ let maxAmount = undefined;
801
+ let precision = undefined;
802
+ if (valueScale !== undefined) {
803
+ const precisionString = this.parsePrecision (valueScaleString);
804
+ precision = this.parseNumber (precisionString);
805
+ minAmount = this.parseNumber (Precise.stringMul (minValueEv, precisionString));
806
+ maxAmount = this.parseNumber (Precise.stringMul (maxValueEv, precisionString));
807
+ }
808
+ result[code] = {
809
+ 'id': id,
810
+ 'info': currency,
811
+ 'code': code,
812
+ 'name': name,
813
+ 'active': undefined,
814
+ 'deposit': undefined,
815
+ 'withdraw': undefined,
816
+ 'fee': undefined,
817
+ 'precision': precision,
818
+ 'limits': {
819
+ 'amount': {
820
+ 'min': minAmount,
821
+ 'max': maxAmount,
822
+ },
823
+ 'withdraw': {
824
+ 'min': undefined,
825
+ 'max': undefined,
826
+ },
827
+ },
828
+ 'valueScale': valueScale,
829
+ };
830
+ }
831
+ return result;
832
+ }
833
+
834
+ parseBidAsk (bidask, priceKey = 0, amountKey = 1, market = undefined) {
835
+ if (market === undefined) {
836
+ throw new ArgumentsRequired (this.id + ' parseBidAsk() requires a market argument');
837
+ }
838
+ let amount = this.safeString (bidask, amountKey);
839
+ if (market['spot']) {
840
+ amount = this.fromEv (amount, market);
841
+ }
842
+ return [
843
+ this.parseNumber (this.fromEp (this.safeString (bidask, priceKey), market)),
844
+ this.parseNumber (amount),
845
+ ];
846
+ }
847
+
848
+ parseOrderBook (orderbook, symbol, timestamp = undefined, bidsKey = 'bids', asksKey = 'asks', priceKey = 0, amountKey = 1, market = undefined) {
849
+ const result = {
850
+ 'symbol': symbol,
851
+ 'timestamp': timestamp,
852
+ 'datetime': this.iso8601 (timestamp),
853
+ 'nonce': undefined,
854
+ };
855
+ const sides = [ bidsKey, asksKey ];
856
+ for (let i = 0; i < sides.length; i++) {
857
+ const side = sides[i];
858
+ const orders = [];
859
+ const bidasks = this.safeValue (orderbook, side);
860
+ for (let k = 0; k < bidasks.length; k++) {
861
+ orders.push (this.parseBidAsk (bidasks[k], priceKey, amountKey, market));
862
+ }
863
+ result[side] = orders;
864
+ }
865
+ result[bidsKey] = this.sortBy (result[bidsKey], 0, true);
866
+ result[asksKey] = this.sortBy (result[asksKey], 0);
867
+ return result;
868
+ }
869
+
870
+ async fetchOrderBook (symbol, limit = undefined, params = {}) {
871
+ await this.loadMarkets ();
872
+ const market = this.market (symbol);
873
+ const request = {
874
+ 'symbol': market['id'],
875
+ // 'id': 123456789, // optional request id
876
+ };
877
+ const response = await this.v1GetMdOrderbook (this.extend (request, params));
878
+ //
879
+ // {
880
+ // "error": null,
881
+ // "id": 0,
882
+ // "result": {
883
+ // "book": {
884
+ // "asks": [
885
+ // [ 23415000000, 105262000 ],
886
+ // [ 23416000000, 147914000 ],
887
+ // [ 23419000000, 160914000 ],
888
+ // ],
889
+ // "bids": [
890
+ // [ 23360000000, 32995000 ],
891
+ // [ 23359000000, 221887000 ],
892
+ // [ 23356000000, 284599000 ],
893
+ // ],
894
+ // },
895
+ // "depth": 30,
896
+ // "sequence": 1592059928,
897
+ // "symbol": "sETHUSDT",
898
+ // "timestamp": 1592387340020000955,
899
+ // "type": "snapshot"
900
+ // }
901
+ // }
902
+ //
903
+ const result = this.safeValue (response, 'result', {});
904
+ const book = this.safeValue (result, 'book', {});
905
+ const timestamp = this.safeIntegerProduct (result, 'timestamp', 0.000001);
906
+ const orderbook = this.parseOrderBook (book, symbol, timestamp, 'bids', 'asks', 0, 1, market);
907
+ orderbook['nonce'] = this.safeInteger (result, 'sequence');
908
+ return orderbook;
909
+ }
910
+
911
+ toEn (n, scale) {
912
+ const stringN = n.toString ();
913
+ const precise = new Precise (stringN);
914
+ precise.decimals = precise.decimals - scale;
915
+ precise.reduce ();
916
+ const stringValue = precise.toString ();
917
+ return parseInt (parseFloat (stringValue));
918
+ }
919
+
920
+ toEv (amount, market = undefined) {
921
+ if ((amount === undefined) || (market === undefined)) {
922
+ return amount;
923
+ }
924
+ return this.toEn (amount, market['valueScale']);
925
+ }
926
+
927
+ toEp (price, market = undefined) {
928
+ if ((price === undefined) || (market === undefined)) {
929
+ return price;
930
+ }
931
+ return this.toEn (price, market['priceScale']);
932
+ }
933
+
934
+ fromEn (en, scale) {
935
+ if (en === undefined) {
936
+ return undefined;
937
+ }
938
+ const precise = new Precise (en);
939
+ precise.decimals = this.sum (precise.decimals, scale);
940
+ precise.reduce ();
941
+ return precise.toString ();
942
+ }
943
+
944
+ fromEp (ep, market = undefined) {
945
+ if ((ep === undefined) || (market === undefined)) {
946
+ return ep;
947
+ }
948
+ return this.fromEn (ep, this.safeInteger (market, 'priceScale'));
949
+ }
950
+
951
+ fromEv (ev, market = undefined) {
952
+ if ((ev === undefined) || (market === undefined)) {
953
+ return ev;
954
+ }
955
+ return this.fromEn (ev, this.safeInteger (market, 'valueScale'));
956
+ }
957
+
958
+ fromEr (er, market = undefined) {
959
+ if ((er === undefined) || (market === undefined)) {
960
+ return er;
961
+ }
962
+ return this.fromEn (er, this.safeInteger (market, 'ratioScale'));
963
+ }
964
+
965
+ parseOHLCV (ohlcv, market = undefined) {
966
+ //
967
+ // [
968
+ // 1592467200, // timestamp
969
+ // 300, // interval
970
+ // 23376000000, // last
971
+ // 23322000000, // open
972
+ // 23381000000, // high
973
+ // 23315000000, // low
974
+ // 23367000000, // close
975
+ // 208671000, // base volume
976
+ // 48759063370, // quote volume
977
+ // ]
978
+ //
979
+ let baseVolume = undefined;
980
+ if ((market !== undefined) && market['spot']) {
981
+ baseVolume = this.parseNumber (this.fromEv (this.safeString (ohlcv, 7), market));
982
+ } else {
983
+ baseVolume = this.safeNumber (ohlcv, 7);
984
+ }
985
+ return [
986
+ this.safeTimestamp (ohlcv, 0),
987
+ this.parseNumber (this.fromEp (this.safeString (ohlcv, 3), market)),
988
+ this.parseNumber (this.fromEp (this.safeString (ohlcv, 4), market)),
989
+ this.parseNumber (this.fromEp (this.safeString (ohlcv, 5), market)),
990
+ this.parseNumber (this.fromEp (this.safeString (ohlcv, 6), market)),
991
+ baseVolume,
992
+ ];
993
+ }
994
+
995
+ async fetchOHLCV (symbol, timeframe = '1m', since = undefined, limit = undefined, params = {}) {
996
+ const request = {
997
+ // 'symbol': market['id'],
998
+ 'resolution': this.timeframes[timeframe],
999
+ // 'from': 1588830682, // seconds
1000
+ // 'to': this.seconds (),
1001
+ };
1002
+ const duration = this.parseTimeframe (timeframe);
1003
+ const now = this.seconds ();
1004
+ if (since !== undefined) {
1005
+ if (limit === undefined) {
1006
+ limit = 2000; // max 2000
1007
+ }
1008
+ since = parseInt (since / 1000);
1009
+ request['from'] = since;
1010
+ // time ranges ending in the future are not accepted
1011
+ // https://github.com/ccxt/ccxt/issues/8050
1012
+ request['to'] = Math.min (now, this.sum (since, duration * limit));
1013
+ } else if (limit !== undefined) {
1014
+ limit = Math.min (limit, 2000);
1015
+ request['from'] = now - duration * this.sum (limit, 1);
1016
+ request['to'] = now;
1017
+ } else {
1018
+ throw new ArgumentsRequired (this.id + ' fetchOHLCV() requires a since argument, or a limit argument, or both');
1019
+ }
1020
+ await this.loadMarkets ();
1021
+ const market = this.market (symbol);
1022
+ request['symbol'] = market['id'];
1023
+ const response = await this.publicGetMdKline (this.extend (request, params));
1024
+ //
1025
+ // {
1026
+ // "code":0,
1027
+ // "msg":"OK",
1028
+ // "data":{
1029
+ // "total":-1,
1030
+ // "rows":[
1031
+ // [1592467200,300,23376000000,23322000000,23381000000,23315000000,23367000000,208671000,48759063370],
1032
+ // [1592467500,300,23367000000,23314000000,23390000000,23311000000,23331000000,234820000,54848948710],
1033
+ // [1592467800,300,23331000000,23385000000,23391000000,23326000000,23387000000,152931000,35747882250],
1034
+ // ]
1035
+ // }
1036
+ // }
1037
+ //
1038
+ const data = this.safeValue (response, 'data', {});
1039
+ const rows = this.safeValue (data, 'rows', []);
1040
+ return this.parseOHLCVs (rows, market, timeframe, since, limit);
1041
+ }
1042
+
1043
+ parseTicker (ticker, market = undefined) {
1044
+ //
1045
+ // spot
1046
+ //
1047
+ // {
1048
+ // "askEp": 943836000000,
1049
+ // "bidEp": 943601000000,
1050
+ // "highEp": 955946000000,
1051
+ // "lastEp": 943803000000,
1052
+ // "lowEp": 924973000000,
1053
+ // "openEp": 948693000000,
1054
+ // "symbol": "sBTCUSDT",
1055
+ // "timestamp": 1592471203505728630,
1056
+ // "turnoverEv": 111822826123103,
1057
+ // "volumeEv": 11880532281
1058
+ // }
1059
+ //
1060
+ // swap
1061
+ //
1062
+ // {
1063
+ // "askEp": 2332500,
1064
+ // "bidEp": 2331000,
1065
+ // "fundingRateEr": 10000,
1066
+ // "highEp": 2380000,
1067
+ // "indexEp": 2329057,
1068
+ // "lastEp": 2331500,
1069
+ // "lowEp": 2274000,
1070
+ // "markEp": 2329232,
1071
+ // "openEp": 2337500,
1072
+ // "openInterest": 1298050,
1073
+ // "predFundingRateEr": 19921,
1074
+ // "symbol": "ETHUSD",
1075
+ // "timestamp": 1592474241582701416,
1076
+ // "turnoverEv": 47228362330,
1077
+ // "volume": 4053863
1078
+ // }
1079
+ //
1080
+ const marketId = this.safeString (ticker, 'symbol');
1081
+ market = this.safeMarket (marketId, market);
1082
+ const symbol = market['symbol'];
1083
+ const timestamp = this.safeIntegerProduct (ticker, 'timestamp', 0.000001);
1084
+ const last = this.fromEp (this.safeString (ticker, 'lastEp'), market);
1085
+ const quoteVolume = this.fromEv (this.safeString (ticker, 'turnoverEv'), market);
1086
+ let baseVolume = this.safeString (ticker, 'volume');
1087
+ if (baseVolume === undefined) {
1088
+ baseVolume = this.fromEv (this.safeString (ticker, 'volumeEv'), market);
1089
+ }
1090
+ const open = this.fromEp (this.safeString (ticker, 'openEp'), market);
1091
+ return this.safeTicker ({
1092
+ 'symbol': symbol,
1093
+ 'timestamp': timestamp,
1094
+ 'datetime': this.iso8601 (timestamp),
1095
+ 'high': this.fromEp (this.safeString (ticker, 'highEp'), market),
1096
+ 'low': this.fromEp (this.safeString (ticker, 'lowEp'), market),
1097
+ 'bid': this.fromEp (this.safeString (ticker, 'bidEp'), market),
1098
+ 'bidVolume': undefined,
1099
+ 'ask': this.fromEp (this.safeString (ticker, 'askEp'), market),
1100
+ 'askVolume': undefined,
1101
+ 'vwap': undefined,
1102
+ 'open': open,
1103
+ 'close': last,
1104
+ 'last': last,
1105
+ 'previousClose': undefined, // previous day close
1106
+ 'change': undefined,
1107
+ 'percentage': undefined,
1108
+ 'average': undefined,
1109
+ 'baseVolume': baseVolume,
1110
+ 'quoteVolume': quoteVolume,
1111
+ 'info': ticker,
1112
+ }, market, false);
1113
+ }
1114
+
1115
+ async fetchTicker (symbol, params = {}) {
1116
+ await this.loadMarkets ();
1117
+ const market = this.market (symbol);
1118
+ const request = {
1119
+ 'symbol': market['id'],
1120
+ // 'id': 123456789, // optional request id
1121
+ };
1122
+ const method = market['spot'] ? 'v1GetMdSpotTicker24hr' : 'v1GetMdTicker24hr';
1123
+ const response = await this[method] (this.extend (request, params));
1124
+ //
1125
+ // spot
1126
+ //
1127
+ // {
1128
+ // "error": null,
1129
+ // "id": 0,
1130
+ // "result": {
1131
+ // "askEp": 943836000000,
1132
+ // "bidEp": 943601000000,
1133
+ // "highEp": 955946000000,
1134
+ // "lastEp": 943803000000,
1135
+ // "lowEp": 924973000000,
1136
+ // "openEp": 948693000000,
1137
+ // "symbol": "sBTCUSDT",
1138
+ // "timestamp": 1592471203505728630,
1139
+ // "turnoverEv": 111822826123103,
1140
+ // "volumeEv": 11880532281
1141
+ // }
1142
+ // }
1143
+ //
1144
+ // swap
1145
+ //
1146
+ // {
1147
+ // "error": null,
1148
+ // "id": 0,
1149
+ // "result": {
1150
+ // "askEp": 2332500,
1151
+ // "bidEp": 2331000,
1152
+ // "fundingRateEr": 10000,
1153
+ // "highEp": 2380000,
1154
+ // "indexEp": 2329057,
1155
+ // "lastEp": 2331500,
1156
+ // "lowEp": 2274000,
1157
+ // "markEp": 2329232,
1158
+ // "openEp": 2337500,
1159
+ // "openInterest": 1298050,
1160
+ // "predFundingRateEr": 19921,
1161
+ // "symbol": "ETHUSD",
1162
+ // "timestamp": 1592474241582701416,
1163
+ // "turnoverEv": 47228362330,
1164
+ // "volume": 4053863
1165
+ // }
1166
+ // }
1167
+ //
1168
+ const result = this.safeValue (response, 'result', {});
1169
+ return this.parseTicker (result, market);
1170
+ }
1171
+
1172
+ async fetchTrades (symbol, since = undefined, limit = undefined, params = {}) {
1173
+ await this.loadMarkets ();
1174
+ const market = this.market (symbol);
1175
+ const request = {
1176
+ 'symbol': market['id'],
1177
+ // 'id': 123456789, // optional request id
1178
+ };
1179
+ const response = await this.v1GetMdTrade (this.extend (request, params));
1180
+ //
1181
+ // {
1182
+ // "error": null,
1183
+ // "id": 0,
1184
+ // "result": {
1185
+ // "sequence": 1315644947,
1186
+ // "symbol": "BTCUSD",
1187
+ // "trades": [
1188
+ // [ 1592541746712239749, 13156448570000, "Buy", 93070000, 40173 ],
1189
+ // [ 1592541740434625085, 13156447110000, "Sell", 93065000, 5000 ],
1190
+ // [ 1592541732958241616, 13156441390000, "Buy", 93070000, 3460 ],
1191
+ // ],
1192
+ // "type": "snapshot"
1193
+ // }
1194
+ // }
1195
+ //
1196
+ const result = this.safeValue (response, 'result', {});
1197
+ const trades = this.safeValue (result, 'trades', []);
1198
+ return this.parseTrades (trades, market, since, limit);
1199
+ }
1200
+
1201
+ parseTrade (trade, market = undefined) {
1202
+ //
1203
+ // fetchTrades (public)
1204
+ //
1205
+ // [
1206
+ // 1592541746712239749,
1207
+ // 13156448570000,
1208
+ // "Buy",
1209
+ // 93070000,
1210
+ // 40173
1211
+ // ]
1212
+ //
1213
+ // fetchMyTrades (private)
1214
+ //
1215
+ // spot
1216
+ //
1217
+ // {
1218
+ // "qtyType": "ByQuote",
1219
+ // "transactTimeNs": 1589450974800550100,
1220
+ // "clOrdID": "8ba59d40-df25-d4b0-14cf-0703f44e9690",
1221
+ // "orderID": "b2b7018d-f02f-4c59-b4cf-051b9c2d2e83",
1222
+ // "symbol": "sBTCUSDT",
1223
+ // "side": "Buy",
1224
+ // "priceEP": 970056000000,
1225
+ // "baseQtyEv": 0,
1226
+ // "quoteQtyEv": 1000000000,
1227
+ // "action": "New",
1228
+ // "execStatus": "MakerFill",
1229
+ // "ordStatus": "Filled",
1230
+ // "ordType": "Limit",
1231
+ // "execInst": "None",
1232
+ // "timeInForce": "GoodTillCancel",
1233
+ // "stopDirection": "UNSPECIFIED",
1234
+ // "tradeType": "Trade",
1235
+ // "stopPxEp": 0,
1236
+ // "execId": "c6bd8979-07ba-5946-b07e-f8b65135dbb1",
1237
+ // "execPriceEp": 970056000000,
1238
+ // "execBaseQtyEv": 103000,
1239
+ // "execQuoteQtyEv": 999157680,
1240
+ // "leavesBaseQtyEv": 0,
1241
+ // "leavesQuoteQtyEv": 0,
1242
+ // "execFeeEv": 0,
1243
+ // "feeRateEr": 0
1244
+ // }
1245
+ //
1246
+ // swap
1247
+ //
1248
+ // {
1249
+ // "transactTimeNs": 1578026629824704800,
1250
+ // "symbol": "BTCUSD",
1251
+ // "currency": "BTC",
1252
+ // "action": "Replace",
1253
+ // "side": "Sell",
1254
+ // "tradeType": "Trade",
1255
+ // "execQty": 700,
1256
+ // "execPriceEp": 71500000,
1257
+ // "orderQty": 700,
1258
+ // "priceEp": 71500000,
1259
+ // "execValueEv": 9790209,
1260
+ // "feeRateEr": -25000,
1261
+ // "execFeeEv": -2447,
1262
+ // "ordType": "Limit",
1263
+ // "execID": "b01671a1-5ddc-5def-b80a-5311522fd4bf",
1264
+ // "orderID": "b63bc982-be3a-45e0-8974-43d6375fb626",
1265
+ // "clOrdID": "uuid-1577463487504",
1266
+ // "execStatus": "MakerFill"
1267
+ // }
1268
+ //
1269
+ let priceString = undefined;
1270
+ let amountString = undefined;
1271
+ let timestamp = undefined;
1272
+ let id = undefined;
1273
+ let side = undefined;
1274
+ let costString = undefined;
1275
+ let type = undefined;
1276
+ let fee = undefined;
1277
+ const marketId = this.safeString (trade, 'symbol');
1278
+ market = this.safeMarket (marketId, market);
1279
+ const symbol = market['symbol'];
1280
+ let orderId = undefined;
1281
+ let takerOrMaker = undefined;
1282
+ if (Array.isArray (trade)) {
1283
+ const tradeLength = trade.length;
1284
+ timestamp = this.safeIntegerProduct (trade, 0, 0.000001);
1285
+ if (tradeLength > 4) {
1286
+ id = this.safeString (trade, tradeLength - 4);
1287
+ }
1288
+ side = this.safeStringLower (trade, tradeLength - 3);
1289
+ priceString = this.fromEp (this.safeString (trade, tradeLength - 2), market);
1290
+ amountString = this.fromEv (this.safeString (trade, tradeLength - 1), market);
1291
+ } else {
1292
+ timestamp = this.safeIntegerProduct (trade, 'transactTimeNs', 0.000001);
1293
+ id = this.safeString2 (trade, 'execId', 'execID');
1294
+ orderId = this.safeString (trade, 'orderID');
1295
+ side = this.safeStringLower (trade, 'side');
1296
+ type = this.parseOrderType (this.safeString (trade, 'ordType'));
1297
+ const execStatus = this.safeString (trade, 'execStatus');
1298
+ if (execStatus === 'MakerFill') {
1299
+ takerOrMaker = 'maker';
1300
+ }
1301
+ priceString = this.fromEp (this.safeString (trade, 'execPriceEp'), market);
1302
+ amountString = this.fromEv (this.safeString (trade, 'execBaseQtyEv'), market);
1303
+ amountString = this.safeString (trade, 'execQty', amountString);
1304
+ costString = this.fromEv (this.safeString2 (trade, 'execQuoteQtyEv', 'execValueEv'), market);
1305
+ const feeCostString = this.fromEv (this.safeString (trade, 'execFeeEv'), market);
1306
+ if (feeCostString !== undefined) {
1307
+ const feeRateString = this.fromEr (this.safeString (trade, 'feeRateEr'), market);
1308
+ let feeCurrencyCode = undefined;
1309
+ if (market['spot']) {
1310
+ feeCurrencyCode = (side === 'buy') ? market['base'] : market['quote'];
1311
+ } else {
1312
+ const info = this.safeValue (market, 'info');
1313
+ if (info !== undefined) {
1314
+ const settlementCurrencyId = this.safeString (info, 'settlementCurrency');
1315
+ feeCurrencyCode = this.safeCurrencyCode (settlementCurrencyId);
1316
+ }
1317
+ }
1318
+ fee = {
1319
+ 'cost': this.parseNumber (feeCostString),
1320
+ 'rate': this.parseNumber (feeRateString),
1321
+ 'currency': feeCurrencyCode,
1322
+ };
1323
+ }
1324
+ }
1325
+ return this.safeTrade ({
1326
+ 'info': trade,
1327
+ 'id': id,
1328
+ 'symbol': symbol,
1329
+ 'timestamp': timestamp,
1330
+ 'datetime': this.iso8601 (timestamp),
1331
+ 'order': orderId,
1332
+ 'type': type,
1333
+ 'side': side,
1334
+ 'takerOrMaker': takerOrMaker,
1335
+ 'price': priceString,
1336
+ 'amount': amountString,
1337
+ 'cost': costString,
1338
+ 'fee': fee,
1339
+ }, market);
1340
+ }
1341
+
1342
+ parseSpotBalance (response) {
1343
+ //
1344
+ // {
1345
+ // "code":0,
1346
+ // "msg":"",
1347
+ // "data":[
1348
+ // {
1349
+ // "currency":"USDT",
1350
+ // "balanceEv":0,
1351
+ // "lockedTradingBalanceEv":0,
1352
+ // "lockedWithdrawEv":0,
1353
+ // "lastUpdateTimeNs":1592065834511322514,
1354
+ // "walletVid":0
1355
+ // },
1356
+ // {
1357
+ // "currency":"ETH",
1358
+ // "balanceEv":0,
1359
+ // "lockedTradingBalanceEv":0,
1360
+ // "lockedWithdrawEv":0,
1361
+ // "lastUpdateTimeNs":1592065834511322514,
1362
+ // "walletVid":0
1363
+ // }
1364
+ // ]
1365
+ // }
1366
+ //
1367
+ let timestamp = undefined;
1368
+ const result = { 'info': response };
1369
+ const data = this.safeValue (response, 'data', []);
1370
+ for (let i = 0; i < data.length; i++) {
1371
+ const balance = data[i];
1372
+ const currencyId = this.safeString (balance, 'currency');
1373
+ const code = this.safeCurrencyCode (currencyId);
1374
+ const currency = this.safeValue (this.currencies, code, {});
1375
+ const scale = this.safeInteger (currency, 'valueScale', 8);
1376
+ const account = this.account ();
1377
+ const balanceEv = this.safeString (balance, 'balanceEv');
1378
+ const lockedTradingBalanceEv = this.safeString (balance, 'lockedTradingBalanceEv');
1379
+ const lockedWithdrawEv = this.safeString (balance, 'lockedWithdrawEv');
1380
+ const total = this.fromEn (balanceEv, scale);
1381
+ const lockedTradingBalance = this.fromEn (lockedTradingBalanceEv, scale);
1382
+ const lockedWithdraw = this.fromEn (lockedWithdrawEv, scale);
1383
+ const used = Precise.stringAdd (lockedTradingBalance, lockedWithdraw);
1384
+ const lastUpdateTimeNs = this.safeIntegerProduct (balance, 'lastUpdateTimeNs', 0.000001);
1385
+ timestamp = (timestamp === undefined) ? lastUpdateTimeNs : Math.max (timestamp, lastUpdateTimeNs);
1386
+ account['total'] = total;
1387
+ account['used'] = used;
1388
+ result[code] = account;
1389
+ }
1390
+ result['timestamp'] = timestamp;
1391
+ result['datetime'] = this.iso8601 (timestamp);
1392
+ return this.safeBalance (result);
1393
+ }
1394
+
1395
+ parseSwapBalance (response) {
1396
+ //
1397
+ // {
1398
+ // "code":0,
1399
+ // "msg":"",
1400
+ // "data":{
1401
+ // "account":{
1402
+ // "accountId":6192120001,
1403
+ // "currency":"BTC",
1404
+ // "accountBalanceEv":1254744,
1405
+ // "totalUsedBalanceEv":0,
1406
+ // "bonusBalanceEv":1254744
1407
+ // },
1408
+ // "positions":[
1409
+ // {
1410
+ // "accountID":6192120001,
1411
+ // "symbol":"BTCUSD",
1412
+ // "currency":"BTC",
1413
+ // "side":"None",
1414
+ // "positionStatus":"Normal",
1415
+ // "crossMargin":false,
1416
+ // "leverageEr":0,
1417
+ // "leverage":0E-8,
1418
+ // "initMarginReqEr":1000000,
1419
+ // "initMarginReq":0.01000000,
1420
+ // "maintMarginReqEr":500000,
1421
+ // "maintMarginReq":0.00500000,
1422
+ // "riskLimitEv":10000000000,
1423
+ // "riskLimit":100.00000000,
1424
+ // "size":0,
1425
+ // "value":0E-8,
1426
+ // "valueEv":0,
1427
+ // "avgEntryPriceEp":0,
1428
+ // "avgEntryPrice":0E-8,
1429
+ // "posCostEv":0,
1430
+ // "posCost":0E-8,
1431
+ // "assignedPosBalanceEv":0,
1432
+ // "assignedPosBalance":0E-8,
1433
+ // "bankruptCommEv":0,
1434
+ // "bankruptComm":0E-8,
1435
+ // "bankruptPriceEp":0,
1436
+ // "bankruptPrice":0E-8,
1437
+ // "positionMarginEv":0,
1438
+ // "positionMargin":0E-8,
1439
+ // "liquidationPriceEp":0,
1440
+ // "liquidationPrice":0E-8,
1441
+ // "deleveragePercentileEr":0,
1442
+ // "deleveragePercentile":0E-8,
1443
+ // "buyValueToCostEr":1150750,
1444
+ // "buyValueToCost":0.01150750,
1445
+ // "sellValueToCostEr":1149250,
1446
+ // "sellValueToCost":0.01149250,
1447
+ // "markPriceEp":96359083,
1448
+ // "markPrice":9635.90830000,
1449
+ // "markValueEv":0,
1450
+ // "markValue":null,
1451
+ // "unRealisedPosLossEv":0,
1452
+ // "unRealisedPosLoss":null,
1453
+ // "estimatedOrdLossEv":0,
1454
+ // "estimatedOrdLoss":0E-8,
1455
+ // "usedBalanceEv":0,
1456
+ // "usedBalance":0E-8,
1457
+ // "takeProfitEp":0,
1458
+ // "takeProfit":null,
1459
+ // "stopLossEp":0,
1460
+ // "stopLoss":null,
1461
+ // "realisedPnlEv":0,
1462
+ // "realisedPnl":null,
1463
+ // "cumRealisedPnlEv":0,
1464
+ // "cumRealisedPnl":null
1465
+ // }
1466
+ // ]
1467
+ // }
1468
+ // }
1469
+ //
1470
+ const result = { 'info': response };
1471
+ const data = this.safeValue (response, 'data', {});
1472
+ const balance = this.safeValue (data, 'account', {});
1473
+ const currencyId = this.safeString (balance, 'currency');
1474
+ const code = this.safeCurrencyCode (currencyId);
1475
+ const currency = this.currency (code);
1476
+ const account = this.account ();
1477
+ const accountBalanceEv = this.safeString (balance, 'accountBalanceEv');
1478
+ const totalUsedBalanceEv = this.safeString (balance, 'totalUsedBalanceEv');
1479
+ const valueScale = this.safeInteger (currency, 'valueScale', 8);
1480
+ account['total'] = this.fromEn (accountBalanceEv, valueScale);
1481
+ account['used'] = this.fromEn (totalUsedBalanceEv, valueScale);
1482
+ result[code] = account;
1483
+ return this.safeBalance (result);
1484
+ }
1485
+
1486
+ async fetchBalance (params = {}) {
1487
+ await this.loadMarkets ();
1488
+ const defaultType = this.safeString2 (this.options, 'defaultType', 'fetchBalance', 'spot');
1489
+ const type = this.safeString (params, 'type', defaultType);
1490
+ let method = 'privateGetSpotWallets';
1491
+ const request = {};
1492
+ if (type === 'swap') {
1493
+ const code = this.safeString (params, 'code');
1494
+ if (code !== undefined) {
1495
+ const currency = this.currency (code);
1496
+ request['currency'] = currency['id'];
1497
+ params = this.omit (params, 'code');
1498
+ } else {
1499
+ const currency = this.safeString (params, 'currency');
1500
+ if (currency === undefined) {
1501
+ throw new ArgumentsRequired (this.id + ' fetchBalance() requires a code parameter or a currency parameter for ' + type + ' type');
1502
+ }
1503
+ }
1504
+ method = 'privateGetAccountsAccountPositions';
1505
+ }
1506
+ params = this.omit (params, 'type');
1507
+ const response = await this[method] (this.extend (request, params));
1508
+ //
1509
+ // spot
1510
+ //
1511
+ // {
1512
+ // "code":0,
1513
+ // "msg":"",
1514
+ // "data":[
1515
+ // {
1516
+ // "currency":"USDT",
1517
+ // "balanceEv":0,
1518
+ // "lockedTradingBalanceEv":0,
1519
+ // "lockedWithdrawEv":0,
1520
+ // "lastUpdateTimeNs":1592065834511322514,
1521
+ // "walletVid":0
1522
+ // },
1523
+ // {
1524
+ // "currency":"ETH",
1525
+ // "balanceEv":0,
1526
+ // "lockedTradingBalanceEv":0,
1527
+ // "lockedWithdrawEv":0,
1528
+ // "lastUpdateTimeNs":1592065834511322514,
1529
+ // "walletVid":0
1530
+ // }
1531
+ // ]
1532
+ // }
1533
+ //
1534
+ // swap
1535
+ //
1536
+ // {
1537
+ // "code":0,
1538
+ // "msg":"",
1539
+ // "data":{
1540
+ // "account":{
1541
+ // "accountId":6192120001,
1542
+ // "currency":"BTC",
1543
+ // "accountBalanceEv":1254744,
1544
+ // "totalUsedBalanceEv":0,
1545
+ // "bonusBalanceEv":1254744
1546
+ // },
1547
+ // "positions":[
1548
+ // {
1549
+ // "accountID":6192120001,
1550
+ // "symbol":"BTCUSD",
1551
+ // "currency":"BTC",
1552
+ // "side":"None",
1553
+ // "positionStatus":"Normal",
1554
+ // "crossMargin":false,
1555
+ // "leverageEr":0,
1556
+ // "leverage":0E-8,
1557
+ // "initMarginReqEr":1000000,
1558
+ // "initMarginReq":0.01000000,
1559
+ // "maintMarginReqEr":500000,
1560
+ // "maintMarginReq":0.00500000,
1561
+ // "riskLimitEv":10000000000,
1562
+ // "riskLimit":100.00000000,
1563
+ // "size":0,
1564
+ // "value":0E-8,
1565
+ // "valueEv":0,
1566
+ // "avgEntryPriceEp":0,
1567
+ // "avgEntryPrice":0E-8,
1568
+ // "posCostEv":0,
1569
+ // "posCost":0E-8,
1570
+ // "assignedPosBalanceEv":0,
1571
+ // "assignedPosBalance":0E-8,
1572
+ // "bankruptCommEv":0,
1573
+ // "bankruptComm":0E-8,
1574
+ // "bankruptPriceEp":0,
1575
+ // "bankruptPrice":0E-8,
1576
+ // "positionMarginEv":0,
1577
+ // "positionMargin":0E-8,
1578
+ // "liquidationPriceEp":0,
1579
+ // "liquidationPrice":0E-8,
1580
+ // "deleveragePercentileEr":0,
1581
+ // "deleveragePercentile":0E-8,
1582
+ // "buyValueToCostEr":1150750,
1583
+ // "buyValueToCost":0.01150750,
1584
+ // "sellValueToCostEr":1149250,
1585
+ // "sellValueToCost":0.01149250,
1586
+ // "markPriceEp":96359083,
1587
+ // "markPrice":9635.90830000,
1588
+ // "markValueEv":0,
1589
+ // "markValue":null,
1590
+ // "unRealisedPosLossEv":0,
1591
+ // "unRealisedPosLoss":null,
1592
+ // "estimatedOrdLossEv":0,
1593
+ // "estimatedOrdLoss":0E-8,
1594
+ // "usedBalanceEv":0,
1595
+ // "usedBalance":0E-8,
1596
+ // "takeProfitEp":0,
1597
+ // "takeProfit":null,
1598
+ // "stopLossEp":0,
1599
+ // "stopLoss":null,
1600
+ // "realisedPnlEv":0,
1601
+ // "realisedPnl":null,
1602
+ // "cumRealisedPnlEv":0,
1603
+ // "cumRealisedPnl":null
1604
+ // }
1605
+ // ]
1606
+ // }
1607
+ // }
1608
+ //
1609
+ const result = (type === 'swap') ? this.parseSwapBalance (response) : this.parseSpotBalance (response);
1610
+ return result;
1611
+ }
1612
+
1613
+ parseOrderStatus (status) {
1614
+ const statuses = {
1615
+ 'Created': 'open',
1616
+ 'Untriggered': 'open',
1617
+ 'Deactivated': 'closed',
1618
+ 'Triggered': 'open',
1619
+ 'Rejected': 'rejected',
1620
+ 'New': 'open',
1621
+ 'PartiallyFilled': 'open',
1622
+ 'Filled': 'closed',
1623
+ 'Canceled': 'canceled',
1624
+ };
1625
+ return this.safeString (statuses, status, status);
1626
+ }
1627
+
1628
+ parseOrderType (type) {
1629
+ const types = {
1630
+ 'Limit': 'limit',
1631
+ 'Market': 'market',
1632
+ };
1633
+ return this.safeString (types, type, type);
1634
+ }
1635
+
1636
+ parseTimeInForce (timeInForce) {
1637
+ const timeInForces = {
1638
+ 'GoodTillCancel': 'GTC',
1639
+ 'PostOnly': 'PO',
1640
+ 'ImmediateOrCancel': 'IOC',
1641
+ 'FillOrKill': 'FOK',
1642
+ };
1643
+ return this.safeString (timeInForces, timeInForce, timeInForce);
1644
+ }
1645
+
1646
+ parseSpotOrder (order, market = undefined) {
1647
+ //
1648
+ // spot
1649
+ //
1650
+ // {
1651
+ // "orderID": "d1d09454-cabc-4a23-89a7-59d43363f16d",
1652
+ // "clOrdID": "309bcd5c-9f6e-4a68-b775-4494542eb5cb",
1653
+ // "priceEp": 0,
1654
+ // "action": "New",
1655
+ // "trigger": "UNSPECIFIED",
1656
+ // "pegPriceType": "UNSPECIFIED",
1657
+ // "stopDirection": "UNSPECIFIED",
1658
+ // "bizError": 0,
1659
+ // "symbol": "sBTCUSDT",
1660
+ // "side": "Buy",
1661
+ // "baseQtyEv": 0,
1662
+ // "ordType": "Limit",
1663
+ // "timeInForce": "GoodTillCancel",
1664
+ // "ordStatus": "Created",
1665
+ // "cumFeeEv": 0,
1666
+ // "cumBaseQtyEv": 0,
1667
+ // "cumQuoteQtyEv": 0,
1668
+ // "leavesBaseQtyEv": 0,
1669
+ // "leavesQuoteQtyEv": 0,
1670
+ // "avgPriceEp": 0,
1671
+ // "cumBaseAmountEv": 0,
1672
+ // "cumQuoteAmountEv": 0,
1673
+ // "quoteQtyEv": 0,
1674
+ // "qtyType": "ByBase",
1675
+ // "stopPxEp": 0,
1676
+ // "pegOffsetValueEp": 0
1677
+ // }
1678
+ //
1679
+ // {
1680
+ // "orderID":"99232c3e-3d6a-455f-98cc-2061cdfe91bc",
1681
+ // "stopPxEp":0,
1682
+ // "avgPriceEp":0,
1683
+ // "qtyType":"ByBase",
1684
+ // "leavesBaseQtyEv":0,
1685
+ // "leavesQuoteQtyEv":0,
1686
+ // "baseQtyEv":"1000000000",
1687
+ // "feeCurrency":"4",
1688
+ // "stopDirection":"UNSPECIFIED",
1689
+ // "symbol":"sETHUSDT",
1690
+ // "side":"Buy",
1691
+ // "quoteQtyEv":250000000000,
1692
+ // "priceEp":25000000000,
1693
+ // "ordType":"Limit",
1694
+ // "timeInForce":"GoodTillCancel",
1695
+ // "ordStatus":"Rejected",
1696
+ // "execStatus":"NewRejected",
1697
+ // "createTimeNs":1592675305266037130,
1698
+ // "cumFeeEv":0,
1699
+ // "cumBaseValueEv":0,
1700
+ // "cumQuoteValueEv":0
1701
+ // }
1702
+ //
1703
+ const id = this.safeString (order, 'orderID');
1704
+ let clientOrderId = this.safeString (order, 'clOrdID');
1705
+ if ((clientOrderId !== undefined) && (clientOrderId.length < 1)) {
1706
+ clientOrderId = undefined;
1707
+ }
1708
+ const marketId = this.safeString (order, 'symbol');
1709
+ const symbol = this.safeSymbol (marketId, market);
1710
+ const price = this.fromEp (this.safeString (order, 'priceEp'), market);
1711
+ const amount = this.fromEv (this.safeString (order, 'baseQtyEv'), market);
1712
+ const remaining = this.omitZero (this.fromEv (this.safeString (order, 'leavesBaseQtyEv'), market));
1713
+ const filled = this.fromEv (this.safeString2 (order, 'cumBaseQtyEv', 'cumBaseValueEv'), market);
1714
+ const cost = this.fromEv (this.safeString2 (order, 'cumQuoteValueEv', 'quoteQtyEv'), market);
1715
+ const average = this.fromEp (this.safeString (order, 'avgPriceEp'), market);
1716
+ const status = this.parseOrderStatus (this.safeString (order, 'ordStatus'));
1717
+ const side = this.safeStringLower (order, 'side');
1718
+ const type = this.parseOrderType (this.safeString (order, 'ordType'));
1719
+ const timestamp = this.safeIntegerProduct2 (order, 'actionTimeNs', 'createTimeNs', 0.000001);
1720
+ let fee = undefined;
1721
+ const feeCost = this.fromEv (this.safeString (order, 'cumFeeEv'), market);
1722
+ if (feeCost !== undefined) {
1723
+ fee = {
1724
+ 'cost': feeCost,
1725
+ 'currency': undefined,
1726
+ };
1727
+ }
1728
+ const timeInForce = this.parseTimeInForce (this.safeString (order, 'timeInForce'));
1729
+ const stopPrice = this.parseNumber (this.omitZero (this.fromEp (this.safeString (order, 'stopPxEp', market))));
1730
+ const postOnly = (timeInForce === 'PO');
1731
+ return this.safeOrder ({
1732
+ 'info': order,
1733
+ 'id': id,
1734
+ 'clientOrderId': clientOrderId,
1735
+ 'timestamp': timestamp,
1736
+ 'datetime': this.iso8601 (timestamp),
1737
+ 'lastTradeTimestamp': undefined,
1738
+ 'symbol': symbol,
1739
+ 'type': type,
1740
+ 'timeInForce': timeInForce,
1741
+ 'postOnly': postOnly,
1742
+ 'side': side,
1743
+ 'price': price,
1744
+ 'stopPrice': stopPrice,
1745
+ 'amount': amount,
1746
+ 'cost': cost,
1747
+ 'average': average,
1748
+ 'filled': filled,
1749
+ 'remaining': remaining,
1750
+ 'status': status,
1751
+ 'fee': fee,
1752
+ 'trades': undefined,
1753
+ }, market);
1754
+ }
1755
+
1756
+ parseSwapOrder (order, market = undefined) {
1757
+ //
1758
+ // {
1759
+ // "bizError":0,
1760
+ // "orderID":"7a1ad384-44a3-4e54-a102-de4195a29e32",
1761
+ // "clOrdID":"",
1762
+ // "symbol":"ETHUSD",
1763
+ // "side":"Buy",
1764
+ // "actionTimeNs":1592668973945065381,
1765
+ // "transactTimeNs":0,
1766
+ // "orderType":"Market",
1767
+ // "priceEp":2267500,
1768
+ // "price":226.75000000,
1769
+ // "orderQty":1,
1770
+ // "displayQty":0,
1771
+ // "timeInForce":"ImmediateOrCancel",
1772
+ // "reduceOnly":false,
1773
+ // "closedPnlEv":0,
1774
+ // "closedPnl":0E-8,
1775
+ // "closedSize":0,
1776
+ // "cumQty":0,
1777
+ // "cumValueEv":0,
1778
+ // "cumValue":0E-8,
1779
+ // "leavesQty":1,
1780
+ // "leavesValueEv":11337,
1781
+ // "leavesValue":1.13370000,
1782
+ // "stopDirection":"UNSPECIFIED",
1783
+ // "stopPxEp":0,
1784
+ // "stopPx":0E-8,
1785
+ // "trigger":"UNSPECIFIED",
1786
+ // "pegOffsetValueEp":0,
1787
+ // "execStatus":"PendingNew",
1788
+ // "pegPriceType":"UNSPECIFIED",
1789
+ // "ordStatus":"Created"
1790
+ // }
1791
+ //
1792
+ const id = this.safeString (order, 'orderID');
1793
+ let clientOrderId = this.safeString (order, 'clOrdID');
1794
+ if ((clientOrderId !== undefined) && (clientOrderId.length < 1)) {
1795
+ clientOrderId = undefined;
1796
+ }
1797
+ const marketId = this.safeString (order, 'symbol');
1798
+ const symbol = this.safeSymbol (marketId, market);
1799
+ const status = this.parseOrderStatus (this.safeString (order, 'ordStatus'));
1800
+ const side = this.safeStringLower (order, 'side');
1801
+ const type = this.parseOrderType (this.safeString (order, 'orderType'));
1802
+ const price = this.parseNumber (this.fromEp (this.safeString (order, 'priceEp'), market));
1803
+ const amount = this.safeNumber (order, 'orderQty');
1804
+ const filled = this.safeNumber (order, 'cumQty');
1805
+ const remaining = this.safeNumber (order, 'leavesQty');
1806
+ const timestamp = this.safeIntegerProduct (order, 'actionTimeNs', 0.000001);
1807
+ const cost = this.safeNumber (order, 'cumValue');
1808
+ let lastTradeTimestamp = this.safeIntegerProduct (order, 'transactTimeNs', 0.000001);
1809
+ if (lastTradeTimestamp === 0) {
1810
+ lastTradeTimestamp = undefined;
1811
+ }
1812
+ const timeInForce = this.parseTimeInForce (this.safeString (order, 'timeInForce'));
1813
+ const stopPrice = this.safeNumber (order, 'stopPx');
1814
+ const postOnly = (timeInForce === 'PO');
1815
+ return {
1816
+ 'info': order,
1817
+ 'id': id,
1818
+ 'clientOrderId': clientOrderId,
1819
+ 'datetime': this.iso8601 (timestamp),
1820
+ 'timestamp': timestamp,
1821
+ 'lastTradeTimestamp': lastTradeTimestamp,
1822
+ 'symbol': symbol,
1823
+ 'type': type,
1824
+ 'timeInForce': timeInForce,
1825
+ 'postOnly': postOnly,
1826
+ 'side': side,
1827
+ 'price': price,
1828
+ 'stopPrice': stopPrice,
1829
+ 'amount': amount,
1830
+ 'filled': filled,
1831
+ 'remaining': remaining,
1832
+ 'cost': cost,
1833
+ 'average': undefined,
1834
+ 'status': status,
1835
+ 'fee': undefined,
1836
+ 'trades': undefined,
1837
+ };
1838
+ }
1839
+
1840
+ parseOrder (order, market = undefined) {
1841
+ if ('closedPnl' in order) {
1842
+ return this.parseSwapOrder (order, market);
1843
+ }
1844
+ return this.parseSpotOrder (order, market);
1845
+ }
1846
+
1847
+ async createOrder (symbol, type, side, amount, price = undefined, params = {}) {
1848
+ await this.loadMarkets ();
1849
+ const market = this.market (symbol);
1850
+ side = this.capitalize (side);
1851
+ type = this.capitalize (type);
1852
+ const request = {
1853
+ // common
1854
+ 'symbol': market['id'],
1855
+ 'side': side, // Sell, Buy
1856
+ 'ordType': type, // Market, Limit, Stop, StopLimit, MarketIfTouched, LimitIfTouched or Pegged for swap orders
1857
+ // 'stopPxEp': this.toEp (stopPx, market), // for conditional orders
1858
+ // 'priceEp': this.toEp (price, market), // required for limit orders
1859
+ // 'timeInForce': 'GoodTillCancel', // GoodTillCancel, PostOnly, ImmediateOrCancel, FillOrKill
1860
+ // ----------------------------------------------------------------
1861
+ // spot
1862
+ // 'qtyType': 'ByBase', // ByBase, ByQuote
1863
+ // 'quoteQtyEv': this.toEp (cost, market),
1864
+ // 'baseQtyEv': this.toEv (amount, market),
1865
+ // 'trigger': 'ByLastPrice', // required for conditional orders
1866
+ // ----------------------------------------------------------------
1867
+ // swap
1868
+ // 'clOrdID': this.uuid (), // max length 40
1869
+ // 'orderQty': this.amountToPrecision (amount, symbol),
1870
+ // 'reduceOnly': false,
1871
+ // 'closeOnTrigger': false, // implicit reduceOnly and cancel other orders in the same direction
1872
+ // 'takeProfitEp': this.toEp (takeProfit, market),
1873
+ // 'stopLossEp': this.toEp (stopLossEp, market),
1874
+ // 'triggerType': 'ByMarkPrice', // ByMarkPrice, ByLastPrice
1875
+ // 'pegOffsetValueEp': integer, // Trailing offset from current price. Negative value when position is long, positive when position is short
1876
+ // 'pegPriceType': 'TrailingStopPeg', // TrailingTakeProfitPeg
1877
+ // 'text': 'comment',
1878
+ };
1879
+ const stopPrice = this.safeString2 (params, 'stopPx', 'stopPrice');
1880
+ if (stopPrice !== undefined) {
1881
+ request['stopPxEp'] = this.toEp (stopPrice, market);
1882
+ }
1883
+ params = this.omit (params, [ 'stopPx', 'stopPrice' ]);
1884
+ if (market['spot']) {
1885
+ let qtyType = this.safeValue (params, 'qtyType', 'ByBase');
1886
+ if ((type === 'Market') || (type === 'Stop') || (type === 'MarketIfTouched')) {
1887
+ if (price !== undefined) {
1888
+ qtyType = 'ByQuote';
1889
+ }
1890
+ }
1891
+ request['qtyType'] = qtyType;
1892
+ if (qtyType === 'ByQuote') {
1893
+ let cost = this.safeNumber (params, 'cost');
1894
+ params = this.omit (params, 'cost');
1895
+ if (this.options['createOrderByQuoteRequiresPrice']) {
1896
+ if (price !== undefined) {
1897
+ cost = amount * price;
1898
+ } else if (cost === undefined) {
1899
+ throw new ArgumentsRequired (this.id + ' createOrder() ' + qtyType + ' requires a price argument or a cost parameter');
1900
+ }
1901
+ }
1902
+ cost = (cost === undefined) ? amount : cost;
1903
+ const costString = cost.toString ();
1904
+ request['quoteQtyEv'] = this.toEv (costString, market);
1905
+ } else {
1906
+ const amountString = amount.toString ();
1907
+ request['baseQtyEv'] = this.toEv (amountString, market);
1908
+ }
1909
+ } else if (market['swap']) {
1910
+ request['orderQty'] = parseInt (amount);
1911
+ if (stopPrice !== undefined) {
1912
+ const triggerType = this.safeString (params, 'triggerType', 'ByMarkPrice');
1913
+ request['triggerType'] = triggerType;
1914
+ }
1915
+ }
1916
+ if ((type === 'Limit') || (type === 'StopLimit') || (type === 'LimitIfTouched')) {
1917
+ const priceString = price.toString ();
1918
+ request['priceEp'] = this.toEp (priceString, market);
1919
+ }
1920
+ const takeProfitPrice = this.safeString (params, 'takeProfitPrice');
1921
+ if (takeProfitPrice !== undefined) {
1922
+ request['takeProfitEp'] = this.toEp (takeProfitPrice, market);
1923
+ params = this.omit (params, 'takeProfitPrice');
1924
+ }
1925
+ const stopLossPrice = this.safeString (params, 'stopLossPrice');
1926
+ if (stopLossPrice !== undefined) {
1927
+ request['stopLossEp'] = this.toEp (stopLossPrice, market);
1928
+ params = this.omit (params, 'stopLossPrice');
1929
+ }
1930
+ const method = market['spot'] ? 'privatePostSpotOrders' : 'privatePostOrders';
1931
+ const response = await this[method] (this.extend (request, params));
1932
+ //
1933
+ // spot
1934
+ //
1935
+ // {
1936
+ // "code": 0,
1937
+ // "msg": "",
1938
+ // "data": {
1939
+ // "orderID": "d1d09454-cabc-4a23-89a7-59d43363f16d",
1940
+ // "clOrdID": "309bcd5c-9f6e-4a68-b775-4494542eb5cb",
1941
+ // "priceEp": 0,
1942
+ // "action": "New",
1943
+ // "trigger": "UNSPECIFIED",
1944
+ // "pegPriceType": "UNSPECIFIED",
1945
+ // "stopDirection": "UNSPECIFIED",
1946
+ // "bizError": 0,
1947
+ // "symbol": "sBTCUSDT",
1948
+ // "side": "Buy",
1949
+ // "baseQtyEv": 0,
1950
+ // "ordType": "Limit",
1951
+ // "timeInForce": "GoodTillCancel",
1952
+ // "ordStatus": "Created",
1953
+ // "cumFeeEv": 0,
1954
+ // "cumBaseQtyEv": 0,
1955
+ // "cumQuoteQtyEv": 0,
1956
+ // "leavesBaseQtyEv": 0,
1957
+ // "leavesQuoteQtyEv": 0,
1958
+ // "avgPriceEp": 0,
1959
+ // "cumBaseAmountEv": 0,
1960
+ // "cumQuoteAmountEv": 0,
1961
+ // "quoteQtyEv": 0,
1962
+ // "qtyType": "ByBase",
1963
+ // "stopPxEp": 0,
1964
+ // "pegOffsetValueEp": 0
1965
+ // }
1966
+ // }
1967
+ //
1968
+ // swap
1969
+ //
1970
+ // {
1971
+ // "code":0,
1972
+ // "msg":"",
1973
+ // "data":{
1974
+ // "bizError":0,
1975
+ // "orderID":"7a1ad384-44a3-4e54-a102-de4195a29e32",
1976
+ // "clOrdID":"",
1977
+ // "symbol":"ETHUSD",
1978
+ // "side":"Buy",
1979
+ // "actionTimeNs":1592668973945065381,
1980
+ // "transactTimeNs":0,
1981
+ // "orderType":"Market",
1982
+ // "priceEp":2267500,
1983
+ // "price":226.75000000,
1984
+ // "orderQty":1,
1985
+ // "displayQty":0,
1986
+ // "timeInForce":"ImmediateOrCancel",
1987
+ // "reduceOnly":false,
1988
+ // "closedPnlEv":0,
1989
+ // "closedPnl":0E-8,
1990
+ // "closedSize":0,
1991
+ // "cumQty":0,
1992
+ // "cumValueEv":0,
1993
+ // "cumValue":0E-8,
1994
+ // "leavesQty":1,
1995
+ // "leavesValueEv":11337,
1996
+ // "leavesValue":1.13370000,
1997
+ // "stopDirection":"UNSPECIFIED",
1998
+ // "stopPxEp":0,
1999
+ // "stopPx":0E-8,
2000
+ // "trigger":"UNSPECIFIED",
2001
+ // "pegOffsetValueEp":0,
2002
+ // "execStatus":"PendingNew",
2003
+ // "pegPriceType":"UNSPECIFIED",
2004
+ // "ordStatus":"Created"
2005
+ // }
2006
+ // }
2007
+ //
2008
+ const data = this.safeValue (response, 'data', {});
2009
+ return this.parseOrder (data, market);
2010
+ }
2011
+
2012
+ async editOrder (id, symbol, type = undefined, side = undefined, amount = undefined, price = undefined, params = {}) {
2013
+ if (symbol === undefined) {
2014
+ throw new ArgumentsRequired (this.id + ' editOrder() requires a symbol argument');
2015
+ }
2016
+ if (type !== undefined) {
2017
+ throw new ArgumentsRequired (this.id + ' editOrder() type changing is not implemented. Try to cancel & recreate order for that purpose');
2018
+ }
2019
+ if (side !== undefined) {
2020
+ throw new ArgumentsRequired (this.id + ' editOrder() side changing is not implemented. Try to cancel & recreate order for that purpose');
2021
+ }
2022
+ await this.loadMarkets ();
2023
+ const market = this.market (symbol);
2024
+ const request = {
2025
+ 'symbol': market['id'],
2026
+ };
2027
+ const clientOrderId = this.safeString2 (params, 'clientOrderId', 'clOrdID');
2028
+ params = this.omit (params, [ 'clientOrderId', 'clOrdID' ]);
2029
+ if (clientOrderId !== undefined) {
2030
+ request['clOrdID'] = clientOrderId;
2031
+ } else {
2032
+ request['orderID'] = id;
2033
+ }
2034
+ if (price !== undefined) {
2035
+ request['priceEp'] = this.toEp (price, market);
2036
+ }
2037
+ // Note the uppercase 'V' in 'baseQtyEV' request. that is exchange's requirement at this moment. However, to avoid mistakes from user side, let's support lowercased 'baseQtyEv' too
2038
+ const finalQty = this.safeString (params, 'baseQtyEv');
2039
+ params = this.omit (params, [ 'baseQtyEv' ]);
2040
+ if (finalQty !== undefined) {
2041
+ request['baseQtyEV'] = finalQty;
2042
+ } else if (amount !== undefined) {
2043
+ request['baseQtyEV'] = this.toEv (amount, market);
2044
+ }
2045
+ const stopPrice = this.safeString2 (params, 'stopPx', 'stopPrice');
2046
+ if (stopPrice !== undefined) {
2047
+ request['stopPxEp'] = this.toEp (stopPrice, market);
2048
+ }
2049
+ params = this.omit (params, [ 'stopPx', 'stopPrice' ]);
2050
+ const method = market['spot'] ? 'privatePutSpotOrders' : 'privatePutOrdersReplace';
2051
+ const response = await this[method] (this.extend (request, params));
2052
+ const data = this.safeValue (response, 'data', {});
2053
+ return this.parseOrder (data, market);
2054
+ }
2055
+
2056
+ async cancelOrder (id, symbol = undefined, params = {}) {
2057
+ if (symbol === undefined) {
2058
+ throw new ArgumentsRequired (this.id + ' cancelOrder() requires a symbol argument');
2059
+ }
2060
+ await this.loadMarkets ();
2061
+ const market = this.market (symbol);
2062
+ const request = {
2063
+ 'symbol': market['id'],
2064
+ };
2065
+ const clientOrderId = this.safeString2 (params, 'clientOrderId', 'clOrdID');
2066
+ params = this.omit (params, [ 'clientOrderId', 'clOrdID' ]);
2067
+ if (clientOrderId !== undefined) {
2068
+ request['clOrdID'] = clientOrderId;
2069
+ } else {
2070
+ request['orderID'] = id;
2071
+ }
2072
+ const method = market['spot'] ? 'privateDeleteSpotOrders' : 'privateDeleteOrdersCancel';
2073
+ const response = await this[method] (this.extend (request, params));
2074
+ const data = this.safeValue (response, 'data', {});
2075
+ return this.parseOrder (data, market);
2076
+ }
2077
+
2078
+ async cancelAllOrders (symbol = undefined, params = {}) {
2079
+ if (symbol === undefined) {
2080
+ throw new ArgumentsRequired (this.id + ' cancelOrder() requires a symbol argument');
2081
+ }
2082
+ await this.loadMarkets ();
2083
+ const request = {
2084
+ // 'symbol': market['id'],
2085
+ // 'untriggerred': false, // false to cancel non-conditional orders, true to cancel conditional orders
2086
+ // 'text': 'up to 40 characters max',
2087
+ };
2088
+ const market = this.market (symbol);
2089
+ let method = 'privateDeleteSpotOrdersAll';
2090
+ if (market['swap']) {
2091
+ method = 'privateDeleteOrdersAll';
2092
+ }
2093
+ request['symbol'] = market['id'];
2094
+ return await this[method] (this.extend (request, params));
2095
+ }
2096
+
2097
+ async fetchOrder (id, symbol = undefined, params = {}) {
2098
+ if (symbol === undefined) {
2099
+ throw new ArgumentsRequired (this.id + ' fetchOrder() requires a symbol argument');
2100
+ }
2101
+ await this.loadMarkets ();
2102
+ const market = this.market (symbol);
2103
+ const method = market['spot'] ? 'privateGetSpotOrdersActive' : 'privateGetExchangeOrder';
2104
+ const request = {
2105
+ 'symbol': market['id'],
2106
+ };
2107
+ const clientOrderId = this.safeString2 (params, 'clientOrderId', 'clOrdID');
2108
+ params = this.omit (params, [ 'clientOrderId', 'clOrdID' ]);
2109
+ if (clientOrderId !== undefined) {
2110
+ request['clOrdID'] = clientOrderId;
2111
+ } else {
2112
+ request['orderID'] = id;
2113
+ }
2114
+ const response = await this[method] (this.extend (request, params));
2115
+ const data = this.safeValue (response, 'data', {});
2116
+ let order = data;
2117
+ if (Array.isArray (data)) {
2118
+ const numOrders = data.length;
2119
+ if (numOrders < 1) {
2120
+ if (clientOrderId !== undefined) {
2121
+ throw new OrderNotFound (this.id + ' fetchOrder() ' + symbol + ' order with clientOrderId ' + clientOrderId + ' not found');
2122
+ } else {
2123
+ throw new OrderNotFound (this.id + ' fetchOrder() ' + symbol + ' order with id ' + id + ' not found');
2124
+ }
2125
+ }
2126
+ order = this.safeValue (data, 0, {});
2127
+ }
2128
+ return this.parseOrder (order, market);
2129
+ }
2130
+
2131
+ async fetchOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) {
2132
+ if (symbol === undefined) {
2133
+ throw new ArgumentsRequired (this.id + ' fetchOrders() requires a symbol argument');
2134
+ }
2135
+ await this.loadMarkets ();
2136
+ const market = this.market (symbol);
2137
+ const method = market['spot'] ? 'privateGetSpotOrders' : 'privateGetExchangeOrderList';
2138
+ const request = {
2139
+ 'symbol': market['id'],
2140
+ };
2141
+ if (since !== undefined) {
2142
+ request['start'] = since;
2143
+ }
2144
+ if (limit !== undefined) {
2145
+ request['limit'] = limit;
2146
+ }
2147
+ const response = await this[method] (this.extend (request, params));
2148
+ const data = this.safeValue (response, 'data', {});
2149
+ const rows = this.safeValue (data, 'rows', []);
2150
+ return this.parseOrders (rows, market, since, limit);
2151
+ }
2152
+
2153
+ async fetchOpenOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) {
2154
+ if (symbol === undefined) {
2155
+ throw new ArgumentsRequired (this.id + ' fetchOpenOrders() requires a symbol argument');
2156
+ }
2157
+ await this.loadMarkets ();
2158
+ const market = this.market (symbol);
2159
+ const method = market['spot'] ? 'privateGetSpotOrders' : 'privateGetOrdersActiveList';
2160
+ const request = {
2161
+ 'symbol': market['id'],
2162
+ };
2163
+ let response = undefined;
2164
+ try {
2165
+ response = await this[method] (this.extend (request, params));
2166
+ } catch (e) {
2167
+ if (e instanceof OrderNotFound) {
2168
+ return [];
2169
+ }
2170
+ }
2171
+ const data = this.safeValue (response, 'data', {});
2172
+ if (Array.isArray (data)) {
2173
+ return this.parseOrders (data, market, since, limit);
2174
+ } else {
2175
+ const rows = this.safeValue (data, 'rows', []);
2176
+ return this.parseOrders (rows, market, since, limit);
2177
+ }
2178
+ }
2179
+
2180
+ async fetchClosedOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) {
2181
+ if (symbol === undefined) {
2182
+ throw new ArgumentsRequired (this.id + ' fetchClosedOrders() requires a symbol argument');
2183
+ }
2184
+ await this.loadMarkets ();
2185
+ const market = this.market (symbol);
2186
+ const method = market['spot'] ? 'privateGetExchangeSpotOrder' : 'privateGetExchangeOrderList';
2187
+ const request = {
2188
+ 'symbol': market['id'],
2189
+ };
2190
+ if (since !== undefined) {
2191
+ request['start'] = since;
2192
+ }
2193
+ if (limit !== undefined) {
2194
+ request['limit'] = limit;
2195
+ }
2196
+ const response = await this[method] (this.extend (request, params));
2197
+ //
2198
+ // spot
2199
+ //
2200
+ // {
2201
+ // "code":0,
2202
+ // "msg":"OK",
2203
+ // "data":{
2204
+ // "total":8,
2205
+ // "rows":[
2206
+ // {
2207
+ // "orderID":"99232c3e-3d6a-455f-98cc-2061cdfe91bc",
2208
+ // "stopPxEp":0,
2209
+ // "avgPriceEp":0,
2210
+ // "qtyType":"ByBase",
2211
+ // "leavesBaseQtyEv":0,
2212
+ // "leavesQuoteQtyEv":0,
2213
+ // "baseQtyEv":"1000000000",
2214
+ // "feeCurrency":"4",
2215
+ // "stopDirection":"UNSPECIFIED",
2216
+ // "symbol":"sETHUSDT",
2217
+ // "side":"Buy",
2218
+ // "quoteQtyEv":250000000000,
2219
+ // "priceEp":25000000000,
2220
+ // "ordType":"Limit",
2221
+ // "timeInForce":"GoodTillCancel",
2222
+ // "ordStatus":"Rejected",
2223
+ // "execStatus":"NewRejected",
2224
+ // "createTimeNs":1592675305266037130,
2225
+ // "cumFeeEv":0,
2226
+ // "cumBaseValueEv":0,
2227
+ // "cumQuoteValueEv":0
2228
+ // },
2229
+ // ]
2230
+ // }
2231
+ // }
2232
+ //
2233
+ const data = this.safeValue (response, 'data', {});
2234
+ if (Array.isArray (data)) {
2235
+ return this.parseOrders (data, market, since, limit);
2236
+ } else {
2237
+ const rows = this.safeValue (data, 'rows', []);
2238
+ return this.parseOrders (rows, market, since, limit);
2239
+ }
2240
+ }
2241
+
2242
+ async fetchMyTrades (symbol = undefined, since = undefined, limit = undefined, params = {}) {
2243
+ if (symbol === undefined) {
2244
+ throw new ArgumentsRequired (this.id + ' fetchMyTrades() requires a symbol argument');
2245
+ }
2246
+ await this.loadMarkets ();
2247
+ const market = this.market (symbol);
2248
+ const method = market['spot'] ? 'privateGetExchangeSpotOrderTrades' : 'privateGetExchangeOrderTrade';
2249
+ const request = {
2250
+ 'symbol': market['id'],
2251
+ };
2252
+ if (since !== undefined) {
2253
+ request['start'] = since;
2254
+ }
2255
+ if (market['swap'] && (limit !== undefined)) {
2256
+ request['limit'] = limit;
2257
+ }
2258
+ const response = await this[method] (this.extend (request, params));
2259
+ //
2260
+ // spot
2261
+ //
2262
+ // {
2263
+ // "code": 0,
2264
+ // "msg": "OK",
2265
+ // "data": {
2266
+ // "total": 1,
2267
+ // "rows": [
2268
+ // {
2269
+ // "qtyType": "ByQuote",
2270
+ // "transactTimeNs": 1589450974800550100,
2271
+ // "clOrdID": "8ba59d40-df25-d4b0-14cf-0703f44e9690",
2272
+ // "orderID": "b2b7018d-f02f-4c59-b4cf-051b9c2d2e83",
2273
+ // "symbol": "sBTCUSDT",
2274
+ // "side": "Buy",
2275
+ // "priceEP": 970056000000,
2276
+ // "baseQtyEv": 0,
2277
+ // "quoteQtyEv": 1000000000,
2278
+ // "action": "New",
2279
+ // "execStatus": "MakerFill",
2280
+ // "ordStatus": "Filled",
2281
+ // "ordType": "Limit",
2282
+ // "execInst": "None",
2283
+ // "timeInForce": "GoodTillCancel",
2284
+ // "stopDirection": "UNSPECIFIED",
2285
+ // "tradeType": "Trade",
2286
+ // "stopPxEp": 0,
2287
+ // "execId": "c6bd8979-07ba-5946-b07e-f8b65135dbb1",
2288
+ // "execPriceEp": 970056000000,
2289
+ // "execBaseQtyEv": 103000,
2290
+ // "execQuoteQtyEv": 999157680,
2291
+ // "leavesBaseQtyEv": 0,
2292
+ // "leavesQuoteQtyEv": 0,
2293
+ // "execFeeEv": 0,
2294
+ // "feeRateEr": 0
2295
+ // }
2296
+ // ]
2297
+ // }
2298
+ // }
2299
+ //
2300
+ //
2301
+ // swap
2302
+ //
2303
+ // {
2304
+ // "code": 0,
2305
+ // "msg": "OK",
2306
+ // "data": {
2307
+ // "total": 79,
2308
+ // "rows": [
2309
+ // {
2310
+ // "transactTimeNs": 1606054879331565300,
2311
+ // "symbol": "BTCUSD",
2312
+ // "currency": "BTC",
2313
+ // "action": "New",
2314
+ // "side": "Buy",
2315
+ // "tradeType": "Trade",
2316
+ // "execQty": 5,
2317
+ // "execPriceEp": 182990000,
2318
+ // "orderQty": 5,
2319
+ // "priceEp": 183870000,
2320
+ // "execValueEv": 27323,
2321
+ // "feeRateEr": 75000,
2322
+ // "execFeeEv": 21,
2323
+ // "ordType": "Market",
2324
+ // "execID": "5eee56a4-04a9-5677-8eb0-c2fe22ae3645",
2325
+ // "orderID": "ee0acb82-f712-4543-a11d-d23efca73197",
2326
+ // "clOrdID": "",
2327
+ // "execStatus": "TakerFill"
2328
+ // },
2329
+ // ]
2330
+ // }
2331
+ // }
2332
+ //
2333
+ const data = this.safeValue (response, 'data', {});
2334
+ const rows = this.safeValue (data, 'rows', []);
2335
+ return this.parseTrades (rows, market, since, limit);
2336
+ }
2337
+
2338
+ async fetchDepositAddress (code, params = {}) {
2339
+ await this.loadMarkets ();
2340
+ const currency = this.currency (code);
2341
+ const request = {
2342
+ 'currency': currency['id'],
2343
+ };
2344
+ const defaultNetworks = this.safeValue (this.options, 'defaultNetworks');
2345
+ const defaultNetwork = this.safeStringUpper (defaultNetworks, code);
2346
+ const networks = this.safeValue (this.options, 'networks', {});
2347
+ let network = this.safeStringUpper (params, 'network', defaultNetwork);
2348
+ network = this.safeString (networks, network, network);
2349
+ if (network === undefined) {
2350
+ request['chainName'] = currency['id'];
2351
+ } else {
2352
+ request['chainName'] = network;
2353
+ params = this.omit (params, 'network');
2354
+ }
2355
+ const response = await this.privateGetPhemexUserWalletsV2DepositAddress (this.extend (request, params));
2356
+ // {
2357
+ // "code":0,
2358
+ // "msg":"OK",
2359
+ // "data":{
2360
+ // "address":"0x5bfbf60e0fa7f63598e6cfd8a7fd3ffac4ccc6ad",
2361
+ // "tag":null
2362
+ // }
2363
+ // }
2364
+ //
2365
+ const data = this.safeValue (response, 'data', {});
2366
+ const address = this.safeString (data, 'address');
2367
+ const tag = this.safeString (data, 'tag');
2368
+ this.checkAddress (address);
2369
+ return {
2370
+ 'currency': code,
2371
+ 'address': address,
2372
+ 'tag': tag,
2373
+ 'network': undefined,
2374
+ 'info': response,
2375
+ };
2376
+ }
2377
+
2378
+ async fetchDeposits (code = undefined, since = undefined, limit = undefined, params = {}) {
2379
+ await this.loadMarkets ();
2380
+ let currency = undefined;
2381
+ if (code !== undefined) {
2382
+ currency = this.currency (code);
2383
+ }
2384
+ const response = await this.privateGetExchangeWalletsDepositList (params);
2385
+ //
2386
+ // {
2387
+ // "code":0,
2388
+ // "msg":"OK",
2389
+ // "data":[
2390
+ // {
2391
+ // "id":29200,
2392
+ // "currency":"USDT",
2393
+ // "currencyCode":3,
2394
+ // "txHash":"0x0bdbdc47807769a03b158d5753f54dfc58b92993d2f5e818db21863e01238e5d",
2395
+ // "address":"0x5bfbf60e0fa7f63598e6cfd8a7fd3ffac4ccc6ad",
2396
+ // "amountEv":3000000000,
2397
+ // "confirmations":13,
2398
+ // "type":"Deposit",
2399
+ // "status":"Success",
2400
+ // "createdAt":1592722565000
2401
+ // }
2402
+ // ]
2403
+ // }
2404
+ //
2405
+ const data = this.safeValue (response, 'data', {});
2406
+ return this.parseTransactions (data, currency, since, limit);
2407
+ }
2408
+
2409
+ async fetchWithdrawals (code = undefined, since = undefined, limit = undefined, params = {}) {
2410
+ await this.loadMarkets ();
2411
+ let currency = undefined;
2412
+ if (code !== undefined) {
2413
+ currency = this.currency (code);
2414
+ }
2415
+ const response = await this.privateGetExchangeWalletsWithdrawList (params);
2416
+ //
2417
+ // {
2418
+ // "code":0,
2419
+ // "msg":"OK",
2420
+ // "data":[
2421
+ // {
2422
+ // "address": "1Lxxxxxxxxxxx"
2423
+ // "amountEv": 200000
2424
+ // "currency": "BTC"
2425
+ // "currencyCode": 1
2426
+ // "expiredTime": 0
2427
+ // "feeEv": 50000
2428
+ // "rejectReason": null
2429
+ // "status": "Succeed"
2430
+ // "txHash": "44exxxxxxxxxxxxxxxxxxxxxx"
2431
+ // "withdrawStatus: ""
2432
+ // }
2433
+ // ]
2434
+ // }
2435
+ //
2436
+ const data = this.safeValue (response, 'data', {});
2437
+ return this.parseTransactions (data, currency, since, limit);
2438
+ }
2439
+
2440
+ parseTransactionStatus (status) {
2441
+ const statuses = {
2442
+ 'Success': 'ok',
2443
+ 'Succeed': 'ok',
2444
+ };
2445
+ return this.safeString (statuses, status, status);
2446
+ }
2447
+
2448
+ parseTransaction (transaction, currency = undefined) {
2449
+ //
2450
+ // withdraw
2451
+ //
2452
+ // ...
2453
+ //
2454
+ // fetchDeposits
2455
+ //
2456
+ // {
2457
+ // "id":29200,
2458
+ // "currency":"USDT",
2459
+ // "currencyCode":3,
2460
+ // "txHash":"0x0bdbdc47807769a03b158d5753f54dfc58b92993d2f5e818db21863e01238e5d",
2461
+ // "address":"0x5bfbf60e0fa7f63598e6cfd8a7fd3ffac4ccc6ad",
2462
+ // "amountEv":3000000000,
2463
+ // "confirmations":13,
2464
+ // "type":"Deposit",
2465
+ // "status":"Success",
2466
+ // "createdAt":1592722565000
2467
+ // }
2468
+ //
2469
+ // fetchWithdrawals
2470
+ //
2471
+ // {
2472
+ // "address": "1Lxxxxxxxxxxx"
2473
+ // "amountEv": 200000
2474
+ // "currency": "BTC"
2475
+ // "currencyCode": 1
2476
+ // "expiredTime": 0
2477
+ // "feeEv": 50000
2478
+ // "rejectReason": null
2479
+ // "status": "Succeed"
2480
+ // "txHash": "44exxxxxxxxxxxxxxxxxxxxxx"
2481
+ // "withdrawStatus: ""
2482
+ // }
2483
+ //
2484
+ const id = this.safeString (transaction, 'id');
2485
+ const address = this.safeString (transaction, 'address');
2486
+ const tag = undefined;
2487
+ const txid = this.safeString (transaction, 'txHash');
2488
+ const currencyId = this.safeString (transaction, 'currency');
2489
+ currency = this.safeCurrency (currencyId, currency);
2490
+ const code = currency['code'];
2491
+ const timestamp = this.safeInteger2 (transaction, 'createdAt', 'submitedAt');
2492
+ let type = this.safeStringLower (transaction, 'type');
2493
+ const feeCost = this.parseNumber (this.fromEn (this.safeString (transaction, 'feeEv'), currency['valueScale']));
2494
+ let fee = undefined;
2495
+ if (feeCost !== undefined) {
2496
+ type = 'withdrawal';
2497
+ fee = {
2498
+ 'cost': feeCost,
2499
+ 'currency': code,
2500
+ };
2501
+ }
2502
+ const status = this.parseTransactionStatus (this.safeString (transaction, 'status'));
2503
+ const amount = this.parseNumber (this.fromEn (this.safeString (transaction, 'amountEv'), currency['valueScale']));
2504
+ return {
2505
+ 'info': transaction,
2506
+ 'id': id,
2507
+ 'txid': txid,
2508
+ 'timestamp': timestamp,
2509
+ 'datetime': this.iso8601 (timestamp),
2510
+ 'network': undefined,
2511
+ 'address': address,
2512
+ 'addressTo': address,
2513
+ 'addressFrom': undefined,
2514
+ 'tag': tag,
2515
+ 'tagTo': tag,
2516
+ 'tagFrom': undefined,
2517
+ 'type': type,
2518
+ 'amount': amount,
2519
+ 'currency': code,
2520
+ 'status': status,
2521
+ 'updated': undefined,
2522
+ 'fee': fee,
2523
+ };
2524
+ }
2525
+
2526
+ async fetchPositions (symbols = undefined, params = {}) {
2527
+ await this.loadMarkets ();
2528
+ const defaultSubType = this.safeString (this.options, 'defaultSubType', 'linear');
2529
+ let code = this.safeString (params, 'code');
2530
+ if (code === undefined) {
2531
+ code = (defaultSubType === 'linear') ? 'USD' : 'BTC';
2532
+ } else {
2533
+ params = this.omit (params, 'code');
2534
+ }
2535
+ const currency = this.currency (code);
2536
+ const request = {
2537
+ 'currency': currency['id'],
2538
+ };
2539
+ const response = await this.privateGetAccountsAccountPositions (this.extend (request, params));
2540
+ //
2541
+ // {
2542
+ // "code":0,"msg":"",
2543
+ // "data":{
2544
+ // "account":{
2545
+ // "accountId":6192120001,
2546
+ // "currency":"BTC",
2547
+ // "accountBalanceEv":1254744,
2548
+ // "totalUsedBalanceEv":0,
2549
+ // "bonusBalanceEv":1254744
2550
+ // },
2551
+ // "positions":[
2552
+ // {
2553
+ // "accountID":6192120001,
2554
+ // "symbol":"BTCUSD",
2555
+ // "currency":"BTC",
2556
+ // "side":"None",
2557
+ // "positionStatus":"Normal",
2558
+ // "crossMargin":false,
2559
+ // "leverageEr":100000000,
2560
+ // "leverage":1.00000000,
2561
+ // "initMarginReqEr":100000000,
2562
+ // "initMarginReq":1.00000000,
2563
+ // "maintMarginReqEr":500000,
2564
+ // "maintMarginReq":0.00500000,
2565
+ // "riskLimitEv":10000000000,
2566
+ // "riskLimit":100.00000000,
2567
+ // "size":0,
2568
+ // "value":0E-8,
2569
+ // "valueEv":0,
2570
+ // "avgEntryPriceEp":0,
2571
+ // "avgEntryPrice":0E-8,
2572
+ // "posCostEv":0,
2573
+ // "posCost":0E-8,
2574
+ // "assignedPosBalanceEv":0,
2575
+ // "assignedPosBalance":0E-8,
2576
+ // "bankruptCommEv":0,
2577
+ // "bankruptComm":0E-8,
2578
+ // "bankruptPriceEp":0,
2579
+ // "bankruptPrice":0E-8,
2580
+ // "positionMarginEv":0,
2581
+ // "positionMargin":0E-8,
2582
+ // "liquidationPriceEp":0,
2583
+ // "liquidationPrice":0E-8,
2584
+ // "deleveragePercentileEr":0,
2585
+ // "deleveragePercentile":0E-8,
2586
+ // "buyValueToCostEr":100225000,
2587
+ // "buyValueToCost":1.00225000,
2588
+ // "sellValueToCostEr":100075000,
2589
+ // "sellValueToCost":1.00075000,
2590
+ // "markPriceEp":135736070,
2591
+ // "markPrice":13573.60700000,
2592
+ // "markValueEv":0,
2593
+ // "markValue":null,
2594
+ // "unRealisedPosLossEv":0,
2595
+ // "unRealisedPosLoss":null,
2596
+ // "estimatedOrdLossEv":0,
2597
+ // "estimatedOrdLoss":0E-8,
2598
+ // "usedBalanceEv":0,
2599
+ // "usedBalance":0E-8,
2600
+ // "takeProfitEp":0,
2601
+ // "takeProfit":null,
2602
+ // "stopLossEp":0,
2603
+ // "stopLoss":null,
2604
+ // "cumClosedPnlEv":0,
2605
+ // "cumFundingFeeEv":0,
2606
+ // "cumTransactFeeEv":0,
2607
+ // "realisedPnlEv":0,
2608
+ // "realisedPnl":null,
2609
+ // "cumRealisedPnlEv":0,
2610
+ // "cumRealisedPnl":null
2611
+ // }
2612
+ // ]
2613
+ // }
2614
+ // }
2615
+ //
2616
+ const data = this.safeValue (response, 'data', {});
2617
+ const positions = this.safeValue (data, 'positions', []);
2618
+ const result = [];
2619
+ for (let i = 0; i < positions.length; i++) {
2620
+ const position = positions[i];
2621
+ result.push (this.parsePosition (position));
2622
+ }
2623
+ return this.filterByArray (result, 'symbol', symbols, false);
2624
+ }
2625
+
2626
+ parsePosition (position, market = undefined) {
2627
+ //
2628
+ // {
2629
+ // userID: '811370',
2630
+ // accountID: '8113700002',
2631
+ // symbol: 'ETHUSD',
2632
+ // currency: 'USD',
2633
+ // side: 'Buy',
2634
+ // positionStatus: 'Normal',
2635
+ // crossMargin: false,
2636
+ // leverageEr: '200000000',
2637
+ // leverage: '2.00000000',
2638
+ // initMarginReqEr: '50000000',
2639
+ // initMarginReq: '0.50000000',
2640
+ // maintMarginReqEr: '1000000',
2641
+ // maintMarginReq: '0.01000000',
2642
+ // riskLimitEv: '5000000000',
2643
+ // riskLimit: '500000.00000000',
2644
+ // size: '1',
2645
+ // value: '22.22370000',
2646
+ // valueEv: '222237',
2647
+ // avgEntryPriceEp: '44447400',
2648
+ // avgEntryPrice: '4444.74000000',
2649
+ // posCostEv: '111202',
2650
+ // posCost: '11.12020000',
2651
+ // assignedPosBalanceEv: '111202',
2652
+ // assignedPosBalance: '11.12020000',
2653
+ // bankruptCommEv: '84',
2654
+ // bankruptComm: '0.00840000',
2655
+ // bankruptPriceEp: '22224000',
2656
+ // bankruptPrice: '2222.40000000',
2657
+ // positionMarginEv: '111118',
2658
+ // positionMargin: '11.11180000',
2659
+ // liquidationPriceEp: '22669000',
2660
+ // liquidationPrice: '2266.90000000',
2661
+ // deleveragePercentileEr: '0',
2662
+ // deleveragePercentile: '0E-8',
2663
+ // buyValueToCostEr: '50112500',
2664
+ // buyValueToCost: '0.50112500',
2665
+ // sellValueToCostEr: '50187500',
2666
+ // sellValueToCost: '0.50187500',
2667
+ // markPriceEp: '31332499',
2668
+ // markPrice: '3133.24990000',
2669
+ // markValueEv: '0',
2670
+ // markValue: null,
2671
+ // unRealisedPosLossEv: '0',
2672
+ // unRealisedPosLoss: null,
2673
+ // estimatedOrdLossEv: '0',
2674
+ // estimatedOrdLoss: '0E-8',
2675
+ // usedBalanceEv: '111202',
2676
+ // usedBalance: '11.12020000',
2677
+ // takeProfitEp: '0',
2678
+ // takeProfit: null,
2679
+ // stopLossEp: '0',
2680
+ // stopLoss: null,
2681
+ // cumClosedPnlEv: '-1546',
2682
+ // cumFundingFeeEv: '1605',
2683
+ // cumTransactFeeEv: '8438',
2684
+ // realisedPnlEv: '0',
2685
+ // realisedPnl: null,
2686
+ // cumRealisedPnlEv: '0',
2687
+ // cumRealisedPnl: null,
2688
+ // transactTimeNs: '1641571200001885324',
2689
+ // takerFeeRateEr: '0',
2690
+ // makerFeeRateEr: '0',
2691
+ // term: '6',
2692
+ // lastTermEndTimeNs: '1607711882505745356',
2693
+ // lastFundingTimeNs: '1641571200000000000',
2694
+ // curTermRealisedPnlEv: '-1567',
2695
+ // execSeq: '12112761561'
2696
+ // }
2697
+ //
2698
+ const marketId = this.safeString (position, 'symbol');
2699
+ market = this.safeMarket (marketId, market);
2700
+ const symbol = market['symbol'];
2701
+ const collateral = this.safeString (position, 'positionMargin');
2702
+ const notionalString = this.safeString (position, 'value');
2703
+ const maintenanceMarginPercentageString = this.safeString (position, 'maintMarginReq');
2704
+ const maintenanceMarginString = Precise.stringMul (notionalString, maintenanceMarginPercentageString);
2705
+ const initialMarginString = this.safeString (position, 'assignedPosBalance');
2706
+ const initialMarginPercentageString = Precise.stringDiv (initialMarginString, notionalString);
2707
+ const liquidationPrice = this.safeNumber (position, 'liquidationPrice');
2708
+ const markPriceString = this.safeString (position, 'markPrice');
2709
+ const contracts = this.safeString (position, 'size');
2710
+ const contractSize = this.safeValue (market, 'contractSize');
2711
+ const contractSizeString = this.numberToString (contractSize);
2712
+ const leverage = this.safeNumber (position, 'leverage');
2713
+ const entryPriceString = this.safeString (position, 'avgEntryPrice');
2714
+ const rawSide = this.safeString (position, 'side');
2715
+ const side = (rawSide === 'Buy') ? 'long' : 'short';
2716
+ let priceDiff = undefined;
2717
+ const currency = this.safeString (position, 'currency');
2718
+ if (currency === 'USD') {
2719
+ if (side === 'long') {
2720
+ priceDiff = Precise.stringSub (markPriceString, entryPriceString);
2721
+ } else {
2722
+ priceDiff = Precise.stringSub (entryPriceString, markPriceString);
2723
+ }
2724
+ } else {
2725
+ // inverse
2726
+ if (side === 'long') {
2727
+ priceDiff = Precise.stringSub (Precise.stringDiv ('1', entryPriceString), Precise.stringDiv ('1', markPriceString));
2728
+ } else {
2729
+ priceDiff = Precise.stringSub (Precise.stringDiv ('1', markPriceString), Precise.stringDiv ('1', entryPriceString));
2730
+ }
2731
+ }
2732
+ const unrealizedPnl = Precise.stringMul (Precise.stringMul (priceDiff, contracts), contractSizeString);
2733
+ const percentage = Precise.stringMul (Precise.stringDiv (unrealizedPnl, initialMarginString), '100');
2734
+ const marginRatio = Precise.stringDiv (maintenanceMarginString, collateral);
2735
+ return {
2736
+ 'info': position,
2737
+ 'symbol': symbol,
2738
+ 'contracts': this.parseNumber (contracts),
2739
+ 'contractSize': contractSize,
2740
+ 'unrealizedPnl': this.parseNumber (unrealizedPnl),
2741
+ 'leverage': leverage,
2742
+ 'liquidationPrice': liquidationPrice,
2743
+ 'collateral': this.parseNumber (collateral),
2744
+ 'notional': this.parseNumber (notionalString),
2745
+ 'markPrice': this.parseNumber (markPriceString), // markPrice lags a bit ¯\_(ツ)_/¯
2746
+ 'entryPrice': this.parseNumber (entryPriceString),
2747
+ 'timestamp': undefined,
2748
+ 'initialMargin': this.parseNumber (initialMarginString),
2749
+ 'initialMarginPercentage': this.parseNumber (initialMarginPercentageString),
2750
+ 'maintenanceMargin': this.parseNumber (maintenanceMarginString),
2751
+ 'maintenanceMarginPercentage': this.parseNumber (maintenanceMarginPercentageString),
2752
+ 'marginRatio': this.parseNumber (marginRatio),
2753
+ 'datetime': undefined,
2754
+ 'marginType': undefined,
2755
+ 'side': side,
2756
+ 'hedged': false,
2757
+ 'percentage': this.parseNumber (percentage),
2758
+ };
2759
+ }
2760
+
2761
+ sign (path, api = 'public', method = 'GET', params = {}, headers = undefined, body = undefined) {
2762
+ const query = this.omit (params, this.extractParams (path));
2763
+ const requestPath = '/' + this.implodeParams (path, params);
2764
+ let url = requestPath;
2765
+ let queryString = '';
2766
+ if ((method === 'GET') || (method === 'DELETE') || (method === 'PUT')) {
2767
+ if (Object.keys (query).length) {
2768
+ queryString = this.urlencodeWithArrayRepeat (query);
2769
+ url += '?' + queryString;
2770
+ }
2771
+ }
2772
+ if (api === 'private') {
2773
+ this.checkRequiredCredentials ();
2774
+ const timestamp = this.seconds ();
2775
+ const xPhemexRequestExpiry = this.safeInteger (this.options, 'x-phemex-request-expiry', 60);
2776
+ const expiry = this.sum (timestamp, xPhemexRequestExpiry);
2777
+ const expiryString = expiry.toString ();
2778
+ headers = {
2779
+ 'x-phemex-access-token': this.apiKey,
2780
+ 'x-phemex-request-expiry': expiryString,
2781
+ };
2782
+ let payload = '';
2783
+ if (method === 'POST') {
2784
+ payload = this.json (params);
2785
+ body = payload;
2786
+ headers['Content-Type'] = 'application/json';
2787
+ }
2788
+ const auth = requestPath + queryString + expiryString + payload;
2789
+ headers['x-phemex-request-signature'] = this.hmac (this.encode (auth), this.encode (this.secret));
2790
+ }
2791
+ url = this.implodeHostname (this.urls['api'][api]) + url;
2792
+ return { 'url': url, 'method': method, 'body': body, 'headers': headers };
2793
+ }
2794
+
2795
+ async setLeverage (leverage, symbol = undefined, params = {}) {
2796
+ // WARNING: THIS WILL INCREASE LIQUIDATION PRICE FOR OPEN ISOLATED LONG POSITIONS
2797
+ // AND DECREASE LIQUIDATION PRICE FOR OPEN ISOLATED SHORT POSITIONS
2798
+ if (symbol === undefined) {
2799
+ throw new ArgumentsRequired (this.id + ' setLeverage() requires a symbol argument');
2800
+ }
2801
+ if ((leverage < 1) || (leverage > 100)) {
2802
+ throw new BadRequest (this.id + ' setLeverage() leverage should be between 1 and 100');
2803
+ }
2804
+ await this.loadMarkets ();
2805
+ const market = this.market (symbol);
2806
+ const request = {
2807
+ 'symbol': market['id'],
2808
+ 'leverage': leverage,
2809
+ };
2810
+ return await this.privatePutPositionsLeverage (this.extend (request, params));
2811
+ }
2812
+
2813
+ async transfer (code, amount, fromAccount, toAccount, params = {}) {
2814
+ await this.loadMarkets ();
2815
+ const currency = this.currency (code);
2816
+ const accountsByType = this.safeValue (this.options, 'accountsByType', {});
2817
+ const fromId = this.safeString (accountsByType, fromAccount, fromAccount);
2818
+ const toId = this.safeString (accountsByType, toAccount, toAccount);
2819
+ const scaledAmmount = this.toEv (amount, currency);
2820
+ let direction = undefined;
2821
+ let transfer = undefined;
2822
+ if (fromId === 'spot' && toId === 'future') {
2823
+ direction = 2;
2824
+ } else if (fromId === 'future' && toId === 'spot') {
2825
+ direction = 1;
2826
+ }
2827
+ if (direction !== undefined) {
2828
+ const request = {
2829
+ 'currency': currency['id'],
2830
+ 'moveOp': direction,
2831
+ 'amountEv': scaledAmmount,
2832
+ };
2833
+ const response = await this.privatePostAssetsTransfer (this.extend (request, params));
2834
+ //
2835
+ // {
2836
+ // code: '0',
2837
+ // msg: 'OK',
2838
+ // data: {
2839
+ // linkKey: '8564eba4-c9ec-49d6-9b8c-2ec5001a0fb9',
2840
+ // userId: '4018340',
2841
+ // currency: 'USD',
2842
+ // amountEv: '10',
2843
+ // side: '2',
2844
+ // status: '10'
2845
+ // }
2846
+ // }
2847
+ //
2848
+ const data = this.safeValue (response, 'data', {});
2849
+ transfer = this.parseTransfer (data, currency);
2850
+ } else { // sub account transfer
2851
+ const request = {
2852
+ 'fromUserId': fromId,
2853
+ 'toUserId': toId,
2854
+ 'amountEv': scaledAmmount,
2855
+ 'currency': currency['id'],
2856
+ 'bizType': this.safeString (params, 'bizType', 'SPOT'),
2857
+ };
2858
+ const response = await this.privatePostAssetsUniversalTransfer (this.extend (request, params));
2859
+ //
2860
+ // {
2861
+ // code: '0',
2862
+ // msg: 'OK',
2863
+ // data: 'API-923db826-aaaa-aaaa-aaaa-4d98c3a7c9fd'
2864
+ // }
2865
+ //
2866
+ transfer = this.parseTransfer (response);
2867
+ }
2868
+ const transferOptions = this.safeValue (this.options, 'transfer', {});
2869
+ const fillResponseFromRequest = this.safeValue (transferOptions, 'fillResponseFromRequest', true);
2870
+ if (fillResponseFromRequest) {
2871
+ if (transfer['fromAccount'] === undefined) {
2872
+ transfer['fromAccount'] = fromAccount;
2873
+ }
2874
+ if (transfer['toAccount'] === undefined) {
2875
+ transfer['toAccount'] = toAccount;
2876
+ }
2877
+ if (transfer['amount'] === undefined) {
2878
+ transfer['amount'] = amount;
2879
+ }
2880
+ if (transfer['currency'] === undefined) {
2881
+ transfer['currency'] = code;
2882
+ }
2883
+ }
2884
+ return transfer;
2885
+ }
2886
+
2887
+ parseTransfer (transfer, currency = undefined) {
2888
+ //
2889
+ // {
2890
+ // linkKey: '8564eba4-c9ec-49d6-9b8c-2ec5001a0fb9',
2891
+ // userId: '4018340',
2892
+ // currency: 'USD',
2893
+ // amountEv: '10',
2894
+ // side: '2',
2895
+ // status: '10'
2896
+ // }
2897
+ //
2898
+ const id = this.safeString (transfer, 'linkKey');
2899
+ const status = this.safeString (transfer, 'status');
2900
+ const amountEv = this.safeString (transfer, 'amountEv');
2901
+ const amountTransfered = this.fromEv (amountEv, currency);
2902
+ const currencyId = this.safeString (transfer, 'currency');
2903
+ const code = this.safeCurrencyCode (currencyId, currency);
2904
+ const side = this.safeInteger (transfer, 'side');
2905
+ let fromId = undefined;
2906
+ let toId = undefined;
2907
+ if (side === 1) {
2908
+ fromId = 'future';
2909
+ toId = 'spot';
2910
+ } else if (side === 2) {
2911
+ fromId = 'spot';
2912
+ toId = 'future';
2913
+ }
2914
+ return {
2915
+ 'info': transfer,
2916
+ 'id': id,
2917
+ 'timestamp': undefined,
2918
+ 'datetime': undefined,
2919
+ 'currency': code,
2920
+ 'amount': amountTransfered,
2921
+ 'fromAccount': fromId,
2922
+ 'toAccount': toId,
2923
+ 'status': this.parseTransferStatus (status),
2924
+ };
2925
+ }
2926
+
2927
+ parseTransferStatus (status) {
2928
+ const statuses = {
2929
+ '3': 'rejected', // 'Rejected',
2930
+ '6': 'canceled', // 'Got error and wait for recovery',
2931
+ '10': 'ok', // 'Success',
2932
+ '11': 'failed', // 'Failed',
2933
+ };
2934
+ return this.safeString (statuses, status, status);
2935
+ }
2936
+
2937
+ handleErrors (httpCode, reason, url, method, headers, body, response, requestHeaders, requestBody) {
2938
+ if (response === undefined) {
2939
+ return; // fallback to default error handler
2940
+ }
2941
+ //
2942
+ // {"code":30018,"msg":"phemex.data.size.uplimt","data":null}
2943
+ // {"code":412,"msg":"Missing parameter - resolution","data":null}
2944
+ // {"code":412,"msg":"Missing parameter - to","data":null}
2945
+ // {"error":{"code":6001,"message":"invalid argument"},"id":null,"result":null}
2946
+ //
2947
+ const error = this.safeValue (response, 'error', response);
2948
+ const errorCode = this.safeString (error, 'code');
2949
+ const message = this.safeString (error, 'msg');
2950
+ if ((errorCode !== undefined) && (errorCode !== '0')) {
2951
+ const feedback = this.id + ' ' + body;
2952
+ this.throwExactlyMatchedException (this.exceptions['exact'], errorCode, feedback);
2953
+ this.throwBroadlyMatchedException (this.exceptions['broad'], message, feedback);
2954
+ throw new ExchangeError (feedback); // unknown message
2955
+ }
2956
+ }
2957
+ };