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

Проектируем и разрабатываем блокчейн-решения полного цикла: от архитектуры смарт-контрактов до запуска DeFi-протоколов, NFT-маркетплейсов и криптобирж. Аудит безопасности, токеномика, интеграция с существующей инфраструктурой.
Показано 1 из 1 услугВсе 1306 услуг
Разработка скринера криптовалют по индикаторам
Средняя
~5 рабочих дней
Часто задаваемые вопросы
Направления блокчейн-разработки
Этапы блокчейн-разработки
Последние работы
  • image_website-b2b-advance_0.png
    Разработка сайта компании B2B ADVANCE
    1221
  • image_web-applications_feedme_466_0.webp
    Разработка веб-приложения для компании FEEDME
    1163
  • image_websites_belfingroup_462_0.webp
    Разработка веб-сайта для компании БЕЛФИНГРУПП
    855
  • image_ecommerce_furnoro_435_0.webp
    Разработка интернет магазина для компании FURNORO
    1062
  • image_logo-advance_0.png
    Разработка логотипа компании B2B Advance
    561
  • image_crm_enviok_479_0.webp
    Разработка веб-приложения для компании Enviok
    828

Разработка скринера по глубине рынка

Скринер по глубине рынка анализирует order book нескольких инструментов одновременно и находит аномалии: крупные стены ликвидности, дисбаланс bid/ask, аномальный объём на уровнях. Это инструмент для трейдеров, которые читают стакан и принимают решения на основе market microstructure.

Что анализирует скринер глубины

Bid/Ask imbalance: если на bid-стороне объём в 3× больше чем на ask — избыточный buy pressure. Сильный сигнал для краткосрочного движения вверх.

Liquidity walls: аномально крупный ордер на одном уровне. Может быть реальной поддержкой/сопротивлением или spoofing (ордер выставляется и снимается до исполнения).

Spread: широкий спред = низкая ликвидность = высокий slippage при входе.

Depth at price levels: сколько нужно объёма чтобы "съесть" стакан на 1%, 2%, 5%.

Архитектура скринера

interface MarketDepthSnapshot {
  symbol: string;
  exchange: string;
  timestamp: number;
  bids: [price: number, size: number][];
  asks: [price: number, size: number][];
}

interface DepthMetrics {
  symbol: string;
  bidVolume: number;      // суммарный объём на N уровнях bid
  askVolume: number;      // суммарный объём на N уровнях ask
  imbalance: number;      // bid / (bid + ask), 0.5 = нейтрально
  spread: number;         // % спред
  spreadUSD: number;      // абсолютный спред в USD
  bidWall: WallInfo | null;
  askWall: WallInfo | null;
  liquidationAt1Pct: number;  // объём нужный для 1% движения
  liquidationAt2Pct: number;
}

interface WallInfo {
  price: number;
  size: number;
  sizeUSD: number;
  relativeSize: number;  // во сколько раз больше среднего уровня
}

Вычисление метрик

function calculateDepthMetrics(
  snapshot: MarketDepthSnapshot,
  levels: number = 20
): DepthMetrics {
  const bids = snapshot.bids.slice(0, levels);
  const asks = snapshot.asks.slice(0, levels);
  const midPrice = (bids[0][0] + asks[0][0]) / 2;
  
  const bidVolume = bids.reduce((sum, [, size]) => sum + size, 0);
  const askVolume = asks.reduce((sum, [, size]) => sum + size, 0);
  
  const imbalance = bidVolume / (bidVolume + askVolume);
  const spread = (asks[0][0] - bids[0][0]) / midPrice * 100;
  
  // Поиск стен: уровень с объёмом > avg * threshold
  const avgBidSize = bidVolume / bids.length;
  const avgAskSize = askVolume / asks.length;
  const wallThreshold = 3.0;  // в 3× больше среднего = стена
  
  const bidWall = bids.reduce((max, [price, size]) => {
    if (size > avgBidSize * wallThreshold) {
      if (!max || size > max.size) {
        return { price, size, sizeUSD: size * price, 
                 relativeSize: size / avgBidSize };
      }
    }
    return max;
  }, null as WallInfo | null);
  
  // Ликвидность на 1% движения
  const priceAt1PctDown = midPrice * 0.99;
  const liquidationAt1Pct = bids
    .filter(([price]) => price >= priceAt1PctDown)
    .reduce((sum, [, size]) => sum + size * midPrice, 0);
  
  return {
    symbol: snapshot.symbol,
    bidVolume: bidVolume * midPrice,
    askVolume: askVolume * midPrice,
    imbalance,
    spread,
    spreadUSD: asks[0][0] - bids[0][0],
    bidWall,
    askWall: null,  // аналогично для ask
    liquidationAt1Pct,
    liquidationAt2Pct: 0,  // аналогично
  };
}

