The $2.3 Million Data Problem

At 9:47 AM on March 15, a systematic equity strategy at a mid-sized quant fund lost $2.3 million in 23 seconds. The cause was not a trading signal error. The cause was a stale primary market data feed that continued publishing prices 1.2 seconds after the exchange had updated its quote engine. By the time the strategy's risk system detected the discrepancy, three large positions had been liquidated against prices that no longer existed.

This incident is not an outlier. A 2024 survey of institutional trading firms found that 67% had experienced material losses attributable to primary data feed failures in the preceding 24 months. The average incident cost exceeded $400,000. For retail traders and smaller quant shops, the exposure is often smaller in absolute terms but proportionally devastating.

The solution is not a single-provider SLA with 99.99% uptime. The solution is architectural: dual-source cross-validation. By subscribing to a secondary market data feed and running a real-time comparison against the primary, you can detect delays, data gaps, and errors before they cascade into losses.

This article provides the production-grade architecture, algorithm, and code for implementing dual-source validation using TickDB as the secondary feed.


Why Primary Feeds Fail

Understanding what dual-source validation protects against requires a precise taxonomy of primary feed failure modes.

1. Stale Data (Latency Drift)

The most common failure mode. The primary feed continues publishing timestamped ticks, but the timestamps lag behind real time by a threshold that varies by strategy sensitivity. Common causes include:

  • Network congestion or packet loss between the exchange and your colocation facility
  • Feed handler bottlenecks under high message throughput
  • Scheduled maintenance that silently degrades feed performance without triggering disconnection alerts
  • API rate limiting that throttles your subscription, causing systematic delay accumulation

2. Data Gaps (Dropped Ticks)

Ticks that were transmitted by the exchange but never received by your system. These are particularly dangerous because they produce a false impression of price stability. If a 0.8% price move occurs across two dropped ticks, your system perceives a flat market and may make incorrect sizing decisions.

3. Structural Data Errors

Misformatted messages, incorrect sequence numbers, and price-scale errors (e.g., a price encoded in cents rather than dollars). These typically trigger parsing exceptions but can slip through if error handling is lenient.

4. Source Disconnection

The feed handler disconnects and fails to reconnect automatically. Your system continues processing the last known price indefinitely, a condition known as a "stale book."

5. Cross-Asset Price Divergence (Unjustified)

Related instruments that should track each other diverge beyond a historically established range. For example, ES futures and SPY ETF should maintain a correlation of 0.98+. A sudden divergence to 0.85 suggests a data problem on one side.


The Dual-Source Validation Architecture

High-Level Design

┌─────────────────────────────────────────────────────────────┐
│                    Primary Market Data Feed                 │
│                  (Exchange Direct / Vendor)                  │
└────────────────────────┬────────────────────────────────────┘
                         │
                         ▼
              ┌─────────────────────┐
              │  Primary Ingestion  │
              │    Handler (P)       │
              └──────────┬──────────┘
                         │
                         ▼
              ┌─────────────────────┐
              │   Primary Data      │
              │   Buffer (P)        │
              │   Last 100 ticks    │
              └──────────┬──────────┘
                         │
          ┌──────────────┴──────────────┐
          │                             │
          ▼                             ▼
┌─────────────────────┐     ┌─────────────────────┐
│   TickDB Secondary  │     │  Validation Engine  │
│   Ingestion (S)      │     │  (Comparison Loop)  │
└──────────┬──────────┘     └──────────┬──────────┘
           │                           │
           │         ┌─────────────────┘
           ▼         ▼
┌─────────────────────┐
│  Alert Dispatcher   │
│  (Slack / PagerDuty)│
└─────────────────────┘

Why TickDB as the Secondary Source

TickDB provides several properties that make it well-suited for the secondary validation role:

Property Why It Matters for Validation
WebSocket push delivery Sub-100ms latency; matches or exceeds most institutional feeds
Depth channel (HK, Crypto) Enables order-book-level validation, not just price-level
Kline historical endpoint Provides baseline comparison for historical backtesting of the validation algorithm itself
Multi-market coverage Covers equities, crypto, forex — enabling cross-asset validation use cases
Clean OHLCV alignment Timestamps are exchange-synchronized, reducing false positives from timezone artifacts

