diff --git a/CHANGELOG.md b/CHANGELOG.md index c1a756d..d457585 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,13 @@ + +## [1.6.1](https://github.com/benmarten/CryptoETF/compare/1.6.0...1.6.1) (2018-01-09) + + +### Features + +* **ui:** colorize output; allow to hide exchanges below certain holding treshold ([94a1ac1](https://github.com/benmarten/CryptoETF/commit/94a1ac1)) + + + # [1.6.0](https://github.com/benmarten/CryptoETF/compare/1.5.1...1.6.0) (2018-01-06) diff --git a/README.md b/README.md index f3acf28..e90e12e 100644 --- a/README.md +++ b/README.md @@ -43,6 +43,7 @@ The tool expects your settings in settings.json. Take a look at settings.example - rebalanceDeltaTotalPct: Treshold in percent, that will show a Y in the rebalance column, once rebalancing of total portfolio is recommended. - rebalanceDeltaPct: Treshold in percent, that will show a Y in the rebalance column, once rebalancing of individual position is recommended. - minValueBtc: Ignore coins that only have a holdingsvalue under a certain bitcoin value. + - exchangeMinValueBtc: Don't list exchanges in the exchanges column, with less than the specified BTC value. The complete holding value will still be added in the total sum. - hideMissingCoins: By default CryptoETF will add all missing coins up to your last coin holding by rank of the coin (global market cap). This option disables that behaviour. - *outputFile*: Path to a file to forward the output to as json. diff --git a/package-lock.json b/package-lock.json index 3c84057..ee02220 100644 --- a/package-lock.json +++ b/package-lock.json @@ -5402,5 +5402,5 @@ "integrity": "sha1-8m9ITXJoTPQr7ft2lwqhYI+/lXc=" } }, - "version": "1.6.0" + "version": "1.6.1" } diff --git a/package.json b/package.json index e3506c0..8aa4e23 100644 --- a/package.json +++ b/package.json @@ -4,6 +4,7 @@ "binance": "^1.1.0", "bitfinex": "^1.0.3", "coinbase": "^2.0.6", + "colors": "^1.1.2", "gdax": "^0.4.2", "kraken-api": "^1.0.0", "node-bittrex-api": "^0.8.1", @@ -31,5 +32,5 @@ "testLocal": "./node_modules/.bin/nyc mocha --require babel-core/register test/**/*.js test/**/**/*.js", "test": "NODE_ENV=test npm run testLocal" }, - "version": "1.6.0" + "version": "1.6.1" } diff --git a/settings.example.json b/settings.example.json index 2807da6..7388fb1 100644 --- a/settings.example.json +++ b/settings.example.json @@ -57,6 +57,7 @@ "rebalanceDeltaPct": 1.0, "rebalanceDeltaTotalPct": 10.0, "minValueBtc": 0.0001, + "exchangeMinValueBtc": 0.0001, "hideMissingCoins": false }, "outputFile": false diff --git a/src/PromiseUtils.js b/src/PromiseUtils.js deleted file mode 100644 index 3c0d98b..0000000 --- a/src/PromiseUtils.js +++ /dev/null @@ -1,15 +0,0 @@ -export default class PromiseUtils { - /** - * - * @param items An array of items. - * @param fn A function that accepts an item from the array and returns a promise. - * @returns {Promise} - */ - static forEachPromise(items, fn) { - return items.reduce(function(promise, item) { - return promise.then(function() { - return fn(item) - }) - }, Promise.resolve()) - } -} \ No newline at end of file diff --git a/src/Utils.js b/src/Utils.js index 51a47e1..e5f48f3 100644 --- a/src/Utils.js +++ b/src/Utils.js @@ -46,4 +46,12 @@ export default class Utils { static hasDriftedAboveTreshold(drift, treshold) { return (Math.abs(drift) * 100 > treshold) ? 'Y' : '' } + + static colorize(string) { + if (string.startsWith('-')) { + return string.red + } else { + return string.green + } + } } diff --git a/src/index.js b/src/index.js index d4411fc..b0b45c7 100644 --- a/src/index.js +++ b/src/index.js @@ -4,30 +4,34 @@ import Coin from './model/Coin' import Utils from './Utils' import fs from 'fs' import * as Settings from './Settings' +import Terminal from './model/Terminal' async function refreshPortfolio() { return new Promise(async (resolve) => { try { Portfolio.clear() await Coinmarket.init() - let integrations = {} let promises = [] for (let account in Settings.accounts) { let name = Utils.capitalize(account) + let Wallet try { - integrations[name] = require(`./model/integrations/${name}Wallet`) + Wallet = require(`./model/integrations/${name}Wallet`).default } catch (ignored) { console.log(`Warning: Integration for Exchange: ${name} not found!`) continue } - try { - if (Settings.accounts[account] && Settings.accounts[account].length > 0) { - console.log(`Retrieving ${name} balance...`) - promises.push(integrations[name].default.getBalance().then(coins => Portfolio.addCoins(coins))) + + for (let index in Settings.accounts[account]) { + let credentials = Settings.accounts[account][index] + let integration = new Wallet(credentials) + console.log(`Retrieving ${name} balance...`) + try { + promises.push(integration.getBalance().then(coins => Portfolio.addCoins(coins))) + } catch (e) { + console.log(`Error: An error occured while running integration: ${name}, ${e}`) } - } catch (e) { - console.log(`Error: An error occured while running integration: ${name}, ${e}`) } } @@ -48,14 +52,14 @@ async function refreshPortfolio() { Portfolio.removeCoin('USDT') if (Settings.outputFile) { - fs.writeFile(Settings.outputFile, Portfolio.getJson(), 'utf8', function(err) { + fs.writeFile(Settings.outputFile, Portfolio.getPortfolioJson(), 'utf8', function(err) { if (err) throw err console.log(`Saved data to ${Settings.outputFile}...`) }) } - - console.log(Portfolio.getOutput()) + let portfolio = Portfolio.getPortfolio() + Terminal.printOutput(portfolio) } catch (error) { diff --git a/src/model/Coin.js b/src/model/Coin.js index 32341c2..f19fd0a 100644 --- a/src/model/Coin.js +++ b/src/model/Coin.js @@ -1,6 +1,7 @@ import Coinmarket from './Coinmarket' import Portfolio from './Portfolio' import * as Settings from './../Settings' +import _ from 'lodash' export default class Coin { symbol @@ -8,7 +9,6 @@ export default class Coin { amount = parseFloat(0) rank exchanges = {} - exchangesPossible = {} constructor(symbol, amount, exchange, rank) { if (!symbol || (!amount && amount !== 0)) { @@ -22,11 +22,7 @@ export default class Coin { this.amount = parseFloat(amount) if (exchange) { - if (this.amount > 0) { - this.addExchange(exchange) - } else { - this.addExchangePossible(exchange) - } + this.addExchange(exchange, amount) } if (rank) { @@ -86,27 +82,18 @@ export default class Coin { /** * Records on which exchange the coin is traded and we hold it. * @param exchange The name of the exchange + * @param amount The amount held on the exchange */ - addExchange(exchange) { - if (typeof exchange === 'object') { - for (let idx in exchange) { - this.exchanges[exchange[idx]] = 1 - } + addExchange(exchange, amount) { + if (!exchange || exchange.length === 0) { + return } - this.exchanges[exchange] = 1 - } - - /** - * Records on which exchange the coin is traded. - * @param exchange The name of the exchange - */ - addExchangePossible(exchange) { if (typeof exchange === 'object') { for (let idx in exchange) { - this.exchangesPossible[exchange[idx]] = 1 + this.exchanges[exchange[idx]] = amount } } - this.exchangesPossible[exchange] = 1 + this.exchanges[exchange] = amount } getExchanges() { @@ -114,12 +101,17 @@ export default class Coin { } getExchangesString() { - let result - if (Object.keys(this.exchanges).length > 0) { - result = Object.keys(this.exchanges).toString() + let coin = this + let result = _.pickBy(this.exchanges, (value) => { + return (value * Coinmarket.getBtcForX(coin.symbol)) > + (Settings.options.exchangeMinValueBtc || 0) + }) + if (Object.keys(result).length > 0) { + result = Object.keys(result).toString() } else { - result = Object.keys(this.exchangesPossible).toString() + result = Object.keys(this.exchanges).toString().blue.italic } + return (result.charAt(result.length - 1) === ',') ? result.slice(0, -1) : result } } \ No newline at end of file diff --git a/src/model/Portfolio.js b/src/model/Portfolio.js index 8be8b70..962c71e 100644 --- a/src/model/Portfolio.js +++ b/src/model/Portfolio.js @@ -1,8 +1,6 @@ import Utils from './../Utils' import Coinmarket from './Coinmarket' // noinspection NpmUsedModulesInstalled -import {table} from 'table' -import Format from './../Format' import * as Settings from './../Settings' let portfolio = {} @@ -21,11 +19,7 @@ export default class Portfolio { if (portfolio[coin.getSymbol()]) { let existingCoin = portfolio[coin.getSymbol()] existingCoin.addAmount(coin.getAmount()) - if (coin.getAmount() > 0) { - existingCoin.addExchange(coin.getExchanges()) - } else { - existingCoin.addExchangePossible(coin.getExchanges()) - } + existingCoin.addExchange(coin.getExchanges(), coin.getAmount()) } else { portfolio[coin.getSymbol()] = coin this.updateHighestRankWithBalance(coin) @@ -121,123 +115,18 @@ export default class Portfolio { } /** - * Formats the output for the command line. - * @return {string} A string with the result. + * Returns the current portfolio. + * @return {{Object}} The portfolio. */ - static getOutput() { - let stretchFactor = Portfolio.getStretchFactor() - let data = [ - ['#', 'SYMBOL', 'AMOUNT', 'VALUE', 'VALUE', 'ALLOCATION', 'ALLOCATION', 'TARGET', 'TARGET', 'BUY/SELL', 'BUY/SELL', 'BUY/SELL', 'DRIFT', 'REBALANCE', 'EXCHANGES'], - ['', '', '', '฿', '$', 'actual %', 'target %', '฿', '$', '฿', 'ETH', '$', '%', '', ''] - ] - let sortedKeys = Utils.getSortedKeys(portfolio, 'rank') - let targetSum = [] - let targetValueUsd = this.getTargetValueUsd() - let targetValueBtc = this.getTargetValueUsd() / Coinmarket.getBtcUsd() - targetSum['allocationActualPct'] = 0 - targetSum['allocationTargetPct'] = 0 - targetSum['targetBtc'] = 0 - targetSum['targetUsd'] = 0 - for (let index in sortedKeys) { - if (!sortedKeys.hasOwnProperty(index)) { - continue - } - let coin = portfolio[sortedKeys[index]] - let allocationActualPct = coin.getRelativeMarketCap() - let allocationTargetPct = coin.getRelativeMarketCapRecommended() / stretchFactor - let targetBtc = coin.getRelativeMarketCapRecommended() / stretchFactor * targetValueBtc - let targetUsd = coin.getRelativeMarketCapRecommended() / stretchFactor * targetValueUsd - let drift = Math.abs((coin.getUsdValue() - targetUsd) / targetValueUsd) - data.push([ - coin.getRank(), - coin.getSymbol(), - Utils.round(coin.getAmount(), 2), - Format.bitcoin(coin.getBtcValue()), - Format.money(coin.getUsdValue(), 0), - Format.percent(allocationActualPct), - Format.percent(allocationTargetPct), - Format.bitcoin(targetBtc), - Format.money(targetUsd), - Format.bitcoin(targetBtc - coin.getBtcValue(), 8), - Format.bitcoin((targetBtc - coin.getBtcValue()) / Coinmarket.getBtcEth(), 8), - Format.money(targetUsd - coin.getUsdValue()), - Format.percent(drift), - Utils.hasDriftedAboveTreshold(drift, Settings.options.rebalanceDeltaPct), - coin.getExchangesString() - ]) - targetSum['allocationActualPct'] += allocationActualPct || 0 - targetSum['allocationTargetPct'] += allocationTargetPct || 0 - targetSum['targetBtc'] += targetBtc - targetSum['targetUsd'] += targetUsd - } - - let drift = (targetSum['targetBtc'] - this.getSumBtc()) / targetSum['targetBtc'] - data.push([ - '', - '', - '', - Format.bitcoin(this.getSumBtc()), - Format.money(this.getSumUsd()), - Format.percent(targetSum['allocationActualPct']), - Format.percent(targetSum['allocationTargetPct']), - Format.bitcoin(targetSum['targetBtc']), - Format.money(targetSum['targetUsd']), - Format.bitcoin(targetSum['targetBtc'] - this.getSumBtc()), - '', - Format.money(targetSum['targetUsd'] - this.getSumUsd()), - Format.percent(drift), - Utils.hasDriftedAboveTreshold(drift, (Settings.options.rebalanceDeltaTotalPct || - Settings.options.rebalanceDeltaPct)), - '']) - - // noinspection JSUnusedGlobalSymbols - let config = { - columns: { - 2: { - alignment: 'right' - }, - 3: { - alignment: 'right' - }, - 4: { - alignment: 'right' - }, - 5: { - alignment: 'right' - }, - 6: { - alignment: 'right' - }, - 7: { - alignment: 'right' - }, - 8: { - alignment: 'right' - }, - 9: { - alignment: 'right' - }, - 10: { - alignment: 'right' - }, - 11: { - alignment: 'right' - }, - 12: { - alignment: 'right' - }, - 13: { - alignment: 'right' - } - }, - drawHorizontalLine: (index, size) => { - return index === 0 || index === 2 || index === size - 1 || index === size - } - } - return table(data, config) + static getPortfolio() { + return portfolio } - static getJson() { + /** + * Returns the portfolio as json string. + * @return {string} The portfolio as json string. + */ + static getPortfolioJson() { return JSON.stringify(portfolio, null, 2) } } diff --git a/src/model/Terminal.js b/src/model/Terminal.js new file mode 100644 index 0000000..882f31b --- /dev/null +++ b/src/model/Terminal.js @@ -0,0 +1,126 @@ +import Utils from '../Utils' +import Coinmarket from './Coinmarket' +import Portfolio from './Portfolio' +import Format from '../Format' +import * as Settings from '../Settings' +import {table} from 'table' + +export default class Terminal { + /** + * Formats the output for the command line. + * @return {string} A string with the result. + */ + static printOutput(portfolio) { + let stretchFactor = Portfolio.getStretchFactor() + let data = [ + ['#', 'SYMBOL', 'AMOUNT', 'VALUE', 'VALUE', 'ALLOCATION', 'ALLOCATION', 'TARGET', 'TARGET', 'BUY(-)/SELL(+)', 'BUY(-)/SELL(+)', 'BUY(-)/SELL(+)', 'DRIFT', 'REBALANCE', 'EXCHANGES'], + ['', '', '', '฿', '$', 'actual %', 'target %', '฿', '$', '฿', 'ETH', '$', '%', '', ''] + ] + let sortedKeys = Utils.getSortedKeys(portfolio, 'rank') + let targetSum = [] + let targetValueUsd = Portfolio.getTargetValueUsd() + let targetValueBtc = Portfolio.getTargetValueUsd() / Coinmarket.getBtcUsd() + targetSum['allocationActualPct'] = 0 + targetSum['allocationTargetPct'] = 0 + targetSum['targetBtc'] = 0 + targetSum['targetUsd'] = 0 + for (let index in sortedKeys) { + if (!sortedKeys.hasOwnProperty(index)) { + continue + } + let coin = portfolio[sortedKeys[index]] + let allocationActualPct = coin.getRelativeMarketCap() + let allocationTargetPct = coin.getRelativeMarketCapRecommended() / stretchFactor + let targetBtc = coin.getRelativeMarketCapRecommended() / stretchFactor * targetValueBtc + let targetUsd = coin.getRelativeMarketCapRecommended() / stretchFactor * targetValueUsd + let drift = (coin.getUsdValue() - targetUsd) / targetValueUsd + data.push([ + coin.getRank(), + coin.getSymbol(), + Utils.round(coin.getAmount(), 2), + Format.bitcoin(coin.getBtcValue()), + Format.money(coin.getUsdValue(), 0), + Format.percent(allocationActualPct), + Format.percent(allocationTargetPct), + Format.bitcoin(targetBtc), + Format.money(targetUsd), + Utils.colorize(Format.bitcoin(coin.getBtcValue() - targetBtc, 8)), + Utils.colorize(Format.bitcoin((coin.getBtcValue() - targetBtc) / Coinmarket.getBtcEth(), 8)), + Utils.colorize(Format.money(coin.getUsdValue() - targetUsd)), + Utils.colorize(Format.percent(drift)), + Utils.hasDriftedAboveTreshold(drift, Settings.options.rebalanceDeltaPct), + coin.getExchangesString() + ]) + targetSum['allocationActualPct'] += allocationActualPct || 0 + targetSum['allocationTargetPct'] += allocationTargetPct || 0 + targetSum['targetBtc'] += targetBtc + targetSum['targetUsd'] += targetUsd + } + + let drift = (Portfolio.getSumBtc() - targetSum['targetBtc']) / targetSum['targetBtc'] + let deltaSumBtc = Portfolio.getSumBtc() - targetSum['targetBtc'] + data.push([ + '', + '', + '', + '฿' + Format.bitcoin(Portfolio.getSumBtc()), + ('$' + Format.money(Portfolio.getSumUsd())).bold, + Format.percent(targetSum['allocationActualPct']) + '%', + Format.percent(targetSum['allocationTargetPct']) + '%', + '฿' + Format.bitcoin(targetSum['targetBtc']), + '$' + Format.money(targetSum['targetUsd']), + Utils.colorize('฿' + Format.bitcoin(deltaSumBtc)), + Utils.colorize(Format.bitcoin(deltaSumBtc / Coinmarket.getBtcEth()) + ' ETH'), + Utils.colorize('$' + Format.money(Portfolio.getSumUsd() - targetSum['targetUsd'])), + Utils.colorize(Format.percent(drift) + '%'), + Utils.hasDriftedAboveTreshold(drift, (Settings.options.rebalanceDeltaTotalPct || + Settings.options.rebalanceDeltaPct)), + '']) + + // noinspection JSUnusedGlobalSymbols + let config = { + columns: { + 2: { + alignment: 'right' + }, + 3: { + alignment: 'right' + }, + 4: { + alignment: 'right' + }, + 5: { + alignment: 'right' + }, + 6: { + alignment: 'right' + }, + 7: { + alignment: 'right' + }, + 8: { + alignment: 'right' + }, + 9: { + alignment: 'right' + }, + 10: { + alignment: 'right' + }, + 11: { + alignment: 'right' + }, + 12: { + alignment: 'right' + }, + 13: { + alignment: 'right' + } + }, + drawHorizontalLine: (index, size) => { + return index === 0 || index === 2 || index === size - 1 || index === size + } + } + console.log(table(data, config)) + } +} \ No newline at end of file diff --git a/src/model/integrations/AbstractWallet.js b/src/model/integrations/AbstractWallet.js new file mode 100644 index 0000000..d32ff88 --- /dev/null +++ b/src/model/integrations/AbstractWallet.js @@ -0,0 +1,24 @@ +export default class AbstractWallet { + /** + * @param credentials The api credentials. + */ + constructor(credentials) { + this.credentials = credentials + } + + /** + * @return {Promise} The account balances. + */ + static _getBalanceForCredential(credentials) { + throw new Error('Method _getBalanceForCredential() is not implemented!') + } + + /** + * Returns the balances for this account + * + * @return {Promise} The account balances. + */ + getBalance() { + return this.constructor._getBalanceForCredential(this.credentials) + } +} diff --git a/src/model/integrations/BinanceWallet.js b/src/model/integrations/BinanceWallet.js index 54dbd7a..c762bb7 100644 --- a/src/model/integrations/BinanceWallet.js +++ b/src/model/integrations/BinanceWallet.js @@ -1,15 +1,9 @@ -import PromiseUtils from '../../PromiseUtils' +import AbstractWallet from './AbstractWallet' import Coin from '../Coin' // noinspection NpmUsedModulesInstalled import Binance from 'binance' -import * as Settings from './../../Settings' - -export default class BinanceWallet { - static getBalance() { - return PromiseUtils.forEachPromise(Settings.accounts.binance, this._getBalanceForCredential) - } - +export default class BinanceWallet extends AbstractWallet { /** * Returns the balances for a bittrex account. * @param credential The bittrex api credentials. diff --git a/src/model/integrations/BitfinexWallet.js b/src/model/integrations/BitfinexWallet.js index 007c0df..3a7e8c4 100644 --- a/src/model/integrations/BitfinexWallet.js +++ b/src/model/integrations/BitfinexWallet.js @@ -1,14 +1,9 @@ -import PromiseUtils from '../../PromiseUtils' +import AbstractWallet from './AbstractWallet' import Coin from '../Coin' // noinspection NpmUsedModulesInstalled import Bitfinex from 'bitfinex' -import * as Settings from './../../Settings' - -export default class BitfinexWallet { - static getBalance() { - return PromiseUtils.forEachPromise(Settings.accounts.bitfinex, this._getBalanceForCredential) - } +export default class BitfinexWallet extends AbstractWallet { /** * Returns the balances for a Bitfinex account. * @param credential The Bitfinex api credentials. diff --git a/src/model/integrations/BitgrailWallet.js b/src/model/integrations/BitgrailWallet.js index 2575405..711bb2a 100644 --- a/src/model/integrations/BitgrailWallet.js +++ b/src/model/integrations/BitgrailWallet.js @@ -1,16 +1,10 @@ -import PromiseUtils from '../../PromiseUtils' +import AbstractWallet from './AbstractWallet' import Coin from '../Coin' -// noinspection NpmUsedModulesInstalled import request from 'request-promise' import crypto from 'crypto' import querystring from 'querystring' -import * as Settings from './../../Settings' - -export default class BitgrailWallet { - static getBalance() { - return PromiseUtils.forEachPromise(Settings.accounts.bitgrail, this._getBalanceForCredential) - } +export default class BitgrailWallet extends AbstractWallet { /** * Returns the balances for a Bitgrail account. * @param credential The Bitgrail api credentials. diff --git a/src/model/integrations/BittrexWallet.js b/src/model/integrations/BittrexWallet.js index 7760a73..6eca527 100644 --- a/src/model/integrations/BittrexWallet.js +++ b/src/model/integrations/BittrexWallet.js @@ -1,14 +1,9 @@ -import PromiseUtils from '../../PromiseUtils' +import AbstractWallet from './AbstractWallet' import Coin from '../Coin' // noinspection NpmUsedModulesInstalled import Bittrex from 'node-bittrex-api' -import * as Settings from './../../Settings' - -export default class BittrexWallet { - static getBalance() { - return PromiseUtils.forEachPromise(Settings.accounts.bittrex, this._getBalanceForCredential) - } +export default class BittrexWallet extends AbstractWallet { /** * Returns the balances for a bittrex account. * @param credential The bittrex api credentials. diff --git a/src/model/integrations/CoinbaseWallet.js b/src/model/integrations/CoinbaseWallet.js index c87d307..c0ae50a 100644 --- a/src/model/integrations/CoinbaseWallet.js +++ b/src/model/integrations/CoinbaseWallet.js @@ -1,14 +1,9 @@ -import PromiseUtils from '../../PromiseUtils' +import AbstractWallet from './AbstractWallet' import Coin from '../Coin' -import * as Settings from './../../Settings' // noinspection NpmUsedModulesInstalled const Coinbase = require('coinbase').Client -export default class CoinbaseWallet { - static getBalance() { - return PromiseUtils.forEachPromise(Settings.accounts.coinbase, this._getBalanceForCredential) - } - +export default class CoinbaseWallet extends AbstractWallet { /** * Returns the balances for a coinbase account. * @param credential The coinbase api credentials. diff --git a/src/model/integrations/GdaxWallet.js b/src/model/integrations/GdaxWallet.js index c88d559..a1d6eef 100644 --- a/src/model/integrations/GdaxWallet.js +++ b/src/model/integrations/GdaxWallet.js @@ -1,14 +1,9 @@ -import PromiseUtils from '../../PromiseUtils' +import AbstractWallet from './AbstractWallet' import Coin from '../Coin' -import * as Settings from './../../Settings' // noinspection NpmUsedModulesInstalled const Gdax = require('gdax').AuthenticatedClient -export default class GdaxWallet { - static getBalance() { - return PromiseUtils.forEachPromise(Settings.accounts.gdax, this._getBalanceForCredential) - } - +export default class GdaxWallet extends AbstractWallet { /** * Returns the balances for a GDAX account. * @param credential The GDAX API credentials. diff --git a/src/model/integrations/HitbtcWallet.js b/src/model/integrations/HitbtcWallet.js index f8a59bf..df70ff8 100644 --- a/src/model/integrations/HitbtcWallet.js +++ b/src/model/integrations/HitbtcWallet.js @@ -1,14 +1,8 @@ -import PromiseUtils from '../../PromiseUtils' -// noinspection NpmUsedModulesInstalled -import request from 'requestretry' +import AbstractWallet from './AbstractWallet' import Coin from './../Coin' -import * as Settings from './../../Settings' - -export default class HitbtcWallet { - static getBalance() { - return PromiseUtils.forEachPromise(Settings.accounts.hitbtc, this._getBalanceForCredential) - } +import request from 'requestretry' +export default class HitbtcWallet extends AbstractWallet { /** * Returns the balances for a HitBTC account. * @param credential The HitBTC api credentials. diff --git a/src/model/integrations/KrakenWallet.js b/src/model/integrations/KrakenWallet.js index d6e42f4..b8da292 100644 --- a/src/model/integrations/KrakenWallet.js +++ b/src/model/integrations/KrakenWallet.js @@ -1,14 +1,9 @@ -import PromiseUtils from '../../PromiseUtils' +import AbstractWallet from './AbstractWallet' import Coin from '../Coin' // noinspection NpmUsedModulesInstalled import KrakenClient from 'kraken-api' -import * as Settings from './../../Settings' - -export default class KrakenWallet { - static getBalance() { - return PromiseUtils.forEachPromise(Settings.accounts.kraken, this._getBalanceForCredential) - } +export default class KrakenWallet extends AbstractWallet { /** * Returns the balances for a Kraken account. * @param credential The Kraken api credentials. diff --git a/src/model/integrations/PoloniexWallet.js b/src/model/integrations/PoloniexWallet.js index eab5ecc..988a20b 100644 --- a/src/model/integrations/PoloniexWallet.js +++ b/src/model/integrations/PoloniexWallet.js @@ -1,16 +1,10 @@ -import PromiseUtils from '../../PromiseUtils' +import AbstractWallet from './AbstractWallet' import Coin from '../Coin' // noinspection NpmUsedModulesInstalled import Poloniex from 'poloniex-api-node' -import * as Settings from './../../Settings' - -export default class PoloniexWallet { - static getBalance() { - return PromiseUtils.forEachPromise(Settings.accounts.poloniex, this._getBalanceForCredential) - } +export default class PoloniexWallet extends AbstractWallet { /** - * * @param credential.apiKey The api key. * @param credential.apiSecret The api secret. * @prop coin.available Available amount diff --git a/test/model/integrations/testBinanceWallet.js b/test/model/integrations/testBinanceWallet.js index c22631a..9e940a7 100644 --- a/test/model/integrations/testBinanceWallet.js +++ b/test/model/integrations/testBinanceWallet.js @@ -10,7 +10,8 @@ describe('Testing Binance integration', () => { } }) it('Testing initial connection and balances', async () => { - let wallet = await BinanceWallet.getBalance() - assert(wallet.length > 0) + let wallet = new BinanceWallet(Settings.accounts.binance[0]) + let balance = await wallet.getBalance() + assert(balance.length > 0) }) }) \ No newline at end of file diff --git a/test/model/integrations/testBitfinexWallet.js b/test/model/integrations/testBitfinexWallet.js index 84edb98..fb910b5 100644 --- a/test/model/integrations/testBitfinexWallet.js +++ b/test/model/integrations/testBitfinexWallet.js @@ -5,12 +5,13 @@ import * as Settings from './../../../src/Settings' describe('Testing Bitfinex integration', () => { before(function() { - if (!Settings.accounts.binance) { + if (!Settings.accounts.bitfinex) { this.skip() } }) it('Testing initial connection and balances', async () => { - let wallet = await BitfinexWallet.getBalance() - assert(wallet.length > 0) + let wallet = new BitfinexWallet(Settings.accounts.bitfinex[0]) + let balance = await wallet.getBalance() + assert(balance.length > 0) }) }) \ No newline at end of file diff --git a/test/model/integrations/testBitgrailWallet.js b/test/model/integrations/testBitgrailWallet.js index 1239535..9a2b5b7 100644 --- a/test/model/integrations/testBitgrailWallet.js +++ b/test/model/integrations/testBitgrailWallet.js @@ -5,12 +5,13 @@ import * as Settings from './../../../src/Settings' describe('Testing Bitgrail integration', () => { before(function() { - if (!Settings.accounts.binance) { + if (!Settings.accounts.bitgrail) { this.skip() } }) it('Testing initial connection and balances', async () => { - let wallet = await BitgrailWallet.getBalance() - assert(wallet.length > 0) + let wallet = new BitgrailWallet(Settings.accounts.bitgrail[0]) + let balance = await wallet.getBalance() + assert(balance.length > 0) }) }) \ No newline at end of file diff --git a/test/model/integrations/testBittrexWallet.js b/test/model/integrations/testBittrexWallet.js index 553529f..97c6a43 100644 --- a/test/model/integrations/testBittrexWallet.js +++ b/test/model/integrations/testBittrexWallet.js @@ -5,12 +5,13 @@ import * as Settings from './../../../src/Settings' describe('Testing Bittrex integration', () => { before(function() { - if (!Settings.accounts.binance) { + if (!Settings.accounts.bittrex) { this.skip() } }) it('Testing initial connection and balances', async () => { - let wallet = await BittrexWallet.getBalance() - assert(wallet.length > 0) + let wallet = new BittrexWallet(Settings.accounts.bittrex[0]) + let balance = await wallet.getBalance() + assert(balance.length > 0) }) }) \ No newline at end of file diff --git a/test/model/integrations/testCoinbaseWallet.js b/test/model/integrations/testCoinbaseWallet.js index ab3bcbd..2df5d48 100644 --- a/test/model/integrations/testCoinbaseWallet.js +++ b/test/model/integrations/testCoinbaseWallet.js @@ -5,12 +5,13 @@ import * as Settings from './../../../src/Settings' describe('Testing Coinbase integration', () => { before(function() { - if (!Settings.accounts.binance) { + if (!Settings.accounts.coinbase) { this.skip() } }) it('Testing initial connection and balances', async () => { - let wallet = await CoinbaseWallet.getBalance() - assert(wallet.length > 0) + let wallet = new CoinbaseWallet(Settings.accounts.coinbase[0]) + let balance = await wallet.getBalance() + assert(balance.length > 0) }) }) \ No newline at end of file diff --git a/test/model/integrations/testGdaxWallet.js b/test/model/integrations/testGdaxWallet.js index 26da34e..ba782bb 100644 --- a/test/model/integrations/testGdaxWallet.js +++ b/test/model/integrations/testGdaxWallet.js @@ -1,15 +1,17 @@ import GdaxWallet from '../../../src/model/integrations/GdaxWallet' import assert from 'assert' + import * as Settings from './../../../src/Settings' describe('Testing Gdax integration', () => { before(function() { - if (!Settings.accounts.binance) { + if (!Settings.accounts.gdax) { this.skip() } }) it('Testing initial connection and balances', async () => { - let wallet = await GdaxWallet.getBalance() - assert(wallet.length > 0) + let wallet = new GdaxWallet(Settings.accounts.gdax[0]) + let balance = await wallet.getBalance() + assert(balance.length > 0) }) }) \ No newline at end of file diff --git a/test/model/integrations/testHitbtcWallet.js b/test/model/integrations/testHitbtcWallet.js index 3a3462c..80234b5 100644 --- a/test/model/integrations/testHitbtcWallet.js +++ b/test/model/integrations/testHitbtcWallet.js @@ -5,12 +5,13 @@ import * as Settings from './../../../src/Settings' describe('Testing HitBtc integration', () => { before(function() { - if (!Settings.accounts.binance) { + if (!Settings.accounts.hitbtc) { this.skip() } }) it('Testing initial connection and balances', async () => { - let wallet = await HitbtcWallet.getBalance() - assert(wallet.length > 0) + let wallet = new HitbtcWallet(Settings.accounts.hitbtc[0]) + let balance = await wallet.getBalance() + assert(balance.length > 0) }) }) \ No newline at end of file diff --git a/test/model/integrations/testKrakenWallet.js b/test/model/integrations/testKrakenWallet.js index 027b492..bdcec0c 100644 --- a/test/model/integrations/testKrakenWallet.js +++ b/test/model/integrations/testKrakenWallet.js @@ -5,12 +5,13 @@ import * as Settings from './../../../src/Settings' describe('Testing Kraken integration', () => { before(function() { - if (!Settings.accounts.binance) { + if (!Settings.accounts.kraken) { this.skip() } }) it('Testing initial connection and balances', async () => { - let wallet = await KrakenWallet.getBalance() - assert(wallet.length > 0) + let wallet = new KrakenWallet(Settings.accounts.kraken[0]) + let balance = await wallet.getBalance() + assert(balance.length > 0) }) }) \ No newline at end of file diff --git a/test/model/integrations/testPoloniexWallet.js b/test/model/integrations/testPoloniexWallet.js index 9a50067..72d2675 100644 --- a/test/model/integrations/testPoloniexWallet.js +++ b/test/model/integrations/testPoloniexWallet.js @@ -5,12 +5,13 @@ import * as Settings from './../../../src/Settings' describe('Testing Poloniex integration', () => { before(function() { - if (!Settings.accounts.binance) { + if (!Settings.accounts.poloniex) { this.skip() } }) it('Testing initial connection and balances', async () => { - let wallet = await PoloniexWallet.getBalance() - assert(wallet.length > 0) + let wallet = new PoloniexWallet(Settings.accounts.poloniex[0]) + let balance = await wallet.getBalance() + assert(balance.length > 0) }) }) \ No newline at end of file diff --git a/test/model/testPortfolio.js b/test/model/testPortfolio.js index 610e8e2..0232550 100644 --- a/test/model/testPortfolio.js +++ b/test/model/testPortfolio.js @@ -52,7 +52,7 @@ describe('Testing Portfolio', () => { await Portfolio.addCoin(new Coin('BTC', 1.37)) await Portfolio.addCoin(new Coin('ETH', 10)) Portfolio.addMissingCoins(5).then() - let result = Portfolio.getOutput() + let result = Portfolio.getPortfolio() console.log(result) assert(result) }) diff --git a/test/model/testTerminal.js b/test/model/testTerminal.js new file mode 100644 index 0000000..14118ab --- /dev/null +++ b/test/model/testTerminal.js @@ -0,0 +1,18 @@ +import Coin from '../../src/model/Coin' +import Portfolio from '../../src/model/Portfolio' +import Coinmarket from '../../src/model/Coinmarket' +import Terminal from '../../src/model/Terminal' +import assert from 'assert' + +describe('Testing Portfolio', () => { + it('Test output', async () => { + await Coinmarket.init() + await Portfolio.addCoin(new Coin('BTC', 1.37)) + await Portfolio.addCoin(new Coin('ETH', 10)) + Portfolio.addMissingCoins(5).then() + console.log = function(output) { + assert(output.length > 0) + } + Terminal.printOutput(Portfolio.getPortfolio()) + }) +}) \ No newline at end of file