Files
peya-nodejs-pool/lib/market.js
2020-02-10 15:49:40 -05:00

740 lines
21 KiB
JavaScript

/**
* Cryptonote Node.JS Pool
* https://github.com/dvandal/cryptonote-nodejs-pool
*
* Market Exchanges
**/
// Load required modules
let apiInterfaces = require('./apiInterfaces.js')(config.daemon, config.wallet);
// Initialize log system
let logSystem = 'market';
require('./exceptionWriter.js')(logSystem);
/**
* Get market prices
**/
exports.get = function (exchange, tickers, callback) {
if (!exchange) {
callback('No exchange specified', null);
}
exchange = exchange.toLowerCase();
if (!tickers || tickers.length === 0) {
callback('No tickers specified', null);
}
let marketPrices = [];
let numTickers = tickers.length;
let completedFetches = 0;
getExchangeMarkets(exchange, function (error, marketData) {
if (!marketData || marketData.length === 0) {
callback({});
return;
}
for (let i in tickers) {
(function (i) {
let pairName = tickers[i];
let pairParts = pairName.split('-');
let base = pairParts[0] || null;
let target = pairParts[1] || null;
if (!marketData[base]) {
completedFetches++;
if (completedFetches === numTickers) callback(marketPrices);
} else {
let price = marketData[base][target] || null;
if (!price || price === 0) {
let cryptonatorBase;
if (marketData[base]['BTC']) cryptonatorBase = 'BTC';
else if (marketData[base]['ETH']) cryptonatorBase = 'ETH';
else if (marketData[base]['LTC']) cryptonatorBase = 'LTC';
if (!cryptonatorBase) {
completedFetches++;
if (completedFetches === numTickers) callback(marketPrices);
} else {
getExchangePrice("cryptonator", cryptonatorBase, target, function (error, tickerData) {
completedFetches++;
if (tickerData && tickerData.price) {
marketPrices[i] = {
ticker: pairName,
price: tickerData.price * marketData[base][cryptonatorBase],
source: tickerData.source
};
}
if (completedFetches === numTickers) callback(marketPrices);
});
}
} else {
completedFetches++;
marketPrices[i] = {
ticker: pairName,
price: price,
source: exchange
};
if (completedFetches === numTickers) callback(marketPrices);
}
}
})(i);
}
});
}
/**
* Get Exchange Market Prices
**/
let marketRequestsCache = {};
function getExchangeMarkets (exchange, callback) {
callback = callback || function () {};
if (!exchange) {
callback('No exchange specified', null);
}
exchange = exchange.toLowerCase();
// Return cache if available
let cacheKey = exchange;
let currentTimestamp = Date.now() / 1000;
if (marketRequestsCache[cacheKey] && marketRequestsCache[cacheKey].ts > (currentTimestamp - 60)) {
callback(null, marketRequestsCache[cacheKey].data);
return;
}
let target = null;
let symbol = null;
let price = 0.0;
let data = {};
// Altex
if (exchange == "altex") {
apiInterfaces.jsonHttpRequest('api.altex.exchange', 443, '', function (error, response) {
if (error) log('error', logSystem, 'API request to %s has failed: %s', [exchange, error]);
if (error) callback(error, {});
if (!response || !response.success) callback('No market informations', {});
let ticker = null;
for (ticker in response.data) {
tickerParts = ticker.split('_');
target = tickerParts[0];
symbol = tickerParts[1];
price = +parseFloat(response.data[ticker].last);
if (price === 0) continue;
if (!data[symbol]) data[symbol] = {};
data[symbol][target] = price;
}
if (!error) marketRequestsCache[cacheKey] = {
ts: currentTimestamp,
data: data
};
callback(null, data);
}, '/v1/ticker');
}
// Crex24
else if (exchange == "crex24") {
apiInterfaces.jsonHttpRequest('api.crex24.com', 443, '', function (error, response) {
if (error) log('error', logSystem, 'API request to %s has failed: %s', [exchange, error]);
if (error) callback(error, {});
if (!response || !response.Tickers) callback('No market informations', {});
let ticker = null;
let pairName = null;
let pairParts = null;
for (let i in response.Tickers) {
ticker = response.Tickers[i];
pairName = ticker.PairName;
pairParts = pairName.split('_');
target = pairParts[0];
symbol = pairParts[1];
price = +ticker.Last;
if (!price || price === 0) continue;
if (!data[symbol]) data[symbol] = {};
data[symbol][target] = price;
}
if (!error) marketRequestsCache[cacheKey] = {
ts: currentTimestamp,
data: data
};
callback(null, data);
}, '/CryptoExchangeService/BotPublic/ReturnTicker');
}
// Cryptopia
else if (exchange == "cryptopia") {
apiInterfaces.jsonHttpRequest('www.cryptopia.co.nz', 443, '', function (error, response) {
if (error) log('error', logSystem, 'API request to %s has failed: %s', [exchange, error]);
if (error) callback(error, {});
if (!response || !response.Success) callback('No market informations', {});
let ticker = null;
let pairName = null;
let pairParts = null;
for (let i in response.Data) {
ticker = response.Data[i];
pairName = ticker.Label;
pairParts = pairName.split('/');
target = pairParts[1];
symbol = pairParts[0];
price = +ticker.LastPrice;
if (!price || price === 0) continue;
if (!data[symbol]) data[symbol] = {};
data[symbol][target] = price;
}
if (!error) marketRequestsCache[cacheKey] = {
ts: currentTimestamp,
data: data
};
callback(null, data);
}, '/api/GetMarkets');
}
// Stocks.Exchange
else if (exchange == "stocks.exchange") {
apiInterfaces.jsonHttpRequest('stocks.exchange', 443, '', function (error, response) {
if (error) log('error', logSystem, 'API request to %s has failed: %s', [exchange, error]);
if (error) callback(error, {});
if (!response) callback('No market informations', {});
let ticker = null;
let pairName = null;
let pairParts = null;
for (let i in response) {
ticker = response[i];
pairName = ticker.market_name;
pairParts = pairName.split('_');
target = pairParts[1];
symbol = pairParts[0];
price = +ticker.last;
if (!price || price === 0) continue;
if (!data[symbol]) data[symbol] = {};
data[symbol][target] = price;
}
if (!error) marketRequestsCache[cacheKey] = {
ts: currentTimestamp,
data: data
};
callback(null, data);
}, '/api2/ticker');
}
// TradeOgre
else if (exchange == "tradeogre") {
apiInterfaces.jsonHttpRequest('tradeogre.com', 443, '', function (error, response) {
if (error) log('error', logSystem, 'API request to %s has failed: %s', [exchange, error]);
let pairParts = null;
if (!error && response) {
for (let i in response) {
for (let pairName in response[i]) {
pairParts = pairName.split('-');
target = pairParts[0];
symbol = pairParts[1];
price = +response[i][pairName].price;
if (price === 0) continue;
if (!data[symbol]) data[symbol] = {};
data[symbol][target] = price;
}
}
}
if (!error) marketRequestsCache[cacheKey] = {
ts: currentTimestamp,
data: data
};
callback(null, data);
}, '/api/v1/markets');
} else if (exchange == "maplechange") {
apiInterfaces.jsonHttpRequest('maplechange.com', 443, '', function (error, response) {
if (error) log('error', logSystem, 'API request to %s has failed: %s', [exchange, error]);
let data = {};
if (!error && response) {
for (let model in response) {
let len = model.length;
if (len <= 3) continue;
target = model.substring(len - 3, len)
.toUpperCase();
symbol = model.substring(0, len - 3)
.toUpperCase();
price = +response[model]['ticker']['last'];
if (price === 0) continue;
if (!data[symbol]) data[symbol] = {};
data[symbol][target] = price;
}
}
if (!error) marketRequestsCache[cacheKey] = {
ts: currentTimestamp,
data: data
};
callback(null, data);
}, '/api/v2/tickers');
} else if (exchange == "stex") {
apiInterfaces.jsonHttpRequest('app.stex.com', 443, '', function (error, response) {
if (error) log('error', logSystem, 'API request to %s has failed: %s', [exchange, error]);
let pieces = null;
if (!error && response) {
for (let model in response) {
pieces = response[model]['market_name'].split('_');
target = pieces[1];
symbol = pieces[0];
price = +response[model]['last'];
if (price === 0) continue;
if (!data[symbol]) data[symbol] = {};
data[symbol][target] = price;
}
}
if (!error) marketRequestsCache[cacheKey] = {
ts: currentTimestamp,
data: data
};
callback(null, data);
}, '/api2/ticker');
}
// Btc-Alpha
else if (exchange == "btcalpha") {
apiInterfaces.jsonHttpRequest('btc-alpha.com', 443, '', function (error, response) {
if (error) log('error', logSystem, 'API request to %s has failed: %s', [exchange, error]);
let pieces = null;
if (!error && response) {
for (let model in response) {
pieces = response[model]['pair'].split('_');
target = pieces[1];
symbol = pieces[0];
price = +response[model]['price'];
if (price === 0) continue;
if (!data[symbol]) data[symbol] = {};
data[symbol][target] = price;
}
}
if (!error) marketRequestsCache[cacheKey] = {
ts: currentTimestamp,
data: data
};
callback(null, data);
}, '/api/v1/exchanges/' /*JUST FOR 20DEC!! '/api/v1/exchanges/?pair=BDX_BTC'*/ );
}
// tradesatoshi
else if (exchange == "tradesatoshi") {
apiInterfaces.jsonHttpRequest('tradesatoshi.com', 443, '', function (error, response) {
if (error) console.log('error', 'API request to has failed: ' + error);
let pieces = null;
if (!error && response.success) {
for (let model in response.result) {
pieces = response.result[model]['market'].split('_');
target = pieces[1];
symbol = pieces[0];
price = +response.result[model]['last'];
if (price === 0) continue;
if (!data[symbol]) data[symbol] = {};
data[symbol][target] = price;
}
}
if (!error) marketRequestsCache[cacheKey] = {
ts: currentTimestamp,
data: data
};
callback(null, data);
}, '/api/public/getmarketsummaries');
} else if (exchange == "coinmarketcap") {
apiInterfaces.jsonHttpRequest('coinmarketcap.coindeal.com', 443, '', function (error, response) {
if (error) console.log('error', 'API request to has failed: ' + error);
var data = {};
if (!error && response) {
for (var model in response) {
var pieces = model.split('_');
var target = pieces[1];
var symbol = pieces[0];
if (symbol === 'BTC') continue;
var price = +response[model]['last'];
if (price === 0) continue;
if (!data[symbol]) data[symbol] = {};
data[symbol][target] = price;
}
}
console.log(data)
}, '/api/v1/ticker');
} else if (exchange == "tradecx") {
apiInterfaces.jsonHttpRequest('tradecx.io', 443, '', function (error, response) {
if (error) log('error', logSystem, 'API request to %s has failed: %s', [exchange, error]);
let data = {};
if (!error && response) {
for (let model in response) {
let len = model.length;
if (len <= 3) continue;
target = model.substring(len - 3, len)
.toUpperCase();
symbol = model.substring(0, len - 3)
.toUpperCase();
price = +response[model]['ticker']['last'];
if (price === 0) continue;
if (!data[symbol]) data[symbol] = {};
data[symbol][target] = price;
}
}
if (!error) marketRequestsCache[cacheKey] = {
ts: currentTimestamp,
data: data
};
callback(null, data);
}, '/api/tickers');
} else if (exchange == "coingecko") {
apiInterfaces.jsonHttpRequest('api.coingecko.com', 443, '', function (error, response) {
if (error) log('error', logSystem, 'API request to %s has failed: %s', [exchange, error]);
if (!error && response) {
let matchingCoin = response.filter(coin => {
return coin.symbol === config.symbol.toLowerCase() ? coin.name.toLowerCase() : ''
})
apiInterfaces.jsonHttpRequest('api.coingecko.com', 443, '', function (error, response) {
if (error) log('error', logSystem, 'API request to %s has failed: %s', [exchange, error]);
let data = {};
if (!error && response.tickers) {
for (let model in response.tickers) {
target = response.tickers[model].target
symbol = response.tickers[model].base
price = +response.tickers[model].last
if (price === 0) continue;
if (!data[symbol]) data[symbol] = {};
data[symbol][target] = price;
}
}
if (!error) marketRequestsCache[cacheKey] = {
ts: currentTimestamp,
data: data
};
callback(null, data);
}, `/api/v3/coins/${matchingCoin[0].id}/tickers`);
}
}, `/api/v3/coins/list`);
}
// Unknown
else {
callback('Exchange not supported: ' + exchange);
}
}
exports.getExchangeMarkets = getExchangeMarkets;
/**
* Get Exchange Market Price
**/
let priceRequestsCache = {};
function getExchangePrice (exchange, base, target, callback) {
callback = callback || function () {};
if (!exchange) {
callback('No exchange specified');
} else if (!base) {
callback('No base specified');
} else if (!target) {
callback('No target specified');
}
exchange = exchange.toLowerCase();
base = base.toUpperCase();
target = target.toUpperCase();
// Return cache if available
let cacheKey = exchange + '-' + base + '-' + target;
let currentTimestamp = Date.now() / 1000;
let error = null;
let price = 0.0;
let data = {};
let ticker = null;
if (priceRequestsCache[cacheKey] && priceRequestsCache[cacheKey].ts > (currentTimestamp - 60)) {
callback(null, priceRequestsCache[cacheKey].data);
return;
}
// Cryptonator
if (exchange == "cryptonator") {
ticker = base + '-' + target;
apiInterfaces.jsonHttpRequest('api.cryptonator.com', 443, '', function (error, response) {
if (error) log('error', logSystem, 'API request to %s has failed: %s', [exchange, error]);
if (response.error) log('warn', logSystem, 'Cryptonator API error: %s', [response.error]);
error = response.error ? response.error : error;
price = response.success ? +response.ticker.price : null;
if (!price) log('warn', logSystem, 'No exchange data for %s using %s', [ticker, exchange]);
data = {
ticker: ticker,
price: price,
source: exchange
};
if (!error) priceRequestsCache[cacheKey] = {
ts: currentTimestamp,
data: data
};
callback(error, data);
}, '/api/ticker/' + ticker);
}
// Altex
else if (exchange == "altex") {
getExchangeMarkets(exchange, function (error, data) {
if (error) log('error', logSystem, 'API request to %s has failed: %s', [exchange, error]);
price = null;
if (!error && data[base] && data[base][target]) {
price = data[base][target];
}
if (!price) log('warn', logSystem, 'No exchange data for %s using %s', [ticker, exchange]);
data = {
ticker: ticker,
price: price,
source: exchange
};
if (!error) priceRequestsCache[cacheKey] = {
ts: currentTimestamp,
data: data
};
callback(error, data);
});
}
// Crex24
else if (exchange == "crex24") {
ticker = base + '_' + target;
apiInterfaces.jsonHttpRequest('api.crex24.com', 443, '', function (error, response) {
if (error) log('error', logSystem, 'API request to %s has failed: %s', [exchange, error]);
if (response.Error) log('warn', logSystem, 'Crex24 API error: %s', [response.Error]);
error = response.Error ? response.Error : error;
price = (response.Tickers && response.Tickers[0]) ? +response.Tickers[0].Last : null;
if (!price) log('warn', logSystem, 'No exchange data for %s using %s', [ticker, exchange]);
data = {
ticker: ticker,
price: price,
source: exchange
};
if (!error) priceRequestsCache[cacheKey] = {
ts: currentTimestamp,
data: data
};
callback(error, data);
}, '/CryptoExchangeService/BotPublic/ReturnTicker?request=[NamePairs=' + ticker + ']');
}
// Cryptopia
else if (exchange == "cryptopia") {
ticker = base + '_' + target;
apiInterfaces.jsonHttpRequest('www.cryptopia.co.nz', 443, '', function (error, response) {
if (error) log('error', logSystem, 'API request to %s has failed: %s', [exchange, error]);
if (response.Error) log('warn', logSystem, 'Cryptopia API error: %s', [response.Error]);
error = response.Error ? response.Error : error;
price = (response.Data && response.Data.LastPrice) ? +response.Data.LastPrice : null;
data = {
ticker: ticker,
price: price,
source: exchange
};
if (!error) priceRequestsCache[cacheKey] = {
ts: currentTimestamp,
data: data
};
callback(error, data);
}, '/api/GetMarket/' + ticker);
}
// Stocks.Exchange
else if (exchange == "stocks.exchange") {
getExchangeMarkets(exchange, function (error, data) {
if (error) log('error', logSystem, 'API request to %s has failed: %s', [exchange, error]);
if (!error && data[base] && data[base][target]) {
price = data[base][target];
}
if (!price) log('warn', logSystem, 'No exchange data for %s using %s', [ticker, exchange]);
data = {
ticker: ticker,
price: price,
source: exchange
};
if (!error) priceRequestsCache[cacheKey] = {
ts: currentTimestamp,
data: data
};
callback(error, data);
});
}
// TradeOgre
else if (exchange == "tradeogre") {
ticker = target + '-' + base;
apiInterfaces.jsonHttpRequest('tradeogre.com', 443, '', function (error, response) {
if (error) log('error', logSystem, 'API request to %s has failed: %s', [exchange, error]);
if (response.message) log('warn', logSystem, 'TradeOgre API error: %s', [response.message]);
error = response.message ? response.message : error;
price = +response.price || null;
if (!price) log('warn', logSystem, 'No exchange data for %s using %s', [ticker, exchange]);
data = {
ticker: ticker,
price: price,
source: exchange
};
if (!error) priceRequestsCache[cacheKey] = {
ts: currentTimestamp,
data: data
};
callback(error, data);
}, '/api/v2/ticker/' + ticker);
}
// Btc-Alpha
else if (exchange == "btcalpha") {
ticker = base + '_' + target;
apiInterfaces.jsonHttpRequest('btc-alpha.com', 443, '', function (error, response) {
if (error) log('error', logSystem, 'API request to %s has failed: %s', [exchange, error]);
if (response.message) log('warn', logSystem, 'BTC-Alpha API error: %s', [response.message]);
error = response.message ? response.message : error;
price = response[0] != undefined ? response[0]['price'] : null;
if (!price) log('warn', logSystem, 'No exchange data for %s using %s', [ticker, exchange]);
data = {
ticker: ticker,
price: price,
source: exchange
}
if (!error) priceRequestsCache[cacheKey] = {
ts: currentTimestamp,
data: data
};
callback(error, data);
}, '/api/v1/exchanges/?pair=' + ticker + '&limit=1');
}
// tradesatoshi
else if (exchange == "tradesatoshi") {
ticker = base + '_' + target;
apiInterfaces.jsonHttpRequest('tradesatoshi.com', 443, '', function (error, response) {
if (error) log('error', logSystem, 'API request to %s has failed: %s', [exchange, error]);
if (response.message) log('warn', logSystem, 'BTC-Alpha API error: %s', [response.message]);
error = response.message ? response.message : error;
price = response.result != undefined ? response.result['last'] : null;
if (!price) log('warn', logSystem, 'No exchange data for %s using %s', [ticker, exchange]);
data = {
ticker: ticker,
price: price,
source: exchange
}
if (!error) priceRequestsCache[cacheKey] = {
ts: currentTimestamp,
data: data
};
callback(error, data);
}, '/api/public/getmarketsummary?market=' + ticker);
}
// coinmarketcap
else if (exchange == "coinmarketcap") {
apiInterfaces.jsonHttpRequest('api.coinmarketcap.com', 443, '', function (error, response) {
if (error) log('error', logSystem, 'API request to %s has failed: %s', [exchange, error]);
if (response.message) log('warn', logSystem, 'CoinMarketCap API error: %s', [response.message]);
error = response.message ? response.message : error;
price = response ? +response.data.quotes[ticker].price : null;
if (!price) log('warn', logSystem, 'No exchange data for %s using %s', [ticker, exchange]);
data = {
ticker: ticker,
price: price,
source: exchange
}
if (!error) priceRequestsCache[cacheKey] = {
ts: currentTimestamp,
data: data
};
callback(error, data);
}, '/v2/ticker/1/?convert=' + target);
}
// tradecx
else if (exchange == "tradecx") {
apiInterfaces.jsonHttpRequest('tradecx.io', 443, '', function (error, response) {
if (error) log('error', logSystem, 'API request to %s has failed: %s', [exchange, error]);
if (response.message) log('warn', logSystem, 'CoinMarketCap API error: %s', [response.message]);
error = response.message ? response.message : error;
price = response ? +response.data.quotes[ticker].price : null;
if (!price) log('warn', logSystem, 'No exchange data for %s using %s', [ticker, exchange]);
data = {
ticker: ticker,
price: price,
source: exchange
}
if (!error) priceRequestsCache[cacheKey] = {
ts: currentTimestamp,
data: data
};
callback(error, data);
}, '/v2/tickers/' + target);
}
// Unknown
else {
callback('Exchange not supported: ' + exchange);
}
}
exports.getExchangePrice = getExchangePrice;