The Cross-Validation Algorithm

Core Comparison Logic

The validation engine compares primary (P) and secondary (S) ticks on three dimensions:

  1. Timestamp drift: drift = T_publish_S - T_publish_P. A drift exceeding the threshold suggests primary latency.
  2. Price deviation: deviation_pct = |P_price - S_price| / S_price * 100. A deviation exceeding the threshold suggests a data error or market dislocation.
  3. Sequence continuity: For tick-based feeds, missing sequence numbers indicate dropped ticks.

Algorithm Pseudocode

class DualSourceValidator:
    def __init__(self, primary_source, secondary_source, config):
        self.primary = primary_source        # Primary WebSocket feed
        self.secondary = secondary_source  # TickDB WebSocket feed
        self.config = config

        # Thresholds
        self.timestamp_drift_threshold = config.get("drift_ms", 500)      # ms
        self.price_deviation_threshold = config.get("deviation_bps", 5)   # basis points
        self.stale_ticks_threshold = config.get("stale_ticks", 5)         # consecutive stale before alert

        # State
        self.last_primary_tick = None
        self.last_secondary_tick = None
        self.consecutive_stale_count = 0
        self.alerts = []

    def compare_ticks(self, p_tick, s_tick):
        """Compare primary and secondary ticks; return dict of deviations."""
        deviations = {}

        # Timestamp drift
        drift_ms = (s_tick["timestamp"] - p_tick["timestamp"]).total_seconds() * 1000
        deviations["drift_ms"] = drift_ms
        deviations["drift_ok"] = abs(drift_ms) <= self.timestamp_drift_threshold

        # Price deviation (for same symbol)
        if p_tick["symbol"] == s_tick["symbol"]:
            price_diff = abs(p_tick["price"] - s_tick["price"]) / s_tick["price"]
            deviations["price_deviation_bps"] = price_diff * 10000
            deviations["price_ok"] = deviations["price_deviation_bps"] <= self.price_deviation_threshold
        else:
            deviations["price_ok"] = None  # Cannot compare different symbols

        return deviations

    def check_staleness(self, p_tick):
        """Detect if primary feed has gone stale."""
        if self.last_primary_tick is None:
            self.last_primary_tick = p_tick
            return False

        time_since_last = (p_tick["timestamp"] - self.last_primary_tick["timestamp"]).total_seconds()

        # If more than 2x the expected tick interval has passed, mark as potentially stale
        if time_since_last > self.config["expected_interval_sec"] * 2:
            self.consecutive_stale_count += 1
            self.last_primary_tick = p_tick
            return self.consecutive_stale_count >= self.stale_ticks_threshold

        self.consecutive_stale_count = 0
        self.last_primary_tick = p_tick
        return False

Deviation Threshold Calibration

Threshold values are not universal. They must be calibrated to the instrument and market conditions.

Instrument type Typical drift threshold Typical price deviation threshold Rationale
US large-cap equities 200–500 ms 5–10 bps Liquid markets; tight spreads; fast price discovery
Crypto major (BTC, ETH) 100–300 ms 3–8 bps 24/7 markets; high volatility; multiple exchange prices
HK equities 500–1000 ms 10–20 bps Auction mechanism; less liquid; wider spreads
Forex majors 200–500 ms 2–5 bps Extremely liquid; tight spreads; centralized pricing
Futures (ES, NQ) 100–200 ms 3–5 bps Highly electronic; tight spreads; near-zero errors expected

Calibration methodology: Start with conservative thresholds (higher tolerance). Run the validator in shadow mode (log deviations without alerting) for 5 trading days. Analyze the 99th percentile of observed deviations. Set thresholds at 1.5x the 99th percentile to minimize false positives while catching genuine anomalies.


Production-Grade Implementation

TickDB Secondary Feed Integration

