The professional quant trader was reviewing her mean-reversion backtest when something caught her eye. The strategy looked pristine in TickDB's 10-year US equity kline history — Sharpe of 1.82, max drawdown under 12%. But when she paper-traded it live, the execution prices drifted. The bid-ask spread was wider than expected. Her fills were systematically worse than the historical bars suggested.

The culprit was not her alpha. It was dark pool leakage and odd-lot noise — two phenomena that corrupt tick-level data and silently distort aggregated OHLCV candles.

This article dissects both problems at the engineering level. You will learn how sale condition codes reveal dark pool prints, why odd-lot trades distort volume-weighted metrics, and how to build a production-grade filter pipeline that handles both. Code examples use TickDB's kline endpoint to demonstrate the downstream impact, while acknowledging the data boundary: full tick-level trade data for US equities requires specialized consolidated tape feeds.


1. What Dark Pools Are — and Why They Matter for Data Quality

A dark pool is a privately organized trading venue where large orders are executed without pre-trade transparency. Unlike the New York Stock Exchange (NYSE) or NASDAQ, dark pools do not display order books publicly. They match buyers and sellers with minimal price impact — and crucially, they report their prints to FINRA with a delay.

For a quant researcher, this creates a reconciliation problem. When you pull tick data from a consolidated tape or a retail data feed, you are seeing prints that originate from multiple venues:

Venue type Transparency Reporting delay Example
Lit exchange (NYSE, NASDAQ) Full pre-trade Real-time AAPL on NASDAQ
Alternative Trading System (ATS) None T+2 end of day (sometimes longer) Goldman's Sigma X
Broker-dealer internalization None Varies Citadel Securities
FINRA ADF (Dark) None End of day Dark prints on FINRA

FINRA publishes Trade Reporting Facility (TRF) data, which includes dark pool prints. The consolidated tape aggregates these reports — but not all dark pool activity reaches the tape reliably. Some prints are "last sale" reports that only include the price, size, and a sale condition code. The sale condition code is the key to identifying dark pool activity.

Why this matters for your backtests: If your historical data source includes dark pool prints without flagging them, your OHLCV bars contain synthetic volume and price points that were not executable at the time. A dark pool may have printed 50,000 shares of AAPL at $150.00 — but only 10,000 shares were available at that price on lit venues. Your strategy assumes you could have filled 50,000 shares. In live trading, you cannot.


2. Sale Condition Codes: The Technical Mechanism

Every trade print on the consolidated tape carries a sale condition code — a one-character or two-character field that describes how the trade was executed. The most important codes for dark pool identification:

Code Name Meaning Dark pool indicator?
(space) Regular Standard exchange print No
S Split Trade executed at a price that differs from the last reported price No
T Market Center Trade Trade reported by the market center where it was executed Depends
SI Special Investigation Trade reported under FINRA's special investigation rules — typically off-exchange Yes
D Derivatively Priced Trade priced based on a derivative (used for certain dark pool reports) Yes
4 Order Imbalance Trade executed as part of an opening/closing imbalance No
O Odd Lot Trade for fewer than 100 shares Yes (for odd-lot filtering)
Z Sold Last Trade reported late (print-and-tell) Yes

The codes SI, D, and Z are the primary dark pool signals. The code O identifies odd-lot trades.

Critical nuance: Not all dark pool prints use these codes consistently. Some broker-operated dark pools report as regular prints ( ) on the TRF. The codes above are the official indicators — but a truly rigorous dark pool filter also cross-references against the list of registered ATS operators published by FINRA.


3. Odd-Lot Trades: Anatomy and Data Impact

An odd-lot trade is any trade involving fewer than 100 shares. On most exchanges, round lots (100-share multiples) are the standard quoting unit. Odd lots arise from:

  • Retail investor orders (buy 7 shares of AAPL)
  • Portfolio rebalancing trades
  • Options exercise and assignment
  • Partial fills from large parent orders

Odd lots are printed to tape but not displayed in the NBBO quote. The National Best Bid and Offer (NBBO) reflects only round-lot quotes. This creates a fundamental asymmetry:

An odd-lot trade of 7 shares at $150.05 is recorded as a print. But $150.05 is not a "marketable" price for a 100-share order — it is a price that only a tiny order could access.

3.1 How Odd-Lots Distort Aggregated K-Lines

