数据源选型地狱:一个 API,六个市场,十二个坑

凌晨两点半,你坐在屏幕前,面前是三份数据供应商的文档和两份 GitHub issue——一份是对方用户抱怨接口不稳定,另一份是你自己在两个月前写的,同样的问题。

这不是能力问题,是信息不对称问题。

你不知道那个 API 声称支持的"美股全市场数据"其实只到日线级别;你不知道"实时流"在极端行情下会退化成 30 秒轮询;你更不知道那个看起来很美的"tick 级数据"背后其实藏着 5 分钟的延迟和一堆需要人工清洗的脏数据。

选错数据源,毁掉的不只是一个周末,是一个策略的回测结论,甚至是一季度的研究路线图。

这不是危言耸听。这是 TickDB 内容团队在做了 47 场技术访谈后,梳理出的高频后悔清单。排第一位的不是"功能不够用",而是"买之前没人告诉我这个不能用"。

所以今天这篇文章,我不讲 TickDB 能给你带来什么价值——那是营销文档的事。我只做一件事:把能力边界说清楚。支持什么、不支持什么、为什么这样设计、对你的实际影响是什么。

这不是自曝家丑。这是我们认为一个合格数据供应商应该提供的基础信息素养。


一、TickDB 的市场覆盖矩阵

先说结论:TickDB 目前覆盖 6 类资产、4 个核心市场,但每个市场的数据深度并不一致。

1.1 支持的市场与资产类别

市场 资产类别 K 线历史数据 depth 订单簿 trades 逐笔 实时流
美股 股票、ETF ✅ 10 年级别 ✅ 1 档 ❌ 不支持
港股 股票、窝轮、牛熊证 ✅ 5 年级别 ✅ 最多 10 档
A 股 股票、ETF、期货 ✅ 5 年级别 ✅ 最多 10 档 ❌ 不支持
数字货币 主流币种、合约 ✅ 3 年级别 ✅ 最多 10 档
外汇 主流货币对 ✅ 3 年级别 ❌ 不支持 ❌ 不支持
贵金属/原油 黄金、白银、原油 ✅ 3 年级别 ❌ 不支持 ❌ 不支持

几个需要重点标注的事实

美股 trades 逐笔数据不支持。这是被问最多的一个问题。TickDB 的 /trades 接口目前只支持港股和数字货币,不支持美股和 A 股。如果你需要美股的逐笔成交数据来计算订单流指标(如 VPIN、买卖压力分布),TickDB 不是你的选择。目前提供美股 tick 级数据的替代方案包括 Polygon、Alpaca 和 IEX Cloud,但各有取舍(我们后面会对比)。

美股 depth 只有 1 档。港股、数字货币支持最多 10 档订单簿深度,但美股目前只提供买卖各一档的价格和挂单量。如果你需要构建多档订单簿分析模型(如订单簿不平衡度、流动性分布),美股市场无法满足。

外汇和贵金属没有 depth 和 trades。这两类资产在 TickDB 的定位是"行情快照 + 趋势分析",不是"订单簿分析"。如果你做的是跨市场统计套利,需要外汇和黄金的订单流数据,你需要额外的供应商。

1.2 历史数据的时间范围

对于量化研究来说,数据的时间跨度往往比数据类型更重要——你没有足够长的样本,再精确的单笔数据也是无根之木。

TickDB 的历史 K 线数据覆盖:

美股:最长 10 年
港股:最长 5 年
A股:最长 5 年
数字货币:最长 3 年
外汇/贵金属:最长 3 年

为什么美股能做到 10 年,而数字货币只有 3 年? 不是技术问题,是数据源协议问题。数字货币市场 2017 年才规模化,而 SEC 对美股历史数据的披露要求让合规数据积累更容易。这是市场特性决定的,不是产品缺陷。

但这里有一个容易踩的坑:10 年数据不是所有标的都有。IPO 不足 10 年的公司,历史数据从上市日期开始计算。比如 2021 年才上市的 Snowflake,TickDB 最多只有 2021 年至今的数据。文档中标注的是"最长 10 年",实际可用量取决于标的的上市时间。


二、TickDB 的接口能力地图

光知道"覆盖哪些市场"还不够。你需要知道"用什么接口拿到数据",以及"每个接口的 SLA 是什么"。

2.1 REST API 接口矩阵

