Cryptocurrency Portfolio Tracker Development

We design and develop full-cycle blockchain solutions: from smart contract architecture to launching DeFi protocols, NFT marketplaces and crypto exchanges. Security audits, tokenomics, integration with existing infrastructure.
Showing 1 of 1 servicesAll 1306 services
Cryptocurrency Portfolio Tracker Development
Medium
~1-2 weeks
FAQ
Blockchain Development Services
Blockchain Development Stages
Latest works
  • image_website-b2b-advance_0.png
    B2B ADVANCE company website development
    1252
  • image_web-applications_feedme_466_0.webp
    Development of a web application for FEEDME
    1170
  • image_websites_belfingroup_462_0.webp
    Website development for BELFINGROUP
    873
  • image_ecommerce_furnoro_435_0.webp
    Development of an online store for the company FURNORO
    1092
  • image_logo-advance_0.png
    B2B Advance company logo design
    563
  • image_crm_enviok_479_0.webp
    Development of a web application for Enviok
    830

Crypto Portfolio Tracker Development

A simple portfolio tracker — this is a data aggregator. A complex one — this is a real-time system that aggregates on-chain balances from dozens of networks, positions on centralized exchanges, NFTs, DeFi positions, and calculates it all in a single base currency. Complexity difference is roughly 10x.

Data Sources

On-Chain Balances

EVM networks: native balance via eth_getBalance, ERC-20 balances more complex — one RPC call returns balance of one token on one address. With 50 tokens × 5 networks = 250 calls. Solution — Multicall3 (deployed on all EVM networks at address 0xcA11bde05977b3631167028862bE2a173976CA11):

import { createPublicClient, http, parseAbi } from "viem";
import { mainnet } from "viem/chains";

const client = createPublicClient({ chain: mainnet, transport: http() });

const MULTICALL3 = "0xcA11bde05977b3631167028862bE2a173976CA11";
const ERC20_ABI = parseAbi(["function balanceOf(address) view returns (uint256)"]);

async function getTokenBalances(
  walletAddress: `0x${string}`,
  tokenAddresses: `0x${string}`[]
) {
  const calls = tokenAddresses.map((tokenAddress) => ({
    address: tokenAddress,
    abi: ERC20_ABI,
    functionName: "balanceOf" as const,
    args: [walletAddress],
  }));

  return client.multicall({ contracts: calls });
}

One RPC call instead of 50 — critical for rate limits and latency.

Alternative: Alchemy/Moralis Token API. One request returns all ERC-20 balances for address with metadata (symbol, decimals, USD value). Paid, but saves development time.

DeFi Positions

This is the most complex part of tracker. Liquidity position in Uniswap V3, collateral in Aave, staked tokens in Curve — each protocol stores data differently.

Approach 1: direct calls to protocol contracts. For Uniswap V3:

// Position by NFT ID
const position = await nftPositionManager.positions(tokenId);
// { token0, token1, fee, tickLower, tickUpper, liquidity, ... }

// Recalculate to tokens via tick math (complex)
// Better via Uniswap V3 SDK
import { Pool, Position } from "@uniswap/v3-sdk";

Approach 2: The Graph subgraphs. Most DeFi protocols have official subgraphs — GraphQL API over on-chain data:

query GetAavePositions($address: String!) {
  user(id: $address) {
    reserves {
      reserve {
        symbol
        underlyingAsset
      }
      currentATokenBalance
      currentVariableDebt
      currentStableDebt
    }
  }
}

Approach 3: position aggregators — DeBank API, Zapper API, Zerion API. Already integrated with hundreds of protocols. Make sense if you don't want to maintain each DeFi integration yourself.

CEX Balances

Exchange APIs return balances instantly, but require read-only API key from user:

import ccxt from "ccxt";

async function getBinanceBalances(apiKey: string, secret: string) {
  const exchange = new ccxt.binance({ apiKey, secret, sandbox: false });
  const balance = await exchange.fetchBalance();
  return balance.total; // { BTC: 0.5, ETH: 2.3, USDT: 1000 }
}

CCXT supports 100+ exchanges with unified interface — indispensable library for trackers.

Price Data

For USD conversion current prices are needed. Sources:

CoinGecko API — free plan 30 requests/min, 10k/month. Sufficient for small trackers. Pro plan removes limits.

async function getPrices(coinIds: string[]): Promise<Record<string, number>> {
  const ids = coinIds.join(",");
  const data = await fetch(
    `https://api.coingecko.com/api/v3/simple/price?ids=${ids}&vs_currencies=usd`
  ).then(r => r.json());

  return Object.fromEntries(
    Object.entries(data).map(([id, val]: [string, any]) => [id, val.usd])
  );
}

On-chain prices (Chainlink): for real-time without CoinGecko dependency. Chainlink Price Feeds available on all major EVM networks.

Refresh Pipeline Architecture

Data needs updating, but not RPC hammering every second. Strategy:

Data Type Update Frequency Reason
On-chain balances Every 30–60 sec New block
CEX balances Every 30 sec API limits
DeFi positions Every 2–5 min Change slowly
Token prices Every 10–30 sec Critical for P&L
Historical P&L Background job, 1/hour Heavy computation

Background jobs via Redis + BullMQ with separate queues for different data types. Cache results in Redis, frontend reads from cache.

WebSocket for Real-Time

For users who opened tracker in browser — Server-Sent Events or WebSocket with push updates instead of polling:

// Server-Sent Events endpoint
app.get("/api/portfolio/stream", (req, res) => {
  res.setHeader("Content-Type", "text/event-stream");
  res.setHeader("Cache-Control", "no-cache");

  const interval = setInterval(async () => {
    const portfolio = await getPortfolioSnapshot(req.user.id);
    res.write(`data: ${JSON.stringify(portfolio)}\n\n`);
  }, 10000);

  req.on("close", () => clearInterval(interval));
});

Storing Historical Data

For P&L tracking snapshots of portfolio over time are needed. TimescaleDB (PostgreSQL extension) is ideal:

CREATE TABLE portfolio_snapshots (
  user_id UUID,
  snapshot_at TIMESTAMPTZ NOT NULL,
  total_usd NUMERIC(20, 2),
  breakdown JSONB -- { "ETH": { "amount": 2.3, "usd": 7820 }, ... }
);

SELECT create_hypertable('portfolio_snapshots', 'snapshot_at');

Query P&L for period:

SELECT
  time_bucket('1 day', snapshot_at) AS day,
  last(total_usd, snapshot_at) AS end_of_day_value
FROM portfolio_snapshots
WHERE user_id = $1 AND snapshot_at > NOW() - INTERVAL '30 days'
GROUP BY day ORDER BY day;

MVP development timeline with support for 5–6 EVM networks, main DeFi protocols, and 3–4 exchanges: 1–2 weeks.