"Every market data platform has a ceiling. The question is whether that ceiling matches your strategy."

That line is from a conversation with a quant researcher who spent three weeks building a tick-level order flow strategy before discovering his vendor of choice didn't support US equity trades. He switched platforms, lost momentum, and restarted his backtesting pipeline from scratch. His words captured the core frustration: product boundary confusion is not a documentation problem. It is a strategic betrayal.

This article exists to prevent that betrayal. If you are evaluating TickDB for US equity strategies, you deserve a clear, honest explanation of where TickDB's capabilities end — and where they begin. No marketing gloss. No vague assurances. Just the technical reality.


The Question Everyone Asks

Before we answer "why," we need to establish "what."

What does TickDB not support for US equities?

TickDB does not provide tick-level trade data (trades endpoint) for US stocks. The /v1/market/trades endpoint covers HK equities and crypto assets, but it explicitly excludes US equities and A-shares.

This means if your strategy requires individual trade prints — the raw sequence of transactions that power order flow analysis, transaction cost analysis, and microstructure signal research — TickDB is not your platform.

That is a fact. Here is the context behind it.


Why TickDB Made This Choice

The Economics of US Equity Data

US equity market data is expensive. Not "moderately priced" expensive. Fundamentally, structurally expensive.

The primary consolidated tape for US equities — operated by the Financial Industry Regulatory Authority (FINRA) via the Securities Information Processor (SIP) — does not distribute raw tick data for free. The SIP provides NBBO (National Best Bid and Offer) quotes and last-sale data, but at aggregated levels and with latency. Raw trade-by-trade data with full tape attribution (which exchange reported the trade, what was the condition code, was it a print or a correction) requires direct licensing from exchanges.

There are 16 registered exchanges for US equities. Each charges licensing fees for their proprietary data feeds. The CTA and UTP plans add additional costs. A platform ingesting full US equity tick data at exchange-level granularity faces licensing fees that scale into six figures annually before a single line of server code is written.

TickDB's product decision was not a failure of engineering will. It was a recognition that the unit economics of US equity tick data do not align with a developer-friendly, subscription-priced API. The moment TickDB tried to offer "cheap US tick data," it would either be operating at a loss or subsidizing one market segment at the expense of others.

Product Focus: What TickDB Actually Built

TickDB chose to be the best at what it could be the best at.

The decision to focus on cleaned, aligned, long-horizon OHLCV (kline) data was a deliberate strategic pivot. The /v1/market/kline endpoint provides 10+ years of hourly and daily bar data for US equities — data that is suitable for cross-cycle strategy backtesting, factor research, and regime analysis.

This is not a consolation prize. It is a different product.

Data Type US Equities (TickDB) US Equities (Competitors)
Tick-level trades ❌ Not supported ✅ Full tape access
Order book depth L1 (best bid/ask) L2/L3 in some cases
OHLCV kline data ✅ 10+ years, cleaned ✅ Available, varies by vendor
Historical latency <100 ms (WebSocket) Polling: 1–5 sec
Cross-asset coverage 6 asset classes, single API Requires multiple vendors

The OHLCV data that TickDB does provide is not "basic" or "inferior" for the use cases it serves. Cross-cycle backtesting, factor portfolio construction, and regime detection do not require tick-level granularity. What they require is long-horizon data integrity — clean pricing, proper dividend adjustments, split handling, and aligned timestamps across symbols.

TickDB invested in that pipeline. It did not invest in the raw tape ingestion infrastructure required for tick data.


What You Actually Get: US Equity Capabilities

Let us be precise about what TickDB does support for US equities, because the boundary is narrower than some users assume — but not as limiting as they fear.

Supported Capabilities

1. OHLCV Kline Data (10+ Years)

The /v1/market/kline endpoint provides historical candlestick data going back 10+ years for major US equity symbols. This includes adjusted close prices that account for splits and dividends, proper alignment across the symbol universe, and multiple interval options (1m, 5m, 15m, 30m, 1h, 4h, 1d, 1w).

2. L1 Order Book Depth

TickDB provides real-time best bid and best ask for US equities via the /v1/market/depth endpoint. This is Level 1 data — the top of the book only. It does not include queue position, hidden orders, or deep book levels. For strategies that need bid/ask spread dynamics and pressure ratios at the top level, this is sufficient. For strategies requiring deep book reconstruction or queue modeling, it is not.

3. Real-Time WebSocket Streaming

