Розробка системи моніторингу курсів криптовалют

Проєктуємо та розробляємо блокчейн-рішення повного циклу: від архітектури смарт-контрактів до запуску DeFi-протоколів, NFT-маркетплейсів та криптобірж. Аудит безпеки, токеноміка, інтеграція з наявною інфраструктурою.
Показано 1 з 1Усі 1306 послуг
Розробка системи моніторингу курсів криптовалют
Простий
~3-5 днів
Часті запитання

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

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

Останні роботи

  • 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
    1148
  • image_logo-advance_0.webp
    Розробка логотипу компанії B2B Advance
    611
  • image_crm_enviok_479_0.webp
    Розробка веб-додатків для компанії Enviok
    886

Розробка системи мониторингу курсів криптовалют

"Просто дергаємо CoinGecko API раз на хвилину" — цей підхід працює ровно до першого rate limit або до того моменту, коли продукту потрібні дані швидше ніж раз на 60 секунд. Система мониторингу курсів — це не один API запит, це pipeline: джерело даних → нормалізація → зберігання → доставка клієнтам → алерти. Кожен шар має свої вимоги до надійності.

Джерела даних: що використовувати і коли

CEX через WebSocket (найнижча затримка)

Для realtime курсів — напрямку до біржевих WebSocket стримів. Жодної агрегації, мінімальна затримка:

// Binance WebSocket — tick дані в реальному часі
const ws = new WebSocket('wss://stream.binance.com:9443/stream?streams=btcusdt@ticker/ethusdt@ticker')

ws.on('message', (data) => {
  const { stream, data: tick } = JSON.parse(data)
  const symbol = tick.s        // BTCUSDT
  const price = parseFloat(tick.c)   // останній курс
  const volume24h = parseFloat(tick.v)
  const priceChange24h = parseFloat(tick.P)  // відсоток
  
  normalizeAndStore({ source: 'binance', symbol, price, volume24h, timestamp: Date.now() })
})

ws.on('close', () => {
  // Exponential backoff reconnect — не опціональний
  setTimeout(connectBinance, Math.min(reconnectDelay * 2, 30000))
})