The following code implements the TickDB WebSocket subscription with all required production elements: heartbeat, exponential backoff with jitter, rate-limit handling, and environment-variable authentication.

import os
import json
import time
import random
import logging
import threading
from datetime import datetime, timezone
from dataclasses import dataclass, field
from typing import Optional, Callable

import websocket  # pip install websocket-client

logging.basicConfig(
    level=logging.INFO,
    format="%(asctime)s [%(levelname)s] %(name)s: %(message)s"
)
logger = logging.getLogger("tickdb_secondary")


@dataclass
class TickDBConfig:
    api_key: str = field(default_factory=lambda: os.environ.get("TICKDB_API_KEY", ""))
    ws_url: str = "wss://api.tickdb.ai/ws/market"
    ping_interval_sec: int = 15
    reconnect_base_delay: float = 1.0
    reconnect_max_delay: float = 60.0
    rate_limit_retry_delay: float = 5.0


class TickDBSecondaryFeed:
    """Production-grade TickDB WebSocket client with reconnection and rate-limit handling."""

    def __init__(self, config: TickDBConfig):
        self.config = config
        self.ws: Optional[websocket.WebSocketApp] = None
        self._running = False
        self._reconnect_attempts = 0
        self._on_tick: Optional[Callable] = None

    def subscribe(self, symbols: list[str], on_tick: Callable[[dict], None]):
        """
        Subscribe to real-time ticks for the given symbols.

        Args:
            symbols: List of tickers (e.g., ["AAPL.US", "NVDA.US"])
            on_tick: Callback invoked for each received tick.
        """
        self._on_tick = on_tick
        self._running = True
        self._connect(symbols)

    def _connect(self, symbols: list[str]):
        """Establish WebSocket connection with authentication."""
        if not self.config.api_key:
            raise ValueError(
                "TICKDB_API_KEY not set. "
                "Obtain from https://tickdb.ai/dashboard and export as an environment variable."
            )

        params = "&".join(f"symbols={s}" for s in symbols)
        url = f"{self.config.ws_url}?api_key={self.config.api_key}&{params}"

        try:
            self.ws = websocket.WebSocketApp(
                url,
                on_message=self._on_message,
                on_error=self._on_error,
                on_close=self._on_close,
                on_open=self._on_open,
            )

            # Run WebSocket in a daemon thread
            thread = threading.Thread(target=self.ws.run_forever, daemon=True)
            thread.start()

        except Exception as e:
            logger.error(f"Connection failed: {e}")
            self._schedule_reconnect(symbols)

    def _on_open(self, ws):
        """Handle WebSocket open event; start heartbeat."""
        logger.info("TickDB WebSocket connected")
        self._reconnect_attempts = 0
        self._run_heartbeat()

    def _run_heartbeat(self):
        """Send periodic ping to keep connection alive."""
        def ping_loop():
            while self._running and self.ws and self.ws.sock and self.ws.sock.connected:
                try:
                    self.ws.send(json.dumps({"cmd": "ping"}))
                    time.sleep(self.config.ping_interval_sec)
                except Exception:
                    break

        thread = threading.Thread(target=ping_loop, daemon=True)
        thread.start()

    def _on_message(self, ws, message):
        """Parse incoming tick and invoke callback."""
        try:
            data = json.loads(message)

            # Handle different message types
            msg_type = data.get("type") or data.get("channel")

            if msg_type in ("tick", "depth", "trade", "kline"):
                tick = {
                    "symbol": data.get("symbol"),
                    "price": float(data.get("price", data.get("last", 0))),
                    "timestamp": datetime.fromtimestamp(
                        data.get("ts", data.get("timestamp", 0)) / 1000,
                        tz=timezone.utc
                    ),
                    "raw": data,
                }
                if self._on_tick:
                    self._on_tick(tick)

            elif data.get("code") == 3001:
                # Rate limit exceeded
                retry_after = float(data.get("retry_after", self.config.rate_limit_retry_delay))
                logger.warning(f"Rate limit hit. Retrying after {retry_after}s")
                time.sleep(retry_after)
                # Connection will auto-reconnect via ping timeout detection

            elif data.get("code") in (1001, 1002):
                raise ValueError(f"Authentication error {data.get('code')}: check TICKDB_API_KEY")

        except Exception as e:
            logger.error(f"Failed to parse message: {e}")

    def _on_error(self, ws, error):
        """Log WebSocket errors."""
        logger.error(f"WebSocket error: {error}")

    def _on_close(self, ws, close_status_code, close_msg):
        """Handle disconnection; schedule reconnection with backoff."""
        if self._running:
            logger.warning(f"Connection closed ({close_status_code}): {close_msg}")
            self._schedule_reconnect(None)

    def _schedule_reconnect(self, symbols: list[str]):
        """Exponential backoff with jitter to prevent thundering herd."""
        self._reconnect_attempts += 1
        delay = min(
            self.config.reconnect_base_delay * (2 ** self._reconnect_attempts),
            self.config.reconnect_max_delay
        )
        jitter = random.uniform(0, delay * 0.1)  # Up to 10% jitter
        total_delay = delay + jitter

        logger.info(f"Reconnecting in {total_delay:.2f}s (attempt {self._reconnect_attempts})")
        time.sleep(total_delay)

        if symbols:
            self._connect(symbols)

    def stop(self):
        """Gracefully stop the feed."""
        self._running = False
        if self.ws:
            self.ws.close()