Both kline and depth data are available via WebSocket push with sub-100ms latency. The implementation includes native ping/pong heartbeat support, automatic reconnection with exponential backoff, and rate-limit handling per the standard error code schema.

4. Cross-Asset Unified API

A single API covers US equities, HK equities, crypto, forex, precious metals, and indices. For users building multi-asset strategies, this eliminates the multi-vendor complexity that dominates enterprise data stacks.

Unsupported Capabilities

Feature Status Notes
Tick-level trades ❌ Not supported trades endpoint excludes US equities
L2/L3 order book ❌ Not supported US depth limited to L1
Exchange attribution ❌ Not available Which exchange reported a print
FINRA CAT ❌ Not accessible Consolidated audit trail data
Short interest ❌ Not provided Separate data source required
Options chain ❌ Not provided Separate vendor required

The Practical Implication: Strategy Design Constraints

Understanding product boundaries is not an academic exercise. It directly shapes which strategies you can run and which you cannot.

Strategies That Work Well on TickDB

Long-horizon systematic strategies — Factor portfolios, cross-sectional momentum, mean reversion over daily bars, macro regime rotation. These strategies need long data histories, not tick granularity. TickDB's 10+ year kline dataset is purpose-built for this.

Event-driven strategies with OHLCV context — Earnings surprise analysis, macro announcement response, sector rotation. You can construct event windows from kline data and overlay microstructure reasoning from L1 depth.

Multi-asset portfolio construction — Building diversified portfolios across equities, crypto, and forex with a single data API. TickDB's cross-asset coverage simplifies the infrastructure.

Automated trading with L1 depth signals — Strategies that react to bid/ask pressure at the top of book, spread widening, or depth imbalance. L1 data captures these signals adequately for many algorithmic approaches.

Strategies That Require Tick Data (and Cannot Run on TickDB)

Order flow analysis — Buy/sell ratio calculations from individual prints, volume-weighted average price (VWAP) participation analysis, transaction cost analysis (TCA) at the print level.

Market maker strategies — Real-time quote management requiring knowledge of printed volume, trade direction, and exchange attribution to manage inventory risk.

Latency-sensitive microstructure arbitrage — Strategies that exploit quote fade, stale quote detection, or cross-exchange arbitrage requiring sub-second print visibility.

High-frequency statistical arbitrage — Strategies that depend on covariance matrices estimated from intraday tick data or short-window microstructure signals.

If your strategy falls into the second category, you need a different vendor. That is not a failure of TickDB — it is a mismatch of product and use case. Choosing the right tool is part of quant engineering.


Code Example: What TickDB Actually Provides

Here is a production-grade example demonstrating how to access the data that TickDB does provide for US equities — the /v1/market/kline and /v1/market/depth endpoints. This code follows the production-grade standards: heartbeat, exponential backoff with jitter, rate-limit handling, timeout enforcement, and environment-variable authentication.

Fetching 10 Years of US Equity OHLCV Data

import os
import time
import requests
import random
from datetime import datetime, timedelta

