crypto-portfolio-viewer

view your aggregated cryptocurrency portfolio across exchanges, ETH wallet, and any other places!

Usage no npm install needed!

<script type="module">
  import cryptoPortfolioViewer from 'https://cdn.skypack.dev/crypto-portfolio-viewer';
</script>

README

Crypto Portfolio Viewer

View your aggregated cryptocurrency portfolio automagically, no matter where the assets are located:

  • ✅ Exchanges
  • ✅ ETH wallets
  • ✅ Anywhere else, no problem!
  • ⭕️ Polkadot parachains (soon)
  • ⭕️ BSC & HECO (someday)

Foreword

As a crypto trader pro, I have long been struggling with tracking all my tokens in a unified way, since they locate in so many different places: Binance, Huobi, Coinbase, FTX, ETH hot/cold wallets, BTC wallets, BSC, HECO, ICOs, mining machines... 🤯

If you are facing similar issues, this is for you. 🎉

I made this tool for every crypto lover ❤️, like you and I, to manage all assets more conveniently. So we can be more focused on making wise trading decisions. 🥳


Basic Usage

🌀 install

$ yarn add crypto-portfolio-viewer
$ npm install crypto-portfolio-viewer --save

🌀 import

/* ----- CommonJS ----- */
const {
  getPortfolio,
  printPortfolioNicely,   // optional
} = require('./crypto-portfolio-viewer');

/* ----- ES modules ----- */
import {
  getPortfolio,
  printPortfolioNicely,   // optional
} from 'crypto-portfolio-viewer';

🌀 eth + erc20 assets

we can easily view all ETH and ERC20 tokens using ETH addresses.

const addresses = [                         
  '0x0000000000000000000000000000000000011111',
  '0x00000000000000000000000000000000000fffff',
  // ......
];

(async () => {
  const portfolio = await getPortfolio({ addresses });
  printPortfolioNicely(portfolio);
})();

🌀 exchange assets

we can easily view all exchanges assets using exchange api keys. Exchange namings please refer to ccxt.

const keys = {                               
  binance: {
    apiKey: "xxxxxxxxxx",
    secret: "yyyyyyyyyy"
  },
  ftx: {
    apiKey: "aaaaaaaaaa",
    secret: "bbbbbbbbbb",
  },
  // ......
};

(async () => {
  const portfolio = await getPortfolio({ keys });
  printPortfolioNicely(portfolio);
})();

🌀 any other assets

we can easily view any other assets by hard coding their counts.

const othertokens = {                        
  "BTC": [8.5],         // in mysterious wallet
  "BNB": [200],         // in BSC
  "ETH": [10, 30],      // uni-LP, sushi-LP
  "USDT": [
    1000,               // borrowed by Alex
    2000,               // borrowed by Kate
    5000,               // my mining machine's value
  ],
  // ......
};

(async () => {
  const portfolio = await getPortfolio({ othertokens });
  printPortfolioNicely(portfolio);
})();

🌀 ALL assets

Being able to aggregate all assets is the soul of a portfolio viewer.

-- Aristotélēs

we can easily view all of our assets across many different places, by combining the usages above.

const keys = {                               
  binance: {
    apiKey: "xxxxxxxxxx",
    secret: "yyyyyyyyyy"
  },
  ftx: {
    apiKey: "aaaaaaaaaa",
    secret: "bbbbbbbbbb",
  },
};

const addresses = [                         
  '0x0000000000000000000000000000000000011111',
  '0x00000000000000000000000000000000000fffff',
];

const othertokens = {                        
  "BTC": [8.5],         // in cold wallet
  "BNB": [200],         // in BSC
  "ETH": [10, 30],      // uni-LP, sushi-LP
  "USDT": [
    1000,               // borrowed by Alex
    2000,               // borrowed by Kate
    5000,               // my mining machine's value
  ],
};

(async () => {
  const portfolio = await getPortfolio({
    keys,
    addresses,
    othertokens,
  });

  printPortfolioNicely(portfolio);
})();