⚠️ Engineering warning: This implementation uses the websocket-client library for clarity. For production HFT workloads handling more than 10,000 ticks per second, migrate to aiohttp with asyncio for non-blocking I/O and lower GIL contention.


Alert Dispatcher Implementation

import requests
import json
from typing import Literal


class AlertDispatcher:
    """Dispatch validation alerts to Slack, PagerDuty, or a webhook."""

    def __init__(self, slack_webhook_url: str = None, pagerduty_key: str = None):
        self.slack_webhook_url = slack_webhook_url or os.environ.get("SLACK_WEBHOOK_URL")
        self.pagerduty_key = pagerduty_key or os.environ.get("PAGERDUTY_KEY")

    def send_alert(self, severity: Literal["low", "medium", "high", "critical"], message: str, context: dict):
        """
        Send an alert to all configured channels.

        Args:
            severity: Alert severity level
            message: Human-readable alert message
            context: Additional context (deviations, timestamps, symbols)
        """
        alert_payload = {
            "severity": severity,
            "message": message,
            "timestamp": datetime.now(timezone.utc).isoformat(),
            "context": context,
        }

        if self.slack_webhook_url:
            self._send_slack(alert_payload)

        if self.pagerduty_key:
            self._send_pagerduty(alert_payload)

        logger.warning(f"ALERT [{severity.upper()}]: {message}")

    def _send_slack(self, payload: dict):
        """Send alert to Slack via webhook."""
        blocks = [
            {
                "type": "header",
                "text": {"type": "plain_text", "text": f"🚨 Data Quality Alert: {payload['severity'].upper()}"}
            },
            {
                "type": "section",
                "text": {"type": "mrkdwn", "text": f"*{payload['message']}*"}
            },
            {
                "type": "section",
                "fields": [
                    {"type": "mrkdwn", "text": f"*Time:*\n{payload['timestamp']}"},
                    {"type": "mrkdwn", "text": f"*Severity:*\n{payload['severity']}"}
                ]
            }
        ]

        # Add context details
        if payload.get("context"):
            ctx_str = "\n".join(f"`{k}`: {v}" for k, v in payload["context"].items())
            blocks.append({"type": "section", "text": {"type": "mrkdwn", "text": ctx_str}})

        try:
            response = requests.post(
                self.slack_webhook_url,
                json={"blocks": blocks},
                timeout=(3.05, 5),
                headers={"Content-Type": "application/json"}
            )
            response.raise_for_status()
        except requests.RequestException as e:
            logger.error(f"Failed to send Slack alert: {e}")

    def _send_pagerduty(self, payload: dict):
        """Send alert to PagerDuty Events API v2."""
        severity_map = {"low": "info", "medium": "warning", "high": "error", "critical": "critical"}
        pd_severity = severity_map.get(payload["severity"], "warning")

        pd_payload = {
            "routing_key": self.pagerduty_key,
            "event_action": "trigger",
            "payload": {
                "summary": payload["message"],
                "timestamp": payload["timestamp"],
                "severity": pd_severity,
                "custom_details": payload.get("context", {}),
            }
        }

        try:
            response = requests.post(
                "https://events.pagerduty.com/v2/enqueue",
                json=pd_payload,
                timeout=(3.05, 5),
                headers={"Content-Type": "application/json"}
            )
            response.raise_for_status()
        except requests.RequestException as e:
            logger.error(f"Failed to send PagerDuty alert: {e}")

