ccxt 4.4.41__py2.py3-none-any.whl → 4.4.42__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 (162) hide show
  1. ccxt/__init__.py +1 -1
  2. ccxt/abstract/binance.py +3 -0
  3. ccxt/abstract/binancecoinm.py +3 -0
  4. ccxt/abstract/binanceus.py +3 -0
  5. ccxt/abstract/binanceusdm.py +3 -0
  6. ccxt/ace.py +1 -1
  7. ccxt/alpaca.py +0 -1
  8. ccxt/ascendex.py +0 -1
  9. ccxt/async_support/__init__.py +1 -1
  10. ccxt/async_support/ace.py +1 -1
  11. ccxt/async_support/alpaca.py +0 -1
  12. ccxt/async_support/ascendex.py +0 -1
  13. ccxt/async_support/base/exchange.py +15 -15
  14. ccxt/async_support/bigone.py +0 -1
  15. ccxt/async_support/binance.py +3 -0
  16. ccxt/async_support/bingx.py +2 -0
  17. ccxt/async_support/bitfinex.py +122 -0
  18. ccxt/async_support/blofin.py +16 -7
  19. ccxt/async_support/cex.py +1 -1
  20. ccxt/async_support/coinbase.py +8 -9
  21. ccxt/async_support/coinbaseexchange.py +5 -6
  22. ccxt/async_support/coinbaseinternational.py +7 -8
  23. ccxt/async_support/coincatch.py +0 -1
  24. ccxt/async_support/coincheck.py +0 -1
  25. ccxt/async_support/coinex.py +91 -6
  26. ccxt/async_support/coinlist.py +3 -4
  27. ccxt/async_support/coinmate.py +1 -3
  28. ccxt/async_support/coinmetro.py +4 -5
  29. ccxt/async_support/coinone.py +0 -1
  30. ccxt/async_support/coinsph.py +7 -8
  31. ccxt/async_support/cryptocom.py +3 -0
  32. ccxt/async_support/currencycom.py +3 -4
  33. ccxt/async_support/defx.py +6 -7
  34. ccxt/async_support/deribit.py +1 -3
  35. ccxt/async_support/digifinex.py +0 -1
  36. ccxt/async_support/ellipx.py +0 -2
  37. ccxt/async_support/exmo.py +1 -2
  38. ccxt/async_support/gate.py +1 -2
  39. ccxt/async_support/gemini.py +4 -5
  40. ccxt/async_support/hashkey.py +79 -67
  41. ccxt/async_support/hitbtc.py +47 -5
  42. ccxt/async_support/hollaex.py +4 -6
  43. ccxt/async_support/htx.py +1 -3
  44. ccxt/async_support/huobijp.py +0 -1
  45. ccxt/async_support/idex.py +8 -8
  46. ccxt/async_support/independentreserve.py +0 -1
  47. ccxt/async_support/indodax.py +0 -1
  48. ccxt/async_support/kraken.py +63 -3
  49. ccxt/async_support/krakenfutures.py +75 -3
  50. ccxt/async_support/kucoin.py +1 -3
  51. ccxt/async_support/kucoinfutures.py +10 -9
  52. ccxt/async_support/kuna.py +1 -3
  53. ccxt/async_support/latoken.py +1 -3
  54. ccxt/async_support/lbank.py +0 -1
  55. ccxt/async_support/luno.py +0 -1
  56. ccxt/async_support/lykke.py +0 -1
  57. ccxt/async_support/mercado.py +0 -1
  58. ccxt/async_support/mexc.py +3 -4
  59. ccxt/async_support/ndax.py +1 -1
  60. ccxt/async_support/novadax.py +4 -6
  61. ccxt/async_support/oceanex.py +0 -1
  62. ccxt/async_support/okcoin.py +1 -3
  63. ccxt/async_support/okx.py +1 -3
  64. ccxt/async_support/onetrading.py +1 -3
  65. ccxt/async_support/p2b.py +1 -1
  66. ccxt/async_support/paradex.py +5 -7
  67. ccxt/async_support/phemex.py +8 -10
  68. ccxt/async_support/poloniex.py +1 -3
  69. ccxt/async_support/poloniexfutures.py +6 -6
  70. ccxt/async_support/probit.py +0 -1
  71. ccxt/async_support/timex.py +0 -1
  72. ccxt/async_support/tokocrypto.py +11 -14
  73. ccxt/async_support/tradeogre.py +1 -1
  74. ccxt/async_support/upbit.py +0 -1
  75. ccxt/async_support/wavesexchange.py +4 -5
  76. ccxt/async_support/whitebit.py +8 -9
  77. ccxt/async_support/woo.py +98 -12
  78. ccxt/async_support/woofipro.py +96 -15
  79. ccxt/async_support/xt.py +3 -2
  80. ccxt/async_support/yobit.py +0 -1
  81. ccxt/async_support/zaif.py +0 -1
  82. ccxt/async_support/zonda.py +1 -2
  83. ccxt/base/exchange.py +21 -17
  84. ccxt/bigone.py +0 -1
  85. ccxt/binance.py +3 -0
  86. ccxt/bingx.py +2 -0
  87. ccxt/bitfinex.py +122 -0
  88. ccxt/blofin.py +16 -7
  89. ccxt/cex.py +1 -1
  90. ccxt/coinbase.py +8 -9
  91. ccxt/coinbaseexchange.py +5 -6
  92. ccxt/coinbaseinternational.py +7 -8
  93. ccxt/coincatch.py +0 -1
  94. ccxt/coincheck.py +0 -1
  95. ccxt/coinex.py +91 -6
  96. ccxt/coinlist.py +3 -4
  97. ccxt/coinmate.py +1 -3
  98. ccxt/coinmetro.py +4 -5
  99. ccxt/coinone.py +0 -1
  100. ccxt/coinsph.py +7 -8
  101. ccxt/cryptocom.py +3 -0
  102. ccxt/currencycom.py +3 -4
  103. ccxt/defx.py +6 -7
  104. ccxt/deribit.py +1 -3
  105. ccxt/digifinex.py +0 -1
  106. ccxt/ellipx.py +0 -2
  107. ccxt/exmo.py +1 -2
  108. ccxt/gate.py +1 -2
  109. ccxt/gemini.py +4 -5
  110. ccxt/hashkey.py +79 -67
  111. ccxt/hitbtc.py +47 -5
  112. ccxt/hollaex.py +4 -6
  113. ccxt/htx.py +1 -3
  114. ccxt/huobijp.py +0 -1
  115. ccxt/idex.py +8 -8
  116. ccxt/independentreserve.py +0 -1
  117. ccxt/indodax.py +0 -1
  118. ccxt/kraken.py +63 -3
  119. ccxt/krakenfutures.py +75 -3
  120. ccxt/kucoin.py +1 -3
  121. ccxt/kucoinfutures.py +10 -9
  122. ccxt/kuna.py +1 -3
  123. ccxt/latoken.py +1 -3
  124. ccxt/lbank.py +0 -1
  125. ccxt/luno.py +0 -1
  126. ccxt/lykke.py +0 -1
  127. ccxt/mercado.py +0 -1
  128. ccxt/mexc.py +3 -4
  129. ccxt/ndax.py +1 -1
  130. ccxt/novadax.py +4 -6
  131. ccxt/oceanex.py +0 -1
  132. ccxt/okcoin.py +1 -3
  133. ccxt/okx.py +1 -3
  134. ccxt/onetrading.py +1 -3
  135. ccxt/p2b.py +1 -1
  136. ccxt/paradex.py +5 -7
  137. ccxt/phemex.py +8 -10
  138. ccxt/poloniex.py +1 -3
  139. ccxt/poloniexfutures.py +6 -6
  140. ccxt/pro/__init__.py +1 -1
  141. ccxt/probit.py +0 -1
  142. ccxt/timex.py +0 -1
  143. ccxt/tokocrypto.py +11 -14
  144. ccxt/tradeogre.py +1 -1
  145. ccxt/upbit.py +0 -1
  146. ccxt/wavesexchange.py +4 -5
  147. ccxt/whitebit.py +8 -9
  148. ccxt/woo.py +98 -12
  149. ccxt/woofipro.py +96 -15
  150. ccxt/xt.py +3 -2
  151. ccxt/yobit.py +0 -1
  152. ccxt/zaif.py +0 -1
  153. ccxt/zonda.py +1 -2
  154. {ccxt-4.4.41.dist-info → ccxt-4.4.42.dist-info}/METADATA +5 -5
  155. {ccxt-4.4.41.dist-info → ccxt-4.4.42.dist-info}/RECORD +158 -162
  156. ccxt/bitbay.py +0 -17
  157. ccxt/bitfinex2.py +0 -3624
  158. ccxt/hitbtc3.py +0 -16
  159. ccxt/pro/bitfinex2.py +0 -1086
  160. {ccxt-4.4.41.dist-info → ccxt-4.4.42.dist-info}/LICENSE.txt +0 -0
  161. {ccxt-4.4.41.dist-info → ccxt-4.4.42.dist-info}/WHEEL +0 -0
  162. {ccxt-4.4.41.dist-info → ccxt-4.4.42.dist-info}/top_level.txt +0 -0
