diff --git a/js/gemini.js b/js/gemini.js
index 7fe6229d8125..0041137a75c2 100644
--- a/js/gemini.js
+++ b/js/gemini.js
@@ -233,6 +233,11 @@ module.exports = class gemini extends Exchange {
},
'options': {
'fetchMarketsMethod': 'fetch_markets_from_web',
+ 'fetchMarketFromWebRetries': 10,
+ 'fetchMarketsFromAPI': {
+ 'fetchDetailsForAllSymbols': false,
+ 'fetchDetailsForMarketIds': [],
+ },
'fetchTickerMethod': 'fetchTickerV1', // fetchTickerV1, fetchTickerV2, fetchTickerV1AndV2
'networkIds': {
'bitcoin': 'BTC',
@@ -271,7 +276,21 @@ module.exports = class gemini extends Exchange {
}
async fetchMarketsFromWeb (params = {}) {
- const response = await this.webGetRestApi (params);
+ // This endpoint so we retry
+ const maxRetries = this.safeInteger (this.options, 'fetchMarketFromWebRetries', 10);
+ let response = undefined;
+ let retry = 0;
+ while (retry < maxRetries) {
+ try {
+ response = await this.webGetRestApi (params);
+ break;
+ } catch (e) {
+ retry = retry + 1;
+ if (retry === maxRetries) {
+ throw e;
+ }
+ }
+ }
const sections = response.split ('
Symbols and minimums
');
const numSections = sections.length;
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.';
@@ -371,6 +390,17 @@ module.exports = class gemini extends Exchange {
return result;
}
+ parseMarketActive (status) {
+ const statuses = {
+ 'open': true,
+ 'closed': false,
+ 'cancel_only': true,
+ 'post_only': true,
+ 'limit_only': true,
+ };
+ return this.safeValue (statuses, status, true);
+ }
+
async fetchMarketsFromAPI (params = {}) {
const response = await this.publicGetV1Symbols (params);
//
@@ -380,16 +410,86 @@ module.exports = class gemini extends Exchange {
// ...
// ]
//
- const result = [];
+ const result = {};
for (let i = 0; i < response.length; i++) {
const marketId = response[i];
- const market = marketId;
const idLength = marketId.length - 0;
- const baseId = marketId.slice (0, idLength - 3);
+ const baseId = marketId.slice (0, idLength - 3); // Not true for all markets
const quoteId = marketId.slice (idLength - 3, idLength);
const base = this.safeCurrencyCode (baseId);
const quote = this.safeCurrencyCode (quoteId);
- result.push ({
+ result[marketId] = {
+ 'id': marketId,
+ 'symbol': base + '/' + quote,
+ 'swap': false,
+ 'future': false,
+ 'option': false,
+ 'active': undefined,
+ 'contract': false,
+ 'linear': undefined,
+ 'inverse': undefined,
+ 'strike': undefined,
+ 'optionType': undefined,
+ 'precision': {
+ 'price': undefined,
+ 'amount': undefined,
+ },
+ 'limits': {
+ 'leverage': {
+ 'min': undefined,
+ 'max': undefined,
+ },
+ 'amount': {
+ 'min': undefined,
+ 'max': undefined,
+ },
+ 'price': {
+ 'max': undefined,
+ },
+ },
+ 'info': marketId,
+ };
+ }
+ const options = this.safeValue (this.options, 'fetchMarketsFromAPI', {});
+ const fetchDetailsForAllSymbols = this.safeValue (options, 'fetchDetailsForAllSymbols', false);
+ const fetchDetailsForMarketIds = this.safeValue (options, 'fetchDetailsForMarketIds', []);
+ let promises = [];
+ let marketIds = [];
+ if (fetchDetailsForAllSymbols) {
+ marketIds = response;
+ } else {
+ marketIds = fetchDetailsForMarketIds;
+ }
+ for (let i = 0; i < marketIds.length; i++) {
+ const marketId = marketIds[i];
+ const method = 'publicGetV1SymbolsDetailsSymbol';
+ const request = {
+ 'symbol': marketId,
+ };
+ promises.push (this[method] (this.extend (request, params)));
+ //
+ // {
+ // "symbol": "BTCUSD",
+ // "base_currency": "BTC",
+ // "quote_currency": "USD",
+ // "tick_size": 1E-8,
+ // "quote_increment": 0.01,
+ // "min_order_size": "0.00001",
+ // "status": "open",
+ // "wrap_enabled": false
+ // }
+ //
+ }
+ promises = await Promise.all (promises);
+ for (let i = 0; i < promises.length; i++) {
+ const response = promises[i];
+ const marketId = this.safeStringLower (response, 'symbol');
+ const baseId = this.safeString (response, 'base_currency');
+ const base = this.safeCurrencyCode (baseId);
+ const quoteId = this.safeString (response, 'quote_currency');
+ const quote = this.safeCurrencyCode (quoteId);
+ const status = this.safeString (response, 'status');
+ result[marketId] = ({
'id': marketId,
'symbol': base + '/' + quote,
'base': base,
@@ -404,7 +504,7 @@ module.exports = class gemini extends Exchange {
'swap': false,
'future': false,
'option': false,
- 'active': undefined,
+ 'active': this.parseMarketActive (status),
'contract': false,
'linear': undefined,
'inverse': undefined,
@@ -414,8 +514,8 @@ module.exports = class gemini extends Exchange {
'strike': undefined,
'optionType': undefined,
'precision': {
- 'price': undefined,
- 'amount': undefined,
+ 'price': this.safeNumber (response, 'quote_increment'),
+ 'amount': this.safeNumber (response, 'tick_size'),
},
'limits': {
'leverage': {
@@ -423,7 +523,7 @@ module.exports = class gemini extends Exchange {
'max': undefined,
},
'amount': {
- 'min': undefined,
+ 'min': this.safeNumber (response, 'min_order_size'),
'max': undefined,
},
'price': {
@@ -435,10 +535,10 @@ module.exports = class gemini extends Exchange {
'max': undefined,
},
},
- 'info': market,
+ 'info': response,
});
}
- return result;
+ return this.toArray (result);
}
async fetchOrderBook (symbol, limit = undefined, params = {}) {