Integrated Validation Engine

import asyncio
from collections import deque


class ValidationEngine:
    """
    Core dual-source validation engine.
    Compares primary and secondary ticks, detects deviations, and dispatches alerts.
    """

    def __init__(self, config: dict):
        self.config = config
        self.drift_threshold_ms = config.get("drift_ms", 500)
        self.deviation_threshold_bps = config.get("deviation_bps", 5)
        self.stale_threshold = config.get("stale_ticks", 5)

        # Tick buffers (last N ticks per symbol for rolling comparison)
        self.buffer_size = config.get("buffer_size", 100)
        self.primary_buffer: dict[str, deque] = {}
        self.secondary_buffer: dict[str, deque] = {}

        self.consecutive_stale = 0
        self.alert_dispatcher = AlertDispatcher()

    def record_primary_tick(self, tick: dict):
        """Record a tick from the primary source."""
        symbol = tick["symbol"]
        if symbol not in self.primary_buffer:
            self.primary_buffer[symbol] = deque(maxlen=self.buffer_size)
        self.primary_buffer[symbol].append(tick)

        # Check for staleness
        self._check_staleness(symbol)

    def record_secondary_tick(self, tick: dict):
        """Record a tick from the secondary source (TickDB)."""
        symbol = tick["symbol"]
        if symbol not in self.secondary_buffer:
            self.secondary_buffer[symbol] = deque(maxlen=self.buffer_size)
        self.secondary_buffer[symbol].append(tick)

    def _check_staleness(self, symbol: str):
        """Detect stale primary feed."""
        if symbol not in self.primary_buffer or len(self.primary_buffer[symbol]) < 2:
            return

        recent = list(self.primary_buffer[symbol])[-2:]
        interval = (recent[1]["timestamp"] - recent[0]["timestamp"]).total_seconds()

        expected = self.config.get("expected_interval_sec", 1.0)
        if interval > expected * 3:  # 3x expected interval without a tick
            self.consecutive_stale += 1
            if self.consecutive_stale >= self.stale_threshold:
                self.alert_dispatcher.send_alert(
                    severity="high",
                    message=f"Primary feed appears STALE for {symbol} — no tick received for {interval:.1f}s",
                    context={
                        "symbol": symbol,
                        "last_tick_age_sec": interval,
                        "consecutive_stale_count": self.consecutive_stale,
                    }
                )
        else:
            self.consecutive_stale = 0

    def validate(self, symbol: str) -> list[dict]:
        """
        Compare buffered primary and secondary ticks for a symbol.
        Returns a list of deviation records.
        """
        if symbol not in self.primary_buffer or symbol not in self.secondary_buffer:
            return []

        p_ticks = list(self.primary_buffer[symbol])
        s_ticks = list(self.secondary_buffer[symbol])

        deviations = []

        for p_tick in p_ticks[-10:]:  # Compare last 10 primary ticks
            # Find the nearest secondary tick by timestamp
            s_tick = min(
                s_ticks,
                key=lambda s: abs((s["timestamp"] - p_tick["timestamp"]).total_seconds())
            )

            drift_ms = (s_tick["timestamp"] - p_tick["timestamp"]).total_seconds() * 1000
            drift_ok = abs(drift_ms) <= self.drift_threshold_ms

            price_diff = abs(p_tick["price"] - s_tick["price"]) / s_tick["price"]
            deviation_bps = price_diff * 10000
            price_ok = deviation_bps <= self.deviation_threshold_bps

            if not drift_ok or not price_ok:
                deviation_record = {
                    "symbol": symbol,
                    "timestamp": p_tick["timestamp"].isoformat(),
                    "drift_ms": round(drift_ms, 2),
                    "drift_ok": drift_ok,
                    "price_deviation_bps": round(deviation_bps, 2),
                    "price_ok": price_ok,
                    "primary_price": p_tick["price"],
                    "secondary_price": s_tick["price"],
                }
                deviations.append(deviation_record)

                # Alert on significant deviations
                severity = self._assess_severity(drift_ms, deviation_bps)
                if severity:
                    self.alert_dispatcher.send_alert(
                        severity=severity,
                        message=f"Data quality deviation detected for {symbol}",
                        context=deviation_record
                    )

        return deviations

    def _assess_severity(self, drift_ms: float, deviation_bps: float) -> Optional[str]:
        """Determine alert severity based on deviation magnitude."""
        abs_drift = abs(drift_ms)
        abs_deviation = abs(deviation_bps)

        if abs_drift > self.drift_threshold_ms * 5 or abs_deviation > self.deviation_threshold_bps * 5:
            return "critical"
        elif abs_drift > self.drift_threshold_ms * 3 or abs_deviation > self.deviation_threshold_bps * 3:
            return "high"
        elif abs_drift > self.drift_threshold_ms * 1.5 or abs_deviation > self.deviation_threshold_bps * 1.5:
            return "medium"
        return None