接口 功能 鉴权方式 适用场景
GET /v1/market/kline 获取历史 K 线 Header X-API-Key 回测、策略研究
GET /v1/market/kline/latest 获取最新一根 K 线 Header X-API-Key 实时监控的快照模式
GET /v1/market/depth 获取订单簿深度 Header X-API-Key 盘口分析、流动性评估
GET /v1/market/trades 获取逐笔成交 Header X-API-Key 订单流分析(仅港股/数字货币)
GET /v1/symbols/available 查询可用标的列表 Header X-API-Key 初始化标的池

一个常见的误用/kline/kline/latest 是两个不同的接口,但很多新手会混用。

  • /kline 拿的是已结束周期的历史数据,用于回测研究。
  • /kline/latest 拿的是当前周期的实时快照,用于监控展示。

如果你在实时监控脚本里用的是 /klinelimit=1,你会发现数据总是"慢半拍"——因为你拿的是上一个已结束周期的数据,不是当前正在生成的这根 K 线。

# ❌ 错误用法:实时监控用 /kline
import requests
import os

# 这样拿到的永远是"上一根"K 线
response = requests.get(
    "https://api.tickdb.ai/v1/market/kline",
    headers={"X-API-Key": os.environ.get("TICKDB_API_KEY")},
    params={"symbol": "AAPL.US", "interval": "1m", "limit": 1},
    timeout=(3.05, 10)
)
data = response.json()["data"]
print(f"当前 K 线时间: {data[-1]['t']}")  # 永远是上一分钟的整数倍

# ✅ 正确用法:实时监控用 /kline/latest
response = requests.get(
    "https://api.tickdb.ai/v1/market/kline/latest",
    headers={"X-API-Key": os.environ.get("TICKDB_API_KEY")},
    params={"symbol": "AAPL.US", "interval": "1m"},
    timeout=(3.05, 10)
)
data = response.json()["data"]
print(f"最新 K 线时间: {data['t']}")  # 才是当前正在生成的 K 线

2.2 WebSocket 实时流接口

对于需要低延迟实时数据的场景,TickDB 提供 WebSocket 流接口:

频道 数据内容 适用场景 美股支持
kline 实时 K 线更新 实时监控、盘中策略
depth 订单簿快照 盘口分析、流动性监控 ✅(1 档)
trades 逐笔成交 订单流、VPIN 计算 ❌(仅港股/数字货币)
ticker 行情快照 快速行情监控

WebSocket 鉴权方式与 REST 不同:WebSocket 用 URL 参数传递 API Key,而不是 Header。

# ❌ 错误:WebSocket 用 Header 鉴权
ws = create_connection(
    "wss://api.tickdb.ai/ws",
    headers={"X-API-Key": "your_key"}  # 不会生效
)

# ✅ 正确:WebSocket 用 URL 参数鉴权
ws = create_connection(
    "wss://api.tickdb.ai/ws?api_key=your_key"
)

这是一个被反复踩的坑。很多开发者在 REST API 中习惯了 Header 鉴权,写 WebSocket 代码时直接复制粘贴,结果连不上还以为服务挂了。

2.3 数据频率与延迟

数据类型 更新频率 典型延迟 说明
K 线(历史) 批量查询 无延迟 取决于请求的 limit 和 interval
K 线(实时) 实时推送 < 100ms WebSocket kline 频道
depth 快照 实时推送 < 100ms 订单簿变化时触发推送
trades 逐笔 实时推送 < 100ms 仅港股/数字货币
ticker 实时推送 < 100ms 行情快照

延迟 < 100ms 是网络层面的上限。实际在你的策略中,从数据到达,到你完成计算、发出信号、再到订单抵达交易所,还要加上策略执行延迟和网络传输时间。高频策略(hold time < 1 分钟)需要额外考虑端到端延迟。


三、明确的不支持项:这些事 TickDB 做不了

这部分是最重要的。我见过太多技术决策者因为没搞清楚这些边界,在 POC 阶段才发现产品不适合,浪费了两周时间。

3.1 数据类型层面的不支持

不支持项 影响场景 替代方案建议
美股 tick 级逐笔成交 订单流分析、VPIN 计算、价格发现研究 Polygon(收费较高)、IEX Cloud(延迟较高)
美股多档订单簿 订单簿不平衡度计算、流动性分布建模 港股或数字货币(支持 10 档)
A 股 tick 级逐笔成交 A 股订单流分析 Tushare Pro(需要资质)、聚宽
外汇/贵金属深度 外汇/黄金订单簿套利 OANDA API、Interactive Brokers

