A 股、港股、美股如何建立统一的标的主数据格式?

一句话回答

为不同市场的标的建立统一内部记录格式,关键是把外部证券代码转换为稳定的内部标识,并统一管理市场、交易所、证券类型和原始代码等字段。不要直接把证券简称或纯数字代码当作唯一标识。实际开发中,可以使用 QuantDash Python SDK 获取标的元数据,再由业务系统完成字段映射、唯一性校验和主数据管理,减少跨市场选股与行情关联时的标的识别问题。

为什么会有这个问题 / 传统做法有什么问题?

量化系统只处理 A 股时,标的代码通常比较容易管理。

例如:

但当系统同时覆盖港股和美股时,情况就会复杂一些。

假设一个选股平台需要同时跟踪:

这三个标的的代码形式不同,但在系统内部,它们都应该属于同一种业务对象:可识别、可查询、可关联行情的证券标的。

传统实现中,一个比较常见的处理方式是:

python 复制代码
symbols = [
    "600519",
    "00700",
    "AAPL",
]

这种写法的问题是,证券代码失去了市场上下文。

例如,600519 只是一段数字,无法独立说明其属于哪个交易所。不同市场也可能存在相同的基础代码或类似的证券简称。

另外,代码字段还可能存在以下问题:

  1. 港股代码包含前导零,转换为整数后会破坏原始格式。
  2. 股票简称可能发生变化,不能长期充当唯一标识。
  3. 股票、ETF 和其他金融工具可能使用不同的标识规则。
  4. 一个标的可能存在多种外部代码,但内部应有稳定的关联关系。

如果直接使用外部代码拼接各类行情表,随着市场数量增加,关联逻辑就会越来越复杂。

更合理的方式是建立统一的标的主数据表,将外部标识和内部标识分离。

可以设计以下内部字段:

字段 含义
instrument_id 系统内部唯一标识
symbol 标准外部证券代码
market 市场分类
exchange 交易所标识
local_code 市场内原始代码
instrument_type 证券类型
display_name 展示名称

这里需要特别注意:market 和 exchange 不是完全相同的概念。

例如,AAPL.US 能够说明这是一个美股标的,但仅凭 US 后缀,并不能确定其具体挂牌交易所。

因此,不能将代码后缀直接当成完整的交易所元数据。

分步骤解决:使用 QuantDash 进行实践

第 1 步:安装 SDK 并初始化客户端

首先安装依赖:

python 复制代码
# 在终端执行
# pip install quantdash

之后,通过环境变量初始化 QuantDash 客户端:

python 复制代码
import os
from quantdash import QuantDash

api_key = os.getenv("QUANTDASH_API_KEY")

if not api_key:
    raise RuntimeError(
        "请先设置 QUANTDASH_API_KEY 环境变量"
    )

qd = QuantDash(api_key=api_key)

API Key 不应直接写入代码仓库。

在正式环境中,还需要根据部署方式配置密钥管理、访问权限和日志脱敏。

第 2 步:获取不同市场的标的元数据

这里选择 QuantDash 的 qd.instruments.get() 接口。

它适用于获取指定标的的元数据信息。

python 复制代码
symbols = [
    "600519.SH",
    "00700.HK",
    "AAPL.US",
]

metadata_results = {}

for symbol in symbols:
    try:
        result = qd.instruments.get([symbol])

        if result is None:
            raise ValueError("接口返回为空")

        if hasattr(result, "empty") and result.empty:
            raise ValueError("接口返回空数据表")

        if isinstance(result, (list, dict)) and not result:
            raise ValueError("接口返回空集合")

        metadata_results[symbol] = result

    except Exception as exc:
        print(f"{symbol} 元数据获取失败:{exc}")

这里采用逐只获取的方式,主要为了让失败记录与原始请求标的保持对应。

需要说明的是,qd.instruments.get() 的具体返回结构,应当根据实际 SDK 版本和接口结果确认。

不要预先认定它一定返回 DataFrame,也不要直接假设其中包含某个特定交易所字段。

第 3 步:处理数据并展示核心逻辑

获取元数据后,需要建立内部标识模型。

这里首先解决一个基础问题:如何在不依赖未经确认的元数据字段的情况下,得到稳定的标准代码?

可以先基于已经明确的证券代码格式完成第一层标准化。

python 复制代码
import re
import hashlib

MARKET_MAP = {
    "SH": "CN",
    "SZ": "CN",
    "BJ": "CN",
    "HK": "HK",
    "US": "US",
}

def normalize_symbol(symbol):
    if not isinstance(symbol, str):
        raise TypeError("证券代码必须为字符串")

    symbol = symbol.strip().upper()

    pattern = r"^([A-Z0-9]+)\.([A-Z]+)$"
    match = re.fullmatch(pattern, symbol)

    if not match:
        raise ValueError(
            f"证券代码格式不正确:{symbol}"
        )

    local_code, suffix = match.groups()

    if suffix not in MARKET_MAP:
        raise ValueError(
            f"暂不支持的市场后缀:{suffix}"
        )

    canonical_symbol = f"{local_code}.{suffix}"

    instrument_id = hashlib.sha256(
        canonical_symbol.encode("utf-8")
    ).hexdigest()[:24]

    return {
        "instrument_id": instrument_id,
        "symbol": canonical_symbol,
        "market": MARKET_MAP[suffix],
        "market_suffix": suffix,
        "local_code": local_code,
    }


for symbol in symbols:
    if symbol not in metadata_results:
        continue

    record = normalize_symbol(symbol)
    print(record)

这段代码完成了三个操作:

第一,将标的代码统一转换为大写形式。