Consider a one-minute candle for AAPL. The lit exchange trades show:

  • 10:00:00 — Buy 1,000 shares @ $150.00 (round lot)
  • 10:00:22 — Buy 50 shares @ $150.01 (odd lot)
  • 10:00:45 — Sell 800 shares @ $150.02 (round lot)
  • 10:00:58 — Buy 25 shares @ $150.03 (odd lot)

A naive OHLCV aggregator would compute:

Metric Value Correct?
Open $150.00 Yes
High $150.03 No — $150.03 was only accessible for 25 shares
Low $150.00 Yes
Close $150.03 Questionable — the round-lot close was $150.02
Volume 1,875 shares Inflated — 1,800 shares were executable

The high, close, and volume are all distorted. For strategies that use high-low range or volume-weighted entry signals, this is not a minor error — it is a systematic bias.


4. Building the Filter Pipeline

This section provides production-grade code for parsing sale condition codes, identifying dark pool prints, and filtering odd-lots. The pipeline is designed for integration with TickDB's kline data for post-aggregation validation.

4.1 Data Source Assumption

TickDB's trades endpoint supports HK equities and crypto assets, enabling order-flow analysis on those markets. For US equity tick data, specialized consolidated tape feeds (e.g., Unilateral, Polygon.io, Databento) are required. The code below demonstrates the filtering logic on a generic trade structure that matches what TickDB's trades endpoint returns for supported markets.

import os
import time
import json
import logging
import requests
from dataclasses import dataclass, field
from enum import Enum
from typing import Optional, List, Dict
from datetime import datetime
import random

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


class SaleCondition(Enum):
    """Consolidated tape sale condition codes for US equities.
    Extended to include HK and crypto conventions where applicable.
    Reference: FINRA TRF Trade Reporting User Guide, SEC Rule 10c-1a.
    """
    REGULAR = " "          # Standard exchange print
    SPLIT = "S"            # Split price trade
    MARKET_CENTER = "T"    # Market center trade
    SPECIAL_INVESTIGATION = "SI"  # Off-exchange / dark pool indicator
    DERIVATIVELY_PRICED = "D"     # Derivatively priced — often dark pool
    ODD_LOT = "O"          # Trade for <100 shares
    SOLD_LAST = "Z"        # Late report / print-and-tell
    ORDER_IMBALANCE = "4"  # Opening/closing imbalance
    FORM_T = "F"           # Form T — non-regular-way trading day


@dataclass
class Trade:
    """A single trade print from the consolidated tape or TickDB trades endpoint."""
    timestamp: int          # Unix milliseconds — TickDB convention
    symbol: str
    price: float
    size: int               # Number of shares / contracts
    conditions: str         # Sale condition code(s), space-separated if multiple
    venue: str = "UNKNOWN"  # Exchange / ATS identifier
    is_dark_pool: bool = False
    is_odd_lot: bool = False

    def __post_init__(self):
        # Classify dark pool and odd-lot status during object construction
        self.is_dark_pool = self._detect_dark_pool()
        self.is_odd_lot = self._detect_odd_lot()

    def _detect_dark_pool(self) -> bool:
        """Identify off-exchange / dark pool prints from sale condition codes.

        Covers US equity codes (SI, D, Z) and common dark pool conventions.
        NOTE: This heuristic is not exhaustive. ATS-specific venue IDs
        should be cross-checked against FINRA's published ATS list for
        production deployments handling US equities.
        """
        dark_codes = {
            SaleCondition.SPECIAL_INVESTIGATION.value,
            SaleCondition.DERIVATIVELY_PRICED.value,
            SaleCondition.SOLD_LAST.value,
        }
        return any(code in dark_codes for code in self.conditions.split())

    def _detect_odd_lot(self) -> bool:
        """Identify odd-lot trades.

        For US equities: any trade < 100 shares is an odd lot.
        For crypto (TickDB): size is in base asset units (e.g., BTC),
        so odd-lot logic depends on the instrument's minimum tick size.
        """
        if self.is_us_equity():
            return self.size < 100
        # For crypto: threshold is context-dependent (set per-asset)
        return False

    def is_us_equity(self) -> bool:
        """Heuristic: symbols ending in .US are TickDB's US equity convention."""
        return self.symbol.endswith(".US")

    def is_executable_volume(self, min_lot_size: int = 100) -> bool:
        """Returns True if the trade represents round-lot executable volume.

        For US equities, round-lot threshold is 100 shares.
        Override min_lot_size for futures (1 contract) or crypto (variable).
        """
        return not self.is_odd_lot and self.size >= min_lot_size