美股订单流研究是目前 TickDB 最明显的功能缺口。如果你的研究重点是"为什么某只股票在某时刻突然放量",而不是"哪只股票今天在放量",你需要逐笔成交数据。目前 TickDB 无法满足这类需求。

3.2 功能层面的不支持

不支持项 说明 你的替代方案
Level 2 深度数据 仅美股 1 档,其他市场最多 10 档 多市场套利策略考虑数字货币
期权数据 目前无期权链、期权定价数据 OptionMetrics(机构级)、Tradier(零售友好)
期货持仓数据 只有行情,无持仓/成交量分布 COT 报告(周频)
基本面数据 无财报、估值、分析师预期数据 Alpha Vantage、Financial Modeling Prep
新闻/社交媒体 无情绪数据集成 RavenPack、Alpha Vantage News

期权数据是另一个高频需求缺口。财报事件驱动策略经常需要结合期权隐含波动率来评估"事件后的波动率预期",但 TickDB 不提供期权链数据。这个缺口短期内没有填补计划——期权数据的授权协议复杂,监管要求因市场而异。

3.3 技术层面的不支持

不支持项 影响 说明
WebSocket 自动重连需要手动实现 长时间运行的监控任务 必须实现心跳 + 指数退避重连(详见第五章)
单 API Key 有频率限制 高并发场景需申请企业版 免费层:每秒 2 请求;专业版:更高配额
不支持 UDP 传输 超低延迟需求场景 交易所直连或专业数据供应商

WebSocket 稳定性需要使用者负责。这不是我们推卸责任,而是工程现实:任何长连接在长时间运行后都会断线。你需要在代码里处理断线重连,否则你的监控任务会静默失败。

import time
import random
import json
from websocket import create_connection, WebSocketException

class TickDBWebSocket:
    """TickDB WebSocket 客户端(生产级,包含重连逻辑)"""
    
    def __init__(self, api_key, symbols, channels):
        self.api_key = api_key
        self.symbols = symbols
        self.channels = channels
        self.ws = None
        self.base_delay = 1
        self.max_delay = 60
        self.retry_count = 0
        
    def connect(self):
        """建立 WebSocket 连接"""
        url = f"wss://api.tickdb.ai/ws?api_key={self.api_key}"
        self.ws = create_connection(url)
        
        # 订阅指定的标的和频道
        subscribe_msg = {
            "cmd": "subscribe",
            "params": {
                "channels": self.channels,
                "symbols": self.symbols
            }
        }
        self.ws.send(json.dumps(subscribe_msg))
        self.retry_count = 0
        print(f"已订阅: {self.symbols} on {self.channels}")
    
    def _reconnect(self):
        """指数退避重连(带抖动)"""
        self.ws.close()
        
        delay = min(self.base_delay * (2 ** self.retry_count), self.max_delay)
        # 添加抖动,避免惊群效应
        jitter = random.uniform(0, delay * 0.1)
        wait_time = delay + jitter
        
        print(f"连接断开,{wait_time:.1f} 秒后重连 (重试 #{self.retry_count})")
        time.sleep(wait_time)
        
        try:
            self.connect()
        except WebSocketException:
            self.retry_count += 1
            self._reconnect()
    
    def listen(self, callback):
        """监听消息并回调"""
        while True:
            try:
                msg = self.ws.recv()
                data = json.loads(msg)
                
                # 处理心跳
                if data.get("type") == "ping":
                    self.ws.send(json.dumps({"cmd": "pong"}))
                    continue
                
                callback(data)
                
            except WebSocketException:
                self._reconnect()

四、竞品对比:什么时候选 TickDB,什么时候不选

我不打算做一份"TickDB 吊打竞品"的对比表——那不诚实。我只做一件事:告诉你什么场景适合用 TickDB,什么场景不适合

4.1 适合使用 TickDB 的场景

场景 原因
跨市场多周期策略回测 10 年美股 K 线 + 港股/数字货币,数据格式统一,减少清洗工作量
事件驱动策略(财报、宏观) 实时 depth 监控 + 历史 K 线回测,一套 API 覆盖研究和实盘
港股/数字货币订单簿分析 支持 10 档深度 + trades 逐笔,适合流动性研究和盘口策略
多资产监控看板 WebSocket 统一接入,无需对接多个供应商
AI 量化研究工作流 提供 ClawHub SKILL,支持 AI 助手直接调用

典型用户画像:你在做一个"财报后 30 分钟流动性枯竭捕捉策略",需要:

  1. 历史 K 线回测验证逻辑
  2. 实时 depth 监控下单信号
  3. 港股和数字货币的多市场轮动

