Added market sync options: average and coingecko

-The previous market price calculation setting was hardcoded to only display market and USD prices for a single exchange and trading pair which was not very accurate for coins listed on multiple exchanges or with multiple trading pairs. The new default is to average the market prices for all supported exchanges and trading pairs
-The coingecko market price option was added to allow fetching the market price directly from the coingecko api instead of calculating it via supported exchanges known to the explorer
-Added a new root setting option for default_coingecko_ids which allows presetting symbols to their associated internal coingecko id to help prevent matching to the wrong currency with same symbol via coingecko api calls
-Fixed an issue where the explorer would fail to start with an enabled exchange that had no defined trading pairs
This commit is contained in:
Joe Uhren
2024-01-05 00:47:22 -07:00
parent ed8d7a5964
commit 65c48ea829
10 changed files with 443 additions and 195 deletions
+59 -130
View File
@@ -14,8 +14,7 @@ var mongoose = require('mongoose'),
lib = require('./explorer'),
settings = require('./settings'),
locale = require('./locale'),
fs = require('fs'),
coingecko = require('./apis/coingecko');
fs = require('fs');
function find_address(hash, caseSensitive, cb) {
if (caseSensitive) {
@@ -226,64 +225,68 @@ function init_markets(cb) {
if (settings.markets_page.exchanges[key].enabled == true) {
// check if exchange is installed/supported
if (module.exports.fs.existsSync('./lib/markets/' + key + '.js')) {
let pairCounter = 0;
// check if there are any trading pairs
if (settings.markets_page.exchanges[key].trading_pairs.length > 0) {
let pairCounter = 0;
// loop through all trading pairs
settings.markets_page.exchanges[key].trading_pairs.forEach(function (pair_key, pair_index, pair_map) {
// split the pair data
let split_pair = pair_key.toUpperCase().split('/');
// loop through all trading pairs
settings.markets_page.exchanges[key].trading_pairs.forEach(function (pair_key, pair_index, pair_map) {
// split the pair data
let split_pair = pair_key.toUpperCase().split('/');
// check if this is a valid trading pair
if (split_pair.length == 2) {
// add this pair to the list of installed markets
installed_markets.push({
market: key,
coin_symbol: split_pair[0],
pair_symbol: split_pair[1]
});
// check if this is a valid trading pair
if (split_pair.length == 2) {
// add this pair to the list of installed markets
installed_markets.push({
market: key,
coin_symbol: split_pair[0],
pair_symbol: split_pair[1]
});
// lookup the exchange in the market collection
module.exports.check_market(key, split_pair[0], split_pair[1], function(market, exists) {
// check if exchange trading pair exists in the market collection
if (!exists) {
// exchange doesn't exist in the market collection so add a default definition now
console.log('No %s[%s] entry found. Creating new entry now..', market, split_pair[0] + '/' + split_pair[1]);
// lookup the exchange in the market collection
module.exports.check_market(key, split_pair[0], split_pair[1], function(market, exists) {
// check if exchange trading pair exists in the market collection
if (!exists) {
// exchange doesn't exist in the market collection so add a default definition now
console.log('No %s[%s] entry found. Creating new entry now..', market, split_pair[0] + '/' + split_pair[1]);
module.exports.create_market(split_pair[0], split_pair[1], market, function() {
module.exports.create_market(split_pair[0], split_pair[1], market, function() {
pairCounter++;
// check if all pairs have been tested
if (pairCounter == settings.markets_page.exchanges[key].trading_pairs.length)
marketCounter++;
// check if all exchanges have been tested
if (marketCounter == Object.keys(settings.markets_page.exchanges).length) {
// finished initializing markets
return cb(installed_markets);
}
});
} else {
pairCounter++;
// check if all pairs have been tested
if (pairCounter == settings.markets_page.exchanges[key].trading_pairs.length)
marketCounter++;
}
// check if all exchanges have been tested
if (marketCounter == Object.keys(settings.markets_page.exchanges).length) {
// finished initializing markets
return cb(installed_markets);
}
});
} else {
pairCounter++;
// check if all exchanges have been tested
if (marketCounter == Object.keys(settings.markets_page.exchanges).length) {
// finished initializing markets
return cb(installed_markets);
}
});
} else {
pairCounter++;
// check if all pairs have been tested
if (pairCounter == settings.markets_page.exchanges[key].trading_pairs.length)
marketCounter++;
}
// check if all exchanges have been tested
if (marketCounter == Object.keys(settings.markets_page.exchanges).length) {
// finished initializing markets
return cb(installed_markets);
}
});
} else {
pairCounter++;
// check if all pairs have been tested
if (pairCounter == settings.markets_page.exchanges[key].trading_pairs.length)
marketCounter++;
}
});
// check if all pairs have been tested
if (pairCounter == settings.markets_page.exchanges[key].trading_pairs.length)
marketCounter++;
}
});
} else
marketCounter++;
} else
marketCounter++;
} else
@@ -1302,9 +1305,9 @@ module.exports = {
update_markets_db: function(market, coin_symbol, pair_symbol, cb) {
// check if market exists
if (fs.existsSync('./lib/markets/' + market + '.js')) {
get_market_data(market, coin_symbol, pair_symbol, function (err, obj) {
get_market_data(market, coin_symbol, pair_symbol, function (market_err, obj) {
// check if there was an error with getting market data
if (err == null) {
if (market_err == null) {
// update the market collection for the current market and trading pair combination
Markets.updateOne({market: market, coin_symbol: coin_symbol, pair_symbol: pair_symbol}, {
chartdata: JSON.stringify(obj.chartdata),
@@ -1313,93 +1316,19 @@ module.exports = {
history: obj.trades,
summary: obj.stats
}).then(() => {
// check if this is the default market and trading pair
if (market == settings.markets_page.default_exchange.exchange_name && settings.markets_page.default_exchange.trading_pair.toUpperCase() == coin_symbol.toUpperCase() + '/' + pair_symbol.toUpperCase()) {
// this is the default market so update the last price stats
Stats.updateOne({coin: settings.coin.name}, {
last_price: obj.stats.last
}).then(() => {
// finished updating market data
return cb(null);
}).catch((err) => {
console.log(err);
return cb(null);
});
} else {
// this is not the default market so we are finished updating market data
return cb(null);
}
// finished updating market data
return cb(null, obj.stats.last);
}).catch((err) => {
console.log(err);
return cb(null);
return cb(err, null);
});
} else {
// an error occurred with getting market data so return the error msg
return cb(err);
return cb(market_err, null);
}
});
} else {
// market does not exist
return cb('market is not installed');
}
},
get_last_usd_price: function(cb) {
// check if the default market is enabled
if (settings.markets_page.exchanges[settings.markets_page.default_exchange.exchange_name].enabled == true) {
// get the list of coins from coingecko
coingecko.get_coin_data(function (err, coin_list) {
// check for errors
if (err == null) {
var symbol = settings.markets_page.default_exchange.trading_pair.split('/')[1];
var index = coin_list.findIndex(p => p.symbol.toLowerCase() == symbol.toLowerCase());
// check if the default market pair is found in the coin list
if (index > -1) {
// initialize the rate limiter to wait 2 seconds between requests to prevent abusing external apis
var rateLimitLib = require('./ratelimit');
var rateLimit = new rateLimitLib.RateLimit(1, 2000, false);
// automatically pause for 2 seconds in between requests
rateLimit.schedule(function() {
// get the usd value of the default market pair from coingecko
coingecko.get_data(coin_list[index].id, function (err, last_usd) {
// check for errors
if (err == null) {
// get current stats
Stats.findOne({coin: settings.coin.name}).then((stats) => {
// update the last usd price
Stats.updateOne({coin: settings.coin.name}, {
last_usd_price: (last_usd * stats.last_price)
}).then(() => {
// last usd price updated successfully
return cb(null);
}).catch((err) => {
// return error msg
return cb(err);
});
}).catch((err) => {
// return error msg
return cb(err);
});
} else {
// return error msg
return cb(err);
}
});
});
} else {
// return error msg
return cb('cannot find symbol ' + symbol + ' in the coingecko api');
}
} else {
// return error msg
return cb(err);
}
});
} else {
// default exchange is not enabled so just exit without updating last price for now
return cb(null);
return cb('market is not installed', null);
}
},