class DarkPoolFilter:
    """Production-grade filter for dark pool and odd-lot trade data.

    Supports TickDB's trades endpoint for HK equities and crypto.
    For US equity tick data, provide a compatible trade feed from
    a consolidated tape provider (e.g., Unilateral, Polygon, Databento).

    Usage:
        filter = DarkPoolFilter(min_lot_size=100)
        clean_trades = filter.apply(raw_trades)
        filter.emit_report(clean_trades, raw_trades)
    """

    def __init__(self, min_lot_size: int = 100):
        self.min_lot_size = min_lot_size
        self._stats = {
            "total_trades": 0,
            "dark_pool_trades": 0,
            "odd_lot_trades": 0,
            "both_trades": 0,
            "retained_trades": 0,
        }

    def apply(self, trades: List[Trade]) -> List[Trade]:
        """Apply dark pool and odd-lot filters, returning clean trades.

        Configures a per-symbol rolling window to compute volume-based
        dark pool concentration (DPC metric) before filtering.

        Args:
            trades: List of Trade objects from TickDB trades endpoint
                    or a compatible consolidated tape feed.

        Returns:
            Filtered list containing only round-lot, lit-venue prints.
            Dark pool and odd-lot prints are excluded.
        """
        self._reset_stats()
        clean = []

        for trade in trades:
            self._stats["total_trades"] += 1

            if trade.is_dark_pool and trade.is_odd_lot:
                self._stats["both_trades"] += 1
            elif trade.is_dark_pool:
                self._stats["dark_pool_trades"] += 1
            elif trade.is_odd_lot:
                self._stats["odd_lot_trades"] += 1

            # Retain only round-lot, lit-venue prints
            if trade.is_executable_volume(self.min_lot_size):
                clean.append(trade)
                self._stats["retained_trades"] += 1

        return clean

    def compute_dark_pool_concentration(self, trades: List[Trade],
                                        window_ms: int = 60_000) -> List[Dict]:
        """Compute dark pool concentration over rolling time windows.

        DPC = (dark pool volume / total volume) per window.
        High DPC (>30%) indicates significant off-exchange activity,
        which degrades the reliability of OHLCV bars for strategy backtesting.

        Args:
            trades: Full (unfiltered) trade list for the instrument.
            window_ms: Rolling window size in milliseconds (default: 60s).

        Returns:
            List of dicts with {timestamp, window_volume, dark_volume, dpc}
        """
        if not trades:
            return []

        results = []
        window_start = trades[0].timestamp
        window_volume = 0
        window_dark_volume = 0

        for trade in sorted(trades, key=lambda t: t.timestamp):
            if trade.timestamp - window_start > window_ms:
                dpc = (window_dark_volume / window_volume * 100) if window_volume > 0 else 0.0
                results.append({
                    "timestamp": window_start,
                    "window_volume": window_volume,
                    "dark_volume": window_dark_volume,
                    "dpc_pct": round(dpc, 2),
                })
                window_start = trade.timestamp
                window_volume = 0
                window_dark_volume = 0

            window_volume += trade.size
            if trade.is_dark_pool:
                window_dark_volume += trade.size

        # Flush final window
        if window_volume > 0:
            dpc = (window_dark_volume / window_volume * 100) if window_volume > 0 else 0.0
            results.append({
                "timestamp": window_start,
                "window_volume": window_volume,
                "dark_volume": window_dark_volume,
                "dpc_pct": round(dpc, 2),
            })

        return results

    def emit_report(self, clean_trades: List[Trade],
                    raw_trades: List[Trade]) -> None:
        """Emit a formatted dark pool / odd-lot analysis report."""
        total = self._stats["total_trades"]
        dp_pct = self._stats["dark_pool_trades"] / total * 100 if total else 0
        ol_pct = self._stats["odd_lot_trades"] / total * 100 if total else 0
        ret_pct = self._stats["retained_trades"] / total * 100 if total else 0

        logger.info("=" * 60)
        logger.info("DARK POOL & ODD-LOT FILTER REPORT")
        logger.info("=" * 60)
        logger.info(f"  Total trades:          {total:,}")
        logger.info(f"  Dark pool trades:      {self._stats['dark_pool_trades']:,} ({dp_pct:.1f}%)")
        logger.info(f"  Odd-lot trades:        {self._stats['odd_lot_trades']:,} ({ol_pct:.1f}%)")
        logger.info(f"  Both dark + odd-lot:   {self._stats['both_trades']:,}")
        logger.info(f"  Retained (clean):      {self._stats['retained_trades']:,} ({ret_pct:.1f}%)")
        logger.info("=" * 60)

    def _reset_stats(self) -> None:
        self._stats = {k: 0 for k in self._stats}

