ccxt 4.4.88__py2.py3-none-any.whl → 4.4.91__py2.py3-none-any.whl

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 (101) hide show
  1. ccxt/__init__.py +1 -3
  2. ccxt/abstract/bitget.py +58 -0
  3. ccxt/abstract/bitrue.py +65 -65
  4. ccxt/abstract/cryptocom.py +2 -0
  5. ccxt/abstract/luno.py +1 -0
  6. ccxt/async_support/__init__.py +1 -3
  7. ccxt/async_support/base/exchange.py +6 -3
  8. ccxt/async_support/base/ws/client.py +173 -64
  9. ccxt/async_support/base/ws/future.py +23 -50
  10. ccxt/async_support/binance.py +2 -2
  11. ccxt/async_support/bingx.py +55 -29
  12. ccxt/async_support/bitget.py +469 -147
  13. ccxt/async_support/bitmex.py +2 -1
  14. ccxt/async_support/bitrue.py +72 -66
  15. ccxt/async_support/bitvavo.py +34 -0
  16. ccxt/async_support/btcalpha.py +35 -0
  17. ccxt/async_support/btcbox.py +35 -0
  18. ccxt/async_support/btcmarkets.py +35 -0
  19. ccxt/async_support/btcturk.py +35 -0
  20. ccxt/async_support/bybit.py +9 -3
  21. ccxt/async_support/cex.py +61 -0
  22. ccxt/async_support/coinbase.py +1 -3
  23. ccxt/async_support/cryptocom.py +66 -2
  24. ccxt/async_support/cryptomus.py +1 -1
  25. ccxt/async_support/delta.py +2 -2
  26. ccxt/async_support/digifinex.py +39 -99
  27. ccxt/async_support/exmo.py +14 -7
  28. ccxt/async_support/gate.py +14 -7
  29. ccxt/async_support/hashkey.py +15 -28
  30. ccxt/async_support/hollaex.py +27 -22
  31. ccxt/async_support/hyperliquid.py +104 -53
  32. ccxt/async_support/kraken.py +54 -50
  33. ccxt/async_support/luno.py +87 -1
  34. ccxt/async_support/mexc.py +1 -0
  35. ccxt/async_support/modetrade.py +2 -2
  36. ccxt/async_support/okx.py +2 -1
  37. ccxt/async_support/paradex.py +1 -1
  38. ccxt/async_support/phemex.py +16 -8
  39. ccxt/async_support/tradeogre.py +3 -3
  40. ccxt/async_support/xt.py +1 -1
  41. ccxt/base/exchange.py +20 -8
  42. ccxt/binance.py +2 -2
  43. ccxt/bingx.py +55 -29
  44. ccxt/bitget.py +469 -147
  45. ccxt/bitmex.py +2 -1
  46. ccxt/bitrue.py +72 -66
  47. ccxt/bitvavo.py +34 -0
  48. ccxt/btcalpha.py +35 -0
  49. ccxt/btcbox.py +35 -0
  50. ccxt/btcmarkets.py +35 -0
  51. ccxt/btcturk.py +35 -0
  52. ccxt/bybit.py +9 -3
  53. ccxt/cex.py +61 -0
  54. ccxt/coinbase.py +1 -3
  55. ccxt/cryptocom.py +66 -2
  56. ccxt/cryptomus.py +1 -1
  57. ccxt/delta.py +2 -2
  58. ccxt/digifinex.py +39 -99
  59. ccxt/exmo.py +13 -7
  60. ccxt/gate.py +14 -7
  61. ccxt/hashkey.py +15 -28
  62. ccxt/hollaex.py +27 -22
  63. ccxt/hyperliquid.py +104 -53
  64. ccxt/kraken.py +53 -50
  65. ccxt/luno.py +87 -1
  66. ccxt/mexc.py +1 -0
  67. ccxt/modetrade.py +2 -2
  68. ccxt/okx.py +2 -1
  69. ccxt/paradex.py +1 -1
  70. ccxt/phemex.py +16 -8
  71. ccxt/pro/__init__.py +1 -127
  72. ccxt/pro/bitstamp.py +1 -1
  73. ccxt/pro/bybit.py +6 -136
  74. ccxt/pro/coinbase.py +2 -0
  75. ccxt/pro/cryptocom.py +27 -0
  76. ccxt/pro/kraken.py +249 -267
  77. ccxt/pro/mexc.py +0 -1
  78. ccxt/tradeogre.py +3 -3
  79. ccxt/xt.py +1 -1
  80. {ccxt-4.4.88.dist-info → ccxt-4.4.91.dist-info}/METADATA +64 -23
  81. {ccxt-4.4.88.dist-info → ccxt-4.4.91.dist-info}/RECORD +84 -101
  82. ccxt/abstract/coinlist.py +0 -57
  83. ccxt/async_support/base/ws/aiohttp_client.py +0 -147
  84. ccxt/async_support/bitcoincom.py +0 -18
  85. ccxt/async_support/bitfinex1.py +0 -1711
  86. ccxt/async_support/bitpanda.py +0 -17
  87. ccxt/async_support/coinlist.py +0 -2542
  88. ccxt/async_support/poloniexfutures.py +0 -1875
  89. ccxt/bitcoincom.py +0 -18
  90. ccxt/bitfinex1.py +0 -1710
  91. ccxt/bitpanda.py +0 -17
  92. ccxt/coinlist.py +0 -2542
  93. ccxt/poloniexfutures.py +0 -1875
  94. ccxt/pro/bitcoincom.py +0 -35
  95. ccxt/pro/bitfinex1.py +0 -635
  96. ccxt/pro/bitpanda.py +0 -16
  97. ccxt/pro/poloniexfutures.py +0 -1004
  98. ccxt/pro/wazirx.py +0 -766
  99. {ccxt-4.4.88.dist-info → ccxt-4.4.91.dist-info}/LICENSE.txt +0 -0
  100. {ccxt-4.4.88.dist-info → ccxt-4.4.91.dist-info}/WHEEL +0 -0
  101. {ccxt-4.4.88.dist-info → ccxt-4.4.91.dist-info}/top_level.txt +0 -0