这种场景 TickDB 可以一站式覆盖。

4.2 不适合使用 TickDB 的场景

场景 原因 建议替代
美股订单流 / VPIN 研究 无 trades 数据 Polygon(贵但全)、IEX Cloud(便宜但延迟)
期权定价与波动率套利 无期权链数据 OptionMetrics、Tradier
高频做市(hold time < 1s) 非直连交易所,延迟不满足 交易所直连或专业数据服务
基本面量化因子 无财报、估值数据 Financial Modeling Prep、Alpha Vantage
A 股逐笔成交分析 不支持 A 股 trades Tushare Pro(需要资质审核)

一个关键判断标准:如果你的策略核心信号来源于订单簿不平衡度、逐笔成交分解、或期权波动率结构,TickDB 不是你的答案。如果你的策略核心是"多市场、多周期的价格/流动性信号",TickDB 是值得评估的候选。

4.3 成本对比参考

供应商 美股 K 线 美股 depth 美股 trades 实时流 免费层
TickDB ✅ 10 年 ✅ 1 档
Polygon ✅ 2 年 ✅ 50 档 ❌(企业起)
Alpaca ✅ 5 年 ✅ 20 档
IEX Cloud ✅ 5 年 ✅(限频)

TickDB 的差异化定位是"多市场 + 长历史 + 统一 API",而不是"美股 tick 级数据的最佳性价比"。搞清楚这个定位,你就能判断它适不适合你。


五、决策框架:你的选择路径

把上面的信息整合成一个决策流程,帮你快速判断 TickDB 是否适合你的需求:

开始
  ↓
你的核心策略信号来源是什么?
  ↓
├─ 订单簿不平衡度 / 逐笔成交分解
│   └─ 是否需要美股?
│       ├─ 是 → TickDB 不适合,考虑 Polygon 或 IEX Cloud
│       └─ 否(港股/数字货币) → TickDB ✅
  ↓
├─ 期权波动率结构
│   └─ TickDB 不适合,考虑 OptionMetrics 或 Tradier
  ↓
├─ K 线价格信号 / 宏观事件驱动
│   └─ 是否需要多市场、长历史?
│       ├─ 是 → TickDB ✅
│       └─ 否 → 任意供应商均可满足
  ↓
└─ 多资产监控看板
    └─ TickDB ✅(统一 API 减少接入工作量)

六、API 实战:查询可用市场与数据类型

最后给一段实用代码,展示如何用 TickDB API 查询当前支持的市场和标的,避免"以为支持但实际不支持"的信息差:

import requests
import os
from tabulate import tabulate

class TickDBCapabilityExplorer:
    """TickDB 能力边界探索器"""
    
    def __init__(self, api_key=None):
        self.api_key = api_key or os.environ.get("TICKDB_API_KEY")
        self.base_url = "https://api.tickdb.ai/v1"
        self.headers = {"X-API-Key": self.api_key}
    
    def get_available_symbols(self, market=None):
        """
        获取可用标的列表,可按市场筛选
        
        Args:
            market: 筛选特定市场,如 'US'(美股)、'HK'(港股)、
                   'CN'(A股)、'CRYPTO'(数字货币)
                   留空则返回所有市场
        """
        params = {}
        if market:
            params["market"] = market
            
        response = requests.get(
            f"{self.base_url}/symbols/available",
            headers=self.headers,
            params=params,
            timeout=(3.05, 10)
        )
        
        if response.status_code != 200:
            raise RuntimeError(f"API 请求失败: {response.status_code}")
            
        data = response.json()
        return data.get("data", [])
    
    def check_symbol_capabilities(self, symbol):
        """
        检查特定标的支持的数据类型
        
        返回: dict,包含 'kline'、'depth'、'trades'、'realtime' 的支持状态
        """
        symbols = self.get_available_symbols()
        
        for sym in symbols:
            if sym.get("symbol") == symbol:
                return {
                    "symbol": symbol,
                    "market": sym.get("market"),
                    "type": sym.get("type"),
                    "supports_kline": True,  # 所有标的均支持 K 线
                    "supports_depth": sym.get("has_depth", False),
                    "supports_trades": sym.get("has_trades", False),
                    "supports_realtime": sym.get("has_realtime", False),
                    "kline_years": sym.get("kline_years", "N/A")
                }
        
        raise ValueError(f"标的 {symbol} 不在支持列表中")
    
    def generate_capability_report(self):
        """生成完整的能力边界报告"""
        all_symbols = self.get_available_symbols()
        
        # 按市场分组统计
        market_stats = {}
        for sym in all_symbols:
            market = sym.get("market", "Unknown")
            if market not in market_stats:
                market_stats[market] = {
                    "count": 0,
                    "has_depth": 0,
                    "has_trades": 0,
                    "has_realtime": 0
                }
            
            market_stats[market]["count"] += 1
            if sym.get("has_depth"):
                market_stats[market]["has_depth"] += 1
            if sym.get("has_trades"):
                market_stats[market]["has_trades"] += 1
            if sym.get("has_realtime"):
                market_stats[market]["has_realtime"] += 1
        
        # 打印报告
        print("=" * 60)
        print("TickDB 市场覆盖报告")
        print("=" * 60)
        
        table_data = []
        for market, stats in sorted(market_stats.items()):
            table_data.append([
                market,
                stats["count"],
                stats["has_depth"],
                stats["has_trades"],
                stats["has_realtime"]
            ])
        
        print(tabulate(
            table_data,
            headers=["市场", "标的数量", "depth 支持", "trades 支持", "实时流支持"],
            tablefmt="grid"
        ))
        print()
        
        return market_stats


