Back to Ccxt

Fetch All Balances

wiki/examples/js/fetch-all-balances.md

4.5.526.6 KB
Original Source
javascript
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
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',
       'coinbasepro',
       'jubi',
       'hitbtc',
       'bitstamp1',
       'bitfinex2',
       'upbit',
       'huobipro',
   ]
   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, 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, ROUND, 2, DECIMAL_PLACES, PAD_WITH_ZERO),
       }, result);
   })

   const tableResults = table (results)

   log (tableResults)

   log.green ('Currencies:', currencies)

   console.log (new Date ())

}) ()