Deployment Configuration Guide

The following table provides recommended configurations by deployment context.

Parameter Individual trader Small team (3–5) Institutional
Drift threshold 1000 ms 500 ms 200 ms
Deviation threshold 15 bps 8 bps 5 bps
Stale tick threshold 10 ticks 5 ticks 3 ticks
Alert channels Email / Slack Slack Slack + PagerDuty
Validation frequency Every 5 seconds Every 2 seconds Every 500 ms
Buffer size 50 ticks 100 ticks 200 ticks
Secondary source TickDB Free tier TickDB Pro TickDB Enterprise

Environment Variable Setup

# Required
export TICKDB_API_KEY="your_tickdb_api_key_here"

# Optional (for alerting)
export SLACK_WEBHOOK_URL="https://hooks.slack.com/services/YOUR/WEBHOOK/URL"
export PAGERDUTY_KEY="your_pagerduty_integration_key"

# Validation parameters
export DRIFT_MS=500
export DEVIATION_BPS=8
export STALE_TICKS=5

Cross-Asset Validation Use Case

Dual-source validation is not limited to single-symbol comparison. A powerful extension is cross-asset divergence detection, where the relationship between related instruments is monitored for breaks.

Example: SPY vs. ES futures correlation monitoring.

def check_cross_asset_correlation(validator: ValidationEngine, symbols: list[str]) -> dict:
    """
    Check if the correlation between related instruments is within expected bounds.
    This catches data errors that affect only one side of a correlated pair.
    """
    if len(symbols) < 2:
        return {}

    p_ticks = {s: list(validator.primary_buffer.get(s, [])) for s in symbols}

    # Ensure we have enough ticks for correlation calculation
    min_ticks = min(len(v) for v in p_ticks.values())
    if min_ticks < 20:
        return {"status": "insufficient_data", "tick_count": min_ticks}

    # Build price series
    price_series = {}
    for symbol, ticks in p_ticks.items():
        price_series[symbol] = [t["price"] for t in ticks[-20:]]

    # Calculate simple correlation between first two symbols
    s1, s2 = symbols[0], symbols[1]
    returns1 = [price_series[s1][i+1] / price_series[s1][i] - 1 for i in range(len(price_series[s1])-1)]
    returns2 = [price_series[s2][i+1] / price_series[s2][i] - 1 for i in range(len(price_series[s2])-1)]

    correlation = sum(r1 * r2 for r1, r2 in zip(returns1, returns2)) / len(returns1)

    # SPY-ES correlation should be > 0.95 in normal conditions
    correlation_threshold = 0.90

    result = {
        "symbols": [s1, s2],
        "correlation": round(correlation, 4),
        "threshold": correlation_threshold,
        "status": "ok" if correlation > correlation_threshold else "alert",
    }

    if result["status"] == "alert":
        validator.alert_dispatcher.send_alert(
            severity="high",
            message=f"Cross-asset correlation breakdown: {s1} vs {s2} = {correlation:.4f}",
            context=result
        )

    return result

