ccxt-look 1.81.50
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.cache/eslintcache +1 -0
- package/.dockerignore +6 -0
- package/.eslintignore +1 -0
- package/.gitattributes +5 -0
- package/.readthedocs.yaml +16 -0
- package/CONTRIBUTING.md +1049 -0
- package/LICENSE.txt +21 -0
- package/README.md +537 -0
- package/SECURITY.md +5 -0
- package/build/cleanup-old-tags.js +94 -0
- package/build/countries.js +256 -0
- package/build/export-exchanges.js +520 -0
- package/build/fs.js +51 -0
- package/build/transpile.js +1772 -0
- package/build/vss.js +78 -0
- package/ccxt.browser.js +7 -0
- package/ccxt.d.ts +692 -0
- package/ccxt.js +171 -0
- package/cleanup.sh +2 -0
- package/composer-install.sh +20 -0
- package/dist/ccxt.browser.js +208383 -0
- package/gource.sh +3 -0
- package/index.html +7 -0
- package/js/.eslintrc +87 -0
- package/js/aax.js +2686 -0
- package/js/ascendex.js +2584 -0
- package/js/base/.eslintrc.js +43 -0
- package/js/base/Exchange.js +2371 -0
- package/js/base/Precise.js +283 -0
- package/js/base/errorHierarchy.js +47 -0
- package/js/base/errors.js +55 -0
- package/js/base/functions/crypto.js +158 -0
- package/js/base/functions/encode.js +118 -0
- package/js/base/functions/generic.js +270 -0
- package/js/base/functions/misc.js +138 -0
- package/js/base/functions/number.js +329 -0
- package/js/base/functions/platform.js +38 -0
- package/js/base/functions/string.js +21 -0
- package/js/base/functions/throttle.js +79 -0
- package/js/base/functions/time.js +210 -0
- package/js/base/functions/type.js +66 -0
- package/js/base/functions.js +28 -0
- package/js/bequant.js +32 -0
- package/js/bibox.js +1407 -0
- package/js/bigone.js +1366 -0
- package/js/binance.js +5652 -0
- package/js/binancecoinm.js +46 -0
- package/js/binanceus.js +46 -0
- package/js/binanceusdm.js +49 -0
- package/js/bit2c.js +535 -0
- package/js/bitbank.js +842 -0
- package/js/bitbay.js +16 -0
- package/js/bitbns.js +1073 -0
- package/js/bitcoincom.js +15 -0
- package/js/bitfinex.js +1433 -0
- package/js/bitfinex2.js +2025 -0
- package/js/bitflyer.js +840 -0
- package/js/bitforex.js +614 -0
- package/js/bitget.js +2397 -0
- package/js/bithumb.js +980 -0
- package/js/bitmart.js +2516 -0
- package/js/bitmex.js +1809 -0
- package/js/bitopro.js +1443 -0
- package/js/bitpanda.js +1782 -0
- package/js/bitrue.js +1747 -0
- package/js/bitso.js +1062 -0
- package/js/bitstamp.js +1757 -0
- package/js/bitstamp1.js +343 -0
- package/js/bittrex.js +1876 -0
- package/js/bitvavo.js +1579 -0
- package/js/bkex.js +1233 -0
- package/js/bl3p.js +346 -0
- package/js/blockchaincom.js +969 -0
- package/js/btcalpha.js +680 -0
- package/js/btcbox.js +477 -0
- package/js/btcmarkets.js +1022 -0
- package/js/btctradeua.js +466 -0
- package/js/btcturk.js +734 -0
- package/js/buda.js +946 -0
- package/js/bw.js +1265 -0
- package/js/bybit.js +3372 -0
- package/js/bytetrade.js +1336 -0
- package/js/cdax.js +1646 -0
- package/js/cex.js +1410 -0
- package/js/coinbase.js +1342 -0
- package/js/coinbaseprime.js +31 -0
- package/js/coinbasepro.js +1466 -0
- package/js/coincheck.js +755 -0
- package/js/coinex.js +3400 -0
- package/js/coinfalcon.js +880 -0
- package/js/coinmate.js +794 -0
- package/js/coinone.js +816 -0
- package/js/coinspot.js +345 -0
- package/js/crex24.js +1636 -0
- package/js/cryptocom.js +1832 -0
- package/js/currencycom.js +1748 -0
- package/js/delta.js +1547 -0
- package/js/deribit.js +2148 -0
- package/js/digifinex.js +1585 -0
- package/js/eqonex.js +1660 -0
- package/js/exmo.js +1670 -0
- package/js/fairdesk.js +1231 -0
- package/js/flowbtc.js +35 -0
- package/js/fmfwio.js +34 -0
- package/js/ftx.js +2751 -0
- package/js/ftxus.js +38 -0
- package/js/gateio.js +4174 -0
- package/js/gemini.js +1397 -0
- package/js/hitbtc.js +1343 -0
- package/js/hitbtc3.js +2329 -0
- package/js/hollaex.js +1486 -0
- package/js/huobi.js +5706 -0
- package/js/huobijp.js +1710 -0
- package/js/huobipro.js +18 -0
- package/js/idex.js +1439 -0
- package/js/independentreserve.js +649 -0
- package/js/indodax.js +742 -0
- package/js/itbit.js +722 -0
- package/js/kraken.js +2179 -0
- package/js/kucoin.js +2571 -0
- package/js/kucoinfutures.js +1771 -0
- package/js/kuna.js +809 -0
- package/js/latoken.js +1445 -0
- package/js/lbank.js +760 -0
- package/js/liquid.js +1432 -0
- package/js/luno.js +873 -0
- package/js/lykke.js +1147 -0
- package/js/mercado.js +771 -0
- package/js/mexc.js +3151 -0
- package/js/ndax.js +2233 -0
- package/js/novadax.js +1318 -0
- package/js/oceanex.js +816 -0
- package/js/okcoin.js +3841 -0
- package/js/okex.js +16 -0
- package/js/okex5.js +16 -0
- package/js/okx.js +4795 -0
- package/js/paymium.js +498 -0
- package/js/phemex.js +2957 -0
- package/js/poloniex.js +1674 -0
- package/js/probit.js +1346 -0
- package/js/qtrade.js +1588 -0
- package/js/ripio.js +1061 -0
- package/js/static_dependencies/BN/bn.js +3526 -0
- package/js/static_dependencies/README.md +1 -0
- package/js/static_dependencies/crypto-js/crypto-js.js +5988 -0
- package/js/static_dependencies/elliptic/lib/elliptic/curve/base.js +375 -0
- package/js/static_dependencies/elliptic/lib/elliptic/curve/edwards.js +433 -0
- package/js/static_dependencies/elliptic/lib/elliptic/curve/index.js +8 -0
- package/js/static_dependencies/elliptic/lib/elliptic/curve/mont.js +180 -0
- package/js/static_dependencies/elliptic/lib/elliptic/curve/short.js +938 -0
- package/js/static_dependencies/elliptic/lib/elliptic/curves.js +204 -0
- package/js/static_dependencies/elliptic/lib/elliptic/ec/index.js +240 -0
- package/js/static_dependencies/elliptic/lib/elliptic/ec/key.js +119 -0
- package/js/static_dependencies/elliptic/lib/elliptic/ec/signature.js +24 -0
- package/js/static_dependencies/elliptic/lib/elliptic/eddsa/index.js +145 -0
- package/js/static_dependencies/elliptic/lib/elliptic/eddsa/key.js +100 -0
- package/js/static_dependencies/elliptic/lib/elliptic/eddsa/signature.js +65 -0
- package/js/static_dependencies/elliptic/lib/elliptic/precomputed/secp256k1.js +780 -0
- package/js/static_dependencies/elliptic/lib/elliptic/utils.js +214 -0
- package/js/static_dependencies/elliptic/lib/elliptic.js +22 -0
- package/js/static_dependencies/elliptic/lib/hmac-drbg/hmac-drbg.js +114 -0
- package/js/static_dependencies/fetch-ponyfill/fetch-node.js +39 -0
- package/js/static_dependencies/node-fetch/index.js +1564 -0
- package/js/static_dependencies/node-rsa/NodeRSA.js +223 -0
- package/js/static_dependencies/node-rsa/asn1/ber/errors.js +13 -0
- package/js/static_dependencies/node-rsa/asn1/ber/index.js +21 -0
- package/js/static_dependencies/node-rsa/asn1/ber/reader.js +262 -0
- package/js/static_dependencies/node-rsa/asn1/ber/types.js +36 -0
- package/js/static_dependencies/node-rsa/asn1/index.js +17 -0
- package/js/static_dependencies/node-rsa/encryptEngines/js.js +34 -0
- package/js/static_dependencies/node-rsa/formats/components.js +71 -0
- package/js/static_dependencies/node-rsa/formats/formats.js +31 -0
- package/js/static_dependencies/node-rsa/formats/pkcs1.js +148 -0
- package/js/static_dependencies/node-rsa/formats/pkcs8.js +187 -0
- package/js/static_dependencies/node-rsa/libs/jsbn.js +1252 -0
- package/js/static_dependencies/node-rsa/libs/rsa.js +147 -0
- package/js/static_dependencies/node-rsa/schemes/pkcs1.js +176 -0
- package/js/static_dependencies/node-rsa/schemes/schemes.js +21 -0
- package/js/static_dependencies/node-rsa/utils.js +98 -0
- package/js/static_dependencies/qs/formats.js +18 -0
- package/js/static_dependencies/qs/index.js +11 -0
- package/js/static_dependencies/qs/parse.js +242 -0
- package/js/static_dependencies/qs/stringify.js +269 -0
- package/js/static_dependencies/qs/utils.js +230 -0
- package/js/stex.js +1925 -0
- package/js/test/.eslintrc.js +42 -0
- package/js/test/Exchange/test.balance.js +61 -0
- package/js/test/Exchange/test.borrowRate.js +32 -0
- package/js/test/Exchange/test.currency.js +52 -0
- package/js/test/Exchange/test.fetchBalance.js +23 -0
- package/js/test/Exchange/test.fetchBorrowInterest.js +59 -0
- package/js/test/Exchange/test.fetchBorrowRate.js +32 -0
- package/js/test/Exchange/test.fetchBorrowRates.js +28 -0
- package/js/test/Exchange/test.fetchClosedOrders.js +32 -0
- package/js/test/Exchange/test.fetchCurrencies.js +35 -0
- package/js/test/Exchange/test.fetchDeposits.js +31 -0
- package/js/test/Exchange/test.fetchFundingFees.js +19 -0
- package/js/test/Exchange/test.fetchFundingRateHistory.js +40 -0
- package/js/test/Exchange/test.fetchL2OrderBook.js +23 -0
- package/js/test/Exchange/test.fetchLedger.js +42 -0
- package/js/test/Exchange/test.fetchLeverageTiers.js +33 -0
- package/js/test/Exchange/test.fetchMarketLeverageTiers.js +22 -0
- package/js/test/Exchange/test.fetchMarkets.js +33 -0
- package/js/test/Exchange/test.fetchMyTrades.js +42 -0
- package/js/test/Exchange/test.fetchOHLCV.js +46 -0
- package/js/test/Exchange/test.fetchOpenOrders.js +36 -0
- package/js/test/Exchange/test.fetchOrderBook.js +25 -0
- package/js/test/Exchange/test.fetchOrderBooks.js +35 -0
- package/js/test/Exchange/test.fetchOrders.js +41 -0
- package/js/test/Exchange/test.fetchPositions.js +47 -0
- package/js/test/Exchange/test.fetchStatus.js +35 -0
- package/js/test/Exchange/test.fetchTicker.js +38 -0
- package/js/test/Exchange/test.fetchTickers.js +49 -0
- package/js/test/Exchange/test.fetchTrades.js +39 -0
- package/js/test/Exchange/test.fetchTradingFee.js +18 -0
- package/js/test/Exchange/test.fetchTradingFees.js +22 -0
- package/js/test/Exchange/test.fetchTransactions.js +31 -0
- package/js/test/Exchange/test.fetchWithdrawals.js +31 -0
- package/js/test/Exchange/test.ledgerItem.js +46 -0
- package/js/test/Exchange/test.leverageTier.js +33 -0
- package/js/test/Exchange/test.loadMarkets.js +35 -0
- package/js/test/Exchange/test.market.js +129 -0
- package/js/test/Exchange/test.ohlcv.js +33 -0
- package/js/test/Exchange/test.order.js +62 -0
- package/js/test/Exchange/test.orderbook.js +61 -0
- package/js/test/Exchange/test.position.js +21 -0
- package/js/test/Exchange/test.throttle.js +94 -0
- package/js/test/Exchange/test.ticker.js +95 -0
- package/js/test/Exchange/test.trade.js +68 -0
- package/js/test/Exchange/test.tradingFee.js +34 -0
- package/js/test/Exchange/test.transaction.js +35 -0
- package/js/test/base/.eslintrc +38 -0
- package/js/test/base/functions/test.crypto.js +110 -0
- package/js/test/base/functions/test.datetime.js +62 -0
- package/js/test/base/functions/test.generic.js +152 -0
- package/js/test/base/functions/test.number.js +362 -0
- package/js/test/base/functions/test.time.js +56 -0
- package/js/test/base/functions/test.type.js +53 -0
- package/js/test/base/test.base.js +193 -0
- package/js/test/errors/test.InsufficientFunds.js +86 -0
- package/js/test/errors/test.InvalidNonce.js +64 -0
- package/js/test/errors/test.InvalidOrder.js +35 -0
- package/js/test/errors/test.OrderNotFound.js +39 -0
- package/js/test/test.js +426 -0
- package/js/test/test.timeout_hang.js +12 -0
- package/js/therock.js +1431 -0
- package/js/tidebit.js +632 -0
- package/js/tidex.js +939 -0
- package/js/timex.js +1283 -0
- package/js/upbit.js +1622 -0
- package/js/vcc.js +1353 -0
- package/js/wavesexchange.js +2185 -0
- package/js/wazirx.js +732 -0
- package/js/whitebit.js +1352 -0
- package/js/woo.js +1577 -0
- package/js/xena.js +1948 -0
- package/js/yobit.js +1129 -0
- package/js/zaif.js +647 -0
- package/js/zb.js +4088 -0
- package/js/zipmex.js +40 -0
- package/js/zonda.js +1497 -0
- package/multilang.sh +159 -0
- package/package.json +591 -0
- package/postinstall.js +103 -0
package/js/bitfinex.js
ADDED
@@ -0,0 +1,1433 @@
|
|
1
|
+
'use strict';
|
2
|
+
|
3
|
+
// ---------------------------------------------------------------------------
|
4
|
+
|
5
|
+
const Exchange = require ('./base/Exchange');
|
6
|
+
const { NotSupported, RateLimitExceeded, AuthenticationError, PermissionDenied, ArgumentsRequired, ExchangeError, ExchangeNotAvailable, InsufficientFunds, InvalidOrder, OrderNotFound, InvalidNonce, BadSymbol } = require ('./base/errors');
|
7
|
+
const { SIGNIFICANT_DIGITS, DECIMAL_PLACES, TRUNCATE, ROUND } = require ('./base/functions/number');
|
8
|
+
const Precise = require ('./base/Precise');
|
9
|
+
|
10
|
+
// ---------------------------------------------------------------------------
|
11
|
+
|
12
|
+
module.exports = class bitfinex extends Exchange {
|
13
|
+
describe () {
|
14
|
+
return this.deepExtend (super.describe (), {
|
15
|
+
'id': 'bitfinex',
|
16
|
+
'name': 'Bitfinex',
|
17
|
+
'countries': [ 'VG' ],
|
18
|
+
'version': 'v1',
|
19
|
+
// cheapest is 90 requests a minute = 1.5 requests per second on average => ( 1000ms / 1.5) = 666.666 ms between requests on average
|
20
|
+
'rateLimit': 666.666,
|
21
|
+
'pro': true,
|
22
|
+
// new metainfo interface
|
23
|
+
'has': {
|
24
|
+
'CORS': undefined,
|
25
|
+
'spot': true,
|
26
|
+
'margin': undefined, // has but unimplemented
|
27
|
+
'swap': undefined, // has but unimplemented
|
28
|
+
'future': undefined,
|
29
|
+
'option': undefined,
|
30
|
+
'cancelAllOrders': true,
|
31
|
+
'cancelOrder': true,
|
32
|
+
'createDepositAddress': true,
|
33
|
+
'createOrder': true,
|
34
|
+
'editOrder': true,
|
35
|
+
'fetchBalance': true,
|
36
|
+
'fetchClosedOrders': true,
|
37
|
+
'fetchDepositAddress': true,
|
38
|
+
'fetchDeposits': undefined,
|
39
|
+
'fetchFundingFees': true,
|
40
|
+
'fetchIndexOHLCV': false,
|
41
|
+
'fetchLeverageTiers': false,
|
42
|
+
'fetchMarkets': true,
|
43
|
+
'fetchMarkOHLCV': false,
|
44
|
+
'fetchMyTrades': true,
|
45
|
+
'fetchOHLCV': true,
|
46
|
+
'fetchOpenOrders': true,
|
47
|
+
'fetchOrder': true,
|
48
|
+
'fetchOrderBook': true,
|
49
|
+
'fetchPositions': true,
|
50
|
+
'fetchPremiumIndexOHLCV': false,
|
51
|
+
'fetchTicker': true,
|
52
|
+
'fetchTickers': true,
|
53
|
+
'fetchTime': false,
|
54
|
+
'fetchTrades': true,
|
55
|
+
'fetchTradingFee': false,
|
56
|
+
'fetchTradingFees': true,
|
57
|
+
'fetchTransactions': true,
|
58
|
+
'fetchWithdrawals': undefined,
|
59
|
+
'transfer': true,
|
60
|
+
'withdraw': true,
|
61
|
+
},
|
62
|
+
'timeframes': {
|
63
|
+
'1m': '1m',
|
64
|
+
'5m': '5m',
|
65
|
+
'15m': '15m',
|
66
|
+
'30m': '30m',
|
67
|
+
'1h': '1h',
|
68
|
+
'3h': '3h',
|
69
|
+
'4h': '4h',
|
70
|
+
'6h': '6h',
|
71
|
+
'12h': '12h',
|
72
|
+
'1d': '1D',
|
73
|
+
'1w': '7D',
|
74
|
+
'2w': '14D',
|
75
|
+
'1M': '1M',
|
76
|
+
},
|
77
|
+
'urls': {
|
78
|
+
'logo': 'https://user-images.githubusercontent.com/1294454/27766244-e328a50c-5ed2-11e7-947b-041416579bb3.jpg',
|
79
|
+
'api': {
|
80
|
+
'v2': 'https://api-pub.bitfinex.com', // https://github.com/ccxt/ccxt/issues/5109
|
81
|
+
'public': 'https://api.bitfinex.com',
|
82
|
+
'private': 'https://api.bitfinex.com',
|
83
|
+
},
|
84
|
+
'www': 'https://www.bitfinex.com',
|
85
|
+
'referral': 'https://www.bitfinex.com/?refcode=P61eYxFL',
|
86
|
+
'doc': [
|
87
|
+
'https://docs.bitfinex.com/v1/docs',
|
88
|
+
'https://github.com/bitfinexcom/bitfinex-api-node',
|
89
|
+
],
|
90
|
+
},
|
91
|
+
'api': {
|
92
|
+
// v2 symbol ids require a 't' prefix
|
93
|
+
// just the public part of it (use bitfinex2 for everything else)
|
94
|
+
'v2': {
|
95
|
+
'get': {
|
96
|
+
'platform/status': 3, // 30 requests per minute
|
97
|
+
'tickers': 1, // 90 requests a minute
|
98
|
+
'ticker/{symbol}': 1,
|
99
|
+
'tickers/hist': 1,
|
100
|
+
'trades/{symbol}/hist': 1,
|
101
|
+
'book/{symbol}/{precision}': 0.375, // 240 requests per minute = 4 requests per second (1000ms / rateLimit) / 4 = 0.37500375
|
102
|
+
'book/{symbol}/P0': 0.375,
|
103
|
+
'book/{symbol}/P1': 0.375,
|
104
|
+
'book/{symbol}/P2': 0.375,
|
105
|
+
'book/{symbol}/P3': 0.375,
|
106
|
+
'book/{symbol}/R0': 0.375,
|
107
|
+
'stats1/{key}:{size}:{symbol}:{side}/{section}': 1, // 90 requests a minute
|
108
|
+
'stats1/{key}:{size}:{symbol}/{section}': 1,
|
109
|
+
'stats1/{key}:{size}:{symbol}:long/last': 1,
|
110
|
+
'stats1/{key}:{size}:{symbol}:long/hist': 1,
|
111
|
+
'stats1/{key}:{size}:{symbol}:short/last': 1,
|
112
|
+
'stats1/{key}:{size}:{symbol}:short/hist': 1,
|
113
|
+
'candles/trade:{timeframe}:{symbol}/{section}': 1, // 90 requests a minute
|
114
|
+
'candles/trade:{timeframe}:{symbol}/last': 1,
|
115
|
+
'candles/trade:{timeframe}:{symbol}/hist': 1,
|
116
|
+
},
|
117
|
+
},
|
118
|
+
'public': {
|
119
|
+
'get': {
|
120
|
+
'book/{symbol}': 1, // 90 requests a minute
|
121
|
+
// 'candles/{symbol}':0,
|
122
|
+
'lendbook/{currency}': 6, // 15 requests a minute
|
123
|
+
'lends/{currency}': 3, // 30 requests a minute
|
124
|
+
'pubticker/{symbol}': 3, // 30 requests a minute = 0.5 requests per second => (1000ms / rateLimit) / 0.5 = 3.00003
|
125
|
+
'stats/{symbol}': 6, // 15 requests a minute = 0.25 requests per second => (1000ms / rateLimit ) /0.25 = 6.00006 (endpoint returns red html... or 'unknown symbol')
|
126
|
+
'symbols': 18, // 5 requests a minute = 0.08333 requests per second => (1000ms / rateLimit) / 0.08333 = 18.0009
|
127
|
+
'symbols_details': 18, // 5 requests a minute
|
128
|
+
'tickers': 1, // endpoint not mentioned in v1 docs... but still responds
|
129
|
+
'trades/{symbol}': 3, // 60 requests a minute = 1 request per second => (1000ms / rateLimit) / 1 = 1.5 ... but only works if set to 3
|
130
|
+
},
|
131
|
+
},
|
132
|
+
'private': {
|
133
|
+
'post': {
|
134
|
+
'account_fees': 18,
|
135
|
+
'account_infos': 6,
|
136
|
+
'balances': 9.036, // 10 requests a minute = 0.166 requests per second => (1000ms / rateLimit) / 0.166 = 9.036
|
137
|
+
'basket_manage': 6,
|
138
|
+
'credits': 6,
|
139
|
+
'deposit/new': 18,
|
140
|
+
'funding/close': 6,
|
141
|
+
'history': 6, // 15 requests a minute
|
142
|
+
'history/movements': 6,
|
143
|
+
'key_info': 6,
|
144
|
+
'margin_infos': 3, // 30 requests a minute
|
145
|
+
'mytrades': 3,
|
146
|
+
'mytrades_funding': 6,
|
147
|
+
'offer/cancel': 6,
|
148
|
+
'offer/new': 6,
|
149
|
+
'offer/status': 6,
|
150
|
+
'offers': 6,
|
151
|
+
'offers/hist': 90.03, // one request per minute
|
152
|
+
'order/cancel': 0.2,
|
153
|
+
'order/cancel/all': 0.2,
|
154
|
+
'order/cancel/multi': 0.2,
|
155
|
+
'order/cancel/replace': 0.2,
|
156
|
+
'order/new': 0.2, // 450 requests a minute = 7.5 request a second => (1000ms / rateLimit) / 7.5 = 0.2000002
|
157
|
+
'order/new/multi': 0.2,
|
158
|
+
'order/status': 0.2,
|
159
|
+
'orders': 0.2,
|
160
|
+
'orders/hist': 90.03, // one request per minute = 0.1666 => (1000ms / rateLimit) / 0.01666 = 90.03
|
161
|
+
'position/claim': 18,
|
162
|
+
'position/close': 18,
|
163
|
+
'positions': 18,
|
164
|
+
'summary': 18,
|
165
|
+
'taken_funds': 6,
|
166
|
+
'total_taken_funds': 6,
|
167
|
+
'transfer': 18,
|
168
|
+
'unused_taken_funds': 6,
|
169
|
+
'withdraw': 18,
|
170
|
+
},
|
171
|
+
},
|
172
|
+
},
|
173
|
+
'fees': {
|
174
|
+
'trading': {
|
175
|
+
'feeSide': 'get',
|
176
|
+
'tierBased': true,
|
177
|
+
'percentage': true,
|
178
|
+
'maker': this.parseNumber ('0.001'),
|
179
|
+
'taker': this.parseNumber ('0.002'),
|
180
|
+
'tiers': {
|
181
|
+
'taker': [
|
182
|
+
[ this.parseNumber ('0'), this.parseNumber ('0.002') ],
|
183
|
+
[ this.parseNumber ('500000'), this.parseNumber ('0.002') ],
|
184
|
+
[ this.parseNumber ('1000000'), this.parseNumber ('0.002') ],
|
185
|
+
[ this.parseNumber ('2500000'), this.parseNumber ('0.002') ],
|
186
|
+
[ this.parseNumber ('5000000'), this.parseNumber ('0.002') ],
|
187
|
+
[ this.parseNumber ('7500000'), this.parseNumber ('0.002') ],
|
188
|
+
[ this.parseNumber ('10000000'), this.parseNumber ('0.0018') ],
|
189
|
+
[ this.parseNumber ('15000000'), this.parseNumber ('0.0016') ],
|
190
|
+
[ this.parseNumber ('20000000'), this.parseNumber ('0.0014') ],
|
191
|
+
[ this.parseNumber ('25000000'), this.parseNumber ('0.0012') ],
|
192
|
+
[ this.parseNumber ('30000000'), this.parseNumber ('0.001') ],
|
193
|
+
],
|
194
|
+
'maker': [
|
195
|
+
[ this.parseNumber ('0'), this.parseNumber ('0.001') ],
|
196
|
+
[ this.parseNumber ('500000'), this.parseNumber ('0.0008') ],
|
197
|
+
[ this.parseNumber ('1000000'), this.parseNumber ('0.0006') ],
|
198
|
+
[ this.parseNumber ('2500000'), this.parseNumber ('0.0004') ],
|
199
|
+
[ this.parseNumber ('5000000'), this.parseNumber ('0.0002') ],
|
200
|
+
[ this.parseNumber ('7500000'), this.parseNumber ('0') ],
|
201
|
+
[ this.parseNumber ('10000000'), this.parseNumber ('0') ],
|
202
|
+
[ this.parseNumber ('15000000'), this.parseNumber ('0') ],
|
203
|
+
[ this.parseNumber ('20000000'), this.parseNumber ('0') ],
|
204
|
+
[ this.parseNumber ('25000000'), this.parseNumber ('0') ],
|
205
|
+
[ this.parseNumber ('30000000'), this.parseNumber ('0') ],
|
206
|
+
],
|
207
|
+
},
|
208
|
+
},
|
209
|
+
'funding': {
|
210
|
+
'tierBased': false, // true for tier-based/progressive
|
211
|
+
'percentage': false, // fixed commission
|
212
|
+
// Actually deposit fees are free for larger deposits (> $1000 USD equivalent)
|
213
|
+
// these values below are deprecated, we should not hardcode fees and limits anymore
|
214
|
+
// to be reimplemented with bitfinex funding fees from their API or web endpoints
|
215
|
+
'deposit': {},
|
216
|
+
'withdraw': {},
|
217
|
+
},
|
218
|
+
},
|
219
|
+
// todo rewrite for https://api-pub.bitfinex.com//v2/conf/pub:map:tx:method
|
220
|
+
'commonCurrencies': {
|
221
|
+
'ALG': 'ALGO', // https://github.com/ccxt/ccxt/issues/6034
|
222
|
+
'AMP': 'AMPL',
|
223
|
+
'ATO': 'ATOM', // https://github.com/ccxt/ccxt/issues/5118
|
224
|
+
'BCHABC': 'XEC',
|
225
|
+
'BCHN': 'BCH',
|
226
|
+
'DAT': 'DATA',
|
227
|
+
'DOG': 'MDOGE',
|
228
|
+
'DSH': 'DASH',
|
229
|
+
// https://github.com/ccxt/ccxt/issues/7399
|
230
|
+
// https://coinmarketcap.com/currencies/pnetwork/
|
231
|
+
// https://en.cryptonomist.ch/blog/eidoo/the-edo-to-pnt-upgrade-what-you-need-to-know-updated/
|
232
|
+
'EDO': 'PNT',
|
233
|
+
'EUS': 'EURS',
|
234
|
+
'EUT': 'EURT',
|
235
|
+
'IDX': 'ID',
|
236
|
+
'IOT': 'IOTA',
|
237
|
+
'IQX': 'IQ',
|
238
|
+
'MNA': 'MANA',
|
239
|
+
'ORS': 'ORS Group', // conflict with Origin Sport #3230
|
240
|
+
'PAS': 'PASS',
|
241
|
+
'QSH': 'QASH',
|
242
|
+
'QTM': 'QTUM',
|
243
|
+
'RBT': 'RBTC',
|
244
|
+
'SNG': 'SNGLS',
|
245
|
+
'STJ': 'STORJ',
|
246
|
+
'TERRAUST': 'UST',
|
247
|
+
'TSD': 'TUSD',
|
248
|
+
'YGG': 'YEED', // conflict with Yield Guild Games
|
249
|
+
'YYW': 'YOYOW',
|
250
|
+
'UDC': 'USDC',
|
251
|
+
'UST': 'USDT',
|
252
|
+
'VSY': 'VSYS',
|
253
|
+
'WAX': 'WAXP',
|
254
|
+
'XCH': 'XCHF',
|
255
|
+
'ZBT': 'ZB',
|
256
|
+
},
|
257
|
+
'exceptions': {
|
258
|
+
'exact': {
|
259
|
+
'temporarily_unavailable': ExchangeNotAvailable, // Sorry, the service is temporarily unavailable. See https://www.bitfinex.com/ for more info.
|
260
|
+
'Order could not be cancelled.': OrderNotFound, // non-existent order
|
261
|
+
'No such order found.': OrderNotFound, // ?
|
262
|
+
'Order price must be positive.': InvalidOrder, // on price <= 0
|
263
|
+
'Could not find a key matching the given X-BFX-APIKEY.': AuthenticationError,
|
264
|
+
'Key price should be a decimal number, e.g. "123.456"': InvalidOrder, // on isNaN (price)
|
265
|
+
'Key amount should be a decimal number, e.g. "123.456"': InvalidOrder, // on isNaN (amount)
|
266
|
+
'ERR_RATE_LIMIT': RateLimitExceeded,
|
267
|
+
'Ratelimit': RateLimitExceeded,
|
268
|
+
'Nonce is too small.': InvalidNonce,
|
269
|
+
'No summary found.': ExchangeError, // fetchTradingFees (summary) endpoint can give this vague error message
|
270
|
+
'Cannot evaluate your available balance, please try again': ExchangeNotAvailable,
|
271
|
+
'Unknown symbol': BadSymbol,
|
272
|
+
'Cannot complete transfer. Exchange balance insufficient.': InsufficientFunds,
|
273
|
+
'Momentary balance check. Please wait few seconds and try the transfer again.': ExchangeError,
|
274
|
+
},
|
275
|
+
'broad': {
|
276
|
+
'Invalid X-BFX-SIGNATURE': AuthenticationError,
|
277
|
+
'This API key does not have permission': PermissionDenied, // authenticated but not authorized
|
278
|
+
'not enough exchange balance for ': InsufficientFunds, // when buying cost is greater than the available quote currency
|
279
|
+
'minimum size for ': InvalidOrder, // when amount below limits.amount.min
|
280
|
+
'Invalid order': InvalidOrder, // ?
|
281
|
+
'The available balance is only': InsufficientFunds, // {"status":"error","message":"Cannot withdraw 1.0027 ETH from your exchange wallet. The available balance is only 0.0 ETH. If you have limit orders, open positions, unused or active margin funding, this will decrease your available balance. To increase it, you can cancel limit orders or reduce/close your positions.","withdrawal_id":0,"fees":"0.0027"}
|
282
|
+
},
|
283
|
+
},
|
284
|
+
'precisionMode': SIGNIFICANT_DIGITS,
|
285
|
+
'options': {
|
286
|
+
'currencyNames': {
|
287
|
+
'AGI': 'agi',
|
288
|
+
'AID': 'aid',
|
289
|
+
'AIO': 'aio',
|
290
|
+
'ANT': 'ant',
|
291
|
+
'AVT': 'aventus', // #1811
|
292
|
+
'BAT': 'bat',
|
293
|
+
// https://github.com/ccxt/ccxt/issues/5833
|
294
|
+
'BCH': 'bab', // undocumented
|
295
|
+
// 'BCH': 'bcash', // undocumented
|
296
|
+
'BCI': 'bci',
|
297
|
+
'BFT': 'bft',
|
298
|
+
'BSV': 'bsv',
|
299
|
+
'BTC': 'bitcoin',
|
300
|
+
'BTG': 'bgold',
|
301
|
+
'CFI': 'cfi',
|
302
|
+
'COMP': 'comp',
|
303
|
+
'DAI': 'dai',
|
304
|
+
'DADI': 'dad',
|
305
|
+
'DASH': 'dash',
|
306
|
+
'DATA': 'datacoin',
|
307
|
+
'DTH': 'dth',
|
308
|
+
'EDO': 'eidoo', // #1811
|
309
|
+
'ELF': 'elf',
|
310
|
+
'EOS': 'eos',
|
311
|
+
'ETC': 'ethereumc',
|
312
|
+
'ETH': 'ethereum',
|
313
|
+
'ETP': 'metaverse',
|
314
|
+
'FUN': 'fun',
|
315
|
+
'GNT': 'golem',
|
316
|
+
'IOST': 'ios',
|
317
|
+
'IOTA': 'iota',
|
318
|
+
// https://github.com/ccxt/ccxt/issues/5833
|
319
|
+
'LEO': 'let', // ETH chain
|
320
|
+
// 'LEO': 'les', // EOS chain
|
321
|
+
'LINK': 'link',
|
322
|
+
'LRC': 'lrc',
|
323
|
+
'LTC': 'litecoin',
|
324
|
+
'LYM': 'lym',
|
325
|
+
'MANA': 'mna',
|
326
|
+
'MIT': 'mit',
|
327
|
+
'MKR': 'mkr',
|
328
|
+
'MTN': 'mtn',
|
329
|
+
'NEO': 'neo',
|
330
|
+
'ODE': 'ode',
|
331
|
+
'OMG': 'omisego',
|
332
|
+
'OMNI': 'mastercoin',
|
333
|
+
'QASH': 'qash',
|
334
|
+
'QTUM': 'qtum', // #1811
|
335
|
+
'RCN': 'rcn',
|
336
|
+
'RDN': 'rdn',
|
337
|
+
'REP': 'rep',
|
338
|
+
'REQ': 'req',
|
339
|
+
'RLC': 'rlc',
|
340
|
+
'SAN': 'santiment',
|
341
|
+
'SNGLS': 'sng',
|
342
|
+
'SNT': 'status',
|
343
|
+
'SPANK': 'spk',
|
344
|
+
'STORJ': 'stj',
|
345
|
+
'TNB': 'tnb',
|
346
|
+
'TRX': 'trx',
|
347
|
+
'TUSD': 'tsd',
|
348
|
+
'USD': 'wire',
|
349
|
+
'USDC': 'udc', // https://github.com/ccxt/ccxt/issues/5833
|
350
|
+
'UTK': 'utk',
|
351
|
+
'USDT': 'tetheruso', // Tether on Omni
|
352
|
+
// 'USDT': 'tetheruse', // Tether on ERC20
|
353
|
+
// 'USDT': 'tetherusl', // Tether on Liquid
|
354
|
+
// 'USDT': 'tetherusx', // Tether on Tron
|
355
|
+
// 'USDT': 'tetheruss', // Tether on EOS
|
356
|
+
'VEE': 'vee',
|
357
|
+
'WAX': 'wax',
|
358
|
+
'XLM': 'xlm',
|
359
|
+
'XMR': 'monero',
|
360
|
+
'XRP': 'ripple',
|
361
|
+
'XVG': 'xvg',
|
362
|
+
'YOYOW': 'yoyow',
|
363
|
+
'ZEC': 'zcash',
|
364
|
+
'ZRX': 'zrx',
|
365
|
+
'XTZ': 'xtz',
|
366
|
+
},
|
367
|
+
'orderTypes': {
|
368
|
+
'limit': 'exchange limit',
|
369
|
+
'market': 'exchange market',
|
370
|
+
},
|
371
|
+
'fiat': {
|
372
|
+
'USD': 'USD',
|
373
|
+
'EUR': 'EUR',
|
374
|
+
'JPY': 'JPY',
|
375
|
+
'GBP': 'GBP',
|
376
|
+
'CNH': 'CNH',
|
377
|
+
},
|
378
|
+
'accountsByType': {
|
379
|
+
'spot': 'exchange',
|
380
|
+
'margin': 'trading',
|
381
|
+
'funding': 'deposit',
|
382
|
+
'swap': 'trading',
|
383
|
+
},
|
384
|
+
},
|
385
|
+
});
|
386
|
+
}
|
387
|
+
|
388
|
+
async fetchFundingFees (params = {}) {
|
389
|
+
await this.loadMarkets ();
|
390
|
+
const response = await this.privatePostAccountFees (params);
|
391
|
+
const fees = response['withdraw'];
|
392
|
+
const withdraw = {};
|
393
|
+
const ids = Object.keys (fees);
|
394
|
+
for (let i = 0; i < ids.length; i++) {
|
395
|
+
const id = ids[i];
|
396
|
+
const code = this.safeCurrencyCode (id);
|
397
|
+
withdraw[code] = this.safeNumber (fees, id);
|
398
|
+
}
|
399
|
+
return {
|
400
|
+
'info': response,
|
401
|
+
'withdraw': withdraw,
|
402
|
+
'deposit': withdraw, // only for deposits of less than $1000
|
403
|
+
};
|
404
|
+
}
|
405
|
+
|
406
|
+
async fetchTradingFees (params = {}) {
|
407
|
+
await this.loadMarkets ();
|
408
|
+
const response = await this.privatePostSummary (params);
|
409
|
+
//
|
410
|
+
// {
|
411
|
+
// time: '2022-02-23T16:05:47.659000Z',
|
412
|
+
// status: { resid_hint: null, login_last: '2022-02-23T16:05:48Z' },
|
413
|
+
// is_locked: false,
|
414
|
+
// leo_lev: '0',
|
415
|
+
// leo_amount_avg: '0.0',
|
416
|
+
// trade_vol_30d: [
|
417
|
+
// {
|
418
|
+
// curr: 'Total (USD)',
|
419
|
+
// vol: '0.0',
|
420
|
+
// vol_safe: '0.0',
|
421
|
+
// vol_maker: '0.0',
|
422
|
+
// vol_BFX: '0.0',
|
423
|
+
// vol_BFX_safe: '0.0',
|
424
|
+
// vol_BFX_maker: '0.0'
|
425
|
+
// }
|
426
|
+
// ],
|
427
|
+
// fees_funding_30d: {},
|
428
|
+
// fees_funding_total_30d: '0',
|
429
|
+
// fees_trading_30d: {},
|
430
|
+
// fees_trading_total_30d: '0',
|
431
|
+
// rebates_trading_30d: {},
|
432
|
+
// rebates_trading_total_30d: '0',
|
433
|
+
// maker_fee: '0.001',
|
434
|
+
// taker_fee: '0.002',
|
435
|
+
// maker_fee_2crypto: '0.001',
|
436
|
+
// maker_fee_2stablecoin: '0.001',
|
437
|
+
// maker_fee_2fiat: '0.001',
|
438
|
+
// maker_fee_2deriv: '0.0002',
|
439
|
+
// taker_fee_2crypto: '0.002',
|
440
|
+
// taker_fee_2stablecoin: '0.002',
|
441
|
+
// taker_fee_2fiat: '0.002',
|
442
|
+
// taker_fee_2deriv: '0.00065',
|
443
|
+
// deriv_maker_rebate: '0.0002',
|
444
|
+
// deriv_taker_fee: '0.00065',
|
445
|
+
// trade_last: null
|
446
|
+
// }
|
447
|
+
//
|
448
|
+
const result = {};
|
449
|
+
const fiat = this.safeValue (this.options, 'fiat', {});
|
450
|
+
const makerFee = this.safeNumber (response, 'maker_fee');
|
451
|
+
const takerFee = this.safeNumber (response, 'taker_fee');
|
452
|
+
const makerFee2Fiat = this.safeNumber (response, 'maker_fee_2fiat');
|
453
|
+
const takerFee2Fiat = this.safeNumber (response, 'taker_fee_2fiat');
|
454
|
+
const makerFee2Deriv = this.safeNumber (response, 'maker_fee_2deriv');
|
455
|
+
const takerFee2Deriv = this.safeNumber (response, 'taker_fee_2deriv');
|
456
|
+
for (let i = 0; i < this.symbols.length; i++) {
|
457
|
+
const symbol = this.symbols[i];
|
458
|
+
const market = this.market (symbol);
|
459
|
+
const fee = {
|
460
|
+
'info': response,
|
461
|
+
'symbol': symbol,
|
462
|
+
'percentage': true,
|
463
|
+
'tierBased': true,
|
464
|
+
};
|
465
|
+
if (market['quote'] in fiat) {
|
466
|
+
fee['maker'] = makerFee2Fiat;
|
467
|
+
fee['taker'] = takerFee2Fiat;
|
468
|
+
} else if (market['contract']) {
|
469
|
+
fee['maker'] = makerFee2Deriv;
|
470
|
+
fee['taker'] = takerFee2Deriv;
|
471
|
+
} else {
|
472
|
+
fee['maker'] = makerFee;
|
473
|
+
fee['taker'] = takerFee;
|
474
|
+
}
|
475
|
+
result[symbol] = fee;
|
476
|
+
}
|
477
|
+
return result;
|
478
|
+
}
|
479
|
+
|
480
|
+
async fetchMarkets (params = {}) {
|
481
|
+
const ids = await this.publicGetSymbols ();
|
482
|
+
//
|
483
|
+
// [ "btcusd", "ltcusd", "ltcbtc" ]
|
484
|
+
//
|
485
|
+
const details = await this.publicGetSymbolsDetails ();
|
486
|
+
//
|
487
|
+
// [
|
488
|
+
// {
|
489
|
+
// "pair":"btcusd",
|
490
|
+
// "price_precision":5,
|
491
|
+
// "initial_margin":"10.0",
|
492
|
+
// "minimum_margin":"5.0",
|
493
|
+
// "maximum_order_size":"2000.0",
|
494
|
+
// "minimum_order_size":"0.0002",
|
495
|
+
// "expiration":"NA",
|
496
|
+
// "margin":true
|
497
|
+
// },
|
498
|
+
// ]
|
499
|
+
//
|
500
|
+
const result = [];
|
501
|
+
for (let i = 0; i < details.length; i++) {
|
502
|
+
const market = details[i];
|
503
|
+
let id = this.safeString (market, 'pair');
|
504
|
+
if (!this.inArray (id, ids)) {
|
505
|
+
continue;
|
506
|
+
}
|
507
|
+
id = id.toUpperCase ();
|
508
|
+
let baseId = undefined;
|
509
|
+
let quoteId = undefined;
|
510
|
+
if (id.indexOf (':') >= 0) {
|
511
|
+
const parts = id.split (':');
|
512
|
+
baseId = parts[0];
|
513
|
+
quoteId = parts[1];
|
514
|
+
} else {
|
515
|
+
baseId = id.slice (0, 3);
|
516
|
+
quoteId = id.slice (3, 6);
|
517
|
+
}
|
518
|
+
const base = this.safeCurrencyCode (baseId);
|
519
|
+
const quote = this.safeCurrencyCode (quoteId);
|
520
|
+
result.push ({
|
521
|
+
'id': id,
|
522
|
+
'symbol': base + '/' + quote,
|
523
|
+
'base': base,
|
524
|
+
'quote': quote,
|
525
|
+
'settle': undefined,
|
526
|
+
'baseId': baseId,
|
527
|
+
'quoteId': quoteId,
|
528
|
+
'settleId': undefined,
|
529
|
+
'type': 'spot',
|
530
|
+
'spot': true,
|
531
|
+
'margin': this.safeValue (market, 'margin'),
|
532
|
+
'swap': false,
|
533
|
+
'future': false,
|
534
|
+
'option': false,
|
535
|
+
'active': true,
|
536
|
+
'contract': false,
|
537
|
+
'linear': undefined,
|
538
|
+
'inverse': undefined,
|
539
|
+
'contractSize': undefined,
|
540
|
+
'expiry': undefined,
|
541
|
+
'expiryDatetime': undefined,
|
542
|
+
'strike': undefined,
|
543
|
+
'optionType': undefined,
|
544
|
+
'precision': {
|
545
|
+
// https://docs.bitfinex.com/docs/introduction#amount-precision
|
546
|
+
// The amount field allows up to 8 decimals.
|
547
|
+
// Anything exceeding this will be rounded to the 8th decimal.
|
548
|
+
'amount': parseInt ('8'),
|
549
|
+
'price': this.safeInteger (market, 'price_precision'),
|
550
|
+
},
|
551
|
+
'limits': {
|
552
|
+
'leverage': {
|
553
|
+
'min': undefined,
|
554
|
+
'max': undefined,
|
555
|
+
},
|
556
|
+
'amount': {
|
557
|
+
'min': this.safeNumber (market, 'minimum_order_size'),
|
558
|
+
'max': this.safeNumber (market, 'maximum_order_size'),
|
559
|
+
},
|
560
|
+
'price': {
|
561
|
+
'min': this.parseNumber ('1e-8'),
|
562
|
+
'max': undefined,
|
563
|
+
},
|
564
|
+
'cost': {
|
565
|
+
'min': undefined,
|
566
|
+
'max': undefined,
|
567
|
+
},
|
568
|
+
},
|
569
|
+
'info': market,
|
570
|
+
});
|
571
|
+
}
|
572
|
+
return result;
|
573
|
+
}
|
574
|
+
|
575
|
+
amountToPrecision (symbol, amount) {
|
576
|
+
// https://docs.bitfinex.com/docs/introduction#amount-precision
|
577
|
+
// The amount field allows up to 8 decimals.
|
578
|
+
// Anything exceeding this will be rounded to the 8th decimal.
|
579
|
+
return this.decimalToPrecision (amount, TRUNCATE, this.markets[symbol]['precision']['amount'], DECIMAL_PLACES);
|
580
|
+
}
|
581
|
+
|
582
|
+
priceToPrecision (symbol, price) {
|
583
|
+
price = this.decimalToPrecision (price, ROUND, this.markets[symbol]['precision']['price'], this.precisionMode);
|
584
|
+
// https://docs.bitfinex.com/docs/introduction#price-precision
|
585
|
+
// The precision level of all trading prices is based on significant figures.
|
586
|
+
// 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).
|
587
|
+
// Prices submit with a precision larger than 5 will be cut by the API.
|
588
|
+
return this.decimalToPrecision (price, TRUNCATE, 8, DECIMAL_PLACES);
|
589
|
+
}
|
590
|
+
|
591
|
+
async fetchBalance (params = {}) {
|
592
|
+
await this.loadMarkets ();
|
593
|
+
const accountsByType = this.safeValue (this.options, 'accountsByType', {});
|
594
|
+
const requestedType = this.safeString (params, 'type', 'exchange');
|
595
|
+
const accountType = this.safeString (accountsByType, requestedType, requestedType);
|
596
|
+
if (accountType === undefined) {
|
597
|
+
const keys = Object.keys (accountsByType);
|
598
|
+
throw new ExchangeError (this.id + ' fetchBalance() type parameter must be one of ' + keys.join (', '));
|
599
|
+
}
|
600
|
+
const query = this.omit (params, 'type');
|
601
|
+
const response = await this.privatePostBalances (query);
|
602
|
+
// [ { type: 'deposit',
|
603
|
+
// currency: 'btc',
|
604
|
+
// amount: '0.00116721',
|
605
|
+
// available: '0.00116721' },
|
606
|
+
// { type: 'exchange',
|
607
|
+
// currency: 'ust',
|
608
|
+
// amount: '0.0000002',
|
609
|
+
// available: '0.0000002' },
|
610
|
+
// { type: 'trading',
|
611
|
+
// currency: 'btc',
|
612
|
+
// amount: '0.0005',
|
613
|
+
// available: '0.0005' } ],
|
614
|
+
const result = { 'info': response };
|
615
|
+
const isDerivative = requestedType === 'derivatives';
|
616
|
+
for (let i = 0; i < response.length; i++) {
|
617
|
+
const balance = response[i];
|
618
|
+
const type = this.safeString (balance, 'type');
|
619
|
+
const currencyId = this.safeStringLower (balance, 'currency', '');
|
620
|
+
const start = currencyId.length - 2;
|
621
|
+
const isDerivativeCode = currencyId.slice (start) === 'f0';
|
622
|
+
// this will only filter the derivative codes if the requestedType is 'derivatives'
|
623
|
+
const derivativeCondition = (!isDerivative || isDerivativeCode);
|
624
|
+
if ((accountType === type) && derivativeCondition) {
|
625
|
+
const code = this.safeCurrencyCode (currencyId);
|
626
|
+
// bitfinex had BCH previously, now it's BAB, but the old
|
627
|
+
// BCH symbol is kept for backward-compatibility
|
628
|
+
// we need a workaround here so that the old BCH balance
|
629
|
+
// would not override the new BAB balance (BAB is unified to BCH)
|
630
|
+
// https://github.com/ccxt/ccxt/issues/4989
|
631
|
+
if (!(code in result)) {
|
632
|
+
const account = this.account ();
|
633
|
+
account['free'] = this.safeString (balance, 'available');
|
634
|
+
account['total'] = this.safeString (balance, 'amount');
|
635
|
+
result[code] = account;
|
636
|
+
}
|
637
|
+
}
|
638
|
+
}
|
639
|
+
return this.safeBalance (result);
|
640
|
+
}
|
641
|
+
|
642
|
+
async transfer (code, amount, fromAccount, toAccount, params = {}) {
|
643
|
+
// transferring between derivatives wallet and regular wallet is not documented in their API
|
644
|
+
// however we support it in CCXT (from just looking at web inspector)
|
645
|
+
await this.loadMarkets ();
|
646
|
+
const accountsByType = this.safeValue (this.options, 'accountsByType', {});
|
647
|
+
const fromId = this.safeString (accountsByType, fromAccount, fromAccount);
|
648
|
+
const toId = this.safeString (accountsByType, toAccount, toAccount);
|
649
|
+
const currency = this.currency (code);
|
650
|
+
const fromCurrencyId = this.convertDerivativesId (currency['id'], fromAccount);
|
651
|
+
const toCurrencyId = this.convertDerivativesId (currency['id'], toAccount);
|
652
|
+
const requestedAmount = this.currencyToPrecision (code, amount);
|
653
|
+
const request = {
|
654
|
+
'amount': requestedAmount,
|
655
|
+
'currency': fromCurrencyId,
|
656
|
+
'currency_to': toCurrencyId,
|
657
|
+
'walletfrom': fromId,
|
658
|
+
'walletto': toId,
|
659
|
+
};
|
660
|
+
const response = await this.privatePostTransfer (this.extend (request, params));
|
661
|
+
//
|
662
|
+
// [
|
663
|
+
// {
|
664
|
+
// status: 'success',
|
665
|
+
// message: '0.0001 Bitcoin transfered from Margin to Exchange'
|
666
|
+
// }
|
667
|
+
// ]
|
668
|
+
//
|
669
|
+
const result = this.safeValue (response, 0);
|
670
|
+
const message = this.safeString (result, 'message');
|
671
|
+
if (message === undefined) {
|
672
|
+
throw new ExchangeError (this.id + ' transfer failed');
|
673
|
+
}
|
674
|
+
return this.extend (this.parseTransfer (result, currency), {
|
675
|
+
'fromAccount': fromAccount,
|
676
|
+
'toAccount': toAccount,
|
677
|
+
'amount': this.parseNumber (requestedAmount),
|
678
|
+
});
|
679
|
+
}
|
680
|
+
|
681
|
+
parseTransfer (transfer, currency = undefined) {
|
682
|
+
//
|
683
|
+
// {
|
684
|
+
// status: 'success',
|
685
|
+
// message: '0.0001 Bitcoin transfered from Margin to Exchange'
|
686
|
+
// }
|
687
|
+
//
|
688
|
+
const timestamp = this.milliseconds ();
|
689
|
+
return {
|
690
|
+
'info': transfer,
|
691
|
+
'id': undefined,
|
692
|
+
'timestamp': timestamp,
|
693
|
+
'datetime': this.iso8601 (timestamp),
|
694
|
+
'currency': this.safeCurrencyCode (undefined, currency),
|
695
|
+
'amount': undefined,
|
696
|
+
'fromAccount': undefined,
|
697
|
+
'toAccount': undefined,
|
698
|
+
'status': this.parseTransferStatus (this.safeString (transfer, 'status')),
|
699
|
+
};
|
700
|
+
}
|
701
|
+
|
702
|
+
parseTransferStatus (status) {
|
703
|
+
const statuses = {
|
704
|
+
'SUCCESS': 'ok',
|
705
|
+
};
|
706
|
+
return this.safeString (statuses, status, status);
|
707
|
+
}
|
708
|
+
|
709
|
+
convertDerivativesId (currencyId, type) {
|
710
|
+
const start = currencyId.length - 2;
|
711
|
+
const isDerivativeCode = currencyId.slice (start) === 'F0';
|
712
|
+
if ((type !== 'derivatives' && type !== 'trading' && type !== 'margin') && isDerivativeCode) {
|
713
|
+
currencyId = currencyId.slice (0, start);
|
714
|
+
} else if (type === 'derivatives' && !isDerivativeCode) {
|
715
|
+
currencyId = currencyId + 'F0';
|
716
|
+
}
|
717
|
+
return currencyId;
|
718
|
+
}
|
719
|
+
|
720
|
+
async fetchOrderBook (symbol, limit = undefined, params = {}) {
|
721
|
+
await this.loadMarkets ();
|
722
|
+
const request = {
|
723
|
+
'symbol': this.marketId (symbol),
|
724
|
+
};
|
725
|
+
if (limit !== undefined) {
|
726
|
+
request['limit_bids'] = limit;
|
727
|
+
request['limit_asks'] = limit;
|
728
|
+
}
|
729
|
+
const response = await this.publicGetBookSymbol (this.extend (request, params));
|
730
|
+
return this.parseOrderBook (response, symbol, undefined, 'bids', 'asks', 'price', 'amount');
|
731
|
+
}
|
732
|
+
|
733
|
+
async fetchTickers (symbols = undefined, params = {}) {
|
734
|
+
await this.loadMarkets ();
|
735
|
+
const response = await this.publicGetTickers (params);
|
736
|
+
const result = {};
|
737
|
+
for (let i = 0; i < response.length; i++) {
|
738
|
+
const ticker = this.parseTicker (response[i]);
|
739
|
+
const symbol = ticker['symbol'];
|
740
|
+
result[symbol] = ticker;
|
741
|
+
}
|
742
|
+
return this.filterByArray (result, 'symbol', symbols);
|
743
|
+
}
|
744
|
+
|
745
|
+
async fetchTicker (symbol, params = {}) {
|
746
|
+
await this.loadMarkets ();
|
747
|
+
const market = this.market (symbol);
|
748
|
+
const request = {
|
749
|
+
'symbol': market['id'],
|
750
|
+
};
|
751
|
+
const ticker = await this.publicGetPubtickerSymbol (this.extend (request, params));
|
752
|
+
return this.parseTicker (ticker, market);
|
753
|
+
}
|
754
|
+
|
755
|
+
parseTicker (ticker, market = undefined) {
|
756
|
+
const timestamp = this.safeTimestamp (ticker, 'timestamp');
|
757
|
+
let symbol = undefined;
|
758
|
+
if (market !== undefined) {
|
759
|
+
symbol = market['symbol'];
|
760
|
+
} else if ('pair' in ticker) {
|
761
|
+
const marketId = this.safeString (ticker, 'pair');
|
762
|
+
if (marketId !== undefined) {
|
763
|
+
if (marketId in this.markets_by_id) {
|
764
|
+
market = this.markets_by_id[marketId];
|
765
|
+
symbol = market['symbol'];
|
766
|
+
} else {
|
767
|
+
const baseId = marketId.slice (0, 3);
|
768
|
+
const quoteId = marketId.slice (3, 6);
|
769
|
+
const base = this.safeCurrencyCode (baseId);
|
770
|
+
const quote = this.safeCurrencyCode (quoteId);
|
771
|
+
symbol = base + '/' + quote;
|
772
|
+
}
|
773
|
+
}
|
774
|
+
}
|
775
|
+
const last = this.safeString (ticker, 'last_price');
|
776
|
+
return this.safeTicker ({
|
777
|
+
'symbol': symbol,
|
778
|
+
'timestamp': timestamp,
|
779
|
+
'datetime': this.iso8601 (timestamp),
|
780
|
+
'high': this.safeString (ticker, 'high'),
|
781
|
+
'low': this.safeString (ticker, 'low'),
|
782
|
+
'bid': this.safeString (ticker, 'bid'),
|
783
|
+
'bidVolume': undefined,
|
784
|
+
'ask': this.safeString (ticker, 'ask'),
|
785
|
+
'askVolume': undefined,
|
786
|
+
'vwap': undefined,
|
787
|
+
'open': undefined,
|
788
|
+
'close': last,
|
789
|
+
'last': last,
|
790
|
+
'previousClose': undefined,
|
791
|
+
'change': undefined,
|
792
|
+
'percentage': undefined,
|
793
|
+
'average': this.safeString (ticker, 'mid'),
|
794
|
+
'baseVolume': this.safeString (ticker, 'volume'),
|
795
|
+
'quoteVolume': undefined,
|
796
|
+
'info': ticker,
|
797
|
+
}, market, false);
|
798
|
+
}
|
799
|
+
|
800
|
+
parseTrade (trade, market = undefined) {
|
801
|
+
//
|
802
|
+
// fetchTrades (public) v1
|
803
|
+
//
|
804
|
+
// {
|
805
|
+
// "timestamp":1637258380,
|
806
|
+
// "tid":894452833,
|
807
|
+
// "price":"0.99941",
|
808
|
+
// "amount":"261.38",
|
809
|
+
// "exchange":"bitfinex",
|
810
|
+
// "type":"sell"
|
811
|
+
// }
|
812
|
+
//
|
813
|
+
// { "timestamp":1637258238,
|
814
|
+
// "tid":894452800,
|
815
|
+
// "price":"0.99958",
|
816
|
+
// "amount":"261.90514",
|
817
|
+
// "exchange":"bitfinex",
|
818
|
+
// "type":"buy"
|
819
|
+
// }
|
820
|
+
//
|
821
|
+
// fetchMyTrades (private) v1
|
822
|
+
//
|
823
|
+
// {
|
824
|
+
// "price":"0.99941",
|
825
|
+
// "amount":"261.38",
|
826
|
+
// "timestamp":"1637258380.0",
|
827
|
+
// "type":"Sell",
|
828
|
+
// "fee_currency":"UST",
|
829
|
+
// "fee_amount":"-0.52245157",
|
830
|
+
// "tid":894452833,
|
831
|
+
// "order_id":78819731373
|
832
|
+
// }
|
833
|
+
//
|
834
|
+
// {
|
835
|
+
// "price":"0.99958",
|
836
|
+
// "amount":"261.90514",
|
837
|
+
// "timestamp":"1637258238.0",
|
838
|
+
// "type":"Buy",
|
839
|
+
// "fee_currency":"UDC",
|
840
|
+
// "fee_amount":"-0.52381028",
|
841
|
+
// "tid":894452800,
|
842
|
+
// "order_id":78819504838
|
843
|
+
// }
|
844
|
+
//
|
845
|
+
const id = this.safeString (trade, 'tid');
|
846
|
+
const timestamp = this.safeTimestamp (trade, 'timestamp');
|
847
|
+
const type = undefined;
|
848
|
+
const side = this.safeStringLower (trade, 'type');
|
849
|
+
const orderId = this.safeString (trade, 'order_id');
|
850
|
+
const priceString = this.safeString (trade, 'price');
|
851
|
+
const amountString = this.safeString (trade, 'amount');
|
852
|
+
let fee = undefined;
|
853
|
+
if ('fee_amount' in trade) {
|
854
|
+
const feeCostString = Precise.stringNeg (this.safeString (trade, 'fee_amount'));
|
855
|
+
const feeCurrencyId = this.safeString (trade, 'fee_currency');
|
856
|
+
const feeCurrencyCode = this.safeCurrencyCode (feeCurrencyId);
|
857
|
+
fee = {
|
858
|
+
'cost': feeCostString,
|
859
|
+
'currency': feeCurrencyCode,
|
860
|
+
};
|
861
|
+
}
|
862
|
+
return this.safeTrade ({
|
863
|
+
'id': id,
|
864
|
+
'info': trade,
|
865
|
+
'timestamp': timestamp,
|
866
|
+
'datetime': this.iso8601 (timestamp),
|
867
|
+
'symbol': market['symbol'],
|
868
|
+
'type': type,
|
869
|
+
'order': orderId,
|
870
|
+
'side': side,
|
871
|
+
'takerOrMaker': undefined,
|
872
|
+
'price': priceString,
|
873
|
+
'amount': amountString,
|
874
|
+
'cost': undefined,
|
875
|
+
'fee': fee,
|
876
|
+
}, market);
|
877
|
+
}
|
878
|
+
|
879
|
+
async fetchTrades (symbol, since = undefined, limit = 50, params = {}) {
|
880
|
+
await this.loadMarkets ();
|
881
|
+
const market = this.market (symbol);
|
882
|
+
const request = {
|
883
|
+
'symbol': market['id'],
|
884
|
+
'limit_trades': limit,
|
885
|
+
};
|
886
|
+
if (since !== undefined) {
|
887
|
+
request['timestamp'] = parseInt (since / 1000);
|
888
|
+
}
|
889
|
+
const response = await this.publicGetTradesSymbol (this.extend (request, params));
|
890
|
+
return this.parseTrades (response, market, since, limit);
|
891
|
+
}
|
892
|
+
|
893
|
+
async fetchMyTrades (symbol = undefined, since = undefined, limit = undefined, params = {}) {
|
894
|
+
if (symbol === undefined) {
|
895
|
+
throw new ArgumentsRequired (this.id + ' fetchMyTrades() requires a `symbol` argument');
|
896
|
+
}
|
897
|
+
await this.loadMarkets ();
|
898
|
+
const market = this.market (symbol);
|
899
|
+
const request = {
|
900
|
+
'symbol': market['id'],
|
901
|
+
};
|
902
|
+
if (limit !== undefined) {
|
903
|
+
request['limit_trades'] = limit;
|
904
|
+
}
|
905
|
+
if (since !== undefined) {
|
906
|
+
request['timestamp'] = parseInt (since / 1000);
|
907
|
+
}
|
908
|
+
const response = await this.privatePostMytrades (this.extend (request, params));
|
909
|
+
return this.parseTrades (response, market, since, limit);
|
910
|
+
}
|
911
|
+
|
912
|
+
async createOrder (symbol, type, side, amount, price = undefined, params = {}) {
|
913
|
+
await this.loadMarkets ();
|
914
|
+
const postOnly = this.safeValue (params, 'postOnly', false);
|
915
|
+
params = this.omit (params, [ 'postOnly' ]);
|
916
|
+
const request = {
|
917
|
+
'symbol': this.marketId (symbol),
|
918
|
+
'side': side,
|
919
|
+
'amount': this.amountToPrecision (symbol, amount),
|
920
|
+
'type': this.safeString (this.options['orderTypes'], type, type),
|
921
|
+
'ocoorder': false,
|
922
|
+
'buy_price_oco': 0,
|
923
|
+
'sell_price_oco': 0,
|
924
|
+
};
|
925
|
+
if (type === 'market') {
|
926
|
+
request['price'] = this.nonce ().toString ();
|
927
|
+
} else {
|
928
|
+
request['price'] = this.priceToPrecision (symbol, price);
|
929
|
+
}
|
930
|
+
if (postOnly) {
|
931
|
+
request['is_postonly'] = true;
|
932
|
+
}
|
933
|
+
const response = await this.privatePostOrderNew (this.extend (request, params));
|
934
|
+
return this.parseOrder (response);
|
935
|
+
}
|
936
|
+
|
937
|
+
async editOrder (id, symbol, type, side, amount = undefined, price = undefined, params = {}) {
|
938
|
+
await this.loadMarkets ();
|
939
|
+
const order = {
|
940
|
+
'order_id': parseInt (id),
|
941
|
+
};
|
942
|
+
if (price !== undefined) {
|
943
|
+
order['price'] = this.priceToPrecision (symbol, price);
|
944
|
+
}
|
945
|
+
if (amount !== undefined) {
|
946
|
+
order['amount'] = this.numberToString (amount);
|
947
|
+
}
|
948
|
+
if (symbol !== undefined) {
|
949
|
+
order['symbol'] = this.marketId (symbol);
|
950
|
+
}
|
951
|
+
if (side !== undefined) {
|
952
|
+
order['side'] = side;
|
953
|
+
}
|
954
|
+
if (type !== undefined) {
|
955
|
+
order['type'] = this.safeString (this.options['orderTypes'], type, type);
|
956
|
+
}
|
957
|
+
const response = await this.privatePostOrderCancelReplace (this.extend (order, params));
|
958
|
+
return this.parseOrder (response);
|
959
|
+
}
|
960
|
+
|
961
|
+
async cancelOrder (id, symbol = undefined, params = {}) {
|
962
|
+
await this.loadMarkets ();
|
963
|
+
const request = {
|
964
|
+
'order_id': parseInt (id),
|
965
|
+
};
|
966
|
+
return await this.privatePostOrderCancel (this.extend (request, params));
|
967
|
+
}
|
968
|
+
|
969
|
+
async cancelAllOrders (symbol = undefined, params = {}) {
|
970
|
+
return await this.privatePostOrderCancelAll (params);
|
971
|
+
}
|
972
|
+
|
973
|
+
parseOrder (order, market = undefined) {
|
974
|
+
//
|
975
|
+
// {
|
976
|
+
// id: 57334010955,
|
977
|
+
// cid: 1611584840966,
|
978
|
+
// cid_date: null,
|
979
|
+
// gid: null,
|
980
|
+
// symbol: 'ltcbtc',
|
981
|
+
// exchange: null,
|
982
|
+
// price: '0.0042125',
|
983
|
+
// avg_execution_price: '0.0042097',
|
984
|
+
// side: 'sell',
|
985
|
+
// type: 'exchange market',
|
986
|
+
// timestamp: '1611584841.0',
|
987
|
+
// is_live: false,
|
988
|
+
// is_cancelled: false,
|
989
|
+
// is_hidden: 0,
|
990
|
+
// oco_order: 0,
|
991
|
+
// was_forced: false,
|
992
|
+
// original_amount: '0.205176',
|
993
|
+
// remaining_amount: '0.0',
|
994
|
+
// executed_amount: '0.205176',
|
995
|
+
// src: 'web'
|
996
|
+
// }
|
997
|
+
//
|
998
|
+
const side = this.safeString (order, 'side');
|
999
|
+
const open = this.safeValue (order, 'is_live');
|
1000
|
+
const canceled = this.safeValue (order, 'is_cancelled');
|
1001
|
+
let status = undefined;
|
1002
|
+
if (open) {
|
1003
|
+
status = 'open';
|
1004
|
+
} else if (canceled) {
|
1005
|
+
status = 'canceled';
|
1006
|
+
} else {
|
1007
|
+
status = 'closed';
|
1008
|
+
}
|
1009
|
+
const marketId = this.safeStringUpper (order, 'symbol');
|
1010
|
+
const symbol = this.safeSymbol (marketId, market);
|
1011
|
+
let orderType = this.safeString (order, 'type', '');
|
1012
|
+
const exchange = orderType.indexOf ('exchange ') >= 0;
|
1013
|
+
if (exchange) {
|
1014
|
+
const parts = order['type'].split (' ');
|
1015
|
+
orderType = parts[1];
|
1016
|
+
}
|
1017
|
+
const timestamp = this.safeTimestamp (order, 'timestamp');
|
1018
|
+
const id = this.safeString (order, 'id');
|
1019
|
+
return this.safeOrder ({
|
1020
|
+
'info': order,
|
1021
|
+
'id': id,
|
1022
|
+
'clientOrderId': undefined,
|
1023
|
+
'timestamp': timestamp,
|
1024
|
+
'datetime': this.iso8601 (timestamp),
|
1025
|
+
'lastTradeTimestamp': undefined,
|
1026
|
+
'symbol': symbol,
|
1027
|
+
'type': orderType,
|
1028
|
+
'timeInForce': undefined,
|
1029
|
+
'postOnly': undefined,
|
1030
|
+
'side': side,
|
1031
|
+
'price': this.safeString (order, 'price'),
|
1032
|
+
'stopPrice': undefined,
|
1033
|
+
'average': this.safeString (order, 'avg_execution_price'),
|
1034
|
+
'amount': this.safeString (order, 'original_amount'),
|
1035
|
+
'remaining': this.safeString (order, 'remaining_amount'),
|
1036
|
+
'filled': this.safeString (order, 'executed_amount'),
|
1037
|
+
'status': status,
|
1038
|
+
'fee': undefined,
|
1039
|
+
'cost': undefined,
|
1040
|
+
'trades': undefined,
|
1041
|
+
}, market);
|
1042
|
+
}
|
1043
|
+
|
1044
|
+
async fetchOpenOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) {
|
1045
|
+
await this.loadMarkets ();
|
1046
|
+
if (symbol !== undefined) {
|
1047
|
+
if (!(symbol in this.markets)) {
|
1048
|
+
throw new ExchangeError (this.id + ' has no symbol ' + symbol);
|
1049
|
+
}
|
1050
|
+
}
|
1051
|
+
const response = await this.privatePostOrders (params);
|
1052
|
+
let orders = this.parseOrders (response, undefined, since, limit);
|
1053
|
+
if (symbol !== undefined) {
|
1054
|
+
orders = this.filterBy (orders, 'symbol', symbol);
|
1055
|
+
}
|
1056
|
+
return orders;
|
1057
|
+
}
|
1058
|
+
|
1059
|
+
async fetchClosedOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) {
|
1060
|
+
await this.loadMarkets ();
|
1061
|
+
const request = {};
|
1062
|
+
if (limit !== undefined) {
|
1063
|
+
request['limit'] = limit;
|
1064
|
+
}
|
1065
|
+
const response = await this.privatePostOrdersHist (this.extend (request, params));
|
1066
|
+
let orders = this.parseOrders (response, undefined, since, limit);
|
1067
|
+
if (symbol !== undefined) {
|
1068
|
+
orders = this.filterBy (orders, 'symbol', symbol);
|
1069
|
+
}
|
1070
|
+
orders = this.filterByArray (orders, 'status', [ 'closed', 'canceled' ], false);
|
1071
|
+
return orders;
|
1072
|
+
}
|
1073
|
+
|
1074
|
+
async fetchOrder (id, symbol = undefined, params = {}) {
|
1075
|
+
await this.loadMarkets ();
|
1076
|
+
const request = {
|
1077
|
+
'order_id': parseInt (id),
|
1078
|
+
};
|
1079
|
+
const response = await this.privatePostOrderStatus (this.extend (request, params));
|
1080
|
+
return this.parseOrder (response);
|
1081
|
+
}
|
1082
|
+
|
1083
|
+
parseOHLCV (ohlcv, market = undefined) {
|
1084
|
+
//
|
1085
|
+
// [
|
1086
|
+
// 1457539800000,
|
1087
|
+
// 0.02594,
|
1088
|
+
// 0.02594,
|
1089
|
+
// 0.02594,
|
1090
|
+
// 0.02594,
|
1091
|
+
// 0.1
|
1092
|
+
// ]
|
1093
|
+
//
|
1094
|
+
return [
|
1095
|
+
this.safeInteger (ohlcv, 0),
|
1096
|
+
this.safeNumber (ohlcv, 1),
|
1097
|
+
this.safeNumber (ohlcv, 3),
|
1098
|
+
this.safeNumber (ohlcv, 4),
|
1099
|
+
this.safeNumber (ohlcv, 2),
|
1100
|
+
this.safeNumber (ohlcv, 5),
|
1101
|
+
];
|
1102
|
+
}
|
1103
|
+
|
1104
|
+
async fetchOHLCV (symbol, timeframe = '1m', since = undefined, limit = undefined, params = {}) {
|
1105
|
+
await this.loadMarkets ();
|
1106
|
+
if (limit === undefined) {
|
1107
|
+
limit = 100;
|
1108
|
+
}
|
1109
|
+
const market = this.market (symbol);
|
1110
|
+
const v2id = 't' + market['id'];
|
1111
|
+
const request = {
|
1112
|
+
'symbol': v2id,
|
1113
|
+
'timeframe': this.timeframes[timeframe],
|
1114
|
+
'sort': 1,
|
1115
|
+
'limit': limit,
|
1116
|
+
};
|
1117
|
+
if (since !== undefined) {
|
1118
|
+
request['start'] = since;
|
1119
|
+
}
|
1120
|
+
const response = await this.v2GetCandlesTradeTimeframeSymbolHist (this.extend (request, params));
|
1121
|
+
//
|
1122
|
+
// [
|
1123
|
+
// [1457539800000,0.02594,0.02594,0.02594,0.02594,0.1],
|
1124
|
+
// [1457547300000,0.02577,0.02577,0.02577,0.02577,0.01],
|
1125
|
+
// [1457550240000,0.0255,0.0253,0.0255,0.0252,3.2640000000000002],
|
1126
|
+
// ]
|
1127
|
+
//
|
1128
|
+
return this.parseOHLCVs (response, market, timeframe, since, limit);
|
1129
|
+
}
|
1130
|
+
|
1131
|
+
getCurrencyName (code) {
|
1132
|
+
// todo rewrite for https://api-pub.bitfinex.com//v2/conf/pub:map:tx:method
|
1133
|
+
if (code in this.options['currencyNames']) {
|
1134
|
+
return this.options['currencyNames'][code];
|
1135
|
+
}
|
1136
|
+
throw new NotSupported (this.id + ' ' + code + ' not supported for withdrawal');
|
1137
|
+
}
|
1138
|
+
|
1139
|
+
async createDepositAddress (code, params = {}) {
|
1140
|
+
await this.loadMarkets ();
|
1141
|
+
const request = {
|
1142
|
+
'renew': 1,
|
1143
|
+
};
|
1144
|
+
const response = await this.fetchDepositAddress (code, this.extend (request, params));
|
1145
|
+
return response;
|
1146
|
+
}
|
1147
|
+
|
1148
|
+
async fetchDepositAddress (code, params = {}) {
|
1149
|
+
await this.loadMarkets ();
|
1150
|
+
// todo rewrite for https://api-pub.bitfinex.com//v2/conf/pub:map:tx:method
|
1151
|
+
const name = this.getCurrencyName (code);
|
1152
|
+
const request = {
|
1153
|
+
'method': name,
|
1154
|
+
'wallet_name': 'exchange',
|
1155
|
+
'renew': 0, // a value of 1 will generate a new address
|
1156
|
+
};
|
1157
|
+
const response = await this.privatePostDepositNew (this.extend (request, params));
|
1158
|
+
let address = this.safeValue (response, 'address');
|
1159
|
+
let tag = undefined;
|
1160
|
+
if ('address_pool' in response) {
|
1161
|
+
tag = address;
|
1162
|
+
address = response['address_pool'];
|
1163
|
+
}
|
1164
|
+
this.checkAddress (address);
|
1165
|
+
return {
|
1166
|
+
'currency': code,
|
1167
|
+
'address': address,
|
1168
|
+
'tag': tag,
|
1169
|
+
'network': undefined,
|
1170
|
+
'info': response,
|
1171
|
+
};
|
1172
|
+
}
|
1173
|
+
|
1174
|
+
async fetchTransactions (code = undefined, since = undefined, limit = undefined, params = {}) {
|
1175
|
+
await this.loadMarkets ();
|
1176
|
+
let currencyId = this.safeString (params, 'currency');
|
1177
|
+
const query = this.omit (params, 'currency');
|
1178
|
+
let currency = undefined;
|
1179
|
+
if (currencyId === undefined) {
|
1180
|
+
if (code === undefined) {
|
1181
|
+
throw new ArgumentsRequired (this.id + ' fetchTransactions() requires a currency `code` argument or a `currency` parameter');
|
1182
|
+
} else {
|
1183
|
+
currency = this.currency (code);
|
1184
|
+
currencyId = currency['id'];
|
1185
|
+
}
|
1186
|
+
}
|
1187
|
+
query['currency'] = currencyId;
|
1188
|
+
if (since !== undefined) {
|
1189
|
+
query['since'] = parseInt (since / 1000);
|
1190
|
+
}
|
1191
|
+
const response = await this.privatePostHistoryMovements (this.extend (query, params));
|
1192
|
+
//
|
1193
|
+
// [
|
1194
|
+
// {
|
1195
|
+
// "id":581183,
|
1196
|
+
// "txid": 123456,
|
1197
|
+
// "currency":"BTC",
|
1198
|
+
// "method":"BITCOIN",
|
1199
|
+
// "type":"WITHDRAWAL",
|
1200
|
+
// "amount":".01",
|
1201
|
+
// "description":"3QXYWgRGX2BPYBpUDBssGbeWEa5zq6snBZ, offchain transfer ",
|
1202
|
+
// "address":"3QXYWgRGX2BPYBpUDBssGbeWEa5zq6snBZ",
|
1203
|
+
// "status":"COMPLETED",
|
1204
|
+
// "timestamp":"1443833327.0",
|
1205
|
+
// "timestamp_created": "1443833327.1",
|
1206
|
+
// "fee": 0.1,
|
1207
|
+
// }
|
1208
|
+
// ]
|
1209
|
+
//
|
1210
|
+
return this.parseTransactions (response, currency, since, limit);
|
1211
|
+
}
|
1212
|
+
|
1213
|
+
parseTransaction (transaction, currency = undefined) {
|
1214
|
+
//
|
1215
|
+
// crypto
|
1216
|
+
//
|
1217
|
+
// {
|
1218
|
+
// "id": 12042490,
|
1219
|
+
// "fee": "-0.02",
|
1220
|
+
// "txid": "EA5B5A66000B66855865EFF2494D7C8D1921FCBE996482157EBD749F2C85E13D",
|
1221
|
+
// "type": "DEPOSIT",
|
1222
|
+
// "amount": "2099.849999",
|
1223
|
+
// "method": "RIPPLE",
|
1224
|
+
// "status": "COMPLETED",
|
1225
|
+
// "address": "2505189261",
|
1226
|
+
// "currency": "XRP",
|
1227
|
+
// "timestamp": "1551730524.0",
|
1228
|
+
// "description": "EA5B5A66000B66855865EFF2494D7C8D1921FCBE996482157EBD749F2C85E13D",
|
1229
|
+
// "timestamp_created": "1551730523.0"
|
1230
|
+
// }
|
1231
|
+
//
|
1232
|
+
// fiat
|
1233
|
+
//
|
1234
|
+
// {
|
1235
|
+
// "id": 12725095,
|
1236
|
+
// "fee": "-60.0",
|
1237
|
+
// "txid": null,
|
1238
|
+
// "type": "WITHDRAWAL",
|
1239
|
+
// "amount": "9943.0",
|
1240
|
+
// "method": "WIRE",
|
1241
|
+
// "status": "SENDING",
|
1242
|
+
// "address": null,
|
1243
|
+
// "currency": "EUR",
|
1244
|
+
// "timestamp": "1561802484.0",
|
1245
|
+
// "description": "Name: bob, AccountAddress: some address, Account: someaccountno, Bank: bank address, SWIFT: foo, Country: UK, Details of Payment: withdrawal name, Intermediary Bank Name: , Intermediary Bank Address: , Intermediary Bank City: , Intermediary Bank Country: , Intermediary Bank Account: , Intermediary Bank SWIFT: , Fee: -60.0",
|
1246
|
+
// "timestamp_created": "1561716066.0"
|
1247
|
+
// }
|
1248
|
+
//
|
1249
|
+
// withdraw
|
1250
|
+
//
|
1251
|
+
// {
|
1252
|
+
// "status":"success",
|
1253
|
+
// "message":"Your withdrawal request has been successfully submitted.",
|
1254
|
+
// "withdrawal_id":586829
|
1255
|
+
// }
|
1256
|
+
//
|
1257
|
+
const timestamp = this.safeTimestamp (transaction, 'timestamp_created');
|
1258
|
+
const updated = this.safeTimestamp (transaction, 'timestamp');
|
1259
|
+
const currencyId = this.safeString (transaction, 'currency');
|
1260
|
+
const code = this.safeCurrencyCode (currencyId, currency);
|
1261
|
+
const type = this.safeStringLower (transaction, 'type'); // DEPOSIT or WITHDRAWAL
|
1262
|
+
const status = this.parseTransactionStatus (this.safeString (transaction, 'status'));
|
1263
|
+
let feeCost = this.safeNumber (transaction, 'fee');
|
1264
|
+
if (feeCost !== undefined) {
|
1265
|
+
feeCost = Math.abs (feeCost);
|
1266
|
+
}
|
1267
|
+
const tag = this.safeString (transaction, 'description');
|
1268
|
+
return {
|
1269
|
+
'info': transaction,
|
1270
|
+
'id': this.safeString2 (transaction, 'id', 'withdrawal_id'),
|
1271
|
+
'txid': this.safeString (transaction, 'txid'),
|
1272
|
+
'timestamp': timestamp,
|
1273
|
+
'datetime': this.iso8601 (timestamp),
|
1274
|
+
'network': undefined,
|
1275
|
+
'address': this.safeString (transaction, 'address'), // todo: this is actually the tag for XRP transfers (the address is missing)
|
1276
|
+
'addressTo': undefined,
|
1277
|
+
'addressFrom': undefined,
|
1278
|
+
'tag': tag,
|
1279
|
+
'tagTo': undefined,
|
1280
|
+
'tagFrom': undefined,
|
1281
|
+
'type': type,
|
1282
|
+
'amount': this.safeNumber (transaction, 'amount'),
|
1283
|
+
'currency': code,
|
1284
|
+
'status': status,
|
1285
|
+
'updated': updated,
|
1286
|
+
'fee': {
|
1287
|
+
'currency': code,
|
1288
|
+
'cost': feeCost,
|
1289
|
+
'rate': undefined,
|
1290
|
+
},
|
1291
|
+
};
|
1292
|
+
}
|
1293
|
+
|
1294
|
+
parseTransactionStatus (status) {
|
1295
|
+
const statuses = {
|
1296
|
+
'SENDING': 'pending',
|
1297
|
+
'CANCELED': 'canceled',
|
1298
|
+
'ZEROCONFIRMED': 'failed', // ZEROCONFIRMED happens e.g. in a double spend attempt (I had one in my movements!)
|
1299
|
+
'COMPLETED': 'ok',
|
1300
|
+
};
|
1301
|
+
return this.safeString (statuses, status, status);
|
1302
|
+
}
|
1303
|
+
|
1304
|
+
async withdraw (code, amount, address, tag = undefined, params = {}) {
|
1305
|
+
[ tag, params ] = this.handleWithdrawTagAndParams (tag, params);
|
1306
|
+
this.checkAddress (address);
|
1307
|
+
await this.loadMarkets ();
|
1308
|
+
// todo rewrite for https://api-pub.bitfinex.com//v2/conf/pub:map:tx:method
|
1309
|
+
const name = this.getCurrencyName (code);
|
1310
|
+
const currency = this.currency (code);
|
1311
|
+
const request = {
|
1312
|
+
'withdraw_type': name,
|
1313
|
+
'walletselected': 'exchange',
|
1314
|
+
'amount': this.numberToString (amount),
|
1315
|
+
'address': address,
|
1316
|
+
};
|
1317
|
+
if (tag !== undefined) {
|
1318
|
+
request['payment_id'] = tag;
|
1319
|
+
}
|
1320
|
+
const responses = await this.privatePostWithdraw (this.extend (request, params));
|
1321
|
+
//
|
1322
|
+
// [
|
1323
|
+
// {
|
1324
|
+
// "status":"success",
|
1325
|
+
// "message":"Your withdrawal request has been successfully submitted.",
|
1326
|
+
// "withdrawal_id":586829
|
1327
|
+
// }
|
1328
|
+
// ]
|
1329
|
+
//
|
1330
|
+
const response = this.safeValue (responses, 0, {});
|
1331
|
+
const id = this.safeString (response, 'withdrawal_id');
|
1332
|
+
const message = this.safeString (response, 'message');
|
1333
|
+
const errorMessage = this.findBroadlyMatchedKey (this.exceptions['broad'], message);
|
1334
|
+
if (id === 0) {
|
1335
|
+
if (errorMessage !== undefined) {
|
1336
|
+
const ExceptionClass = this.exceptions['broad'][errorMessage];
|
1337
|
+
throw new ExceptionClass (this.id + ' ' + message);
|
1338
|
+
}
|
1339
|
+
throw new ExchangeError (this.id + ' withdraw returned an id of zero: ' + this.json (response));
|
1340
|
+
}
|
1341
|
+
return this.parseTransaction (response, currency);
|
1342
|
+
}
|
1343
|
+
|
1344
|
+
async fetchPositions (symbols = undefined, params = {}) {
|
1345
|
+
await this.loadMarkets ();
|
1346
|
+
const response = await this.privatePostPositions (params);
|
1347
|
+
//
|
1348
|
+
// [
|
1349
|
+
// {
|
1350
|
+
// "id":943715,
|
1351
|
+
// "symbol":"btcusd",
|
1352
|
+
// "status":"ACTIVE",
|
1353
|
+
// "base":"246.94",
|
1354
|
+
// "amount":"1.0",
|
1355
|
+
// "timestamp":"1444141857.0",
|
1356
|
+
// "swap":"0.0",
|
1357
|
+
// "pl":"-2.22042"
|
1358
|
+
// }
|
1359
|
+
// ]
|
1360
|
+
//
|
1361
|
+
// todo unify parsePosition/parsePositions
|
1362
|
+
return response;
|
1363
|
+
}
|
1364
|
+
|
1365
|
+
nonce () {
|
1366
|
+
return this.milliseconds ();
|
1367
|
+
}
|
1368
|
+
|
1369
|
+
sign (path, api = 'public', method = 'GET', params = {}, headers = undefined, body = undefined) {
|
1370
|
+
let request = '/' + this.implodeParams (path, params);
|
1371
|
+
if (api === 'v2') {
|
1372
|
+
request = '/' + api + request;
|
1373
|
+
} else {
|
1374
|
+
request = '/' + this.version + request;
|
1375
|
+
}
|
1376
|
+
let query = this.omit (params, this.extractParams (path));
|
1377
|
+
let url = this.urls['api'][api] + request;
|
1378
|
+
if ((api === 'public') || (path.indexOf ('/hist') >= 0)) {
|
1379
|
+
if (Object.keys (query).length) {
|
1380
|
+
const suffix = '?' + this.urlencode (query);
|
1381
|
+
url += suffix;
|
1382
|
+
request += suffix;
|
1383
|
+
}
|
1384
|
+
}
|
1385
|
+
if (api === 'private') {
|
1386
|
+
this.checkRequiredCredentials ();
|
1387
|
+
const nonce = this.nonce ();
|
1388
|
+
query = this.extend ({
|
1389
|
+
'nonce': nonce.toString (),
|
1390
|
+
'request': request,
|
1391
|
+
}, query);
|
1392
|
+
body = this.json (query);
|
1393
|
+
const payload = this.stringToBase64 (body);
|
1394
|
+
const secret = this.encode (this.secret);
|
1395
|
+
const signature = this.hmac (payload, secret, 'sha384');
|
1396
|
+
headers = {
|
1397
|
+
'X-BFX-APIKEY': this.apiKey,
|
1398
|
+
'X-BFX-PAYLOAD': this.decode (payload),
|
1399
|
+
'X-BFX-SIGNATURE': signature,
|
1400
|
+
'Content-Type': 'application/json',
|
1401
|
+
};
|
1402
|
+
}
|
1403
|
+
return { 'url': url, 'method': method, 'body': body, 'headers': headers };
|
1404
|
+
}
|
1405
|
+
|
1406
|
+
handleErrors (code, reason, url, method, headers, body, response, requestHeaders, requestBody) {
|
1407
|
+
if (response === undefined) {
|
1408
|
+
return;
|
1409
|
+
}
|
1410
|
+
let throwError = false;
|
1411
|
+
if (code >= 400) {
|
1412
|
+
const firstChar = this.safeString (body, 0);
|
1413
|
+
if (firstChar === '{') {
|
1414
|
+
throwError = true;
|
1415
|
+
}
|
1416
|
+
} else {
|
1417
|
+
// json response with error, i.e:
|
1418
|
+
// [{"status":"error","message":"Momentary balance check. Please wait few seconds and try the transfer again."}]
|
1419
|
+
const responseObject = this.safeValue (response, 0, {});
|
1420
|
+
const status = this.safeString (responseObject, 'status', '');
|
1421
|
+
if (status === 'error') {
|
1422
|
+
throwError = true;
|
1423
|
+
}
|
1424
|
+
}
|
1425
|
+
if (throwError) {
|
1426
|
+
const feedback = this.id + ' ' + body;
|
1427
|
+
const message = this.safeString2 (response, 'message', 'error');
|
1428
|
+
this.throwExactlyMatchedException (this.exceptions['exact'], message, feedback);
|
1429
|
+
this.throwBroadlyMatchedException (this.exceptions['broad'], message, feedback);
|
1430
|
+
throw new ExchangeError (feedback); // unknown message
|
1431
|
+
}
|
1432
|
+
}
|
1433
|
+
};
|