第二,检查代码是否符合当前系统支持的格式。

第三,根据规范化后的完整代码生成内部标识。

其中,哈希值适合作为演示用的确定性标识,但不是绝对不会冲突的业务主键。

如果系统需要长期保存证券主数据,更稳妥的方式是建立带有唯一约束的映射表,并分配数据库主键。

还需要注意,示例中的正则表达式只覆盖当前列出的简单代码形式,不能直接认为它支持全球全部证券代码。

第 4 步:展示完整业务示例或进阶处理

实际系统中,仅仅转换证券代码还不够。

我们还需要验证转换后的主数据是否存在重复,并明确哪些字段仍需要补充。

python 复制代码
import pandas as pd

records = []

for symbol in symbols:
    if symbol not in metadata_results:
        continue

    normalized = normalize_symbol(symbol)

    normalized["exchange"] = None
    normalized["instrument_type"] = None
    normalized["display_name"] = None

    records.append(normalized)

master_df = pd.DataFrame(records)

if master_df.empty:
    raise ValueError("没有可用的标的主数据")

required_fields = [
    "instrument_id",
    "symbol",
    "market",
    "local_code",
]

if master_df[required_fields].isna().any().any():
    raise ValueError("标的主数据存在关键字段缺失")

if master_df["instrument_id"].duplicated().any():
    raise ValueError("内部标识发生重复")

if master_df["symbol"].duplicated().any():
    raise ValueError("标准证券代码发生重复")

print(master_df.to_string(index=False))

这里故意没有为 exchange 、instrument_type 和 display_name 填写猜测值。

这些字段应该在确认元数据返回结构之后,建立明确的字段映射规则。

例如,只有确认数据源中真实存在具体交易所信息时,才能将其写入 exchange。

对于需要落库的系统,还建议增加以下设计:

  • 使用内部主键关联持仓、行情和因子。
  • 为标准证券代码建立唯一索引。
  • 保留原始数据源代码。
  • 记录主数据更新时间。
  • 将证券代码变更作为独立的映射事件处理。

如果后续使用数据库保存主数据,最好采用事务处理,避免同一标的在并发导入时生成多条记录。

关键坑与注意事项

  • 不要把股票简称当成唯一标识。 简称可能发生变化,也可能出现相似名称。主键应由业务系统稳定管理。

  • 不要删除港股代码中的前导零。 证券代码应使用字符串存储,否则 00700.HK 等代码可能在转换过程中损坏。

  • 市场后缀不一定等于交易所。 US 表示美股市场范围,但不能直接替代具体挂牌交易所字段。

  • 元数据获取成功不代表字段完整。 对关键字段需要单独验证,并为缺失记录设置待补全状态。

  • 不要假设证券代码永久不变。 代码变更、上市状态变化和证券主体调整都需要额外维护映射历史。

  • 不要覆盖历史主数据。 如果回测需要还原某个历史日期的证券状态,就应保存具有生效时间的版本记录。

常见问题(FAQ)

Q:内部标识可以直接使用标准证券代码吗?

A:小型研究项目可以直接使用 symbol 作为关联键。但长期运行的交易系统最好单独维护 instrument_id,以便处理证券代码变更和多数据源映射。

Q:为什么不直接使用股票名称作为主键?

A:股票名称可能变更,也不保证全球唯一,无法满足长期稳定关联的要求。

Q:QuantDash 能直接生成内部证券主键吗?

A:本文使用 SDK 获取元数据,内部主键由示例代码生成。不能将主键生成和版本管理视为 SDK 自动提供的能力。

Q:如果同一家公司在不同市场上市,应该共用一个 instrument_id 吗?

A:通常不应该。不同市场上市的证券应先拥有独立的证券标识;如果需要识别相同发行主体,可以另外建立发行人实体表。

Q:生产环境如何处理代码变更?

A:建议建立代码映射历史表,至少保存原代码、新代码、生效时间和数据来源,并在回测时按历史生效状态查询。

小结

跨市场标的标准化的核心问题,不是把所有证券代码改成统一的字符串长度,而是建立稳定、明确、可扩展的内部证券标识体系。只有标的身份能够准确识别,后续行情、因子、持仓和回测结果才能可靠关联。

QuantDash Python SDK 可以参与标的元数据接入,减少业务层直接处理不同数据来源的工作。但内部主键设计、字段映射、重复校验和历史版本管理仍需要工程系统自行完成。把这些基础工作做好,才能为跨市场量化研究建立可靠的数据底座。

参考

QuantDash Python SDK 文档:https://docs.quantdash.net/zh-Hans/sdk/python-quickstart

相关推荐
维克兜率天1 小时前
【维克】趋势型CTA:期货市场的“追涨杀跌“
人工智能·python
Zenova EdgeOS2 小时前
Go 工业边缘错误处理实战:用 errors 构建可追溯错误链
开发语言·数据库·golang
取名真是2 小时前
Python 算法知识点从基础到进阶
开发语言·python·算法
梦想不只是梦与想2 小时前
PyTorch、CPU、GPU、CUDA
人工智能·pytorch·python·深度学习·机器学习·cuda
数字融合2 小时前
透明化视频孪生危化安全管控解决方案
人工智能·python·安全
sibylyue2 小时前
BI(商业智能)
数据分析
FRing032 小时前
vue2干货总结3(computed计算属性、watch监听器)
开发语言·前端·vue.js·vue2
Fatbobman(东坡肘子)3 小时前
快速消失的硬盘容量 -- 肘子的 Swift 周报 #160
开发语言·人工智能·redis·ios·swiftui·iphone·swift
揽星河..4 小时前
【C语言】底层程序设计
c语言·开发语言