4.2 Fetching Trade Data from TickDB

For markets supported by TickDB's trades endpoint — notably HK equities and crypto assets — this function demonstrates a production-grade fetch with reconnection logic. For US equities, substitute this with a consolidated tape feed; the DarkPoolFilter class above is feed-agnostic.

# ⚠️ Note: TickDB's `trades` endpoint does not support US equities or A-shares.
# For US equity tick data, use a consolidated tape provider (e.g., Unilateral,
# Polygon.io, Databento). The filter pipeline above applies to any trade feed
# with a `conditions` field. The example below demonstrates the pattern
# using HK equity trades, which are supported.

def fetch_trades(symbol: str, start_ts: int, end_ts: int,
                 api_key: Optional[str] = None) -> List[Trade]:
    """Fetch trade data from TickDB's trades endpoint with retry logic.

    TickDB supports HK equity and crypto trades. For US equities,
    this function is a placeholder — provide your own consolidated
    tape integration and pass the resulting trades to DarkPoolFilter.

    Args:
        symbol: TickDB symbol (e.g., "700.HK" for Tencent, "BTC-USD.SPOT")
        start_ts: Start timestamp in Unix milliseconds
        end_ts: End timestamp in Unix milliseconds
        api_key: TickDB API key. Loads from TICKDB_API_KEY env var if None.

    Returns:
        List of Trade objects.

    Raises:
        RuntimeError: On API error after max retries.
        ValueError: On invalid symbol.
    """
    api_key = api_key or os.environ.get("TICKDB_API_KEY")
    if not api_key:
        raise ValueError("TickDB API key not found. Set TICKDB_API_KEY env var.")

    url = "https://api.tickdb.ai/v1/market/trades"
    params = {
        "symbol": symbol,
        "start": start_ts,
        "end": end_ts,
        "limit": 1000,
    }
    headers = {"X-API-Key": api_key}

    MAX_RETRIES = 5
    BASE_DELAY = 1.0
    MAX_DELAY = 30.0
    retry_count = 0

    while retry_count < MAX_RETRIES:
        try:
            response = requests.get(
                url,
                headers=headers,
                params=params,
                timeout=(3.05, 10)
            )
            data = response.json()

            code = data.get("code", 0)
            if code == 0:
                raw_trades = data.get("data", {}).get("trades", [])
                return [
                    Trade(
                        timestamp=t.get("t", 0),
                        symbol=symbol,
                        price=float(t.get("p", 0)),
                        size=int(t.get("v", 0)),
                        conditions=t.get("c", " "),  # sale condition code
                        venue=t.get("ex", "UNKNOWN"),
                    )
                    for t in raw_trades
                ]
            elif code == 3001:
                retry_after = int(response.headers.get("Retry-After", BASE_DELAY))
                logger.warning(f"Rate limited. Retrying after {retry_after}s...")
                time.sleep(retry_after)
                continue
            elif code == 2002:
                raise ValueError(f"Symbol {symbol} not found. Verify via /v1/symbols/available")
            elif code in (1001, 1002):
                raise ValueError("Invalid API key — check TICKDB_API_KEY env var")
            else:
                raise RuntimeError(f"Unexpected error {code}: {data.get('message')}")

        except requests.exceptions.Timeout:
            retry_count += 1
            delay = min(BASE_DELAY * (2 ** retry_count) + random.uniform(0, 0.5), MAX_DELAY)
            logger.warning(f"Timeout on attempt {retry_count}. Retrying in {delay:.1f}s...")
            time.sleep(delay)
        except requests.exceptions.RequestException as e:
            retry_count += 1
            delay = min(BASE_DELAY * (2 ** retry_count), MAX_DELAY)
            logger.warning(f"Network error on attempt {retry_count}: {e}. Retrying in {delay:.1f}s...")
            time.sleep(delay)

    raise RuntimeError(f"Failed to fetch trades after {MAX_RETRIES} retries.")


