Crypto screener by technical indicators 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
Crypto screener by technical indicators development
Medium
~5 business days
FAQ
Blockchain Development Services
Blockchain Development Stages
Latest works
  • image_website-b2b-advance_0.png
    B2B ADVANCE company website development
    1214
  • image_web-applications_feedme_466_0.webp
    Development of a web application for FEEDME
    1161
  • image_websites_belfingroup_462_0.webp
    Website development for BELFINGROUP
    852
  • image_ecommerce_furnoro_435_0.webp
    Development of an online store for the company FURNORO
    1041
  • image_logo-advance_0.png
    B2B Advance company logo design
    561
  • image_crm_enviok_479_0.webp
    Development of a web application for Enviok
    823

Development of Crypto Market Depth Screener

Market depth screener analyzes order books of multiple instruments simultaneously and finds anomalies: large liquidity walls, bid/ask imbalance, abnormal volume at levels. This is a tool for traders who read the stack and make decisions based on market microstructure.

What Screener Analyzes

Bid/Ask imbalance: if bid-side volume 3x more than ask—excess buy pressure. Strong signal for short-term upward move.

Liquidity walls: anomalously large order at single level. Could be real support/resistance or spoofing (order placed and canceled before execution).

Spread: wide spread = low liquidity = high slippage on entry.

Depth at price levels: how much volume needed to "eat" the stack by 1%, 2%, 5%.

Screener Architecture

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

interface DepthMetrics {
  symbol: string;
  bidVolume: number;      // total volume at N bid levels
  askVolume: number;      // total volume at N ask levels
  imbalance: number;      // bid / (bid + ask), 0.5 = neutral
  spread: number;         // % spread
  spreadUSD: number;      // absolute spread in USD
  bidWall: WallInfo | null;
  askWall: WallInfo | null;
  liquidationAt1Pct: number;  // volume needed for 1% move
  liquidationAt2Pct: number;
}

interface WallInfo {
  price: number;
  size: number;
  sizeUSD: number;
  relativeSize: number;  // how many times larger than average level
}

Computing Metrics

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;
  
  // Find walls: level with volume > avg * threshold
  const avgBidSize = bidVolume / bids.length;
  const avgAskSize = askVolume / asks.length;
  const wallThreshold = 3.0;  // 3x larger = wall
  
  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);
  
  // Liquidity at 1% move
  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,  // similarly for ask
    liquidationAt1Pct,
    liquidationAt2Pct: 0,  // similarly
  };
}

Screener Table

// Sortable table with metrics across all pairs
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 });
  
  // Filter and sort
  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>
  );
}

Condition-Based Alerts

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

Data Collection

Screener requires WebSocket connections to exchanges. For 50 pairs—50 WebSocket channels. Connection manager:

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

Development of market depth screener for 20–50 pairs with real-time updates, sorting, filters and alerts: 4–6 weeks.