class TickDBKlineClient:
    """Production-grade client for TickDB kline endpoint."""
    
    def __init__(self, api_key: str = None):
        self.api_key = api_key or os.environ.get("TICKDB_API_KEY")
        if not self.api_key:
            raise ValueError("TICKDB_API_KEY environment variable is required")
        self.base_url = "https://api.tickdb.ai/v1/market/kline"
        self.max_retries = 5
        self.base_delay = 1.0
        self.max_delay = 32.0
        self.request_timeout = (3.05, 30)  # Connect timeout, read timeout
    
    def _handle_api_error(self, response, retry_count: int):
        """Standard TickDB error handler per handbook error code reference."""
        data = response.json() if response.headers.get("content-type", "").startswith("application/json") else {}
        code = data.get("code", 0)
        
        if code == 0:
            return response  # Success
        
        if code in (1001, 1002):
            raise ValueError("Invalid API key — check your TICKDB_API_KEY env var")
        
        if code == 2002:
            raise KeyError(f"Symbol not found — verify via /v1/symbols/available")
        
        if code == 3001:
            # Rate limit: respect Retry-After header
            retry_after = int(response.headers.get("Retry-After", 5))
            print(f"Rate limited. Waiting {retry_after}s before retry.")
            time.sleep(retry_after)
            return None
        
        raise RuntimeError(f"Unexpected error {code}: {data.get('message')}")
    
    def _request_with_backoff(self, method: str, url: str, **kwargs) -> requests.Response:
        """Exponential backoff with jitter for production resilience."""
        kwargs.setdefault("timeout", self.request_timeout)
        kwargs.setdefault("headers", {})
        kwargs["headers"]["X-API-Key"] = self.api_key
        
        for attempt in range(self.max_retries):
            try:
                response = requests.request(method, url, **kwargs)
                
                if response.status_code == 429:
                    retry_after = int(response.headers.get("Retry-After", 5))
                    delay = retry_after
                else:
                    error_handled = self._handle_api_error(response, attempt)
                    if error_handled is None:
                        delay = min(self.base_delay * (2 ** attempt), self.max_delay)
                    else:
                        return response
                
                # Apply exponential backoff with jitter
                if attempt < self.max_retries - 1:
                    jitter = random.uniform(0, delay * 0.1)
                    sleep_time = min(delay + jitter, self.max_delay)
                    print(f"Retry {attempt + 1}/{self.max_retries} in {sleep_time:.2f}s")
                    time.sleep(sleep_time)
                    delay *= 2
                    
            except requests.exceptions.Timeout:
                if attempt == self.max_retries - 1:
                    raise
                delay = min(self.base_delay * (2 ** attempt), self.max_delay)
                time.sleep(delay)
        
        raise RuntimeError(f"Failed after {self.max_retries} attempts")
    
    def fetch_historical_bars(
        self,
        symbol: str,
        interval: str = "1d",
        start_time: int = None,
        end_time: int = None,
        limit: int = 1000
    ) -> list:
        """
        Fetch historical OHLCV bars for US equity symbol.
        
        Parameters:
            symbol: Ticker symbol with exchange suffix (e.g., "AAPL.US")
            interval: Candle interval ("1m", "5m", "15m", "30m", "1h", "4h", "1d", "1w")
            start_time: Unix timestamp (ms) for period start
            end_time: Unix timestamp (ms) for period end
            limit: Maximum bars returned (max 1000 per request)
        
        Returns:
            List of OHLCV bars with timestamp, open, high, low, close, volume
        """
        params = {
            "symbol": symbol,
            "interval": interval,
            "limit": limit
        }
        
        if start_time:
            params["start"] = start_time
        if end_time:
            params["end"] = end_time
        
        response = self._request_with_backoff("GET", self.base_url, params=params)
        data = response.json()
        
        if data.get("code") != 0:
            raise RuntimeError(f"API error {data.get('code')}: {data.get('message')}")
        
        return data.get("data", [])


# Usage example: fetch 10 years of daily bars for AAPL
if __name__ == "__main__":
    client = TickDBKlineClient()
    
    # Calculate start time: 10 years ago
    end_ts = int(datetime.now().timestamp() * 1000)
    start_ts = int((datetime.now() - timedelta(days=365 * 10)).timestamp() * 1000)
    
    # Fetch in batches (max 1000 per request)
    all_bars = []
    current_end = end_ts
    
    while current_end > start_ts:
        batch = client.fetch_historical_bars(
            symbol="AAPL.US",
            interval="1d",
            start_time=start_ts,
            end_time=current_end,
            limit=1000
        )
        
        if not batch:
            break
            
        all_bars.extend(batch)
        # Move the end cursor to the earliest timestamp in this batch
        current_end = batch[-1]["t"]  # 't' is timestamp field
        
        print(f"Fetched {len(batch)} bars. Total: {len(all_bars)}")
    
    print(f"\nTotal bars retrieved: {len(all_bars)}")
    print(f"Date range: {datetime.fromtimestamp(all_bars[0]['t']/1000)} to {datetime.fromtimestamp(all_bars[-1]['t']/1000)}")

Real-Time L1 Depth Monitoring

import os
import json
import time
import random
import threading
import websocket