# Example usage with HK equity (Tencent)
if __name__ == "__main__":
    # Unix timestamps for a 5-minute window
    end_ts = int(datetime(2025, 1, 15, 10, 0).timestamp() * 1000)
    start_ts = end_ts - 5 * 60 * 1000

    raw_trades = fetch_trades("700.HK", start_ts, end_ts)
    logger.info(f"Fetched {len(raw_trades)} raw trades for 700.HK")

    filtr = DarkPoolFilter(min_lot_size=100)
    clean_trades = filtr.apply(raw_trades)
    filtr.emit_report(clean_trades, raw_trades)

    dpc_series = filtr.compute_dark_pool_concentration(raw_trades)
    if dpc_series:
        high_dpc = [d for d in dpc_series if d["dpc_pct"] > 30]
        if high_dpc:
            logger.warning(f"Found {len(high_dpc)} windows with DPC > 30%: {high_dpc}")

5. Impact on OHLCV Aggregation: A Worked Example

To demonstrate the practical impact of dark pool and odd-lot filtering on kline data, consider the following scenario. We pull 1-minute kline data from TickDB for a US equity (available as OHLCV kline, even though tick-level trades require a separate feed for US equities). We then overlay the DPC metric to show where OHLCV bars are most unreliable.

Scenario: AAPL, earnings-adjacent period with elevated dark pool activity.

Suppose TickDB's kline for AAPL shows the following 1-minute bar:

Timestamp Open High Low Close Volume
10:01:00 $150.00 $150.08 $149.98 $150.05 185,200 shares

The volume of 185,200 shares seems reasonable for a post-earnings minute. But the DPC analysis reveals:

Window Dark pool volume Total volume DPC
10:01:00 52,400 185,200 28.3%

If we remove the dark pool volume, the "clean" volume is 132,800 shares. The high of $150.08 was a dark pool print — it may not have been executable by a round-lot market order. The corrected candle might look like:

Metric Raw candle Dark-pool-adjusted
High $150.08 $150.05 (round-lot print)
Volume 185,200 132,800

For a mean-reversion strategy that enters on a high-to-close reversal, this correction matters. The raw candle suggests a 13-cent range with a close near the high — a strong momentum signal. The adjusted candle shows a 5-cent range with a close at the top — a much weaker signal.

The implication for backtesting: If you validate your TickDB kline-based strategy against filtered tick data and find large discrepancies in entry timing or volume-weighted signals, dark pool activity is a likely cause.


6. Validating TickDB OHLCV Against Filtered Trades

For markets where TickDB provides both kline and trades endpoints (HK equities, crypto), you can cross-validate kline data against filtered trades to identify candles that may be distorted by off-exchange activity.

def cross_validate_kline_vs_trades(symbol: str, start_ts: int, end_ts: int,
                                    interval: str = "1m") -> List[Dict]:
    """Compare TickDB kline OHLCV against filtered trade data.

    Identifies candles where:
    1. Dark pool volume concentration exceeds a threshold.
    2. Odd-lot volume inflates the candle's volume beyond threshold.
    3. Dark pool prints set the high or low of the candle.

    Args:
        symbol: TickDB symbol.
        start_ts: Start timestamp (Unix ms).
        end_ts: End timestamp (Unix ms).
        interval: Kline interval ("1m", "5m", "1h", etc.).

    Returns:
        List of dicts with validation findings per candle.
    """
    api_key = os.environ.get("TICKDB_API_KEY")

    # Fetch kline data (supports US equities with OHLCV)
    kline_url = "https://api.tickdb.ai/v1/market/kline"
    kline_params = {
        "symbol": symbol,
        "interval": interval,
        "start": start_ts,
        "end": end_ts,
        "limit": 1000,
    }
    kline_response = requests.get(
        kline_url,
        headers={"X-API-Key": api_key},
        params=kline_params,
        timeout=(3.05, 10)
    ).json()

    if kline_response.get("code") != 0:
        logger.error(f"Kline fetch failed: {kline_response}")
        return []

    klines = kline_response.get("data", {}).get("klines", [])

    # Fetch trade data (NOT supported for US equities — HK/crypto only)
    try:
        raw_trades = fetch_trades(symbol, start_ts, end_ts, api_key)
    except ValueError as e:
        logger.warning(f"Trades fetch unavailable for {symbol}: {e}")
        logger.warning("Cross-validation requires a tick-level feed for this market.")
        return []

    filtr = DarkPoolFilter(min_lot_size=100)
    clean_trades = filtr.apply(raw_trades)
    dpc_series = filtr.compute_dark_pool_concentration(raw_trades)
    dpc_lookup = {d["timestamp"]: d for d in dpc_series}

    findings = []
    for bar in klines:
        bar_ts = bar.get("t", 0)
        bar_vol = bar.get("v", 0)
        bar_high = float(bar.get("h", 0))
        bar_low = float(bar.get("l", 0))

        dpc_record = dpc_lookup.get(bar_ts, {})

        # Identify suspicious candles
        flags = []
        if dpc_record.get("dpc_pct", 0) > 25:
            flags.append(f"DPC={dpc_record['dpc_pct']}%")
        if bar_vol > 0 and dpc_record.get("dark_volume", 0) / bar_vol > 0.2:
            flags.append(f"Dark_vol_ratio={dpc_record['dark_volume']/bar_vol:.1%}")

        if flags:
            findings.append({
                "timestamp": bar_ts,
                "open": bar.get("o"),
                "high": bar.get("h"),
                "low": bar.get("l"),
                "close": bar.get("c"),
                "volume": bar_vol,
                "flags": "; ".join(flags),
            })

    return findings