ccxt/bitfinex2.py DELETED
@@ -1,3624 +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.bitfinex2 import ImplicitAPI
8
- import hashlib
9
- from ccxt.base.types import Balances, Currencies, Currency, DepositAddress, Int, LedgerEntry, MarginModification, Market, Num, Order, OrderBook, OrderRequest, OrderSide, OrderType, Str, Strings, Ticker, Tickers, FundingRate, FundingRates, 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 BadRequest
16
- from ccxt.base.errors import BadSymbol
17
- from ccxt.base.errors import InsufficientFunds
18
- from ccxt.base.errors import InvalidOrder
19
- from ccxt.base.errors import OrderNotFound
20
- from ccxt.base.errors import NotSupported
21
- from ccxt.base.errors import RateLimitExceeded
22
- from ccxt.base.errors import ExchangeNotAvailable
23
- from ccxt.base.errors import OnMaintenance
24
- from ccxt.base.errors import InvalidNonce
25
- from ccxt.base.decimal_to_precision import ROUND
26
- from ccxt.base.decimal_to_precision import TRUNCATE
27
- from ccxt.base.decimal_to_precision import DECIMAL_PLACES
28
- from ccxt.base.decimal_to_precision import SIGNIFICANT_DIGITS
29
- from ccxt.base.precise import Precise
30
-
31
-
32
- class bitfinex2(Exchange, ImplicitAPI):
33
-
34
- def describe(self):
35
- return self.deep_extend(super(bitfinex2, self).describe(), {
36
- 'id': 'bitfinex2',
37
- 'name': 'Bitfinex',
38
- 'countries': ['VG'],
39
- 'version': 'v2',
40
- 'certified': False,
41
- 'pro': True,
42
- # new metainfo interface
43
- 'has': {
44
- 'CORS': None,
45
- 'spot': True,
46
- 'margin': True,
47
- 'swap': True,
48
- 'future': False,
49
- 'option': False,
50
- 'addMargin': False,
51
- 'borrowCrossMargin': False,
52
- 'borrowIsolatedMargin': False,
53
- 'cancelAllOrders': True,
54
- 'cancelOrder': True,
55
- 'cancelOrders': True,
56
- 'createDepositAddress': True,
57
- 'createLimitOrder': True,
58
- 'createMarketOrder': True,
59
- 'createOrder': True,
60
- 'createPostOnlyOrder': True,
61
- 'createReduceOnlyOrder': True,
62
- 'createStopLimitOrder': True,
63
- 'createStopMarketOrder': True,
64
- 'createStopOrder': True,
65
- 'createTrailingAmountOrder': True,
66
- 'createTrailingPercentOrder': False,
67
- 'createTriggerOrder': True,
68
- 'editOrder': True,
69
- 'fetchBalance': True,
70
- 'fetchBorrowInterest': False,
71
- 'fetchBorrowRate': False,
72
- 'fetchBorrowRateHistories': False,
73
- 'fetchBorrowRateHistory': False,
74
- 'fetchBorrowRates': False,
75
- 'fetchBorrowRatesPerSymbol': False,
76
- 'fetchClosedOrder': True,
77
- 'fetchClosedOrders': True,
78
- 'fetchCrossBorrowRate': False,
79
- 'fetchCrossBorrowRates': False,
80
- 'fetchCurrencies': True,
81
- 'fetchDepositAddress': True,
82
- 'fetchDepositAddresses': False,
83
- 'fetchDepositAddressesByNetwork': False,
84
- 'fetchDepositsWithdrawals': True,
85
- 'fetchFundingHistory': False,
86
- 'fetchFundingRate': 'emulated', # emulated in exchange
87
- 'fetchFundingRateHistory': True,
88
- 'fetchFundingRates': True,
89
- 'fetchIndexOHLCV': False,
90
- 'fetchIsolatedBorrowRate': False,
91
- 'fetchIsolatedBorrowRates': False,
92
- 'fetchLedger': True,
93
- 'fetchLeverage': False,
94
- 'fetchLeverageTiers': False,
95
- 'fetchLiquidations': True,
96
- 'fetchMarginMode': False,
97
- 'fetchMarketLeverageTiers': False,
98
- 'fetchMarkOHLCV': False,
99
- 'fetchMyTrades': True,
100
- 'fetchOHLCV': True,
101
- 'fetchOpenInterest': True,
102
- 'fetchOpenInterestHistory': True,
103
- 'fetchOpenOrder': True,
104
- 'fetchOpenOrders': True,
105
- 'fetchOrder': True,
106
- 'fetchOrderBook': True,
107
- 'fetchOrderBooks': False,
108
- 'fetchOrderTrades': True,
109
- 'fetchPosition': False,
110
- 'fetchPositionMode': False,
111
- 'fetchPositions': True,
112
- 'fetchPremiumIndexOHLCV': False,
113
- 'fetchStatus': True,
114
- 'fetchTickers': True,
115
- 'fetchTime': False,
116
- 'fetchTradingFee': False,
117
- 'fetchTradingFees': True,
118
- 'fetchTransactionFees': None,
119
- 'fetchTransactions': 'emulated',
120
- 'reduceMargin': False,
121
- 'repayCrossMargin': False,
122
- 'repayIsolatedMargin': False,
123
- 'setLeverage': False,
124
- 'setMargin': True,
125
- 'setMarginMode': False,
126
- 'setPositionMode': False,
127
- 'signIn': False,
128
- 'transfer': True,
129
- 'withdraw': True,
130
- },
131
- 'timeframes': {
132
- '1m': '1m',
133
- '5m': '5m',
134
- '15m': '15m',
135
- '30m': '30m',
136
- '1h': '1h',
137
- '3h': '3h',
138
- '4h': '4h',
139
- '6h': '6h',
140
- '12h': '12h',
141
- '1d': '1D',
142
- '1w': '7D',
143
- '2w': '14D',
144
- '1M': '1M',
145
- },
146
- # cheapest endpoint is 240 requests per minute => ~ 4 requests per second =>( 1000ms / 4 ) = 250ms between requests on average
147
- 'rateLimit': 250,
148
- 'urls': {
149
- 'logo': 'https://github.com/user-attachments/assets/4a8e947f-ab46-481a-a8ae-8b20e9b03178',
150
- 'api': {
151
- 'v1': 'https://api.bitfinex.com',
152
- 'public': 'https://api-pub.bitfinex.com',
153
- 'private': 'https://api.bitfinex.com',
154
- },
155
- 'www': 'https://www.bitfinex.com',
156
- 'doc': [
157
- 'https://docs.bitfinex.com/v2/docs/',
158
- 'https://github.com/bitfinexcom/bitfinex-api-node',
159
- ],
160
- 'fees': 'https://www.bitfinex.com/fees',
161
- },
162
- 'api': {
163
- 'public': {
164
- 'get': {
165
- 'conf/{config}': 2.7, # 90 requests a minute, 90/60 = 1.5, 1000 / (250 * 2.66) = 1.503, use 2.7 instead of 2.66 to ensure rateLimitExceeded is not triggered
166
- 'conf/pub:{action}:{object}': 2.7,
167
- 'conf/pub:{action}:{object}:{detail}': 2.7,
168
- 'conf/pub:map:{object}': 2.7,
169
- 'conf/pub:map:{object}:{detail}': 2.7,
170
- 'conf/pub:map:currency:{detail}': 2.7,
171
- 'conf/pub:map:currency:sym': 2.7, # maps symbols to their API symbols, BAB > BCH
172
- 'conf/pub:map:currency:label': 2.7, # verbose friendly names, BNT > Bancor
173
- 'conf/pub:map:currency:unit': 2.7, # maps symbols to unit of measure where applicable
174
- 'conf/pub:map:currency:undl': 2.7, # maps derivatives symbols to their underlying currency
175
- 'conf/pub:map:currency:pool': 2.7, # maps symbols to underlying network/protocol they operate on
176
- 'conf/pub:map:currency:explorer': 2.7, # maps symbols to their recognised block explorer URLs
177
- 'conf/pub:map:currency:tx:fee': 2.7, # maps currencies to their withdrawal fees https://github.com/ccxt/ccxt/issues/7745
178
- 'conf/pub:map:tx:method': 2.7,
179
- 'conf/pub:list:{object}': 2.7,
180
- 'conf/pub:list:{object}:{detail}': 2.7,
181
- 'conf/pub:list:currency': 2.7,
182
- 'conf/pub:list:pair:exchange': 2.7,
183
- 'conf/pub:list:pair:margin': 2.7,
184
- 'conf/pub:list:pair:futures': 2.7,
185
- 'conf/pub:list:competitions': 2.7,
186
- 'conf/pub:info:{object}': 2.7,
187
- 'conf/pub:info:{object}:{detail}': 2.7,
188
- 'conf/pub:info:pair': 2.7,
189
- 'conf/pub:info:pair:futures': 2.7,
190
- 'conf/pub:info:tx:status': 2.7, # [deposit, withdrawal] statuses 1 = active, 0 = maintenance
191
- 'conf/pub:fees': 2.7,
192
- 'platform/status': 8, # 30 requests per minute = 0.5 requests per second =>( 1000ms / rateLimit ) / 0.5 = 8
193
- 'tickers': 2.7, # 90 requests a minute = 1.5 requests per second =>( 1000 / rateLimit ) / 1.5 = 2.666666666
194
- 'ticker/{symbol}': 2.7,
195
- 'tickers/hist': 2.7,
196
- 'trades/{symbol}/hist': 2.7,
197
- 'book/{symbol}/{precision}': 1, # 240 requests a minute
198
- 'book/{symbol}/P0': 1,
199
- 'book/{symbol}/P1': 1,
200
- 'book/{symbol}/P2': 1,
201
- 'book/{symbol}/P3': 1,
202
- 'book/{symbol}/R0': 1,
203
- 'stats1/{key}:{size}:{symbol}:{side}/{section}': 2.7,
204
- 'stats1/{key}:{size}:{symbol}:{side}/last': 2.7,
205
- 'stats1/{key}:{size}:{symbol}:{side}/hist': 2.7,
206
- 'stats1/{key}:{size}:{symbol}/{section}': 2.7,
207
- 'stats1/{key}:{size}:{symbol}/last': 2.7,
208
- 'stats1/{key}:{size}:{symbol}/hist': 2.7,
209
- 'stats1/{key}:{size}:{symbol}:long/last': 2.7,
210
- 'stats1/{key}:{size}:{symbol}:long/hist': 2.7,
211
- 'stats1/{key}:{size}:{symbol}:short/last': 2.7,
212
- 'stats1/{key}:{size}:{symbol}:short/hist': 2.7,
213
- 'candles/trade:{timeframe}:{symbol}:{period}/{section}': 2.7,
214
- 'candles/trade:{timeframe}:{symbol}/{section}': 2.7,
215
- 'candles/trade:{timeframe}:{symbol}/last': 2.7,
216
- 'candles/trade:{timeframe}:{symbol}/hist': 2.7,
217
- 'status/{type}': 2.7,
218
- 'status/deriv': 2.7,
219
- 'status/deriv/{symbol}/hist': 2.7,
220
- 'liquidations/hist': 80, # 3 requests a minute = 0.05 requests a second =>( 1000ms / rateLimit ) / 0.05 = 80
221
- 'rankings/{key}:{timeframe}:{symbol}/{section}': 2.7,
222
- 'rankings/{key}:{timeframe}:{symbol}/hist': 2.7,
223
- 'pulse/hist': 2.7,
224
- 'pulse/profile/{nickname}': 2.7,
225
- 'funding/stats/{symbol}/hist': 10, # ratelimit not in docs
226
- 'ext/vasps': 1,
227
- },
228
- 'post': {
229
- 'calc/trade/avg': 2.7,
230
- 'calc/fx': 2.7,
231
- },
232
- },
233
- 'private': {
234
- 'post': {
235
- # 'auth/r/orders/{symbol}/new', # outdated
236
- # 'auth/r/stats/perf:{timeframe}/hist', # outdated
237
- 'auth/r/wallets': 2.7,
238
- 'auth/r/wallets/hist': 2.7,
239
- 'auth/r/orders': 2.7,
240
- 'auth/r/orders/{symbol}': 2.7,
241
- 'auth/w/order/submit': 2.7,
242
- 'auth/w/order/update': 2.7,
243
- 'auth/w/order/cancel': 2.7,
244
- 'auth/w/order/multi': 2.7,
245
- 'auth/w/order/cancel/multi': 2.7,
246
- 'auth/r/orders/{symbol}/hist': 2.7,
247
- 'auth/r/orders/hist': 2.7,
248
- 'auth/r/order/{symbol}:{id}/trades': 2.7,
249
- 'auth/r/trades/{symbol}/hist': 2.7,
250
- 'auth/r/trades/hist': 2.7,
251
- 'auth/r/ledgers/{currency}/hist': 2.7,
252
- 'auth/r/ledgers/hist': 2.7,
253
- 'auth/r/info/margin/{key}': 2.7,
254
- 'auth/r/info/margin/base': 2.7,
255
- 'auth/r/info/margin/sym_all': 2.7,
256
- 'auth/r/positions': 2.7,
257
- 'auth/w/position/claim': 2.7,
258
- 'auth/w/position/increase:': 2.7,
259
- 'auth/r/position/increase/info': 2.7,
260
- 'auth/r/positions/hist': 2.7,
261
- 'auth/r/positions/audit': 2.7,
262
- 'auth/r/positions/snap': 2.7,
263
- 'auth/w/deriv/collateral/set': 2.7,
264
- 'auth/w/deriv/collateral/limits': 2.7,
265
- 'auth/r/funding/offers': 2.7,
266
- 'auth/r/funding/offers/{symbol}': 2.7,
267
- 'auth/w/funding/offer/submit': 2.7,
268
- 'auth/w/funding/offer/cancel': 2.7,
269
- 'auth/w/funding/offer/cancel/all': 2.7,
270
- 'auth/w/funding/close': 2.7,
271
- 'auth/w/funding/auto': 2.7,
272
- 'auth/w/funding/keep': 2.7,
273
- 'auth/r/funding/offers/{symbol}/hist': 2.7,
274
- 'auth/r/funding/offers/hist': 2.7,
275
- 'auth/r/funding/loans': 2.7,
276
- 'auth/r/funding/loans/hist': 2.7,
277
- 'auth/r/funding/loans/{symbol}': 2.7,
278
- 'auth/r/funding/loans/{symbol}/hist': 2.7,
279
- 'auth/r/funding/credits': 2.7,
280
- 'auth/r/funding/credits/hist': 2.7,
281
- 'auth/r/funding/credits/{symbol}': 2.7,
282
- 'auth/r/funding/credits/{symbol}/hist': 2.7,
283
- 'auth/r/funding/trades/{symbol}/hist': 2.7,
284
- 'auth/r/funding/trades/hist': 2.7,
285
- 'auth/r/info/funding/{key}': 2.7,
286
- 'auth/r/info/user': 2.7,
287
- 'auth/r/summary': 2.7,
288
- 'auth/r/logins/hist': 2.7,
289
- 'auth/r/permissions': 2.7,
290
- 'auth/w/token': 2.7,
291
- 'auth/r/audit/hist': 2.7,
292
- 'auth/w/transfer': 2.7, # ratelimit not in docs...
293
- 'auth/w/deposit/address': 24, # 10 requests a minute = 0.166 requests per second =>( 1000ms / rateLimit ) / 0.166 = 24
294
- 'auth/w/deposit/invoice': 24, # ratelimit not in docs
295
- 'auth/w/withdraw': 24, # ratelimit not in docs
296
- 'auth/r/movements/{currency}/hist': 2.7,
297
- 'auth/r/movements/hist': 2.7,
298
- 'auth/r/alerts': 5.34, # 45 requests a minute = 0.75 requests per second =>( 1000ms / rateLimit ) / 0.749 => 5.34
299
- 'auth/w/alert/set': 2.7,
300
- 'auth/w/alert/price:{symbol}:{price}/del': 2.7,
301
- 'auth/w/alert/{type}:{symbol}:{price}/del': 2.7,
302
- 'auth/calc/order/avail': 2.7,
303
- 'auth/w/settings/set': 2.7,
304
- 'auth/r/settings': 2.7,
305
- 'auth/w/settings/del': 2.7,
306
- 'auth/r/pulse/hist': 2.7,
307
- 'auth/w/pulse/add': 16, # 15 requests a minute = 0.25 requests per second =>( 1000ms / rateLimit ) / 0.25 => 16
308
- 'auth/w/pulse/del': 2.7,
309
- },
310
- },
311
- },
312
- 'fees': {
313
- 'trading': {
314
- 'feeSide': 'get',
315
- 'percentage': True,
316
- 'tierBased': True,
317
- 'maker': self.parse_number('0.001'),
318
- 'taker': self.parse_number('0.002'),
319
- 'tiers': {
320
- 'taker': [
321
- [self.parse_number('0'), self.parse_number('0.002')],
322
- [self.parse_number('500000'), self.parse_number('0.002')],
323
- [self.parse_number('1000000'), self.parse_number('0.002')],
324
- [self.parse_number('2500000'), self.parse_number('0.002')],
325
- [self.parse_number('5000000'), self.parse_number('0.002')],
326
- [self.parse_number('7500000'), self.parse_number('0.002')],
327
- [self.parse_number('10000000'), self.parse_number('0.0018')],
328
- [self.parse_number('15000000'), self.parse_number('0.0016')],
329
- [self.parse_number('20000000'), self.parse_number('0.0014')],
330
- [self.parse_number('25000000'), self.parse_number('0.0012')],
331
- [self.parse_number('30000000'), self.parse_number('0.001')],
332
- ],
333
- 'maker': [
334
- [self.parse_number('0'), self.parse_number('0.001')],
335
- [self.parse_number('500000'), self.parse_number('0.0008')],
336
- [self.parse_number('1000000'), self.parse_number('0.0006')],
337
- [self.parse_number('2500000'), self.parse_number('0.0004')],
338
- [self.parse_number('5000000'), self.parse_number('0.0002')],
339
- [self.parse_number('7500000'), self.parse_number('0')],
340
- [self.parse_number('10000000'), self.parse_number('0')],
341
- [self.parse_number('15000000'), self.parse_number('0')],
342
- [self.parse_number('20000000'), self.parse_number('0')],
343
- [self.parse_number('25000000'), self.parse_number('0')],
344
- [self.parse_number('30000000'), self.parse_number('0')],
345
- ],
346
- },
347
- },
348
- 'funding': {
349
- 'withdraw': {},
350
- },
351
- },
352
- 'precisionMode': SIGNIFICANT_DIGITS,
353
- 'options': {
354
- 'precision': 'R0', # P0, P1, P2, P3, P4, R0
355
- # convert 'EXCHANGE MARKET' to lowercase 'market'
356
- # convert 'EXCHANGE LIMIT' to lowercase 'limit'
357
- # everything else remains uppercase
358
- 'exchangeTypes': {
359
- 'MARKET': 'market',
360
- 'EXCHANGE MARKET': 'market',
361
- 'LIMIT': 'limit',
362
- 'EXCHANGE LIMIT': 'limit',
363
- # 'STOP': None,
364
- 'EXCHANGE STOP': 'market',
365
- # 'TRAILING STOP': None,
366
- # 'EXCHANGE TRAILING STOP': None,
367
- # 'FOK': None,
368
- 'EXCHANGE FOK': 'limit',
369
- # 'STOP LIMIT': None,
370
- 'EXCHANGE STOP LIMIT': 'limit',
371
- # 'IOC': None,
372
- 'EXCHANGE IOC': 'limit',
373
- },
374
- # convert 'market' to 'EXCHANGE MARKET'
375
- # convert 'limit' 'EXCHANGE LIMIT'
376
- # everything else remains
377
- 'orderTypes': {
378
- 'market': 'EXCHANGE MARKET',
379
- 'limit': 'EXCHANGE LIMIT',
380
- },
381
- 'fiat': {
382
- 'USD': 'USD',
383
- 'EUR': 'EUR',
384
- 'JPY': 'JPY',
385
- 'GBP': 'GBP',
386
- 'CHN': 'CHN',
387
- },
388
- # actually the correct names unlike the v1
389
- # we don't want to self.extend self with accountsByType in v1
390
- 'v2AccountsByType': {
391
- 'spot': 'exchange',
392
- 'exchange': 'exchange',
393
- 'funding': 'funding',
394
- 'margin': 'margin',
395
- 'derivatives': 'margin',
396
- 'future': 'margin',
397
- 'swap': 'margin',
398
- },
399
- 'withdraw': {
400
- 'includeFee': False,
401
- },
402
- 'networks': {
403
- 'BTC': 'BITCOIN',
404
- 'LTC': 'LITECOIN',
405
- 'ERC20': 'ETHEREUM',
406
- 'OMNI': 'TETHERUSO',
407
- 'LIQUID': 'TETHERUSL',
408
- 'TRC20': 'TETHERUSX',
409
- 'EOS': 'TETHERUSS',
410
- 'AVAX': 'TETHERUSDTAVAX',
411
- 'SOL': 'TETHERUSDTSOL',
412
- 'ALGO': 'TETHERUSDTALG',
413
- 'BCH': 'TETHERUSDTBCH',
414
- 'KSM': 'TETHERUSDTKSM',
415
- 'DVF': 'TETHERUSDTDVF',
416
- 'OMG': 'TETHERUSDTOMG',
417
- },
418
- 'networksById': {
419
- 'TETHERUSE': 'ERC20',
420
- },
421
- },
422
- 'exceptions': {
423
- 'exact': {
424
- '11010': RateLimitExceeded,
425
- '10001': PermissionDenied, # api_key: permission invalid(#10001)
426
- '10020': BadRequest,
427
- '10100': AuthenticationError,
428
- '10114': InvalidNonce,
429
- '20060': OnMaintenance,
430
- # {"code":503,"error":"temporarily_unavailable","error_description":"Sorry, the service is temporarily unavailable. See https://www.bitfinex.com/ for more info."}
431
- 'temporarily_unavailable': ExchangeNotAvailable,
432
- },
433
- 'broad': {
434
- 'available balance is only': InsufficientFunds,
435
- 'not enough exchange balance': InsufficientFunds,
436
- 'Order not found': OrderNotFound,
437
- 'symbol: invalid': BadSymbol,
438
- },
439
- },
440
- 'commonCurrencies': {
441
- 'UST': 'USDT',
442
- 'EUTF0': 'EURT',
443
- 'USTF0': 'USDT',
444
- 'ALG': 'ALGO', # https://github.com/ccxt/ccxt/issues/6034
445
- 'AMP': 'AMPL',
446
- 'ATO': 'ATOM', # https://github.com/ccxt/ccxt/issues/5118
447
- 'BCHABC': 'XEC',
448
- 'BCHN': 'BCH',
449
- 'DAT': 'DATA',
450
- 'DOG': 'MDOGE',
451
- 'DSH': 'DASH',
452
- 'EDO': 'PNT',
453
- 'EUS': 'EURS',
454
- 'EUT': 'EURT',
455
- 'HTX': 'HT',
456
- 'IDX': 'ID',
457
- 'IOT': 'IOTA',
458
- 'IQX': 'IQ',
459
- 'LUNA': 'LUNC',
460
- 'LUNA2': 'LUNA',
461
- 'MNA': 'MANA',
462
- 'ORS': 'ORS Group', # conflict with Origin Sport #3230
463
- 'PAS': 'PASS',
464
- 'QSH': 'QASH',
465
- 'QTM': 'QTUM',
466
- 'RBT': 'RBTC',
467
- 'SNG': 'SNGLS',
468
- 'STJ': 'STORJ',
469
- 'TERRAUST': 'USTC',
470
- 'TSD': 'TUSD',
471
- 'YGG': 'YEED', # conflict with Yield Guild Games
472
- 'YYW': 'YOYOW',
473
- 'UDC': 'USDC',
474
- 'VSY': 'VSYS',
475
- 'WAX': 'WAXP',
476
- 'XCH': 'XCHF',
477
- 'ZBT': 'ZB',
478
- },
479
- })
480
-
481
- def is_fiat(self, code):
482
- return(code in self.options['fiat'])
483
-
484
- def get_currency_id(self, code):
485
- return 'f' + code
486
-
487
- def get_currency_name(self, code):
488
- # temporary fix for transpiler recognition, even though self is in parent class
489
- if code in self.options['currencyNames']:
490
- return self.options['currencyNames'][code]
491
- raise NotSupported(self.id + ' ' + code + ' not supported for withdrawal')
492
-
493
- def amount_to_precision(self, symbol, amount):
494
- # https://docs.bitfinex.com/docs/introduction#amount-precision
495
- # The amount field allows up to 8 decimals.
496
- # Anything exceeding self will be rounded to the 8th decimal.
497
- symbol = self.safe_symbol(symbol)
498
- return self.decimal_to_precision(amount, TRUNCATE, self.markets[symbol]['precision']['amount'], DECIMAL_PLACES)
499
-
500
- def price_to_precision(self, symbol, price):
501
- symbol = self.safe_symbol(symbol)
502
- price = self.decimal_to_precision(price, ROUND, self.markets[symbol]['precision']['price'], self.precisionMode)
503
- # https://docs.bitfinex.com/docs/introduction#price-precision
504
- # The precision level of all trading prices is based on significant figures.
505
- # 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).
506
- # Prices submit with a precision larger than 5 will be cut by the API.
507
- return self.decimal_to_precision(price, TRUNCATE, 8, DECIMAL_PLACES)
508
-
509
- def fetch_status(self, params={}):
510
- """
511
- the latest known information on the availability of the exchange API
512
-
513
- https://docs.bitfinex.com/reference/rest-public-platform-status
514
-
515
- :param dict [params]: extra parameters specific to the exchange API endpoint
516
- :returns dict: a `status structure <https://docs.ccxt.com/#/?id=exchange-status-structure>`
517
- """
518
- #
519
- # [1] # operative
520
- # [0] # maintenance
521
- #
522
- response = self.publicGetPlatformStatus(params)
523
- statusRaw = self.safe_string(response, 0)
524
- return {
525
- 'status': self.safe_string({'0': 'maintenance', '1': 'ok'}, statusRaw, statusRaw),
526
- 'updated': None,
527
- 'eta': None,
528
- 'url': None,
529
- 'info': response,
530
- }
531
-
532
- def fetch_markets(self, params={}) -> List[Market]:
533
- """
534
- retrieves data on all markets for bitfinex2
535
-
536
- https://docs.bitfinex.com/reference/rest-public-conf
537
-
538
- :param dict [params]: extra parameters specific to the exchange API endpoint
539
- :returns dict[]: an array of objects representing market data
540
- """
541
- spotMarketsInfoPromise = self.publicGetConfPubInfoPair(params)
542
- futuresMarketsInfoPromise = self.publicGetConfPubInfoPairFutures(params)
543
- marginIdsPromise = self.publicGetConfPubListPairMargin(params)
544
- spotMarketsInfo, futuresMarketsInfo, marginIds = [spotMarketsInfoPromise, futuresMarketsInfoPromise, marginIdsPromise]
545
- spotMarketsInfo = self.safe_list(spotMarketsInfo, 0, [])
546
- futuresMarketsInfo = self.safe_list(futuresMarketsInfo, 0, [])
547
- markets = self.array_concat(spotMarketsInfo, futuresMarketsInfo)
548
- marginIds = self.safe_value(marginIds, 0, [])
549
- #
550
- # [
551
- # "1INCH:USD",
552
- # [
553
- # null,
554
- # null,
555
- # null,
556
- # "2.0",
557
- # "100000.0",
558
- # null,
559
- # null,
560
- # null,
561
- # null,
562
- # null,
563
- # null,
564
- # null
565
- # ]
566
- # ]
567
- #
568
- result = []
569
- for i in range(0, len(markets)):
570
- pair = markets[i]
571
- id = self.safe_string_upper(pair, 0)
572
- market = self.safe_value(pair, 1, {})
573
- spot = True
574
- if id.find('F0') >= 0:
575
- spot = False
576
- swap = not spot
577
- baseId = None
578
- quoteId = None
579
- if id.find(':') >= 0:
580
- parts = id.split(':')
581
- baseId = parts[0]
582
- quoteId = parts[1]
583
- else:
584
- baseId = id[0:3]
585
- quoteId = id[3:6]
586
- base = self.safe_currency_code(baseId)
587
- quote = self.safe_currency_code(quoteId)
588
- splitBase = base.split('F0')
589
- splitQuote = quote.split('F0')
590
- base = self.safe_string(splitBase, 0)
591
- quote = self.safe_string(splitQuote, 0)
592
- symbol = base + '/' + quote
593
- baseId = self.get_currency_id(baseId)
594
- quoteId = self.get_currency_id(quoteId)
595
- settle = None
596
- settleId = None
597
- if swap:
598
- settle = quote
599
- settleId = quote
600
- symbol = symbol + ':' + settle
601
- minOrderSizeString = self.safe_string(market, 3)
602
- maxOrderSizeString = self.safe_string(market, 4)
603
- margin = False
604
- if spot and self.in_array(id, marginIds):
605
- margin = True
606
- result.append({
607
- 'id': 't' + id,
608
- 'symbol': symbol,
609
- 'base': base,
610
- 'quote': quote,
611
- 'settle': settle,
612
- 'baseId': baseId,
613
- 'quoteId': quoteId,
614
- 'settleId': settleId,
615
- 'type': 'spot' if spot else 'swap',
616
- 'spot': spot,
617
- 'margin': margin,
618
- 'swap': swap,
619
- 'future': False,
620
- 'option': False,
621
- 'active': True,
622
- 'contract': swap,
623
- 'linear': True if swap else None,
624
- 'inverse': False if swap else None,
625
- 'contractSize': self.parse_number('1') if swap else None,
626
- 'expiry': None,
627
- 'expiryDatetime': None,
628
- 'strike': None,
629
- 'optionType': None,
630
- 'precision': {
631
- 'amount': int('8'), # https://github.com/ccxt/ccxt/issues/7310
632
- 'price': int('5'),
633
- },
634
- 'limits': {
635
- 'leverage': {
636
- 'min': None,
637
- 'max': None,
638
- },
639
- 'amount': {
640
- 'min': self.parse_number(minOrderSizeString),
641
- 'max': self.parse_number(maxOrderSizeString),
642
- },
643
- 'price': {
644
- 'min': self.parse_number('1e-8'),
645
- 'max': None,
646
- },
647
- 'cost': {
648
- 'min': None,
649
- 'max': None,
650
- },
651
- },
652
- 'created': None, # todo: the api needs revision for extra params & endpoints for possibility of returning a timestamp for self
653
- 'info': market,
654
- })
655
- return result
656
-
657
- def fetch_currencies(self, params={}) -> Currencies:
658
- """
659
- fetches all available currencies on an exchange
660
-
661
- https://docs.bitfinex.com/reference/rest-public-conf
662
-
663
- :param dict [params]: extra parameters specific to the exchange API endpoint
664
- :returns dict: an associative dictionary of currencies
665
- """
666
- labels = [
667
- 'pub:list:currency',
668
- 'pub:map:currency:sym', # maps symbols to their API symbols, BAB > BCH
669
- 'pub:map:currency:label', # verbose friendly names, BNT > Bancor
670
- 'pub:map:currency:unit', # maps symbols to unit of measure where applicable
671
- 'pub:map:currency:undl', # maps derivatives symbols to their underlying currency
672
- 'pub:map:currency:pool', # maps symbols to underlying network/protocol they operate on
673
- 'pub:map:currency:explorer', # maps symbols to their recognised block explorer URLs
674
- 'pub:map:currency:tx:fee', # maps currencies to their withdrawal fees https://github.com/ccxt/ccxt/issues/7745,
675
- 'pub:map:tx:method', # maps withdrawal/deposit methods to their API symbols
676
- ]
677
- config = ','.join(labels)
678
- request: dict = {
679
- 'config': config,
680
- }
681
- response = self.publicGetConfConfig(self.extend(request, params))
682
- #
683
- # [
684
- #
685
- # a list of symbols
686
- # ["AAA","ABS","ADA"],
687
- #
688
- # # sym
689
- # # maps symbols to their API symbols, BAB > BCH
690
- # [
691
- # ["BAB", "BCH"],
692
- # ["CNHT", "CNHt"],
693
- # ["DSH", "DASH"],
694
- # ["IOT", "IOTA"],
695
- # ["LES", "LEO-EOS"],
696
- # ["LET", "LEO-ERC20"],
697
- # ["STJ", "STORJ"],
698
- # ["TSD", "TUSD"],
699
- # ["UDC", "USDC"],
700
- # ["USK", "USDK"],
701
- # ["UST", "USDt"],
702
- # ["USTF0", "USDt0"],
703
- # ["XCH", "XCHF"],
704
- # ["YYW", "YOYOW"],
705
- # # ...
706
- # ],
707
- # # label
708
- # # verbose friendly names, BNT > Bancor
709
- # [
710
- # ["BAB", "Bitcoin Cash"],
711
- # ["BCH", "Bitcoin Cash"],
712
- # ["LEO", "Unus Sed LEO"],
713
- # ["LES", "Unus Sed LEO(EOS)"],
714
- # ["LET", "Unus Sed LEO(ERC20)"],
715
- # # ...
716
- # ],
717
- # # unit
718
- # # maps symbols to unit of measure where applicable
719
- # [
720
- # ["IOT", "Mi|MegaIOTA"],
721
- # ],
722
- # # undl
723
- # # maps derivatives symbols to their underlying currency
724
- # [
725
- # ["USTF0", "UST"],
726
- # ["BTCF0", "BTC"],
727
- # ["ETHF0", "ETH"],
728
- # ],
729
- # # pool
730
- # # maps symbols to underlying network/protocol they operate on
731
- # [
732
- # ['SAN', 'ETH'], ['OMG', 'ETH'], ['AVT', 'ETH'], ["EDO", "ETH"],
733
- # ['ESS', 'ETH'], ['ATD', 'EOS'], ['ADD', 'EOS'], ["MTO", "EOS"],
734
- # ['PNK', 'ETH'], ['BAB', 'BCH'], ['WLO', 'XLM'], ["VLD", "ETH"],
735
- # ['BTT', 'TRX'], ['IMP', 'ETH'], ['SCR', 'ETH'], ["GNO", "ETH"],
736
- # # ...
737
- # ],
738
- # # explorer
739
- # # maps symbols to their recognised block explorer URLs
740
- # [
741
- # [
742
- # "AIO",
743
- # [
744
- # "https://mainnet.aion.network",
745
- # "https://mainnet.aion.network/#/account/VAL",
746
- # "https://mainnet.aion.network/#/transaction/VAL"
747
- # ]
748
- # ],
749
- # # ...
750
- # ],
751
- # # fee
752
- # # maps currencies to their withdrawal fees
753
- # [
754
- # ["AAA",[0,0]],
755
- # ["ABS",[0,131.3]],
756
- # ["ADA",[0,0.3]],
757
- # ],
758
- # ]
759
- #
760
- indexed: dict = {
761
- 'sym': self.index_by(self.safe_value(response, 1, []), 0),
762
- 'label': self.index_by(self.safe_value(response, 2, []), 0),
763
- 'unit': self.index_by(self.safe_value(response, 3, []), 0),
764
- 'undl': self.index_by(self.safe_value(response, 4, []), 0),
765
- 'pool': self.index_by(self.safe_value(response, 5, []), 0),
766
- 'explorer': self.index_by(self.safe_value(response, 6, []), 0),
767
- 'fees': self.index_by(self.safe_value(response, 7, []), 0),
768
- }
769
- ids = self.safe_value(response, 0, [])
770
- result: dict = {}
771
- for i in range(0, len(ids)):
772
- id = ids[i]
773
- if id.find('F0') >= 0:
774
- # we get a lot of F0 currencies, skip those
775
- continue
776
- code = self.safe_currency_code(id)
777
- label = self.safe_value(indexed['label'], id, [])
778
- name = self.safe_string(label, 1)
779
- pool = self.safe_value(indexed['pool'], id, [])
780
- rawType = self.safe_string(pool, 1)
781
- isCryptoCoin = (rawType is not None) or (id in indexed['explorer']) # "hacky" solution
782
- type = None
783
- if isCryptoCoin:
784
- type = 'crypto'
785
- feeValues = self.safe_value(indexed['fees'], id, [])
786
- fees = self.safe_value(feeValues, 1, [])
787
- fee = self.safe_number(fees, 1)
788
- undl = self.safe_value(indexed['undl'], id, [])
789
- precision = '8' # default precision, todo: fix "magic constants"
790
- fid = 'f' + id
791
- result[code] = {
792
- 'id': fid,
793
- 'uppercaseId': id,
794
- 'code': code,
795
- 'info': [id, label, pool, feeValues, undl],
796
- 'type': type,
797
- 'name': name,
798
- 'active': True,
799
- 'deposit': None,
800
- 'withdraw': None,
801
- 'fee': fee,
802
- 'precision': int(precision),
803
- 'limits': {
804
- 'amount': {
805
- 'min': self.parse_number(self.parse_precision(precision)),
806
- 'max': None,
807
- },
808
- 'withdraw': {
809
- 'min': fee,
810
- 'max': None,
811
- },
812
- },
813
- 'networks': {},
814
- }
815
- networks: dict = {}
816
- currencyNetworks = self.safe_value(response, 8, [])
817
- cleanId = id.replace('F0', '')
818
- for j in range(0, len(currencyNetworks)):
819
- pair = currencyNetworks[j]
820
- networkId = self.safe_string(pair, 0)
821
- currencyId = self.safe_string(self.safe_value(pair, 1, []), 0)
822
- if currencyId == cleanId:
823
- network = self.network_id_to_code(networkId)
824
- networks[network] = {
825
- 'info': networkId,
826
- 'id': networkId.lower(),
827
- 'network': networkId,
828
- 'active': None,
829
- 'deposit': None,
830
- 'withdraw': None,
831
- 'fee': None,
832
- 'precision': None,
833
- 'limits': {
834
- 'withdraw': {
835
- 'min': None,
836
- 'max': None,
837
- },
838
- },
839
- }
840
- keysNetworks = list(networks.keys())
841
- networksLength = len(keysNetworks)
842
- if networksLength > 0:
843
- result[code]['networks'] = networks
844
- return result
845
-
846
- def fetch_balance(self, params={}) -> Balances:
847
- """
848
- query for balance and get the amount of funds available for trading or funds locked in orders
849
-
850
- https://docs.bitfinex.com/reference/rest-auth-wallets
851
-
852
- :param dict [params]: extra parameters specific to the exchange API endpoint
853
- :returns dict: a `balance structure <https://docs.ccxt.com/#/?id=balance-structure>`
854
- """
855
- # self api call does not return the 'used' amount - use the v1 version instead(which also returns zero balances)
856
- # there is a difference between self and the v1 api, namely trading wallet is called margin in v2
857
- self.load_markets()
858
- accountsByType = self.safe_value(self.options, 'v2AccountsByType', {})
859
- requestedType = self.safe_string(params, 'type', 'exchange')
860
- accountType = self.safe_string(accountsByType, requestedType, requestedType)
861
- if accountType is None:
862
- keys = list(accountsByType.keys())
863
- raise ExchangeError(self.id + ' fetchBalance() type parameter must be one of ' + ', '.join(keys))
864
- isDerivative = requestedType == 'derivatives'
865
- query = self.omit(params, 'type')
866
- response = self.privatePostAuthRWallets(query)
867
- result: dict = {'info': response}
868
- for i in range(0, len(response)):
869
- balance = response[i]
870
- account = self.account()
871
- interest = self.safe_string(balance, 3)
872
- if interest != '0':
873
- account['debt'] = interest
874
- type = self.safe_string(balance, 0)
875
- currencyId = self.safe_string_lower(balance, 1, '')
876
- start = len(currencyId) - 2
877
- isDerivativeCode = currencyId[start:] == 'f0'
878
- # self will only filter the derivative codes if the requestedType is 'derivatives'
879
- derivativeCondition = (not isDerivative or isDerivativeCode)
880
- if (accountType == type) and derivativeCondition:
881
- code = self.safe_currency_code(currencyId)
882
- account['total'] = self.safe_string(balance, 2)
883
- account['free'] = self.safe_string(balance, 4)
884
- result[code] = account
885
- return self.safe_balance(result)
886
-
887
- def transfer(self, code: str, amount: float, fromAccount: str, toAccount: str, params={}) -> TransferEntry:
888
- """
889
- transfer currency internally between wallets on the same account
890
-
891
- https://docs.bitfinex.com/reference/rest-auth-transfer
892
-
893
- :param str code: unified currency code
894
- :param float amount: amount to transfer
895
- :param str fromAccount: account to transfer from
896
- :param str toAccount: account to transfer to
897
- :param dict [params]: extra parameters specific to the exchange API endpoint
898
- :returns dict: a `transfer structure <https://docs.ccxt.com/#/?id=transfer-structure>`
899
- """
900
- # transferring between derivatives wallet and regular wallet is not documented in their API
901
- # however we support it in CCXT(from just looking at web inspector)
902
- self.load_markets()
903
- accountsByType = self.safe_value(self.options, 'v2AccountsByType', {})
904
- fromId = self.safe_string(accountsByType, fromAccount)
905
- if fromId is None:
906
- keys = list(accountsByType.keys())
907
- raise ArgumentsRequired(self.id + ' transfer() fromAccount must be one of ' + ', '.join(keys))
908
- toId = self.safe_string(accountsByType, toAccount)
909
- if toId is None:
910
- keys = list(accountsByType.keys())
911
- raise ArgumentsRequired(self.id + ' transfer() toAccount must be one of ' + ', '.join(keys))
912
- currency = self.currency(code)
913
- fromCurrencyId = self.convert_derivatives_id(currency, fromAccount)
914
- toCurrencyId = self.convert_derivatives_id(currency, toAccount)
915
- requestedAmount = self.currency_to_precision(code, amount)
916
- # self request is slightly different from v1 fromAccount -> from
917
- request: dict = {
918
- 'amount': requestedAmount,
919
- 'currency': fromCurrencyId,
920
- 'currency_to': toCurrencyId,
921
- 'from': fromId,
922
- 'to': toId,
923
- }
924
- response = self.privatePostAuthWTransfer(self.extend(request, params))
925
- #
926
- # [
927
- # 1616451183763,
928
- # "acc_tf",
929
- # null,
930
- # null,
931
- # [
932
- # 1616451183763,
933
- # "exchange",
934
- # "margin",
935
- # null,
936
- # "UST",
937
- # "UST",
938
- # null,
939
- # 1
940
- # ],
941
- # null,
942
- # "SUCCESS",
943
- # "1.0 Tether USDt transfered from Exchange to Margin"
944
- # ]
945
- #
946
- error = self.safe_string(response, 0)
947
- if error == 'error':
948
- message = self.safe_string(response, 2, '')
949
- # same message v1
950
- self.throw_exactly_matched_exception(self.exceptions['exact'], message, self.id + ' ' + message)
951
- raise ExchangeError(self.id + ' ' + message)
952
- return self.parse_transfer({'result': response}, currency)
953
-
954
- def parse_transfer(self, transfer: dict, currency: Currency = None) -> TransferEntry:
955
- #
956
- # transfer
957
- #
958
- # [
959
- # 1616451183763,
960
- # "acc_tf",
961
- # null,
962
- # null,
963
- # [
964
- # 1616451183763,
965
- # "exchange",
966
- # "margin",
967
- # null,
968
- # "UST",
969
- # "UST",
970
- # null,
971
- # 1
972
- # ],
973
- # null,
974
- # "SUCCESS",
975
- # "1.0 Tether USDt transfered from Exchange to Margin"
976
- # ]
977
- #
978
- result = self.safe_list(transfer, 'result')
979
- timestamp = self.safe_integer(result, 0)
980
- info = self.safe_value(result, 4)
981
- fromAccount = self.safe_string(info, 1)
982
- toAccount = self.safe_string(info, 2)
983
- currencyId = self.safe_string(info, 5)
984
- status = self.safe_string(result, 6)
985
- return {
986
- 'id': None,
987
- 'timestamp': timestamp,
988
- 'datetime': self.iso8601(timestamp),
989
- 'status': self.parse_transfer_status(status),
990
- 'amount': self.safe_number(info, 7),
991
- 'currency': self.safe_currency_code(currencyId, currency),
992
- 'fromAccount': fromAccount,
993
- 'toAccount': toAccount,
994
- 'info': result,
995
- }
996
-
997
- def parse_transfer_status(self, status: Str) -> Str:
998
- statuses: dict = {
999
- 'SUCCESS': 'ok',
1000
- 'ERROR': 'failed',
1001
- 'FAILURE': 'failed',
1002
- }
1003
- return self.safe_string(statuses, status, status)
1004
-
1005
- def convert_derivatives_id(self, currency, type):
1006
- # there is a difference between self and the v1 api, namely trading wallet is called margin in v2
1007
- # {
1008
- # "id": "fUSTF0",
1009
- # "code": "USTF0",
1010
- # "info": ['USTF0', [], [], [], ["USTF0", "UST"]],
1011
- info = self.safe_value(currency, 'info')
1012
- transferId = self.safe_string(info, 0)
1013
- underlying = self.safe_value(info, 4, [])
1014
- currencyId = None
1015
- if type == 'derivatives':
1016
- currencyId = self.safe_string(underlying, 0, transferId)
1017
- start = len(currencyId) - 2
1018
- isDerivativeCode = currencyId[start:] == 'F0'
1019
- if not isDerivativeCode:
1020
- currencyId = currencyId + 'F0'
1021
- elif type != 'margin':
1022
- currencyId = self.safe_string(underlying, 1, transferId)
1023
- else:
1024
- currencyId = transferId
1025
- return currencyId
1026
-
1027
- def fetch_order_book(self, symbol: str, limit: Int = None, params={}) -> OrderBook:
1028
- """
1029
- fetches information on open orders with bid(buy) and ask(sell) prices, volumes and other data
1030
-
1031
- https://docs.bitfinex.com/reference/rest-public-book
1032
-
1033
- :param str symbol: unified symbol of the market to fetch the order book for
1034
- :param int [limit]: the maximum amount of order book entries to return, bitfinex only allows 1, 25, or 100
1035
- :param dict [params]: extra parameters specific to the exchange API endpoint
1036
- :returns dict: A dictionary of `order book structures <https://docs.ccxt.com/#/?id=order-book-structure>` indexed by market symbols
1037
- """
1038
- self.load_markets()
1039
- precision = self.safe_value(self.options, 'precision', 'R0')
1040
- market = self.market(symbol)
1041
- request: dict = {
1042
- 'symbol': market['id'],
1043
- 'precision': precision,
1044
- }
1045
- if limit is not None:
1046
- request['len'] = limit
1047
- fullRequest = self.extend(request, params)
1048
- orderbook = self.publicGetBookSymbolPrecision(fullRequest)
1049
- timestamp = self.milliseconds()
1050
- result: dict = {
1051
- 'symbol': market['symbol'],
1052
- 'bids': [],
1053
- 'asks': [],
1054
- 'timestamp': timestamp,
1055
- 'datetime': self.iso8601(timestamp),
1056
- 'nonce': None,
1057
- }
1058
- priceIndex = 1 if (fullRequest['precision'] == 'R0') else 0
1059
- for i in range(0, len(orderbook)):
1060
- order = orderbook[i]
1061
- price = self.safe_number(order, priceIndex)
1062
- signedAmount = self.safe_string(order, 2)
1063
- amount = Precise.string_abs(signedAmount)
1064
- side = 'bids' if Precise.string_gt(signedAmount, '0') else 'asks'
1065
- result[side].append([price, self.parse_number(amount)])
1066
- result['bids'] = self.sort_by(result['bids'], 0, True)
1067
- result['asks'] = self.sort_by(result['asks'], 0)
1068
- return result
1069
-
1070
- def parse_ticker(self, ticker: dict, market: Market = None) -> Ticker:
1071
- #
1072
- # on trading pairs(ex. tBTCUSD)
1073
- #
1074
- # {
1075
- # 'result': [
1076
- # SYMBOL,
1077
- # BID,
1078
- # BID_SIZE,
1079
- # ASK,
1080
- # ASK_SIZE,
1081
- # DAILY_CHANGE,
1082
- # DAILY_CHANGE_RELATIVE,
1083
- # LAST_PRICE,
1084
- # VOLUME,
1085
- # HIGH,
1086
- # LOW
1087
- # ]
1088
- # }
1089
- #
1090
- #
1091
- # on funding currencies(ex. fUSD)
1092
- #
1093
- # {
1094
- # 'result': [
1095
- # SYMBOL,
1096
- # FRR,
1097
- # BID,
1098
- # BID_PERIOD,
1099
- # BID_SIZE,
1100
- # ASK,
1101
- # ASK_PERIOD,
1102
- # ASK_SIZE,
1103
- # DAILY_CHANGE,
1104
- # DAILY_CHANGE_RELATIVE,
1105
- # LAST_PRICE,
1106
- # VOLUME,
1107
- # HIGH,
1108
- # LOW,
1109
- # _PLACEHOLDER,
1110
- # _PLACEHOLDER,
1111
- # FRR_AMOUNT_AVAILABLE
1112
- # ]
1113
- # }
1114
- #
1115
- result = self.safe_list(ticker, 'result')
1116
- symbol = self.safe_symbol(None, market)
1117
- length = len(result)
1118
- last = self.safe_string(result, length - 4)
1119
- percentage = self.safe_string(result, length - 5)
1120
- return self.safe_ticker({
1121
- 'symbol': symbol,
1122
- 'timestamp': None,
1123
- 'datetime': None,
1124
- 'high': self.safe_string(result, length - 2),
1125
- 'low': self.safe_string(result, length - 1),
1126
- 'bid': self.safe_string(result, length - 10),
1127
- 'bidVolume': self.safe_string(result, length - 9),
1128
- 'ask': self.safe_string(result, length - 8),
1129
- 'askVolume': self.safe_string(result, length - 7),
1130
- 'vwap': None,
1131
- 'open': None,
1132
- 'close': last,
1133
- 'last': last,
1134
- 'previousClose': None,
1135
- 'change': self.safe_string(result, length - 6),
1136
- 'percentage': Precise.string_mul(percentage, '100'),
1137
- 'average': None,
1138
- 'baseVolume': self.safe_string(result, length - 3),
1139
- 'quoteVolume': None,
1140
- 'info': result,
1141
- }, market)
1142
-
1143
- def fetch_tickers(self, symbols: Strings = None, params={}) -> Tickers:
1144
- """
1145
- fetches price tickers for multiple markets, statistical information calculated over the past 24 hours for each market
1146
-
1147
- https://docs.bitfinex.com/reference/rest-public-tickers
1148
-
1149
- :param str[]|None symbols: unified symbols of the markets to fetch the ticker for, all market tickers are returned if not assigned
1150
- :param dict [params]: extra parameters specific to the exchange API endpoint
1151
- :returns dict: a dictionary of `ticker structures <https://docs.ccxt.com/#/?id=ticker-structure>`
1152
- """
1153
- self.load_markets()
1154
- symbols = self.market_symbols(symbols)
1155
- request: dict = {}
1156
- if symbols is not None:
1157
- ids = self.market_ids(symbols)
1158
- request['symbols'] = ','.join(ids)
1159
- else:
1160
- request['symbols'] = 'ALL'
1161
- tickers = self.publicGetTickers(self.extend(request, params))
1162
- #
1163
- # [
1164
- # # on trading pairs(ex. tBTCUSD)
1165
- # [
1166
- # SYMBOL,
1167
- # BID,
1168
- # BID_SIZE,
1169
- # ASK,
1170
- # ASK_SIZE,
1171
- # DAILY_CHANGE,
1172
- # DAILY_CHANGE_RELATIVE,
1173
- # LAST_PRICE,
1174
- # VOLUME,
1175
- # HIGH,
1176
- # LOW
1177
- # ],
1178
- # # on funding currencies(ex. fUSD)
1179
- # [
1180
- # SYMBOL,
1181
- # FRR,
1182
- # BID,
1183
- # BID_PERIOD,
1184
- # BID_SIZE,
1185
- # ASK,
1186
- # ASK_PERIOD,
1187
- # ASK_SIZE,
1188
- # DAILY_CHANGE,
1189
- # DAILY_CHANGE_RELATIVE,
1190
- # LAST_PRICE,
1191
- # VOLUME,
1192
- # HIGH,
1193
- # LOW,
1194
- # _PLACEHOLDER,
1195
- # _PLACEHOLDER,
1196
- # FRR_AMOUNT_AVAILABLE
1197
- # ],
1198
- # ...
1199
- # ]
1200
- #
1201
- result: dict = {}
1202
- for i in range(0, len(tickers)):
1203
- ticker = tickers[i]
1204
- marketId = self.safe_string(ticker, 0)
1205
- market = self.safe_market(marketId)
1206
- symbol = market['symbol']
1207
- result[symbol] = self.parse_ticker({'result': ticker}, market)
1208
- return self.filter_by_array_tickers(result, 'symbol', symbols)
1209
-
1210
- def fetch_ticker(self, symbol: str, params={}) -> Ticker:
1211
- """
1212
- fetches a price ticker, a statistical calculation with the information calculated over the past 24 hours for a specific market
1213
-
1214
- https://docs.bitfinex.com/reference/rest-public-ticker
1215
-
1216
- :param str symbol: unified symbol of the market to fetch the ticker for
1217
- :param dict [params]: extra parameters specific to the exchange API endpoint
1218
- :returns dict: a `ticker structure <https://docs.ccxt.com/#/?id=ticker-structure>`
1219
- """
1220
- self.load_markets()
1221
- market = self.market(symbol)
1222
- request: dict = {
1223
- 'symbol': market['id'],
1224
- }
1225
- ticker = self.publicGetTickerSymbol(self.extend(request, params))
1226
- result: dict = {'result': ticker}
1227
- return self.parse_ticker(result, market)
1228
-
1229
- def parse_trade(self, trade: dict, market: Market = None) -> Trade:
1230
- #
1231
- # fetchTrades(public)
1232
- #
1233
- # [
1234
- # ID,
1235
- # MTS, # timestamp
1236
- # AMOUNT,
1237
- # PRICE
1238
- # ]
1239
- #
1240
- # fetchMyTrades(private)
1241
- #
1242
- # [
1243
- # ID,
1244
- # PAIR,
1245
- # MTS_CREATE,
1246
- # ORDER_ID,
1247
- # EXEC_AMOUNT,
1248
- # EXEC_PRICE,
1249
- # ORDER_TYPE,
1250
- # ORDER_PRICE,
1251
- # MAKER,
1252
- # FEE,
1253
- # FEE_CURRENCY,
1254
- # ...
1255
- # ]
1256
- #
1257
- tradeList = self.safe_list(trade, 'result', [])
1258
- tradeLength = len(tradeList)
1259
- isPrivate = (tradeLength > 5)
1260
- id = self.safe_string(tradeList, 0)
1261
- amountIndex = 4 if isPrivate else 2
1262
- side = None
1263
- amountString = self.safe_string(tradeList, amountIndex)
1264
- priceIndex = 5 if isPrivate else 3
1265
- priceString = self.safe_string(tradeList, priceIndex)
1266
- if amountString[0] == '-':
1267
- side = 'sell'
1268
- amountString = Precise.string_abs(amountString)
1269
- else:
1270
- side = 'buy'
1271
- orderId = None
1272
- takerOrMaker = None
1273
- type = None
1274
- fee = None
1275
- symbol = self.safe_symbol(None, market)
1276
- timestampIndex = 2 if isPrivate else 1
1277
- timestamp = self.safe_integer(tradeList, timestampIndex)
1278
- if isPrivate:
1279
- marketId = tradeList[1]
1280
- symbol = self.safe_symbol(marketId)
1281
- orderId = self.safe_string(tradeList, 3)
1282
- maker = self.safe_integer(tradeList, 8)
1283
- takerOrMaker = 'maker' if (maker == 1) else 'taker'
1284
- feeCostString = self.safe_string(tradeList, 9)
1285
- feeCostString = Precise.string_neg(feeCostString)
1286
- feeCurrencyId = self.safe_string(tradeList, 10)
1287
- feeCurrency = self.safe_currency_code(feeCurrencyId)
1288
- fee = {
1289
- 'cost': feeCostString,
1290
- 'currency': feeCurrency,
1291
- }
1292
- orderType = tradeList[6]
1293
- type = self.safe_string(self.options['exchangeTypes'], orderType)
1294
- return self.safe_trade({
1295
- 'id': id,
1296
- 'timestamp': timestamp,
1297
- 'datetime': self.iso8601(timestamp),
1298
- 'symbol': symbol,
1299
- 'order': orderId,
1300
- 'side': side,
1301
- 'type': type,
1302
- 'takerOrMaker': takerOrMaker,
1303
- 'price': priceString,
1304
- 'amount': amountString,
1305
- 'cost': None,
1306
- 'fee': fee,
1307
- 'info': tradeList,
1308
- }, market)
1309
-
1310
- def fetch_trades(self, symbol: str, since: Int = None, limit: Int = None, params={}) -> List[Trade]:
1311
- """
1312
- get the list of most recent trades for a particular symbol
1313
-
1314
- https://docs.bitfinex.com/reference/rest-public-trades
1315
-
1316
- :param str symbol: unified symbol of the market to fetch trades for
1317
- :param int [since]: timestamp in ms of the earliest trade to fetch
1318
- :param int [limit]: the maximum amount of trades to fetch, default 120, max 10000
1319
- :param dict [params]: extra parameters specific to the exchange API endpoint
1320
- :param boolean [params.paginate]: default False, when True will automatically paginate by calling self endpoint multiple times. See in the docs all the [available parameters](https://github.com/ccxt/ccxt/wiki/Manual#pagination-params)
1321
- :param int [params.until]: the latest time in ms to fetch entries for
1322
- :returns Trade[]: a list of `trade structures <https://docs.ccxt.com/#/?id=public-trades>`
1323
- """
1324
- self.load_markets()
1325
- paginate = False
1326
- paginate, params = self.handle_option_and_params(params, 'fetchTrades', 'paginate')
1327
- if paginate:
1328
- return self.fetch_paginated_call_dynamic('fetchTrades', symbol, since, limit, params, 10000)
1329
- market = self.market(symbol)
1330
- sort = '-1'
1331
- request: dict = {
1332
- 'symbol': market['id'],
1333
- }
1334
- if since is not None:
1335
- request['start'] = since
1336
- sort = '1'
1337
- if limit is not None:
1338
- request['limit'] = min(limit, 10000) # default 120, max 10000
1339
- request['sort'] = sort
1340
- request, params = self.handle_until_option('end', request, params)
1341
- response = self.publicGetTradesSymbolHist(self.extend(request, params))
1342
- #
1343
- # [
1344
- # [
1345
- # ID,
1346
- # MTS, # timestamp
1347
- # AMOUNT,
1348
- # PRICE
1349
- # ]
1350
- # ]
1351
- #
1352
- trades = self.sort_by(response, 1)
1353
- tradesList = []
1354
- for i in range(0, len(trades)):
1355
- tradesList.append({'result': trades[i]}) # convert to array of dicts to match parseOrder signature
1356
- return self.parse_trades(tradesList, market, None, limit)
1357
-
1358
- def fetch_ohlcv(self, symbol: str, timeframe='1m', since: Int = None, limit: Int = 100, params={}) -> List[list]:
1359
- """
1360
- fetches historical candlestick data containing the open, high, low, and close price, and the volume of a market
1361
-
1362
- https://docs.bitfinex.com/reference/rest-public-candles
1363
-
1364
- :param str symbol: unified symbol of the market to fetch OHLCV data for
1365
- :param str timeframe: the length of time each candle represents
1366
- :param int [since]: timestamp in ms of the earliest candle to fetch
1367
- :param int [limit]: the maximum amount of candles to fetch, default 100 max 10000
1368
- :param dict [params]: extra parameters specific to the exchange API endpoint
1369
- :returns int[][]: A list of candles ordered, open, high, low, close, volume
1370
- :param int [params.until]: timestamp in ms of the latest candle to fetch
1371
- :param boolean [params.paginate]: default False, when True will automatically paginate by calling self endpoint multiple times. See in the docs all the [available parameters](https://github.com/ccxt/ccxt/wiki/Manual#pagination-params)
1372
- """
1373
- self.load_markets()
1374
- paginate = False
1375
- paginate, params = self.handle_option_and_params(params, 'fetchOHLCV', 'paginate')
1376
- if paginate:
1377
- return self.fetch_paginated_call_deterministic('fetchOHLCV', symbol, since, limit, timeframe, params, 10000)
1378
- market = self.market(symbol)
1379
- if limit is None:
1380
- limit = 10000
1381
- else:
1382
- limit = min(limit, 10000)
1383
- request: dict = {
1384
- 'symbol': market['id'],
1385
- 'timeframe': self.safe_string(self.timeframes, timeframe, timeframe),
1386
- 'sort': 1,
1387
- 'limit': limit,
1388
- }
1389
- if since is not None:
1390
- request['start'] = since
1391
- request, params = self.handle_until_option('end', request, params)
1392
- response = self.publicGetCandlesTradeTimeframeSymbolHist(self.extend(request, params))
1393
- #
1394
- # [
1395
- # [1591503840000,0.025069,0.025068,0.025069,0.025068,1.97828998],
1396
- # [1591504500000,0.025065,0.025065,0.025065,0.025065,1.0164],
1397
- # [1591504620000,0.025062,0.025062,0.025062,0.025062,0.5],
1398
- # ]
1399
- #
1400
- return self.parse_ohlcvs(response, market, timeframe, since, limit)
1401
-
1402
- def parse_ohlcv(self, ohlcv, market: Market = None) -> list:
1403
- #
1404
- # [
1405
- # 1457539800000,
1406
- # 0.02594,
1407
- # 0.02594,
1408
- # 0.02594,
1409
- # 0.02594,
1410
- # 0.1
1411
- # ]
1412
- #
1413
- return [
1414
- self.safe_integer(ohlcv, 0),
1415
- self.safe_number(ohlcv, 1),
1416
- self.safe_number(ohlcv, 3),
1417
- self.safe_number(ohlcv, 4),
1418
- self.safe_number(ohlcv, 2),
1419
- self.safe_number(ohlcv, 5),
1420
- ]
1421
-
1422
- def parse_order_status(self, status: Str):
1423
- if status is None:
1424
- return status
1425
- parts = status.split(' ')
1426
- state = self.safe_string(parts, 0)
1427
- statuses: dict = {
1428
- 'ACTIVE': 'open',
1429
- 'PARTIALLY': 'open',
1430
- 'EXECUTED': 'closed',
1431
- 'CANCELED': 'canceled',
1432
- 'INSUFFICIENT': 'canceled',
1433
- 'POSTONLY CANCELED': 'canceled',
1434
- 'RSN_DUST': 'rejected',
1435
- 'RSN_PAUSE': 'rejected',
1436
- 'IOC CANCELED': 'canceled',
1437
- 'FILLORKILL CANCELED': 'canceled',
1438
- }
1439
- return self.safe_string(statuses, state, status)
1440
-
1441
- def parse_order_flags(self, flags):
1442
- # flags can be added to each other...
1443
- flagValues: dict = {
1444
- '1024': ['reduceOnly'],
1445
- '4096': ['postOnly'],
1446
- '5120': ['reduceOnly', 'postOnly'],
1447
- # '64': 'hidden', # The hidden order option ensures an order does not appear in the order book
1448
- # '512': 'close', # Close position if position present.
1449
- # '16384': 'OCO', # The one cancels other order option allows you to place a pair of orders stipulating that if one order is executed fully or partially, then the other is automatically canceled.
1450
- # '524288': 'No Var Rates' # Excludes variable rate funding offers from matching against self order, if on margin
1451
- }
1452
- return self.safe_value(flagValues, flags, None)
1453
-
1454
- def parse_time_in_force(self, orderType):
1455
- orderTypes: dict = {
1456
- 'EXCHANGE IOC': 'IOC',
1457
- 'EXCHANGE FOK': 'FOK',
1458
- 'IOC': 'IOC', # Margin
1459
- 'FOK': 'FOK', # Margin
1460
- }
1461
- return self.safe_string(orderTypes, orderType, 'GTC')
1462
-
1463
- def parse_order(self, order: dict, market: Market = None) -> Order:
1464
- orderList = self.safe_list(order, 'result')
1465
- id = self.safe_string(orderList, 0)
1466
- marketId = self.safe_string(orderList, 3)
1467
- symbol = self.safe_symbol(marketId)
1468
- # https://github.com/ccxt/ccxt/issues/6686
1469
- # timestamp = self.safe_timestamp(orderObject, 5)
1470
- timestamp = self.safe_integer(orderList, 5)
1471
- remaining = Precise.string_abs(self.safe_string(orderList, 6))
1472
- signedAmount = self.safe_string(orderList, 7)
1473
- amount = Precise.string_abs(signedAmount)
1474
- side = 'sell' if Precise.string_lt(signedAmount, '0') else 'buy'
1475
- orderType = self.safe_string(orderList, 8)
1476
- type = self.safe_string(self.safe_value(self.options, 'exchangeTypes'), orderType)
1477
- timeInForce = self.parse_time_in_force(orderType)
1478
- rawFlags = self.safe_string(orderList, 12)
1479
- flags = self.parse_order_flags(rawFlags)
1480
- postOnly = False
1481
- if flags is not None:
1482
- for i in range(0, len(flags)):
1483
- if flags[i] == 'postOnly':
1484
- postOnly = True
1485
- price = self.safe_string(orderList, 16)
1486
- stopPrice = None
1487
- if (orderType == 'EXCHANGE STOP') or (orderType == 'EXCHANGE STOP LIMIT'):
1488
- price = None
1489
- stopPrice = self.safe_string(orderList, 16)
1490
- if orderType == 'EXCHANGE STOP LIMIT':
1491
- price = self.safe_string(orderList, 19)
1492
- status = None
1493
- statusString = self.safe_string(orderList, 13)
1494
- if statusString is not None:
1495
- parts = statusString.split(' @ ')
1496
- status = self.parse_order_status(self.safe_string(parts, 0))
1497
- average = self.safe_string(orderList, 17)
1498
- clientOrderId = self.safe_string(orderList, 2)
1499
- return self.safe_order({
1500
- 'info': orderList,
1501
- 'id': id,
1502
- 'clientOrderId': clientOrderId,
1503
- 'timestamp': timestamp,
1504
- 'datetime': self.iso8601(timestamp),
1505
- 'lastTradeTimestamp': None,
1506
- 'symbol': symbol,
1507
- 'type': type,
1508
- 'timeInForce': timeInForce,
1509
- 'postOnly': postOnly,
1510
- 'side': side,
1511
- 'price': price,
1512
- 'stopPrice': stopPrice,
1513
- 'triggerPrice': stopPrice,
1514
- 'amount': amount,
1515
- 'cost': None,
1516
- 'average': average,
1517
- 'filled': None,
1518
- 'remaining': remaining,
1519
- 'status': status,
1520
- 'fee': None,
1521
- 'trades': None,
1522
- }, market)
1523
-
1524
- def create_order_request(self, symbol: str, type: OrderType, side: OrderSide, amount: float, price: Num = None, params={}):
1525
- """
1526
- @ignore
1527
- helper function to build an order request
1528
- :param str symbol: unified symbol of the market to create an order in
1529
- :param str type: 'market' or 'limit'
1530
- :param str side: 'buy' or 'sell'
1531
- :param float amount: how much you want to trade in units of the base currency
1532
- :param float [price]: the price of the order, in units of the quote currency, ignored in market orders
1533
- :param dict [params]: extra parameters specific to the exchange API endpoint
1534
- :param float [params.stopPrice]: The price at which a trigger order is triggered at
1535
- :param str [params.timeInForce]: "GTC", "IOC", "FOK", or "PO"
1536
- :param bool [params.postOnly]:
1537
- :param bool [params.reduceOnly]: Ensures that the executed order does not flip the opened position.
1538
- :param int [params.flags]: additional order parameters: 4096(Post Only), 1024(Reduce Only), 16384(OCO), 64(Hidden), 512(Close), 524288(No Var Rates)
1539
- :param int [params.lev]: leverage for a derivative order, supported by derivative symbol orders only. The value should be between 1 and 100 inclusive.
1540
- :param str [params.price_traling]: The trailing price for a trailing stop order
1541
- :param str [params.price_aux_limit]: Order price for stop limit orders
1542
- :param str [params.price_oco_stop]: OCO stop price
1543
- :returns dict: an `order structure <https://github.com/ccxt/ccxt/wiki/Manual#order-structure>`
1544
- """
1545
- market = self.market(symbol)
1546
- amountString = self.amount_to_precision(symbol, amount)
1547
- amountString = amountString if (side == 'buy') else Precise.string_neg(amountString)
1548
- request: dict = {
1549
- 'symbol': market['id'],
1550
- 'amount': amountString,
1551
- }
1552
- stopPrice = self.safe_string_2(params, 'stopPrice', 'triggerPrice')
1553
- trailingAmount = self.safe_string(params, 'trailingAmount')
1554
- timeInForce = self.safe_string(params, 'timeInForce')
1555
- postOnlyParam = self.safe_bool(params, 'postOnly', False)
1556
- reduceOnly = self.safe_bool(params, 'reduceOnly', False)
1557
- clientOrderId = self.safe_value_2(params, 'cid', 'clientOrderId')
1558
- orderType = type.upper()
1559
- if trailingAmount is not None:
1560
- orderType = 'TRAILING STOP'
1561
- request['price_trailing'] = trailingAmount
1562
- elif stopPrice is not None:
1563
- # request['price'] is taken for stop orders
1564
- request['price'] = self.price_to_precision(symbol, stopPrice)
1565
- if type == 'limit':
1566
- orderType = 'STOP LIMIT'
1567
- request['price_aux_limit'] = self.price_to_precision(symbol, price)
1568
- else:
1569
- orderType = 'STOP'
1570
- ioc = (timeInForce == 'IOC')
1571
- fok = (timeInForce == 'FOK')
1572
- postOnly = (postOnlyParam or (timeInForce == 'PO'))
1573
- if (ioc or fok) and (price is None):
1574
- raise InvalidOrder(self.id + ' createOrder() requires a price argument with IOC and FOK orders')
1575
- if (ioc or fok) and (type == 'market'):
1576
- raise InvalidOrder(self.id + ' createOrder() does not allow market IOC and FOK orders')
1577
- if (type != 'market') and (stopPrice is None):
1578
- request['price'] = self.price_to_precision(symbol, price)
1579
- if ioc:
1580
- orderType = 'IOC'
1581
- elif fok:
1582
- orderType = 'FOK'
1583
- marginMode = None
1584
- marginMode, params = self.handle_margin_mode_and_params('createOrder', params)
1585
- if market['spot'] and (marginMode is None):
1586
- # The EXCHANGE prefix is only required for non margin spot markets
1587
- orderType = 'EXCHANGE ' + orderType
1588
- request['type'] = orderType
1589
- # flag values may be summed to combine flags
1590
- flags = 0
1591
- if postOnly:
1592
- flags = self.sum(flags, 4096)
1593
- if reduceOnly:
1594
- flags = self.sum(flags, 1024)
1595
- if flags != 0:
1596
- request['flags'] = flags
1597
- if clientOrderId is not None:
1598
- request['cid'] = clientOrderId
1599
- params = self.omit(params, ['triggerPrice', 'stopPrice', 'timeInForce', 'postOnly', 'reduceOnly', 'trailingAmount', 'clientOrderId'])
1600
- return self.extend(request, params)
1601
-
1602
- def create_order(self, symbol: str, type: OrderType, side: OrderSide, amount: float, price: Num = None, params={}):
1603
- """
1604
- create an order on the exchange
1605
-
1606
- https://docs.bitfinex.com/reference/rest-auth-submit-order
1607
-
1608
- :param str symbol: unified CCXT market symbol
1609
- :param str type: 'limit' or 'market'
1610
- :param str side: 'buy' or 'sell'
1611
- :param float amount: the amount of currency to trade
1612
- :param float [price]: price of the order
1613
- :param dict [params]: extra parameters specific to the exchange API endpoint
1614
- :param float [params.stopPrice]: the price that triggers a trigger order
1615
- :param str [params.timeInForce]: "GTC", "IOC", "FOK", or "PO"
1616
- :param boolean [params.postOnly]: set to True if you want to make a post only order
1617
- :param boolean [params.reduceOnly]: indicates that the order is to reduce the size of a position
1618
- :param int [params.flags]: additional order parameters: 4096(Post Only), 1024(Reduce Only), 16384(OCO), 64(Hidden), 512(Close), 524288(No Var Rates)
1619
- :param int [params.lev]: leverage for a derivative order, supported by derivative symbol orders only. The value should be between 1 and 100 inclusive.
1620
- :param str [params.price_aux_limit]: order price for stop limit orders
1621
- :param str [params.price_oco_stop]: OCO stop price
1622
- :param str [params.trailingAmount]: *swap only* the quote amount to trail away from the current market price
1623
- :returns dict: an `order structure <https://docs.ccxt.com/#/?id=order-structure>`
1624
- """
1625
- self.load_markets()
1626
- market = self.market(symbol)
1627
- request = self.create_order_request(symbol, type, side, amount, price, params)
1628
- response = self.privatePostAuthWOrderSubmit(request)
1629
- #
1630
- # [
1631
- # 1653325121, # Timestamp in milliseconds
1632
- # "on-req", # Purpose of notification('on-req', 'oc-req', "uca", 'fon-req', "foc-req")
1633
- # null, # unique ID of the message
1634
- # null,
1635
- # [
1636
- # [
1637
- # 95412102131, # Order ID
1638
- # null, # Group ID
1639
- # 1653325121798, # Client Order ID
1640
- # "tDOGE:UST", # Market ID
1641
- # 1653325121798, # Millisecond timestamp of creation
1642
- # 1653325121798, # Millisecond timestamp of update
1643
- # -10, # Amount(Positive means buy, negative means sell)
1644
- # -10, # Original amount
1645
- # "EXCHANGE LIMIT", # Type of the order: LIMIT, EXCHANGE LIMIT, MARKET, EXCHANGE MARKET, STOP, EXCHANGE STOP, STOP LIMIT, EXCHANGE STOP LIMIT, TRAILING STOP, EXCHANGE TRAILING STOP, FOK, EXCHANGE FOK, IOC, EXCHANGE IOC.
1646
- # null, # Previous order type(stop-limit orders are converted to limit orders so for them previous type is always STOP)
1647
- # null, # Millisecond timestamp of Time-In-Force: automatic order cancellation
1648
- # null, # _PLACEHOLDER
1649
- # 4096, # Flags, see parseOrderFlags()
1650
- # "ACTIVE", # Order Status, see parseOrderStatus()
1651
- # null, # _PLACEHOLDER
1652
- # null, # _PLACEHOLDER
1653
- # 0.071, # Price(Stop Price for stop-limit orders, Limit Price for limit orders)
1654
- # 0, # Average Price
1655
- # 0, # Trailing Price
1656
- # 0, # Auxiliary Limit price(for STOP LIMIT)
1657
- # null, # _PLACEHOLDER
1658
- # null, # _PLACEHOLDER
1659
- # null, # _PLACEHOLDER
1660
- # 0, # Hidden(0 if False, 1 if True)
1661
- # 0, # Placed ID(If another order caused self order to be placed(OCO) self will be that other order's ID)
1662
- # null, # _PLACEHOLDER
1663
- # null, # _PLACEHOLDER
1664
- # null, # _PLACEHOLDER
1665
- # "API>BFX", # Routing, indicates origin of action: BFX, ETHFX, API>BFX, API>ETHFX
1666
- # null, # _PLACEHOLDER
1667
- # null, # _PLACEHOLDER
1668
- # {"$F7":1} # additional meta information about the order( $F7 = IS_POST_ONLY(0 if False, 1 if True), $F33 = Leverage(int))
1669
- # ]
1670
- # ],
1671
- # null, # CODE(work in progress)
1672
- # "SUCCESS", # Status of the request
1673
- # "Submitting 1 orders." # Message
1674
- # ]
1675
- #
1676
- status = self.safe_string(response, 6)
1677
- if status != 'SUCCESS':
1678
- errorCode = response[5]
1679
- errorText = response[7]
1680
- raise ExchangeError(self.id + ' ' + response[6] + ': ' + errorText + '(#' + errorCode + ')')
1681
- orders = self.safe_list(response, 4, [])
1682
- order = self.safe_list(orders, 0)
1683
- newOrder = {'result': order}
1684
- return self.parse_order(newOrder, market)
1685
-
1686
- def create_orders(self, orders: List[OrderRequest], params={}):
1687
- """
1688
- create a list of trade orders
1689
-
1690
- https://docs.bitfinex.com/reference/rest-auth-order-multi
1691
-
1692
- :param Array orders: list of orders to create, each object should contain the parameters required by createOrder, namely symbol, type, side, amount, price and params
1693
- :param dict [params]: extra parameters specific to the exchange API endpoint
1694
- :returns dict: an `order structure <https://docs.ccxt.com/#/?id=order-structure>`
1695
- """
1696
- self.load_markets()
1697
- ordersRequests = []
1698
- for i in range(0, len(orders)):
1699
- rawOrder = orders[i]
1700
- symbol = self.safe_string(rawOrder, 'symbol')
1701
- type = self.safe_string(rawOrder, 'type')
1702
- side = self.safe_string(rawOrder, 'side')
1703
- amount = self.safe_number(rawOrder, 'amount')
1704
- price = self.safe_number(rawOrder, 'price')
1705
- orderParams = self.safe_dict(rawOrder, 'params', {})
1706
- orderRequest = self.create_order_request(symbol, type, side, amount, price, orderParams)
1707
- ordersRequests.append(['on', orderRequest])
1708
- request: dict = {
1709
- 'ops': ordersRequests,
1710
- }
1711
- response = self.privatePostAuthWOrderMulti(request)
1712
- #
1713
- # [
1714
- # 1706762515553,
1715
- # "ox_multi-req",
1716
- # null,
1717
- # null,
1718
- # [
1719
- # [
1720
- # 1706762515,
1721
- # "on-req",
1722
- # null,
1723
- # null,
1724
- # [
1725
- # [139567428547,null,1706762515551,"tBTCUST",1706762515551,1706762515551,0.0001,0.0001,"EXCHANGE LIMIT",null,null,null,0,"ACTIVE",null,null,35000,0,0,0,null,null,null,0,0,null,null,null,"API>BFX",null,null,{}]
1726
- # ],
1727
- # null,
1728
- # "SUCCESS",
1729
- # "Submitting 1 orders."
1730
- # ],
1731
- # ],
1732
- # null,
1733
- # "SUCCESS",
1734
- # "Submitting 2 order operations."
1735
- # ]
1736
- #
1737
- results = []
1738
- data = self.safe_list(response, 4, [])
1739
- for i in range(0, len(data)):
1740
- entry = data[i]
1741
- individualOrder = entry[4]
1742
- results.append({'result': individualOrder[0]})
1743
- return self.parse_orders(results)
1744
-
1745
- def cancel_all_orders(self, symbol: Str = None, params={}):
1746
- """
1747
- cancel all open orders
1748
-
1749
- https://docs.bitfinex.com/reference/rest-auth-cancel-orders-multiple
1750
-
1751
- :param str symbol: unified market symbol, only orders in the market of self symbol are cancelled when symbol is not None
1752
- :param dict [params]: extra parameters specific to the exchange API endpoint
1753
- :returns dict[]: a list of `order structures <https://docs.ccxt.com/#/?id=order-structure>`
1754
- """
1755
- self.load_markets()
1756
- request: dict = {
1757
- 'all': 1,
1758
- }
1759
- response = self.privatePostAuthWOrderCancelMulti(self.extend(request, params))
1760
- orders = self.safe_list(response, 4, [])
1761
- ordersList = []
1762
- for i in range(0, len(orders)):
1763
- ordersList.append({'result': orders[i]})
1764
- return self.parse_orders(ordersList)
1765
-
1766
- def cancel_order(self, id: str, symbol: Str = None, params={}):
1767
- """
1768
- cancels an open order
1769
-
1770
- https://docs.bitfinex.com/reference/rest-auth-cancel-order
1771
-
1772
- :param str id: order id
1773
- :param str symbol: Not used by bitfinex2 cancelOrder()
1774
- :param dict [params]: extra parameters specific to the exchange API endpoint
1775
- :returns dict: An `order structure <https://docs.ccxt.com/#/?id=order-structure>`
1776
- """
1777
- self.load_markets()
1778
- cid = self.safe_value_2(params, 'cid', 'clientOrderId') # client order id
1779
- request = None
1780
- market = None
1781
- if symbol is not None:
1782
- market = self.market(symbol)
1783
- if cid is not None:
1784
- cidDate = self.safe_value(params, 'cidDate') # client order id date
1785
- if cidDate is None:
1786
- raise InvalidOrder(self.id + " canceling an order by clientOrderId('cid') requires both 'cid' and 'cid_date'('YYYY-MM-DD')")
1787
- request = {
1788
- 'cid': cid,
1789
- 'cid_date': cidDate,
1790
- }
1791
- params = self.omit(params, ['cid', 'clientOrderId'])
1792
- else:
1793
- request = {
1794
- 'id': int(id),
1795
- }
1796
- response = self.privatePostAuthWOrderCancel(self.extend(request, params))
1797
- order = self.safe_value(response, 4)
1798
- newOrder = {'result': order}
1799
- return self.parse_order(newOrder, market)
1800
-
1801
- def cancel_orders(self, ids, symbol: Str = None, params={}):
1802
- """
1803
- cancel multiple orders at the same time
1804
-
1805
- https://docs.bitfinex.com/reference/rest-auth-cancel-orders-multiple
1806
-
1807
- :param str[] ids: order ids
1808
- :param str symbol: unified market symbol, default is None
1809
- :param dict [params]: extra parameters specific to the exchange API endpoint
1810
- :returns dict: an array of `order structures <https://docs.ccxt.com/#/?id=order-structure>`
1811
- """
1812
- self.load_markets()
1813
- for i in range(0, len(ids)):
1814
- ids[i] = self.parse_to_numeric(ids[i])
1815
- request: dict = {
1816
- 'id': ids,
1817
- }
1818
- market = None
1819
- if symbol is not None:
1820
- market = self.market(symbol)
1821
- response = self.privatePostAuthWOrderCancelMulti(self.extend(request, params))
1822
- #
1823
- # [
1824
- # 1706740198811,
1825
- # "oc_multi-req",
1826
- # null,
1827
- # null,
1828
- # [
1829
- # [
1830
- # 139530205057,
1831
- # null,
1832
- # 1706740132275,
1833
- # "tBTCF0:USTF0",
1834
- # 1706740132276,
1835
- # 1706740132276,
1836
- # 0.0001,
1837
- # 0.0001,
1838
- # "LIMIT",
1839
- # null,
1840
- # null,
1841
- # null,
1842
- # 0,
1843
- # "ACTIVE",
1844
- # null,
1845
- # null,
1846
- # 39000,
1847
- # 0,
1848
- # 0,
1849
- # 0,
1850
- # null,
1851
- # null,
1852
- # null,
1853
- # 0,
1854
- # 0,
1855
- # null,
1856
- # null,
1857
- # null,
1858
- # "API>BFX",
1859
- # null,
1860
- # null,
1861
- # {
1862
- # "lev": 10,
1863
- # "$F33": 10
1864
- # }
1865
- # ],
1866
- # ],
1867
- # null,
1868
- # "SUCCESS",
1869
- # "Submitting 2 order cancellations."
1870
- # ]
1871
- #
1872
- orders = self.safe_list(response, 4, [])
1873
- ordersList = []
1874
- for i in range(0, len(orders)):
1875
- ordersList.append({'result': orders[i]})
1876
- return self.parse_orders(ordersList, market)
1877
-
1878
- def fetch_open_order(self, id: str, symbol: Str = None, params={}):
1879
- """
1880
- fetch an open order by it's id
1881
-
1882
- https://docs.bitfinex.com/reference/rest-auth-retrieve-orders
1883
- https://docs.bitfinex.com/reference/rest-auth-retrieve-orders-by-symbol
1884
-
1885
- :param str id: order id
1886
- :param str symbol: unified market symbol, default is None
1887
- :param dict [params]: extra parameters specific to the exchange API endpoint
1888
- :returns dict: an `order structure <https://docs.ccxt.com/#/?id=order-structure>`
1889
- """
1890
- request: dict = {
1891
- 'id': [int(id)],
1892
- }
1893
- orders = self.fetch_open_orders(symbol, None, None, self.extend(request, params))
1894
- order = self.safe_value(orders, 0)
1895
- if order is None:
1896
- raise OrderNotFound(self.id + ' order ' + id + ' not found')
1897
- return order
1898
-
1899
- def fetch_closed_order(self, id: str, symbol: Str = None, params={}):
1900
- """
1901
- fetch an open order by it's id
1902
-
1903
- https://docs.bitfinex.com/reference/rest-auth-retrieve-orders
1904
- https://docs.bitfinex.com/reference/rest-auth-retrieve-orders-by-symbol
1905
-
1906
- :param str id: order id
1907
- :param str symbol: unified market symbol, default is None
1908
- :param dict [params]: extra parameters specific to the exchange API endpoint
1909
- :returns dict: an `order structure <https://docs.ccxt.com/#/?id=order-structure>`
1910
- """
1911
- request: dict = {
1912
- 'id': [int(id)],
1913
- }
1914
- orders = self.fetch_closed_orders(symbol, None, None, self.extend(request, params))
1915
- order = self.safe_value(orders, 0)
1916
- if order is None:
1917
- raise OrderNotFound(self.id + ' order ' + id + ' not found')
1918
- return order
1919
-
1920
- def fetch_open_orders(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}) -> List[Order]:
1921
- """
1922
- fetch all unfilled currently open orders
1923
-
1924
- https://docs.bitfinex.com/reference/rest-auth-retrieve-orders
1925
- https://docs.bitfinex.com/reference/rest-auth-retrieve-orders-by-symbol
1926
-
1927
- :param str symbol: unified market symbol
1928
- :param int [since]: the earliest time in ms to fetch open orders for
1929
- :param int [limit]: the maximum number of open orders structures to retrieve
1930
- :param dict [params]: extra parameters specific to the exchange API endpoint
1931
- :returns Order[]: a list of `order structures <https://docs.ccxt.com/#/?id=order-structure>`
1932
- """
1933
- self.load_markets()
1934
- request: dict = {}
1935
- market = None
1936
- response = None
1937
- if symbol is None:
1938
- response = self.privatePostAuthROrders(self.extend(request, params))
1939
- else:
1940
- market = self.market(symbol)
1941
- request['symbol'] = market['id']
1942
- response = self.privatePostAuthROrdersSymbol(self.extend(request, params))
1943
- #
1944
- # [
1945
- # [
1946
- # 95408916206, # Order ID
1947
- # null, # Group Order ID
1948
- # 1653322349926, # Client Order ID
1949
- # "tDOGE:UST", # Market ID
1950
- # 1653322349926, # Created Timestamp in milliseconds
1951
- # 1653322349927, # Updated Timestamp in milliseconds
1952
- # -10, # Amount remaining(Positive means buy, negative means sell)
1953
- # -10, # Original amount
1954
- # "EXCHANGE LIMIT", # Order type
1955
- # null, # Previous Order Type
1956
- # null, # _PLACEHOLDER
1957
- # null, # _PLACEHOLDER
1958
- # 0, # Flags, see parseOrderFlags()
1959
- # "ACTIVE", # Order Status, see parseOrderStatus()
1960
- # null, # _PLACEHOLDER
1961
- # null, # _PLACEHOLDER
1962
- # 0.11, # Price
1963
- # 0, # Average Price
1964
- # 0, # Trailing Price
1965
- # 0, # Auxiliary Limit price(for STOP LIMIT)
1966
- # null, # _PLACEHOLDER
1967
- # null, # _PLACEHOLDER
1968
- # null, # _PLACEHOLDER
1969
- # 0, # Hidden(0 if False, 1 if True)
1970
- # 0, # Placed ID(If another order caused self order to be placed(OCO) self will be that other order's ID)
1971
- # null, # _PLACEHOLDER
1972
- # null, # _PLACEHOLDER
1973
- # null, # _PLACEHOLDER
1974
- # "API>BFX", # Routing, indicates origin of action: BFX, ETHFX, API>BFX, API>ETHFX
1975
- # null, # _PLACEHOLDER
1976
- # null, # _PLACEHOLDER
1977
- # {"$F7":1} # additional meta information about the order( $F7 = IS_POST_ONLY(0 if False, 1 if True), $F33 = Leverage(int))
1978
- # ],
1979
- # ]
1980
- #
1981
- ordersList = []
1982
- for i in range(0, len(response)):
1983
- ordersList.append({'result': response[i]})
1984
- return self.parse_orders(ordersList, market, since, limit)
1985
-
1986
- def fetch_closed_orders(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}) -> List[Order]:
1987
- """
1988
- fetches information on multiple closed orders made by the user
1989
-
1990
- https://docs.bitfinex.com/reference/rest-auth-retrieve-orders
1991
- https://docs.bitfinex.com/reference/rest-auth-retrieve-orders-by-symbol
1992
-
1993
- :param str symbol: unified market symbol of the market orders were made in
1994
- :param int [since]: the earliest time in ms to fetch orders for
1995
- :param int [limit]: the maximum number of order structures to retrieve
1996
- :param dict [params]: extra parameters specific to the exchange API endpoint
1997
- :param int [params.until]: the latest time in ms to fetch entries for
1998
- :param boolean [params.paginate]: default False, when True will automatically paginate by calling self endpoint multiple times. See in the docs all the [availble parameters](https://github.com/ccxt/ccxt/wiki/Manual#pagination-params)
1999
- :returns Order[]: a list of `order structures <https://docs.ccxt.com/#/?id=order-structure>`
2000
- """
2001
- # returns the most recent closed or canceled orders up to circa two weeks ago
2002
- self.load_markets()
2003
- paginate = False
2004
- paginate, params = self.handle_option_and_params(params, 'fetchClosedOrders', 'paginate')
2005
- if paginate:
2006
- return self.fetch_paginated_call_dynamic('fetchClosedOrders', symbol, since, limit, params)
2007
- request: dict = {}
2008
- if since is not None:
2009
- request['start'] = since
2010
- if limit is not None:
2011
- request['limit'] = limit # default 25, max 2500
2012
- request, params = self.handle_until_option('end', request, params)
2013
- market = None
2014
- response = None
2015
- if symbol is None:
2016
- response = self.privatePostAuthROrdersHist(self.extend(request, params))
2017
- else:
2018
- market = self.market(symbol)
2019
- request['symbol'] = market['id']
2020
- response = self.privatePostAuthROrdersSymbolHist(self.extend(request, params))
2021
- #
2022
- # [
2023
- # [
2024
- # 95412102131, # Order ID
2025
- # null, # Group Order ID
2026
- # 1653325121798, # Client Order ID
2027
- # "tDOGE:UST", # Market ID
2028
- # 1653325122000, # Created Timestamp in milliseconds
2029
- # 1653325122000, # Updated Timestamp in milliseconds
2030
- # -10, # Amount remaining(Positive means buy, negative means sell)
2031
- # -10, # Original amount
2032
- # "EXCHANGE LIMIT", # Order type
2033
- # null, # Previous Order Type
2034
- # null, # Millisecond timestamp of Time-In-Force: automatic order cancellation
2035
- # null, # _PLACEHOLDER
2036
- # "4096", # Flags, see parseOrderFlags()
2037
- # "POSTONLY CANCELED", # Order Status, see parseOrderStatus()
2038
- # null, # _PLACEHOLDER
2039
- # null, # _PLACEHOLDER
2040
- # 0.071, # Price
2041
- # 0, # Average Price
2042
- # 0, # Trailing Price
2043
- # 0, # Auxiliary Limit price(for STOP LIMIT)
2044
- # null, # _PLACEHOLDER
2045
- # null, # _PLACEHOLDER
2046
- # null, # _PLACEHOLDER
2047
- # 0, # Notify(0 if False, 1 if True)
2048
- # 0, # Hidden(0 if False, 1 if True)
2049
- # null, # Placed ID(If another order caused self order to be placed(OCO) self will be that other order's ID)
2050
- # null, # _PLACEHOLDER
2051
- # null, # _PLACEHOLDER
2052
- # "API>BFX", # Routing, indicates origin of action: BFX, ETHFX, API>BFX, API>ETHFX
2053
- # null, # _PLACEHOLDER
2054
- # null, # _PLACEHOLDER
2055
- # {"_$F7":1} # additional meta information about the order( _$F7 = IS_POST_ONLY(0 if False, 1 if True), _$F33 = Leverage(int))
2056
- # ]
2057
- # ]
2058
- #
2059
- ordersList = []
2060
- for i in range(0, len(response)):
2061
- ordersList.append({'result': response[i]})
2062
- return self.parse_orders(ordersList, market, since, limit)
2063
-
2064
- def fetch_order_trades(self, id: str, symbol: Str = None, since: Int = None, limit: Int = None, params={}):
2065
- """
2066
- fetch all the trades made from a single order
2067
-
2068
- https://docs.bitfinex.com/reference/rest-auth-order-trades
2069
-
2070
- :param str id: order id
2071
- :param str symbol: unified market symbol
2072
- :param int [since]: the earliest time in ms to fetch trades for
2073
- :param int [limit]: the maximum number of trades to retrieve
2074
- :param dict [params]: extra parameters specific to the exchange API endpoint
2075
- :returns dict[]: a list of `trade structures <https://docs.ccxt.com/#/?id=trade-structure>`
2076
- """
2077
- if symbol is None:
2078
- raise ArgumentsRequired(self.id + ' fetchOrderTrades() requires a symbol argument')
2079
- self.load_markets()
2080
- market = self.market(symbol)
2081
- orderId = int(id)
2082
- request: dict = {
2083
- 'id': orderId,
2084
- 'symbol': market['id'],
2085
- }
2086
- # valid for trades upto 10 days old
2087
- response = self.privatePostAuthROrderSymbolIdTrades(self.extend(request, params))
2088
- tradesList = []
2089
- for i in range(0, len(response)):
2090
- tradesList.append({'result': response[i]}) # convert to array of dicts to match parseOrder signature
2091
- return self.parse_trades(tradesList, market, since, limit)
2092
-
2093
- def fetch_my_trades(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}):
2094
- """
2095
- fetch all trades made by the user
2096
-
2097
- https://docs.bitfinex.com/reference/rest-auth-trades
2098
- https://docs.bitfinex.com/reference/rest-auth-trades-by-symbol
2099
-
2100
- :param str symbol: unified market symbol
2101
- :param int [since]: the earliest time in ms to fetch trades for
2102
- :param int [limit]: the maximum number of trades structures to retrieve
2103
- :param dict [params]: extra parameters specific to the exchange API endpoint
2104
- :returns Trade[]: a list of `trade structures <https://docs.ccxt.com/#/?id=trade-structure>`
2105
- """
2106
- self.load_markets()
2107
- market = None
2108
- request: dict = {
2109
- 'end': self.milliseconds(),
2110
- }
2111
- if since is not None:
2112
- request['start'] = since
2113
- if limit is not None:
2114
- request['limit'] = limit # default 25, max 1000
2115
- response = None
2116
- if symbol is not None:
2117
- market = self.market(symbol)
2118
- request['symbol'] = market['id']
2119
- response = self.privatePostAuthRTradesSymbolHist(self.extend(request, params))
2120
- else:
2121
- response = self.privatePostAuthRTradesHist(self.extend(request, params))
2122
- tradesList = []
2123
- for i in range(0, len(response)):
2124
- tradesList.append({'result': response[i]}) # convert to array of dicts to match parseOrder signature
2125
- return self.parse_trades(tradesList, market, since, limit)
2126
-
2127
- def create_deposit_address(self, code: str, params={}):
2128
- """
2129
- create a currency deposit address
2130
-
2131
- https://docs.bitfinex.com/reference/rest-auth-deposit-address
2132
-
2133
- :param str code: unified currency code of the currency for the deposit address
2134
- :param dict [params]: extra parameters specific to the exchange API endpoint
2135
- :returns dict: an `address structure <https://docs.ccxt.com/#/?id=address-structure>`
2136
- """
2137
- self.load_markets()
2138
- request: dict = {
2139
- 'op_renew': 1,
2140
- }
2141
- return self.fetch_deposit_address(code, self.extend(request, params))
2142
-
2143
- def fetch_deposit_address(self, code: str, params={}) -> DepositAddress:
2144
- """
2145
- fetch the deposit address for a currency associated with self account
2146
-
2147
- https://docs.bitfinex.com/reference/rest-auth-deposit-address
2148
-
2149
- :param str code: unified currency code
2150
- :param dict [params]: extra parameters specific to the exchange API endpoint
2151
- :returns dict: an `address structure <https://docs.ccxt.com/#/?id=address-structure>`
2152
- """
2153
- self.load_markets()
2154
- currency = self.currency(code)
2155
- # if not provided explicitly we will try to match using the currency name
2156
- network = self.safe_string(params, 'network', code)
2157
- currencyNetworks = self.safe_value(currency, 'networks', {})
2158
- currencyNetwork = self.safe_value(currencyNetworks, network)
2159
- networkId = self.safe_string(currencyNetwork, 'id')
2160
- if networkId is None:
2161
- raise ArgumentsRequired(self.id + " fetchDepositAddress() could not find a network for '" + code + "'. You can specify it by providing the 'network' value inside params")
2162
- wallet = self.safe_string(params, 'wallet', 'exchange') # 'exchange', 'margin', 'funding' and also old labels 'exchange', 'trading', 'deposit', respectively
2163
- params = self.omit(params, 'network', 'wallet')
2164
- request: dict = {
2165
- 'method': networkId,
2166
- 'wallet': wallet,
2167
- 'op_renew': 0, # a value of 1 will generate a new address
2168
- }
2169
- response = self.privatePostAuthWDepositAddress(self.extend(request, params))
2170
- #
2171
- # [
2172
- # 1582269616687, # MTS Millisecond Time Stamp of the update
2173
- # "acc_dep", # TYPE Purpose of notification "acc_dep" for account deposit
2174
- # null, # MESSAGE_ID unique ID of the message
2175
- # null, # not documented
2176
- # [
2177
- # null, # PLACEHOLDER
2178
- # "BITCOIN", # METHOD Method of deposit
2179
- # "BTC", # CURRENCY_CODE Currency code of new address
2180
- # null, # PLACEHOLDER
2181
- # "1BC9PZqpUmjyEB54uggn8TFKj49zSDYzqG", # ADDRESS
2182
- # null, # POOL_ADDRESS
2183
- # ],
2184
- # null, # CODE null or integer work in progress
2185
- # "SUCCESS", # STATUS Status of the notification, SUCCESS, ERROR, FAILURE
2186
- # "success", # TEXT Text of the notification
2187
- # ]
2188
- #
2189
- result = self.safe_value(response, 4, [])
2190
- poolAddress = self.safe_string(result, 5)
2191
- address = self.safe_string(result, 4) if (poolAddress is None) else poolAddress
2192
- tag = None if (poolAddress is None) else self.safe_string(result, 4)
2193
- self.check_address(address)
2194
- return {
2195
- 'currency': code,
2196
- 'address': address,
2197
- 'tag': tag,
2198
- 'network': None,
2199
- 'info': response,
2200
- }
2201
-
2202
- def parse_transaction_status(self, status: Str):
2203
- statuses: dict = {
2204
- 'SUCCESS': 'ok',
2205
- 'COMPLETED': 'ok',
2206
- 'ERROR': 'failed',
2207
- 'FAILURE': 'failed',
2208
- 'CANCELED': 'canceled',
2209
- 'PENDING APPROVAL': 'pending',
2210
- 'PENDING': 'pending',
2211
- 'PENDING REVIEW': 'pending',
2212
- 'PENDING CANCELLATION': 'pending',
2213
- 'SENDING': 'pending',
2214
- 'USER APPROVED': 'pending',
2215
- }
2216
- return self.safe_string(statuses, status, status)
2217
-
2218
- def parse_transaction(self, transaction: dict, currency: Currency = None) -> Transaction:
2219
- #
2220
- # withdraw
2221
- #
2222
- # [
2223
- # 1582271520931, # MTS Millisecond Time Stamp of the update
2224
- # "acc_wd-req", # TYPE Purpose of notification "acc_wd-req" account withdrawal request
2225
- # null, # MESSAGE_ID unique ID of the message
2226
- # null, # not documented
2227
- # [
2228
- # 0, # WITHDRAWAL_ID Unique Withdrawal ID
2229
- # null, # PLACEHOLDER
2230
- # "bitcoin", # METHOD Method of withdrawal
2231
- # null, # PAYMENT_ID Payment ID if relevant
2232
- # "exchange", # WALLET Sending wallet
2233
- # 1, # AMOUNT Amount of Withdrawal less fee
2234
- # null, # PLACEHOLDER
2235
- # null, # PLACEHOLDER
2236
- # 0.0004, # WITHDRAWAL_FEE Fee on withdrawal
2237
- # ],
2238
- # null, # CODE null or integer Work in progress
2239
- # "SUCCESS", # STATUS Status of the notification, it may vary over time SUCCESS, ERROR, FAILURE
2240
- # "Invalid bitcoin address(abcdef)", # TEXT Text of the notification
2241
- # ]
2242
- #
2243
- # fetchDepositsWithdrawals
2244
- #
2245
- # [
2246
- # 13293039, # ID
2247
- # "ETH", # CURRENCY
2248
- # "ETHEREUM", # CURRENCY_NAME
2249
- # null,
2250
- # null,
2251
- # 1574175052000, # MTS_STARTED
2252
- # 1574181326000, # MTS_UPDATED
2253
- # null,
2254
- # null,
2255
- # "CANCELED", # STATUS
2256
- # null,
2257
- # null,
2258
- # -0.24, # AMOUNT, negative for withdrawals
2259
- # -0.00135, # FEES
2260
- # null,
2261
- # null,
2262
- # "0x38110e0Fc932CB2BE...........", # DESTINATION_ADDRESS
2263
- # null,
2264
- # null,
2265
- # null,
2266
- # "0x523ec8945500.....................................", # TRANSACTION_ID
2267
- # "Purchase of 100 pizzas", # WITHDRAW_TRANSACTION_NOTE, might also be: null
2268
- # ]
2269
- #
2270
- transactionLength = len(transaction)
2271
- timestamp = None
2272
- updated = None
2273
- code = None
2274
- amount = None
2275
- id = None
2276
- status = None
2277
- tag = None
2278
- type = None
2279
- feeCost = None
2280
- txid = None
2281
- addressTo = None
2282
- network = None
2283
- comment = None
2284
- if transactionLength == 8:
2285
- data = self.safe_value(transaction, 4, [])
2286
- timestamp = self.safe_integer(transaction, 0)
2287
- if currency is not None:
2288
- code = currency['code']
2289
- feeCost = self.safe_string(data, 8)
2290
- if feeCost is not None:
2291
- feeCost = Precise.string_abs(feeCost)
2292
- amount = self.safe_number(data, 5)
2293
- id = self.safe_integer(data, 0)
2294
- status = 'ok'
2295
- if id == 0:
2296
- id = None
2297
- status = 'failed'
2298
- tag = self.safe_string(data, 3)
2299
- type = 'withdrawal'
2300
- networkId = self.safe_string(data, 2)
2301
- network = self.network_id_to_code(networkId.upper()) # withdraw returns in lowercase
2302
- elif transactionLength == 22:
2303
- id = self.safe_string(transaction, 0)
2304
- currencyId = self.safe_string(transaction, 1)
2305
- code = self.safe_currency_code(currencyId, currency)
2306
- networkId = self.safe_string(transaction, 2)
2307
- network = self.network_id_to_code(networkId)
2308
- timestamp = self.safe_integer(transaction, 5)
2309
- updated = self.safe_integer(transaction, 6)
2310
- status = self.parse_transaction_status(self.safe_string(transaction, 9))
2311
- signedAmount = self.safe_string(transaction, 12)
2312
- amount = Precise.string_abs(signedAmount)
2313
- if signedAmount is not None:
2314
- if Precise.string_lt(signedAmount, '0'):
2315
- type = 'withdrawal'
2316
- else:
2317
- type = 'deposit'
2318
- feeCost = self.safe_string(transaction, 13)
2319
- if feeCost is not None:
2320
- feeCost = Precise.string_abs(feeCost)
2321
- addressTo = self.safe_string(transaction, 16)
2322
- txid = self.safe_string(transaction, 20)
2323
- comment = self.safe_string(transaction, 21)
2324
- return {
2325
- 'info': transaction,
2326
- 'id': id,
2327
- 'txid': txid,
2328
- 'type': type,
2329
- 'currency': code,
2330
- 'network': network,
2331
- 'amount': self.parse_number(amount),
2332
- 'status': status,
2333
- 'timestamp': timestamp,
2334
- 'datetime': self.iso8601(timestamp),
2335
- 'address': addressTo, # self is actually the tag for XRP transfers(the address is missing)
2336
- 'addressFrom': None,
2337
- 'addressTo': addressTo,
2338
- 'tag': tag, # refix it properly for the tag from description
2339
- 'tagFrom': None,
2340
- 'tagTo': tag,
2341
- 'updated': updated,
2342
- 'comment': comment,
2343
- 'internal': None,
2344
- 'fee': {
2345
- 'currency': code,
2346
- 'cost': self.parse_number(feeCost),
2347
- 'rate': None,
2348
- },
2349
- }
2350
-
2351
- def fetch_trading_fees(self, params={}) -> TradingFees:
2352
- """
2353
- fetch the trading fees for multiple markets
2354
-
2355
- https://docs.bitfinex.com/reference/rest-auth-summary
2356
-
2357
- :param dict [params]: extra parameters specific to the exchange API endpoint
2358
- :returns dict: a dictionary of `fee structures <https://docs.ccxt.com/#/?id=fee-structure>` indexed by market symbols
2359
- """
2360
- self.load_markets()
2361
- response = self.privatePostAuthRSummary(params)
2362
- #
2363
- # Response Spec:
2364
- # [
2365
- # PLACEHOLDER,
2366
- # PLACEHOLDER,
2367
- # PLACEHOLDER,
2368
- # PLACEHOLDER,
2369
- # [
2370
- # [
2371
- # MAKER_FEE,
2372
- # MAKER_FEE,
2373
- # MAKER_FEE,
2374
- # PLACEHOLDER,
2375
- # PLACEHOLDER,
2376
- # DERIV_REBATE
2377
- # ],
2378
- # [
2379
- # TAKER_FEE_TO_CRYPTO,
2380
- # TAKER_FEE_TO_STABLE,
2381
- # TAKER_FEE_TO_FIAT,
2382
- # PLACEHOLDER,
2383
- # PLACEHOLDER,
2384
- # DERIV_TAKER_FEE
2385
- # ]
2386
- # ],
2387
- # PLACEHOLDER,
2388
- # PLACEHOLDER,
2389
- # PLACEHOLDER,
2390
- # PLACEHOLDER,
2391
- # {
2392
- # LEO_LEV,
2393
- # LEO_AMOUNT_AVG
2394
- # }
2395
- # ]
2396
- #
2397
- # Example response:
2398
- #
2399
- # [
2400
- # null,
2401
- # null,
2402
- # null,
2403
- # null,
2404
- # [
2405
- # [0.001, 0.001, 0.001, null, null, 0.0002],
2406
- # [0.002, 0.002, 0.002, null, null, 0.00065]
2407
- # ],
2408
- # [
2409
- # [
2410
- # {
2411
- # "curr": "Total(USD)",
2412
- # "vol": "0",
2413
- # "vol_safe": "0",
2414
- # "vol_maker": "0",
2415
- # "vol_BFX": "0",
2416
- # "vol_BFX_safe": "0",
2417
- # "vol_BFX_maker": "0"
2418
- # }
2419
- # ],
2420
- # {},
2421
- # 0
2422
- # ],
2423
- # [null, {}, 0],
2424
- # null,
2425
- # null,
2426
- # {leo_lev: "0", leo_amount_avg: "0"}
2427
- # ]
2428
- #
2429
- result: dict = {}
2430
- fiat = self.safe_value(self.options, 'fiat', {})
2431
- feeData = self.safe_value(response, 4, [])
2432
- makerData = self.safe_value(feeData, 0, [])
2433
- takerData = self.safe_value(feeData, 1, [])
2434
- makerFee = self.safe_number(makerData, 0)
2435
- makerFeeFiat = self.safe_number(makerData, 2)
2436
- makerFeeDeriv = self.safe_number(makerData, 5)
2437
- takerFee = self.safe_number(takerData, 0)
2438
- takerFeeFiat = self.safe_number(takerData, 2)
2439
- takerFeeDeriv = self.safe_number(takerData, 5)
2440
- for i in range(0, len(self.symbols)):
2441
- symbol = self.symbols[i]
2442
- market = self.market(symbol)
2443
- fee = {
2444
- 'info': response,
2445
- 'symbol': symbol,
2446
- 'percentage': True,
2447
- 'tierBased': True,
2448
- }
2449
- if market['quote'] in fiat:
2450
- fee['maker'] = makerFeeFiat
2451
- fee['taker'] = takerFeeFiat
2452
- elif market['contract']:
2453
- fee['maker'] = makerFeeDeriv
2454
- fee['taker'] = takerFeeDeriv
2455
- else: # TODO check if stable coin
2456
- fee['maker'] = makerFee
2457
- fee['taker'] = takerFee
2458
- result[symbol] = fee
2459
- return result
2460
-
2461
- def fetch_deposits_withdrawals(self, code: Str = None, since: Int = None, limit: Int = None, params={}) -> List[Transaction]:
2462
- """
2463
- fetch history of deposits and withdrawals
2464
-
2465
- https://docs.bitfinex.com/reference/movement-info
2466
- https://docs.bitfinex.com/reference/rest-auth-movements
2467
-
2468
- :param str [code]: unified currency code for the currency of the deposit/withdrawals, default is None
2469
- :param int [since]: timestamp in ms of the earliest deposit/withdrawal, default is None
2470
- :param int [limit]: max number of deposit/withdrawals to return, default is None
2471
- :param dict [params]: extra parameters specific to the exchange API endpoint
2472
- :returns dict: a list of `transaction structure <https://docs.ccxt.com/#/?id=transaction-structure>`
2473
- """
2474
- self.load_markets()
2475
- currency = None
2476
- request: dict = {}
2477
- if since is not None:
2478
- request['start'] = since
2479
- if limit is not None:
2480
- request['limit'] = limit # max 1000
2481
- response = None
2482
- if code is not None:
2483
- currency = self.currency(code)
2484
- request['currency'] = currency['uppercaseId']
2485
- response = self.privatePostAuthRMovementsCurrencyHist(self.extend(request, params))
2486
- else:
2487
- response = self.privatePostAuthRMovementsHist(self.extend(request, params))
2488
- #
2489
- # [
2490
- # [
2491
- # 13293039, # ID
2492
- # "ETH", # CURRENCY
2493
- # "ETHEREUM", # CURRENCY_NAME
2494
- # null,
2495
- # null,
2496
- # 1574175052000, # MTS_STARTED
2497
- # 1574181326000, # MTS_UPDATED
2498
- # null,
2499
- # null,
2500
- # "CANCELED", # STATUS
2501
- # null,
2502
- # null,
2503
- # -0.24, # AMOUNT, negative for withdrawals
2504
- # -0.00135, # FEES
2505
- # null,
2506
- # null,
2507
- # "0x38110e0Fc932CB2BE...........", # DESTINATION_ADDRESS
2508
- # null,
2509
- # null,
2510
- # null,
2511
- # "0x523ec8945500.....................................", # TRANSACTION_ID
2512
- # "Purchase of 100 pizzas", # WITHDRAW_TRANSACTION_NOTE, might also be: null
2513
- # ]
2514
- # ]
2515
- #
2516
- return self.parse_transactions(response, currency, since, limit)
2517
-
2518
- def withdraw(self, code: str, amount: float, address: str, tag=None, params={}) -> Transaction:
2519
- """
2520
- make a withdrawal
2521
-
2522
- https://docs.bitfinex.com/reference/rest-auth-withdraw
2523
-
2524
- :param str code: unified currency code
2525
- :param float amount: the amount to withdraw
2526
- :param str address: the address to withdraw to
2527
- :param str tag:
2528
- :param dict [params]: extra parameters specific to the exchange API endpoint
2529
- :returns dict: a `transaction structure <https://docs.ccxt.com/#/?id=transaction-structure>`
2530
- """
2531
- self.check_address(address)
2532
- self.load_markets()
2533
- currency = self.currency(code)
2534
- # if not provided explicitly we will try to match using the currency name
2535
- network = self.safe_string(params, 'network', code)
2536
- params = self.omit(params, 'network')
2537
- currencyNetworks = self.safe_value(currency, 'networks', {})
2538
- currencyNetwork = self.safe_value(currencyNetworks, network)
2539
- networkId = self.safe_string(currencyNetwork, 'id')
2540
- if networkId is None:
2541
- raise ArgumentsRequired(self.id + " withdraw() could not find a network for '" + code + "'. You can specify it by providing the 'network' value inside params")
2542
- wallet = self.safe_string(params, 'wallet', 'exchange') # 'exchange', 'margin', 'funding' and also old labels 'exchange', 'trading', 'deposit', respectively
2543
- params = self.omit(params, 'network', 'wallet')
2544
- request: dict = {
2545
- 'method': networkId,
2546
- 'wallet': wallet,
2547
- 'amount': self.number_to_string(amount),
2548
- 'address': address,
2549
- }
2550
- if tag is not None:
2551
- request['payment_id'] = tag
2552
- withdrawOptions = self.safe_value(self.options, 'withdraw', {})
2553
- includeFee = self.safe_bool(withdrawOptions, 'includeFee', False)
2554
- if includeFee:
2555
- request['fee_deduct'] = 1
2556
- response = self.privatePostAuthWWithdraw(self.extend(request, params))
2557
- #
2558
- # [
2559
- # 1582271520931, # MTS Millisecond Time Stamp of the update
2560
- # "acc_wd-req", # TYPE Purpose of notification "acc_wd-req" account withdrawal request
2561
- # null, # MESSAGE_ID unique ID of the message
2562
- # null, # not documented
2563
- # [
2564
- # 0, # WITHDRAWAL_ID Unique Withdrawal ID
2565
- # null, # PLACEHOLDER
2566
- # "bitcoin", # METHOD Method of withdrawal
2567
- # null, # PAYMENT_ID Payment ID if relevant
2568
- # "exchange", # WALLET Sending wallet
2569
- # 1, # AMOUNT Amount of Withdrawal less fee
2570
- # null, # PLACEHOLDER
2571
- # null, # PLACEHOLDER
2572
- # 0.0004, # WITHDRAWAL_FEE Fee on withdrawal
2573
- # ],
2574
- # null, # CODE null or integer Work in progress
2575
- # "SUCCESS", # STATUS Status of the notification, it may vary over time SUCCESS, ERROR, FAILURE
2576
- # "Invalid bitcoin address(abcdef)", # TEXT Text of the notification
2577
- # ]
2578
- #
2579
- # in case of failure:
2580
- #
2581
- # [
2582
- # "error",
2583
- # 10001,
2584
- # "Momentary balance check. Please wait few seconds and try the transfer again."
2585
- # ]
2586
- #
2587
- statusMessage = self.safe_string(response, 0)
2588
- if statusMessage == 'error':
2589
- feedback = self.id + ' ' + response
2590
- message = self.safe_string(response, 2, '')
2591
- # same message v1
2592
- self.throw_exactly_matched_exception(self.exceptions['exact'], message, feedback)
2593
- self.throw_broadly_matched_exception(self.exceptions['broad'], message, feedback)
2594
- raise ExchangeError(feedback) # unknown message
2595
- text = self.safe_string(response, 7)
2596
- if text != 'success':
2597
- self.throw_broadly_matched_exception(self.exceptions['broad'], text, text)
2598
- return self.parse_transaction(response, currency)
2599
-
2600
- def fetch_positions(self, symbols: Strings = None, params={}):
2601
- """
2602
- fetch all open positions
2603
-
2604
- https://docs.bitfinex.com/reference/rest-auth-positions
2605
-
2606
- :param str[]|None symbols: list of unified market symbols
2607
- :param dict [params]: extra parameters specific to the exchange API endpoint
2608
- :returns dict[]: a list of `position structure <https://docs.ccxt.com/#/?id=position-structure>`
2609
- """
2610
- self.load_markets()
2611
- symbols = self.market_symbols(symbols)
2612
- response = self.privatePostAuthRPositions(params)
2613
- #
2614
- # [
2615
- # [
2616
- # "tBTCUSD", # SYMBOL
2617
- # "ACTIVE", # STATUS
2618
- # 0.0195, # AMOUNT
2619
- # 8565.0267019, # BASE_PRICE
2620
- # 0, # MARGIN_FUNDING
2621
- # 0, # MARGIN_FUNDING_TYPE
2622
- # -0.33455568705000516, # PL
2623
- # -0.0003117550117425625, # PL_PERC
2624
- # 7045.876419249083, # PRICE_LIQ
2625
- # 3.0673001895895604, # LEVERAGE
2626
- # null, # _PLACEHOLDER
2627
- # 142355652, # POSITION_ID
2628
- # 1574002216000, # MTS_CREATE
2629
- # 1574002216000, # MTS_UPDATE
2630
- # null, # _PLACEHOLDER
2631
- # 0, # TYPE
2632
- # null, # _PLACEHOLDER
2633
- # 0, # COLLATERAL
2634
- # 0, # COLLATERAL_MIN
2635
- # # META
2636
- # {
2637
- # "reason":"TRADE",
2638
- # "order_id":34271018124,
2639
- # "liq_stage":null,
2640
- # "trade_price":"8565.0267019",
2641
- # "trade_amount":"0.0195",
2642
- # "order_id_oppo":34277498022
2643
- # }
2644
- # ]
2645
- # ]
2646
- #
2647
- positionsList = []
2648
- for i in range(0, len(response)):
2649
- positionsList.append({'result': response[i]})
2650
- return self.parse_positions(positionsList, symbols)
2651
-
2652
- def parse_position(self, position: dict, market: Market = None):
2653
- #
2654
- # [
2655
- # "tBTCUSD", # SYMBOL
2656
- # "ACTIVE", # STATUS
2657
- # 0.0195, # AMOUNT
2658
- # 8565.0267019, # BASE_PRICE
2659
- # 0, # MARGIN_FUNDING
2660
- # 0, # MARGIN_FUNDING_TYPE
2661
- # -0.33455568705000516, # PL
2662
- # -0.0003117550117425625, # PL_PERC
2663
- # 7045.876419249083, # PRICE_LIQ
2664
- # 3.0673001895895604, # LEVERAGE
2665
- # null, # _PLACEHOLDER
2666
- # 142355652, # POSITION_ID
2667
- # 1574002216000, # MTS_CREATE
2668
- # 1574002216000, # MTS_UPDATE
2669
- # null, # _PLACEHOLDER
2670
- # 0, # TYPE
2671
- # null, # _PLACEHOLDER
2672
- # 0, # COLLATERAL
2673
- # 0, # COLLATERAL_MIN
2674
- # # META
2675
- # {
2676
- # "reason": "TRADE",
2677
- # "order_id": 34271018124,
2678
- # "liq_stage": null,
2679
- # "trade_price": "8565.0267019",
2680
- # "trade_amount": "0.0195",
2681
- # "order_id_oppo": 34277498022
2682
- # }
2683
- # ]
2684
- #
2685
- positionList = self.safe_list(position, 'result')
2686
- marketId = self.safe_string(positionList, 0)
2687
- amount = self.safe_string(positionList, 2)
2688
- timestamp = self.safe_integer(positionList, 12)
2689
- meta = self.safe_string(positionList, 19)
2690
- tradePrice = self.safe_string(meta, 'trade_price')
2691
- tradeAmount = self.safe_string(meta, 'trade_amount')
2692
- return self.safe_position({
2693
- 'info': positionList,
2694
- 'id': self.safe_string(positionList, 11),
2695
- 'symbol': self.safe_symbol(marketId, market),
2696
- 'notional': self.parse_number(amount),
2697
- 'marginMode': 'isolated', # derivatives use isolated, margin uses cross, https://support.bitfinex.com/hc/en-us/articles/360035475374-Derivatives-Trading-on-Bitfinex
2698
- 'liquidationPrice': self.safe_number(positionList, 8),
2699
- 'entryPrice': self.safe_number(positionList, 3),
2700
- 'unrealizedPnl': self.safe_number(positionList, 6),
2701
- 'percentage': self.safe_number(positionList, 7),
2702
- 'contracts': None,
2703
- 'contractSize': None,
2704
- 'markPrice': None,
2705
- 'lastPrice': None,
2706
- 'side': 'long' if Precise.string_gt(amount, '0') else 'short',
2707
- 'hedged': None,
2708
- 'timestamp': timestamp,
2709
- 'datetime': self.iso8601(timestamp),
2710
- 'lastUpdateTimestamp': self.safe_integer(positionList, 13),
2711
- 'maintenanceMargin': self.safe_number(positionList, 18),
2712
- 'maintenanceMarginPercentage': None,
2713
- 'collateral': self.safe_number(positionList, 17),
2714
- 'initialMargin': self.parse_number(Precise.string_mul(tradeAmount, tradePrice)),
2715
- 'initialMarginPercentage': None,
2716
- 'leverage': self.safe_number(positionList, 9),
2717
- 'marginRatio': None,
2718
- 'stopLossPrice': None,
2719
- 'takeProfitPrice': None,
2720
- })
2721
-
2722
- def nonce(self):
2723
- return self.milliseconds()
2724
-
2725
- def sign(self, path, api='public', method='GET', params={}, headers=None, body=None):
2726
- request = '/' + self.implode_params(path, params)
2727
- query = self.omit(params, self.extract_params(path))
2728
- if api == 'v1':
2729
- request = api + request
2730
- else:
2731
- request = self.version + request
2732
- url = self.urls['api'][api] + '/' + request
2733
- if api == 'public':
2734
- if query:
2735
- url += '?' + self.urlencode(query)
2736
- if api == 'private':
2737
- self.check_required_credentials()
2738
- nonce = str(self.nonce())
2739
- body = self.json(query)
2740
- auth = '/api/' + request + nonce + body
2741
- signature = self.hmac(self.encode(auth), self.encode(self.secret), hashlib.sha384)
2742
- headers = {
2743
- 'bfx-nonce': nonce,
2744
- 'bfx-apikey': self.apiKey,
2745
- 'bfx-signature': signature,
2746
- 'Content-Type': 'application/json',
2747
- }
2748
- return {'url': url, 'method': method, 'body': body, 'headers': headers}
2749
-
2750
- def handle_errors(self, statusCode, statusText, url, method, headers, body, response, requestHeaders, requestBody):
2751
- # ["error", 11010, "ratelimit: error"]
2752
- if response is not None:
2753
- if not isinstance(response, list):
2754
- message = self.safe_string_2(response, 'message', 'error')
2755
- feedback = self.id + ' ' + body
2756
- self.throw_exactly_matched_exception(self.exceptions['exact'], message, feedback)
2757
- self.throw_broadly_matched_exception(self.exceptions['broad'], message, feedback)
2758
- raise ExchangeError(self.id + ' ' + body)
2759
- elif response == '':
2760
- raise ExchangeError(self.id + ' returned empty response')
2761
- if statusCode == 429:
2762
- raise RateLimitExceeded(self.id + ' ' + body)
2763
- if statusCode == 500:
2764
- # See https://docs.bitfinex.com/docs/abbreviations-glossary#section-errorinfo-codes
2765
- errorCode = self.safe_string(response, 1, '')
2766
- errorText = self.safe_string(response, 2, '')
2767
- feedback = self.id + ' ' + errorText
2768
- self.throw_broadly_matched_exception(self.exceptions['broad'], errorText, feedback)
2769
- self.throw_exactly_matched_exception(self.exceptions['exact'], errorCode, feedback)
2770
- self.throw_exactly_matched_exception(self.exceptions['exact'], errorText, feedback)
2771
- raise ExchangeError(self.id + ' ' + errorText + '(#' + errorCode + ')')
2772
- return response
2773
-
2774
- def parse_ledger_entry_type(self, type: Str):
2775
- if type is None:
2776
- return None
2777
- elif type.find('fee') >= 0 or type.find('charged') >= 0:
2778
- return 'fee'
2779
- elif type.find('rebate') >= 0:
2780
- return 'rebate'
2781
- elif type.find('deposit') >= 0 or type.find('withdrawal') >= 0:
2782
- return 'transaction'
2783
- elif type.find('transfer') >= 0:
2784
- return 'transfer'
2785
- elif type.find('payment') >= 0:
2786
- return 'payout'
2787
- elif type.find('exchange') >= 0 or type.find('position') >= 0:
2788
- return 'trade'
2789
- else:
2790
- return type
2791
-
2792
- def parse_ledger_entry(self, item: dict, currency: Currency = None) -> LedgerEntry:
2793
- #
2794
- # [
2795
- # [
2796
- # 2531822314, # ID: Ledger identifier
2797
- # "USD", # CURRENCY: The symbol of the currency(ex. "BTC")
2798
- # null, # PLACEHOLDER
2799
- # 1573521810000, # MTS: Timestamp in milliseconds
2800
- # null, # PLACEHOLDER
2801
- # 0.01644445, # AMOUNT: Amount of funds moved
2802
- # 0, # BALANCE: New balance
2803
- # null, # PLACEHOLDER
2804
- # "Settlement @ 185.79 on wallet margin" # DESCRIPTION: Description of ledger transaction
2805
- # ]
2806
- # ]
2807
- #
2808
- itemList = self.safe_list(item, 'result', [])
2809
- type = None
2810
- id = self.safe_string(itemList, 0)
2811
- currencyId = self.safe_string(itemList, 1)
2812
- code = self.safe_currency_code(currencyId, currency)
2813
- currency = self.safe_currency(currencyId, currency)
2814
- timestamp = self.safe_integer(itemList, 3)
2815
- amount = self.safe_number(itemList, 5)
2816
- after = self.safe_number(itemList, 6)
2817
- description = self.safe_string(itemList, 8)
2818
- if description is not None:
2819
- parts = description.split(' @ ')
2820
- first = self.safe_string_lower(parts, 0)
2821
- type = self.parse_ledger_entry_type(first)
2822
- return self.safe_ledger_entry({
2823
- 'info': item,
2824
- 'id': id,
2825
- 'direction': None,
2826
- 'account': None,
2827
- 'referenceId': id,
2828
- 'referenceAccount': None,
2829
- 'type': type,
2830
- 'currency': code,
2831
- 'amount': amount,
2832
- 'timestamp': timestamp,
2833
- 'datetime': self.iso8601(timestamp),
2834
- 'before': None,
2835
- 'after': after,
2836
- 'status': None,
2837
- 'fee': None,
2838
- }, currency)
2839
-
2840
- def fetch_ledger(self, code: Str = None, since: Int = None, limit: Int = None, params={}) -> List[LedgerEntry]:
2841
- """
2842
- fetch the history of changes, actions done by the user or operations that altered the balance of the user
2843
-
2844
- https://docs.bitfinex.com/reference/rest-auth-ledgers
2845
-
2846
- :param str [code]: unified currency code, default is None
2847
- :param int [since]: timestamp in ms of the earliest ledger entry, default is None
2848
- :param int [limit]: max number of ledger entries to return, default is None, max is 2500
2849
- :param dict [params]: extra parameters specific to the exchange API endpoint
2850
- :param int [params.until]: timestamp in ms of the latest ledger entry
2851
- :param boolean [params.paginate]: default False, when True will automatically paginate by calling self endpoint multiple times. See in the docs all the [available parameters](https://github.com/ccxt/ccxt/wiki/Manual#pagination-params)
2852
- :returns dict: a `ledger structure <https://docs.ccxt.com/#/?id=ledger-structure>`
2853
- """
2854
- self.load_markets()
2855
- paginate = False
2856
- paginate, params = self.handle_option_and_params(params, 'fetchLedger', 'paginate')
2857
- if paginate:
2858
- return self.fetch_paginated_call_dynamic('fetchLedger', code, since, limit, params, 2500)
2859
- currency = None
2860
- request: dict = {}
2861
- if since is not None:
2862
- request['start'] = since
2863
- if limit is not None:
2864
- request['limit'] = limit
2865
- request, params = self.handle_until_option('end', request, params)
2866
- response = None
2867
- if code is not None:
2868
- currency = self.currency(code)
2869
- request['currency'] = currency['uppercaseId']
2870
- response = self.privatePostAuthRLedgersCurrencyHist(self.extend(request, params))
2871
- else:
2872
- response = self.privatePostAuthRLedgersHist(self.extend(request, params))
2873
- #
2874
- # [
2875
- # [
2876
- # 2531822314, # ID: Ledger identifier
2877
- # "USD", # CURRENCY: The symbol of the currency(ex. "BTC")
2878
- # null, # PLACEHOLDER
2879
- # 1573521810000, # MTS: Timestamp in milliseconds
2880
- # null, # PLACEHOLDER
2881
- # 0.01644445, # AMOUNT: Amount of funds moved
2882
- # 0, # BALANCE: New balance
2883
- # null, # PLACEHOLDER
2884
- # "Settlement @ 185.79 on wallet margin" # DESCRIPTION: Description of ledger transaction
2885
- # ]
2886
- # ]
2887
- #
2888
- ledgerObjects = []
2889
- for i in range(0, len(response)):
2890
- item = response[i]
2891
- ledgerObjects.append({'result': item})
2892
- return self.parse_ledger(ledgerObjects, currency, since, limit)
2893
-
2894
- def fetch_funding_rates(self, symbols: Strings = None, params={}) -> FundingRates:
2895
- """
2896
- fetch the current funding rate for multiple symbols
2897
-
2898
- https://docs.bitfinex.com/reference/rest-public-derivatives-status
2899
-
2900
- :param str[] symbols: list of unified market symbols
2901
- :param dict [params]: extra parameters specific to the exchange API endpoint
2902
- :returns dict[]: a list of `funding rate structures <https://docs.ccxt.com/#/?id=funding-rate-structure>`
2903
- """
2904
- if symbols is None:
2905
- raise ArgumentsRequired(self.id + ' fetchFundingRates() requires a symbols argument')
2906
- self.load_markets()
2907
- marketIds = self.market_ids(symbols)
2908
- request: dict = {
2909
- 'keys': ','.join(marketIds),
2910
- }
2911
- response = self.publicGetStatusDeriv(self.extend(request, params))
2912
- #
2913
- # [
2914
- # [
2915
- # "tBTCF0:USTF0",
2916
- # 1691165059000,
2917
- # null,
2918
- # 29297.851276225,
2919
- # 29277.5,
2920
- # null,
2921
- # 36950860.76010306,
2922
- # null,
2923
- # 1691193600000,
2924
- # 0.00000527,
2925
- # 82,
2926
- # null,
2927
- # 0.00014548,
2928
- # null,
2929
- # null,
2930
- # 29278.8925,
2931
- # null,
2932
- # null,
2933
- # 9636.07644994,
2934
- # null,
2935
- # null,
2936
- # null,
2937
- # 0.0005,
2938
- # 0.0025
2939
- # ]
2940
- # ]
2941
- #
2942
- return self.parse_funding_rates(response)
2943
-
2944
- def fetch_funding_rate_history(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}):
2945
- """
2946
- fetches historical funding rate prices
2947
-
2948
- https://docs.bitfinex.com/reference/rest-public-derivatives-status-history
2949
-
2950
- :param str symbol: unified market symbol
2951
- :param int [since]: timestamp in ms of the earliest funding rate entry
2952
- :param int [limit]: max number of funding rate entrys to return
2953
- :param dict [params]: extra parameters specific to the exchange API endpoint
2954
- :param int [params.until]: timestamp in ms of the latest funding rate
2955
- :param boolean [params.paginate]: default False, when True will automatically paginate by calling self endpoint multiple times. See in the docs all the [available parameters](https://github.com/ccxt/ccxt/wiki/Manual#pagination-params)
2956
- :returns dict: a `funding rate structure <https://docs.ccxt.com/#/?id=funding-rate-structure>`
2957
- """
2958
- if symbol is None:
2959
- raise ArgumentsRequired(self.id + ' fetchFundingRateHistory() requires a symbol argument')
2960
- self.load_markets()
2961
- paginate = False
2962
- paginate, params = self.handle_option_and_params(params, 'fetchFundingRateHistory', 'paginate')
2963
- if paginate:
2964
- return self.fetch_paginated_call_deterministic('fetchFundingRateHistory', symbol, since, limit, '8h', params, 5000)
2965
- market = self.market(symbol)
2966
- request: dict = {
2967
- 'symbol': market['id'],
2968
- }
2969
- if since is not None:
2970
- request['start'] = since
2971
- request, params = self.handle_until_option('end', request, params)
2972
- response = self.publicGetStatusDerivSymbolHist(self.extend(request, params))
2973
- #
2974
- # [
2975
- # [
2976
- # "tBTCF0:USTF0",
2977
- # 1691165059000,
2978
- # null,
2979
- # 29297.851276225,
2980
- # 29277.5,
2981
- # null,
2982
- # 36950860.76010306,
2983
- # null,
2984
- # 1691193600000,
2985
- # 0.00000527,
2986
- # 82,
2987
- # null,
2988
- # 0.00014548,
2989
- # null,
2990
- # null,
2991
- # 29278.8925,
2992
- # null,
2993
- # null,
2994
- # 9636.07644994,
2995
- # null,
2996
- # null,
2997
- # null,
2998
- # 0.0005,
2999
- # 0.0025
3000
- # ]
3001
- # ]
3002
- #
3003
- rates = []
3004
- for i in range(0, len(response)):
3005
- fr = response[i]
3006
- rate = self.parse_funding_rate_history(fr, market)
3007
- rates.append(rate)
3008
- reversedArray = []
3009
- rawRates = self.filter_by_symbol_since_limit(rates, symbol, since, limit)
3010
- ratesLength = len(rawRates)
3011
- for i in range(0, ratesLength):
3012
- index = ratesLength - i - 1
3013
- valueAtIndex = rawRates[index]
3014
- reversedArray.append(valueAtIndex)
3015
- return reversedArray
3016
-
3017
- def parse_funding_rate(self, contract, market: Market = None) -> FundingRate:
3018
- #
3019
- # [
3020
- # "tBTCF0:USTF0",
3021
- # 1691165059000,
3022
- # null,
3023
- # 29297.851276225,
3024
- # 29277.5,
3025
- # null,
3026
- # 36950860.76010306,
3027
- # null,
3028
- # 1691193600000,
3029
- # 0.00000527,
3030
- # 82,
3031
- # null,
3032
- # 0.00014548,
3033
- # null,
3034
- # null,
3035
- # 29278.8925,
3036
- # null,
3037
- # null,
3038
- # 9636.07644994,
3039
- # null,
3040
- # null,
3041
- # null,
3042
- # 0.0005,
3043
- # 0.0025
3044
- # ]
3045
- #
3046
- marketId = self.safe_string(contract, 0)
3047
- timestamp = self.safe_integer(contract, 1)
3048
- nextFundingTimestamp = self.safe_integer(contract, 8)
3049
- return {
3050
- 'info': contract,
3051
- 'symbol': self.safe_symbol(marketId, market),
3052
- 'markPrice': self.safe_number(contract, 15),
3053
- 'indexPrice': self.safe_number(contract, 3),
3054
- 'interestRate': None,
3055
- 'estimatedSettlePrice': None,
3056
- 'timestamp': timestamp,
3057
- 'datetime': self.iso8601(timestamp),
3058
- 'fundingRate': self.safe_number(contract, 12),
3059
- 'fundingTimestamp': None,
3060
- 'fundingDatetime': None,
3061
- 'nextFundingRate': self.safe_number(contract, 9),
3062
- 'nextFundingTimestamp': nextFundingTimestamp,
3063
- 'nextFundingDatetime': self.iso8601(nextFundingTimestamp),
3064
- 'previousFundingRate': None,
3065
- 'previousFundingTimestamp': None,
3066
- 'previousFundingDatetime': None,
3067
- 'interval': None,
3068
- }
3069
-
3070
- def parse_funding_rate_history(self, contract, market: Market = None):
3071
- #
3072
- # [
3073
- # 1691165494000,
3074
- # null,
3075
- # 29278.95838065,
3076
- # 29260.5,
3077
- # null,
3078
- # 36950860.76010305,
3079
- # null,
3080
- # 1691193600000,
3081
- # 0.00001449,
3082
- # 222,
3083
- # null,
3084
- # 0.00014548,
3085
- # null,
3086
- # null,
3087
- # 29260.005,
3088
- # null,
3089
- # null,
3090
- # 9635.86484562,
3091
- # null,
3092
- # null,
3093
- # null,
3094
- # 0.0005,
3095
- # 0.0025
3096
- # ]
3097
- #
3098
- timestamp = self.safe_integer(contract, 0)
3099
- nextFundingTimestamp = self.safe_integer(contract, 7)
3100
- return {
3101
- 'info': contract,
3102
- 'symbol': self.safe_symbol(None, market),
3103
- 'markPrice': self.safe_number(contract, 14),
3104
- 'indexPrice': self.safe_number(contract, 2),
3105
- 'interestRate': None,
3106
- 'estimatedSettlePrice': None,
3107
- 'timestamp': timestamp,
3108
- 'datetime': self.iso8601(timestamp),
3109
- 'fundingRate': self.safe_number(contract, 11),
3110
- 'fundingTimestamp': None,
3111
- 'fundingDatetime': None,
3112
- 'nextFundingRate': self.safe_number(contract, 8),
3113
- 'nextFundingTimestamp': nextFundingTimestamp,
3114
- 'nextFundingDatetime': self.iso8601(nextFundingTimestamp),
3115
- 'previousFundingRate': None,
3116
- 'previousFundingTimestamp': None,
3117
- 'previousFundingDatetime': None,
3118
- }
3119
-
3120
- def fetch_open_interest(self, symbol: str, params={}):
3121
- """
3122
- retrieves the open interest of a contract trading pair
3123
-
3124
- https://docs.bitfinex.com/reference/rest-public-derivatives-status
3125
-
3126
- :param str symbol: unified CCXT market symbol
3127
- :param dict [params]: exchange specific parameters
3128
- :returns dict: an `open interest structure <https://docs.ccxt.com/#/?id=open-interest-structure>`
3129
- """
3130
- self.load_markets()
3131
- market = self.market(symbol)
3132
- request: dict = {
3133
- 'keys': market['id'],
3134
- }
3135
- response = self.publicGetStatusDeriv(self.extend(request, params))
3136
- #
3137
- # [
3138
- # [
3139
- # "tXRPF0:USTF0", # market id
3140
- # 1706256986000, # millisecond timestamp
3141
- # null,
3142
- # 0.512705, # derivative mid price
3143
- # 0.512395, # underlying spot mid price
3144
- # null,
3145
- # 37671483.04, # insurance fund balance
3146
- # null,
3147
- # 1706284800000, # timestamp of next funding
3148
- # 0.00002353, # accrued funding for next period
3149
- # 317, # next funding step
3150
- # null,
3151
- # 0, # current funding
3152
- # null,
3153
- # null,
3154
- # 0.5123016, # mark price
3155
- # null,
3156
- # null,
3157
- # 2233562.03115, # open interest in contracts
3158
- # null,
3159
- # null,
3160
- # null,
3161
- # 0.0005, # average spread without funding payment
3162
- # 0.0025 # funding payment cap
3163
- # ]
3164
- # ]
3165
- #
3166
- oi = self.safe_list(response, 0)
3167
- return self.parse_open_interest(oi, market)
3168
-
3169
- def fetch_open_interest_history(self, symbol: str, timeframe='1m', since: Int = None, limit: Int = None, params={}):
3170
- """
3171
- retrieves the open interest history of a currency
3172
-
3173
- https://docs.bitfinex.com/reference/rest-public-derivatives-status-history
3174
-
3175
- :param str symbol: unified CCXT market symbol
3176
- :param str timeframe: the time period of each row of data, not used by bitfinex2
3177
- :param int [since]: the time in ms of the earliest record to retrieve unix timestamp
3178
- :param int [limit]: the number of records in the response
3179
- :param dict [params]: exchange specific parameters
3180
- :param int [params.until]: the time in ms of the latest record to retrieve unix timestamp
3181
- :param boolean [params.paginate]: default False, when True will automatically paginate by calling self endpoint multiple times. See in the docs all the [available parameters](https://github.com/ccxt/ccxt/wiki/Manual#pagination-params)
3182
- :returns: An array of `open interest structures <https://docs.ccxt.com/#/?id=open-interest-structure>`
3183
- """
3184
- self.load_markets()
3185
- paginate = False
3186
- paginate, params = self.handle_option_and_params(params, 'fetchOpenInterestHistory', 'paginate')
3187
- if paginate:
3188
- return self.fetch_paginated_call_deterministic('fetchOpenInterestHistory', symbol, since, limit, '8h', params, 5000)
3189
- market = self.market(symbol)
3190
- request: dict = {
3191
- 'symbol': market['id'],
3192
- }
3193
- if since is not None:
3194
- request['start'] = since
3195
- if limit is not None:
3196
- request['limit'] = limit
3197
- request, params = self.handle_until_option('end', request, params)
3198
- response = self.publicGetStatusDerivSymbolHist(self.extend(request, params))
3199
- #
3200
- # [
3201
- # [
3202
- # 1706295191000, # timestamp
3203
- # null,
3204
- # 42152.425382, # derivative mid price
3205
- # 42133, # spot mid price
3206
- # null,
3207
- # 37671589.7853521, # insurance fund balance
3208
- # null,
3209
- # 1706313600000, # timestamp of next funding
3210
- # 0.00018734, # accrued funding for next period
3211
- # 3343, # next funding step
3212
- # null,
3213
- # 0.00007587, # current funding
3214
- # null,
3215
- # null,
3216
- # 42134.1, # mark price
3217
- # null,
3218
- # null,
3219
- # 5775.20348804, # open interest number of contracts
3220
- # null,
3221
- # null,
3222
- # null,
3223
- # 0.0005, # average spread without funding payment
3224
- # 0.0025 # funding payment cap
3225
- # ],
3226
- # ]
3227
- #
3228
- return self.parse_open_interests(response, market, since, limit)
3229
-
3230
- def parse_open_interest(self, interest, market: Market = None):
3231
- #
3232
- # fetchOpenInterest:
3233
- #
3234
- # [
3235
- # "tXRPF0:USTF0", # market id
3236
- # 1706256986000, # millisecond timestamp
3237
- # null,
3238
- # 0.512705, # derivative mid price
3239
- # 0.512395, # underlying spot mid price
3240
- # null,
3241
- # 37671483.04, # insurance fund balance
3242
- # null,
3243
- # 1706284800000, # timestamp of next funding
3244
- # 0.00002353, # accrued funding for next period
3245
- # 317, # next funding step
3246
- # null,
3247
- # 0, # current funding
3248
- # null,
3249
- # null,
3250
- # 0.5123016, # mark price
3251
- # null,
3252
- # null,
3253
- # 2233562.03115, # open interest in contracts
3254
- # null,
3255
- # null,
3256
- # null,
3257
- # 0.0005, # average spread without funding payment
3258
- # 0.0025 # funding payment cap
3259
- # ]
3260
- #
3261
- # fetchOpenInterestHistory:
3262
- #
3263
- # [
3264
- # 1706295191000, # timestamp
3265
- # null,
3266
- # 42152.425382, # derivative mid price
3267
- # 42133, # spot mid price
3268
- # null,
3269
- # 37671589.7853521, # insurance fund balance
3270
- # null,
3271
- # 1706313600000, # timestamp of next funding
3272
- # 0.00018734, # accrued funding for next period
3273
- # 3343, # next funding step
3274
- # null,
3275
- # 0.00007587, # current funding
3276
- # null,
3277
- # null,
3278
- # 42134.1, # mark price
3279
- # null,
3280
- # null,
3281
- # 5775.20348804, # open interest number of contracts
3282
- # null,
3283
- # null,
3284
- # null,
3285
- # 0.0005, # average spread without funding payment
3286
- # 0.0025 # funding payment cap
3287
- # ]
3288
- #
3289
- interestLength = len(interest)
3290
- openInterestIndex = 17 if (interestLength == 23) else 18
3291
- timestamp = self.safe_integer(interest, 1)
3292
- marketId = self.safe_string(interest, 0)
3293
- return self.safe_open_interest({
3294
- 'symbol': self.safe_symbol(marketId, market, None, 'swap'),
3295
- 'openInterestAmount': self.safe_number(interest, openInterestIndex),
3296
- 'openInterestValue': None,
3297
- 'timestamp': timestamp,
3298
- 'datetime': self.iso8601(timestamp),
3299
- 'info': interest,
3300
- }, market)
3301
-
3302
- def fetch_liquidations(self, symbol: str, since: Int = None, limit: Int = None, params={}):
3303
- """
3304
- retrieves the public liquidations of a trading pair
3305
-
3306
- https://docs.bitfinex.com/reference/rest-public-liquidations
3307
-
3308
- :param str symbol: unified CCXT market symbol
3309
- :param int [since]: the earliest time in ms to fetch liquidations for
3310
- :param int [limit]: the maximum number of liquidation structures to retrieve
3311
- :param dict [params]: exchange specific parameters
3312
- :param int [params.until]: timestamp in ms of the latest liquidation
3313
- :param boolean [params.paginate]: default False, when True will automatically paginate by calling self endpoint multiple times. See in the docs all the [available parameters](https://github.com/ccxt/ccxt/wiki/Manual#pagination-params)
3314
- :returns dict: an array of `liquidation structures <https://docs.ccxt.com/#/?id=liquidation-structure>`
3315
- """
3316
- self.load_markets()
3317
- paginate = False
3318
- paginate, params = self.handle_option_and_params(params, 'fetchLiquidations', 'paginate')
3319
- if paginate:
3320
- return self.fetch_paginated_call_deterministic('fetchLiquidations', symbol, since, limit, '8h', params, 500)
3321
- market = self.market(symbol)
3322
- request: dict = {}
3323
- if since is not None:
3324
- request['start'] = since
3325
- if limit is not None:
3326
- request['limit'] = limit
3327
- request, params = self.handle_until_option('end', request, params)
3328
- response = self.publicGetLiquidationsHist(self.extend(request, params))
3329
- #
3330
- # [
3331
- # [
3332
- # [
3333
- # "pos",
3334
- # 171085137,
3335
- # 1706395919788,
3336
- # null,
3337
- # "tAVAXF0:USTF0",
3338
- # -8,
3339
- # 32.868,
3340
- # null,
3341
- # 1,
3342
- # 1,
3343
- # null,
3344
- # 33.255
3345
- # ]
3346
- # ],
3347
- # ]
3348
- #
3349
- return self.parse_liquidations(response, market, since, limit)
3350
-
3351
- def parse_liquidation(self, liquidation, market: Market = None):
3352
- #
3353
- # [
3354
- # [
3355
- # "pos",
3356
- # 171085137, # position id
3357
- # 1706395919788, # timestamp
3358
- # null,
3359
- # "tAVAXF0:USTF0", # market id
3360
- # -8, # amount in contracts
3361
- # 32.868, # base price
3362
- # null,
3363
- # 1,
3364
- # 1,
3365
- # null,
3366
- # 33.255 # acquired price
3367
- # ]
3368
- # ]
3369
- #
3370
- entry = liquidation[0]
3371
- timestamp = self.safe_integer(entry, 2)
3372
- marketId = self.safe_string(entry, 4)
3373
- contracts = Precise.string_abs(self.safe_string(entry, 5))
3374
- contractSize = self.safe_string(market, 'contractSize')
3375
- baseValue = Precise.string_mul(contracts, contractSize)
3376
- price = self.safe_string(entry, 11)
3377
- return self.safe_liquidation({
3378
- 'info': entry,
3379
- 'symbol': self.safe_symbol(marketId, market, None, 'contract'),
3380
- 'contracts': self.parse_number(contracts),
3381
- 'contractSize': self.parse_number(contractSize),
3382
- 'price': self.parse_number(price),
3383
- 'baseValue': self.parse_number(baseValue),
3384
- 'quoteValue': self.parse_number(Precise.string_mul(baseValue, price)),
3385
- 'timestamp': timestamp,
3386
- 'datetime': self.iso8601(timestamp),
3387
- })
3388
-
3389
- def set_margin(self, symbol: str, amount: float, params={}) -> MarginModification:
3390
- """
3391
- either adds or reduces margin in a swap position in order to set the margin to a specific value
3392
-
3393
- https://docs.bitfinex.com/reference/rest-auth-deriv-pos-collateral-set
3394
-
3395
- :param str symbol: unified market symbol of the market to set margin in
3396
- :param float amount: the amount to set the margin to
3397
- :param dict [params]: parameters specific to the exchange API endpoint
3398
- :returns dict: A `margin structure <https://github.com/ccxt/ccxt/wiki/Manual#add-margin-structure>`
3399
- """
3400
- self.load_markets()
3401
- market = self.market(symbol)
3402
- if not market['swap']:
3403
- raise NotSupported(self.id + ' setMargin() only support swap markets')
3404
- request: dict = {
3405
- 'symbol': market['id'],
3406
- 'collateral': self.parse_to_numeric(amount),
3407
- }
3408
- response = self.privatePostAuthWDerivCollateralSet(self.extend(request, params))
3409
- #
3410
- # [
3411
- # [
3412
- # 1
3413
- # ]
3414
- # ]
3415
- #
3416
- data = self.safe_value(response, 0)
3417
- return self.parse_margin_modification(data, market)
3418
-
3419
- def parse_margin_modification(self, data, market=None) -> MarginModification:
3420
- #
3421
- # setMargin
3422
- #
3423
- # [
3424
- # [
3425
- # 1
3426
- # ]
3427
- # ]
3428
- #
3429
- marginStatusRaw = data[0]
3430
- marginStatus = 'ok' if (marginStatusRaw == 1) else 'failed'
3431
- return {
3432
- 'info': data,
3433
- 'symbol': market['symbol'],
3434
- 'type': None,
3435
- 'marginMode': 'isolated',
3436
- 'amount': None,
3437
- 'total': None,
3438
- 'code': None,
3439
- 'status': marginStatus,
3440
- 'timestamp': None,
3441
- 'datetime': None,
3442
- }
3443
-
3444
- def fetch_order(self, id: str, symbol: Str = None, params={}):
3445
- """
3446
- fetches information on an order made by the user
3447
-
3448
- https://docs.bitfinex.com/reference/rest-auth-retrieve-orders
3449
- https://docs.bitfinex.com/reference/rest-auth-retrieve-orders-by-symbol
3450
-
3451
- :param str id: the order id
3452
- :param str [symbol]: unified symbol of the market the order was made in
3453
- :param dict [params]: extra parameters specific to the exchange API endpoint
3454
- :returns dict: an `order structure <https://docs.ccxt.com/#/?id=order-structure>`
3455
- """
3456
- self.load_markets()
3457
- request: dict = {
3458
- 'id': [self.parse_to_numeric(id)],
3459
- }
3460
- market = None
3461
- response = None
3462
- if symbol is None:
3463
- response = self.privatePostAuthROrders(self.extend(request, params))
3464
- else:
3465
- market = self.market(symbol)
3466
- request['symbol'] = market['id']
3467
- response = self.privatePostAuthROrdersSymbol(self.extend(request, params))
3468
- #
3469
- # [
3470
- # [
3471
- # 139658969116,
3472
- # null,
3473
- # 1706843908637,
3474
- # "tBTCUST",
3475
- # 1706843908637,
3476
- # 1706843908638,
3477
- # 0.0001,
3478
- # 0.0001,
3479
- # "EXCHANGE LIMIT",
3480
- # null,
3481
- # null,
3482
- # null,
3483
- # 0,
3484
- # "ACTIVE",
3485
- # null,
3486
- # null,
3487
- # 35000,
3488
- # 0,
3489
- # 0,
3490
- # 0,
3491
- # null,
3492
- # null,
3493
- # null,
3494
- # 0,
3495
- # 0,
3496
- # null,
3497
- # null,
3498
- # null,
3499
- # "API>BFX",
3500
- # null,
3501
- # null,
3502
- # {}
3503
- # ]
3504
- # ]
3505
- #
3506
- order = self.safe_list(response, 0)
3507
- newOrder = {'result': order}
3508
- return self.parse_order(newOrder, market)
3509
-
3510
- def edit_order(self, id: str, symbol: str, type: OrderType, side: OrderSide, amount: Num = None, price: Num = None, params={}):
3511
- """
3512
- edit a trade order
3513
-
3514
- https://docs.bitfinex.com/reference/rest-auth-update-order
3515
-
3516
- :param str id: edit order id
3517
- :param str symbol: unified symbol of the market to edit an order in
3518
- :param str type: 'market' or 'limit'
3519
- :param str side: 'buy' or 'sell'
3520
- :param float amount: how much you want to trade in units of the base currency
3521
- :param float [price]: the price at which the order is to be fulfilled, in units of the quote currency, ignored in market orders
3522
- :param dict [params]: extra parameters specific to the exchange API endpoint
3523
- :param float [params.stopPrice]: the price that triggers a trigger order
3524
- :param boolean [params.postOnly]: set to True if you want to make a post only order
3525
- :param boolean [params.reduceOnly]: indicates that the order is to reduce the size of a position
3526
- :param int [params.flags]: additional order parameters: 4096(Post Only), 1024(Reduce Only), 16384(OCO), 64(Hidden), 512(Close), 524288(No Var Rates)
3527
- :param int [params.leverage]: leverage for a derivative order, supported by derivative symbol orders only, the value should be between 1 and 100 inclusive
3528
- :param int [params.clientOrderId]: a unique client order id for the order
3529
- :param float [params.trailingAmount]: *swap only* the quote amount to trail away from the current market price
3530
- :returns dict: an `order structure <https://docs.ccxt.com/#/?id=order-structure>`
3531
- """
3532
- self.load_markets()
3533
- market = self.market(symbol)
3534
- request: dict = {
3535
- 'id': self.parse_to_numeric(id),
3536
- }
3537
- if amount is not None:
3538
- amountString = self.amount_to_precision(symbol, amount)
3539
- amountString = amountString if (side == 'buy') else Precise.string_neg(amountString)
3540
- request['amount'] = amountString
3541
- stopPrice = self.safe_string_2(params, 'stopPrice', 'triggerPrice')
3542
- trailingAmount = self.safe_string(params, 'trailingAmount')
3543
- timeInForce = self.safe_string(params, 'timeInForce')
3544
- postOnlyParam = self.safe_bool(params, 'postOnly', False)
3545
- reduceOnly = self.safe_bool(params, 'reduceOnly', False)
3546
- clientOrderId = self.safe_integer_2(params, 'cid', 'clientOrderId')
3547
- if trailingAmount is not None:
3548
- request['price_trailing'] = trailingAmount
3549
- elif stopPrice is not None:
3550
- # request['price'] is taken for stop orders
3551
- request['price'] = self.price_to_precision(symbol, stopPrice)
3552
- if type == 'limit':
3553
- request['price_aux_limit'] = self.price_to_precision(symbol, price)
3554
- postOnly = (postOnlyParam or (timeInForce == 'PO'))
3555
- if (type != 'market') and (stopPrice is None):
3556
- request['price'] = self.price_to_precision(symbol, price)
3557
- # flag values may be summed to combine flags
3558
- flags = 0
3559
- if postOnly:
3560
- flags = self.sum(flags, 4096)
3561
- if reduceOnly:
3562
- flags = self.sum(flags, 1024)
3563
- if flags != 0:
3564
- request['flags'] = flags
3565
- if clientOrderId is not None:
3566
- request['cid'] = clientOrderId
3567
- leverage = self.safe_integer_2(params, 'leverage', 'lev')
3568
- if leverage is not None:
3569
- request['lev'] = leverage
3570
- params = self.omit(params, ['triggerPrice', 'stopPrice', 'timeInForce', 'postOnly', 'reduceOnly', 'trailingAmount', 'clientOrderId', 'leverage'])
3571
- response = self.privatePostAuthWOrderUpdate(self.extend(request, params))
3572
- #
3573
- # [
3574
- # 1706845376402,
3575
- # "ou-req",
3576
- # null,
3577
- # null,
3578
- # [
3579
- # 139658969116,
3580
- # null,
3581
- # 1706843908637,
3582
- # "tBTCUST",
3583
- # 1706843908637,
3584
- # 1706843908638,
3585
- # 0.0002,
3586
- # 0.0002,
3587
- # "EXCHANGE LIMIT",
3588
- # null,
3589
- # null,
3590
- # null,
3591
- # 0,
3592
- # "ACTIVE",
3593
- # null,
3594
- # null,
3595
- # 35000,
3596
- # 0,
3597
- # 0,
3598
- # 0,
3599
- # null,
3600
- # null,
3601
- # null,
3602
- # 0,
3603
- # 0,
3604
- # null,
3605
- # null,
3606
- # null,
3607
- # "API>BFX",
3608
- # null,
3609
- # null,
3610
- # {}
3611
- # ],
3612
- # null,
3613
- # "SUCCESS",
3614
- # "Submitting update to exchange limit buy order for 0.0002 BTC."
3615
- # ]
3616
- #
3617
- status = self.safe_string(response, 6)
3618
- if status != 'SUCCESS':
3619
- errorCode = response[5]
3620
- errorText = response[7]
3621
- raise ExchangeError(self.id + ' ' + response[6] + ': ' + errorText + '(#' + errorCode + ')')
3622
- order = self.safe_list(response, 4, [])
3623
- newOrder = {'result': order}
3624
- return self.parse_order(newOrder, market)