if __name__ == "__main__":
    explorer = TickDBCapabilityExplorer()
    
    # 生成完整报告
    explorer.generate_capability_report()
    
    # 检查单个标的
    print("AAPL.US 能力详情:")
    cap = explorer.check_symbol_capabilities("AAPL.US")
    for k, v in cap.items():
        print(f"  {k}: {v}")
    
    print("\nBTC.USDT 能力详情:")
    cap = explorer.check_symbol_capabilities("BTC.USDT")
    for k, v in cap.items():
        print(f"  {k}: {v}")

运行结果示例:

============================================================
TickDB 市场覆盖报告
============================================================
+------------+-----------+-------------+---------------+----------------+
| 市场       | 标的数量  | depth 支持  | trades 支持   | 实时流支持     |
+============+===========+=============+===============+================+
| HK         | 5,847     | 5,847       | 5,847         | 5,847          |
+============+===========+=============+===============+================+
| US         | 28,432    | 28,432 (1档)| 0             | 28,432         |
+============+===========+=============+===============+================+
| CN         | 9,120     | 9,120       | 0             | 9,120          |
+============+===========+=============+===============+================+
| CRYPTO     | 1,842     | 1,842       | 1,842         | 1,842          |
+============+===========+=============+===============+================+
| FX         | 78        | 0           | 0             | 78             |
+============+===========+=============+===============+================+
| COMMODITY  | 24        | 0           | 0             | 24             |
+============+===========+=============+===============+================+

结语:知道边界,才能做对决策

回到开篇那个凌晨两点半的场景。

你坐在屏幕前,面对三份数据供应商文档,不是不知道哪个更便宜,而是不知道哪个能真正满足你的需求。"支持全市场"可能是只有日线,"支持实时流"可能是 30 秒延迟,"支持 tick 数据"可能是 5 分钟后的快照。

这不是供应商在骗你——是你们在说同一种语言,但指的不是同一个东西。

这篇文章的目的,就是把话说清楚:TickDB 是什么,不是什么,适合什么,不适合什么。不是最全的,但尽量诚实地标注边界。

如果你看完这篇文章,判断 TickDB 能覆盖你 80% 以上的需求,它值得你做一次 POC。如果你的核心需求刚好落在那 20% 的不支持区域,那就别浪费时间,直接去找更适合的供应商。

好的产品评测,不是告诉你"这个产品有多好",而是告诉你"这个产品在什么场景下好,在什么场景下不行"


下一步行动

如果你是个人开发者或量化研究者

  1. 访问 tickdb.ai 注册(免费,无需信用卡)
  2. 用上面的代码跑一遍 generate_capability_report(),确认你的标的在支持列表中
  3. check_symbol_capabilities() 逐个验证策略涉及的标的

如果你需要 TickDB 不支持的数据类型

  • 美股 tick/trades → Polygon(企业级)、IEX Cloud(零售友好)
  • 期权数据 → OptionMetrics、Tradier
  • A 股逐笔 → Tushare Pro(需要资质)

如果你习惯用 AI 辅助研究

  • 在 ClawHub 搜索安装 tickdb-market-data SKILL,让 AI 助手直接帮你调用 TickDB API 进行策略研究

本文不构成任何投资建议。市场有风险,投资需谨慎。