Limitations and Known False Positive Scenarios

No validation system is perfect. Understanding where the algorithm produces false positives is as important as understanding where it catches real issues.

Scenario Why it triggers a false positive Mitigation
Different closing auction mechanisms HK and US equities have different auction windows; price can differ by several cents between sources Use only exchange-native timestamps; exclude auction periods from validation window
Pre/post-market price gaps Secondary source may not provide pre-market data; primary does Disable validation outside regular trading hours, or align both feeds to the same session
Corporate action adjustments One source may adjust for splits/dividends; the other may not Subscribe to corporate action feeds; temporarily exclude affected symbols
Decimal vs. fractional pricing Rare, but some legacy feeds use 1/8th dollar notation Normalize all prices to float before comparison
High-volatility intraday spikes During flash crashes, real price divergence can exceed thresholds legitimately Use wider thresholds during volatile periods, or implement a volatility-adjusted threshold

Operational Runbook: Responding to Alerts

When an alert fires, follow this decision tree:

Alert received
    │
    ├── Drift deviation (timestamp drift > threshold)
    │       │
    │       ├── Check primary feed handler status
    │       ├── Check network latency to primary source
    │       ├── If persistent > 2 min → failover to secondary as primary
    │       └── Log incident; review primary feed SLA
    │
    ├── Price deviation (price difference > threshold)
    │       │
    │       ├── Identify which source matches recent prints
    │       ├── Cross-reference with exchange native tape
    │       ├── If primary diverges → flag primary; continue using secondary
    │       └── If both diverge → market event; no action needed
    │
    └── Stale feed (no ticks received)
            │
            ├── Verify TickDB secondary is still connected
            ├── Check network/firewall rules
            ├── If TickDB also stale → exchange-level issue; monitor
            └── If TickDB healthy → primary handler crash; restart primary feed

Conclusion

Data quality is not a solved problem. Even the most reliable market data providers experience outages, latency drift, and data gaps. The $2.3 million loss scenario described at the opening of this article was preventable — not with a better primary provider, but with an architecture that assumed failure and monitored for it.

Dual-source cross-validation with TickDB as the secondary feed provides:

  • Sub-second anomaly detection across timestamp drift, price deviation, and sequence continuity
  • Production-grade infrastructure with heartbeat, exponential backoff, and rate-limit handling built in
  • Configurable severity tiers that match alert urgency to deviation magnitude
  • Cross-asset correlation monitoring to catch data errors that affect only one side of a correlated pair

The architecture scales from individual traders monitoring a handful of symbols to institutional teams running continuous validation across hundreds of instruments.


Next Steps

If you're an individual quant trader, start with the shadow-mode validation run: collect deviation statistics for 5 days before enabling alerts. This prevents alert fatigue and lets you calibrate thresholds to your specific symbols.

If you want to implement this today:

  1. Sign up at tickdb.ai (free tier available; no credit card required)
  2. Generate an API key in the dashboard
  3. Set the TICKDB_API_KEY environment variable
  4. Copy the code from this article and configure your threshold parameters
  5. Run in shadow mode for 5 trading days; review deviation logs

If you need institutional-grade infrastructure with dedicated support, SLA guarantees, and extended symbol coverage, reach out to enterprise@tickdb.ai for custom plans.

If you use AI coding assistants, search for and install the tickdb-market-data SKILL in your AI tool's marketplace for integrated TickDB API access within your development workflow.


This article does not constitute investment advice. Market data systems involve operational complexity; thorough testing in paper trading environments is recommended before production deployment.