掌握 gs-quant 的 Index.get_identifier:跨时间获取指数证券标识符的权威指南
导读
在 Goldman Sachs 开源的 Python 量化工具包 gs-quant 中,Index.get_identifier() 是查询指数(Index)证券各类市场标识符(如 RIC、Bloomberg ID、CUSIP、ISIN、SEDOL、Ticker)的统一入口。本文以 docs/functions/gs_quant.markets.index.Index.get_identifier.rst 所对应的 API 文档为核心,结合仓库源码与测试用例,系统讲解该方法的参数语义、时序(as-of)标识符解析机制、底层数据来源与缓存策略,并给出可直接运行的实战示例。读完本文,你将能够根据业务需要,在任意历史时点准确取回指数在各大数据体系中的标识符,并理解其在 gs-quant 证券主数据架构中的位置。
一、方法定位:Index 从何处继承 get_identifier
Index 类定义于 gs_quant/markets/index.py,其声明为:
class Index(Asset, PositionedEntity):
它同时继承自 Asset(资产基类)与 PositionedEntity(持仓实体),因此 Index.get_identifier() 并非 Index 自身定义的方法,而是继承自基类 Asset 在 gs_quant/markets/securities.py 中实现的方法。docs 目录下的 gs_quant.markets.index.Index.get_identifier.rst 正是通过 Sphinx automethod 指令自动生成该方法的参考文档,其完整签名如下:
def get_identifier(self, id_type: AssetIdentifier, as_of: dt.date = None):
方法返回单个标识符值(字符串或 None),与一次性返回全部标识符字典的 get_identifiers(as_of=None)(securities.py)形成互补关系。
二、参数详解:id_type 与 as_of
2.1 id_type:目标标识符类型
id_type 是枚举 AssetIdentifier 的实例,定义于 gs_quant/markets/securities.py。该枚举覆盖了主流证券标识体系,各成员及其取值如下:
| 枚举成员 | 取值 | 说明 | 示例 |
|---|---|---|---|
AssetIdentifier.MARQUEE_ID |
"MQID" |
Goldman Sachs Marquee 内部标识符 | MA4B66MW5E27UAHKG34 |
AssetIdentifier.REUTERS_ID |
"RIC" |
路透/Refinitiv 代码 | GS.N |
AssetIdentifier.BLOOMBERG_ID |
"BBID" |
彭博标识符加交易所代码 | GS UN |
AssetIdentifier.BLOOMBERG_COMPOSITE_ID |
"BCID" |
彭博综合标识符 | GS US |
AssetIdentifier.CUSIP |
"CUSIP" |
美国证券统一识别编号委员会代码 | 38141G104 |
AssetIdentifier.ISIN |
"ISIN" |
国际证券识别编码 | US38141G1040 |
AssetIdentifier.SEDOL |
"SEDOL" |
伦敦证券交易所每日官方列表代码 | 2407966 |
AssetIdentifier.TICKER |
"TICKER" |
交易所代码 | GS |
AssetIdentifier.PLOT_ID |
"PLOT_ID" |
Marquee PlotTool 使用的 ID | — |
AssetIdentifier.GSID |
"GSID" |
高盛证券主数据内部 ID | — |
AssetIdentifier.NAME |
"NAME" |
资产名称 | US Treasury 20y GOVN |
2.2 as_of:标识符的有效日期
as_of 参数用于处理时序性标识符——证券(包括指数)的标识符可能随公司行动(如更名、换交易所、结构调整)而随时间变化。当传入 as_of 时,方法返回该日期在有效区间内的标识符;当省略时,则回退到当前 PricingContext 的定价日期(见下文源码剖析)。
三、官方文档示例:三种典型调用方式
Asset.get_identifier 的 docstring(securities.py)给出了三类官方示例,全部适用于 Index 实例:
3.1 获取当前 SEDOL
import datetime as dt
from gs_quant.markets.index import Index
from gs_quant.markets.securities import AssetIdentifier
# 先通过任意常见标识符解析出 Index 对象(如 Marquee 指数代码)
index = Index.get("GSMBXXXX")
# 获取当前 SEDOL
index.get_identifier(AssetIdentifier.SEDOL)
3.2 指定历史日期获取 SEDOL
index.get_identifier(AssetIdentifier.SEDOL, as_of=dt.date(2018, 1, 1))
3.3 借助 PricingContext 隐式指定 as-of 日期
from gs_quant.markets import PricingContext
with PricingContext(dt.date(2018, 1, 1)) as ctx:
index.get_identifier(AssetIdentifier.SEDOL)
在第三种写法中,PricingContext 为上下文内的所有查询统一设定定价日期,as_of 将自动取自 ctx 的 pricing_date,适合在同一个历史场景下批量查询多个指标时的场景一致性。
四、源码级原理剖析
4.1 两层调用链与 xref 时间过滤
get_identifier 的核心逻辑(securities.py)只有两步:
if id_type == AssetIdentifier.MARQUEE_ID:
return self.get_marquee_id()
ids = self.get_identifiers(as_of=as_of)
return ids.get(id_type.value)
- 特判分支:
MARQUEE_ID无需网络查询,直接由get_marquee_id()返回对象内部的 Marquee ID(Index在构造时即以id_保存该值,见 index.py)。 - 通用分支:委托给
get_identifiers(as_of),其实现(securities.py)通过GsAssetApi.get_asset_xrefs(self.get_marquee_id())从 Marquee 拉取该资产的交叉引用(xref)记录;每条 xref 携带startDate与endDate,代码以start_date <= as_of <= end_date过滤出命中区间的记录,再将其 identifiers 字典按键名(大写后与AssetIdentifier取值比对)筛选后返回。
由此可以推断:标识符的时间有效性由服务端 xref 记录维护,客户端仅负责按 as_of 选取区间。
4.2 默认 as_of 的解析逻辑
省略 as_of 时(securities.py),方法读取 PricingContext.current.pricing_date;若当前上下文尚未进入(is_entered 为 False),则会自动 with current: 进入一次以获取定价日期。返回的 pricing_date 可能是 dt.datetime,此时会被统一转换为 dt.date 后再做区间比较。
4.3 结果缓存策略
get_identifier 上标注了 cachetools.cached 装饰器(securities.py):
@cachetools.cached(
cachetools.TTLCache(256, 600),
lambda s, id_type, as_of=None: cachetools.keys.hashkey(s.get_marquee_id(), id_type, as_of),
threading.RLock(),
)
即:以 (marquee_id, id_type, as_of) 为键缓存,缓存容量 256 条、TTL 600 秒(10 分钟),并在多线程访问时以 RLock 保证线程安全。重复查询同一标识符不会重复发起网络请求,适合在循环中批量解析指数标识符的场景。
五、相关变体:SecMasterAsset 的 get_identifier
值得说明的是,gs_quant/markets/securities.py 中 SecMasterAsset 重写了 get_identifier,其签名扩展为 Union[AssetIdentifier, SecurityIdentifier]:
- 传入
AssetIdentifier时,会先经_ASSET_TO_SECURITY_IDENTIFIER映射转换为对应的SecurityIdentifier(如BLOOMBERG_ID → BBID、REUTERS_ID → RIC、TICKER → TICKER、ISIN → ISIN); - 若无对应等价映射(如
AssetIdentifier.PLOT_ID),则抛出MqTypeError; - 传入普通字符串则直接抛出
MqTypeError——id_type 必须是枚举成员,而非字符串字面量。
该行为已由 gs_quant/test/markets/test_securities.py 中的 test_secmaster_asset_get_identifier_with_security_identifier、test_secmaster_asset_get_identifier_with_asset_identifier、test_secmaster_asset_get_identifier_unsupported_asset_identifier_raises 等用例验证。
六、测试佐证:真实标识符查询行为
仓库测试 gs_quant/test/markets/test_securities.py 展示了携带 as_of=dt.date.today() 的查询断言:
assert asset.get_identifier(AssetIdentifier.REUTERS_ID, as_of=dt.date.today()) == '.GSTHHVIP'
assert asset.get_identifier(AssetIdentifier.BLOOMBERG_ID, as_of=dt.date.today()) == 'GSTHHVIP'
assert asset.get_identifier(AssetIdentifier.CUSIP, as_of=dt.date.today()) == '9EQ24FPE5'
assert asset.get_identifier(AssetIdentifier.TICKER, as_of=dt.date.today()) == 'GSTHHVIP'
这些断言说明:同一资产在同一天内可同时返回多套标识体系的值,验证了 get_identifier 针对不同 id_type 的取值路径相互独立,也印证了 get_identifiers 一次性返回全部可用标识符后按需取值的实现方式。
七、使用注意事项与最佳实践
- 优先使用枚举而非字符串:
id_type必须为AssetIdentifier枚举成员,传入"SEDOL"之类的裸字符串不会生效(对SecMasterAsset会直接抛MqTypeError)。 - 利用缓存避免重复请求:方法自带 10 分钟 TTL 缓存,短时间内的重复查询开销极低;但对不同
as_of的查询会各自成键,历史回溯时应尽量减少as_of取值数量。 - 保持历史查询的场景一致:涉及多个指标的历史查询,建议统一放入同一个
PricingContext,避免各自省略as_of而取到不同定价日期。 - 理解标识符的时效性:返回结果依赖服务端 xref 记录的有效区间;若资产在目标日期尚不存在,可能返回
None,业务侧应做好空值处理。 - 区分数据来源:
Index(继承自Asset)与SecMasterAsset底层数据来源不同(前者走GsAssetApi.get_asset_xrefs,后者走 SecurityMaster 的标识符历史),在需要与证券主数据对齐时,可结合SecurityMaster与SecMasterContext使用对应变体。
结语
Index.get_identifier() 虽是一个签名简洁的 API,背后却串联了 gs-quant 的枚举体系、时序标识符数据模型、PricingContext 日期上下文与本地缓存机制。理解其继承关系(Index → Asset)与 as_of 语义,是正确构建跨市场、跨历史时点指数研究工作流的关键一步。相关参考文档位于 docs/functions/gs_quant.markets.index.Index.get_identifier.rst,完整实现与测试可分别查阅 gs_quant/markets/securities.py 与 gs_quant/test/markets/test_securities.py。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust4.24 K638- DDeepSeek-V4.1-FlashDeepSeek-V4.1-Flash 是一个多模态混合专家(MoE)模型,拥有 5520 亿骨干参数,并支持最多一百万 token 的上下文长度。该模型原生支持图像和文本输入,并以自回归方式生成文本Python650
SlideSCIPPT插件,支持素材库、AI助手、一键添加图片标题,复制粘贴位置、一键图片对齐、一键插入Markdown(加粗、超链接等行内样式、代码块、LaTeX等块级样式)、便捷导出图片!C#180
hello-agents📚 《从零开始构建智能体》——从零开始的智能体原理与实践教程Python52774
new-apiAI模型聚合管理中转分发系统,一个应用管理您的所有AI模型,支持将多种大模型转为统一格式调用,支持OpenAI、Claude、Gemini等格式,可供个人或者企业内部管理与分发渠道使用。🍥 A Unified AI Model Management & Distribution System. Aggregate all your LLMs into one app and access them via an OpenAI-compatible API, with native support for Claude (Messages) and Gemini formats.Go22545
JeecgBoot🔥企业级低代码平台集成了AI应用平台,帮助企业快速实现低代码开发和构建AI应用!前后端分离架构 SpringBoot,SpringCloud、Mybatis,Ant Design4、 Vue3.0、TS+vite!强大的代码生成器让前后端代码一键生成,无需写任何代码! 引领AI低代码开发模式: AI生成->OnlineCoding-> 代码生成-> 手工MERGE,显著的提高效率,又不失灵活~Java36351