class TickDBDepthWebSocket:
    """
    Production-grade WebSocket client for US equity L1 depth data.
    
    ⚠️ For production HFT workloads, consider aiohttp/asyncio for non-blocking I/O.
    This implementation is synchronous and suitable for strategy prototyping and
    low-to-medium frequency trading systems.
    """
    
    def __init__(self, api_key: str = None):
        self.api_key = api_key or os.environ.get("TICKDB_API_KEY")
        if not self.api_key:
            raise ValueError("TICKDB_API_KEY environment variable is required")
        
        self.ws_url = "wss://api.tickdb.ai/v1/ws/market/depth"
        self.ws = None
        self.connected = False
        self.reconnect_delay = 1.0
        self.max_reconnect_delay = 32.0
        self.heartbeat_interval = 20  # seconds
        self.running = False
        self.subscription_callback = None
    
    def on_message(self, ws, message):
        """Handle incoming WebSocket messages."""
        try:
            data = json.loads(message)
            
            # Handle ping/pong heartbeat
            if data.get("type") == "pong":
                return
            
            # Handle depth update
            if data.get("type") == "depth":
                self._process_depth_update(data)
            
            # Handle subscription confirmation
            if data.get("type") == "subscribe":
                print(f"Subscription confirmed: {data}")
        
        except json.JSONDecodeError:
            print(f"Failed to parse message: {message}")
        except Exception as e:
            print(f"Error processing message: {e}")
    
    def _process_depth_update(self, data: dict):
        """Process and forward depth updates to callback."""
        symbol = data.get("symbol", "UNKNOWN")
        bids = data.get("b", [])  # Best bid
        asks = data.get("a", [])  # Best ask
        
        # Compute pressure ratio from L1 data
        if bids and asks:
            bid_size = float(bids[0][1]) if bids else 0.0
            ask_size = float(asks[0][1]) if asks else 0.0
            pressure_ratio = bid_size / ask_size if ask_size > 0 else float('inf')
            
            update = {
                "symbol": symbol,
                "timestamp": data.get("t"),
                "best_bid": float(bids[0][0]),
                "best_bid_size": bid_size,
                "best_ask": float(asks[0][0]),
                "best_ask_size": ask_size,
                "spread_bps": ((float(asks[0][0]) - float(bids[0][0])) / float(bids[0][0])) * 10000,
                "pressure_ratio": pressure_ratio
            }
            
            if self.subscription_callback:
                self.subscription_callback(update)
    
    def on_error(self, ws, error):
        print(f"WebSocket error: {error}")
    
    def on_close(self, ws, close_status_code, close_msg):
        print(f"WebSocket closed: {close_status_code} - {close_msg}")
        self.connected = False
        
        # Automatic reconnection with exponential backoff + jitter
        if self.running:
            self._schedule_reconnect()
    
    def on_open(self, ws):
        """Called when WebSocket connection is established."""
        print("WebSocket connection established")
        self.connected = True
        self.reconnect_delay = 1.0  # Reset delay on successful connection
        
        # Subscribe to depth for US equity symbols
        symbols = ["AAPL.US", "NVDA.US", "TSLA.US"]
        subscribe_msg = {
            "type": "subscribe",
            "symbols": symbols
        }
        ws.send(json.dumps(subscribe_msg))
        print(f"Subscribed to depth for: {symbols}")
    
    def _schedule_reconnect(self):
        """Schedule reconnection with exponential backoff + jitter."""
        jitter = random.uniform(0, self.reconnect_delay * 0.1)
        sleep_time = min(self.reconnect_delay + jitter, self.max_reconnect_delay)
        print(f"Scheduling reconnect in {sleep_time:.2f}s (delay={self.reconnect_delay:.2f}s)")
        
        # Run reconnect in background thread
        reconnect_thread = threading.Thread(
            target=lambda: self._delayed_reconnect(sleep_time)
        )
        reconnect_thread.daemon = True
        reconnect_thread.start()
    
    def _delayed_reconnect(self, delay: float):
        """Delay wrapper for reconnection."""
        time.sleep(delay)
        self.reconnect_delay = min(self.reconnect_delay * 2, self.max_reconnect_delay)
        self._connect()
    
    def _connect(self):
        """Establish WebSocket connection with auth in URL parameter."""
        auth_url = f"{self.ws_url}?api_key={self.api_key}"
        self.ws = websocket.WebSocketApp(
            auth_url,
            on_message=self.on_message,
            on_error=self.on_error,
            on_close=self.on_close,
            on_open=self.on_open
        )
        
        # Run in background thread
        ws_thread = threading.Thread(target=self.ws.run_forever)
        ws_thread.daemon = True
        ws_thread.start()
    
    def start(self, callback=None):
        """
        Start the WebSocket client with optional callback for depth updates.
        
        Args:
            callback: Function called with each depth update dict
        """
        self.subscription_callback = callback
        self.running = True
        self._connect()
    
    def stop(self):
        """Stop the WebSocket client gracefully."""
        self.running = False
        if self.ws:
            self.ws.close()
        print("WebSocket client stopped")