Скринер таблица

// Сортируемая таблица с метриками по всем парам
function DepthScreener() {
  const [metrics, setMetrics] = useState<DepthMetrics[]>([]);
  const [sort, setSort] = useState<{ field: keyof DepthMetrics; direction: 'asc' | 'desc' }>(
    { field: 'imbalance', direction: 'desc' }
  );
  const [filter, setFilter] = useState({ minImbalance: 0.6, maxSpread: 0.1 });
  
  // Фильтруем и сортируем
  const filtered = metrics
    .filter(m => m.imbalance >= filter.minImbalance && m.spread <= filter.maxSpread)
    .sort((a, b) => {
      const val = (x: DepthMetrics) => x[sort.field] as number;
      return sort.direction === 'desc' ? val(b) - val(a) : val(a) - val(b);
    });
  
  return (
    <table>
      <thead>
        <SortableHeader field="symbol" label="Symbol" {...sort} onSort={setSort} />
        <SortableHeader field="imbalance" label="Imbalance" {...sort} onSort={setSort} />
        <SortableHeader field="spread" label="Spread %" {...sort} onSort={setSort} />
        <SortableHeader field="bidVolume" label="Bid Volume" {...sort} onSort={setSort} />
        <SortableHeader field="liquidationAt1Pct" label="Liq @1%" {...sort} onSort={setSort} />
      </thead>
      <tbody>
        {filtered.map(m => (
          <DepthMetricRow key={m.symbol} metrics={m} />
        ))}
      </tbody>
    </table>
  );
}

Алерты по условиям

interface DepthAlert {
  symbol: string;
  condition: 'imbalance_spike' | 'wall_appeared' | 'wall_removed' | 'spread_widened';
  threshold: number;
  notifyVia: ('ui' | 'telegram' | 'webhook')[];
}

class DepthAlertEngine {
  private prevSnapshots = new Map<string, DepthMetrics>();
  
  checkAlerts(current: DepthMetrics, alerts: DepthAlert[]) {
    const prev = this.prevSnapshots.get(current.symbol);
    if (!prev) {
      this.prevSnapshots.set(current.symbol, current);
      return;
    }
    
    for (const alert of alerts) {
      if (alert.symbol !== current.symbol) continue;
      
      switch (alert.condition) {
        case 'imbalance_spike':
          if (current.imbalance >= alert.threshold && prev.imbalance < alert.threshold) {
            this.triggerAlert(alert, `Imbalance spike on ${current.symbol}: ${(current.imbalance * 100).toFixed(1)}%`);
          }
          break;
        case 'wall_appeared':
          if (current.bidWall && !prev.bidWall && current.bidWall.sizeUSD >= alert.threshold) {
            this.triggerAlert(alert, `Bid wall appeared on ${current.symbol}: $${(current.bidWall.sizeUSD/1000).toFixed(0)}k`);
          }
          break;
      }
    }
    
    this.prevSnapshots.set(current.symbol, current);
  }
}

Сбор данных

Скринер требует WebSocket подключений к биржам. Для 50 пар — 50 WebSocket каналов. Менеджер соединений:

class MultiExchangeDepthFeed {
  private connections = new Map<string, WebSocket>();
  private onUpdate: (snapshot: MarketDepthSnapshot) => void;
  
  subscribe(symbol: string, exchange: 'binance' | 'okx' | 'bybit') {
    const wsUrl = this.getWSUrl(exchange, symbol);
    const ws = new WebSocket(wsUrl);
    
    ws.onmessage = (e) => {
      const snapshot = this.parseMessage(exchange, JSON.parse(e.data));
      if (snapshot) this.onUpdate(snapshot);
    };
    
    ws.onclose = () => {
      setTimeout(() => this.subscribe(symbol, exchange), 3000);
    };
    
    this.connections.set(`${exchange}:${symbol}`, ws);
  }
}

Разработка скринера по глубине рынка для 20–50 пар с real-time обновлениями, сортировкой, фильтрами и алертами: 4–6 недель.