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
@@ -0,0 +1,2025 @@
1
+ 'use strict';
2
+
3
+ // ---------------------------------------------------------------------------
4
+
5
+ const bitfinex = require ('./bitfinex.js');
6
+ const { ExchangeError, InvalidAddress, ArgumentsRequired, InsufficientFunds, AuthenticationError, OrderNotFound, InvalidOrder, BadRequest, InvalidNonce, BadSymbol, OnMaintenance, NotSupported, PermissionDenied, ExchangeNotAvailable } = require ('./base/errors');
7
+ const Precise = require ('./base/Precise');
8
+
9
+ // ---------------------------------------------------------------------------
10
+
11
+ module.exports = class bitfinex2 extends bitfinex {
12
+ describe () {
13
+ return this.deepExtend (super.describe (), {
14
+ 'id': 'bitfinex2',
15
+ 'name': 'Bitfinex',
16
+ 'countries': [ 'VG' ],
17
+ 'version': 'v2',
18
+ 'certified': false,
19
+ 'pro': false,
20
+ // new metainfo interface
21
+ 'has': {
22
+ 'CORS': undefined,
23
+ 'spot': true,
24
+ 'margin': undefined, // has but unimplemented
25
+ 'swap': undefined, // has but unimplemented
26
+ 'future': undefined,
27
+ 'option': undefined,
28
+ 'cancelAllOrders': true,
29
+ 'cancelOrder': true,
30
+ 'createDepositAddress': true,
31
+ 'createLimitOrder': true,
32
+ 'createMarketOrder': true,
33
+ 'createOrder': true,
34
+ 'createStopLimitOrder': true,
35
+ 'createStopMarketOrder': true,
36
+ 'createStopOrder': true,
37
+ 'editOrder': undefined,
38
+ 'fetchBalance': true,
39
+ 'fetchClosedOrder': true,
40
+ 'fetchClosedOrders': true,
41
+ 'fetchCurrencies': true,
42
+ 'fetchDepositAddress': true,
43
+ 'fetchFundingFees': undefined,
44
+ 'fetchIndexOHLCV': false,
45
+ 'fetchLedger': true,
46
+ 'fetchMarkOHLCV': false,
47
+ 'fetchMyTrades': true,
48
+ 'fetchOHLCV': true,
49
+ 'fetchOpenOrder': true,
50
+ 'fetchOpenOrders': true,
51
+ 'fetchOrder': true,
52
+ 'fetchOrderTrades': true,
53
+ 'fetchStatus': true,
54
+ 'fetchTickers': true,
55
+ 'fetchTime': false,
56
+ 'fetchTradingFee': false,
57
+ 'fetchTradingFees': true,
58
+ 'fetchTransactions': true,
59
+ 'withdraw': true,
60
+ },
61
+ 'timeframes': {
62
+ '1m': '1m',
63
+ '5m': '5m',
64
+ '15m': '15m',
65
+ '30m': '30m',
66
+ '1h': '1h',
67
+ '3h': '3h',
68
+ '4h': '4h',
69
+ '6h': '6h',
70
+ '12h': '12h',
71
+ '1d': '1D',
72
+ '1w': '7D',
73
+ '2w': '14D',
74
+ '1M': '1M',
75
+ },
76
+ // cheapest endpoint is 240 requests per minute => ~ 4 requests per second => ( 1000ms / 4 ) = 250ms between requests on average
77
+ 'rateLimit': 250,
78
+ 'urls': {
79
+ 'logo': 'https://user-images.githubusercontent.com/1294454/27766244-e328a50c-5ed2-11e7-947b-041416579bb3.jpg',
80
+ 'api': {
81
+ 'v1': 'https://api.bitfinex.com',
82
+ 'public': 'https://api-pub.bitfinex.com',
83
+ 'private': 'https://api.bitfinex.com',
84
+ },
85
+ 'www': 'https://www.bitfinex.com',
86
+ 'doc': [
87
+ 'https://docs.bitfinex.com/v2/docs/',
88
+ 'https://github.com/bitfinexcom/bitfinex-api-node',
89
+ ],
90
+ 'fees': 'https://www.bitfinex.com/fees',
91
+ },
92
+ 'api': {
93
+ 'v1': {
94
+ 'get': [
95
+ 'symbols',
96
+ 'symbols_details',
97
+ ],
98
+ },
99
+ 'public': {
100
+ 'get': {
101
+ 'conf/{config}': 2.66, // 90 requests a minute
102
+ 'conf/pub:{action}:{object}': 2.66,
103
+ 'conf/pub:{action}:{object}:{detail}': 2.66,
104
+ 'conf/pub:map:{object}': 2.66,
105
+ 'conf/pub:map:{object}:{detail}': 2.66,
106
+ 'conf/pub:map:currency:{detail}': 2.66,
107
+ 'conf/pub:map:currency:sym': 2.66, // maps symbols to their API symbols, BAB > BCH
108
+ 'conf/pub:map:currency:label': 2.66, // verbose friendly names, BNT > Bancor
109
+ 'conf/pub:map:currency:unit': 2.66, // maps symbols to unit of measure where applicable
110
+ 'conf/pub:map:currency:undl': 2.66, // maps derivatives symbols to their underlying currency
111
+ 'conf/pub:map:currency:pool': 2.66, // maps symbols to underlying network/protocol they operate on
112
+ 'conf/pub:map:currency:explorer': 2.66, // maps symbols to their recognised block explorer URLs
113
+ 'conf/pub:map:currency:tx:fee': 2.66, // maps currencies to their withdrawal fees https://github.com/ccxt/ccxt/issues/7745
114
+ 'conf/pub:map:tx:method': 2.66,
115
+ 'conf/pub:list:{object}': 2.66,
116
+ 'conf/pub:list:{object}:{detail}': 2.66,
117
+ 'conf/pub:list:currency': 2.66,
118
+ 'conf/pub:list:pair:exchange': 2.66,
119
+ 'conf/pub:list:pair:margin': 2.66,
120
+ 'conf/pub:list:pair:futures': 2.66,
121
+ 'conf/pub:list:competitions': 2.66,
122
+ 'conf/pub:info:{object}': 2.66,
123
+ 'conf/pub:info:{object}:{detail}': 2.66,
124
+ 'conf/pub:info:pair': 2.66,
125
+ 'conf/pub:info:tx:status': 2.66, // [ deposit, withdrawal ] statuses 1 = active, 0 = maintenance
126
+ 'conf/pub:fees': 2.66,
127
+ 'platform/status': 8, // 30 requests per minute = 0.5 requests per second => ( 1000ms / rateLimit ) / 0.5 = 8
128
+ 'tickers': 2.66, // 90 requests a minute = 1.5 requests per second => ( 1000 / rateLimit ) / 1.5 = 2.666666666
129
+ 'ticker/{symbol}': 2.66,
130
+ 'tickers/hist': 2.66,
131
+ 'trades/{symbol}/hist': 2.66,
132
+ 'book/{symbol}/{precision}': 1, // 240 requests a minute
133
+ 'book/{symbol}/P0': 1,
134
+ 'book/{symbol}/P1': 1,
135
+ 'book/{symbol}/P2': 1,
136
+ 'book/{symbol}/P3': 1,
137
+ 'book/{symbol}/R0': 1,
138
+ 'stats1/{key}:{size}:{symbol}:{side}/{section}': 2.66,
139
+ 'stats1/{key}:{size}:{symbol}:{side}/last': 2.66,
140
+ 'stats1/{key}:{size}:{symbol}:{side}/hist': 2.66,
141
+ 'stats1/{key}:{size}:{symbol}/{section}': 2.66,
142
+ 'stats1/{key}:{size}:{symbol}/last': 2.66,
143
+ 'stats1/{key}:{size}:{symbol}/hist': 2.66,
144
+ 'stats1/{key}:{size}:{symbol}:long/last': 2.66,
145
+ 'stats1/{key}:{size}:{symbol}:long/hist': 2.66,
146
+ 'stats1/{key}:{size}:{symbol}:short/last': 2.66,
147
+ 'stats1/{key}:{size}:{symbol}:short/hist': 2.66,
148
+ 'candles/trade:{timeframe}:{symbol}:{period}/{section}': 2.66,
149
+ 'candles/trade:{timeframe}:{symbol}/{section}': 2.66,
150
+ 'candles/trade:{timeframe}:{symbol}/last': 2.66,
151
+ 'candles/trade:{timeframe}:{symbol}/hist': 2.66,
152
+ 'status/{type}': 2.66,
153
+ 'status/deriv': 2.66,
154
+ 'liquidations/hist': 80, // 3 requests a minute = 0.05 requests a second => ( 1000ms / rateLimit ) / 0.05 = 80
155
+ 'rankings/{key}:{timeframe}:{symbol}/{section}': 2.66,
156
+ 'rankings/{key}:{timeframe}:{symbol}/hist': 2.66,
157
+ 'pulse/hist': 2.66,
158
+ 'pulse/profile/{nickname}': 2.66,
159
+ 'funding/stats/{symbol}/hist': 10, // ratelimit not in docs
160
+ },
161
+ 'post': {
162
+ 'calc/trade/avg': 2.66,
163
+ 'calc/fx': 2.66,
164
+ },
165
+ },
166
+ 'private': {
167
+ 'post': {
168
+ // 'auth/r/orders/{symbol}/new', // outdated
169
+ // 'auth/r/stats/perf:{timeframe}/hist', // outdated
170
+ 'auth/r/wallets': 2.66,
171
+ 'auth/r/wallets/hist': 2.66,
172
+ 'auth/r/orders': 2.66,
173
+ 'auth/r/orders/{symbol}': 2.66,
174
+ 'auth/w/order/submit': 2.66,
175
+ 'auth/w/order/update': 2.66,
176
+ 'auth/w/order/cancel': 2.66,
177
+ 'auth/w/order/multi': 2.66,
178
+ 'auth/w/order/cancel/multi': 2.66,
179
+ 'auth/r/orders/{symbol}/hist': 2.66,
180
+ 'auth/r/orders/hist': 2.66,
181
+ 'auth/r/order/{symbol}:{id}/trades': 2.66,
182
+ 'auth/r/trades/{symbol}/hist': 2.66,
183
+ 'auth/r/trades/hist': 2.66,
184
+ 'auth/r/ledgers/{currency}/hist': 2.66,
185
+ 'auth/r/ledgers/hist': 2.66,
186
+ 'auth/r/info/margin/{key}': 2.66,
187
+ 'auth/r/info/margin/base': 2.66,
188
+ 'auth/r/info/margin/sym_all': 2.66,
189
+ 'auth/r/positions': 2.66,
190
+ 'auth/w/position/claim': 2.66,
191
+ 'auth/w/position/increase:': 2.66,
192
+ 'auth/r/position/increase/info': 2.66,
193
+ 'auth/r/positions/hist': 2.66,
194
+ 'auth/r/positions/audit': 2.66,
195
+ 'auth/r/positions/snap': 2.66,
196
+ 'auth/w/deriv/collateral/set': 2.66,
197
+ 'auth/w/deriv/collateral/limits': 2.66,
198
+ 'auth/r/funding/offers': 2.66,
199
+ 'auth/r/funding/offers/{symbol}': 2.66,
200
+ 'auth/w/funding/offer/submit': 2.66,
201
+ 'auth/w/funding/offer/cancel': 2.66,
202
+ 'auth/w/funding/offer/cancel/all': 2.66,
203
+ 'auth/w/funding/close': 2.66,
204
+ 'auth/w/funding/auto': 2.66,
205
+ 'auth/w/funding/keep': 2.66,
206
+ 'auth/r/funding/offers/{symbol}/hist': 2.66,
207
+ 'auth/r/funding/offers/hist': 2.66,
208
+ 'auth/r/funding/loans': 2.66,
209
+ 'auth/r/funding/loans/hist': 2.66,
210
+ 'auth/r/funding/loans/{symbol}': 2.66,
211
+ 'auth/r/funding/loans/{symbol}/hist': 2.66,
212
+ 'auth/r/funding/credits': 2.66,
213
+ 'auth/r/funding/credits/hist': 2.66,
214
+ 'auth/r/funding/credits/{symbol}': 2.66,
215
+ 'auth/r/funding/credits/{symbol}/hist': 2.66,
216
+ 'auth/r/funding/trades/{symbol}/hist': 2.66,
217
+ 'auth/r/funding/trades/hist': 2.66,
218
+ 'auth/r/info/funding/{key}': 2.66,
219
+ 'auth/r/info/user': 2.66,
220
+ 'auth/r/summary': 2.66,
221
+ 'auth/r/logins/hist': 2.66,
222
+ 'auth/r/permissions': 2.66,
223
+ 'auth/w/token': 2.66,
224
+ 'auth/r/audit/hist': 2.66,
225
+ 'auth/w/transfer': 2.66, // ratelimit not in docs...
226
+ 'auth/w/deposit/address': 24, // 10 requests a minute = 0.166 requests per second => ( 1000ms / rateLimit ) / 0.166 = 24
227
+ 'auth/w/deposit/invoice': 24, // ratelimit not in docs
228
+ 'auth/w/withdraw': 24, // ratelimit not in docs
229
+ 'auth/r/movements/{currency}/hist': 2.66,
230
+ 'auth/r/movements/hist': 2.66,
231
+ 'auth/r/alerts': 5.33, // 45 requests a minute = 0.75 requests per second => ( 1000ms / rateLimit ) / 0.75 => 5.33
232
+ 'auth/w/alert/set': 2.66,
233
+ 'auth/w/alert/price:{symbol}:{price}/del': 2.66,
234
+ 'auth/w/alert/{type}:{symbol}:{price}/del': 2.66,
235
+ 'auth/calc/order/avail': 2.66,
236
+ 'auth/w/settings/set': 2.66,
237
+ 'auth/r/settings': 2.66,
238
+ 'auth/w/settings/del': 2.66,
239
+ 'auth/r/pulse/hist': 2.66,
240
+ 'auth/w/pulse/add': 16, // 15 requests a minute = 0.25 requests per second => ( 1000ms / rateLimit ) / 0.25 => 16
241
+ 'auth/w/pulse/del': 2.66,
242
+ },
243
+ },
244
+ },
245
+ 'fees': {
246
+ 'trading': {
247
+ 'feeSide': 'get',
248
+ 'percentage': true,
249
+ 'tierBased': true,
250
+ 'maker': this.parseNumber ('0.001'),
251
+ 'taker': this.parseNumber ('0.002'),
252
+ 'tiers': {
253
+ 'taker': [
254
+ [ this.parseNumber ('0'), this.parseNumber ('0.002') ],
255
+ [ this.parseNumber ('500000'), this.parseNumber ('0.002') ],
256
+ [ this.parseNumber ('1000000'), this.parseNumber ('0.002') ],
257
+ [ this.parseNumber ('2500000'), this.parseNumber ('0.002') ],
258
+ [ this.parseNumber ('5000000'), this.parseNumber ('0.002') ],
259
+ [ this.parseNumber ('7500000'), this.parseNumber ('0.002') ],
260
+ [ this.parseNumber ('10000000'), this.parseNumber ('0.0018') ],
261
+ [ this.parseNumber ('15000000'), this.parseNumber ('0.0016') ],
262
+ [ this.parseNumber ('20000000'), this.parseNumber ('0.0014') ],
263
+ [ this.parseNumber ('25000000'), this.parseNumber ('0.0012') ],
264
+ [ this.parseNumber ('30000000'), this.parseNumber ('0.001') ],
265
+ ],
266
+ 'maker': [
267
+ [ this.parseNumber ('0'), this.parseNumber ('0.001') ],
268
+ [ this.parseNumber ('500000'), this.parseNumber ('0.0008') ],
269
+ [ this.parseNumber ('1000000'), this.parseNumber ('0.0006') ],
270
+ [ this.parseNumber ('2500000'), this.parseNumber ('0.0004') ],
271
+ [ this.parseNumber ('5000000'), this.parseNumber ('0.0002') ],
272
+ [ this.parseNumber ('7500000'), this.parseNumber ('0') ],
273
+ [ this.parseNumber ('10000000'), this.parseNumber ('0') ],
274
+ [ this.parseNumber ('15000000'), this.parseNumber ('0') ],
275
+ [ this.parseNumber ('20000000'), this.parseNumber ('0') ],
276
+ [ this.parseNumber ('25000000'), this.parseNumber ('0') ],
277
+ [ this.parseNumber ('30000000'), this.parseNumber ('0') ],
278
+ ],
279
+ },
280
+ },
281
+ 'funding': {
282
+ 'withdraw': {},
283
+ },
284
+ },
285
+ 'options': {
286
+ 'precision': 'R0', // P0, P1, P2, P3, P4, R0
287
+ // convert 'EXCHANGE MARKET' to lowercase 'market'
288
+ // convert 'EXCHANGE LIMIT' to lowercase 'limit'
289
+ // everything else remains uppercase
290
+ 'exchangeTypes': {
291
+ // 'MARKET': undefined,
292
+ 'EXCHANGE MARKET': 'market',
293
+ // 'LIMIT': undefined,
294
+ 'EXCHANGE LIMIT': 'limit',
295
+ // 'STOP': undefined,
296
+ // 'EXCHANGE STOP': undefined,
297
+ // 'TRAILING STOP': undefined,
298
+ // 'EXCHANGE TRAILING STOP': undefined,
299
+ // 'FOK': undefined,
300
+ // 'EXCHANGE FOK': undefined,
301
+ // 'STOP LIMIT': undefined,
302
+ // 'EXCHANGE STOP LIMIT': undefined,
303
+ // 'IOC': undefined,
304
+ // 'EXCHANGE IOC': undefined,
305
+ },
306
+ // convert 'market' to 'EXCHANGE MARKET'
307
+ // convert 'limit' 'EXCHANGE LIMIT'
308
+ // everything else remains as is
309
+ 'orderTypes': {
310
+ 'market': 'EXCHANGE MARKET',
311
+ 'limit': 'EXCHANGE LIMIT',
312
+ },
313
+ 'fiat': {
314
+ 'USD': 'USD',
315
+ 'EUR': 'EUR',
316
+ 'JPY': 'JPY',
317
+ 'GBP': 'GBP',
318
+ 'CHN': 'CHN',
319
+ },
320
+ // actually the correct names unlike the v1
321
+ // we don't want to extend this with accountsByType in v1
322
+ 'v2AccountsByType': {
323
+ 'spot': 'exchange',
324
+ 'exchange': 'exchange',
325
+ 'funding': 'funding',
326
+ 'margin': 'margin',
327
+ 'derivatives': 'margin',
328
+ 'future': 'margin',
329
+ },
330
+ 'swap': {
331
+ 'fetchMarkets': {
332
+ 'settlementCurrencies': [ 'BTC', 'USDT', 'EURT' ],
333
+ },
334
+ },
335
+ },
336
+ 'exceptions': {
337
+ 'exact': {
338
+ '10001': PermissionDenied, // api_key: permission invalid (#10001)
339
+ '10020': BadRequest,
340
+ '10100': AuthenticationError,
341
+ '10114': InvalidNonce,
342
+ '20060': OnMaintenance,
343
+ // {"code":503,"error":"temporarily_unavailable","error_description":"Sorry, the service is temporarily unavailable. See https://www.bitfinex.com/ for more info."}
344
+ 'temporarily_unavailable': ExchangeNotAvailable,
345
+ },
346
+ 'broad': {
347
+ 'address': InvalidAddress,
348
+ 'available balance is only': InsufficientFunds,
349
+ 'not enough exchange balance': InsufficientFunds,
350
+ 'Order not found': OrderNotFound,
351
+ 'symbol: invalid': BadSymbol,
352
+ 'Invalid order': InvalidOrder,
353
+ },
354
+ },
355
+ 'commonCurrencies': {
356
+ 'EUTFO': 'EURT',
357
+ 'USTF0': 'USDT',
358
+ },
359
+ });
360
+ }
361
+
362
+ isFiat (code) {
363
+ return (code in this.options['fiat']);
364
+ }
365
+
366
+ getCurrencyId (code) {
367
+ return 'f' + code;
368
+ }
369
+
370
+ getCurrencyName (code) {
371
+ // temporary fix for transpiler recognition, even though this is in parent class
372
+ if (code in this.options['currencyNames']) {
373
+ return this.options['currencyNames'][code];
374
+ }
375
+ throw new NotSupported (this.id + ' ' + code + ' not supported for withdrawal');
376
+ }
377
+
378
+ async fetchStatus (params = {}) {
379
+ //
380
+ // [1] // operative
381
+ // [0] // maintenance
382
+ //
383
+ const response = await this.publicGetPlatformStatus (params);
384
+ const statusRaw = this.safeString (response, 0);
385
+ return {
386
+ 'status': this.safeString ({ '0': 'maintenance', '1': 'ok' }, statusRaw, statusRaw),
387
+ 'updated': this.milliseconds (),
388
+ 'eta': undefined,
389
+ 'url': undefined,
390
+ 'info': response,
391
+ };
392
+ }
393
+
394
+ async fetchMarkets (params = {}) {
395
+ // todo drop v1 in favor of v2 configs ( temp-reference for v2update: https://pastebin.com/raw/S8CmqSHQ )
396
+ // pub:list:pair:exchange,pub:list:pair:margin,pub:list:pair:futures,pub:info:pair
397
+ const v2response = await this.publicGetConfPubListPairFutures (params);
398
+ const v1response = await this.v1GetSymbolsDetails (params);
399
+ const swapMarketIds = this.safeValue (v2response, 0, []);
400
+ const result = [];
401
+ for (let i = 0; i < v1response.length; i++) {
402
+ const market = v1response[i];
403
+ const id = this.safeStringUpper (market, 'pair');
404
+ let spot = true;
405
+ if (this.inArray (id, swapMarketIds)) {
406
+ spot = false;
407
+ }
408
+ const swap = !spot;
409
+ let baseId = undefined;
410
+ let quoteId = undefined;
411
+ if (id.indexOf (':') >= 0) {
412
+ const parts = id.split (':');
413
+ baseId = parts[0];
414
+ quoteId = parts[1];
415
+ } else {
416
+ baseId = id.slice (0, 3);
417
+ quoteId = id.slice (3, 6);
418
+ }
419
+ let base = this.safeCurrencyCode (baseId);
420
+ let quote = this.safeCurrencyCode (quoteId);
421
+ const splitBase = base.split ('F0');
422
+ const splitQuote = quote.split ('F0');
423
+ base = this.safeString (splitBase, 0);
424
+ quote = this.safeString (splitQuote, 0);
425
+ let symbol = base + '/' + quote;
426
+ baseId = this.getCurrencyId (baseId);
427
+ quoteId = this.getCurrencyId (quoteId);
428
+ let settleId = undefined;
429
+ let settle = undefined;
430
+ if (swap) {
431
+ settleId = quoteId;
432
+ settle = this.safeCurrencyCode (settleId);
433
+ symbol = symbol + ':' + settle;
434
+ }
435
+ const minOrderSizeString = this.safeString (market, 'minimum_order_size');
436
+ const maxOrderSizeString = this.safeString (market, 'maximum_order_size');
437
+ result.push ({
438
+ 'id': 't' + id,
439
+ 'symbol': symbol,
440
+ 'base': base,
441
+ 'quote': quote,
442
+ 'settle': settle,
443
+ 'baseId': baseId,
444
+ 'quoteId': quoteId,
445
+ 'settleId': settleId,
446
+ 'type': spot ? 'spot' : 'swap',
447
+ 'spot': spot,
448
+ 'margin': this.safeValue (market, 'margin', false),
449
+ 'swap': swap,
450
+ 'future': false,
451
+ 'option': false,
452
+ 'active': true,
453
+ 'contract': swap,
454
+ 'linear': swap ? true : undefined,
455
+ 'inverse': swap ? false : undefined,
456
+ 'contractSize': swap ? this.parseNumber ('1') : undefined,
457
+ 'expiry': undefined,
458
+ 'expiryDatetime': undefined,
459
+ 'strike': undefined,
460
+ 'optionType': undefined,
461
+ 'precision': {
462
+ 'amount': parseInt ('8'), // https://github.com/ccxt/ccxt/issues/7310
463
+ 'price': this.safeInteger (market, 'price_precision'),
464
+ },
465
+ 'limits': {
466
+ 'leverage': {
467
+ 'min': undefined,
468
+ 'max': undefined,
469
+ },
470
+ 'amount': {
471
+ 'min': this.parseNumber (minOrderSizeString),
472
+ 'max': this.parseNumber (maxOrderSizeString),
473
+ },
474
+ 'price': {
475
+ 'min': this.parseNumber ('1e-8'),
476
+ 'max': undefined,
477
+ },
478
+ 'cost': {
479
+ 'min': undefined,
480
+ 'max': undefined,
481
+ },
482
+ },
483
+ 'info': market,
484
+ });
485
+ }
486
+ return result;
487
+ }
488
+
489
+ async fetchCurrencies (params = {}) {
490
+ const labels = [
491
+ 'pub:list:currency',
492
+ 'pub:map:currency:sym', // maps symbols to their API symbols, BAB > BCH
493
+ 'pub:map:currency:label', // verbose friendly names, BNT > Bancor
494
+ 'pub:map:currency:unit', // maps symbols to unit of measure where applicable
495
+ 'pub:map:currency:undl', // maps derivatives symbols to their underlying currency
496
+ 'pub:map:currency:pool', // maps symbols to underlying network/protocol they operate on
497
+ 'pub:map:currency:explorer', // maps symbols to their recognised block explorer URLs
498
+ 'pub:map:currency:tx:fee', // maps currencies to their withdrawal fees https://github.com/ccxt/ccxt/issues/7745
499
+ ];
500
+ const config = labels.join (',');
501
+ const request = {
502
+ 'config': config,
503
+ };
504
+ const response = await this.publicGetConfConfig (this.extend (request, params));
505
+ //
506
+ // [
507
+ //
508
+ // a list of symbols
509
+ // ["AAA","ABS","ADA"],
510
+ //
511
+ // // sym
512
+ // // maps symbols to their API symbols, BAB > BCH
513
+ // [
514
+ // [ 'BAB', 'BCH' ],
515
+ // [ 'CNHT', 'CNHt' ],
516
+ // [ 'DSH', 'DASH' ],
517
+ // [ 'IOT', 'IOTA' ],
518
+ // [ 'LES', 'LEO-EOS' ],
519
+ // [ 'LET', 'LEO-ERC20' ],
520
+ // [ 'STJ', 'STORJ' ],
521
+ // [ 'TSD', 'TUSD' ],
522
+ // [ 'UDC', 'USDC' ],
523
+ // [ 'USK', 'USDK' ],
524
+ // [ 'UST', 'USDt' ],
525
+ // [ 'USTF0', 'USDt0' ],
526
+ // [ 'XCH', 'XCHF' ],
527
+ // [ 'YYW', 'YOYOW' ],
528
+ // // ...
529
+ // ],
530
+ // // label
531
+ // // verbose friendly names, BNT > Bancor
532
+ // [
533
+ // [ 'BAB', 'Bitcoin Cash' ],
534
+ // [ 'BCH', 'Bitcoin Cash' ],
535
+ // [ 'LEO', 'Unus Sed LEO' ],
536
+ // [ 'LES', 'Unus Sed LEO (EOS)' ],
537
+ // [ 'LET', 'Unus Sed LEO (ERC20)' ],
538
+ // // ...
539
+ // ],
540
+ // // unit
541
+ // // maps symbols to unit of measure where applicable
542
+ // [
543
+ // [ 'IOT', 'Mi|MegaIOTA' ],
544
+ // ],
545
+ // // undl
546
+ // // maps derivatives symbols to their underlying currency
547
+ // [
548
+ // [ 'USTF0', 'UST' ],
549
+ // [ 'BTCF0', 'BTC' ],
550
+ // [ 'ETHF0', 'ETH' ],
551
+ // ],
552
+ // // pool
553
+ // // maps symbols to underlying network/protocol they operate on
554
+ // [
555
+ // [ 'SAN', 'ETH' ], [ 'OMG', 'ETH' ], [ 'AVT', 'ETH' ], [ 'EDO', 'ETH' ],
556
+ // [ 'ESS', 'ETH' ], [ 'ATD', 'EOS' ], [ 'ADD', 'EOS' ], [ 'MTO', 'EOS' ],
557
+ // [ 'PNK', 'ETH' ], [ 'BAB', 'BCH' ], [ 'WLO', 'XLM' ], [ 'VLD', 'ETH' ],
558
+ // [ 'BTT', 'TRX' ], [ 'IMP', 'ETH' ], [ 'SCR', 'ETH' ], [ 'GNO', 'ETH' ],
559
+ // // ...
560
+ // ],
561
+ // // explorer
562
+ // // maps symbols to their recognised block explorer URLs
563
+ // [
564
+ // [
565
+ // 'AIO',
566
+ // [
567
+ // "https://mainnet.aion.network",
568
+ // "https://mainnet.aion.network/#/account/VAL",
569
+ // "https://mainnet.aion.network/#/transaction/VAL"
570
+ // ]
571
+ // ],
572
+ // // ...
573
+ // ],
574
+ // // fee
575
+ // // maps currencies to their withdrawal fees
576
+ // [
577
+ // ["AAA",[0,0]],
578
+ // ["ABS",[0,131.3]],
579
+ // ["ADA",[0,0.3]],
580
+ // ],
581
+ // ]
582
+ //
583
+ const indexed = {
584
+ 'sym': this.indexBy (this.safeValue (response, 1, []), 0),
585
+ 'label': this.indexBy (this.safeValue (response, 2, []), 0),
586
+ 'unit': this.indexBy (this.safeValue (response, 3, []), 0),
587
+ 'undl': this.indexBy (this.safeValue (response, 4, []), 0),
588
+ 'pool': this.indexBy (this.safeValue (response, 5, []), 0),
589
+ 'explorer': this.indexBy (this.safeValue (response, 6, []), 0),
590
+ 'fees': this.indexBy (this.safeValue (response, 7, []), 0),
591
+ };
592
+ const ids = this.safeValue (response, 0, []);
593
+ const result = {};
594
+ for (let i = 0; i < ids.length; i++) {
595
+ const id = ids[i];
596
+ const code = this.safeCurrencyCode (id);
597
+ const label = this.safeValue (indexed['label'], id, []);
598
+ const name = this.safeString (label, 1);
599
+ const pool = this.safeValue (indexed['pool'], id, []);
600
+ const type = this.safeString (pool, 1);
601
+ const feeValues = this.safeValue (indexed['fees'], id, []);
602
+ const fees = this.safeValue (feeValues, 1, []);
603
+ const fee = this.safeNumber (fees, 1);
604
+ const undl = this.safeValue (indexed['undl'], id, []);
605
+ const precision = 8; // default precision, todo: fix "magic constants"
606
+ const fid = 'f' + id;
607
+ result[code] = {
608
+ 'id': fid,
609
+ 'uppercaseId': id,
610
+ 'code': code,
611
+ 'info': [ id, label, pool, feeValues, undl ],
612
+ 'type': type,
613
+ 'name': name,
614
+ 'active': true,
615
+ 'deposit': undefined,
616
+ 'withdraw': undefined,
617
+ 'fee': fee,
618
+ 'precision': precision,
619
+ 'limits': {
620
+ 'amount': {
621
+ 'min': 1 / Math.pow (10, precision),
622
+ 'max': undefined,
623
+ },
624
+ 'withdraw': {
625
+ 'min': fee,
626
+ 'max': undefined,
627
+ },
628
+ },
629
+ };
630
+ }
631
+ return result;
632
+ }
633
+
634
+ async fetchBalance (params = {}) {
635
+ // this api call does not return the 'used' amount - use the v1 version instead (which also returns zero balances)
636
+ // there is a difference between this and the v1 api, namely trading wallet is called margin in v2
637
+ await this.loadMarkets ();
638
+ const accountsByType = this.safeValue (this.options, 'v2AccountsByType', {});
639
+ const requestedType = this.safeString (params, 'type', 'exchange');
640
+ const accountType = this.safeString (accountsByType, requestedType, requestedType);
641
+ if (accountType === undefined) {
642
+ const keys = Object.keys (accountsByType);
643
+ throw new ExchangeError (this.id + ' fetchBalance() type parameter must be one of ' + keys.join (', '));
644
+ }
645
+ const isDerivative = requestedType === 'derivatives';
646
+ const query = this.omit (params, 'type');
647
+ const response = await this.privatePostAuthRWallets (query);
648
+ const result = { 'info': response };
649
+ for (let i = 0; i < response.length; i++) {
650
+ const balance = response[i];
651
+ const type = this.safeString (balance, 0);
652
+ const currencyId = this.safeStringLower (balance, 1, '');
653
+ const start = currencyId.length - 2;
654
+ const isDerivativeCode = currencyId.slice (start) === 'f0';
655
+ // this will only filter the derivative codes if the requestedType is 'derivatives'
656
+ const derivativeCondition = (!isDerivative || isDerivativeCode);
657
+ if ((accountType === type) && derivativeCondition) {
658
+ const code = this.safeCurrencyCode (currencyId);
659
+ const account = this.account ();
660
+ account['total'] = this.safeString (balance, 2);
661
+ account['free'] = this.safeString (balance, 4);
662
+ result[code] = account;
663
+ }
664
+ }
665
+ return this.safeBalance (result);
666
+ }
667
+
668
+ async transfer (code, amount, fromAccount, toAccount, params = {}) {
669
+ // transferring between derivatives wallet and regular wallet is not documented in their API
670
+ // however we support it in CCXT (from just looking at web inspector)
671
+ await this.loadMarkets ();
672
+ const accountsByType = this.safeValue (this.options, 'v2AccountsByType', {});
673
+ const fromId = this.safeString (accountsByType, fromAccount);
674
+ if (fromId === undefined) {
675
+ const keys = Object.keys (accountsByType);
676
+ throw new ArgumentsRequired (this.id + ' transfer() fromAccount must be one of ' + keys.join (', '));
677
+ }
678
+ const toId = this.safeString (accountsByType, toAccount);
679
+ if (toId === undefined) {
680
+ const keys = Object.keys (accountsByType);
681
+ throw new ArgumentsRequired (this.id + ' transfer() toAccount must be one of ' + keys.join (', '));
682
+ }
683
+ const currency = this.currency (code);
684
+ const fromCurrencyId = this.convertDerivativesId (currency, fromAccount);
685
+ const toCurrencyId = this.convertDerivativesId (currency, toAccount);
686
+ const requestedAmount = this.currencyToPrecision (code, amount);
687
+ // this request is slightly different from v1 fromAccount -> from
688
+ const request = {
689
+ 'amount': requestedAmount,
690
+ 'currency': fromCurrencyId,
691
+ 'currency_to': toCurrencyId,
692
+ 'from': fromId,
693
+ 'to': toId,
694
+ };
695
+ const response = await this.privatePostAuthWTransfer (this.extend (request, params));
696
+ // [1616451183763,"acc_tf",null,null,[1616451183763,"exchange","margin",null,"UST","UST",null,1],null,"SUCCESS","1.0 Tether USDt transfered from Exchange to Margin"]
697
+ const timestamp = this.safeInteger (response, 0);
698
+ // ["error",10001,"Momentary balance check. Please wait few seconds and try the transfer again."]
699
+ const error = this.safeString (response, 0);
700
+ if (error === 'error') {
701
+ const message = this.safeString (response, 2, '');
702
+ // same message as in v1
703
+ this.throwExactlyMatchedException (this.exceptions['exact'], message, this.id + ' ' + message);
704
+ throw new ExchangeError (this.id + ' ' + message);
705
+ }
706
+ const info = this.safeValue (response, 4);
707
+ const fromResponse = this.safeString (info, 1);
708
+ const toResponse = this.safeString (info, 2);
709
+ const toCode = this.safeCurrencyCode (this.safeString (info, 5));
710
+ const success = this.safeString (response, 6);
711
+ const status = (success === 'SUCCESS') ? 'ok' : undefined;
712
+ return {
713
+ 'info': response,
714
+ 'timestamp': timestamp,
715
+ 'datetime': this.iso8601 (timestamp),
716
+ 'status': status,
717
+ 'amount': requestedAmount,
718
+ 'code': toCode,
719
+ 'fromAccount': fromResponse,
720
+ 'toAccount': toResponse,
721
+ };
722
+ }
723
+
724
+ convertDerivativesId (currency, type) {
725
+ // there is a difference between this and the v1 api, namely trading wallet is called margin in v2
726
+ // {
727
+ // id: 'fUSTF0',
728
+ // code: 'USTF0',
729
+ // info: [ 'USTF0', [], [], [], [ 'USTF0', 'UST' ] ],
730
+ const info = this.safeValue (currency, 'info');
731
+ const transferId = this.safeString (info, 0);
732
+ const underlying = this.safeValue (info, 4, []);
733
+ let currencyId = undefined;
734
+ if (type === 'derivatives') {
735
+ currencyId = this.safeString (underlying, 0, transferId);
736
+ const start = currencyId.length - 2;
737
+ const isDerivativeCode = currencyId.slice (start) === 'F0';
738
+ if (!isDerivativeCode) {
739
+ currencyId = currencyId + 'F0';
740
+ }
741
+ } else if (type !== 'margin') {
742
+ currencyId = this.safeString (underlying, 1, transferId);
743
+ } else {
744
+ currencyId = transferId;
745
+ }
746
+ return currencyId;
747
+ }
748
+
749
+ async fetchOrder (id, symbol = undefined, params = {}) {
750
+ throw new NotSupported (this.id + ' fetchOrder() is not supported yet');
751
+ }
752
+
753
+ async fetchOrderBook (symbol, limit = undefined, params = {}) {
754
+ await this.loadMarkets ();
755
+ const precision = this.safeValue (this.options, 'precision', 'R0');
756
+ const request = {
757
+ 'symbol': this.marketId (symbol),
758
+ 'precision': precision,
759
+ };
760
+ if (limit !== undefined) {
761
+ request['len'] = limit; // 25 or 100
762
+ }
763
+ const fullRequest = this.extend (request, params);
764
+ const orderbook = await this.publicGetBookSymbolPrecision (fullRequest);
765
+ const timestamp = this.milliseconds ();
766
+ const result = {
767
+ 'symbol': symbol,
768
+ 'bids': [],
769
+ 'asks': [],
770
+ 'timestamp': timestamp,
771
+ 'datetime': this.iso8601 (timestamp),
772
+ 'nonce': undefined,
773
+ };
774
+ const priceIndex = (fullRequest['precision'] === 'R0') ? 1 : 0;
775
+ for (let i = 0; i < orderbook.length; i++) {
776
+ const order = orderbook[i];
777
+ const price = this.safeNumber (order, priceIndex);
778
+ const signedAmount = this.safeNumber (order, 2);
779
+ const amount = Math.abs (signedAmount);
780
+ const side = (signedAmount > 0) ? 'bids' : 'asks';
781
+ result[side].push ([ price, amount ]);
782
+ }
783
+ result['bids'] = this.sortBy (result['bids'], 0, true);
784
+ result['asks'] = this.sortBy (result['asks'], 0);
785
+ return result;
786
+ }
787
+
788
+ parseTicker (ticker, market = undefined) {
789
+ //
790
+ // on trading pairs (ex. tBTCUSD)
791
+ //
792
+ // [
793
+ // SYMBOL,
794
+ // BID,
795
+ // BID_SIZE,
796
+ // ASK,
797
+ // ASK_SIZE,
798
+ // DAILY_CHANGE,
799
+ // DAILY_CHANGE_RELATIVE,
800
+ // LAST_PRICE,
801
+ // VOLUME,
802
+ // HIGH,
803
+ // LOW
804
+ // ]
805
+ //
806
+ // on funding currencies (ex. fUSD)
807
+ //
808
+ // [
809
+ // SYMBOL,
810
+ // FRR,
811
+ // BID,
812
+ // BID_PERIOD,
813
+ // BID_SIZE,
814
+ // ASK,
815
+ // ASK_PERIOD,
816
+ // ASK_SIZE,
817
+ // DAILY_CHANGE,
818
+ // DAILY_CHANGE_RELATIVE,
819
+ // LAST_PRICE,
820
+ // VOLUME,
821
+ // HIGH,
822
+ // LOW,
823
+ // _PLACEHOLDER,
824
+ // _PLACEHOLDER,
825
+ // FRR_AMOUNT_AVAILABLE
826
+ // ]
827
+ //
828
+ const timestamp = this.milliseconds ();
829
+ const symbol = this.safeSymbol (undefined, market);
830
+ const length = ticker.length;
831
+ const last = this.safeString (ticker, length - 4);
832
+ const percentage = this.safeString (ticker, length - 5);
833
+ return this.safeTicker ({
834
+ 'symbol': symbol,
835
+ 'timestamp': timestamp,
836
+ 'datetime': this.iso8601 (timestamp),
837
+ 'high': this.safeString (ticker, length - 2),
838
+ 'low': this.safeString (ticker, length - 1),
839
+ 'bid': this.safeString (ticker, length - 10),
840
+ 'bidVolume': undefined,
841
+ 'ask': this.safeString (ticker, length - 8),
842
+ 'askVolume': undefined,
843
+ 'vwap': undefined,
844
+ 'open': undefined,
845
+ 'close': last,
846
+ 'last': last,
847
+ 'previousClose': undefined,
848
+ 'change': this.safeString (ticker, length - 6),
849
+ 'percentage': Precise.stringMul (percentage, '100'),
850
+ 'average': undefined,
851
+ 'baseVolume': this.safeString (ticker, length - 3),
852
+ 'quoteVolume': undefined,
853
+ 'info': ticker,
854
+ }, market, false);
855
+ }
856
+
857
+ async fetchTickers (symbols = undefined, params = {}) {
858
+ await this.loadMarkets ();
859
+ const request = {};
860
+ if (symbols !== undefined) {
861
+ const ids = this.marketIds (symbols);
862
+ request['symbols'] = ids.join (',');
863
+ } else {
864
+ request['symbols'] = 'ALL';
865
+ }
866
+ const tickers = await this.publicGetTickers (this.extend (request, params));
867
+ //
868
+ // [
869
+ // // on trading pairs (ex. tBTCUSD)
870
+ // [
871
+ // SYMBOL,
872
+ // BID,
873
+ // BID_SIZE,
874
+ // ASK,
875
+ // ASK_SIZE,
876
+ // DAILY_CHANGE,
877
+ // DAILY_CHANGE_RELATIVE,
878
+ // LAST_PRICE,
879
+ // VOLUME,
880
+ // HIGH,
881
+ // LOW
882
+ // ],
883
+ // // on funding currencies (ex. fUSD)
884
+ // [
885
+ // SYMBOL,
886
+ // FRR,
887
+ // BID,
888
+ // BID_PERIOD,
889
+ // BID_SIZE,
890
+ // ASK,
891
+ // ASK_PERIOD,
892
+ // ASK_SIZE,
893
+ // DAILY_CHANGE,
894
+ // DAILY_CHANGE_RELATIVE,
895
+ // LAST_PRICE,
896
+ // VOLUME,
897
+ // HIGH,
898
+ // LOW,
899
+ // _PLACEHOLDER,
900
+ // _PLACEHOLDER,
901
+ // FRR_AMOUNT_AVAILABLE
902
+ // ],
903
+ // ...
904
+ // ]
905
+ //
906
+ const result = {};
907
+ for (let i = 0; i < tickers.length; i++) {
908
+ const ticker = tickers[i];
909
+ const id = ticker[0];
910
+ if (id in this.markets_by_id) {
911
+ const market = this.markets_by_id[id];
912
+ const symbol = market['symbol'];
913
+ result[symbol] = this.parseTicker (ticker, market);
914
+ }
915
+ }
916
+ return this.filterByArray (result, 'symbol', symbols);
917
+ }
918
+
919
+ async fetchTicker (symbol, params = {}) {
920
+ await this.loadMarkets ();
921
+ const market = this.market (symbol);
922
+ const request = {
923
+ 'symbol': market['id'],
924
+ };
925
+ const ticker = await this.publicGetTickerSymbol (this.extend (request, params));
926
+ return this.parseTicker (ticker, market);
927
+ }
928
+
929
+ parseSymbol (marketId) {
930
+ if (marketId === undefined) {
931
+ return marketId;
932
+ }
933
+ marketId = marketId.replace ('t', '');
934
+ let baseId = undefined;
935
+ let quoteId = undefined;
936
+ if (marketId.indexOf (':') >= 0) {
937
+ const parts = marketId.split (':');
938
+ baseId = parts[0];
939
+ quoteId = parts[1];
940
+ } else {
941
+ baseId = marketId.slice (0, 3);
942
+ quoteId = marketId.slice (3, 6);
943
+ }
944
+ const base = this.safeCurrencyCode (baseId);
945
+ const quote = this.safeCurrencyCode (quoteId);
946
+ return base + '/' + quote;
947
+ }
948
+
949
+ parseTrade (trade, market = undefined) {
950
+ //
951
+ // fetchTrades (public)
952
+ //
953
+ // [
954
+ // ID,
955
+ // MTS, // timestamp
956
+ // AMOUNT,
957
+ // PRICE
958
+ // ]
959
+ //
960
+ // fetchMyTrades (private)
961
+ //
962
+ // [
963
+ // ID,
964
+ // PAIR,
965
+ // MTS_CREATE,
966
+ // ORDER_ID,
967
+ // EXEC_AMOUNT,
968
+ // EXEC_PRICE,
969
+ // ORDER_TYPE,
970
+ // ORDER_PRICE,
971
+ // MAKER,
972
+ // FEE,
973
+ // FEE_CURRENCY,
974
+ // ...
975
+ // ]
976
+ //
977
+ const tradeLength = trade.length;
978
+ const isPrivate = (tradeLength > 5);
979
+ const id = this.safeString (trade, 0);
980
+ const amountIndex = isPrivate ? 4 : 2;
981
+ let side = undefined;
982
+ let amountString = this.safeString (trade, amountIndex);
983
+ const priceIndex = isPrivate ? 5 : 3;
984
+ const priceString = this.safeString (trade, priceIndex);
985
+ if (amountString[0] === '-') {
986
+ side = 'sell';
987
+ amountString = Precise.stringAbs (amountString);
988
+ } else {
989
+ side = 'buy';
990
+ }
991
+ let orderId = undefined;
992
+ let takerOrMaker = undefined;
993
+ let type = undefined;
994
+ let fee = undefined;
995
+ let symbol = undefined;
996
+ const timestampIndex = isPrivate ? 2 : 1;
997
+ const timestamp = this.safeInteger (trade, timestampIndex);
998
+ if (isPrivate) {
999
+ const marketId = trade[1];
1000
+ if (marketId in this.markets_by_id) {
1001
+ market = this.markets_by_id[marketId];
1002
+ symbol = market['symbol'];
1003
+ } else {
1004
+ symbol = this.parseSymbol (marketId);
1005
+ }
1006
+ orderId = this.safeString (trade, 3);
1007
+ const maker = this.safeInteger (trade, 8);
1008
+ takerOrMaker = (maker === 1) ? 'maker' : 'taker';
1009
+ let feeCostString = this.safeString (trade, 9);
1010
+ feeCostString = Precise.stringNeg (feeCostString);
1011
+ const feeCurrencyId = this.safeString (trade, 10);
1012
+ const feeCurrency = this.safeCurrencyCode (feeCurrencyId);
1013
+ fee = {
1014
+ 'cost': feeCostString,
1015
+ 'currency': feeCurrency,
1016
+ };
1017
+ const orderType = trade[6];
1018
+ type = this.safeString (this.options['exchangeTypes'], orderType);
1019
+ }
1020
+ if (symbol === undefined) {
1021
+ if (market !== undefined) {
1022
+ symbol = market['symbol'];
1023
+ }
1024
+ }
1025
+ return this.safeTrade ({
1026
+ 'id': id,
1027
+ 'timestamp': timestamp,
1028
+ 'datetime': this.iso8601 (timestamp),
1029
+ 'symbol': symbol,
1030
+ 'order': orderId,
1031
+ 'side': side,
1032
+ 'type': type,
1033
+ 'takerOrMaker': takerOrMaker,
1034
+ 'price': priceString,
1035
+ 'amount': amountString,
1036
+ 'cost': undefined,
1037
+ 'fee': fee,
1038
+ 'info': trade,
1039
+ }, market);
1040
+ }
1041
+
1042
+ async fetchTrades (symbol, since = undefined, limit = undefined, params = {}) {
1043
+ await this.loadMarkets ();
1044
+ const market = this.market (symbol);
1045
+ let sort = '-1';
1046
+ const request = {
1047
+ 'symbol': market['id'],
1048
+ };
1049
+ if (since !== undefined) {
1050
+ request['start'] = since;
1051
+ sort = '1';
1052
+ }
1053
+ if (limit !== undefined) {
1054
+ request['limit'] = limit; // default 120, max 5000
1055
+ }
1056
+ request['sort'] = sort;
1057
+ const response = await this.publicGetTradesSymbolHist (this.extend (request, params));
1058
+ //
1059
+ // [
1060
+ // [
1061
+ // ID,
1062
+ // MTS, // timestamp
1063
+ // AMOUNT,
1064
+ // PRICE
1065
+ // ]
1066
+ // ]
1067
+ //
1068
+ const trades = this.sortBy (response, 1);
1069
+ return this.parseTrades (trades, market, undefined, limit);
1070
+ }
1071
+
1072
+ async fetchOHLCV (symbol, timeframe = '1m', since = undefined, limit = 100, params = {}) {
1073
+ await this.loadMarkets ();
1074
+ const market = this.market (symbol);
1075
+ if (limit === undefined) {
1076
+ limit = 100; // default 100, max 5000
1077
+ }
1078
+ if (since === undefined) {
1079
+ const duration = this.parseTimeframe (timeframe);
1080
+ since = this.milliseconds () - duration * limit * 1000;
1081
+ }
1082
+ const request = {
1083
+ 'symbol': market['id'],
1084
+ 'timeframe': this.timeframes[timeframe],
1085
+ 'sort': 1,
1086
+ 'start': since,
1087
+ 'limit': limit,
1088
+ };
1089
+ const response = await this.publicGetCandlesTradeTimeframeSymbolHist (this.extend (request, params));
1090
+ //
1091
+ // [
1092
+ // [1591503840000,0.025069,0.025068,0.025069,0.025068,1.97828998],
1093
+ // [1591504500000,0.025065,0.025065,0.025065,0.025065,1.0164],
1094
+ // [1591504620000,0.025062,0.025062,0.025062,0.025062,0.5],
1095
+ // ]
1096
+ //
1097
+ return this.parseOHLCVs (response, market, timeframe, since, limit);
1098
+ }
1099
+
1100
+ parseOrderStatus (status) {
1101
+ if (status === undefined) {
1102
+ return status;
1103
+ }
1104
+ const parts = status.split (' ');
1105
+ const state = this.safeString (parts, 0);
1106
+ const statuses = {
1107
+ 'ACTIVE': 'open',
1108
+ 'PARTIALLY': 'open',
1109
+ 'EXECUTED': 'closed',
1110
+ 'CANCELED': 'canceled',
1111
+ 'INSUFFICIENT': 'canceled',
1112
+ 'POSTONLY': 'canceled',
1113
+ 'RSN_DUST': 'rejected',
1114
+ 'RSN_PAUSE': 'rejected',
1115
+ };
1116
+ return this.safeString (statuses, state, status);
1117
+ }
1118
+
1119
+ parseOrder (order, market = undefined) {
1120
+ const id = this.safeString (order, 0);
1121
+ let symbol = undefined;
1122
+ const marketId = this.safeString (order, 3);
1123
+ if (marketId in this.markets_by_id) {
1124
+ market = this.markets_by_id[marketId];
1125
+ } else {
1126
+ symbol = this.parseSymbol (marketId);
1127
+ }
1128
+ if ((symbol === undefined) && (market !== undefined)) {
1129
+ symbol = market['symbol'];
1130
+ }
1131
+ // https://github.com/ccxt/ccxt/issues/6686
1132
+ // const timestamp = this.safeTimestamp (order, 5);
1133
+ const timestamp = this.safeInteger (order, 5);
1134
+ const remaining = Precise.stringAbs (this.safeString (order, 6));
1135
+ const signedAmount = this.safeString (order, 7);
1136
+ const amount = Precise.stringAbs (signedAmount);
1137
+ const side = Precise.stringLt (signedAmount, '0') ? 'sell' : 'buy';
1138
+ const orderType = this.safeString (order, 8);
1139
+ const type = this.safeString (this.safeValue (this.options, 'exchangeTypes'), orderType);
1140
+ let status = undefined;
1141
+ const statusString = this.safeString (order, 13);
1142
+ if (statusString !== undefined) {
1143
+ const parts = statusString.split (' @ ');
1144
+ status = this.parseOrderStatus (this.safeString (parts, 0));
1145
+ }
1146
+ const price = this.safeString (order, 16);
1147
+ const average = this.safeString (order, 17);
1148
+ const clientOrderId = this.safeString (order, 2);
1149
+ return this.safeOrder ({
1150
+ 'info': order,
1151
+ 'id': id,
1152
+ 'clientOrderId': clientOrderId,
1153
+ 'timestamp': timestamp,
1154
+ 'datetime': this.iso8601 (timestamp),
1155
+ 'lastTradeTimestamp': undefined,
1156
+ 'symbol': symbol,
1157
+ 'type': type,
1158
+ 'timeInForce': undefined,
1159
+ 'postOnly': undefined,
1160
+ 'side': side,
1161
+ 'price': price,
1162
+ 'stopPrice': undefined,
1163
+ 'amount': amount,
1164
+ 'cost': undefined,
1165
+ 'average': average,
1166
+ 'filled': undefined,
1167
+ 'remaining': remaining,
1168
+ 'status': status,
1169
+ 'fee': undefined,
1170
+ 'trades': undefined,
1171
+ }, market);
1172
+ }
1173
+
1174
+ async createOrder (symbol, type, side, amount, price = undefined, params = {}) {
1175
+ await this.loadMarkets ();
1176
+ const market = this.market (symbol);
1177
+ const orderTypes = this.safeValue (this.options, 'orderTypes', {});
1178
+ const orderType = this.safeStringUpper (orderTypes, type, type);
1179
+ const postOnly = this.safeValue (params, 'postOnly', false);
1180
+ params = this.omit (params, [ 'postOnly' ]);
1181
+ amount = (side === 'sell') ? -amount : amount;
1182
+ const request = {
1183
+ // 'gid': 0123456789, // int32, optional group id for the order
1184
+ // 'cid': 0123456789, // int32 client order id
1185
+ 'type': orderType,
1186
+ 'symbol': market['id'],
1187
+ // 'price': this.numberToString (price),
1188
+ 'amount': this.numberToString (amount),
1189
+ // 'flags': 0, // int32, https://docs.bitfinex.com/v2/docs/flag-values
1190
+ // 'lev': 10, // the value should be between 1 and 100 inclusive, optional, 10 by default
1191
+ // 'price_trailing': this.numberToString (priceTrailing),
1192
+ // 'price_aux_limit': this.numberToString (stopPrice),
1193
+ // 'price_oco_stop': this.numberToString (ocoStopPrice),
1194
+ // 'tif': '2020-01-01 10:45:23', // datetime for automatic order cancellation
1195
+ // 'meta': {
1196
+ // 'aff_code': 'AFF_CODE_HERE'
1197
+ // },
1198
+ };
1199
+ if (postOnly) {
1200
+ request['flags'] = 4096;
1201
+ }
1202
+ if ((orderType === 'LIMIT') || (orderType === 'EXCHANGE LIMIT')) {
1203
+ request['price'] = this.numberToString (price);
1204
+ } else if ((orderType === 'STOP') || (orderType === 'EXCHANGE STOP')) {
1205
+ const stopPrice = this.safeNumber (params, 'stopPrice', price);
1206
+ request['price'] = this.numberToString (stopPrice);
1207
+ } else if ((orderType === 'STOP LIMIT') || (orderType === 'EXCHANGE STOP LIMIT')) {
1208
+ const priceAuxLimit = this.safeNumber (params, 'price_aux_limit');
1209
+ let stopPrice = this.safeNumber (params, 'stopPrice');
1210
+ if (priceAuxLimit === undefined) {
1211
+ if (stopPrice === undefined) {
1212
+ throw new ArgumentsRequired (this.id + ' createOrder() requires a stopPrice parameter or a price_aux_limit parameter for a ' + orderType + ' order');
1213
+ } else {
1214
+ request['price_aux_limit'] = this.numberToString (price);
1215
+ }
1216
+ } else {
1217
+ request['price_aux_limit'] = this.numberToString (priceAuxLimit);
1218
+ if (stopPrice === undefined) {
1219
+ stopPrice = price;
1220
+ }
1221
+ }
1222
+ request['price'] = this.numberToString (stopPrice);
1223
+ } else if ((orderType === 'TRAILING STOP') || (orderType === 'EXCHANGE TRAILING STOP')) {
1224
+ const priceTrailing = this.safeNumber (params, 'price_trailing');
1225
+ request['price_trailing'] = this.numberToString (priceTrailing);
1226
+ const stopPrice = this.safeNumber (params, 'stopPrice', price);
1227
+ request['price'] = this.numberToString (stopPrice);
1228
+ } else if ((orderType === 'FOK') || (orderType === 'EXCHANGE FOK') || (orderType === 'IOC') || (orderType === 'EXCHANGE IOC')) {
1229
+ request['price'] = this.numberToString (price);
1230
+ }
1231
+ params = this.omit (params, [ 'stopPrice', 'price_aux_limit', 'price_trailing' ]);
1232
+ const clientOrderId = this.safeValue2 (params, 'cid', 'clientOrderId');
1233
+ if (clientOrderId !== undefined) {
1234
+ request['cid'] = clientOrderId;
1235
+ params = this.omit (params, [ 'cid', 'clientOrderId' ]);
1236
+ }
1237
+ const response = await this.privatePostAuthWOrderSubmit (this.extend (request, params));
1238
+ //
1239
+ // [
1240
+ // 1578784364.748, // Millisecond Time Stamp of the update
1241
+ // "on-req", // Purpose of notification ('on-req', 'oc-req', 'uca', 'fon-req', 'foc-req')
1242
+ // null, // Unique ID of the message
1243
+ // null, // Ignore
1244
+ // [
1245
+ // [
1246
+ // 37271830598, // Order ID
1247
+ // null, // Group ID
1248
+ // 1578784364748, // Client Order ID
1249
+ // "tBTCUST", // Pair
1250
+ // 1578784364748, // Millisecond timestamp of creation
1251
+ // 1578784364748, // Millisecond timestamp of update
1252
+ // -0.005, // Positive means buy, negative means sell
1253
+ // -0.005, // Original amount
1254
+ // "EXCHANGE LIMIT", // Order type (LIMIT, MARKET, STOP, TRAILING STOP, EXCHANGE MARKET, EXCHANGE LIMIT, EXCHANGE STOP, EXCHANGE TRAILING STOP, FOK, EXCHANGE FOK, IOC, EXCHANGE IOC)
1255
+ // null, // Previous order type
1256
+ // null, // Millisecond timestamp of Time-In-Force: automatic order cancellation
1257
+ // null, // Ignore
1258
+ // 0, // Flags (see https://docs.bitfinex.com/docs/flag-values)
1259
+ // "ACTIVE", // Order Status
1260
+ // null, // Ignore
1261
+ // null, // Ignore
1262
+ // 20000, // Price
1263
+ // 0, // Average price
1264
+ // 0, // The trailing price
1265
+ // 0, // Auxiliary Limit price (for STOP LIMIT)
1266
+ // null, // Ignore
1267
+ // null, // Ignore
1268
+ // null, // Ignore
1269
+ // 0, // 1 - hidden order
1270
+ // null, // If another order caused this order to be placed (OCO) this will be that other order's ID
1271
+ // null, // Ignore
1272
+ // null, // Ignore
1273
+ // null, // Ignore
1274
+ // "API>BFX", // Origin of action: BFX, ETHFX, API>BFX, API>ETHFX
1275
+ // null, // Ignore
1276
+ // null, // Ignore
1277
+ // null // Meta
1278
+ // ]
1279
+ // ],
1280
+ // null, // Error code
1281
+ // "SUCCESS", // Status (SUCCESS, ERROR, FAILURE, ...)
1282
+ // "Submitting 1 orders." // Text of the notification
1283
+ // ]
1284
+ //
1285
+ const status = this.safeString (response, 6);
1286
+ if (status !== 'SUCCESS') {
1287
+ const errorCode = response[5];
1288
+ const errorText = response[7];
1289
+ throw new ExchangeError (this.id + ' ' + response[6] + ': ' + errorText + ' (#' + errorCode + ')');
1290
+ }
1291
+ const orders = this.safeValue (response, 4, []);
1292
+ const order = this.safeValue (orders, 0);
1293
+ return this.parseOrder (order, market);
1294
+ }
1295
+
1296
+ async cancelAllOrders (symbol = undefined, params = {}) {
1297
+ const request = {
1298
+ 'all': 1,
1299
+ };
1300
+ const response = await this.privatePostAuthWOrderCancelMulti (this.extend (request, params));
1301
+ const orders = this.safeValue (response, 4, []);
1302
+ return this.parseOrders (orders);
1303
+ }
1304
+
1305
+ async cancelOrder (id, symbol = undefined, params = {}) {
1306
+ const cid = this.safeValue2 (params, 'cid', 'clientOrderId'); // client order id
1307
+ let request = undefined;
1308
+ if (cid !== undefined) {
1309
+ const cidDate = this.safeValue (params, 'cidDate'); // client order id date
1310
+ if (cidDate === undefined) {
1311
+ throw new InvalidOrder (this.id + " canceling an order by clientOrderId ('cid') requires both 'cid' and 'cid_date' ('YYYY-MM-DD')");
1312
+ }
1313
+ request = {
1314
+ 'cid': cid,
1315
+ 'cid_date': cidDate,
1316
+ };
1317
+ params = this.omit (params, [ 'cid', 'clientOrderId' ]);
1318
+ } else {
1319
+ request = {
1320
+ 'id': parseInt (id),
1321
+ };
1322
+ }
1323
+ const response = await this.privatePostAuthWOrderCancel (this.extend (request, params));
1324
+ const order = this.safeValue (response, 4);
1325
+ return this.parseOrder (order);
1326
+ }
1327
+
1328
+ async fetchOpenOrder (id, symbol = undefined, params = {}) {
1329
+ const request = {
1330
+ 'id': [ parseInt (id) ],
1331
+ };
1332
+ const orders = await this.fetchOpenOrders (symbol, undefined, undefined, this.extend (request, params));
1333
+ const order = this.safeValue (orders, 0);
1334
+ if (order === undefined) {
1335
+ throw new OrderNotFound (this.id + ' order ' + id + ' not found');
1336
+ }
1337
+ return order;
1338
+ }
1339
+
1340
+ async fetchClosedOrder (id, symbol = undefined, params = {}) {
1341
+ const request = {
1342
+ 'id': [ parseInt (id) ],
1343
+ };
1344
+ const orders = await this.fetchClosedOrders (symbol, undefined, undefined, this.extend (request, params));
1345
+ const order = this.safeValue (orders, 0);
1346
+ if (order === undefined) {
1347
+ throw new OrderNotFound (this.id + ' order ' + id + ' not found');
1348
+ }
1349
+ return order;
1350
+ }
1351
+
1352
+ async fetchOpenOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) {
1353
+ await this.loadMarkets ();
1354
+ const request = {};
1355
+ let market = undefined;
1356
+ let response = undefined;
1357
+ if (symbol === undefined) {
1358
+ response = await this.privatePostAuthROrders (this.extend (request, params));
1359
+ } else {
1360
+ market = this.market (symbol);
1361
+ request['symbol'] = market['id'];
1362
+ response = await this.privatePostAuthROrdersSymbol (this.extend (request, params));
1363
+ }
1364
+ return this.parseOrders (response, market, since, limit);
1365
+ }
1366
+
1367
+ async fetchClosedOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) {
1368
+ // returns the most recent closed or canceled orders up to circa two weeks ago
1369
+ await this.loadMarkets ();
1370
+ const request = {};
1371
+ let market = undefined;
1372
+ let response = undefined;
1373
+ if (symbol === undefined) {
1374
+ response = await this.privatePostAuthROrdersHist (this.extend (request, params));
1375
+ } else {
1376
+ market = this.market (symbol);
1377
+ request['symbol'] = market['id'];
1378
+ response = await this.privatePostAuthROrdersSymbolHist (this.extend (request, params));
1379
+ }
1380
+ if (since !== undefined) {
1381
+ request['start'] = since;
1382
+ }
1383
+ if (limit !== undefined) {
1384
+ request['limit'] = limit; // default 25, max 2500
1385
+ }
1386
+ return this.parseOrders (response, market, since, limit);
1387
+ }
1388
+
1389
+ async fetchOrderTrades (id, symbol = undefined, since = undefined, limit = undefined, params = {}) {
1390
+ if (symbol === undefined) {
1391
+ throw new ArgumentsRequired (this.id + ' fetchOrderTrades() requires a symbol argument');
1392
+ }
1393
+ await this.loadMarkets ();
1394
+ const market = this.market (symbol);
1395
+ const orderId = parseInt (id);
1396
+ const request = {
1397
+ 'id': orderId,
1398
+ 'symbol': market['id'],
1399
+ };
1400
+ // valid for trades upto 10 days old
1401
+ const response = await this.privatePostAuthROrderSymbolIdTrades (this.extend (request, params));
1402
+ return this.parseTrades (response, market, since, limit);
1403
+ }
1404
+
1405
+ async fetchMyTrades (symbol = undefined, since = undefined, limit = undefined, params = {}) {
1406
+ await this.loadMarkets ();
1407
+ let market = undefined;
1408
+ const request = {
1409
+ 'end': this.milliseconds (),
1410
+ };
1411
+ if (since !== undefined) {
1412
+ request['start'] = since;
1413
+ }
1414
+ if (limit !== undefined) {
1415
+ request['limit'] = limit; // default 25, max 1000
1416
+ }
1417
+ let method = 'privatePostAuthRTradesHist';
1418
+ if (symbol !== undefined) {
1419
+ market = this.market (symbol);
1420
+ request['symbol'] = market['id'];
1421
+ method = 'privatePostAuthRTradesSymbolHist';
1422
+ }
1423
+ const response = await this[method] (this.extend (request, params));
1424
+ return this.parseTrades (response, market, since, limit);
1425
+ }
1426
+
1427
+ async createDepositAddress (code, params = {}) {
1428
+ await this.loadMarkets ();
1429
+ const request = {
1430
+ 'op_renew': 1,
1431
+ };
1432
+ const response = await this.fetchDepositAddress (code, this.extend (request, params));
1433
+ return response;
1434
+ }
1435
+
1436
+ async fetchDepositAddress (code, params = {}) {
1437
+ await this.loadMarkets ();
1438
+ // todo rewrite for https://api-pub.bitfinex.com//v2/conf/pub:map:tx:method
1439
+ const name = this.getCurrencyName (code);
1440
+ const request = {
1441
+ 'method': name,
1442
+ 'wallet': 'exchange', // 'exchange', 'margin', 'funding' and also old labels 'exchange', 'trading', 'deposit', respectively
1443
+ 'op_renew': 0, // a value of 1 will generate a new address
1444
+ };
1445
+ const response = await this.privatePostAuthWDepositAddress (this.extend (request, params));
1446
+ //
1447
+ // [
1448
+ // 1582269616687, // MTS Millisecond Time Stamp of the update
1449
+ // 'acc_dep', // TYPE Purpose of notification 'acc_dep' for account deposit
1450
+ // null, // MESSAGE_ID unique ID of the message
1451
+ // null, // not documented
1452
+ // [
1453
+ // null, // PLACEHOLDER
1454
+ // 'BITCOIN', // METHOD Method of deposit
1455
+ // 'BTC', // CURRENCY_CODE Currency code of new address
1456
+ // null, // PLACEHOLDER
1457
+ // '1BC9PZqpUmjyEB54uggn8TFKj49zSDYzqG', // ADDRESS
1458
+ // null, // POOL_ADDRESS
1459
+ // ],
1460
+ // null, // CODE null or integer work in progress
1461
+ // 'SUCCESS', // STATUS Status of the notification, SUCCESS, ERROR, FAILURE
1462
+ // 'success', // TEXT Text of the notification
1463
+ // ]
1464
+ //
1465
+ const result = this.safeValue (response, 4, []);
1466
+ const poolAddress = this.safeString (result, 5);
1467
+ const address = (poolAddress === undefined) ? this.safeString (result, 4) : poolAddress;
1468
+ const tag = (poolAddress === undefined) ? undefined : this.safeString (result, 4);
1469
+ this.checkAddress (address);
1470
+ return {
1471
+ 'currency': code,
1472
+ 'address': address,
1473
+ 'tag': tag,
1474
+ 'network': undefined,
1475
+ 'info': response,
1476
+ };
1477
+ }
1478
+
1479
+ parseTransactionStatus (status) {
1480
+ const statuses = {
1481
+ 'SUCCESS': 'ok',
1482
+ 'ERROR': 'failed',
1483
+ 'FAILURE': 'failed',
1484
+ 'CANCELED': 'canceled',
1485
+ 'COMPLETED': 'ok',
1486
+ };
1487
+ return this.safeString (statuses, status, status);
1488
+ }
1489
+
1490
+ parseTransaction (transaction, currency = undefined) {
1491
+ //
1492
+ // withdraw
1493
+ //
1494
+ // [
1495
+ // 1582271520931, // MTS Millisecond Time Stamp of the update
1496
+ // "acc_wd-req", // TYPE Purpose of notification 'acc_wd-req' account withdrawal request
1497
+ // null, // MESSAGE_ID unique ID of the message
1498
+ // null, // not documented
1499
+ // [
1500
+ // 0, // WITHDRAWAL_ID Unique Withdrawal ID
1501
+ // null, // PLACEHOLDER
1502
+ // "bitcoin", // METHOD Method of withdrawal
1503
+ // null, // PAYMENT_ID Payment ID if relevant
1504
+ // "exchange", // WALLET Sending wallet
1505
+ // 1, // AMOUNT Amount of Withdrawal less fee
1506
+ // null, // PLACEHOLDER
1507
+ // null, // PLACEHOLDER
1508
+ // 0.0004, // WITHDRAWAL_FEE Fee on withdrawal
1509
+ // ],
1510
+ // null, // CODE null or integer Work in progress
1511
+ // "SUCCESS", // STATUS Status of the notification, it may vary over time SUCCESS, ERROR, FAILURE
1512
+ // "Invalid bitcoin address (abcdef)", // TEXT Text of the notification
1513
+ // ]
1514
+ //
1515
+ // fetchTransactions
1516
+ //
1517
+ // [
1518
+ // 13293039, // ID
1519
+ // 'ETH', // CURRENCY
1520
+ // 'ETHEREUM', // CURRENCY_NAME
1521
+ // null,
1522
+ // null,
1523
+ // 1574175052000, // MTS_STARTED
1524
+ // 1574181326000, // MTS_UPDATED
1525
+ // null,
1526
+ // null,
1527
+ // 'CANCELED', // STATUS
1528
+ // null,
1529
+ // null,
1530
+ // -0.24, // AMOUNT, negative for withdrawals
1531
+ // -0.00135, // FEES
1532
+ // null,
1533
+ // null,
1534
+ // '0x38110e0Fc932CB2BE...........', // DESTINATION_ADDRESS
1535
+ // null,
1536
+ // null,
1537
+ // null,
1538
+ // '0x523ec8945500.....................................', // TRANSACTION_ID
1539
+ // "Purchase of 100 pizzas", // WITHDRAW_TRANSACTION_NOTE, might also be: null
1540
+ // ]
1541
+ //
1542
+ const transactionLength = transaction.length;
1543
+ let timestamp = undefined;
1544
+ let updated = undefined;
1545
+ let code = undefined;
1546
+ let amount = undefined;
1547
+ let id = undefined;
1548
+ let status = undefined;
1549
+ let tag = undefined;
1550
+ let type = undefined;
1551
+ let feeCost = undefined;
1552
+ let txid = undefined;
1553
+ let addressTo = undefined;
1554
+ if (transactionLength === 8) {
1555
+ const data = this.safeValue (transaction, 4, []);
1556
+ timestamp = this.safeInteger (transaction, 0);
1557
+ if (currency !== undefined) {
1558
+ code = currency['code'];
1559
+ }
1560
+ feeCost = this.safeNumber (data, 8);
1561
+ if (feeCost !== undefined) {
1562
+ feeCost = -feeCost;
1563
+ }
1564
+ amount = this.safeNumber (data, 5);
1565
+ id = this.safeValue (data, 0);
1566
+ status = 'ok';
1567
+ if (id === 0) {
1568
+ id = undefined;
1569
+ status = 'failed';
1570
+ }
1571
+ tag = this.safeString (data, 3);
1572
+ type = 'withdrawal';
1573
+ } else if (transactionLength === 22) {
1574
+ id = this.safeString (transaction, 0);
1575
+ const currencyId = this.safeString (transaction, 1);
1576
+ code = this.safeCurrencyCode (currencyId, currency);
1577
+ timestamp = this.safeInteger (transaction, 5);
1578
+ updated = this.safeInteger (transaction, 6);
1579
+ status = this.parseTransactionStatus (this.safeString (transaction, 9));
1580
+ amount = this.safeNumber (transaction, 12);
1581
+ if (amount !== undefined) {
1582
+ if (amount < 0) {
1583
+ type = 'withdrawal';
1584
+ } else {
1585
+ type = 'deposit';
1586
+ }
1587
+ }
1588
+ feeCost = this.safeNumber (transaction, 13);
1589
+ if (feeCost !== undefined) {
1590
+ feeCost = -feeCost;
1591
+ }
1592
+ addressTo = this.safeString (transaction, 16);
1593
+ txid = this.safeString (transaction, 20);
1594
+ }
1595
+ return {
1596
+ 'info': transaction,
1597
+ 'id': id,
1598
+ 'txid': txid,
1599
+ 'timestamp': timestamp,
1600
+ 'datetime': this.iso8601 (timestamp),
1601
+ 'network': undefined,
1602
+ 'addressFrom': undefined,
1603
+ 'address': addressTo, // this is actually the tag for XRP transfers (the address is missing)
1604
+ 'addressTo': addressTo,
1605
+ 'tagFrom': undefined,
1606
+ 'tag': tag, // refix it properly for the tag from description
1607
+ 'tagTo': tag,
1608
+ 'type': type,
1609
+ 'amount': amount,
1610
+ 'currency': code,
1611
+ 'status': status,
1612
+ 'updated': updated,
1613
+ 'fee': {
1614
+ 'currency': code,
1615
+ 'cost': feeCost,
1616
+ 'rate': undefined,
1617
+ },
1618
+ };
1619
+ }
1620
+
1621
+ async fetchTradingFees (params = {}) {
1622
+ await this.loadMarkets ();
1623
+ const response = await this.privatePostAuthRSummary (params);
1624
+ //
1625
+ // Response Spec:
1626
+ // [
1627
+ // PLACEHOLDER,
1628
+ // PLACEHOLDER,
1629
+ // PLACEHOLDER,
1630
+ // PLACEHOLDER,
1631
+ // [
1632
+ // [
1633
+ // MAKER_FEE,
1634
+ // MAKER_FEE,
1635
+ // MAKER_FEE,
1636
+ // PLACEHOLDER,
1637
+ // PLACEHOLDER,
1638
+ // DERIV_REBATE
1639
+ // ],
1640
+ // [
1641
+ // TAKER_FEE_TO_CRYPTO,
1642
+ // TAKER_FEE_TO_STABLE,
1643
+ // TAKER_FEE_TO_FIAT,
1644
+ // PLACEHOLDER,
1645
+ // PLACEHOLDER,
1646
+ // DERIV_TAKER_FEE
1647
+ // ]
1648
+ // ],
1649
+ // PLACEHOLDER,
1650
+ // PLACEHOLDER,
1651
+ // PLACEHOLDER,
1652
+ // PLACEHOLDER,
1653
+ // {
1654
+ // LEO_LEV,
1655
+ // LEO_AMOUNT_AVG
1656
+ // }
1657
+ // ]
1658
+ //
1659
+ // Example response:
1660
+ //
1661
+ // [
1662
+ // null,
1663
+ // null,
1664
+ // null,
1665
+ // null,
1666
+ // [
1667
+ // [ 0.001, 0.001, 0.001, null, null, 0.0002 ],
1668
+ // [ 0.002, 0.002, 0.002, null, null, 0.00065 ]
1669
+ // ],
1670
+ // [
1671
+ // [
1672
+ // {
1673
+ // curr: 'Total (USD)',
1674
+ // vol: '0',
1675
+ // vol_safe: '0',
1676
+ // vol_maker: '0',
1677
+ // vol_BFX: '0',
1678
+ // vol_BFX_safe: '0',
1679
+ // vol_BFX_maker: '0'
1680
+ // }
1681
+ // ],
1682
+ // {},
1683
+ // 0
1684
+ // ],
1685
+ // [ null, {}, 0 ],
1686
+ // null,
1687
+ // null,
1688
+ // { leo_lev: '0', leo_amount_avg: '0' }
1689
+ // ]
1690
+ //
1691
+ const result = {};
1692
+ const fiat = this.safeValue (this.options, 'fiat', {});
1693
+ const feeData = this.safeValue (response, 4, []);
1694
+ const makerData = this.safeValue (feeData, 0, []);
1695
+ const takerData = this.safeValue (feeData, 1, []);
1696
+ const makerFee = this.safeNumber (makerData, 0);
1697
+ const makerFeeFiat = this.safeNumber (makerData, 2);
1698
+ const makerFeeDeriv = this.safeNumber (makerData, 5);
1699
+ const takerFee = this.safeNumber (takerData, 0);
1700
+ const takerFeeFiat = this.safeNumber (takerData, 2);
1701
+ const takerFeeDeriv = this.safeNumber (takerData, 5);
1702
+ for (let i = 0; i < this.symbols.length; i++) {
1703
+ const symbol = this.symbols[i];
1704
+ const market = this.market (symbol);
1705
+ const fee = {
1706
+ 'info': response,
1707
+ 'symbol': symbol,
1708
+ 'percentage': true,
1709
+ 'tierBased': true,
1710
+ };
1711
+ if (market['quote'] in fiat) {
1712
+ fee['maker'] = makerFeeFiat;
1713
+ fee['taker'] = takerFeeFiat;
1714
+ } else if (market['contract']) {
1715
+ fee['maker'] = makerFeeDeriv;
1716
+ fee['taker'] = takerFeeDeriv;
1717
+ } else { // TODO check if stable coin
1718
+ fee['maker'] = makerFee;
1719
+ fee['taker'] = takerFee;
1720
+ }
1721
+ result[symbol] = fee;
1722
+ }
1723
+ return result;
1724
+ }
1725
+
1726
+ async fetchTransactions (code = undefined, since = undefined, limit = undefined, params = {}) {
1727
+ await this.loadMarkets ();
1728
+ let currency = undefined;
1729
+ const request = {};
1730
+ let method = 'privatePostAuthRMovementsHist';
1731
+ if (code !== undefined) {
1732
+ currency = this.currency (code);
1733
+ request['currency'] = currency['uppercaseId'];
1734
+ method = 'privatePostAuthRMovementsCurrencyHist';
1735
+ }
1736
+ if (since !== undefined) {
1737
+ request['start'] = since;
1738
+ }
1739
+ if (limit !== undefined) {
1740
+ request['limit'] = limit; // max 1000
1741
+ }
1742
+ const response = await this[method] (this.extend (request, params));
1743
+ //
1744
+ // [
1745
+ // [
1746
+ // 13293039, // ID
1747
+ // 'ETH', // CURRENCY
1748
+ // 'ETHEREUM', // CURRENCY_NAME
1749
+ // null,
1750
+ // null,
1751
+ // 1574175052000, // MTS_STARTED
1752
+ // 1574181326000, // MTS_UPDATED
1753
+ // null,
1754
+ // null,
1755
+ // 'CANCELED', // STATUS
1756
+ // null,
1757
+ // null,
1758
+ // -0.24, // AMOUNT, negative for withdrawals
1759
+ // -0.00135, // FEES
1760
+ // null,
1761
+ // null,
1762
+ // '0x38110e0Fc932CB2BE...........', // DESTINATION_ADDRESS
1763
+ // null,
1764
+ // null,
1765
+ // null,
1766
+ // '0x523ec8945500.....................................', // TRANSACTION_ID
1767
+ // "Purchase of 100 pizzas", // WITHDRAW_TRANSACTION_NOTE, might also be: null
1768
+ // ]
1769
+ // ]
1770
+ //
1771
+ return this.parseTransactions (response, currency, since, limit);
1772
+ }
1773
+
1774
+ async withdraw (code, amount, address, tag = undefined, params = {}) {
1775
+ this.checkAddress (address);
1776
+ await this.loadMarkets ();
1777
+ const currency = this.currency (code);
1778
+ // todo rewrite for https://api-pub.bitfinex.com//v2/conf/pub:map:tx:method
1779
+ const name = this.getCurrencyName (code);
1780
+ const request = {
1781
+ 'method': name,
1782
+ 'wallet': 'exchange', // 'exchange', 'margin', 'funding' and also old labels 'exchange', 'trading', 'deposit', respectively
1783
+ 'amount': this.numberToString (amount),
1784
+ 'address': address,
1785
+ };
1786
+ if (tag !== undefined) {
1787
+ request['payment_id'] = tag;
1788
+ }
1789
+ const response = await this.privatePostAuthWWithdraw (this.extend (request, params));
1790
+ //
1791
+ // [
1792
+ // 1582271520931, // MTS Millisecond Time Stamp of the update
1793
+ // "acc_wd-req", // TYPE Purpose of notification 'acc_wd-req' account withdrawal request
1794
+ // null, // MESSAGE_ID unique ID of the message
1795
+ // null, // not documented
1796
+ // [
1797
+ // 0, // WITHDRAWAL_ID Unique Withdrawal ID
1798
+ // null, // PLACEHOLDER
1799
+ // "bitcoin", // METHOD Method of withdrawal
1800
+ // null, // PAYMENT_ID Payment ID if relevant
1801
+ // "exchange", // WALLET Sending wallet
1802
+ // 1, // AMOUNT Amount of Withdrawal less fee
1803
+ // null, // PLACEHOLDER
1804
+ // null, // PLACEHOLDER
1805
+ // 0.0004, // WITHDRAWAL_FEE Fee on withdrawal
1806
+ // ],
1807
+ // null, // CODE null or integer Work in progress
1808
+ // "SUCCESS", // STATUS Status of the notification, it may vary over time SUCCESS, ERROR, FAILURE
1809
+ // "Invalid bitcoin address (abcdef)", // TEXT Text of the notification
1810
+ // ]
1811
+ //
1812
+ const text = this.safeString (response, 7);
1813
+ if (text !== 'success') {
1814
+ this.throwBroadlyMatchedException (this.exceptions['broad'], text, text);
1815
+ }
1816
+ const transaction = this.parseTransaction (response, currency);
1817
+ return this.extend (transaction, {
1818
+ 'address': address,
1819
+ });
1820
+ }
1821
+
1822
+ async fetchPositions (symbols = undefined, params = {}) {
1823
+ await this.loadMarkets ();
1824
+ const response = await this.privatePostAuthRPositions (params);
1825
+ //
1826
+ // [
1827
+ // [
1828
+ // "tBTCUSD", // SYMBOL
1829
+ // "ACTIVE", // STATUS
1830
+ // 0.0195, // AMOUNT
1831
+ // 8565.0267019, // BASE_PRICE
1832
+ // 0, // MARGIN_FUNDING
1833
+ // 0, // MARGIN_FUNDING_TYPE
1834
+ // -0.33455568705000516, // PL
1835
+ // -0.0003117550117425625, // PL_PERC
1836
+ // 7045.876419249083, // PRICE_LIQ
1837
+ // 3.0673001895895604, // LEVERAGE
1838
+ // null, // _PLACEHOLDER
1839
+ // 142355652, // POSITION_ID
1840
+ // 1574002216000, // MTS_CREATE
1841
+ // 1574002216000, // MTS_UPDATE
1842
+ // null, // _PLACEHOLDER
1843
+ // 0, // TYPE
1844
+ // null, // _PLACEHOLDER
1845
+ // 0, // COLLATERAL
1846
+ // 0, // COLLATERAL_MIN
1847
+ // // META
1848
+ // {
1849
+ // "reason":"TRADE",
1850
+ // "order_id":34271018124,
1851
+ // "liq_stage":null,
1852
+ // "trade_price":"8565.0267019",
1853
+ // "trade_amount":"0.0195",
1854
+ // "order_id_oppo":34277498022
1855
+ // }
1856
+ // ]
1857
+ // ]
1858
+ //
1859
+ // todo unify parsePosition/parsePositions
1860
+ return response;
1861
+ }
1862
+
1863
+ nonce () {
1864
+ return this.milliseconds ();
1865
+ }
1866
+
1867
+ sign (path, api = 'public', method = 'GET', params = {}, headers = undefined, body = undefined) {
1868
+ let request = '/' + this.implodeParams (path, params);
1869
+ const query = this.omit (params, this.extractParams (path));
1870
+ if (api === 'v1') {
1871
+ request = api + request;
1872
+ } else {
1873
+ request = this.version + request;
1874
+ }
1875
+ let url = this.urls['api'][api] + '/' + request;
1876
+ if (api === 'public') {
1877
+ if (Object.keys (query).length) {
1878
+ url += '?' + this.urlencode (query);
1879
+ }
1880
+ }
1881
+ if (api === 'private') {
1882
+ this.checkRequiredCredentials ();
1883
+ const nonce = this.nonce ().toString ();
1884
+ body = this.json (query);
1885
+ const auth = '/api/' + request + nonce + body;
1886
+ const signature = this.hmac (this.encode (auth), this.encode (this.secret), 'sha384');
1887
+ headers = {
1888
+ 'bfx-nonce': nonce,
1889
+ 'bfx-apikey': this.apiKey,
1890
+ 'bfx-signature': signature,
1891
+ 'Content-Type': 'application/json',
1892
+ };
1893
+ }
1894
+ return { 'url': url, 'method': method, 'body': body, 'headers': headers };
1895
+ }
1896
+
1897
+ handleErrors (statusCode, statusText, url, method, responseHeaders, responseBody, response, requestHeaders, requestBody) {
1898
+ if (response !== undefined) {
1899
+ if (!Array.isArray (response)) {
1900
+ const message = this.safeString2 (response, 'message', 'error');
1901
+ const feedback = this.id + ' ' + responseBody;
1902
+ this.throwExactlyMatchedException (this.exceptions['exact'], message, feedback);
1903
+ this.throwBroadlyMatchedException (this.exceptions['broad'], message, feedback);
1904
+ throw new ExchangeError (this.id + ' ' + responseBody);
1905
+ }
1906
+ } else if (response === '') {
1907
+ throw new ExchangeError (this.id + ' returned empty response');
1908
+ }
1909
+ if (statusCode === 500) {
1910
+ // See https://docs.bitfinex.com/docs/abbreviations-glossary#section-errorinfo-codes
1911
+ const errorCode = this.numberToString (response[1]);
1912
+ const errorText = response[2];
1913
+ const feedback = this.id + ' ' + errorText;
1914
+ this.throwExactlyMatchedException (this.exceptions['exact'], errorCode, feedback);
1915
+ this.throwExactlyMatchedException (this.exceptions['exact'], errorText, feedback);
1916
+ this.throwBroadlyMatchedException (this.exceptions['broad'], errorText, feedback);
1917
+ throw new ExchangeError (this.id + ' ' + errorText + ' (#' + errorCode + ')');
1918
+ }
1919
+ return response;
1920
+ }
1921
+
1922
+ parseLedgerEntryType (type) {
1923
+ if (type === undefined) {
1924
+ return undefined;
1925
+ } else if (type.indexOf ('fee') >= 0 || type.indexOf ('charged') >= 0) {
1926
+ return 'fee';
1927
+ } else if (type.indexOf ('exchange') >= 0 || type.indexOf ('position') >= 0) {
1928
+ return 'trade';
1929
+ } else if (type.indexOf ('rebate') >= 0) {
1930
+ return 'rebate';
1931
+ } else if (type.indexOf ('deposit') >= 0 || type.indexOf ('withdrawal') >= 0) {
1932
+ return 'transaction';
1933
+ } else if (type.indexOf ('transfer') >= 0) {
1934
+ return 'transfer';
1935
+ } else if (type.indexOf ('payment') >= 0) {
1936
+ return 'payout';
1937
+ } else {
1938
+ return type;
1939
+ }
1940
+ }
1941
+
1942
+ parseLedgerEntry (item, currency = undefined) {
1943
+ //
1944
+ // [
1945
+ // [
1946
+ // 2531822314, // ID: Ledger identifier
1947
+ // "USD", // CURRENCY: The symbol of the currency (ex. "BTC")
1948
+ // null, // PLACEHOLDER
1949
+ // 1573521810000, // MTS: Timestamp in milliseconds
1950
+ // null, // PLACEHOLDER
1951
+ // 0.01644445, // AMOUNT: Amount of funds moved
1952
+ // 0, // BALANCE: New balance
1953
+ // null, // PLACEHOLDER
1954
+ // "Settlement @ 185.79 on wallet margin" // DESCRIPTION: Description of ledger transaction
1955
+ // ]
1956
+ // ]
1957
+ //
1958
+ let type = undefined;
1959
+ const id = this.safeString (item, 0);
1960
+ const currencyId = this.safeString (item, 1);
1961
+ const code = this.safeCurrencyCode (currencyId, currency);
1962
+ const timestamp = this.safeInteger (item, 3);
1963
+ const amount = this.safeNumber (item, 5);
1964
+ const after = this.safeNumber (item, 6);
1965
+ const description = this.safeString (item, 8);
1966
+ if (description !== undefined) {
1967
+ const parts = description.split (' @ ');
1968
+ const first = this.safeStringLower (parts, 0);
1969
+ type = this.parseLedgerEntryType (first);
1970
+ }
1971
+ return {
1972
+ 'id': id,
1973
+ 'direction': undefined,
1974
+ 'account': undefined,
1975
+ 'referenceId': id,
1976
+ 'referenceAccount': undefined,
1977
+ 'type': type,
1978
+ 'currency': code,
1979
+ 'amount': amount,
1980
+ 'timestamp': timestamp,
1981
+ 'datetime': this.iso8601 (timestamp),
1982
+ 'before': undefined,
1983
+ 'after': after,
1984
+ 'status': undefined,
1985
+ 'fee': undefined,
1986
+ 'info': item,
1987
+ };
1988
+ }
1989
+
1990
+ async fetchLedger (code = undefined, since = undefined, limit = undefined, params = {}) {
1991
+ await this.loadMarkets ();
1992
+ await this.loadMarkets ();
1993
+ let currency = undefined;
1994
+ const request = {};
1995
+ let method = 'privatePostAuthRLedgersHist';
1996
+ if (code !== undefined) {
1997
+ currency = this.currency (code);
1998
+ request['currency'] = currency['uppercaseId'];
1999
+ method = 'privatePostAuthRLedgersCurrencyHist';
2000
+ }
2001
+ if (since !== undefined) {
2002
+ request['start'] = since;
2003
+ }
2004
+ if (limit !== undefined) {
2005
+ request['limit'] = limit; // max 2500
2006
+ }
2007
+ const response = await this[method] (this.extend (request, params));
2008
+ //
2009
+ // [
2010
+ // [
2011
+ // 2531822314, // ID: Ledger identifier
2012
+ // "USD", // CURRENCY: The symbol of the currency (ex. "BTC")
2013
+ // null, // PLACEHOLDER
2014
+ // 1573521810000, // MTS: Timestamp in milliseconds
2015
+ // null, // PLACEHOLDER
2016
+ // 0.01644445, // AMOUNT: Amount of funds moved
2017
+ // 0, // BALANCE: New balance
2018
+ // null, // PLACEHOLDER
2019
+ // "Settlement @ 185.79 on wallet margin" // DESCRIPTION: Description of ledger transaction
2020
+ // ]
2021
+ // ]
2022
+ //
2023
+ return this.parseLedger (response, currency, since, limit);
2024
+ }
2025
+ };