# Usage example
if __name__ == "__main__":
    def handle_depth(update: dict):
        """Callback to process real-time depth updates."""
        print(
            f"{update['symbol']} | "
            f"Bid: ${update['best_bid']:.2f} x {update['best_bid_size']:,.0f} | "
            f"Ask: ${update['best_ask']:.2f} x {update['best_ask_size']:,.0f} | "
            f"Spread: {update['spread_bps']:.1f} bps | "
            f"Pressure: {update['pressure_ratio']:.2f}"
        )
    
    client = TickDBDepthWebSocket()
    
    try:
        print("Starting TickDB depth monitoring (press Ctrl+C to stop)...")
        client.start(callback=handle_depth)
        
        while client.running:
            time.sleep(1)
            
    except KeyboardInterrupt:
        print("\nShutting down...")
        client.stop()

Comparison Table: What You Sacrifice, What You Gain

This table is not designed to convince you that TickDB is superior to tick-data platforms. It is designed to help you make an informed choice based on your actual requirements.

Dimension TickDB Polygon Databento
US equity tick trades ❌ Not supported ✅ Full tape ✅ Full tape
US equity OHLCV (10+ yr) ✅ Supported ✅ Supported ✅ Supported
US equity L1 depth ✅ Supported ✅ Supported ✅ Supported
US equity L2/L3 depth ❌ Not supported ✅ Supported ✅ Supported
HK equity trades ✅ Supported ❌ Limited ❌ Limited
Crypto trades ✅ Supported ✅ Supported ✅ Supported
Cross-asset single API ✅ 6 asset classes ❌ Multi-product ❌ Multi-product
Pricing model Subscription Tiered by data volume Tiered by data volume
WebSocket latency <100 ms Polling (1–5s) on free tier <100 ms
API authentication Header (X-API-Key) Header Header
Heartbeat / reconnect Native DIY Native

The honest summary: If you need US equity tick trades, go to Polygon or Databento for that data. If you need long-horizon OHLCV, cross-asset coverage, and a developer-friendly API, TickDB is purpose-built for that. Do not pay for a Ferrari when you need a moving truck — and do not buy a moving truck expecting it to win races.


Deployment Guidance by User Segment

Individual Retail Traders

If you are running end-of-day strategies, daily mean reversion, or multi-day momentum on US equities, TickDB's OHLCV data covers your needs. The free tier provides sufficient access for strategy prototyping. Do not over-engineer your data stack.

Quantitative Developers

If you are building a strategy that requires tick-level order flow analysis, use a dedicated tick-data vendor for that specific data stream, and use TickDB for historical bar backtesting and cross-asset context data. The two can coexist in your pipeline.

Institutional Teams

If your strategy requires tick data as a first-class input (market making, TCA, HFT), you need a dedicated tick-data platform. Evaluate Polygon, Databento, or direct exchange feeds. For portfolio-level systematic strategies that operate on daily bars, TickDB's long-horizon dataset and cross-asset API reduce infrastructure complexity significantly.


Strategic Takeaways

Three principles for navigating market data product boundaries:

1. Define your data requirements before selecting a vendor. A strategy that requires tick prints cannot be retrofitted to run on bar data. Know your inputs before you commit to a platform.

2. Understand that product focus is not a limitation — it is a design choice. TickDB chose to be excellent at long-horizon OHLCV and cross-asset coverage. That focus has a cost: it cannot also be excellent at tick data ingestion at the same price point. Every platform makes tradeoffs. Align yourself with platforms that made tradeoffs in your favor.

3. Multi-vendor data stacks are the industry norm for a reason. No single vendor covers every data need. The professional quant stack includes TickDB for historical bars and cross-asset context, plus a tick-data vendor for order flow analysis, plus a separate data source for short interest or options flow. Build infrastructure that can ingest from multiple sources, and choose vendors based on data quality for specific use cases.


Next Steps

If you are evaluating TickDB for long-horizon strategy backtesting, visit tickdb.ai and sign up for a free API key to access 10+ years of US equity OHLCV data with no credit card required.

If you need tick-level trade data for US equities, explore Polygon or Databento — both offer US equity tick data as a core capability. Use TickDB alongside for historical bar data and cross-asset context.

If you are building a multi-asset strategy, TickDB's unified API covering equities, crypto, forex, and indices simplifies your data infrastructure significantly. Install the tickdb-market-data SKILL in your AI coding assistant to streamline integration.


This article does not constitute investment advice. Market data products have specific capability boundaries; always verify current API documentation before building production systems. Past data coverage does not guarantee future availability.