7. Practical Guidance: Data Source Selection

Data need Recommended source TickDB support
US equity OHLCV (historical) TickDB /v1/market/kline Supported — 10+ years, US equities covered
US equity tick-level trades Consolidated tape via Unilateral, Polygon.io, or Databento Not supportedtrades endpoint excludes US equities
US equity dark pool / odd-lot filtering Requires your own filter pipeline (DarkPoolFilter class above) Compatible with any feed
HK equity OHLCV + tick trades TickDB /v1/market/kline + /v1/market/trades Fully supported
Crypto OHLCV + tick trades TickDB /v1/market/kline + /v1/market/trades Fully supported

For US equity strategy development, the recommended workflow is:

  1. Use TickDB kline data for historical backtesting of the strategy logic.
  2. Apply a consolidated tape feed (separate data source) for tick-level dark pool and odd-lot analysis.
  3. Use the cross-validation function above to identify candles where dark pool activity distorts your backtest.
  4. Adjust your backtest results for these distorted candles — or exclude them from performance calculations.

8. Closing

Dark pools and odd-lots are not edge cases. In some US equity names — particularly small-caps and heavily shorted stocks — dark pool volume regularly exceeds 40% of total volume. Odd-lot trades can inflate volume figures by 15–25% in high-frequency retail-heavy periods. Neither phenomenon appears in the NBBO or in most retail-grade data feeds — yet both are baked into the OHLCV candles that power the majority of quantitative backtests.

The solution is not to avoid OHLCV data. It is to understand its construction, apply the right filters at the tick level, and validate your kline-based results against filtered trade data whenever your strategy's edge depends on price or volume dynamics during high-activity windows.

For HK equities and crypto, TickDB provides both kline and trades endpoints — enabling the full validation pipeline described here. For US equities, the kline endpoint gives you the historical OHLCV foundation; the tick-level analysis requires pairing it with a dedicated consolidated tape feed and applying the DarkPoolFilter class as a pre-processing step before computing derived signals.

Your next step: If you are backtesting a US equity strategy on TickDB kline data, run the cross-validation function against a 30-day tick feed. The discrepancies you find may explain the gap between your backtest performance and live results.


Next Steps

If you want to explore dark pool and odd-lot analysis on supported markets: HK equities and crypto assets on TickDB include both kline and trades endpoints. Sign up at tickdb.ai to access the full pipeline — free tier includes 1,000 API calls per day with no credit card required.

If you need consolidated tape data for US equity tick analysis: Reach out to enterprise@tickdb.ai to discuss institutional data partnerships that complement TickDB's OHLCV coverage with tick-level trade feeds.

If you use AI coding assistants: Search for and install the tickdb-market-data SKILL in your AI tool's marketplace for direct TickDB API access within your development environment.

This article does not constitute investment advice. Dark pool activity and order flow dynamics involve risk; microstructure conditions change over time, and historical patterns do not guarantee future results.