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/gemini.js
ADDED
@@ -0,0 +1,1397 @@
|
|
1
|
+
'use strict';
|
2
|
+
|
3
|
+
// ---------------------------------------------------------------------------
|
4
|
+
|
5
|
+
const Exchange = require ('./base/Exchange');
|
6
|
+
const { ExchangeError, ArgumentsRequired, BadRequest, OrderNotFound, InvalidOrder, InvalidNonce, InsufficientFunds, AuthenticationError, PermissionDenied, NotSupported, OnMaintenance, RateLimitExceeded, ExchangeNotAvailable } = require ('./base/errors');
|
7
|
+
const { TICK_SIZE } = require ('./base/functions/number');
|
8
|
+
const Precise = require ('./base/Precise');
|
9
|
+
|
10
|
+
// ---------------------------------------------------------------------------
|
11
|
+
|
12
|
+
module.exports = class gemini extends Exchange {
|
13
|
+
describe () {
|
14
|
+
return this.deepExtend (super.describe (), {
|
15
|
+
'id': 'gemini',
|
16
|
+
'name': 'Gemini',
|
17
|
+
'countries': [ 'US' ],
|
18
|
+
// 600 requests a minute = 10 requests per second => 1000ms / 10 = 100ms between requests (private endpoints)
|
19
|
+
// 120 requests a minute = 2 requests per second => ( 1000ms / rateLimit ) / 2 = 5 (public endpoints)
|
20
|
+
'rateLimit': 100,
|
21
|
+
'version': 'v1',
|
22
|
+
'has': {
|
23
|
+
'CORS': undefined,
|
24
|
+
'spot': true,
|
25
|
+
'margin': false,
|
26
|
+
'swap': false,
|
27
|
+
'future': false,
|
28
|
+
'option': false,
|
29
|
+
'addMargin': false,
|
30
|
+
'cancelOrder': true,
|
31
|
+
'createDepositAddress': true,
|
32
|
+
'createMarketOrder': undefined,
|
33
|
+
'createOrder': true,
|
34
|
+
'createReduceOnlyOrder': false,
|
35
|
+
'fetchBalance': true,
|
36
|
+
'fetchBidsAsks': undefined,
|
37
|
+
'fetchBorrowRate': false,
|
38
|
+
'fetchBorrowRateHistories': false,
|
39
|
+
'fetchBorrowRateHistory': false,
|
40
|
+
'fetchBorrowRates': false,
|
41
|
+
'fetchBorrowRatesPerSymbol': false,
|
42
|
+
'fetchClosedOrders': undefined,
|
43
|
+
'fetchDepositAddress': undefined, // TODO
|
44
|
+
'fetchDepositAddressesByNetwork': true,
|
45
|
+
'fetchDeposits': undefined,
|
46
|
+
'fetchFundingHistory': false,
|
47
|
+
'fetchFundingRate': false,
|
48
|
+
'fetchFundingRateHistory': false,
|
49
|
+
'fetchFundingRates': false,
|
50
|
+
'fetchIndexOHLCV': false,
|
51
|
+
'fetchLeverage': false,
|
52
|
+
'fetchLeverageTiers': false,
|
53
|
+
'fetchMarkets': true,
|
54
|
+
'fetchMarkOHLCV': false,
|
55
|
+
'fetchMyTrades': true,
|
56
|
+
'fetchOHLCV': true,
|
57
|
+
'fetchOpenOrders': true,
|
58
|
+
'fetchOrder': true,
|
59
|
+
'fetchOrderBook': true,
|
60
|
+
'fetchOrders': undefined,
|
61
|
+
'fetchPosition': false,
|
62
|
+
'fetchPositions': false,
|
63
|
+
'fetchPositionsRisk': false,
|
64
|
+
'fetchPremiumIndexOHLCV': false,
|
65
|
+
'fetchTicker': true,
|
66
|
+
'fetchTickers': true,
|
67
|
+
'fetchTrades': true,
|
68
|
+
'fetchTradingFee': false,
|
69
|
+
'fetchTradingFees': true,
|
70
|
+
'fetchTransactions': true,
|
71
|
+
'fetchWithdrawals': undefined,
|
72
|
+
'postOnly': true,
|
73
|
+
'reduceMargin': false,
|
74
|
+
'setLeverage': false,
|
75
|
+
'setMarginMode': false,
|
76
|
+
'setPositionMode': false,
|
77
|
+
'withdraw': true,
|
78
|
+
},
|
79
|
+
'urls': {
|
80
|
+
'logo': 'https://user-images.githubusercontent.com/1294454/27816857-ce7be644-6096-11e7-82d6-3c257263229c.jpg',
|
81
|
+
'api': {
|
82
|
+
'public': 'https://api.gemini.com',
|
83
|
+
'private': 'https://api.gemini.com',
|
84
|
+
'web': 'https://docs.gemini.com',
|
85
|
+
},
|
86
|
+
'www': 'https://gemini.com/',
|
87
|
+
'doc': [
|
88
|
+
'https://docs.gemini.com/rest-api',
|
89
|
+
'https://docs.sandbox.gemini.com',
|
90
|
+
],
|
91
|
+
'test': {
|
92
|
+
'public': 'https://api.sandbox.gemini.com',
|
93
|
+
'private': 'https://api.sandbox.gemini.com',
|
94
|
+
// use the true doc instead of the sandbox doc
|
95
|
+
// since they differ in parsing
|
96
|
+
// https://github.com/ccxt/ccxt/issues/7874
|
97
|
+
// https://github.com/ccxt/ccxt/issues/7894
|
98
|
+
'web': 'https://docs.gemini.com',
|
99
|
+
},
|
100
|
+
'fees': [
|
101
|
+
'https://gemini.com/api-fee-schedule',
|
102
|
+
'https://gemini.com/trading-fees',
|
103
|
+
'https://gemini.com/transfer-fees',
|
104
|
+
],
|
105
|
+
},
|
106
|
+
'api': {
|
107
|
+
'web': {
|
108
|
+
'get': [
|
109
|
+
'rest-api',
|
110
|
+
],
|
111
|
+
},
|
112
|
+
'public': {
|
113
|
+
'get': {
|
114
|
+
'v1/symbols': 5,
|
115
|
+
'v1/symbols/details/{symbol}': 5,
|
116
|
+
'v1/pubticker/{symbol}': 5,
|
117
|
+
'v2/ticker/{symbol}': 5,
|
118
|
+
'v2/candles/{symbol}/{timeframe}': 5,
|
119
|
+
'v1/trades/{symbol}': 5,
|
120
|
+
'v1/auction/{symbol}': 5,
|
121
|
+
'v1/auction/{symbol}/history': 5,
|
122
|
+
'v1/pricefeed': 5,
|
123
|
+
'v1/book/{symbol}': 5,
|
124
|
+
'v1/earn/rates': 5,
|
125
|
+
},
|
126
|
+
},
|
127
|
+
'private': {
|
128
|
+
'post': {
|
129
|
+
'v1/order/new': 1,
|
130
|
+
'v1/order/cancel': 1,
|
131
|
+
'v1/wrap/{symbol}': 1,
|
132
|
+
'v1/order/cancel/session': 1,
|
133
|
+
'v1/order/cancel/all': 1,
|
134
|
+
'v1/order/status': 1,
|
135
|
+
'v1/orders': 1,
|
136
|
+
'v1/mytrades': 1,
|
137
|
+
'v1/notionalvolume': 1,
|
138
|
+
'v1/tradevolume': 1,
|
139
|
+
'v1/clearing/new': 1,
|
140
|
+
'v1/clearing/status': 1,
|
141
|
+
'v1/clearing/cancel': 1,
|
142
|
+
'v1/clearing/confirm': 1,
|
143
|
+
'v1/balances': 1,
|
144
|
+
'v1/notionalbalances/{currency}': 1,
|
145
|
+
'v1/transfers': 1,
|
146
|
+
'v1/addresses/{network}': 1,
|
147
|
+
'v1/deposit/{network}/newAddress': 1,
|
148
|
+
'v1/deposit/{currency}/newAddress': 1,
|
149
|
+
'v1/withdraw/{currency}': 1,
|
150
|
+
'v1/account/transfer/{currency}': 1,
|
151
|
+
'v1/payments/addbank': 1,
|
152
|
+
'v1/payments/methods': 1,
|
153
|
+
'v1/payments/sen/withdraw': 1,
|
154
|
+
'v1/balances/earn': 1,
|
155
|
+
'v1/earn/interest': 1,
|
156
|
+
'v1/approvedAddresses/{network}/request': 1,
|
157
|
+
'v1/approvedAddresses/account/{network}': 1,
|
158
|
+
'v1/approvedAddresses/{network}/remove': 1,
|
159
|
+
'v1/account': 1,
|
160
|
+
'v1/account/create': 1,
|
161
|
+
'v1/account/list': 1,
|
162
|
+
'v1/heartbeat': 1,
|
163
|
+
},
|
164
|
+
},
|
165
|
+
},
|
166
|
+
'precisionMode': TICK_SIZE,
|
167
|
+
'fees': {
|
168
|
+
'trading': {
|
169
|
+
'taker': 0.004,
|
170
|
+
'maker': 0.002,
|
171
|
+
},
|
172
|
+
},
|
173
|
+
'httpExceptions': {
|
174
|
+
'400': BadRequest, // Auction not open or paused, ineligible timing, market not open, or the request was malformed, in the case of a private API request, missing or malformed Gemini private API authentication headers
|
175
|
+
'403': PermissionDenied, // The API key is missing the role necessary to access this private API endpoint
|
176
|
+
'404': OrderNotFound, // Unknown API entry point or Order not found
|
177
|
+
'406': InsufficientFunds, // Insufficient Funds
|
178
|
+
'429': RateLimitExceeded, // Rate Limiting was applied
|
179
|
+
'500': ExchangeError, // The server encountered an error
|
180
|
+
'502': ExchangeNotAvailable, // Technical issues are preventing the request from being satisfied
|
181
|
+
'503': OnMaintenance, // The exchange is down for maintenance
|
182
|
+
},
|
183
|
+
'timeframes': {
|
184
|
+
'1m': '1m',
|
185
|
+
'5m': '5m',
|
186
|
+
'15m': '15m',
|
187
|
+
'30m': '30m',
|
188
|
+
'1h': '1hr',
|
189
|
+
'6h': '6hr',
|
190
|
+
'1d': '1day',
|
191
|
+
},
|
192
|
+
'exceptions': {
|
193
|
+
'exact': {
|
194
|
+
'AuctionNotOpen': BadRequest, // Failed to place an auction-only order because there is no current auction open for this symbol
|
195
|
+
'ClientOrderIdTooLong': BadRequest, // The Client Order ID must be under 100 characters
|
196
|
+
'ClientOrderIdMustBeString': BadRequest, // The Client Order ID must be a string
|
197
|
+
'ConflictingOptions': BadRequest, // New orders using a combination of order execution options are not supported
|
198
|
+
'EndpointMismatch': BadRequest, // The request was submitted to an endpoint different than the one in the payload
|
199
|
+
'EndpointNotFound': BadRequest, // No endpoint was specified
|
200
|
+
'IneligibleTiming': BadRequest, // Failed to place an auction order for the current auction on this symbol because the timing is not eligible, new orders may only be placed before the auction begins.
|
201
|
+
'InsufficientFunds': InsufficientFunds, // The order was rejected because of insufficient funds
|
202
|
+
'InvalidJson': BadRequest, // The JSON provided is invalid
|
203
|
+
'InvalidNonce': InvalidNonce, // The nonce was not greater than the previously used nonce, or was not present
|
204
|
+
'InvalidOrderType': InvalidOrder, // An unknown order type was provided
|
205
|
+
'InvalidPrice': InvalidOrder, // For new orders, the price was invalid
|
206
|
+
'InvalidQuantity': InvalidOrder, // A negative or otherwise invalid quantity was specified
|
207
|
+
'InvalidSide': InvalidOrder, // For new orders, and invalid side was specified
|
208
|
+
'InvalidSignature': AuthenticationError, // The signature did not match the expected signature
|
209
|
+
'InvalidSymbol': BadRequest, // An invalid symbol was specified
|
210
|
+
'InvalidTimestampInPayload': BadRequest, // The JSON payload contained a timestamp parameter with an unsupported value.
|
211
|
+
'Maintenance': OnMaintenance, // The system is down for maintenance
|
212
|
+
'MarketNotOpen': InvalidOrder, // The order was rejected because the market is not accepting new orders
|
213
|
+
'MissingApikeyHeader': AuthenticationError, // The X-GEMINI-APIKEY header was missing
|
214
|
+
'MissingOrderField': InvalidOrder, // A required order_id field was not specified
|
215
|
+
'MissingRole': AuthenticationError, // The API key used to access this endpoint does not have the required role assigned to it
|
216
|
+
'MissingPayloadHeader': AuthenticationError, // The X-GEMINI-PAYLOAD header was missing
|
217
|
+
'MissingSignatureHeader': AuthenticationError, // The X-GEMINI-SIGNATURE header was missing
|
218
|
+
'NoSSL': AuthenticationError, // You must use HTTPS to access the API
|
219
|
+
'OptionsMustBeArray': BadRequest, // The options parameter must be an array.
|
220
|
+
'OrderNotFound': OrderNotFound, // The order specified was not found
|
221
|
+
'RateLimit': RateLimitExceeded, // Requests were made too frequently. See Rate Limits below.
|
222
|
+
'System': ExchangeError, // We are experiencing technical issues
|
223
|
+
'UnsupportedOption': BadRequest, // This order execution option is not supported.
|
224
|
+
},
|
225
|
+
'broad': {
|
226
|
+
'The Gemini Exchange is currently undergoing maintenance.': OnMaintenance, // The Gemini Exchange is currently undergoing maintenance. Please check https://status.gemini.com/ for more information.
|
227
|
+
'We are investigating technical issues with the Gemini Exchange.': ExchangeNotAvailable, // We are investigating technical issues with the Gemini Exchange. Please check https://status.gemini.com/ for more information.
|
228
|
+
},
|
229
|
+
},
|
230
|
+
'options': {
|
231
|
+
'fetchMarketsMethod': 'fetch_markets_from_web',
|
232
|
+
'fetchTickerMethod': 'fetchTickerV1', // fetchTickerV1, fetchTickerV2, fetchTickerV1AndV2
|
233
|
+
'networkIds': {
|
234
|
+
'bitcoin': 'BTC',
|
235
|
+
'ethereum': 'ERC20',
|
236
|
+
'bitcoincash': 'BCH',
|
237
|
+
'litecoin': 'LTC',
|
238
|
+
'zcash': 'ZEC',
|
239
|
+
'filecoin': 'FIL',
|
240
|
+
'dogecoin': 'DOGE',
|
241
|
+
'tezos': 'XTZ',
|
242
|
+
},
|
243
|
+
'networks': {
|
244
|
+
'BTC': 'bitcoin',
|
245
|
+
'ERC20': 'ethereum',
|
246
|
+
'BCH': 'bitcoincash',
|
247
|
+
'LTC': 'litecoin',
|
248
|
+
'ZEC': 'zcash',
|
249
|
+
'FIL': 'filecoin',
|
250
|
+
'DOGE': 'dogecoin',
|
251
|
+
'XTZ': 'tezos',
|
252
|
+
},
|
253
|
+
},
|
254
|
+
});
|
255
|
+
}
|
256
|
+
|
257
|
+
async fetchMarkets (params = {}) {
|
258
|
+
const method = this.safeValue (this.options, 'fetchMarketsMethod', 'fetch_markets_from_api');
|
259
|
+
return await this[method] (params);
|
260
|
+
}
|
261
|
+
|
262
|
+
async fetchMarketsFromWeb (params = {}) {
|
263
|
+
const response = await this.webGetRestApi (params);
|
264
|
+
const sections = response.split ('<h1 id="symbols-and-minimums">Symbols and minimums</h1>');
|
265
|
+
const numSections = sections.length;
|
266
|
+
const error = this.id + ' fetchMarketsFromWeb() the ' + this.name + ' API doc HTML markup has changed, breaking the parser of order limits and precision info for ' + this.name + ' markets.';
|
267
|
+
if (numSections !== 2) {
|
268
|
+
throw new NotSupported (error);
|
269
|
+
}
|
270
|
+
const tables = sections[1].split ('tbody>');
|
271
|
+
const numTables = tables.length;
|
272
|
+
if (numTables < 2) {
|
273
|
+
throw new NotSupported (error);
|
274
|
+
}
|
275
|
+
const rows = tables[1].split ("\n<tr>\n"); // eslint-disable-line quotes
|
276
|
+
const numRows = rows.length;
|
277
|
+
if (numRows < 2) {
|
278
|
+
throw new NotSupported (error);
|
279
|
+
}
|
280
|
+
const result = [];
|
281
|
+
// skip the first element (empty string)
|
282
|
+
for (let i = 1; i < numRows; i++) {
|
283
|
+
const row = rows[i];
|
284
|
+
const cells = row.split ("</td>\n"); // eslint-disable-line quotes
|
285
|
+
const numCells = cells.length;
|
286
|
+
if (numCells < 5) {
|
287
|
+
throw new NotSupported (error);
|
288
|
+
}
|
289
|
+
// [
|
290
|
+
// '<td>btcusd', // currency
|
291
|
+
// '<td>0.00001 BTC (1e-5)', // min order size
|
292
|
+
// '<td>0.00000001 BTC (1e-8)', // tick size
|
293
|
+
// '<td>0.01 USD', // quote currency price increment
|
294
|
+
// '</tr>'
|
295
|
+
// ]
|
296
|
+
const marketId = cells[0].replace ('<td>', '');
|
297
|
+
// const base = this.safeCurrencyCode (baseId);
|
298
|
+
const minAmountString = cells[1].replace ('<td>', '');
|
299
|
+
const minAmountParts = minAmountString.split (' ');
|
300
|
+
const minAmount = this.safeNumber (minAmountParts, 0);
|
301
|
+
const amountPrecisionString = cells[2].replace ('<td>', '');
|
302
|
+
const amountPrecisionParts = amountPrecisionString.split (' ');
|
303
|
+
const idLength = marketId.length - 0;
|
304
|
+
const startingIndex = idLength - 3;
|
305
|
+
const pricePrecisionString = cells[3].replace ('<td>', '');
|
306
|
+
const pricePrecisionParts = pricePrecisionString.split (' ');
|
307
|
+
const quoteId = this.safeStringLower (pricePrecisionParts, 1, marketId.slice (startingIndex, idLength));
|
308
|
+
const baseId = this.safeStringLower (amountPrecisionParts, 1, marketId.replace (quoteId, ''));
|
309
|
+
const base = this.safeCurrencyCode (baseId);
|
310
|
+
const quote = this.safeCurrencyCode (quoteId);
|
311
|
+
result.push ({
|
312
|
+
'id': marketId,
|
313
|
+
'symbol': base + '/' + quote,
|
314
|
+
'base': base,
|
315
|
+
'quote': quote,
|
316
|
+
'settle': undefined,
|
317
|
+
'baseId': baseId,
|
318
|
+
'quoteId': quoteId,
|
319
|
+
'settleId': undefined,
|
320
|
+
'type': 'spot',
|
321
|
+
'spot': true,
|
322
|
+
'margin': false,
|
323
|
+
'swap': false,
|
324
|
+
'future': false,
|
325
|
+
'option': false,
|
326
|
+
'active': undefined,
|
327
|
+
'contract': false,
|
328
|
+
'linear': undefined,
|
329
|
+
'inverse': undefined,
|
330
|
+
'contractSize': undefined,
|
331
|
+
'expiry': undefined,
|
332
|
+
'expiryDatetime': undefined,
|
333
|
+
'strike': undefined,
|
334
|
+
'optionType': undefined,
|
335
|
+
'precision': {
|
336
|
+
'amount': this.safeNumber (amountPrecisionParts, 0),
|
337
|
+
'price': this.safeNumber (pricePrecisionParts, 0),
|
338
|
+
},
|
339
|
+
'limits': {
|
340
|
+
'leverage': {
|
341
|
+
'min': undefined,
|
342
|
+
'max': undefined,
|
343
|
+
},
|
344
|
+
'amount': {
|
345
|
+
'min': minAmount,
|
346
|
+
'max': undefined,
|
347
|
+
},
|
348
|
+
'price': {
|
349
|
+
'min': undefined,
|
350
|
+
'max': undefined,
|
351
|
+
},
|
352
|
+
'cost': {
|
353
|
+
'min': undefined,
|
354
|
+
'max': undefined,
|
355
|
+
},
|
356
|
+
},
|
357
|
+
'info': row,
|
358
|
+
});
|
359
|
+
}
|
360
|
+
return result;
|
361
|
+
}
|
362
|
+
|
363
|
+
async fetchMarketsFromAPI (params = {}) {
|
364
|
+
const response = await this.publicGetV1Symbols (params);
|
365
|
+
const result = [];
|
366
|
+
for (let i = 0; i < response.length; i++) {
|
367
|
+
const marketId = response[i];
|
368
|
+
const market = marketId;
|
369
|
+
const idLength = marketId.length - 0;
|
370
|
+
const baseId = marketId.slice (0, idLength - 3);
|
371
|
+
const quoteId = marketId.slice (idLength - 3, idLength);
|
372
|
+
const base = this.safeCurrencyCode (baseId);
|
373
|
+
const quote = this.safeCurrencyCode (quoteId);
|
374
|
+
result.push ({
|
375
|
+
'id': marketId,
|
376
|
+
'symbol': base + '/' + quote,
|
377
|
+
'base': base,
|
378
|
+
'quote': quote,
|
379
|
+
'settle': undefined,
|
380
|
+
'baseId': baseId,
|
381
|
+
'quoteId': quoteId,
|
382
|
+
'settleId': undefined,
|
383
|
+
'type': 'spot',
|
384
|
+
'spot': true,
|
385
|
+
'margin': false,
|
386
|
+
'swap': false,
|
387
|
+
'future': false,
|
388
|
+
'option': false,
|
389
|
+
'active': undefined,
|
390
|
+
'contract': false,
|
391
|
+
'linear': undefined,
|
392
|
+
'inverse': undefined,
|
393
|
+
'contractSize': undefined,
|
394
|
+
'expiry': undefined,
|
395
|
+
'expiryDatetime': undefined,
|
396
|
+
'strike': undefined,
|
397
|
+
'optionType': undefined,
|
398
|
+
'precision': {
|
399
|
+
'price': undefined,
|
400
|
+
'amount': undefined,
|
401
|
+
},
|
402
|
+
'limits': {
|
403
|
+
'leverage': {
|
404
|
+
'min': undefined,
|
405
|
+
'max': undefined,
|
406
|
+
},
|
407
|
+
'amount': {
|
408
|
+
'min': undefined,
|
409
|
+
'max': undefined,
|
410
|
+
},
|
411
|
+
'price': {
|
412
|
+
'min': undefined,
|
413
|
+
'max': undefined,
|
414
|
+
},
|
415
|
+
'cost': {
|
416
|
+
'min': undefined,
|
417
|
+
'max': undefined,
|
418
|
+
},
|
419
|
+
},
|
420
|
+
'info': market,
|
421
|
+
});
|
422
|
+
}
|
423
|
+
return result;
|
424
|
+
}
|
425
|
+
|
426
|
+
async fetchOrderBook (symbol, limit = undefined, params = {}) {
|
427
|
+
await this.loadMarkets ();
|
428
|
+
const request = {
|
429
|
+
'symbol': this.marketId (symbol),
|
430
|
+
};
|
431
|
+
if (limit !== undefined) {
|
432
|
+
request['limit_bids'] = limit;
|
433
|
+
request['limit_asks'] = limit;
|
434
|
+
}
|
435
|
+
const response = await this.publicGetV1BookSymbol (this.extend (request, params));
|
436
|
+
return this.parseOrderBook (response, symbol, undefined, 'bids', 'asks', 'price', 'amount');
|
437
|
+
}
|
438
|
+
|
439
|
+
async fetchTickerV1 (symbol, params = {}) {
|
440
|
+
await this.loadMarkets ();
|
441
|
+
const market = this.market (symbol);
|
442
|
+
const request = {
|
443
|
+
'symbol': market['id'],
|
444
|
+
};
|
445
|
+
const response = await this.publicGetV1PubtickerSymbol (this.extend (request, params));
|
446
|
+
//
|
447
|
+
// {
|
448
|
+
// "bid":"9117.95",
|
449
|
+
// "ask":"9117.96",
|
450
|
+
// "volume":{
|
451
|
+
// "BTC":"1615.46861748",
|
452
|
+
// "USD":"14727307.57545006088",
|
453
|
+
// "timestamp":1594982700000
|
454
|
+
// },
|
455
|
+
// "last":"9115.23"
|
456
|
+
// }
|
457
|
+
//
|
458
|
+
return this.parseTicker (response, market);
|
459
|
+
}
|
460
|
+
|
461
|
+
async fetchTickerV2 (symbol, params = {}) {
|
462
|
+
await this.loadMarkets ();
|
463
|
+
const market = this.market (symbol);
|
464
|
+
const request = {
|
465
|
+
'symbol': market['id'],
|
466
|
+
};
|
467
|
+
const response = await this.publicGetV2TickerSymbol (this.extend (request, params));
|
468
|
+
//
|
469
|
+
// {
|
470
|
+
// "symbol":"BTCUSD",
|
471
|
+
// "open":"9080.58",
|
472
|
+
// "high":"9184.53",
|
473
|
+
// "low":"9063.56",
|
474
|
+
// "close":"9116.08",
|
475
|
+
// // Hourly prices descending for past 24 hours
|
476
|
+
// "changes":["9117.33","9105.69","9106.23","9120.35","9098.57","9114.53","9113.55","9128.01","9113.63","9133.49","9133.49","9137.75","9126.73","9103.91","9119.33","9123.04","9124.44","9117.57","9114.22","9102.33","9076.67","9074.72","9074.97","9092.05"],
|
477
|
+
// "bid":"9115.86",
|
478
|
+
// "ask":"9115.87"
|
479
|
+
// }
|
480
|
+
//
|
481
|
+
return this.parseTicker (response, market);
|
482
|
+
}
|
483
|
+
|
484
|
+
async fetchTickerV1AndV2 (symbol, params = {}) {
|
485
|
+
const tickerA = await this.fetchTickerV1 (symbol, params);
|
486
|
+
const tickerB = await this.fetchTickerV2 (symbol, params);
|
487
|
+
return this.deepExtend (tickerA, {
|
488
|
+
'open': tickerB['open'],
|
489
|
+
'high': tickerB['high'],
|
490
|
+
'low': tickerB['low'],
|
491
|
+
'change': tickerB['change'],
|
492
|
+
'percentage': tickerB['percentage'],
|
493
|
+
'average': tickerB['average'],
|
494
|
+
'info': tickerB['info'],
|
495
|
+
});
|
496
|
+
}
|
497
|
+
|
498
|
+
async fetchTicker (symbol, params = {}) {
|
499
|
+
const method = this.safeValue (this.options, 'fetchTickerMethod', 'fetchTickerV1');
|
500
|
+
return await this[method] (symbol, params);
|
501
|
+
}
|
502
|
+
|
503
|
+
parseTicker (ticker, market = undefined) {
|
504
|
+
//
|
505
|
+
// fetchTickers
|
506
|
+
//
|
507
|
+
// {
|
508
|
+
// "pair": "BATUSD",
|
509
|
+
// "price": "0.20687",
|
510
|
+
// "percentChange24h": "0.0146"
|
511
|
+
// }
|
512
|
+
//
|
513
|
+
// fetchTickerV1
|
514
|
+
//
|
515
|
+
// {
|
516
|
+
// "bid":"9117.95",
|
517
|
+
// "ask":"9117.96",
|
518
|
+
// "volume":{
|
519
|
+
// "BTC":"1615.46861748",
|
520
|
+
// "USD":"14727307.57545006088",
|
521
|
+
// "timestamp":1594982700000
|
522
|
+
// },
|
523
|
+
// "last":"9115.23"
|
524
|
+
// }
|
525
|
+
//
|
526
|
+
// fetchTickerV2
|
527
|
+
//
|
528
|
+
// {
|
529
|
+
// "symbol":"BTCUSD",
|
530
|
+
// "open":"9080.58",
|
531
|
+
// "high":"9184.53",
|
532
|
+
// "low":"9063.56",
|
533
|
+
// "close":"9116.08",
|
534
|
+
// // Hourly prices descending for past 24 hours
|
535
|
+
// "changes":["9117.33","9105.69","9106.23","9120.35","9098.57","9114.53","9113.55","9128.01","9113.63","9133.49","9133.49","9137.75","9126.73","9103.91","9119.33","9123.04","9124.44","9117.57","9114.22","9102.33","9076.67","9074.72","9074.97","9092.05"],
|
536
|
+
// "bid":"9115.86",
|
537
|
+
// "ask":"9115.87"
|
538
|
+
// }
|
539
|
+
//
|
540
|
+
const volume = this.safeValue (ticker, 'volume', {});
|
541
|
+
const timestamp = this.safeInteger (volume, 'timestamp');
|
542
|
+
let symbol = undefined;
|
543
|
+
const marketId = this.safeStringLower (ticker, 'pair');
|
544
|
+
market = this.safeMarket (marketId, market);
|
545
|
+
let baseId = undefined;
|
546
|
+
let quoteId = undefined;
|
547
|
+
let base = undefined;
|
548
|
+
let quote = undefined;
|
549
|
+
if ((marketId !== undefined) && (market === undefined)) {
|
550
|
+
const idLength = marketId.length - 0;
|
551
|
+
if (idLength === 7) {
|
552
|
+
baseId = marketId.slice (0, 4);
|
553
|
+
quoteId = marketId.slice (4, 7);
|
554
|
+
} else {
|
555
|
+
baseId = marketId.slice (0, 3);
|
556
|
+
quoteId = marketId.slice (3, 6);
|
557
|
+
}
|
558
|
+
base = this.safeCurrencyCode (baseId);
|
559
|
+
quote = this.safeCurrencyCode (quoteId);
|
560
|
+
symbol = base + '/' + quote;
|
561
|
+
}
|
562
|
+
if ((symbol === undefined) && (market !== undefined)) {
|
563
|
+
symbol = market['symbol'];
|
564
|
+
baseId = this.safeStringUpper (market, 'baseId');
|
565
|
+
quoteId = this.safeStringUpper (market, 'quoteId');
|
566
|
+
}
|
567
|
+
const price = this.safeString (ticker, 'price');
|
568
|
+
const last = this.safeString2 (ticker, 'last', 'close', price);
|
569
|
+
const percentage = this.safeString (ticker, 'percentChange24h');
|
570
|
+
const open = this.safeString (ticker, 'open');
|
571
|
+
const baseVolume = this.safeString (volume, baseId);
|
572
|
+
const quoteVolume = this.safeString (volume, quoteId);
|
573
|
+
return this.safeTicker ({
|
574
|
+
'symbol': symbol,
|
575
|
+
'timestamp': timestamp,
|
576
|
+
'datetime': this.iso8601 (timestamp),
|
577
|
+
'high': this.safeString (ticker, 'high'),
|
578
|
+
'low': this.safeString (ticker, 'low'),
|
579
|
+
'bid': this.safeString (ticker, 'bid'),
|
580
|
+
'bidVolume': undefined,
|
581
|
+
'ask': this.safeString (ticker, 'ask'),
|
582
|
+
'askVolume': undefined,
|
583
|
+
'vwap': undefined,
|
584
|
+
'open': open,
|
585
|
+
'close': last,
|
586
|
+
'last': last,
|
587
|
+
'previousClose': undefined, // previous day close
|
588
|
+
'change': undefined,
|
589
|
+
'percentage': percentage,
|
590
|
+
'average': undefined,
|
591
|
+
'baseVolume': baseVolume,
|
592
|
+
'quoteVolume': quoteVolume,
|
593
|
+
'info': ticker,
|
594
|
+
}, market, false);
|
595
|
+
}
|
596
|
+
|
597
|
+
async fetchTickers (symbols = undefined, params = {}) {
|
598
|
+
await this.loadMarkets ();
|
599
|
+
const response = await this.publicGetV1Pricefeed (params);
|
600
|
+
//
|
601
|
+
// [
|
602
|
+
// {
|
603
|
+
// "pair": "BATUSD",
|
604
|
+
// "price": "0.20687",
|
605
|
+
// "percentChange24h": "0.0146"
|
606
|
+
// },
|
607
|
+
// {
|
608
|
+
// "pair": "LINKETH",
|
609
|
+
// "price": "0.018",
|
610
|
+
// "percentChange24h": "0.0000"
|
611
|
+
// },
|
612
|
+
// ]
|
613
|
+
//
|
614
|
+
return this.parseTickers (response, symbols);
|
615
|
+
}
|
616
|
+
|
617
|
+
parseTrade (trade, market = undefined) {
|
618
|
+
//
|
619
|
+
// public fetchTrades
|
620
|
+
//
|
621
|
+
// {
|
622
|
+
// "timestamp":1601617445,
|
623
|
+
// "timestampms":1601617445144,
|
624
|
+
// "tid":14122489752,
|
625
|
+
// "price":"0.46476",
|
626
|
+
// "amount":"28.407209",
|
627
|
+
// "exchange":"gemini",
|
628
|
+
// "type":"buy"
|
629
|
+
// }
|
630
|
+
//
|
631
|
+
// private fetchTrades
|
632
|
+
//
|
633
|
+
// {
|
634
|
+
// "price":"3900.00",
|
635
|
+
// "amount":"0.00996",
|
636
|
+
// "timestamp":1638891173,
|
637
|
+
// "timestampms":1638891173518,
|
638
|
+
// "type":"Sell",
|
639
|
+
// "aggressor":false,
|
640
|
+
// "fee_currency":"EUR",
|
641
|
+
// "fee_amount":"0.00",
|
642
|
+
// "tid":73621746145,
|
643
|
+
// "order_id":"73621746059",
|
644
|
+
// "exchange":"gemini",
|
645
|
+
// "is_auction_fill":false,
|
646
|
+
// "is_clearing_fill":false,
|
647
|
+
// "symbol":"ETHEUR",
|
648
|
+
// "client_order_id":"1638891171610"
|
649
|
+
// }
|
650
|
+
//
|
651
|
+
const timestamp = this.safeInteger (trade, 'timestampms');
|
652
|
+
const id = this.safeString (trade, 'tid');
|
653
|
+
const orderId = this.safeString (trade, 'order_id');
|
654
|
+
const feeCurrencyId = this.safeString (trade, 'fee_currency');
|
655
|
+
const feeCurrencyCode = this.safeCurrencyCode (feeCurrencyId);
|
656
|
+
const fee = {
|
657
|
+
'cost': this.safeString (trade, 'fee_amount'),
|
658
|
+
'currency': feeCurrencyCode,
|
659
|
+
};
|
660
|
+
const priceString = this.safeString (trade, 'price');
|
661
|
+
const amountString = this.safeString (trade, 'amount');
|
662
|
+
const side = this.safeStringLower (trade, 'type');
|
663
|
+
const symbol = this.safeSymbol (undefined, market);
|
664
|
+
return this.safeTrade ({
|
665
|
+
'id': id,
|
666
|
+
'order': orderId,
|
667
|
+
'info': trade,
|
668
|
+
'timestamp': timestamp,
|
669
|
+
'datetime': this.iso8601 (timestamp),
|
670
|
+
'symbol': symbol,
|
671
|
+
'type': undefined,
|
672
|
+
'side': side,
|
673
|
+
'takerOrMaker': undefined,
|
674
|
+
'price': priceString,
|
675
|
+
'cost': undefined,
|
676
|
+
'amount': amountString,
|
677
|
+
'fee': fee,
|
678
|
+
}, market);
|
679
|
+
}
|
680
|
+
|
681
|
+
async fetchTrades (symbol, since = undefined, limit = undefined, params = {}) {
|
682
|
+
await this.loadMarkets ();
|
683
|
+
const market = this.market (symbol);
|
684
|
+
const request = {
|
685
|
+
'symbol': market['id'],
|
686
|
+
};
|
687
|
+
const response = await this.publicGetV1TradesSymbol (this.extend (request, params));
|
688
|
+
//
|
689
|
+
// [
|
690
|
+
// {
|
691
|
+
// "timestamp":1601617445,
|
692
|
+
// "timestampms":1601617445144,
|
693
|
+
// "tid":14122489752,
|
694
|
+
// "price":"0.46476",
|
695
|
+
// "amount":"28.407209",
|
696
|
+
// "exchange":"gemini",
|
697
|
+
// "type":"buy"
|
698
|
+
// },
|
699
|
+
// ]
|
700
|
+
//
|
701
|
+
return this.parseTrades (response, market, since, limit);
|
702
|
+
}
|
703
|
+
|
704
|
+
parseBalance (response) {
|
705
|
+
const result = { 'info': response };
|
706
|
+
for (let i = 0; i < response.length; i++) {
|
707
|
+
const balance = response[i];
|
708
|
+
const currencyId = this.safeString (balance, 'currency');
|
709
|
+
const code = this.safeCurrencyCode (currencyId);
|
710
|
+
const account = this.account ();
|
711
|
+
account['free'] = this.safeString (balance, 'available');
|
712
|
+
account['total'] = this.safeString (balance, 'amount');
|
713
|
+
result[code] = account;
|
714
|
+
}
|
715
|
+
return this.safeBalance (result);
|
716
|
+
}
|
717
|
+
|
718
|
+
async fetchTradingFees (params = {}) {
|
719
|
+
await this.loadMarkets ();
|
720
|
+
const response = await this.privatePostV1Notionalvolume (params);
|
721
|
+
//
|
722
|
+
// {
|
723
|
+
// "web_maker_fee_bps": 25,
|
724
|
+
// "web_taker_fee_bps": 35,
|
725
|
+
// "web_auction_fee_bps": 25,
|
726
|
+
// "api_maker_fee_bps": 10,
|
727
|
+
// "api_taker_fee_bps": 35,
|
728
|
+
// "api_auction_fee_bps": 20,
|
729
|
+
// "fix_maker_fee_bps": 10,
|
730
|
+
// "fix_taker_fee_bps": 35,
|
731
|
+
// "fix_auction_fee_bps": 20,
|
732
|
+
// "block_maker_fee_bps": 0,
|
733
|
+
// "block_taker_fee_bps": 50,
|
734
|
+
// "notional_30d_volume": 150.00,
|
735
|
+
// "last_updated_ms": 1551371446000,
|
736
|
+
// "date": "2019-02-28",
|
737
|
+
// "notional_1d_volume": [
|
738
|
+
// {
|
739
|
+
// "date": "2019-02-22",
|
740
|
+
// "notional_volume": 75.00
|
741
|
+
// },
|
742
|
+
// {
|
743
|
+
// "date": "2019-02-14",
|
744
|
+
// "notional_volume": 75.00
|
745
|
+
// }
|
746
|
+
// ]
|
747
|
+
// }
|
748
|
+
//
|
749
|
+
const makerBps = this.safeString (response, 'api_maker_fee_bps');
|
750
|
+
const takerBps = this.safeString (response, 'api_taker_fee_bps');
|
751
|
+
const makerString = Precise.stringDiv (makerBps, '10000');
|
752
|
+
const takerString = Precise.stringDiv (takerBps, '10000');
|
753
|
+
const maker = this.parseNumber (makerString);
|
754
|
+
const taker = this.parseNumber (takerString);
|
755
|
+
const result = {};
|
756
|
+
for (let i = 0; i < this.symbols.length; i++) {
|
757
|
+
const symbol = this.symbols[i];
|
758
|
+
result[symbol] = {
|
759
|
+
'info': response,
|
760
|
+
'symbol': symbol,
|
761
|
+
'maker': maker,
|
762
|
+
'taker': taker,
|
763
|
+
'percentage': true,
|
764
|
+
'tierBased': true,
|
765
|
+
};
|
766
|
+
}
|
767
|
+
return result;
|
768
|
+
}
|
769
|
+
|
770
|
+
async fetchBalance (params = {}) {
|
771
|
+
await this.loadMarkets ();
|
772
|
+
const response = await this.privatePostV1Balances (params);
|
773
|
+
return this.parseBalance (response);
|
774
|
+
}
|
775
|
+
|
776
|
+
parseOrder (order, market = undefined) {
|
777
|
+
//
|
778
|
+
// createOrder (private)
|
779
|
+
//
|
780
|
+
// {
|
781
|
+
// "order_id":"106027397702",
|
782
|
+
// "id":"106027397702",
|
783
|
+
// "symbol":"etheur",
|
784
|
+
// "exchange":"gemini",
|
785
|
+
// "avg_execution_price":"2877.48",
|
786
|
+
// "side":"sell",
|
787
|
+
// "type":"exchange limit",
|
788
|
+
// "timestamp":"1650398122",
|
789
|
+
// "timestampms":1650398122308,
|
790
|
+
// "is_live":false,
|
791
|
+
// "is_cancelled":false,
|
792
|
+
// "is_hidden":false,
|
793
|
+
// "was_forced":false,
|
794
|
+
// "executed_amount":"0.014434",
|
795
|
+
// "client_order_id":"1650398121695",
|
796
|
+
// "options":[],
|
797
|
+
// "price":"2800.00",
|
798
|
+
// "original_amount":"0.014434",
|
799
|
+
// "remaining_amount":"0"
|
800
|
+
// }
|
801
|
+
//
|
802
|
+
// fetchOrder (private)
|
803
|
+
//
|
804
|
+
// {
|
805
|
+
// "order_id":"106028543717",
|
806
|
+
// "id":"106028543717",
|
807
|
+
// "symbol":"etheur",
|
808
|
+
// "exchange":"gemini",
|
809
|
+
// "avg_execution_price":"0.00",
|
810
|
+
// "side":"buy",
|
811
|
+
// "type":"exchange limit",
|
812
|
+
// "timestamp":"1650398446",
|
813
|
+
// "timestampms":1650398446375,
|
814
|
+
// "is_live":true,
|
815
|
+
// "is_cancelled":false,
|
816
|
+
// "is_hidden":false,
|
817
|
+
// "was_forced":false,
|
818
|
+
// "executed_amount":"0",
|
819
|
+
// "client_order_id":"1650398445709",
|
820
|
+
// "options":[],
|
821
|
+
// "price":"2000.00",
|
822
|
+
// "original_amount":"0.01",
|
823
|
+
// "remaining_amount":"0.01"
|
824
|
+
// }
|
825
|
+
//
|
826
|
+
// fetchOpenOrders (private)
|
827
|
+
//
|
828
|
+
// {
|
829
|
+
// "order_id":"106028543717",
|
830
|
+
// "id":"106028543717",
|
831
|
+
// "symbol":"etheur",
|
832
|
+
// "exchange":"gemini",
|
833
|
+
// "avg_execution_price":"0.00",
|
834
|
+
// "side":"buy",
|
835
|
+
// "type":"exchange limit",
|
836
|
+
// "timestamp":"1650398446",
|
837
|
+
// "timestampms":1650398446375,
|
838
|
+
// "is_live":true,
|
839
|
+
// "is_cancelled":false,
|
840
|
+
// "is_hidden":false,
|
841
|
+
// "was_forced":false,
|
842
|
+
// "executed_amount":"0",
|
843
|
+
// "client_order_id":"1650398445709",
|
844
|
+
// "options":[],
|
845
|
+
// "price":"2000.00",
|
846
|
+
// "original_amount":"0.01",
|
847
|
+
// "remaining_amount":"0.01"
|
848
|
+
// }
|
849
|
+
//
|
850
|
+
// cancelOrder (private)
|
851
|
+
//
|
852
|
+
// {
|
853
|
+
// "order_id":"106028543717",
|
854
|
+
// "id":"106028543717",
|
855
|
+
// "symbol":"etheur",
|
856
|
+
// "exchange":"gemini",
|
857
|
+
// "avg_execution_price":"0.00",
|
858
|
+
// "side":"buy",
|
859
|
+
// "type":"exchange limit",
|
860
|
+
// "timestamp":"1650398446",
|
861
|
+
// "timestampms":1650398446375,
|
862
|
+
// "is_live":false,
|
863
|
+
// "is_cancelled":true,
|
864
|
+
// "is_hidden":false,
|
865
|
+
// "was_forced":false,
|
866
|
+
// "executed_amount":"0",
|
867
|
+
// "client_order_id":"1650398445709",
|
868
|
+
// "reason":"Requested",
|
869
|
+
// "options":[],
|
870
|
+
// "price":"2000.00",
|
871
|
+
// "original_amount":"0.01",
|
872
|
+
// "remaining_amount":"0.01"
|
873
|
+
// }
|
874
|
+
//
|
875
|
+
const timestamp = this.safeInteger (order, 'timestampms');
|
876
|
+
const amount = this.safeString (order, 'original_amount');
|
877
|
+
const remaining = this.safeString (order, 'remaining_amount');
|
878
|
+
const filled = this.safeString (order, 'executed_amount');
|
879
|
+
let status = 'closed';
|
880
|
+
if (order['is_live']) {
|
881
|
+
status = 'open';
|
882
|
+
}
|
883
|
+
if (order['is_cancelled']) {
|
884
|
+
status = 'canceled';
|
885
|
+
}
|
886
|
+
const price = this.safeString (order, 'price');
|
887
|
+
const average = this.safeString (order, 'avg_execution_price');
|
888
|
+
let type = this.safeString (order, 'type');
|
889
|
+
if (type === 'exchange limit') {
|
890
|
+
type = 'limit';
|
891
|
+
} else if (type === 'market buy' || type === 'market sell') {
|
892
|
+
type = 'market';
|
893
|
+
} else {
|
894
|
+
type = order['type'];
|
895
|
+
}
|
896
|
+
const fee = undefined;
|
897
|
+
const marketId = this.safeString (order, 'symbol');
|
898
|
+
const symbol = this.safeSymbol (marketId, market);
|
899
|
+
const id = this.safeString (order, 'order_id');
|
900
|
+
const side = this.safeStringLower (order, 'side');
|
901
|
+
const clientOrderId = this.safeString (order, 'client_order_id');
|
902
|
+
const optionsArray = this.safeValue (order, 'options', []);
|
903
|
+
const option = this.safeString (optionsArray, 0);
|
904
|
+
let timeInForce = 'GTC';
|
905
|
+
let postOnly = false;
|
906
|
+
if (option !== undefined) {
|
907
|
+
if (option === 'immediate-or-cancel') {
|
908
|
+
timeInForce = 'IOC';
|
909
|
+
} else if (option === 'fill-or-kill') {
|
910
|
+
timeInForce = 'FOK';
|
911
|
+
} else if (option === 'maker-or-cancel') {
|
912
|
+
timeInForce = 'PO';
|
913
|
+
postOnly = true;
|
914
|
+
}
|
915
|
+
}
|
916
|
+
return this.safeOrder ({
|
917
|
+
'id': id,
|
918
|
+
'clientOrderId': clientOrderId,
|
919
|
+
'info': order,
|
920
|
+
'timestamp': timestamp,
|
921
|
+
'datetime': this.iso8601 (timestamp),
|
922
|
+
'lastTradeTimestamp': undefined,
|
923
|
+
'status': status,
|
924
|
+
'symbol': symbol,
|
925
|
+
'type': type,
|
926
|
+
'timeInForce': timeInForce, // default set to GTC
|
927
|
+
'postOnly': postOnly,
|
928
|
+
'side': side,
|
929
|
+
'price': price,
|
930
|
+
'stopPrice': undefined,
|
931
|
+
'average': average,
|
932
|
+
'cost': undefined,
|
933
|
+
'amount': amount,
|
934
|
+
'filled': filled,
|
935
|
+
'remaining': remaining,
|
936
|
+
'fee': fee,
|
937
|
+
'trades': undefined,
|
938
|
+
}, market);
|
939
|
+
}
|
940
|
+
|
941
|
+
async fetchOrder (id, symbol = undefined, params = {}) {
|
942
|
+
await this.loadMarkets ();
|
943
|
+
const request = {
|
944
|
+
'order_id': id,
|
945
|
+
};
|
946
|
+
const response = await this.privatePostV1OrderStatus (this.extend (request, params));
|
947
|
+
//
|
948
|
+
// {
|
949
|
+
// "order_id":"106028543717",
|
950
|
+
// "id":"106028543717",
|
951
|
+
// "symbol":"etheur",
|
952
|
+
// "exchange":"gemini",
|
953
|
+
// "avg_execution_price":"0.00",
|
954
|
+
// "side":"buy",
|
955
|
+
// "type":"exchange limit",
|
956
|
+
// "timestamp":"1650398446",
|
957
|
+
// "timestampms":1650398446375,
|
958
|
+
// "is_live":true,
|
959
|
+
// "is_cancelled":false,
|
960
|
+
// "is_hidden":false,
|
961
|
+
// "was_forced":false,
|
962
|
+
// "executed_amount":"0",
|
963
|
+
// "client_order_id":"1650398445709",
|
964
|
+
// "options":[],
|
965
|
+
// "price":"2000.00",
|
966
|
+
// "original_amount":"0.01",
|
967
|
+
// "remaining_amount":"0.01"
|
968
|
+
// }
|
969
|
+
//
|
970
|
+
return this.parseOrder (response);
|
971
|
+
}
|
972
|
+
|
973
|
+
async fetchOpenOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) {
|
974
|
+
await this.loadMarkets ();
|
975
|
+
const response = await this.privatePostV1Orders (); // takes no params
|
976
|
+
//
|
977
|
+
// [
|
978
|
+
// {
|
979
|
+
// "order_id":"106028543717",
|
980
|
+
// "id":"106028543717",
|
981
|
+
// "symbol":"etheur",
|
982
|
+
// "exchange":"gemini",
|
983
|
+
// "avg_execution_price":"0.00",
|
984
|
+
// "side":"buy",
|
985
|
+
// "type":"exchange limit",
|
986
|
+
// "timestamp":"1650398446",
|
987
|
+
// "timestampms":1650398446375,
|
988
|
+
// "is_live":true,
|
989
|
+
// "is_cancelled":false,
|
990
|
+
// "is_hidden":false,
|
991
|
+
// "was_forced":false,
|
992
|
+
// "executed_amount":"0",
|
993
|
+
// "client_order_id":"1650398445709",
|
994
|
+
// "options":[],
|
995
|
+
// "price":"2000.00",
|
996
|
+
// "original_amount":"0.01",
|
997
|
+
// "remaining_amount":"0.01"
|
998
|
+
// }
|
999
|
+
// ]
|
1000
|
+
//
|
1001
|
+
let market = undefined;
|
1002
|
+
if (symbol !== undefined) {
|
1003
|
+
market = this.market (symbol); // throws on non-existent symbol
|
1004
|
+
}
|
1005
|
+
return this.parseOrders (response, market, since, limit);
|
1006
|
+
}
|
1007
|
+
|
1008
|
+
async createOrder (symbol, type, side, amount, price = undefined, params = {}) {
|
1009
|
+
await this.loadMarkets ();
|
1010
|
+
if (type === 'market') {
|
1011
|
+
throw new ExchangeError (this.id + ' createOrder() allows limit orders only');
|
1012
|
+
}
|
1013
|
+
let clientOrderId = this.safeString2 (params, 'clientOrderId', 'client_order_id');
|
1014
|
+
params = this.omit (params, [ 'clientOrderId', 'client_order_id' ]);
|
1015
|
+
if (clientOrderId === undefined) {
|
1016
|
+
clientOrderId = this.nonce ();
|
1017
|
+
}
|
1018
|
+
const amountString = this.amountToPrecision (symbol, amount);
|
1019
|
+
const priceString = this.priceToPrecision (symbol, price);
|
1020
|
+
const request = {
|
1021
|
+
'client_order_id': clientOrderId.toString (),
|
1022
|
+
'symbol': this.marketId (symbol),
|
1023
|
+
'amount': amountString,
|
1024
|
+
'price': priceString,
|
1025
|
+
'side': side,
|
1026
|
+
'type': 'exchange limit', // gemini allows limit orders only
|
1027
|
+
// 'options': [], one of: maker-or-cancel, immediate-or-cancel, fill-or-kill, auction-only, indication-of-interest
|
1028
|
+
};
|
1029
|
+
type = this.safeString (params, 'type', type);
|
1030
|
+
params = this.omit (params, 'type');
|
1031
|
+
const rawStopPrice = this.safeString2 (params, 'stop_price', 'stopPrice');
|
1032
|
+
params = this.omit (params, [ 'stop_price', 'stopPrice', 'type' ]);
|
1033
|
+
if (type === 'stopLimit') {
|
1034
|
+
throw new ArgumentsRequired (this.id + ' createOrder() requires a stopPrice parameter or a stop_price parameter for ' + type + ' orders');
|
1035
|
+
}
|
1036
|
+
if (rawStopPrice !== undefined) {
|
1037
|
+
request['stop_price'] = this.priceToPrecision (symbol, rawStopPrice);
|
1038
|
+
request['type'] = 'exchange stop limit';
|
1039
|
+
} else {
|
1040
|
+
// No options can be applied to stop-limit orders at this time.
|
1041
|
+
const timeInForce = this.safeString (params, 'timeInForce');
|
1042
|
+
params = this.omit (params, 'timeInForce');
|
1043
|
+
if (timeInForce !== undefined) {
|
1044
|
+
if ((timeInForce === 'IOC') || (timeInForce === 'immediate-or-cancel')) {
|
1045
|
+
request['options'] = [ 'immediate-or-cancel' ];
|
1046
|
+
} else if ((timeInForce === 'FOK') || (timeInForce === 'fill-or-kill')) {
|
1047
|
+
request['options'] = [ 'fill-or-kill' ];
|
1048
|
+
} else if (timeInForce === 'PO') {
|
1049
|
+
request['options'] = [ 'maker-or-cancel' ];
|
1050
|
+
}
|
1051
|
+
}
|
1052
|
+
const postOnly = this.safeValue (params, 'postOnly', false);
|
1053
|
+
params = this.omit (params, 'postOnly');
|
1054
|
+
if (postOnly) {
|
1055
|
+
request['options'] = [ 'maker-or-cancel' ];
|
1056
|
+
}
|
1057
|
+
// allowing override for auction-only and indication-of-interest order options
|
1058
|
+
const options = this.safeString (params, 'options');
|
1059
|
+
if (options !== undefined) {
|
1060
|
+
request['options'] = [ options ];
|
1061
|
+
}
|
1062
|
+
}
|
1063
|
+
const response = await this.privatePostV1OrderNew (this.extend (request, params));
|
1064
|
+
//
|
1065
|
+
// {
|
1066
|
+
// "order_id":"106027397702",
|
1067
|
+
// "id":"106027397702",
|
1068
|
+
// "symbol":"etheur",
|
1069
|
+
// "exchange":"gemini",
|
1070
|
+
// "avg_execution_price":"2877.48",
|
1071
|
+
// "side":"sell",
|
1072
|
+
// "type":"exchange limit",
|
1073
|
+
// "timestamp":"1650398122",
|
1074
|
+
// "timestampms":1650398122308,
|
1075
|
+
// "is_live":false,
|
1076
|
+
// "is_cancelled":false,
|
1077
|
+
// "is_hidden":false,
|
1078
|
+
// "was_forced":false,
|
1079
|
+
// "executed_amount":"0.014434",
|
1080
|
+
// "client_order_id":"1650398121695",
|
1081
|
+
// "options":[],
|
1082
|
+
// "price":"2800.00",
|
1083
|
+
// "original_amount":"0.014434",
|
1084
|
+
// "remaining_amount":"0"
|
1085
|
+
// }
|
1086
|
+
//
|
1087
|
+
return this.parseOrder (response);
|
1088
|
+
}
|
1089
|
+
|
1090
|
+
async cancelOrder (id, symbol = undefined, params = {}) {
|
1091
|
+
await this.loadMarkets ();
|
1092
|
+
const request = {
|
1093
|
+
'order_id': id,
|
1094
|
+
};
|
1095
|
+
const response = await this.privatePostV1OrderCancel (this.extend (request, params));
|
1096
|
+
//
|
1097
|
+
// {
|
1098
|
+
// "order_id":"106028543717",
|
1099
|
+
// "id":"106028543717",
|
1100
|
+
// "symbol":"etheur",
|
1101
|
+
// "exchange":"gemini",
|
1102
|
+
// "avg_execution_price":"0.00",
|
1103
|
+
// "side":"buy",
|
1104
|
+
// "type":"exchange limit",
|
1105
|
+
// "timestamp":"1650398446",
|
1106
|
+
// "timestampms":1650398446375,
|
1107
|
+
// "is_live":false,
|
1108
|
+
// "is_cancelled":true,
|
1109
|
+
// "is_hidden":false,
|
1110
|
+
// "was_forced":false,
|
1111
|
+
// "executed_amount":"0",
|
1112
|
+
// "client_order_id":"1650398445709",
|
1113
|
+
// "reason":"Requested",
|
1114
|
+
// "options":[],
|
1115
|
+
// "price":"2000.00",
|
1116
|
+
// "original_amount":"0.01",
|
1117
|
+
// "remaining_amount":"0.01"
|
1118
|
+
// }
|
1119
|
+
//
|
1120
|
+
return this.parseOrder (response);
|
1121
|
+
}
|
1122
|
+
|
1123
|
+
async fetchMyTrades (symbol = undefined, since = undefined, limit = undefined, params = {}) {
|
1124
|
+
if (symbol === undefined) {
|
1125
|
+
throw new ArgumentsRequired (this.id + ' fetchMyTrades() requires a symbol argument');
|
1126
|
+
}
|
1127
|
+
await this.loadMarkets ();
|
1128
|
+
const market = this.market (symbol);
|
1129
|
+
const request = {
|
1130
|
+
'symbol': market['id'],
|
1131
|
+
};
|
1132
|
+
if (limit !== undefined) {
|
1133
|
+
request['limit_trades'] = limit;
|
1134
|
+
}
|
1135
|
+
if (since !== undefined) {
|
1136
|
+
request['timestamp'] = parseInt (since / 1000);
|
1137
|
+
}
|
1138
|
+
const response = await this.privatePostV1Mytrades (this.extend (request, params));
|
1139
|
+
return this.parseTrades (response, market, since, limit);
|
1140
|
+
}
|
1141
|
+
|
1142
|
+
async withdraw (code, amount, address, tag = undefined, params = {}) {
|
1143
|
+
[ tag, params ] = this.handleWithdrawTagAndParams (tag, params);
|
1144
|
+
this.checkAddress (address);
|
1145
|
+
await this.loadMarkets ();
|
1146
|
+
const currency = this.currency (code);
|
1147
|
+
const request = {
|
1148
|
+
'currency': currency['id'],
|
1149
|
+
'amount': amount,
|
1150
|
+
'address': address,
|
1151
|
+
};
|
1152
|
+
const response = await this.privatePostV1WithdrawCurrency (this.extend (request, params));
|
1153
|
+
//
|
1154
|
+
// for BTC
|
1155
|
+
// {
|
1156
|
+
// "address":"mi98Z9brJ3TgaKsmvXatuRahbFRUFKRUdR",
|
1157
|
+
// "amount":"1",
|
1158
|
+
// "withdrawalId":"02176a83-a6b1-4202-9b85-1c1c92dd25c4",
|
1159
|
+
// "message":"You have requested a transfer of 1 BTC to mi98Z9brJ3TgaKsmvXatuRahbFRUFKRUdR. This withdrawal will be sent to the blockchain within the next 60 seconds."
|
1160
|
+
// }
|
1161
|
+
//
|
1162
|
+
// for ETH
|
1163
|
+
// {
|
1164
|
+
// "address":"0xA63123350Acc8F5ee1b1fBd1A6717135e82dBd28",
|
1165
|
+
// "amount":"2.34567",
|
1166
|
+
// "txHash":"0x28267179f92926d85c5516bqc063b2631935573d8915258e95d9572eedcc8cc"
|
1167
|
+
// }
|
1168
|
+
//
|
1169
|
+
// for error (other variations of error messages are also expected)
|
1170
|
+
// {
|
1171
|
+
// "result":"error",
|
1172
|
+
// "reason":"CryptoAddressWhitelistsNotEnabled",
|
1173
|
+
// "message":"Cryptocurrency withdrawal address whitelists are not enabled for account 24. Please contact support@gemini.com for information on setting up a withdrawal address whitelist."
|
1174
|
+
// }
|
1175
|
+
//
|
1176
|
+
const result = this.safeString (response, 'result');
|
1177
|
+
if (result === 'error') {
|
1178
|
+
throw new ExchangeError (this.id + ' withdraw() failed: ' + this.json (response));
|
1179
|
+
}
|
1180
|
+
return this.parseTransaction (response, currency);
|
1181
|
+
}
|
1182
|
+
|
1183
|
+
nonce () {
|
1184
|
+
return this.milliseconds ();
|
1185
|
+
}
|
1186
|
+
|
1187
|
+
async fetchTransactions (code = undefined, since = undefined, limit = undefined, params = {}) {
|
1188
|
+
await this.loadMarkets ();
|
1189
|
+
const request = {};
|
1190
|
+
if (limit !== undefined) {
|
1191
|
+
request['limit_transfers'] = limit;
|
1192
|
+
}
|
1193
|
+
if (since !== undefined) {
|
1194
|
+
request['timestamp'] = since;
|
1195
|
+
}
|
1196
|
+
const response = await this.privatePostV1Transfers (this.extend (request, params));
|
1197
|
+
return this.parseTransactions (response);
|
1198
|
+
}
|
1199
|
+
|
1200
|
+
parseTransaction (transaction, currency = undefined) {
|
1201
|
+
//
|
1202
|
+
// withdraw
|
1203
|
+
//
|
1204
|
+
// for BTC
|
1205
|
+
// {
|
1206
|
+
// "address":"mi98Z9brJ3TgaKsmvXatuRahbFRUFKRUdR",
|
1207
|
+
// "amount":"1",
|
1208
|
+
// "withdrawalId":"02176a83-a6b1-4202-9b85-1c1c92dd25c4",
|
1209
|
+
// "message":"You have requested a transfer of 1 BTC to mi98Z9brJ3TgaKsmvXatuRahbFRUFKRUdR. This withdrawal will be sent to the blockchain within the next 60 seconds."
|
1210
|
+
// }
|
1211
|
+
//
|
1212
|
+
// for ETH
|
1213
|
+
// {
|
1214
|
+
// "address":"0xA63123350Acc8F5ee1b1fBd1A6717135e82dBd28",
|
1215
|
+
// "amount":"2.34567",
|
1216
|
+
// "txHash":"0x28267179f92926d85c5516bqc063b2631935573d8915258e95d9572eedcc8cc"
|
1217
|
+
// }
|
1218
|
+
//
|
1219
|
+
const timestamp = this.safeInteger (transaction, 'timestampms');
|
1220
|
+
const currencyId = this.safeString (transaction, 'currency');
|
1221
|
+
const code = this.safeCurrencyCode (currencyId, currency);
|
1222
|
+
const address = this.safeString (transaction, 'destination');
|
1223
|
+
const type = this.safeStringLower (transaction, 'type');
|
1224
|
+
// if status field is available, then it's complete
|
1225
|
+
const statusRaw = this.safeString (transaction, 'status');
|
1226
|
+
let fee = undefined;
|
1227
|
+
const feeAmount = this.safeNumber (transaction, 'feeAmount');
|
1228
|
+
if (feeAmount !== undefined) {
|
1229
|
+
fee = {
|
1230
|
+
'cost': feeAmount,
|
1231
|
+
'currency': code,
|
1232
|
+
};
|
1233
|
+
}
|
1234
|
+
return {
|
1235
|
+
'info': transaction,
|
1236
|
+
'id': this.safeString2 (transaction, 'eid', 'withdrawalId'),
|
1237
|
+
'txid': this.safeString (transaction, 'txHash'),
|
1238
|
+
'timestamp': timestamp,
|
1239
|
+
'datetime': this.iso8601 (timestamp),
|
1240
|
+
'network': undefined,
|
1241
|
+
'address': address,
|
1242
|
+
'addressTo': undefined,
|
1243
|
+
'addressFrom': undefined,
|
1244
|
+
'tag': undefined, // or is it defined?
|
1245
|
+
'tagTo': undefined,
|
1246
|
+
'tagFrom': undefined,
|
1247
|
+
'type': type, // direction of the transaction, ('deposit' | 'withdraw')
|
1248
|
+
'amount': this.safeNumber (transaction, 'amount'),
|
1249
|
+
'currency': code,
|
1250
|
+
'status': this.parseTransactionStatus (statusRaw),
|
1251
|
+
'updated': undefined,
|
1252
|
+
'fee': fee,
|
1253
|
+
};
|
1254
|
+
}
|
1255
|
+
|
1256
|
+
parseTransactionStatus (status) {
|
1257
|
+
const statuses = {
|
1258
|
+
'Advanced': 'ok',
|
1259
|
+
'Complete': 'ok',
|
1260
|
+
};
|
1261
|
+
return this.safeString (statuses, status, status);
|
1262
|
+
}
|
1263
|
+
|
1264
|
+
parseDepositAddress (depositAddress, currency = undefined) {
|
1265
|
+
//
|
1266
|
+
// {
|
1267
|
+
// address: "0xed6494Fe7c1E56d1bd6136e89268C51E32d9708B",
|
1268
|
+
// timestamp: "1636813923098",
|
1269
|
+
// addressVersion: "eV1" }
|
1270
|
+
// }
|
1271
|
+
//
|
1272
|
+
const address = this.safeString (depositAddress, 'address');
|
1273
|
+
return {
|
1274
|
+
'currency': currency,
|
1275
|
+
'network': undefined,
|
1276
|
+
'address': address,
|
1277
|
+
'tag': undefined,
|
1278
|
+
'info': depositAddress,
|
1279
|
+
};
|
1280
|
+
}
|
1281
|
+
|
1282
|
+
async fetchDepositAddressesByNetwork (code, params = {}) {
|
1283
|
+
await this.loadMarkets ();
|
1284
|
+
const network = this.safeString (params, 'network');
|
1285
|
+
if (network === undefined) {
|
1286
|
+
throw new ArgumentsRequired (this.id + ' fetchDepositAddressesByNetwork() requires a network parameter');
|
1287
|
+
}
|
1288
|
+
params = this.omit (params, 'network');
|
1289
|
+
const networks = this.safeValue (this.options, 'networks', {});
|
1290
|
+
const networkId = this.safeString (networks, network, network);
|
1291
|
+
const networkIds = this.safeValue (this.options, 'networkIds', {});
|
1292
|
+
const networkCode = this.safeString (networkIds, networkId, network);
|
1293
|
+
const request = {
|
1294
|
+
'network': networkId,
|
1295
|
+
};
|
1296
|
+
const response = await this.privatePostV1AddressesNetwork (this.extend (request, params));
|
1297
|
+
const results = this.parseDepositAddresses (response, [ code ], false, { 'network': networkCode, 'currency': code });
|
1298
|
+
return this.groupBy (results, 'network');
|
1299
|
+
}
|
1300
|
+
|
1301
|
+
sign (path, api = 'public', method = 'GET', params = {}, headers = undefined, body = undefined) {
|
1302
|
+
let url = '/' + this.implodeParams (path, params);
|
1303
|
+
const query = this.omit (params, this.extractParams (path));
|
1304
|
+
if (api === 'private') {
|
1305
|
+
this.checkRequiredCredentials ();
|
1306
|
+
const apiKey = this.apiKey;
|
1307
|
+
if (apiKey.indexOf ('account') < 0) {
|
1308
|
+
throw new AuthenticationError (this.id + ' sign() requires an account-key, master-keys are not-supported');
|
1309
|
+
}
|
1310
|
+
const nonce = this.nonce ();
|
1311
|
+
const request = this.extend ({
|
1312
|
+
'request': url,
|
1313
|
+
'nonce': nonce,
|
1314
|
+
}, query);
|
1315
|
+
let payload = this.json (request);
|
1316
|
+
payload = this.stringToBase64 (payload);
|
1317
|
+
const signature = this.hmac (payload, this.encode (this.secret), 'sha384');
|
1318
|
+
headers = {
|
1319
|
+
'Content-Type': 'text/plain',
|
1320
|
+
'X-GEMINI-APIKEY': this.apiKey,
|
1321
|
+
'X-GEMINI-PAYLOAD': this.decode (payload),
|
1322
|
+
'X-GEMINI-SIGNATURE': signature,
|
1323
|
+
};
|
1324
|
+
} else {
|
1325
|
+
if (Object.keys (query).length) {
|
1326
|
+
url += '?' + this.urlencode (query);
|
1327
|
+
}
|
1328
|
+
}
|
1329
|
+
url = this.urls['api'][api] + url;
|
1330
|
+
if ((method === 'POST') || (method === 'DELETE')) {
|
1331
|
+
body = this.json (query);
|
1332
|
+
}
|
1333
|
+
return { 'url': url, 'method': method, 'body': body, 'headers': headers };
|
1334
|
+
}
|
1335
|
+
|
1336
|
+
handleErrors (httpCode, reason, url, method, headers, body, response, requestHeaders, requestBody) {
|
1337
|
+
if (response === undefined) {
|
1338
|
+
if (typeof body === 'string') {
|
1339
|
+
const feedback = this.id + ' ' + body;
|
1340
|
+
this.throwBroadlyMatchedException (this.exceptions['broad'], body, feedback);
|
1341
|
+
}
|
1342
|
+
return; // fallback to default error handler
|
1343
|
+
}
|
1344
|
+
//
|
1345
|
+
// {
|
1346
|
+
// "result": "error",
|
1347
|
+
// "reason": "BadNonce",
|
1348
|
+
// "message": "Out-of-sequence nonce <1234> precedes previously used nonce <2345>"
|
1349
|
+
// }
|
1350
|
+
//
|
1351
|
+
const result = this.safeString (response, 'result');
|
1352
|
+
if (result === 'error') {
|
1353
|
+
const reason = this.safeString (response, 'reason');
|
1354
|
+
const message = this.safeString (response, 'message');
|
1355
|
+
const feedback = this.id + ' ' + message;
|
1356
|
+
this.throwExactlyMatchedException (this.exceptions['exact'], reason, feedback);
|
1357
|
+
this.throwExactlyMatchedException (this.exceptions['exact'], message, feedback);
|
1358
|
+
this.throwBroadlyMatchedException (this.exceptions['broad'], message, feedback);
|
1359
|
+
throw new ExchangeError (feedback); // unknown message
|
1360
|
+
}
|
1361
|
+
}
|
1362
|
+
|
1363
|
+
async createDepositAddress (code, params = {}) {
|
1364
|
+
await this.loadMarkets ();
|
1365
|
+
const currency = this.currency (code);
|
1366
|
+
const request = {
|
1367
|
+
'currency': currency['id'],
|
1368
|
+
};
|
1369
|
+
const response = await this.privatePostV1DepositCurrencyNewAddress (this.extend (request, params));
|
1370
|
+
const address = this.safeString (response, 'address');
|
1371
|
+
this.checkAddress (address);
|
1372
|
+
return {
|
1373
|
+
'currency': code,
|
1374
|
+
'address': address,
|
1375
|
+
'tag': undefined,
|
1376
|
+
'info': response,
|
1377
|
+
};
|
1378
|
+
}
|
1379
|
+
|
1380
|
+
async fetchOHLCV (symbol, timeframe = '5m', since = undefined, limit = undefined, params = {}) {
|
1381
|
+
await this.loadMarkets ();
|
1382
|
+
const market = this.market (symbol);
|
1383
|
+
const request = {
|
1384
|
+
'timeframe': this.timeframes[timeframe],
|
1385
|
+
'symbol': market['id'],
|
1386
|
+
};
|
1387
|
+
const response = await this.publicGetV2CandlesSymbolTimeframe (this.extend (request, params));
|
1388
|
+
//
|
1389
|
+
// [
|
1390
|
+
// [1591515000000,0.02509,0.02509,0.02509,0.02509,0],
|
1391
|
+
// [1591514700000,0.02503,0.02509,0.02503,0.02509,44.6405],
|
1392
|
+
// [1591514400000,0.02503,0.02503,0.02503,0.02503,0],
|
1393
|
+
// ]
|
1394
|
+
//
|
1395
|
+
return this.parseOHLCVs (response, market, timeframe, since, limit);
|
1396
|
+
}
|
1397
|
+
};
|