🌀 example result

$ node getPortfolio.js
started to fetch portfolio data ...
(1/5) fetching exchange token counts ...
(2/5) fetching ERC20 token counts ...
(3/5) fetching other token counts ...
(4/5) fetching all token prices ...
(5/5) calculating all token values ...
finished!! Let's go Bitcoin!!

----------------------------------------------------------
₿                    Binance tokens                      ₿
----------------------------------------------------------
| name  | USD value | ratio | BTC value | price  | count |
|-------|-----------|-------|-----------|--------|-------|
| TOTAL | $25000    | 100%  | ₿2.5      | $0     | 0     |
| BTC   | $10000    | 40%   | ₿1        | $10000 | 1     |
| ETH   | $10000    | 40%   | ₿1        | $1000  | 10    |
| BNB   | $5000     | 20%   | ₿0.5      | $100   | 50    |

----------------------------------------------------------
₿                      FTX tokens                        ₿
----------------------------------------------------------
| name  | USD value | ratio | BTC value | price  | count |
|-------|-----------|-------|-----------|--------|-------|
| TOTAL | $15000    | 100%  | ₿1.5      | $0     | 0     |
| BTC   | $10000    | 66%   | ₿1        | $10000 | 1     |
| ATOM  | $10000    | 66%   | ₿1        | $20    | 500   |
| USDT  | $-5000    | -33%  | ₿-0.5     | $1     | -5000 |
// negative value means borrowed from contract or margin
// this can be disabled or customized

----------------------------------------------------------
₿                  ETH + ERC20 tokens                    ₿
----------------------------------------------------------
| name  | USD value | ratio | BTC value | price  | count |
|-------|-----------|-------|-----------|--------|-------|
| TOTAL | $30000    | 100%  | ₿2        | $0     | 0     |
| UNI   | $20000    | 66%   | ₿2        | $50    | 400   |
| ETH   | $10000    | 33%   | ₿1        | $1000  | 10    |

----------------------------------------------------------
₿                     other tokens                       ₿
----------------------------------------------------------
| name  | USD value | ratio | BTC value | price  | count |
|-------|-----------|-------|-----------|--------|-------|
| TOTAL | $50000    | 100%  | ₿5        | $0     | 0     |
| DOT   | $30000    | 60%   | ₿3        | $100   | 300   |
| KSM   | $20000    | 40%   | ₿2        | $1000  | 20    |

----------------------------------------------------------
₿                      all tokens                        ₿
----------------------------------------------------------
| name  | USD value | ratio | BTC value | price  | count |
|-------|-----------|-------|-----------|--------|-------|
| TOTAL | $120000   | 100%  | ₿12       | $0     | 0     |
| DOT   | $30000    | 25%   | ₿3        | $100   | 300   |
| KSM   | $20000    | 16.7% | ₿2        | $1000  | 20    |
| UNI   | $20000    | 16.7% | ₿2        | $50    | 400   |
| BTC   | $20000    | 16.7% | ₿2        | $10000 | 2     |
| ETH   | $20000    | 16.7% | ₿2        | $1000  | 20    |
| ATOM  | $10000    | 8.3%  | ₿1        | $20    | 500   |
| BNB   | $5000     | 4.1%  | ₿0.5      | $100   | 50    |
| USDT  | $-5000    | -4.1% | ₿-0.5     | $1     | -5000 |

Advanced Usage

🔥 custom printer

Viewing result nicely is the soul of a portfolio viewer.

--Shakespeare

we can easily print the result in your favorite fashion:

const myFavoritePrinter = portfolio => { ... };

(async () => {
  const portfolio = await getPortfolio({
    keys,
    addresses,
    othertokens,
  });

  myFavoritePrinter(portfolio);
})();

🔥 combine results

by default we view each exchange and each ETH address separately:

