API 访问 · 数据产品
构建数据 API
订阅构建数据产品、生成 API 密钥,即可以签名 URL parquet 形式获取每日更新的因子数据。REST 接口,Bearer 鉴权,无需 SDK。
快速开始
- 1
在 /lab/data 订阅产品 — 每个订阅都会授予您的密钥访问该产品数据的权限。
- 2
在账户页面生成 API 密钥。完整密钥仅显示一次,请妥善保存。
- 3
发起第一个请求 — manifest 端点是验证密钥与订阅是否生效的最省事方式:
curl -H "Authorization: Bearer $NUMINOR_KEY" \
https://api.numinor.io/v1/constructs/sam-amplifier/manifest鉴权
每个请求都以 Bearer token 形式发送密钥。一个密钥即可访问您订阅的所有产品(权限由您的有效订阅决定)。Matrix 层密钥不提供 REST 原始导出 — 这是 API 层功能。
Authorization: Bearer nm_live_…核心概念
- 时点延迟
- API 层提供当前数据;Matrix 内层延迟 30 天。每一行都明确标注时点(PIT),确保回测无前视偏差。
- 签名 URL
- 数据端点返回短时效签名 S3 URL(约 4 小时)。直接从 S3 下载 parquet — 该传输不计量、不限流。
- Parquet 格式
- 所有文件均为 Apache Parquet。可用 pyarrow、DuckDB 或 polars 读取 — 常见场景无需服务端查询端点。
- 速率限制
- 每个密钥每分钟最多 1000 次请求。超限返回 429 并附带 Retry-After 响应头。
端点参考
基础 URL: https://api.numinor.io/v1
/constructs/{sku}/manifest产品的数据新鲜度、覆盖范围与签名 URL 有效期。
| 参数 | 位置 | 说明 |
|---|---|---|
| sku* | path | 产品标识,例如 sam-amplifier。 |
curl -H "Authorization: Bearer $NUMINOR_KEY" \
https://api.numinor.io/v1/constructs/sam-amplifier/manifest响应示例
{
"sku": "sam-amplifier-construct-v1",
"tier": "api",
"status": "green",
"latest_trade_date": "2026-06-18",
"signed_url_ttl_seconds": 14400,
"historical_coverage": {
"start": "2016-01-04",
"end": "2026-06-18"
}
}/constructs/{sku}/day/{date}指向某一交易日分区的签名 URL。
| 参数 | 位置 | 说明 |
|---|---|---|
| sku* | path | 产品标识,例如 sam-amplifier。 |
| date* | path | 交易日,格式 YYYYMMDD 或 YYYY-MM-DD。 |
# get a signed URL for one trading day, then download the parquet
curl -H "Authorization: Bearer $NUMINOR_KEY" \
https://api.numinor.io/v1/constructs/sam-amplifier/day/20260515响应示例
{
"url": "https://numinor-construct-data.s3.ap-northeast-2.amazonaws.com/…&X-Amz-Signature=…",
"trade_date": "2026-05-15",
"expires_in": 14400,
"format": "parquet"
}/constructs/{sku}/range日期区间(含端点)内每个已发布交易日的签名 URL。
| 参数 | 位置 | 说明 |
|---|---|---|
| sku* | path | 产品标识,例如 sam-amplifier。 |
| start* | query | 区间起始(含),YYYYMMDD。 |
| end* | query | 区间结束(含),YYYYMMDD。 |
curl -H "Authorization: Bearer $NUMINOR_KEY" \
"https://api.numinor.io/v1/constructs/sam-amplifier/range?start=20260501&end=20260531"响应示例
{
"sku": "sam-amplifier-construct-v1",
"tier": "api",
"count": 21,
"days": [
{
"trade_date": "2026-05-06",
"url": "https://…signed…"
}
],
"format": "parquet"
}/constructs/{sku}/historical指向完整历史批量文件(2016 至今)的签名 URL。
| 参数 | 位置 | 说明 |
|---|---|---|
| sku* | path | 产品标识,例如 sam-amplifier。 |
curl -H "Authorization: Bearer $NUMINOR_KEY" \
https://api.numinor.io/v1/constructs/sam-amplifier/historical响应示例
{
"url": "https://…signed-bulk-file…",
"expires_in": 14400,
"format": "parquet"
}/constructs/{sku}/query内联筛选查询 — 规划中(目前返回 501)。
| 参数 | 位置 | 说明 |
|---|---|---|
| sku* | path | 产品标识,例如 sam-amplifier。 |
# roadmap — returns 501 today
curl -X POST -H "Authorization: Bearer $NUMINOR_KEY" \
https://api.numinor.io/v1/constructs/sam-amplifier/query响应示例
{
"ok": false,
"error": "not_implemented",
"detail": "Roadmap — fetch signed URLs via /day or /range and read the parquet locally."
}字段级导出
购买单个源数据字段 — 在 Matrix 中组装为跨数据集的“配方” — 并在此导出。无需产品标识:一次调用即导出密钥持有者订阅的全部字段。导出为异步 — POST 立即返回一个任务 id,轮询至清单就绪后,从各自的签名 URL 下载每张表一个投影后的 parquet。每次导出都会重新生成当前数据,因此同一调用始终返回最新行;URL 约 3 天后过期,而您的配方将无限期保留。
基础 URL: https://api.numinor.io/v1
/field-export/status用于计划/条件拉取的低成本新鲜度检查:返回您配方的当前版本号(不含数据,无需重新生成)。将其与上次拉取比较——或使用 ETag / If-None-Match 头(未变化时返回 304)——仅在版本号变化时才运行 /field-export。
# scheduled / conditional pull — only export when the data actually changed
LAST=$(cat .numinor_vintage 2>/dev/null)
NOW=$(curl -s -H "Authorization: Bearer $NUMINOR_KEY" https://api.numinor.io/v1/field-export/status | jq -r .vintage)
[ "$NOW" = "$LAST" ] && { echo "no new data"; exit 0; }
echo "$NOW" > .numinor_vintage
# → changed: run the export below, then load the fresh files响应示例
{
"ok": true,
"vintage": "a1b2c3d4e5f6",
"datasets": [
{
"dataset": "rfp_bids",
"vintage": "9a2f1c4e7b83",
"latest_known_date": "20260728",
"major": 3
}
],
"note": "Compare `vintage` (or use the ETag) to your last pull; export only when it changed."
}/field-export异步导出您全部有效字段配方。立即返回任务 id(202)。
# 1) kick the export → job id
JOB=$(curl -s -X POST -H "Authorization: Bearer $NUMINOR_KEY" \
https://api.numinor.io/v1/field-export | jq -r .job_id)
# 2) poll until ready
until [ "$(curl -s -H "Authorization: Bearer $NUMINOR_KEY" \
https://api.numinor.io/v1/field-export/jobs/$JOB | jq -r .status)" = "ready" ]; do sleep 3; done
# 3) grab the signed per-table URLs
curl -s -H "Authorization: Bearer $NUMINOR_KEY" \
https://api.numinor.io/v1/field-export/jobs/$JOB | jq -r '.manifest.tables[].file.url'响应示例
{
"ok": true,
"job_id": "b3f1c0a2-5e6d-4c7b-9a01-2f3e4d5c6b7a",
"status": "pending",
"reused": false,
"poll_url": "/v1/field-export/jobs/b3f1c0a2-5e6d-4c7b-9a01-2f3e4d5c6b7a"
}/field-export/jobs/{job_id}轮询任务。状态为 ready 时携带签名的分表下载清单;failed 时携带原因。
| 参数 | 位置 | 说明 |
|---|---|---|
| job_id* | path | POST /field-export 返回的任务 id。 |
curl -H "Authorization: Bearer $NUMINOR_KEY" \
https://api.numinor.io/v1/field-export/jobs/b3f1c0a2-5e6d-4c7b-9a01-2f3e4d5c6b7a响应示例
{
"ok": true,
"status": "ready",
"manifest": {
"recipe": {
"datasets": [
"sam"
],
"table_count": 1,
"paid_field_count": 2
},
"url_expires_in_seconds": 259200,
"tables": [
{
"dataset": "sam",
"table": "fin_secu_sam_product",
"rows": 991882,
"columns": [
"secu",
"report_date",
"product_income",
"_known_date",
"_panel_op"
],
"keys": [
"secu",
"report_date"
],
"file": {
"name": "sam__fin_secu_sam_product.parquet",
"url": "https://…signed…"
}
}
],
"readme": "Each file is one table, projected to your fields + free join keys + version columns…"
}
}错误码
| 状态 | 错误 | 含义 |
|---|---|---|
| 401 | missing_bearer_token · invalid_api_key | 缺少或无效的 API 密钥。 |
| 403 | not_subscribed · rest_requires_api_tier | 您的密钥没有该产品的 API 层订阅(或仅有 Matrix 层)。 |
| 404 | unknown_construct · no_partition | 未知产品,或该日期无已发布分区。 |
| 400 | bad_date · bad_range · missing_params | 日期或区间格式有误,或缺少查询参数。 |
| 413 | range_too_large | 区间跨越天数过多 — 请改用历史批量文件。 |
| 429 | rate_limited | 超出速率限制(1000/分钟)。请遵循 Retry-After 响应头。 |
| 501 | not_implemented | 该端点尚在规划中,暂未实现。 |