ccxt/bitfinex1.py DELETED
@@ -1,1710 +0,0 @@
1
- # -*- coding: utf-8 -*-
2
-
3
- # PLEASE DO NOT EDIT THIS FILE, IT IS GENERATED AND WILL BE OVERWRITTEN:
4
- # https://github.com/ccxt/ccxt/blob/master/CONTRIBUTING.md#how-to-contribute-code
5
-
6
- from ccxt.base.exchange import Exchange
7
- from ccxt.abstract.bitfinex1 import ImplicitAPI
8
- import hashlib
9
- from ccxt.base.types import Any, Balances, Currency, DepositAddress, Int, Market, Num, Order, OrderBook, OrderSide, OrderType, Str, Strings, Ticker, Tickers, Trade, TradingFees, Transaction, TransferEntry
10
- from typing import List
11
- from ccxt.base.errors import ExchangeError
12
- from ccxt.base.errors import AuthenticationError
13
- from ccxt.base.errors import PermissionDenied
14
- from ccxt.base.errors import ArgumentsRequired
15
- from ccxt.base.errors import BadSymbol
16
- from ccxt.base.errors import InsufficientFunds
17
- from ccxt.base.errors import InvalidOrder
18
- from ccxt.base.errors import OrderNotFound
19
- from ccxt.base.errors import NotSupported
20
- from ccxt.base.errors import RateLimitExceeded
21
- from ccxt.base.errors import ExchangeNotAvailable
22
- from ccxt.base.errors import InvalidNonce
23
- from ccxt.base.decimal_to_precision import ROUND
24
- from ccxt.base.decimal_to_precision import TRUNCATE
25
- from ccxt.base.decimal_to_precision import DECIMAL_PLACES
26
- from ccxt.base.decimal_to_precision import SIGNIFICANT_DIGITS
27
- from ccxt.base.precise import Precise
28
-
29
-
30
- class bitfinex1(Exchange, ImplicitAPI):
31
-
32
- def describe(self) -> Any:
33
- return self.deep_extend(super(bitfinex1, self).describe(), {
34
- 'id': 'bitfinex1',
35
- 'name': 'Bitfinex',
36
- 'countries': ['VG'],
37
- 'version': 'v1',
38
- # cheapest is 90 requests a minute = 1.5 requests per second on average =>( 1000ms / 1.5) = 666.666 ms between requests on average
39
- 'rateLimit': 666.666,
40
- 'pro': True,
41
- # new metainfo interface
42
- 'has': {
43
- 'CORS': None,
44
- 'spot': True,
45
- 'margin': None, # has but unimplemented
46
- 'swap': None, # has but unimplemented
47
- 'future': None,
48
- 'option': None,
49
- 'cancelAllOrders': True,
50
- 'cancelOrder': True,
51
- 'createDepositAddress': True,
52
- 'createOrder': True,
53
- 'editOrder': True,
54
- 'fetchBalance': True,
55
- 'fetchClosedOrders': True,
56
- 'fetchDepositAddress': True,
57
- 'fetchDepositAddresses': False,
58
- 'fetchDepositAddressesByNetwork': False,
59
- 'fetchDeposits': False,
60
- 'fetchDepositsWithdrawals': True,
61
- 'fetchDepositWithdrawFee': 'emulated',
62
- 'fetchDepositWithdrawFees': True,
63
- 'fetchFundingHistory': False,
64
- 'fetchFundingRate': False, # Endpoint 'lendbook/{currency}' is related to interest rates on spot margin lending
65
- 'fetchFundingRateHistory': False,
66
- 'fetchFundingRates': False,
67
- 'fetchIndexOHLCV': False,
68
- 'fetchLeverageTiers': False,
69
- 'fetchMarginMode': False,
70
- 'fetchMarkets': True,
71
- 'fetchMarkOHLCV': False,
72
- 'fetchMyTrades': True,
73
- 'fetchOHLCV': True,
74
- 'fetchOpenOrders': True,
75
- 'fetchOrder': True,
76
- 'fetchOrderBook': True,
77
- 'fetchPositionMode': False,
78
- 'fetchPositions': True,
79
- 'fetchPremiumIndexOHLCV': False,
80
- 'fetchTicker': True,
81
- 'fetchTickers': True,
82
- 'fetchTime': False,
83
- 'fetchTrades': True,
84
- 'fetchTradingFee': False,
85
- 'fetchTradingFees': True,
86
- 'fetchTransactionFees': True,
87
- 'fetchTransactions': 'emulated',
88
- 'transfer': True,
89
- 'withdraw': True,
90
- },
91
- 'timeframes': {
92
- '1m': '1m',
93
- '5m': '5m',
94
- '15m': '15m',
95
- '30m': '30m',
96
- '1h': '1h',
97
- '3h': '3h',
98
- '4h': '4h',
99
- '6h': '6h',
100
- '12h': '12h',
101
- '1d': '1D',
102
- '1w': '7D',
103
- '2w': '14D',
104
- '1M': '1M',
105
- },
106
- 'urls': {
107
- 'logo': 'https://github.com/user-attachments/assets/9147c6c5-7197-481e-827b-7483672bb0e9',
108
- 'api': {
109
- 'v2': 'https://api-pub.bitfinex.com', # https://github.com/ccxt/ccxt/issues/5109
110
- 'public': 'https://api.bitfinex.com',
111
- 'private': 'https://api.bitfinex.com',
112
- },
113
- 'www': 'https://www.bitfinex.com',
114
- 'referral': 'https://www.bitfinex.com/?refcode=P61eYxFL',
115
- 'doc': [
116
- 'https://docs.bitfinex.com/v1/docs',
117
- 'https://github.com/bitfinexcom/bitfinex-api-node',
118
- ],
119
- },
120
- 'api': {
121
- # v2 symbol ids require a 't' prefix
122
- # just the public part of it(use bitfinex2 for everything else)
123
- 'v2': {
124
- 'get': {
125
- 'platform/status': 3, # 30 requests per minute
126
- 'tickers': 1, # 90 requests a minute
127
- 'ticker/{symbol}': 1,
128
- 'tickers/hist': 1,
129
- 'trades/{symbol}/hist': 1,
130
- 'book/{symbol}/{precision}': 0.375, # 240 requests per minute = 4 requests per second(1000ms / rateLimit) / 4 = 0.37500375
131
- 'book/{symbol}/P0': 0.375,
132
- 'book/{symbol}/P1': 0.375,
133
- 'book/{symbol}/P2': 0.375,
134
- 'book/{symbol}/P3': 0.375,
135
- 'book/{symbol}/R0': 0.375,
136
- 'stats1/{key}:{size}:{symbol}:{side}/{section}': 1, # 90 requests a minute
137
- 'stats1/{key}:{size}:{symbol}/{section}': 1,
138
- 'stats1/{key}:{size}:{symbol}:long/last': 1,
139
- 'stats1/{key}:{size}:{symbol}:long/hist': 1,
140
- 'stats1/{key}:{size}:{symbol}:short/last': 1,
141
- 'stats1/{key}:{size}:{symbol}:short/hist': 1,
142
- 'candles/trade:{timeframe}:{symbol}/{section}': 1, # 90 requests a minute
143
- 'candles/trade:{timeframe}:{symbol}/last': 1,
144
- 'candles/trade:{timeframe}:{symbol}/hist': 1,
145
- },
146
- },
147
- 'public': {
148
- 'get': {
149
- 'book/{symbol}': 1, # 90 requests a minute
150
- # 'candles/{symbol}':0,
151
- 'lendbook/{currency}': 6, # 15 requests a minute
152
- 'lends/{currency}': 3, # 30 requests a minute
153
- 'pubticker/{symbol}': 3, # 30 requests a minute = 0.5 requests per second =>(1000ms / rateLimit) / 0.5 = 3.00003
154
- 'stats/{symbol}': 6, # 15 requests a minute = 0.25 requests per second =>(1000ms / rateLimit ) /0.25 = 6.00006(endpoint returns red html... or 'unknown symbol')
155
- 'symbols': 18, # 5 requests a minute = 0.08333 requests per second =>(1000ms / rateLimit) / 0.08333 = 18.0009
156
- 'symbols_details': 18, # 5 requests a minute
157
- 'tickers': 1, # endpoint not mentioned in v1 docs... but still responds
158
- 'trades/{symbol}': 3, # 60 requests a minute = 1 request per second =>(1000ms / rateLimit) / 1 = 1.5 ... but only works if set to 3
159
- },
160
- },
161
- 'private': {
162
- 'post': {
163
- 'account_fees': 18,
164
- 'account_infos': 6,
165
- 'balances': 9.036, # 10 requests a minute = 0.166 requests per second =>(1000ms / rateLimit) / 0.166 = 9.036
166
- 'basket_manage': 6,
167
- 'credits': 6,
168
- 'deposit/new': 18,
169
- 'funding/close': 6,
170
- 'history': 6, # 15 requests a minute
171
- 'history/movements': 6,
172
- 'key_info': 6,
173
- 'margin_infos': 3, # 30 requests a minute
174
- 'mytrades': 3,
175
- 'mytrades_funding': 6,
176
- 'offer/cancel': 6,
177
- 'offer/new': 6,
178
- 'offer/status': 6,
179
- 'offers': 6,
180
- 'offers/hist': 90.03, # one request per minute
181
- 'order/cancel': 0.2,
182
- 'order/cancel/all': 0.2,
183
- 'order/cancel/multi': 0.2,
184
- 'order/cancel/replace': 0.2,
185
- 'order/new': 0.2, # 450 requests a minute = 7.5 request a second =>(1000ms / rateLimit) / 7.5 = 0.2000002
186
- 'order/new/multi': 0.2,
187
- 'order/status': 0.2,
188
- 'orders': 0.2,
189
- 'orders/hist': 90.03, # one request per minute = 0.1666 =>(1000ms / rateLimit) / 0.01666 = 90.03
190
- 'position/claim': 18,
191
- 'position/close': 18,
192
- 'positions': 18,
193
- 'summary': 18,
194
- 'taken_funds': 6,
195
- 'total_taken_funds': 6,
196
- 'transfer': 18,
197
- 'unused_taken_funds': 6,
198
- 'withdraw': 18,
199
- },
200
- },
201
- },
202
- 'fees': {
203
- 'trading': {
204
- 'feeSide': 'get',
205
- 'tierBased': True,
206
- 'percentage': True,
207
- 'maker': self.parse_number('0.001'),
208
- 'taker': self.parse_number('0.002'),
209
- 'tiers': {
210
- 'taker': [
211
- [self.parse_number('0'), self.parse_number('0.002')],
212
- [self.parse_number('500000'), self.parse_number('0.002')],
213
- [self.parse_number('1000000'), self.parse_number('0.002')],
214
- [self.parse_number('2500000'), self.parse_number('0.002')],
215
- [self.parse_number('5000000'), self.parse_number('0.002')],
216
- [self.parse_number('7500000'), self.parse_number('0.002')],
217
- [self.parse_number('10000000'), self.parse_number('0.0018')],
218
- [self.parse_number('15000000'), self.parse_number('0.0016')],
219
- [self.parse_number('20000000'), self.parse_number('0.0014')],
220
- [self.parse_number('25000000'), self.parse_number('0.0012')],
221
- [self.parse_number('30000000'), self.parse_number('0.001')],
222
- ],
223
- 'maker': [
224
- [self.parse_number('0'), self.parse_number('0.001')],
225
- [self.parse_number('500000'), self.parse_number('0.0008')],
226
- [self.parse_number('1000000'), self.parse_number('0.0006')],
227
- [self.parse_number('2500000'), self.parse_number('0.0004')],
228
- [self.parse_number('5000000'), self.parse_number('0.0002')],
229
- [self.parse_number('7500000'), self.parse_number('0')],
230
- [self.parse_number('10000000'), self.parse_number('0')],
231
- [self.parse_number('15000000'), self.parse_number('0')],
232
- [self.parse_number('20000000'), self.parse_number('0')],
233
- [self.parse_number('25000000'), self.parse_number('0')],
234
- [self.parse_number('30000000'), self.parse_number('0')],
235
- ],
236
- },
237
- },
238
- 'funding': {
239
- 'tierBased': False, # True for tier-based/progressive
240
- 'percentage': False, # fixed commission
241
- # Actually deposit fees are free for larger deposits(> $1000 USD equivalent)
242
- # these values below are deprecated, we should not hardcode fees and limits anymore
243
- # to be reimplemented with bitfinex funding fees from their API or web endpoints
244
- 'deposit': {},
245
- 'withdraw': {},
246
- },
247
- },
248
- # todo rewrite for https://api-pub.bitfinex.com//v2/conf/pub:map:tx:method
249
- 'commonCurrencies': {
250
- 'ALG': 'ALGO', # https://github.com/ccxt/ccxt/issues/6034
251
- 'AMP': 'AMPL',
252
- 'ATO': 'ATOM', # https://github.com/ccxt/ccxt/issues/5118
253
- 'BCHABC': 'XEC',
254
- 'BCHN': 'BCH',
255
- 'DAT': 'DATA',
256
- 'DOG': 'MDOGE',
257
- 'DSH': 'DASH',
258
- # https://github.com/ccxt/ccxt/issues/7399
259
- # https://coinmarketcap.com/currencies/pnetwork/
260
- # https://en.cryptonomist.ch/blog/eidoo/the-edo-to-pnt-upgrade-what-you-need-to-know-updated/
261
- 'EDO': 'PNT',
262
- 'EUS': 'EURS',
263
- 'EUT': 'EURT',
264
- 'IDX': 'ID',
265
- 'IOT': 'IOTA',
266
- 'IQX': 'IQ',
267
- 'LUNA': 'LUNC',
268
- 'LUNA2': 'LUNA',
269
- 'MNA': 'MANA',
270
- 'ORS': 'ORS Group', # conflict with Origin Sport #3230
271
- 'PAS': 'PASS',
272
- 'QSH': 'QASH',
273
- 'QTM': 'QTUM',
274
- 'RBT': 'RBTC',
275
- 'SNG': 'SNGLS',
276
- 'STJ': 'STORJ',
277
- 'TERRAUST': 'USTC',
278
- 'TSD': 'TUSD',
279
- 'YGG': 'YEED', # conflict with Yield Guild Games
280
- 'YYW': 'YOYOW',
281
- 'UDC': 'USDC',
282
- 'UST': 'USDT',
283
- 'VSY': 'VSYS',
284
- 'WAX': 'WAXP',
285
- 'XCH': 'XCHF',
286
- 'ZBT': 'ZB',
287
- },
288
- 'exceptions': {
289
- 'exact': {
290
- 'temporarily_unavailable': ExchangeNotAvailable, # Sorry, the service is temporarily unavailable. See https://www.bitfinex.com/ for more info.
291
- 'Order could not be cancelled.': OrderNotFound, # non-existent order
292
- 'No such order found.': OrderNotFound, # ?
293
- 'Order price must be positive.': InvalidOrder, # on price <= 0
294
- 'Could not find a key matching the given X-BFX-APIKEY.': AuthenticationError,
295
- 'Key price should be a decimal number, e.g. "123.456"': InvalidOrder, # on isNaN(price)
296
- 'Key amount should be a decimal number, e.g. "123.456"': InvalidOrder, # on isNaN(amount)
297
- 'ERR_RATE_LIMIT': RateLimitExceeded,
298
- 'Ratelimit': RateLimitExceeded,
299
- 'Nonce is too small.': InvalidNonce,
300
- 'No summary found.': ExchangeError, # fetchTradingFees(summary) endpoint can give self vague error message
301
- 'Cannot evaluate your available balance, please try again': ExchangeNotAvailable,
302
- 'Unknown symbol': BadSymbol,
303
- 'Cannot complete transfer. Exchange balance insufficient.': InsufficientFunds,
304
- 'Momentary balance check. Please wait few seconds and try the transfer again.': ExchangeError,
305
- },
306
- 'broad': {
307
- 'Invalid X-BFX-SIGNATURE': AuthenticationError,
308
- 'This API key does not have permission': PermissionDenied, # authenticated but not authorized
309
- 'not enough exchange balance for ': InsufficientFunds, # when buying cost is greater than the available quote currency
310
- 'minimum size for ': InvalidOrder, # when amount below limits.amount.min
311
- 'Invalid order': InvalidOrder, # ?
312
- 'The available balance is only': InsufficientFunds, # {"status":"error","message":"Cannot withdraw 1.0027 ETH from your exchange wallet. The available balance is only 0.0 ETH. If you have limit orders, open positions, unused or active margin funding, self will decrease your available balance. To increase it, you can cancel limit orders or reduce/close your positions.","withdrawal_id":0,"fees":"0.0027"}
313
- },
314
- },
315
- 'precisionMode': SIGNIFICANT_DIGITS,
316
- 'options': {
317
- 'currencyNames': {
318
- 'AGI': 'agi',
319
- 'AID': 'aid',
320
- 'AIO': 'aio',
321
- 'ANT': 'ant',
322
- 'AVT': 'aventus', # #1811
323
- 'BAT': 'bat',
324
- # https://github.com/ccxt/ccxt/issues/5833
325
- 'BCH': 'bab', # undocumented
326
- # 'BCH': 'bcash', # undocumented
327
- 'BCI': 'bci',
328
- 'BFT': 'bft',
329
- 'BSV': 'bsv',
330
- 'BTC': 'bitcoin',
331
- 'BTG': 'bgold',
332
- 'CFI': 'cfi',
333
- 'COMP': 'comp',
334
- 'DAI': 'dai',
335
- 'DADI': 'dad',
336
- 'DASH': 'dash',
337
- 'DATA': 'datacoin',
338
- 'DTH': 'dth',
339
- 'EDO': 'eidoo', # #1811
340
- 'ELF': 'elf',
341
- 'EOS': 'eos',
342
- 'ETC': 'ethereumc',
343
- 'ETH': 'ethereum',
344
- 'ETP': 'metaverse',
345
- 'FUN': 'fun',
346
- 'GNT': 'golem',
347
- 'IOST': 'ios',
348
- 'IOTA': 'iota',
349
- # https://github.com/ccxt/ccxt/issues/5833
350
- 'LEO': 'let', # ETH chain
351
- # 'LEO': 'les', # EOS chain
352
- 'LINK': 'link',
353
- 'LRC': 'lrc',
354
- 'LTC': 'litecoin',
355
- 'LYM': 'lym',
356
- 'MANA': 'mna',
357
- 'MIT': 'mit',
358
- 'MKR': 'mkr',
359
- 'MTN': 'mtn',
360
- 'NEO': 'neo',
361
- 'ODE': 'ode',
362
- 'OMG': 'omisego',
363
- 'OMNI': 'mastercoin',
364
- 'QASH': 'qash',
365
- 'QTUM': 'qtum', # #1811
366
- 'RCN': 'rcn',
367
- 'RDN': 'rdn',
368
- 'REP': 'rep',
369
- 'REQ': 'req',
370
- 'RLC': 'rlc',
371
- 'SAN': 'santiment',
372
- 'SNGLS': 'sng',
373
- 'SNT': 'status',
374
- 'SPANK': 'spk',
375
- 'STORJ': 'stj',
376
- 'TNB': 'tnb',
377
- 'TRX': 'trx',
378
- 'TUSD': 'tsd',
379
- 'USD': 'wire',
380
- 'USDC': 'udc', # https://github.com/ccxt/ccxt/issues/5833
381
- 'UTK': 'utk',
382
- 'USDT': 'tetheruso', # Tether on Omni
383
- # 'USDT': 'tetheruse', # Tether on ERC20
384
- # 'USDT': 'tetherusl', # Tether on Liquid
385
- # 'USDT': 'tetherusx', # Tether on Tron
386
- # 'USDT': 'tetheruss', # Tether on EOS
387
- 'VEE': 'vee',
388
- 'WAX': 'wax',
389
- 'XLM': 'xlm',
390
- 'XMR': 'monero',
391
- 'XRP': 'ripple',
392
- 'XVG': 'xvg',
393
- 'YOYOW': 'yoyow',
394
- 'ZEC': 'zcash',
395
- 'ZRX': 'zrx',
396
- 'XTZ': 'xtz',
397
- },
398
- 'orderTypes': {
399
- 'limit': 'exchange limit',
400
- 'market': 'exchange market',
401
- },
402
- 'fiat': {
403
- 'USD': 'USD',
404
- 'EUR': 'EUR',
405
- 'JPY': 'JPY',
406
- 'GBP': 'GBP',
407
- 'CNH': 'CNH',
408
- },
409
- 'accountsByType': {
410
- 'spot': 'exchange',
411
- 'margin': 'trading',
412
- 'funding': 'deposit',
413
- 'swap': 'trading',
414
- },
415
- },
416
- })
417
-
418
- def fetch_transaction_fees(self, codes: Strings = None, params={}):
419
- """
420
- @deprecated
421
- please use fetchDepositWithdrawFees instead
422
-
423
- https://docs.bitfinex.com/v1/reference/rest-auth-fees
424
-
425
- :param str[]|None codes: list of unified currency codes
426
- :param dict [params]: extra parameters specific to the exchange API endpoint
427
- :returns dict[]: a list of `fees structures <https://docs.ccxt.com/#/?id=fee-structure>`
428
- """
429
- self.load_markets()
430
- result: dict = {}
431
- response = self.privatePostAccountFees(params)
432
- #
433
- # {
434
- # "withdraw": {
435
- # "BTC": "0.0004",
436
- # }
437
- # }
438
- #
439
- fees = self.safe_dict(response, 'withdraw', {})
440
- ids = list(fees.keys())
441
- for i in range(0, len(ids)):
442
- id = ids[i]
443
- code = self.safe_currency_code(id)
444
- if (codes is not None) and not self.in_array(code, codes):
445
- continue
446
- result[code] = {
447
- 'withdraw': self.safe_number(fees, id),
448
- 'deposit': {},
449
- 'info': self.safe_number(fees, id),
450
- }
451
- return result
452
-
453
- def fetch_deposit_withdraw_fees(self, codes: Strings = None, params={}):
454
- """
455
- fetch deposit and withdraw fees
456
-
457
- https://docs.bitfinex.com/v1/reference/rest-auth-fees
458
-
459
- :param str[]|None codes: list of unified currency codes
460
- :param dict [params]: extra parameters specific to the exchange API endpoint
461
- :returns dict[]: a list of `fees structures <https://docs.ccxt.com/#/?id=fee-structure>`
462
- """
463
- self.load_markets()
464
- response = self.privatePostAccountFees(params)
465
- #
466
- # {
467
- # "withdraw": {
468
- # "BTC": "0.0004",
469
- # ...
470
- # }
471
- # }
472
- #
473
- withdraw = self.safe_list(response, 'withdraw')
474
- return self.parse_deposit_withdraw_fees(withdraw, codes)
475
-
476
- def parse_deposit_withdraw_fee(self, fee, currency: Currency = None):
477
- #
478
- # '0.0004'
479
- #
480
- return {
481
- 'withdraw': {
482
- 'fee': self.parse_number(fee),
483
- 'percentage': None,
484
- },
485
- 'deposit': {
486
- 'fee': None,
487
- 'percentage': None,
488
- },
489
- 'networks': {},
490
- 'info': fee,
491
- }
492
-
493
- def fetch_trading_fees(self, params={}) -> TradingFees:
494
- """
495
- fetch the trading fees for multiple markets
496
-
497
- https://docs.bitfinex.com/v1/reference/rest-auth-summary
498
-
499
- :param dict [params]: extra parameters specific to the exchange API endpoint
500
- :returns dict: a dictionary of `fee structures <https://docs.ccxt.com/#/?id=fee-structure>` indexed by market symbols
501
- """
502
- self.load_markets()
503
- response = self.privatePostSummary(params)
504
- #
505
- # {
506
- # "time": "2022-02-23T16:05:47.659000Z",
507
- # "status": {resid_hint: null, login_last: "2022-02-23T16:05:48Z"},
508
- # "is_locked": False,
509
- # "leo_lev": "0",
510
- # "leo_amount_avg": "0.0",
511
- # "trade_vol_30d": [
512
- # {
513
- # "curr": "Total(USD)",
514
- # "vol": "0.0",
515
- # "vol_safe": "0.0",
516
- # "vol_maker": "0.0",
517
- # "vol_BFX": "0.0",
518
- # "vol_BFX_safe": "0.0",
519
- # "vol_BFX_maker": "0.0"
520
- # }
521
- # ],
522
- # "fees_funding_30d": {},
523
- # "fees_funding_total_30d": "0",
524
- # "fees_trading_30d": {},
525
- # "fees_trading_total_30d": "0",
526
- # "rebates_trading_30d": {},
527
- # "rebates_trading_total_30d": "0",
528
- # "maker_fee": "0.001",
529
- # "taker_fee": "0.002",
530
- # "maker_fee_2crypto": "0.001",
531
- # "maker_fee_2stablecoin": "0.001",
532
- # "maker_fee_2fiat": "0.001",
533
- # "maker_fee_2deriv": "0.0002",
534
- # "taker_fee_2crypto": "0.002",
535
- # "taker_fee_2stablecoin": "0.002",
536
- # "taker_fee_2fiat": "0.002",
537
- # "taker_fee_2deriv": "0.00065",
538
- # "deriv_maker_rebate": "0.0002",
539
- # "deriv_taker_fee": "0.00065",
540
- # "trade_last": null
541
- # }
542
- #
543
- result: dict = {}
544
- fiat = self.safe_dict(self.options, 'fiat', {})
545
- makerFee = self.safe_number(response, 'maker_fee')
546
- takerFee = self.safe_number(response, 'taker_fee')
547
- makerFee2Fiat = self.safe_number(response, 'maker_fee_2fiat')
548
- takerFee2Fiat = self.safe_number(response, 'taker_fee_2fiat')
549
- makerFee2Deriv = self.safe_number(response, 'maker_fee_2deriv')
550
- takerFee2Deriv = self.safe_number(response, 'taker_fee_2deriv')
551
- for i in range(0, len(self.symbols)):
552
- symbol = self.symbols[i]
553
- market = self.market(symbol)
554
- fee = {
555
- 'info': response,
556
- 'symbol': symbol,
557
- 'percentage': True,
558
- 'tierBased': True,
559
- }
560
- if market['quote'] in fiat:
561
- fee['maker'] = makerFee2Fiat
562
- fee['taker'] = takerFee2Fiat
563
- elif market['contract']:
564
- fee['maker'] = makerFee2Deriv
565
- fee['taker'] = takerFee2Deriv
566
- else:
567
- fee['maker'] = makerFee
568
- fee['taker'] = takerFee
569
- result[symbol] = fee
570
- return result
571
-
572
- def fetch_markets(self, params={}) -> List[Market]:
573
- """
574
- retrieves data on all markets for bitfinex
575
-
576
- https://docs.bitfinex.com/v1/reference/rest-public-symbols
577
- https://docs.bitfinex.com/v1/reference/rest-public-symbol-details
578
-
579
- :param dict [params]: extra parameters specific to the exchange API endpoint
580
- :returns dict[]: an array of objects representing market data
581
- """
582
- idsPromise = self.publicGetSymbols()
583
- #
584
- # ["btcusd", "ltcusd", "ltcbtc"]
585
- #
586
- detailsPromise = self.publicGetSymbolsDetails()
587
- #
588
- # [
589
- # {
590
- # "pair":"btcusd",
591
- # "price_precision":5,
592
- # "initial_margin":"10.0",
593
- # "minimum_margin":"5.0",
594
- # "maximum_order_size":"2000.0",
595
- # "minimum_order_size":"0.0002",
596
- # "expiration":"NA",
597
- # "margin":true
598
- # },
599
- # ]
600
- #
601
- ids, details = [idsPromise, detailsPromise]
602
- result = []
603
- for i in range(0, len(details)):
604
- market = details[i]
605
- id = self.safe_string(market, 'pair')
606
- if not self.in_array(id, ids):
607
- continue
608
- id = id.upper()
609
- baseId = None
610
- quoteId = None
611
- if id.find(':') >= 0:
612
- parts = id.split(':')
613
- baseId = parts[0]
614
- quoteId = parts[1]
615
- else:
616
- baseId = id[0:3]
617
- quoteId = id[3:6]
618
- base = self.safe_currency_code(baseId)
619
- quote = self.safe_currency_code(quoteId)
620
- symbol = base + '/' + quote
621
- type = 'spot'
622
- if id.find('F0') > -1:
623
- type = 'swap'
624
- result.append({
625
- 'id': id,
626
- 'symbol': symbol,
627
- 'base': base,
628
- 'quote': quote,
629
- 'settle': None,
630
- 'baseId': baseId,
631
- 'quoteId': quoteId,
632
- 'settleId': None,
633
- 'type': type,
634
- 'spot': (type == 'spot'),
635
- 'margin': self.safe_bool(market, 'margin'),
636
- 'swap': (type == 'swap'),
637
- 'future': False,
638
- 'option': False,
639
- 'active': True,
640
- 'contract': (type == 'swap'),
641
- 'linear': None,
642
- 'inverse': None,
643
- 'contractSize': None,
644
- 'expiry': None,
645
- 'expiryDatetime': None,
646
- 'strike': None,
647
- 'optionType': None,
648
- 'precision': {
649
- # https://docs.bitfinex.com/docs/introduction#amount-precision
650
- # The amount field allows up to 8 decimals.
651
- # Anything exceeding self will be rounded to the 8th decimal.
652
- 'amount': int('8'),
653
- 'price': self.safe_integer(market, 'price_precision'),
654
- },
655
- 'limits': {
656
- 'leverage': {
657
- 'min': None,
658
- 'max': None,
659
- },
660
- 'amount': {
661
- 'min': self.safe_number(market, 'minimum_order_size'),
662
- 'max': self.safe_number(market, 'maximum_order_size'),
663
- },
664
- 'price': {
665
- 'min': self.parse_number('1e-8'),
666
- 'max': None,
667
- },
668
- 'cost': {
669
- 'min': None,
670
- 'max': None,
671
- },
672
- },
673
- 'created': None,
674
- 'info': market,
675
- })
676
- return result
677
-
678
- def amount_to_precision(self, symbol, amount):
679
- # https://docs.bitfinex.com/docs/introduction#amount-precision
680
- # The amount field allows up to 8 decimals.
681
- # Anything exceeding self will be rounded to the 8th decimal.
682
- symbol = self.safe_symbol(symbol)
683
- return self.decimal_to_precision(amount, TRUNCATE, self.markets[symbol]['precision']['amount'], DECIMAL_PLACES)
684
-
685
- def price_to_precision(self, symbol, price):
686
- symbol = self.safe_symbol(symbol)
687
- price = self.decimal_to_precision(price, ROUND, self.markets[symbol]['precision']['price'], self.precisionMode)
688
- # https://docs.bitfinex.com/docs/introduction#price-precision
689
- # The precision level of all trading prices is based on significant figures.
690
- # All pairs on Bitfinex use up to 5 significant digits and up to 8 decimals(e.g. 1.2345, 123.45, 1234.5, 0.00012345).
691
- # Prices submit with a precision larger than 5 will be cut by the API.
692
- return self.decimal_to_precision(price, TRUNCATE, 8, DECIMAL_PLACES)
693
-
694
- def fetch_balance(self, params={}) -> Balances:
695
- """
696
- query for balance and get the amount of funds available for trading or funds locked in orders
697
-
698
- https://docs.bitfinex.com/v1/reference/rest-auth-wallet-balances
699
-
700
- :param dict [params]: extra parameters specific to the exchange API endpoint
701
- :returns dict: a `balance structure <https://docs.ccxt.com/#/?id=balance-structure>`
702
- """
703
- self.load_markets()
704
- accountsByType = self.safe_dict(self.options, 'accountsByType', {})
705
- requestedType = self.safe_string(params, 'type', 'exchange')
706
- accountType = self.safe_string(accountsByType, requestedType, requestedType)
707
- if accountType is None:
708
- keys = list(accountsByType.keys())
709
- raise ExchangeError(self.id + ' fetchBalance() type parameter must be one of ' + ', '.join(keys))
710
- query = self.omit(params, 'type')
711
- response = self.privatePostBalances(query)
712
- # [{type: "deposit",
713
- # "currency": "btc",
714
- # "amount": "0.00116721",
715
- # "available": "0.00116721"},
716
- # {type: "exchange",
717
- # "currency": "ust",
718
- # "amount": "0.0000002",
719
- # "available": "0.0000002"},
720
- # {type: "trading",
721
- # "currency": "btc",
722
- # "amount": "0.0005",
723
- # "available": "0.0005"}],
724
- result: dict = {'info': response}
725
- isDerivative = requestedType == 'derivatives'
726
- for i in range(0, len(response)):
727
- balance = response[i]
728
- type = self.safe_string(balance, 'type')
729
- currencyId = self.safe_string_lower(balance, 'currency', '')
730
- start = len(currencyId) - 2
731
- isDerivativeCode = currencyId[start:] == 'f0'
732
- # self will only filter the derivative codes if the requestedType is 'derivatives'
733
- derivativeCondition = (not isDerivative or isDerivativeCode)
734
- if (accountType == type) and derivativeCondition:
735
- code = self.safe_currency_code(currencyId)
736
- # bitfinex had BCH previously, now it's BAB, but the old
737
- # BCH symbol is kept for backward-compatibility
738
- # we need a workaround here so that the old BCH balance
739
- # would not override the new BAB balance(BAB is unified to BCH)
740
- # https://github.com/ccxt/ccxt/issues/4989
741
- if not (code in result):
742
- account = self.account()
743
- account['free'] = self.safe_string(balance, 'available')
744
- account['total'] = self.safe_string(balance, 'amount')
745
- result[code] = account
746
- return self.safe_balance(result)
747
-
748
- def transfer(self, code: str, amount: float, fromAccount: str, toAccount: str, params={}) -> TransferEntry:
749
- """
750
- transfer currency internally between wallets on the same account
751
-
752
- https://docs.bitfinex.com/v1/reference/rest-auth-transfer-between-wallets
753
-
754
- :param str code: unified currency code
755
- :param float amount: amount to transfer
756
- :param str fromAccount: account to transfer from
757
- :param str toAccount: account to transfer to
758
- :param dict [params]: extra parameters specific to the exchange API endpoint
759
- :returns dict: a `transfer structure <https://docs.ccxt.com/#/?id=transfer-structure>`
760
- """
761
- # transferring between derivatives wallet and regular wallet is not documented in their API
762
- # however we support it in CCXT(from just looking at web inspector)
763
- self.load_markets()
764
- accountsByType = self.safe_dict(self.options, 'accountsByType', {})
765
- fromId = self.safe_string(accountsByType, fromAccount, fromAccount)
766
- toId = self.safe_string(accountsByType, toAccount, toAccount)
767
- currency = self.currency(code)
768
- fromCurrencyId = self.convert_derivatives_id(currency['id'], fromAccount)
769
- toCurrencyId = self.convert_derivatives_id(currency['id'], toAccount)
770
- requestedAmount = self.currency_to_precision(code, amount)
771
- request: dict = {
772
- 'amount': requestedAmount,
773
- 'currency': fromCurrencyId,
774
- 'currency_to': toCurrencyId,
775
- 'walletfrom': fromId,
776
- 'walletto': toId,
777
- }
778
- response = self.privatePostTransfer(self.extend(request, params))
779
- #
780
- # [
781
- # {
782
- # "status": "success",
783
- # "message": "0.0001 Bitcoin transfered from Margin to Exchange"
784
- # }
785
- # ]
786
- #
787
- result = self.safe_value(response, 0)
788
- message = self.safe_string(result, 'message')
789
- if message is None:
790
- raise ExchangeError(self.id + ' transfer failed')
791
- return self.extend(self.parse_transfer(result, currency), {
792
- 'fromAccount': fromAccount,
793
- 'toAccount': toAccount,
794
- 'amount': self.parse_number(requestedAmount),
795
- })
796
-
797
- def parse_transfer(self, transfer: dict, currency: Currency = None) -> TransferEntry:
798
- #
799
- # {
800
- # "status": "success",
801
- # "message": "0.0001 Bitcoin transfered from Margin to Exchange"
802
- # }
803
- #
804
- return {
805
- 'info': transfer,
806
- 'id': None,
807
- 'timestamp': None,
808
- 'datetime': None,
809
- 'currency': self.safe_currency_code(None, currency),
810
- 'amount': None,
811
- 'fromAccount': None,
812
- 'toAccount': None,
813
- 'status': self.parse_transfer_status(self.safe_string(transfer, 'status')),
814
- }
815
-
816
- def parse_transfer_status(self, status: Str) -> Str:
817
- statuses: dict = {
818
- 'SUCCESS': 'ok',
819
- }
820
- return self.safe_string(statuses, status, status)
821
-
822
- def convert_derivatives_id(self, currencyId, type):
823
- start = len(currencyId) - 2
824
- isDerivativeCode = currencyId[start:] == 'F0'
825
- if (type != 'derivatives' and type != 'trading' and type != 'margin') and isDerivativeCode:
826
- currencyId = currencyId[0:start]
827
- elif type == 'derivatives' and not isDerivativeCode:
828
- currencyId = currencyId + 'F0'
829
- return currencyId
830
-
831
- def fetch_order_book(self, symbol: str, limit: Int = None, params={}) -> OrderBook:
832
- """
833
- fetches information on open orders with bid(buy) and ask(sell) prices, volumes and other data
834
-
835
- https://docs.bitfinex.com/v1/reference/rest-public-orderbook
836
-
837
- :param str symbol: unified symbol of the market to fetch the order book for
838
- :param int [limit]: the maximum amount of order book entries to return
839
- :param dict [params]: extra parameters specific to the exchange API endpoint
840
- :returns dict: A dictionary of `order book structures <https://docs.ccxt.com/#/?id=order-book-structure>` indexed by market symbols
841
- """
842
- self.load_markets()
843
- market = self.market(symbol)
844
- request: dict = {
845
- 'symbol': market['id'],
846
- }
847
- if limit is not None:
848
- request['limit_bids'] = limit
849
- request['limit_asks'] = limit
850
- response = self.publicGetBookSymbol(self.extend(request, params))
851
- return self.parse_order_book(response, market['symbol'], None, 'bids', 'asks', 'price', 'amount')
852
-
853
- def fetch_tickers(self, symbols: Strings = None, params={}) -> Tickers:
854
- """
855
- fetches price tickers for multiple markets, statistical information calculated over the past 24 hours for each market
856
- :param str[] [symbols]: unified symbols of the markets to fetch the ticker for, all market tickers are returned if not assigned
857
- :param dict [params]: extra parameters specific to the exchange API endpoint
858
- :returns dict: a dictionary of `ticker structures <https://docs.ccxt.com/#/?id=ticker-structure>`
859
- """
860
- self.load_markets()
861
- symbols = self.market_symbols(symbols)
862
- response = self.publicGetTickers(params)
863
- result: dict = {}
864
- for i in range(0, len(response)):
865
- ticker = self.parse_ticker(response[i])
866
- symbol = ticker['symbol']
867
- result[symbol] = ticker
868
- return self.filter_by_array_tickers(result, 'symbol', symbols)
869
-
870
- def fetch_ticker(self, symbol: str, params={}) -> Ticker:
871
- """
872
- fetches a price ticker, a statistical calculation with the information calculated over the past 24 hours for a specific market
873
-
874
- https://docs.bitfinex.com/v1/reference/rest-public-ticker
875
-
876
- :param str symbol: unified symbol of the market to fetch the ticker for
877
- :param dict [params]: extra parameters specific to the exchange API endpoint
878
- :returns dict: a `ticker structure <https://docs.ccxt.com/#/?id=ticker-structure>`
879
- """
880
- self.load_markets()
881
- market = self.market(symbol)
882
- request: dict = {
883
- 'symbol': market['id'],
884
- }
885
- ticker = self.publicGetPubtickerSymbol(self.extend(request, params))
886
- #
887
- # {
888
- # mid: '63560.5',
889
- # bid: '63560.0',
890
- # ask: '63561.0',
891
- # last_price: '63547.0',
892
- # low: '62812.0',
893
- # high: '64480.0',
894
- # volume: '517.25634977',
895
- # timestamp: '1715102384.9849467'
896
- # }
897
- #
898
- return self.parse_ticker(ticker, market)
899
-
900
- def parse_ticker(self, ticker: dict, market: Market = None) -> Ticker:
901
- #
902
- # {
903
- # mid: '63560.5',
904
- # bid: '63560.0',
905
- # ask: '63561.0',
906
- # last_price: '63547.0',
907
- # low: '62812.0',
908
- # high: '64480.0',
909
- # volume: '517.25634977',
910
- # timestamp: '1715102384.9849467'
911
- # }
912
- #
913
- timestamp = self.safe_timestamp(ticker, 'timestamp')
914
- marketId = self.safe_string(ticker, 'pair')
915
- market = self.safe_market(marketId, market)
916
- symbol = market['symbol']
917
- last = self.safe_string(ticker, 'last_price')
918
- return self.safe_ticker({
919
- 'symbol': symbol,
920
- 'timestamp': timestamp,
921
- 'datetime': self.iso8601(timestamp),
922
- 'high': self.safe_string(ticker, 'high'),
923
- 'low': self.safe_string(ticker, 'low'),
924
- 'bid': self.safe_string(ticker, 'bid'),
925
- 'bidVolume': None,
926
- 'ask': self.safe_string(ticker, 'ask'),
927
- 'askVolume': None,
928
- 'vwap': None,
929
- 'open': None,
930
- 'close': last,
931
- 'last': last,
932
- 'previousClose': None,
933
- 'change': None,
934
- 'percentage': None,
935
- 'average': self.safe_string(ticker, 'mid'),
936
- 'baseVolume': self.safe_string(ticker, 'volume'),
937
- 'quoteVolume': None,
938
- 'info': ticker,
939
- }, market)
940
-
941
- def parse_trade(self, trade: dict, market: Market = None) -> Trade:
942
- #
943
- # fetchTrades(public) v1
944
- #
945
- # {
946
- # "timestamp":1637258380,
947
- # "tid":894452833,
948
- # "price":"0.99941",
949
- # "amount":"261.38",
950
- # "exchange":"bitfinex",
951
- # "type":"sell"
952
- # }
953
- #
954
- # fetchMyTrades(private) v1
955
- #
956
- # {
957
- # "price":"0.99941",
958
- # "amount":"261.38",
959
- # "timestamp":"1637258380.0",
960
- # "type":"Sell",
961
- # "fee_currency":"UST",
962
- # "fee_amount":"-0.52245157",
963
- # "tid":894452833,
964
- # "order_id":78819731373
965
- # }
966
- #
967
- # {
968
- # "price":"0.99958",
969
- # "amount":"261.90514",
970
- # "timestamp":"1637258238.0",
971
- # "type":"Buy",
972
- # "fee_currency":"UDC",
973
- # "fee_amount":"-0.52381028",
974
- # "tid":894452800,
975
- # "order_id":78819504838
976
- # }
977
- #
978
- id = self.safe_string(trade, 'tid')
979
- timestamp = self.safe_timestamp(trade, 'timestamp')
980
- type = None
981
- side = self.safe_string_lower(trade, 'type')
982
- orderId = self.safe_string(trade, 'order_id')
983
- priceString = self.safe_string(trade, 'price')
984
- amountString = self.safe_string(trade, 'amount')
985
- fee = None
986
- if 'fee_amount' in trade:
987
- feeCostString = Precise.string_neg(self.safe_string(trade, 'fee_amount'))
988
- feeCurrencyId = self.safe_string(trade, 'fee_currency')
989
- feeCurrencyCode = self.safe_currency_code(feeCurrencyId)
990
- fee = {
991
- 'cost': feeCostString,
992
- 'currency': feeCurrencyCode,
993
- }
994
- return self.safe_trade({
995
- 'id': id,
996
- 'info': trade,
997
- 'timestamp': timestamp,
998
- 'datetime': self.iso8601(timestamp),
999
- 'symbol': market['symbol'],
1000
- 'type': type,
1001
- 'order': orderId,
1002
- 'side': side,
1003
- 'takerOrMaker': None,
1004
- 'price': priceString,
1005
- 'amount': amountString,
1006
- 'cost': None,
1007
- 'fee': fee,
1008
- }, market)
1009
-
1010
- def fetch_trades(self, symbol: str, since: Int = None, limit: Int = 50, params={}) -> List[Trade]:
1011
- """
1012
- get the list of most recent trades for a particular symbol
1013
-
1014
- https://docs.bitfinex.com/v1/reference/rest-public-trades
1015
-
1016
- :param str symbol: unified symbol of the market to fetch trades for
1017
- :param int [since]: timestamp in ms of the earliest trade to fetch
1018
- :param int [limit]: the maximum amount of trades to fetch
1019
- :param dict [params]: extra parameters specific to the exchange API endpoint
1020
- :returns Trade[]: a list of `trade structures <https://docs.ccxt.com/#/?id=public-trades>`
1021
- """
1022
- self.load_markets()
1023
- market = self.market(symbol)
1024
- request: dict = {
1025
- 'symbol': market['id'],
1026
- 'limit_trades': limit,
1027
- }
1028
- if since is not None:
1029
- request['timestamp'] = self.parse_to_int(since / 1000)
1030
- response = self.publicGetTradesSymbol(self.extend(request, params))
1031
- #
1032
- # [
1033
- # {
1034
- # "timestamp": "1694284565",
1035
- # "tid": "1415415034",
1036
- # "price": "25862.0",
1037
- # "amount": "0.00020685",
1038
- # "exchange": "bitfinex",
1039
- # "type": "buy"
1040
- # },
1041
- # ]
1042
- #
1043
- return self.parse_trades(response, market, since, limit)
1044
-
1045
- def fetch_my_trades(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}):
1046
- """
1047
- fetch all trades made by the user
1048
-
1049
- https://docs.bitfinex.com/v1/reference/rest-auth-past-trades
1050
-
1051
- :param str symbol: unified market symbol
1052
- :param int [since]: the earliest time in ms to fetch trades for
1053
- :param int [limit]: the maximum number of trades structures to retrieve
1054
- :param dict [params]: extra parameters specific to the exchange API endpoint
1055
- :returns Trade[]: a list of `trade structures <https://docs.ccxt.com/#/?id=trade-structure>`
1056
- """
1057
- if symbol is None:
1058
- raise ArgumentsRequired(self.id + ' fetchMyTrades() requires a symbol argument')
1059
- self.load_markets()
1060
- market = self.market(symbol)
1061
- request: dict = {
1062
- 'symbol': market['id'],
1063
- }
1064
- if limit is not None:
1065
- request['limit_trades'] = limit
1066
- if since is not None:
1067
- request['timestamp'] = self.parse_to_int(since / 1000)
1068
- response = self.privatePostMytrades(self.extend(request, params))
1069
- return self.parse_trades(response, market, since, limit)
1070
-
1071
- def create_order(self, symbol: str, type: OrderType, side: OrderSide, amount: float, price: Num = None, params={}):
1072
- """
1073
- create a trade order
1074
-
1075
- https://docs.bitfinex.com/v1/reference/rest-auth-new-order
1076
-
1077
- :param str symbol: unified symbol of the market to create an order in
1078
- :param str type: 'market' or 'limit'
1079
- :param str side: 'buy' or 'sell'
1080
- :param float amount: how much of currency you want to trade in units of base currency
1081
- :param float [price]: the price at which the order is to be fulfilled, in units of the quote currency, ignored in market orders
1082
- :param dict [params]: extra parameters specific to the exchange API endpoint
1083
- :returns dict: an `order structure <https://docs.ccxt.com/#/?id=order-structure>`
1084
- """
1085
- self.load_markets()
1086
- market = self.market(symbol)
1087
- postOnly = self.safe_bool(params, 'postOnly', False)
1088
- type = type.lower()
1089
- params = self.omit(params, ['postOnly'])
1090
- if market['spot']:
1091
- # although they claim that type needs to be 'exchange limit' or 'exchange market'
1092
- # in fact that's not the case for swap markets
1093
- type = self.safe_string_lower(self.options['orderTypes'], type, type)
1094
- request: dict = {
1095
- 'symbol': market['id'],
1096
- 'side': side,
1097
- 'amount': self.amount_to_precision(symbol, amount),
1098
- 'type': type,
1099
- 'ocoorder': False,
1100
- 'buy_price_oco': 0,
1101
- 'sell_price_oco': 0,
1102
- }
1103
- if type.find('market') > -1:
1104
- request['price'] = str(self.nonce())
1105
- else:
1106
- request['price'] = self.price_to_precision(symbol, price)
1107
- if postOnly:
1108
- request['is_postonly'] = True
1109
- response = self.privatePostOrderNew(self.extend(request, params))
1110
- return self.parse_order(response, market)
1111
-
1112
- def edit_order(self, id: str, symbol: str, type: OrderType, side: OrderSide, amount: Num = None, price: Num = None, params={}):
1113
- self.load_markets()
1114
- order: dict = {
1115
- 'order_id': int(id),
1116
- }
1117
- if price is not None:
1118
- order['price'] = self.price_to_precision(symbol, price)
1119
- if amount is not None:
1120
- order['amount'] = self.number_to_string(amount)
1121
- if symbol is not None:
1122
- order['symbol'] = self.market_id(symbol)
1123
- if side is not None:
1124
- order['side'] = side
1125
- if type is not None:
1126
- order['type'] = self.safe_string(self.options['orderTypes'], type, type)
1127
- response = self.privatePostOrderCancelReplace(self.extend(order, params))
1128
- return self.parse_order(response)
1129
-
1130
- def cancel_order(self, id: str, symbol: Str = None, params={}):
1131
- """
1132
- cancels an open order
1133
-
1134
- https://docs.bitfinex.com/v1/reference/rest-auth-cancel-order
1135
-
1136
- :param str id: order id
1137
- :param str symbol: not used by bitfinex cancelOrder()
1138
- :param dict [params]: extra parameters specific to the exchange API endpoint
1139
- :returns dict: An `order structure <https://docs.ccxt.com/#/?id=order-structure>`
1140
- """
1141
- self.load_markets()
1142
- request: dict = {
1143
- 'order_id': int(id),
1144
- }
1145
- response = self.privatePostOrderCancel(self.extend(request, params))
1146
- #
1147
- # {
1148
- # id: '161236928925',
1149
- # cid: '1720172026812',
1150
- # cid_date: '2024-07-05',
1151
- # gid: null,
1152
- # symbol: 'adaust',
1153
- # exchange: 'bitfinex',
1154
- # price: '0.33',
1155
- # avg_execution_price: '0.0',
1156
- # side: 'buy',
1157
- # type: 'exchange limit',
1158
- # timestamp: '1720172026.813',
1159
- # is_live: True,
1160
- # is_cancelled: False,
1161
- # is_hidden: False,
1162
- # oco_order: null,
1163
- # was_forced: False,
1164
- # original_amount: '10.0',
1165
- # remaining_amount: '10.0',
1166
- # executed_amount: '0.0',
1167
- # src: 'api',
1168
- # meta: {}
1169
- # }
1170
- #
1171
- return self.parse_order(response)
1172
-
1173
- def cancel_all_orders(self, symbol: Str = None, params={}):
1174
- """
1175
- cancel all open orders
1176
-
1177
- https://docs.bitfinex.com/v1/reference/rest-auth-cancel-all-orders
1178
-
1179
- :param str symbol: not used by bitfinex cancelAllOrders
1180
- :param dict [params]: extra parameters specific to the exchange API endpoint
1181
- :returns dict: response from exchange
1182
- """
1183
- response = self.privatePostOrderCancelAll(params)
1184
- #
1185
- # {result: 'Submitting 1 order cancellations.'}
1186
- #
1187
- return [
1188
- self.safe_order({
1189
- 'info': response,
1190
- }),
1191
- ]
1192
-
1193
- def parse_order(self, order: dict, market: Market = None) -> Order:
1194
- #
1195
- # {
1196
- # "id": 57334010955,
1197
- # "cid": 1611584840966,
1198
- # "cid_date": null,
1199
- # "gid": null,
1200
- # "symbol": "ltcbtc",
1201
- # "exchange": null,
1202
- # "price": "0.0042125",
1203
- # "avg_execution_price": "0.0042097",
1204
- # "side": "sell",
1205
- # "type": "exchange market",
1206
- # "timestamp": "1611584841.0",
1207
- # "is_live": False,
1208
- # "is_cancelled": False,
1209
- # "is_hidden": 0,
1210
- # "oco_order": 0,
1211
- # "was_forced": False,
1212
- # "original_amount": "0.205176",
1213
- # "remaining_amount": "0.0",
1214
- # "executed_amount": "0.205176",
1215
- # "src": "web"
1216
- # }
1217
- #
1218
- side = self.safe_string(order, 'side')
1219
- open = self.safe_bool(order, 'is_live')
1220
- canceled = self.safe_bool(order, 'is_cancelled')
1221
- status = None
1222
- if open:
1223
- status = 'open'
1224
- elif canceled:
1225
- status = 'canceled'
1226
- else:
1227
- status = 'closed'
1228
- marketId = self.safe_string_upper(order, 'symbol')
1229
- symbol = self.safe_symbol(marketId, market)
1230
- orderType = self.safe_string(order, 'type', '')
1231
- exchange = orderType.find('exchange ') >= 0
1232
- if exchange:
1233
- parts = order['type'].split(' ')
1234
- orderType = parts[1]
1235
- timestamp = self.safe_timestamp(order, 'timestamp')
1236
- id = self.safe_string(order, 'id')
1237
- return self.safe_order({
1238
- 'info': order,
1239
- 'id': id,
1240
- 'clientOrderId': None,
1241
- 'timestamp': timestamp,
1242
- 'datetime': self.iso8601(timestamp),
1243
- 'lastTradeTimestamp': None,
1244
- 'symbol': symbol,
1245
- 'type': orderType,
1246
- 'timeInForce': None,
1247
- 'postOnly': None,
1248
- 'side': side,
1249
- 'price': self.safe_string(order, 'price'),
1250
- 'triggerPrice': None,
1251
- 'average': self.safe_string(order, 'avg_execution_price'),
1252
- 'amount': self.safe_string(order, 'original_amount'),
1253
- 'remaining': self.safe_string(order, 'remaining_amount'),
1254
- 'filled': self.safe_string(order, 'executed_amount'),
1255
- 'status': status,
1256
- 'fee': None,
1257
- 'cost': None,
1258
- 'trades': None,
1259
- }, market)
1260
-
1261
- def fetch_open_orders(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}) -> List[Order]:
1262
- """
1263
- fetch all unfilled currently open orders
1264
-
1265
- https://docs.bitfinex.com/v1/reference/rest-auth-active-orders
1266
-
1267
- :param str symbol: unified market symbol
1268
- :param int [since]: the earliest time in ms to fetch open orders for
1269
- :param int [limit]: the maximum number of open orders structures to retrieve
1270
- :param dict [params]: extra parameters specific to the exchange API endpoint
1271
- :returns Order[]: a list of `order structures <https://docs.ccxt.com/#/?id=order-structure>`
1272
- """
1273
- self.load_markets()
1274
- if symbol is not None:
1275
- if not (symbol in self.markets):
1276
- raise ExchangeError(self.id + ' has no symbol ' + symbol)
1277
- response = self.privatePostOrders(params)
1278
- orders = self.parse_orders(response, None, since, limit)
1279
- if symbol is not None:
1280
- orders = self.filter_by(orders, 'symbol', symbol)
1281
- return orders
1282
-
1283
- def fetch_closed_orders(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}) -> List[Order]:
1284
- """
1285
- fetches information on multiple closed orders made by the user
1286
-
1287
- https://docs.bitfinex.com/v1/reference/rest-auth-orders-history
1288
-
1289
- :param str symbol: unified market symbol of the market orders were made in
1290
- :param int [since]: the earliest time in ms to fetch orders for
1291
- :param int [limit]: the maximum number of order structures to retrieve
1292
- :param dict [params]: extra parameters specific to the exchange API endpoint
1293
- :returns Order[]: a list of `order structures <https://docs.ccxt.com/#/?id=order-structure>`
1294
- """
1295
- self.load_markets()
1296
- symbol = self.symbol(symbol)
1297
- request: dict = {}
1298
- if limit is not None:
1299
- request['limit'] = limit
1300
- response = self.privatePostOrdersHist(self.extend(request, params))
1301
- orders = self.parse_orders(response, None, since, limit)
1302
- if symbol is not None:
1303
- orders = self.filter_by(orders, 'symbol', symbol)
1304
- orders = self.filter_by_array(orders, 'status', ['closed', 'canceled'], False)
1305
- return orders
1306
-
1307
- def fetch_order(self, id: str, symbol: Str = None, params={}):
1308
- """
1309
- fetches information on an order made by the user
1310
-
1311
- https://docs.bitfinex.com/v1/reference/rest-auth-order-status
1312
-
1313
- :param str id: the order id
1314
- :param str symbol: not used by bitfinex fetchOrder
1315
- :param dict [params]: extra parameters specific to the exchange API endpoint
1316
- :returns dict: An `order structure <https://docs.ccxt.com/#/?id=order-structure>`
1317
- """
1318
- self.load_markets()
1319
- request: dict = {
1320
- 'order_id': int(id),
1321
- }
1322
- response = self.privatePostOrderStatus(self.extend(request, params))
1323
- return self.parse_order(response)
1324
-
1325
- def parse_ohlcv(self, ohlcv, market: Market = None) -> list:
1326
- #
1327
- # [
1328
- # 1457539800000,
1329
- # 0.02594,
1330
- # 0.02594,
1331
- # 0.02594,
1332
- # 0.02594,
1333
- # 0.1
1334
- # ]
1335
- #
1336
- return [
1337
- self.safe_integer(ohlcv, 0),
1338
- self.safe_number(ohlcv, 1),
1339
- self.safe_number(ohlcv, 3),
1340
- self.safe_number(ohlcv, 4),
1341
- self.safe_number(ohlcv, 2),
1342
- self.safe_number(ohlcv, 5),
1343
- ]
1344
-
1345
- def fetch_ohlcv(self, symbol: str, timeframe='1m', since: Int = None, limit: Int = None, params={}) -> List[list]:
1346
- """
1347
- fetches historical candlestick data containing the open, high, low, and close price, and the volume of a market
1348
-
1349
- https://docs.bitfinex.com/reference/rest-public-candles#aggregate-funding-currency-candles
1350
-
1351
- :param str symbol: unified symbol of the market to fetch OHLCV data for
1352
- :param str timeframe: the length of time each candle represents
1353
- :param int [since]: timestamp in ms of the earliest candle to fetch
1354
- :param int [limit]: the maximum amount of candles to fetch
1355
- :param dict [params]: extra parameters specific to the exchange API endpoint
1356
- :param int [params.until]: timestamp in ms of the latest candle to fetch
1357
- :returns int[][]: A list of candles ordered, open, high, low, close, volume
1358
- """
1359
- self.load_markets()
1360
- if limit is None:
1361
- limit = 100
1362
- else:
1363
- limit = min(limit, 10000)
1364
- market = self.market(symbol)
1365
- v2id = 't' + market['id']
1366
- request: dict = {
1367
- 'symbol': v2id,
1368
- 'timeframe': self.safe_string(self.timeframes, timeframe, timeframe),
1369
- 'sort': 1,
1370
- 'limit': limit,
1371
- }
1372
- until = self.safe_integer(params, 'until')
1373
- if since is not None:
1374
- request['start'] = since
1375
- elif until is not None:
1376
- duration = self.parse_timeframe(timeframe)
1377
- request['start'] = until - ((limit - 1) * duration * 1000)
1378
- if until is not None:
1379
- request['end'] = until
1380
- params = self.omit(params, 'until')
1381
- response = self.v2GetCandlesTradeTimeframeSymbolHist(self.extend(request, params))
1382
- #
1383
- # [
1384
- # [1457539800000,0.02594,0.02594,0.02594,0.02594,0.1],
1385
- # [1457547300000,0.02577,0.02577,0.02577,0.02577,0.01],
1386
- # [1457550240000,0.0255,0.0253,0.0255,0.0252,3.2640000000000002],
1387
- # ]
1388
- #
1389
- return self.parse_ohlcvs(response, market, timeframe, since, limit)
1390
-
1391
- def get_currency_name(self, code):
1392
- # todo rewrite for https://api-pub.bitfinex.com//v2/conf/pub:map:tx:method
1393
- if code in self.options['currencyNames']:
1394
- return self.options['currencyNames'][code]
1395
- raise NotSupported(self.id + ' ' + code + ' not supported for withdrawal')
1396
-
1397
- def create_deposit_address(self, code: str, params={}) -> DepositAddress:
1398
- """
1399
- create a currency deposit address
1400
-
1401
- https://docs.bitfinex.com/v1/reference/rest-auth-deposit
1402
-
1403
- :param str code: unified currency code of the currency for the deposit address
1404
- :param dict [params]: extra parameters specific to the exchange API endpoint
1405
- :returns dict: an `address structure <https://docs.ccxt.com/#/?id=address-structure>`
1406
- """
1407
- self.load_markets()
1408
- request: dict = {
1409
- 'renew': 1,
1410
- }
1411
- return self.fetch_deposit_address(code, self.extend(request, params))
1412
-
1413
- def fetch_deposit_address(self, code: str, params={}) -> DepositAddress:
1414
- """
1415
- fetch the deposit address for a currency associated with self account
1416
-
1417
- https://docs.bitfinex.com/v1/reference/rest-auth-deposit
1418
-
1419
- :param str code: unified currency code
1420
- :param dict [params]: extra parameters specific to the exchange API endpoint
1421
- :returns dict: an `address structure <https://docs.ccxt.com/#/?id=address-structure>`
1422
- """
1423
- self.load_markets()
1424
- # todo rewrite for https://api-pub.bitfinex.com//v2/conf/pub:map:tx:method
1425
- name = self.get_currency_name(code)
1426
- request: dict = {
1427
- 'method': name,
1428
- 'wallet_name': 'exchange',
1429
- 'renew': 0, # a value of 1 will generate a new address
1430
- }
1431
- response = self.privatePostDepositNew(self.extend(request, params))
1432
- address = self.safe_value(response, 'address')
1433
- tag = None
1434
- if 'address_pool' in response:
1435
- tag = address
1436
- address = response['address_pool']
1437
- self.check_address(address)
1438
- return {
1439
- 'currency': code,
1440
- 'address': address,
1441
- 'tag': tag,
1442
- 'network': None,
1443
- 'info': response,
1444
- }
1445
-
1446
- def fetch_deposits_withdrawals(self, code: Str = None, since: Int = None, limit: Int = None, params={}) -> List[Transaction]:
1447
- """
1448
- fetch history of deposits and withdrawals
1449
-
1450
- https://docs.bitfinex.com/v1/reference/rest-auth-deposit-withdrawal-history
1451
-
1452
- :param str code: unified currency code for the currency of the deposit/withdrawals
1453
- :param int [since]: timestamp in ms of the earliest deposit/withdrawal, default is None
1454
- :param int [limit]: max number of deposit/withdrawals to return, default is None
1455
- :param dict [params]: extra parameters specific to the exchange API endpoint
1456
- :returns dict: a list of `transaction structure <https://docs.ccxt.com/#/?id=transaction-structure>`
1457
- """
1458
- self.load_markets()
1459
- currencyId = self.safe_string(params, 'currency')
1460
- query = self.omit(params, 'currency')
1461
- currency = None
1462
- if currencyId is None:
1463
- if code is None:
1464
- raise ArgumentsRequired(self.id + ' fetchDepositsWithdrawals() requires a currency `code` argument or a `currency` parameter')
1465
- else:
1466
- currency = self.currency(code)
1467
- currencyId = currency['id']
1468
- query['currency'] = currencyId
1469
- if since is not None:
1470
- query['since'] = self.parse_to_int(since / 1000)
1471
- response = self.privatePostHistoryMovements(self.extend(query, params))
1472
- #
1473
- # [
1474
- # {
1475
- # "id": 581183,
1476
- # "txid": 123456,
1477
- # "currency": "BTC",
1478
- # "method": "BITCOIN",
1479
- # "type": "WITHDRAWAL",
1480
- # "amount": ".01",
1481
- # "description": "3QXYWgRGX2BPYBpUDBssGbeWEa5zq6snBZ, offchain transfer ",
1482
- # "address": "3QXYWgRGX2BPYBpUDBssGbeWEa5zq6snBZ",
1483
- # "status": "COMPLETED",
1484
- # "timestamp": "1443833327.0",
1485
- # "timestamp_created": "1443833327.1",
1486
- # "fee": 0.1,
1487
- # }
1488
- # ]
1489
- #
1490
- return self.parse_transactions(response, currency, since, limit)
1491
-
1492
- def parse_transaction(self, transaction: dict, currency: Currency = None) -> Transaction:
1493
- #
1494
- # crypto
1495
- #
1496
- # {
1497
- # "id": 12042490,
1498
- # "fee": "-0.02",
1499
- # "txid": "EA5B5A66000B66855865EFF2494D7C8D1921FCBE996482157EBD749F2C85E13D",
1500
- # "type": "DEPOSIT",
1501
- # "amount": "2099.849999",
1502
- # "method": "RIPPLE",
1503
- # "status": "COMPLETED",
1504
- # "address": "2505189261",
1505
- # "currency": "XRP",
1506
- # "timestamp": "1551730524.0",
1507
- # "description": "EA5B5A66000B66855865EFF2494D7C8D1921FCBE996482157EBD749F2C85E13D",
1508
- # "timestamp_created": "1551730523.0"
1509
- # }
1510
- #
1511
- # fiat
1512
- #
1513
- # {
1514
- # "id": 12725095,
1515
- # "fee": "-60.0",
1516
- # "txid": null,
1517
- # "type": "WITHDRAWAL",
1518
- # "amount": "9943.0",
1519
- # "method": "WIRE",
1520
- # "status": "SENDING",
1521
- # "address": null,
1522
- # "currency": "EUR",
1523
- # "timestamp": "1561802484.0",
1524
- # "description": "Name: bob, AccountAddress: some address, Account: someaccountno, Bank: bank address, SWIFT: foo, Country: UK, Details of Payment: withdrawal name, Intermediary Bank Name: , Intermediary Bank Address: , Intermediary Bank City: , Intermediary Bank Country: , Intermediary Bank Account: , Intermediary Bank SWIFT: , Fee: -60.0",
1525
- # "timestamp_created": "1561716066.0"
1526
- # }
1527
- #
1528
- # withdraw
1529
- #
1530
- # {
1531
- # "status": "success",
1532
- # "message": "Your withdrawal request has been successfully submitted.",
1533
- # "withdrawal_id": 586829
1534
- # }
1535
- #
1536
- timestamp = self.safe_timestamp(transaction, 'timestamp_created')
1537
- currencyId = self.safe_string(transaction, 'currency')
1538
- code = self.safe_currency_code(currencyId, currency)
1539
- feeCost = self.safe_string(transaction, 'fee')
1540
- if feeCost is not None:
1541
- feeCost = Precise.string_abs(feeCost)
1542
- return {
1543
- 'info': transaction,
1544
- 'id': self.safe_string_2(transaction, 'id', 'withdrawal_id'),
1545
- 'txid': self.safe_string(transaction, 'txid'),
1546
- 'type': self.safe_string_lower(transaction, 'type'), # DEPOSIT or WITHDRAWAL,
1547
- 'currency': code,
1548
- 'network': None,
1549
- 'amount': self.safe_number(transaction, 'amount'),
1550
- 'status': self.parse_transaction_status(self.safe_string(transaction, 'status')),
1551
- 'timestamp': timestamp,
1552
- 'datetime': self.iso8601(timestamp),
1553
- 'address': self.safe_string(transaction, 'address'), # todo: self is actually the tag for XRP transfers(the address is missing)
1554
- 'addressFrom': None,
1555
- 'addressTo': None,
1556
- 'tag': self.safe_string(transaction, 'description'),
1557
- 'tagFrom': None,
1558
- 'tagTo': None,
1559
- 'updated': self.safe_timestamp(transaction, 'timestamp'),
1560
- 'comment': None,
1561
- 'internal': None,
1562
- 'fee': {
1563
- 'currency': code,
1564
- 'cost': self.parse_number(feeCost),
1565
- 'rate': None,
1566
- },
1567
- }
1568
-
1569
- def parse_transaction_status(self, status: Str):
1570
- statuses: dict = {
1571
- 'SENDING': 'pending',
1572
- 'CANCELED': 'canceled',
1573
- 'ZEROCONFIRMED': 'failed', # ZEROCONFIRMED happens e.g. in a double spend attempt(I had one in my movementsnot )
1574
- 'COMPLETED': 'ok',
1575
- }
1576
- return self.safe_string(statuses, status, status)
1577
-
1578
- def withdraw(self, code: str, amount: float, address: str, tag=None, params={}) -> Transaction:
1579
- """
1580
- make a withdrawal
1581
-
1582
- https://docs.bitfinex.com/v1/reference/rest-auth-withdrawal
1583
-
1584
- :param str code: unified currency code
1585
- :param float amount: the amount to withdraw
1586
- :param str address: the address to withdraw to
1587
- :param str tag:
1588
- :param dict [params]: extra parameters specific to the exchange API endpoint
1589
- :returns dict: a `transaction structure <https://docs.ccxt.com/#/?id=transaction-structure>`
1590
- """
1591
- tag, params = self.handle_withdraw_tag_and_params(tag, params)
1592
- self.check_address(address)
1593
- self.load_markets()
1594
- # todo rewrite for https://api-pub.bitfinex.com//v2/conf/pub:map:tx:method
1595
- name = self.get_currency_name(code)
1596
- currency = self.currency(code)
1597
- request: dict = {
1598
- 'withdraw_type': name,
1599
- 'walletselected': 'exchange',
1600
- 'amount': self.number_to_string(amount),
1601
- 'address': address,
1602
- }
1603
- if tag is not None:
1604
- request['payment_id'] = tag
1605
- responses = self.privatePostWithdraw(self.extend(request, params))
1606
- #
1607
- # [
1608
- # {
1609
- # "status":"success",
1610
- # "message":"Your withdrawal request has been successfully submitted.",
1611
- # "withdrawal_id":586829
1612
- # }
1613
- # ]
1614
- #
1615
- response = self.safe_dict(responses, 0, {})
1616
- id = self.safe_integer(response, 'withdrawal_id')
1617
- message = self.safe_string(response, 'message')
1618
- errorMessage = self.find_broadly_matched_key(self.exceptions['broad'], message)
1619
- if id == 0:
1620
- if errorMessage is not None:
1621
- ExceptionClass = self.exceptions['broad'][errorMessage]
1622
- raise ExceptionClass(self.id + ' ' + message)
1623
- raise ExchangeError(self.id + ' withdraw returned an id of zero: ' + self.json(response))
1624
- return self.parse_transaction(response, currency)
1625
-
1626
- def fetch_positions(self, symbols: Strings = None, params={}):
1627
- """
1628
- fetch all open positions
1629
-
1630
- https://docs.bitfinex.com/v1/reference/rest-auth-active-positions
1631
-
1632
- :param str[]|None symbols: list of unified market symbols
1633
- :param dict [params]: extra parameters specific to the exchange API endpoint
1634
- :returns dict[]: a list of `position structure <https://docs.ccxt.com/#/?id=position-structure>`
1635
- """
1636
- self.load_markets()
1637
- response = self.privatePostPositions(params)
1638
- #
1639
- # [
1640
- # {
1641
- # "id":943715,
1642
- # "symbol":"btcusd",
1643
- # "status":"ACTIVE",
1644
- # "base":"246.94",
1645
- # "amount":"1.0",
1646
- # "timestamp":"1444141857.0",
1647
- # "swap":"0.0",
1648
- # "pl":"-2.22042"
1649
- # }
1650
- # ]
1651
- #
1652
- # todo unify parsePosition/parsePositions
1653
- return response
1654
-
1655
- def nonce(self):
1656
- return self.microseconds()
1657
-
1658
- def sign(self, path, api='public', method='GET', params={}, headers=None, body=None):
1659
- request = '/' + self.implode_params(path, params)
1660
- if api == 'v2':
1661
- request = '/' + api + request
1662
- else:
1663
- request = '/' + self.version + request
1664
- query = self.omit(params, self.extract_params(path))
1665
- url = self.urls['api'][api] + request
1666
- if (api == 'public') or (path.find('/hist') >= 0):
1667
- if query:
1668
- suffix = '?' + self.urlencode(query)
1669
- url += suffix
1670
- request += suffix
1671
- if api == 'private':
1672
- self.check_required_credentials()
1673
- nonce = self.nonce()
1674
- query = self.extend({
1675
- 'nonce': str(nonce),
1676
- 'request': request,
1677
- }, query)
1678
- body = self.json(query)
1679
- payload = self.string_to_base64(body)
1680
- secret = self.encode(self.secret)
1681
- signature = self.hmac(self.encode(payload), secret, hashlib.sha384)
1682
- headers = {
1683
- 'X-BFX-APIKEY': self.apiKey,
1684
- 'X-BFX-PAYLOAD': payload,
1685
- 'X-BFX-SIGNATURE': signature,
1686
- 'Content-Type': 'application/json',
1687
- }
1688
- return {'url': url, 'method': method, 'body': body, 'headers': headers}
1689
-
1690
- def handle_errors(self, code: int, reason: str, url: str, method: str, headers: dict, body: str, response, requestHeaders, requestBody):
1691
- if response is None:
1692
- return None
1693
- throwError = False
1694
- if code >= 400:
1695
- if body[0] == '{':
1696
- throwError = True
1697
- else:
1698
- # json response with error, i.e:
1699
- # [{"status":"error","message":"Momentary balance check. Please wait few seconds and try the transfer again."}]
1700
- responseObject = self.safe_dict(response, 0, {})
1701
- status = self.safe_string(responseObject, 'status', '')
1702
- if status == 'error':
1703
- throwError = True
1704
- if throwError:
1705
- feedback = self.id + ' ' + body
1706
- message = self.safe_string_2(response, 'message', 'error')
1707
- self.throw_exactly_matched_exception(self.exceptions['exact'], message, feedback)
1708
- self.throw_broadly_matched_exception(self.exceptions['broad'], message, feedback)
1709
- raise ExchangeError(feedback) # unknown message
1710
- return None