----------------------------------------------------------
₿                    Binance tokens                      ₿
----------------------------------------------------------
......
----------------------------------------------------------
₿                      FTX tokens                        ₿
----------------------------------------------------------
......
----------------------------------------------------------
₿                 0x1234...5678 tokens                   ₿
----------------------------------------------------------
......
----------------------------------------------------------
₿                 0x9876...5432 tokens                   ₿
----------------------------------------------------------

to simplify our portfolio, we can combine them as a whole

(async () => {
  const portfolio = await getPortfolio({
    keys,
    addresses,
    othertokens,
    combineExchanges: true,     // <--here!
    combineAddresses: true,     // <--here!
  });

  printPortfolioNicely(portfolio);
})();
----------------------------------------------------------
₿                    exchange tokens                     ₿
----------------------------------------------------------
all exchange tokens combined print here ......
----------------------------------------------------------
₿                      ETH tokens                        ₿
----------------------------------------------------------
all ETH + ERC20 tokens combined print here ......

🔥 contract/future accounts

For contract/future/margin assets in exchanges, since the ccxt library that we rely on doesn't yet provide unified interfaces for these accounts, there is no automatted way to catch them into the exchange result.

But don't worry, we have 2 different ways to inlcude them into our portfolio:

1) hard code

We can hard code these assets in othertokens. (see example above)

This is pretty convenient, but we will have to manually update othertokens whenever assets change in future accounts.

2) custom fetcher

We can also provide a custom fetcher for each exchange, or call it adapter if you prefer.

This is more flexible and powerful. One huge advantage is being able to include contract positions as assets, which I personally use A LOT!! 🥰. It enables us to more precisely calculate portfolio details.

For example, if we have 1000 USDT collateral, as well as a contract position of BTC long (2000 USDT worth), then technically our 'real' portfolio should look like

{
  BTC:   { USD_value: 2000, ... },     // longed
  USDT:  { USD_value: -1000, ... },    // 1000 (collateral) - 2000 (borrowed)
  TOTAL: { USD_value: 1000, ... },     // net worth
}

with method 1 (hard code), on the other hand, our 'fake' portfolio looks like

{
  BTC:  { USD_value: 0, ... },       // totally ignores contract positions!
  USDT: { USD_value: 1000, ... },    // 1000 (collateral) 
  TOTAL: { USD_value: 1000, ... },   // net worth
}

available fetchers

There are already 2 fetchers that I personally use, feel free to use them directly if you happen to use these exchanges : )

You can also reference them to write your own, or even better, contribute your custom fetchers : )

const {
  getPortfolio,
  printPortfolioNicely,
  fetchers,
} = require('./crypto-portfolio-viewer');

const {
  fetchBinanceContractBalances,
  fetchFTXContractBalances,
} = fetchers;

(async () => {
  const portfolio = await getPortfolio({
    keys,
    addresses,
    othertokens,
    extraFetchers: {                          // <--here!
      binance: fetchBinanceContractBalances,
      ftx: fetchFTXContractBalances,,
    },
  });

  printPortfolioNicely(portfolio);
})();

🔥 LP tokens

Currently we don't support automatically "decode" LP tokens to their real values, to track these assets, please hard code them in other tokens.

LP tokens' "decoding" might be implemented in the future : )


APIs Summary

available parameters for getPortfolio(): | param | type | default | required? | description | |------------------|--------|---------|-----------|-----------------------------------| | keys | object | {} | no | exchange api keys | | addresses | array | [] | no | erc20 addresses | | othertokens | object | {} | no | other tokens | | extraFetchers | object | {} | no | customized fetcher for exchanges | | combineExchanges | bool | false | no | combine exchange assets in result | | combineAddresses | bool | false | no | combine erc20 assets in result | | verbose | bool | true | no | you know it |


Bugs? Questions? Contributions?

Feel free to open an issue, or create a pull request!


Special Thanks

Really appreciate all the fantastic works by ccxt and coingecko-api, which provide super useful utilities supporting this library.


UI

coming soon