Аналогічні стрими є у Coinbase (wss://advanced-trade-ws.coinbase.com/), OKX, Bybit. Для ліквідних пар — мінімум три джерела, медіанна ціна як захист від outliers.

DEX on-chain ціни

Для DeFi додатків ціни часто потрібні саме on-chain. Два підходи:

Uniswap V3 TWAP — Time-Weighted Average Price за останні N блоків. Стійкий до маніпуляцій (для flash loan атак потрібно утримувати позицію кілька блоків):

// На контракті — приблизно як працює читання TWAP
IUniswapV3Pool pool = IUniswapV3Pool(WETH_USDC_POOL);
(int56[] memory tickCumulatives,) = pool.observe([600, 0]); // 600 секунд назад і тепер
int56 tickDiff = tickCumulatives[1] - tickCumulatives[0];
int24 avgTick = int24(tickDiff / 600);
uint160 sqrtPriceX96 = TickMath.getSqrtRatioAtTick(avgTick);
// Перевід sqrtPriceX96 в читаний людиною формат ціни...

Chainlink Price Feeds — для production смарт-контрактів це стандарт. Decentralized oracle network, агрегує дані від множини джерел:

AggregatorV3Interface priceFeed = AggregatorV3Interface(0x5f4eC3Df9cbd43714FE2740f5E3616155c5b8419); // ETH/USD
(, int256 price, , uint256 updatedAt,) = priceFeed.latestRoundData();
require(block.timestamp - updatedAt < 3600, "Price feed stale"); // перевірка свіжості

CoinGecko / CoinMarketCap (агрегована)

Для історичних даних і менш ліквідних токенів. Rate limits: CoinGecko free — 30 запитів/хв, paid API — до 500. Кешуємо агресивно.

Архітектура системи

Зберігання: TimescaleDB або InfluxDB

Курси — типовий time-series use case. PostgreSQL з розширенням TimescaleDB — хороший вибір якщо вже використовується PG:

CREATE TABLE price_ticks (
  time        TIMESTAMPTZ NOT NULL,
  symbol      VARCHAR(20) NOT NULL,
  source      VARCHAR(20) NOT NULL,
  price       NUMERIC(20, 8) NOT NULL,
  volume_24h  NUMERIC(30, 2),
  bid         NUMERIC(20, 8),
  ask         NUMERIC(20, 8)
);

SELECT create_hypertable('price_ticks', 'time');

-- Автоматична агрегація в OHLCV свічки
SELECT 
  time_bucket('1 minute', time) AS bucket,
  symbol,
  first(price, time) AS open,
  max(price) AS high,
  min(price) AS low,
  last(price, time) AS close,
  sum(volume_24h) AS volume
FROM price_ticks
WHERE time > NOW() - INTERVAL '1 hour'
GROUP BY bucket, symbol
ORDER BY bucket DESC;

TimescaleDB автоматично партиціонує дані за часом і надає функції time_bucket, first, last. Retention policy — автоудалення тиків старше 30 днів, зберігати тільки агрегати (свічки 1m/5m/1h/1d) для історії.

Алерти

Два типи алертів:

Price change alert — ціна змінилась на X% за Y хвилин:

class PriceAlertService {
  constructor(redis) {
    this.redis = redis
    this.subscribers = new Map()
  }
  
  async checkAlert(symbol, currentPrice) {
    const priceKey = `price:${symbol}:1m_ago`
    const pastPrice = await this.redis.get(priceKey)
    
    if (pastPrice) {
      const changePercent = Math.abs((currentPrice - pastPrice) / pastPrice * 100)
      
      if (changePercent >= ALERT_THRESHOLD_PERCENT) {
        await this.triggerAlert({
          symbol,
          currentPrice,
          pastPrice: parseFloat(pastPrice),
          changePercent,
          direction: currentPrice > pastPrice ? 'up' : 'down'
        })
      }
    }
    
    // Зберігаємо поточну ціну для наступної перевірки
    await this.redis.setex(priceKey, 60, currentPrice.toString())
  }
  
  async triggerAlert(alertData) {
    // Відправка в Telegram, Slack, email — залежить від конфігу
    for (const [webhookUrl, config] of this.subscribers) {
      if (config.symbols.includes(alertData.symbol)) {
        fetch(webhookUrl, { method: 'POST', body: JSON.stringify(alertData) })
      }
    }
  }
}

Stale data alert — якщо дані перестали оновлюватись (джерело впало):

setInterval(() => {
  for (const [symbol, lastUpdate] of lastUpdates) {
    if (Date.now() - lastUpdate > STALE_THRESHOLD_MS) {
      sendAlert(`Data for ${symbol} stale for ${Math.round((Date.now() - lastUpdate)/1000)}s`)
    }
  }
}, 10000)

Доставка клієнтам

WebSocket API для фронтенду:

// Server-sent events або WebSocket — SSE простіше для read-only стрима
app.get('/stream/prices', (req, res) => {
  res.setHeader('Content-Type', 'text/event-stream')
  res.setHeader('Cache-Control', 'no-cache')
  
  const symbols = req.query.symbols?.split(',') || ['BTCUSDT', 'ETHUSDT']
  
  const interval = setInterval(async () => {
    const prices = await getPricesFromCache(symbols)
    res.write(`data: ${JSON.stringify(prices)}\n\n`)
  }, 1000)
  
  req.on('close', () => clearInterval(interval))
})

Redis pub/sub між колектором даних і API шаром — щоб не навантажувати БД на кожен запит клієнта.

Що входить в роботу

  • Підключення до джерел даних (біржові WebSocket, Chainlink, агрегатори)
  • Нормалізація даних і TimescaleDB/InfluxDB зберігання
  • REST і WebSocket API для клієнтів
  • Система алертів з настроюваними умовами
  • Моніторинг доступності джерел і автопереключення