Разработка портфельного трекера криптовалют

Проектируем и разрабатываем блокчейн-решения полного цикла: от архитектуры смарт-контрактов до запуска DeFi-протоколов, NFT-маркетплейсов и криптобирж. Аудит безопасности, токеномика, интеграция с существующей инфраструктурой.
Показано 1 из 1Все 1306 услуг
Разработка портфельного трекера криптовалют
Средний
~1-2 недели
Часто задаваемые вопросы

Направления блокчейн-разработки

Этапы блокчейн-разработки

Последние работы

  • image_website-b2b-advance_0.webp
    Разработка сайта компании B2B ADVANCE
    1308
  • image_web-applications_feedme_466_0.webp
    Разработка веб-приложения для компании FEEDME
    1220
  • image_websites_belfingroup_462_0.webp
    Разработка веб-сайта для компании БЕЛФИНГРУПП
    921
  • image_ecommerce_furnoro_435_0.webp
    Разработка интернет магазина для компании FURNORO
    1149
  • image_logo-advance_0.webp
    Разработка логотипа компании B2B Advance
    611
  • image_crm_enviok_479_0.webp
    Разработка веб-приложения для компании Enviok
    886

Разработка портфельного трекера криптовалют

Простой портфельный трекер — это агрегатор данных. Сложный — это система реального времени, которая сводит on-chain балансы из десятков сетей, позиции на централизованных биржах, NFT, DeFi позиции и считает всё это в единой базовой валюте. Разница в сложности примерно в 10x.

Источники данных

On-chain балансы

EVM-сети: нативный баланс через eth_getBalance, ERC-20 балансы сложнее — один RPC вызов возвращает баланс одного токена на одном адресе. При 50 токенах × 5 сетей = 250 вызовов. Решение — Multicall3 (задеплоен на всех EVM-сетях по адресу 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 });
}

Один RPC вызов вместо 50 — критично для rate limits и latency.

Альтернатива: Alchemy/Moralis Token API. Один запрос возвращает все ERC-20 балансы для адреса с метаданными (символ, decimals, USD стоимость). Платно, но экономит время разработки.

DeFi позиции

Это самая сложная часть трекера. Liquidity позиция в Uniswap V3, collateral в Aave, стейкнутые токены в Curve — каждый протокол хранит данные по-своему.

Подход 1: прямые вызовы к контрактам протоколов. Для Uniswap V3:

// Позиция по NFT ID
const position = await nftPositionManager.positions(tokenId);
// { token0, token1, fee, tickLower, tickUpper, liquidity, ... }

// Пересчёт в токены через математику тиков (сложно)
// Лучше через Uniswap V3 SDK
import { Pool, Position } from "@uniswap/v3-sdk";

Подход 2: The Graph subgraphs. Большинство DeFi протоколов имеют официальные subgraph — GraphQL API поверх on-chain данных:

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

Подход 3: агрегаторы позиций — DeBank API, Zapper API, Zerion API. Они уже интегрированы с сотнями протоколов. Имеют смысл если не хотите поддерживать каждую DeFi интеграцию самостоятельно.

CEX балансы

Биржевые API отдают балансы мгновенно, но требуют read-only API ключ от пользователя:

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 поддерживает 100+ бирж с единым интерфейсом — незаменимая библиотека для трекеров.

Ценовые данные

Для пересчёта в USD нужны актуальные цены. Источники:

CoinGecko API — бесплатный план 30 запросов/мин, 10k/мес. Для небольших трекеров достаточно. Pro план снимает лимиты.

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 цены (Chainlink): для реального времени без зависимости от CoinGecko. Chainlink Price Feeds доступны на всех крупных EVM-сетях.

Архитектура refresh pipeline

Данные нужно обновлять, но не молотить RPC каждую секунду. Стратегия:

Тип данных Частота обновления Причина
On-chain балансы Каждые 30–60 сек Новый блок
CEX балансы Каждые 30 сек API лимиты
DeFi позиции Каждые 2–5 мин Медленно меняются
Цены токенов Каждые 10–30 сек Критично для P&L
Historical P&L Фоновый job, 1/час Тяжёлые вычисления

Background jobs через Redis + BullMQ с отдельными очередями для разных типов данных. Результаты кешируем в Redis, фронтенд читает из кеша.

WebSocket для real-time

Для пользователей, открывших трекер в браузере — Server-Sent Events или WebSocket с push-обновлениями вместо 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));
});

Хранение исторических данных

Для P&L трекинга нужны снапшоты портфеля во времени. TimescaleDB (расширение PostgreSQL) идеально подходит:

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');

Запрос P&L за период:

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 с поддержкой 5–6 EVM сетей, основными DeFi протоколами и 3–4 биржами: 1–2 недели.