wiki/examples/js/fetch-all-balances.md
// @NO_AUTO_TRANSPILE
import { PAD_WITH_ZERO } from '../../js/src/base/functions/number.js';
//-----------------------------------------------------------------------------
import ccxt from '../../js/ccxt.js';
import fs from 'fs';
import path from 'path';
import ansicolor from 'ansicolor';
import asTable from 'as-table';
import ololog from 'ololog';
ansicolor.nice;
//-----------------------------------------------------------------------------
const table = asTable.configure({
delimiter: '|'.lightGray.dim,
right: true,
title: x => String(x).lightGray,
print: x => {
if (typeof x === 'object') {
const j = JSON.stringify(x).trim();
if (j.length < 100)
return j;
}
return String(x);
}
}), { ROUND, DECIMAL_PLACES, decimalToPrecision, omit, unique, flatten, extend } = ccxt, log = ololog.handleNodeErrors().noLocate.unlimited;
//-----------------------------------------------------------------------------
// set up keys and settings, if any
const keysGlobal = path.resolve('keys.json');
const keysLocal = path.resolve('keys.local.json');
const keysGlobalExists = fs.existsSync(keysGlobal);
const keysLocalExists = fs.existsSync(keysLocal);
if (!(keysGlobalExists || keysLocalExists)) {
const lines = [
'This script requires a keys.json or a keys.local.json file containing the API keys in JSON format',
'{',
' "binance": {',
' "apiKey": "YOUR_API_KEY",',
' "secret": "YOUR_SECRET"',
' }',
' "bitfinex": {',
' "apiKey": "YOUR_API_KEY",',
' "secret": "YOUR_SECRET"',
' }',
'}'
];
const errorMessage = lines.join("\n");
log.red.bright(errorMessage);
process.exit();
}
let globalKeysFile = keysGlobalExists ? keysGlobal : false;
let localKeysFile = keysLocalExists ? keysLocal : globalKeysFile;
// @ts-ignore
const dynamicLocalKeysFile = JSON.parse(fs.readFileSync(localKeysFile));
let settings = localKeysFile ? (dynamicLocalKeysFile || {}) : {};
//-----------------------------------------------------------------------------
const timeout = 30000;
const coins = [
'BTC',
'ETH',
'BNB',
'EUR',
'LTC',
'USD',
'USDC',
'USDT',
'BUSD',
'XRP',
'DOGE',
'YFI',
'LINK',
'XLM',
'ADA',
'SOL',
];
function initializeAllExchanges() {
let numErrors = 0;
const ignore = [
'bcex',
'bitsane',
'chbtc',
'coinbaseexchange',
'jubi',
'hitbtc',
'bitstamp1',
'bitfinex',
'upbit',
'htx',
];
const result = [];
ccxt.exchanges.filter(exchangeId => (!ignore.includes(exchangeId))).forEach(exchangeId => {
try {
const verbose = false;
const exchange = new ccxt[exchangeId]({
timeout,
verbose,
...(settings[exchangeId] || {})
});
exchange.checkRequiredCredentials();
result.push(exchange);
}
catch (e) {
numErrors++;
log.red(exchangeId, 'initialization failed', e.constructor.name, e.message.slice(0, 100));
}
});
log('Initialized', ccxt.exchanges.length - numErrors, 'of', ccxt.exchanges.length, 'exchanges,', numErrors, 'error' + (((numErrors < 1) || (numErrors > 1)) ? 's' : '') + ',', ignore.length, 'skipped');
return result;
}
(async () => {
const exchanges = initializeAllExchanges();
console.log(exchanges.map(exchange => exchange.id));
let results = [];
const priceOracle = new ccxt.gate();
const tickers = await priceOracle.fetchTickers();
await Promise.all(exchanges.map((exchange) => (async function () {
try {
if (exchange.has['signIn']) {
await exchange.signIn();
}
const balance = await exchange.fetchTotalBalance();
if (!balance) {
throw new Error(exchange.id + ' erroneous balance');
}
const keys = Object.keys(balance).sort();
const nonzeroBalance = {};
for (let i = 0; i < keys.length; i++) {
const key = keys[i];
if (coins.includes(key)) {
const value = balance[key];
const valueToPrecision = decimalToPrecision(value, ROUND, 8, DECIMAL_PLACES);
if (valueToPrecision !== '0') {
nonzeroBalance[key] = valueToPrecision;
}
}
}
const numNonzeroKeys = Object.keys(nonzeroBalance).length;
if (numNonzeroKeys < 1) {
log.yellow(exchange.id + ' empty balance');
}
else {
log.green(exchange.id, numNonzeroKeys, 'currencies');
results.push({ exchange: exchange.id, ...nonzeroBalance });
}
}
catch (e) {
log.red(exchange.id, e.constructor.name, e.message.split("\n")[0].slice(0, 100));
}
})()));
results = ccxt.sortBy(results, 'exchange');
const currencies = unique(flatten(results.map(result => Object.keys(omit(result, 'exchange')))));
currencies.sort();
const total = {};
for (let i = 0; i < currencies.length; i++) {
const currency = currencies[i];
let sum = 0;
results.forEach(result => {
if (currency in result) {
sum += parseFloat(result[currency]);
}
});
total[currency] = decimalToPrecision(sum.toString(), ROUND, 8, DECIMAL_PLACES);
}
results.push(extend({ 'exchange': 'total' }, total));
results = results.map(result => {
let value = 0;
const convertTo = 'USD';
currencies.forEach(currency => {
if (currency === convertTo) {
if (currency in result) {
value += parseFloat(result[currency]);
}
}
else {
const symbol = currency + '/' + convertTo;
if (symbol in tickers) {
if (currency in result) {
const ticker = tickers[symbol];
value += parseFloat(result[currency]) * ticker['last'];
}
}
}
});
return extend({
'exchange': result.exchange,
'$': decimalToPrecision(value.toString(), ROUND, 2, DECIMAL_PLACES, PAD_WITH_ZERO),
}, result);
});
const tableResults = table(results);
log(tableResults);
log.green('Currencies:', currencies);
console.log(new Date());
})();