gangtise-openapi-cli 0.36.0 → 0.37.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +53 -19
- package/dist/src/cli.js +9 -4
- package/dist/src/core/client.js +5 -4
- package/dist/src/core/commandBodies.js +17 -2
- package/dist/src/core/download.js +16 -6
- package/dist/src/version.js +1 -1
- package/gangtise-openapi/SKILL.md +37 -13
- package/gangtise-openapi/references/commands/indicator.md +85 -33
- package/gangtise-openapi/references/commands/insight.md +5 -5
- package/gangtise-openapi/references/commands/reference-and-lookup.md +3 -3
- package/gangtise-openapi/references/commands/vault.md +1 -1
- package/gangtise-openapi/references/examples.md +2 -2
- package/gangtise-openapi/references/fields.md +24 -3
- package/gangtise-openapi/references/lookup-ids.md +2 -2
- package/gangtise-openapi/references/response-schema.md +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -6,11 +6,11 @@
|
|
|
6
6
|
|
|
7
7
|
README 仅列最近 5 个版本摘要:
|
|
8
8
|
|
|
9
|
-
- **v0.
|
|
10
|
-
- **v0.
|
|
9
|
+
- **v0.37.1 — 2026-08-31**:**文档修正,无代码变更**。① `indicator screener` 用静态属性选股的示例补进 README——`pty_*`(经营范围·注册地…)/ `scr_*`(上市板块·ISIN…)两族用 `--indicator-param "F1:"`(冒号后留空)声明该指标不吃查询日期后,可直接用于条件选股(v0.36.0 起支持),此前 README 示例仍写着要先用 `cross-section` 取回再本地筛。② **数据权限时间范围的说明按实测更正**:这个窗口按**账号**配、不按接口配——`indicator` 的 `cross-section` / `time-series` / `screener` 与 `quote day-kline` 在同一条边界上,**撞到 `110003` 换接口绕不过去**,正确做法是把日期移进权限范围,或联系客户经理开通更长历史;文档此前建议的「`screener` 撞界改用 `cross-section` 拉数再本地筛」已不适用。③ EDE 文本筛选示例换成有区分度的条件,避免示例条件把整个板块原样返回、看不出筛选是否生效。
|
|
10
|
+
- **v0.37.0 — 2026-08-29**:🔴 **下载的「智能文件命名」改为默认只读缓存**。省略 `--output` 时仍优先用 `title-cache` 里的真实标题——先 `list` 再 `download` 的常规用法**不受影响,也不产生额外调用**;但**缓存未命中时不再自动回查 list 接口**,改为退回服务端返回的文件名或 `<type>-<id>.<ext>`。回查一次要拉 200 条记录(4 次请求),而这 12 个下载命令里有 9 个的 list 按 0.1 积分/条计费,约 20 积分——这笔开销只用于取一个更易读的文件名,所以改成显式的 `--resolve-title`。加了该参数时,取回的 200 条标题会一并写入缓存,同一批后续下载不再重复回查。⚠️ **依赖旧行为拿中文文件名的脚本**:升级后会得到 ID 文件名,补 `--resolve-title`,或按推荐用法先跑一次 `list`。**另有三项修正**:① 下载已成功、仅标题回查阶段遇到异常响应时,退出码会变成 3(脚本按 `!= 0` 判失败会误判为下载失败),现已隔离——下载完整就是 0;② `indicator cross-section` / `time-series` 的 `--indicator-param` 若写了 `--indicator` 里没有的指标编码(多为拼写错误),此前该参数不会作用到你要查的指标上且没有任何提示,现改为发请求前直接报错并指出是哪个编码(`screener` 一直是这个行为);③ 下载请求的超时改为与其他请求同一套解析逻辑,行为对齐。
|
|
11
|
+
- **v0.36.0 — 2026-08-18**:**日期写法放宽**——`YYYY-MM-DD`、`YYYY/MM/DD`、`YYYYMMDD` 三种「年在前」写法都收,统一归一成 `YYYY-MM-DD` 发出(datetime 只归一日期部分,Unix 时间戳原样透传);「年在后」写法(`01-07-2026`)仍在本地拒绝——接口会按美式「月在前」解析它,欧洲习惯写法会静默拿到差半年的数据,详见「关于日期格式」。**`indicator screener` 支持无日期指标**:`--indicator-param "F1:"`(冒号后留空)声明该指标不要查询日期,`pty_*` / `scr_*` 静态属性两族与 `div_cash_paid_ratio` / `div_cash_yr` / `pty_shr_reg` 现在可以直接用于条件选股(此前只能在 `cross-section` 取回后本地筛),写法与截面一致、可与真实参数共存。**全量拉取的 `total` 封顶探测恢复覆盖 `ai hot-topic`**(v0.35.0 曾跳过)。另:EDE 报错提示同步更新;补充计费说明(`ai hot-topic` 50/篇 的「篇」= 一整份报告;按篇/按条计费的接口查不到内容不扣分)。
|
|
12
|
+
- **v0.35.0 — 2026-08-16**:新增 `--indicator-param "<code>:"`(冒号后留空)声明「这个指标不要查询日期」,用于 `parameterList` 里没有日期参数的指标——`pty_*`(经营范围/注册地/法定代表人…)、`scr_*`(上市市场/上市板块/ISIN…)两族,以及 `div_cash_paid_ratio` / `div_cash_yr` / `pty_shr_reg`。这类指标此前在 `indicator cross-section` 上取不到数(`--date` 必填且会注入 `tradeDate`,而它们不收,整条请求被拒);该写法可与真实参数共存(`"code:" + "code:fiscalYear=2025"`)。**EDE 日期参数报错提示重写**:拆成五种报文形态分别给建议,服务端同时点名「不该有的键」和「缺的键」时直说换哪个,只说了一半时不再瞎猜,多指标批量报错时不再用单数口吻指向其中一个指标。另:`--rank-type` 的说明按实测更正(差别大小取决于关键词,`--search-type` 不影响 `--rank-type 1` 取回哪些条目);`ai hot-topic` 全量拉取跳过 `total` 封顶探测(**已于 v0.36.0 撤回**——该探测不额外计费)。
|
|
11
13
|
- **v0.34.1 — 2026-08-15**:EDE 报告期类指标传错日期参数时,报错里直接给出该改的 CLI 写法(此前只有服务端那句「缺少必填参数 reportDate」,要自己推断该用 `--indicator-param`);该提示对 `100001` / `100003` 两个错误码都生效,并注明少数指标两个日期都要、另有指标要 `fiscalYear`,一律以 `indicator search` 的 `parameterList` 为准。另修复下载文件名缓存在并发写入下可能丢条目的问题(单进程使用不受影响)。
|
|
12
|
-
- **v0.34.0 — 2026-08-15**:跟进 2026-08-14 服务端更新。🔴 **破坏性**:`quote day-kline --security all` 已失效(服务端停止支持),改用 `aShares` / `hkStocks` / `usStocks`,且市场关键字必须单独传(不能与证券代码或另一个关键字混填)——这两种写法 CLI 都会在发请求前报错并指出正确写法;`ai stock-summary` 同理不再接受市场关键字。`day-kline` 现覆盖 A股/港股/美股个股与交易所/概念/行业指数(可混查),三个旧命令 `day-kline-hk`/`day-kline-us`/`index-day-kline` 标记为已下线;`minute-kline` 支持指数。**另两处影响取数完整性的修复**:`quote fund-flow` 把市场关键字与证券代码混填时,此前会只返回那几个代码的数据且不报错("全市场 + 这只"静默变成"只有这只"),现改为本地拦截;`quote index-day-kline --security all` 跨 30 天以上时分片过宽会撞行数上限被截断(标 `partial` + 退出 3),现已调细粒度,同区间可完整取回。另:三大报表新增 `earliestAnncDate`(做时点对齐用它,不要用 `announcementDate`),EDE 报告期类指标改为必须显式传 `reportDate`,错误码提示按新行为更新。
|
|
13
|
-
- **v0.33.0 — 2026-08-09**:四处行为变更,都是把「静默给出看着正常的错结果」改成显式失败——分页端点返回异形首包(含 `data: null`)改退出码 3;`total` 被服务端封顶时探测并标 `totalCapped` + 退出 3(三个 opinion 端点的 `total` 恒为 10000 而实际远不止,全量导出此前会被静默截断);空结果不再在 stdout 留空行、`null` 不再被渲染成一条记录。另补多处帮助文案与 EDE 占位值(个别指标填 `0` 而非 `null`)的说明。
|
|
14
14
|
|
|
15
15
|
### 历史里程碑
|
|
16
16
|
|
|
@@ -260,7 +260,29 @@ gangtise ai knowledge-batch --query 比亚迪 --query 最近热门概念
|
|
|
260
260
|
- **HTTP keep-alive**:所有请求复用同一个 `undici.Agent`(连接池 16),避免重复 TLS 握手。
|
|
261
261
|
- **流式下载**:指定 `--output` 时,二进制响应(PDF 等)直接 `pipeline` 到磁盘,不经过内存缓冲;50MB PDF 内存占用近乎为零。
|
|
262
262
|
- **流式输出**:`jsonl`/`csv` 格式且 `--output` 指定时,超过 1000 行自动切换为逐行写盘,避免一次性构建百 MB 字符串。
|
|
263
|
-
- **自动重试**:5xx / 429 / `ECONNREFUSED` / `ECONNRESET` / `ETIMEDOUT` / `ENOTFOUND` / `EAI_AGAIN` / `UND_ERR_*`(undici 连接/超时类)/ `999999` 系统错误自动指数退避重试 2 次。**贵档端点例外**(one-pager 等生成/提交类 + `tool file-parse` 提交 + 50/篇 的 summary / foreign-report / my-conference 下载 + 单价未公布但保守同档的 pamirs-summary 下载,共 18 个):5xx/超时不重放——**重放会重复扣分**:服务端可能已经执行并计费,重发按次计费的再扣一次,重发按篇/按条计费的会把已交付的行再计一次;仅连接失败、429 与 token 自愈重试。**`indicator`(EDE)端点对 `999999` 不重试**——重放一次已计费的查询没有意义(该码 2026-08-01
|
|
263
|
+
- **自动重试**:5xx / 429 / `ECONNREFUSED` / `ECONNRESET` / `ETIMEDOUT` / `ENOTFOUND` / `EAI_AGAIN` / `UND_ERR_*`(undici 连接/超时类)/ `999999` 系统错误自动指数退避重试 2 次。**贵档端点例外**(one-pager 等生成/提交类 + `tool file-parse` 提交 + 50/篇 的 summary / foreign-report / my-conference 下载 + 单价未公布但保守同档的 pamirs-summary 下载,共 18 个):5xx/超时不重放——**重放会重复扣分**:服务端可能已经执行并计费,重发按次计费的再扣一次,重发按篇/按条计费的会把已交付的行再计一次;仅连接失败、429 与 token 自愈重试。**`indicator`(EDE)端点对 `999999` 不重试**——重放一次已计费的查询没有意义(该码 2026-08-01 前还兼表「查询无数据」,现在无数据是保留行列的占位单元格(统一 `null`),空表另表示整轴 code 未识别)。**终态码 `999011`(凭证无效)/ `140002`(异步生成失败)在任何 HTTP 状态下都不重试**——凭证错不会因重试而变,异步生成失败是终态。
|
|
264
|
+
|
|
265
|
+
<!-- no-replay-endpoints
|
|
266
|
+
上面那句点名的「不重放」端点,完整清单如下(endpoint key,与 `gangtise raw list` 一致):
|
|
267
|
+
ai.earnings-review.get-id
|
|
268
|
+
ai.hot-topic
|
|
269
|
+
ai.investment-logic
|
|
270
|
+
ai.knowledge-batch
|
|
271
|
+
ai.management-discuss-announcement
|
|
272
|
+
ai.management-discuss-earnings-call
|
|
273
|
+
ai.one-pager
|
|
274
|
+
ai.peer-comparison
|
|
275
|
+
ai.research-outline
|
|
276
|
+
ai.theme-tracking
|
|
277
|
+
ai.viewpoint-debate.get-id
|
|
278
|
+
alternative.concept-info
|
|
279
|
+
alternative.concept-securities
|
|
280
|
+
insight.foreign-report.download
|
|
281
|
+
insight.pamirs-summary.download
|
|
282
|
+
insight.summary.download
|
|
283
|
+
tool.file-parse.submit
|
|
284
|
+
vault.my-conference.download
|
|
285
|
+
-->
|
|
264
286
|
- **Token 自愈**:调用返回 `0000001008` / `999002` 时自动强制刷新 Token 并重试一次。
|
|
265
287
|
- **K线/资金流向自动分片**:`quote day-kline --security aShares|hkStocks|usStocks`、`quote fund-flow --security aShares` 等全市场查询自动按日期切分(A股 K线/资金流向 1 天/片、美股 1 天/片、港股 2 天/片;已下线的 `day-kline-hk`/`day-kline-us`/`index-day-kline` 用 `all`,分别 2/1/15 天/片),并发执行后合并结果;按日分片自动跳过周六日。分片时如果用户未传 `--limit`,自动注入 `limit: 10000`(API 上限)避免默认 6000 截断。
|
|
266
288
|
- **Token 内存缓存**:Token 在进程内存中缓存,避免每次请求读盘。
|
|
@@ -301,20 +323,27 @@ gangtise ai knowledge-batch --query 比亚迪 --query 最近热门概念
|
|
|
301
323
|
- `--from` 必须是非负整数,`--size` 必须是正整数;非法数字会在本地直接报 `ValidationError`,不会继续请求 API
|
|
302
324
|
- 安全上限:自动翻页最多 1000 页,防止异常循环
|
|
303
325
|
- 部分页失败、或服务端实际返回行数与 `total` 矛盾(提前短页)时,不丢弃已取到的数据:结果带 `partial: true`(页失败时另有 `failedPages`;K线分片为 `failedShards`;`--format json` 可见),stderr 输出警告,**进程退出码为 3**(完整成功为 0)
|
|
304
|
-
- **`indicator` 命令的退出码 3**(脚本按 `!= 0` 判失败的需留意):服务端整指标/整证券没返回时标 `partial` + `omittedIndicators` / `omittedSecurities` 并退出 3。**2026-08-15 起这个分支基本收不到样本**——服务端现在对解析不了的代码直接报 `100003` 并点名是哪个(指标码拼错 →「指标 xxx 不存在」;证券后缀错,如美股写成 `AAPL.US` 而非 `AAPL.O` →「xxx 不是有效证券或者板块ID」),**无论同批有没有正确的代码都会报**,CLI 相应退出 1。真实的无数据/无覆盖仍是占位单元格 + 退出码 0
|
|
305
|
-
- **分页端点返回 `null` 也退出 3
|
|
306
|
-
- 🔴 **`total` 被服务端封顶时会标 `totalCapped` 并退出 3
|
|
326
|
+
- **`indicator` 命令的退出码 3**(脚本按 `!= 0` 判失败的需留意):服务端整指标/整证券没返回时标 `partial` + `omittedIndicators` / `omittedSecurities` 并退出 3。**2026-08-15 起这个分支基本收不到样本**——服务端现在对解析不了的代码直接报 `100003` 并点名是哪个(指标码拼错 →「指标 xxx 不存在」;证券后缀错,如美股写成 `AAPL.US` 而非 `AAPL.O` →「xxx 不是有效证券或者板块ID」),**无论同批有没有正确的代码都会报**,CLI 相应退出 1。真实的无数据/无覆盖仍是占位单元格 + 退出码 0。占位值统一是 `null`。⚠️ **报告期类指标(`is_*`)的时序上大部分行都是占位**(只有报告期末那几行是真值),`null` 虽被 Excel / pandas / SQL 的聚合跳过,**但行数不变**,手工「总和 ÷ 行数」仍会差几十倍;详见 skill 的 `references/commands/indicator.md`。**条件选股的缺列另有更严的一档**:把缺列的变量当作无法求值,若表达式(按 `&&`/`||` 的布尔结构)再无任何可成立的分支,则**退出码 1 且不输出**——那些行以「通过了该条件」的名义呈现,而条件根本无法证明被执行过。⚠️ 这一档以「服务端返回了命中行」为前提;**零命中时一律退出码 0**(没有行需要被质疑),所以空集不能直接当成「无标的符合条件」——另有两种成因产生**逐字相同**的输出:**日期没落在报告期末**(报告期类指标此时整批 `null`),或**该指标不覆盖这批证券**(如拿 A 股专属指标查港美股)。语义约定:`0` 完整成功(含合法空结果)/`3` 有数据但不完整/`1` 硬失败
|
|
327
|
+
- **分页端点返回 `null` 也退出 3**:分页端点的正常响应是 `{total, list}`,真实的空结果是 `{total: 0, list: []}`。若响应体是 `null`,CLI 在 stderr 告警并**退出码 3**——只给告警的话,脚本无法区分「这个筛选确实没命中」和「这个筛选没生效」。机器格式(jsonl/csv)此时 **stdout 不输出任何字节**(不是空行),`--format json` 仍忠实打印 `null`。⚠️ 带 `--output` 时文件仍会被创建:csv 会写入 3 字节 UTF-8 BOM(Excel 兼容用),jsonl 为 0 字节——**按文件大小判空的脚本要留意 csv 的这 3 个字节**。
|
|
328
|
+
- 🔴 **`total` 被服务端封顶时会标 `totalCapped` 并退出 3**:分页端点的 `total` 若被服务端封顶(返回一个固定上限而非真实条数),省略 `--size` 的全量拉取会**正好取满那个上限就停、且不报任何异常**——导出的文件是截断的却看不出来。现在全量拉取结束后会**多探一行**(`from = total`):探到数据就标 `partial` + `totalCapped` 并退出 3。判据不写死 10000,服务端改配置仍然有效;`total` 诚实时探针返回空、不产生计费。传了 `--size` 的有界请求不做此探测。
|
|
307
329
|
- 分页结果中 `total` 字段会被保留(json 格式输出 `{total, list}`);其他格式下 stderr 输出 `Total: N, showing: M`(json 格式不输出该行)
|
|
308
330
|
|
|
309
331
|
## 智能文件命名
|
|
310
332
|
|
|
311
333
|
下载命令(`summary download`、`pamirs-summary download`、`research download`、`foreign-report download`、`announcement download`、`announcement-hk download`、`announcement-us download`、`official-account download`、`performance-calendar download`、`vault drive-download`、`vault record-download`、`vault my-conference-download`)省略 `--output` 时,自动使用真实标题作为文件名:
|
|
312
334
|
|
|
313
|
-
1. **缓存优先** — 如果之前执行过对应的 `list` 命令,标题已缓存在 `~/.config/gangtise/title-cache.json
|
|
314
|
-
2.
|
|
315
|
-
3. **兜底** — 都找不到时使用服务器返回的原始文件名或 `{type}-{id}.{ext}`
|
|
335
|
+
1. **缓存优先** — 如果之前执行过对应的 `list` 命令,标题已缓存在 `~/.config/gangtise/title-cache.json`,直接使用,**无额外 API 调用、无额外积分**
|
|
336
|
+
2. **兜底** — 缓存未命中时使用服务器返回的原始文件名,无则 `{type}-{id}.{ext}`
|
|
316
337
|
|
|
317
|
-
推荐工作流:先 `list` 再 `download
|
|
338
|
+
推荐工作流:先 `list` 再 `download`,文件名自动正确且零额外成本。
|
|
339
|
+
|
|
340
|
+
🔴 **缓存未命中时不会自动回查 list 接口**(v0.37.0 起)。回查要拉最近 200 条记录(4 次请求),而上面 12 个命令里有 9 个的 list 按 **0.1 积分/条**计费,约 20 积分——这笔开销只用于取一个更易读的文件名(下载本身 10–50 积分),所以改成按需开启。需要时加 `--resolve-title`:
|
|
341
|
+
|
|
342
|
+
```bash
|
|
343
|
+
gangtise insight research download --report-id 432092410345574400 --resolve-title
|
|
344
|
+
```
|
|
345
|
+
|
|
346
|
+
`--resolve-title` 取回的 200 条标题会一并写入缓存,所以同一批后续的下载不再重复回查。带 `--output` 时该参数无效(文件名已由你指定)。
|
|
318
347
|
|
|
319
348
|
## 常用示例
|
|
320
349
|
|
|
@@ -347,10 +376,13 @@ gangtise insight pamirs-summary list --keyword PCB --search-type 2 --rank-type 2
|
|
|
347
376
|
gangtise insight pamirs-summary download --summary-id 5863771 --file-type 2
|
|
348
377
|
# → PCB钻针:高端钻针扩产有壁垒,供需紧缺会持续到28年.html
|
|
349
378
|
|
|
350
|
-
# 下载:先 list 再 download
|
|
379
|
+
# 下载:先 list 再 download,标题已在缓存里,文件名自动正确且零额外成本
|
|
351
380
|
gangtise insight summary download --summary-id 4902586
|
|
352
381
|
# → 超颖电子:2026年4月7日投资者关系活动记录表.txt
|
|
353
382
|
|
|
383
|
+
# 没先跑过 list(缓存未命中)时,默认退回 ID 文件名;要标题就显式回查
|
|
384
|
+
gangtise insight summary download --summary-id 4902586 --resolve-title
|
|
385
|
+
|
|
354
386
|
# 下载 Markdown 版本
|
|
355
387
|
gangtise insight research download --report-id 432092410345574400 --file-type 2
|
|
356
388
|
# 下载外资研报中文翻译版
|
|
@@ -512,9 +544,8 @@ gangtise ai knowledge-batch --query 比亚迪 --query 最近热门概念
|
|
|
512
544
|
gangtise ai knowledge-batch --query 新能源汽车 --resource-type 10 --resource-type 11 --top 10
|
|
513
545
|
gangtise ai security-clue --start-time "2026-04-01 00:00:00" --end-time "2026-04-09 23:59:59" --query-mode byIndustry --gts-code 821035.SWI --source researchReport --source announcement
|
|
514
546
|
gangtise ai one-pager --security-code 600519.SH
|
|
515
|
-
# 个股看点(精炼投研总结,仅 A
|
|
547
|
+
# 个股看点(精炼投研总结,仅 A 股/港股):只收具体代码,单次最多 6000 个;不支持全市场关键字
|
|
516
548
|
gangtise ai stock-summary --security 600519.SH --security 00700.HK --format json
|
|
517
|
-
gangtise ai stock-summary --security hkStocks --format json
|
|
518
549
|
gangtise ai investment-logic --security-code 600519.SH
|
|
519
550
|
gangtise ai peer-comparison --security-code 600519.SH
|
|
520
551
|
gangtise ai earnings-review --security-code 600519.SH --period 2025q3
|
|
@@ -607,9 +638,12 @@ gangtise indicator screener --indicator F1:mgn_flag \
|
|
|
607
638
|
--security 1000000287 --expression "F1 contains '是'" \
|
|
608
639
|
--date 2026-08-13 --format table # 白酒板块里的融资融券标的
|
|
609
640
|
|
|
610
|
-
#
|
|
611
|
-
#
|
|
612
|
-
#
|
|
641
|
+
# 公司/证券静态属性(pty_* 经营范围·注册地 / scr_* 上市板块·ISIN 等)的 parameterList
|
|
642
|
+
# 里没有日期参数,要加一条冒号后留空的绑定声明「该指标不要 --date 注入的 tradeDate」;
|
|
643
|
+
# 截面与选股写法一致,选股上按变量名(F1:)、截面上按指标 code(code:):
|
|
644
|
+
gangtise indicator screener --indicator F1:pty_op_scope --indicator-param "F1:" \
|
|
645
|
+
--security 1000000287 --expression "F1 contains '葡萄酒'" \
|
|
646
|
+
--date 2026-08-13 --format table # 白酒板块里经营范围提到葡萄酒的公司
|
|
613
647
|
gangtise indicator cross-section --indicator pty_op_scope \
|
|
614
648
|
--indicator-param "pty_op_scope:" \
|
|
615
649
|
--security 1000000287 --date 2026-08-13 --format jsonl | grep 酒
|
|
@@ -747,7 +781,7 @@ datetime 参数(`--start-time` / `--end-time`)同理,只归一日期部分
|
|
|
747
781
|
| `999010` | 接口地址不存在(`raw call` 的 key 可能已下线,用 `raw list` 核对) |
|
|
748
782
|
| `999012` / `999013` / `999014` | 账号禁用 / 已过期 / 租户失效 |
|
|
749
783
|
| `999016` | 调用方 IP 不在允许范围 |
|
|
750
|
-
| `999999` | Gangtise 系统错误,请稍后重试(`indicator` 端点的「无数据」已不再用此码——有效 code
|
|
784
|
+
| `999999` | Gangtise 系统错误,请稍后重试(`indicator` 端点的「无数据」已不再用此码——有效 code 无数据返回占位单元格(统一 `null`),此码基本只剩真故障) |
|
|
751
785
|
| `140002` | 终态失败:AI 异步生成失败,或 `indicator` 的参数/表达式错误(枚举越界、语法错)——改参数重提,不重试 |
|
|
752
786
|
| `100003` | 参数值非法——**最宽的兜底码**;msg 通常已指明字段(如「limit 最小为 1,最大为 10000」),先读 msg |
|
|
753
787
|
| `100001` | 缺必填参数(msg 带字段名,如「缺少必填参数: reportId」) |
|
package/dist/src/cli.js
CHANGED
|
@@ -56,6 +56,9 @@ function addDownloadCommand(parent, spec) {
|
|
|
56
56
|
}
|
|
57
57
|
if (spec.contentTypeDescription)
|
|
58
58
|
cmd.requiredOption("--content-type <type>", spec.contentTypeDescription);
|
|
59
|
+
if (spec.titleListEndpoint) {
|
|
60
|
+
cmd.option("--resolve-title", "On a title-cache miss, query the list endpoint for a friendly filename (4 extra requests; most of these list endpoints bill per row). Without it the server filename or <prefix>-<id> is used. Ignored when --output is given");
|
|
61
|
+
}
|
|
59
62
|
cmd.option("--output <path>").action((options) => withClient(async (client) => {
|
|
60
63
|
const id = options[spec.idField];
|
|
61
64
|
const qp = { [spec.idField]: id };
|
|
@@ -67,7 +70,9 @@ function addDownloadCommand(parent, spec) {
|
|
|
67
70
|
await runDownload(client, spec.endpointKey, qp, {
|
|
68
71
|
output: options.output,
|
|
69
72
|
fallbackName: `${spec.fallbackPrefix}-${id}`,
|
|
70
|
-
resolveOutputPath: titleList
|
|
73
|
+
resolveOutputPath: titleList
|
|
74
|
+
? (result) => resolveTitle(client, result, titleList, spec.idField, id, { allowLookup: Boolean(options.resolveTitle) })
|
|
75
|
+
: undefined,
|
|
71
76
|
});
|
|
72
77
|
}));
|
|
73
78
|
}
|
|
@@ -300,7 +305,7 @@ addTimeFilters(announcementUs.command("list").addOption(new Option("--search-typ
|
|
|
300
305
|
securityList: maybeArray(options.security), categoryList: maybeArray(options.category),
|
|
301
306
|
}), { endpointKey: "insight.announcement-us.list", idField: "announcementId" }));
|
|
302
307
|
addDownloadCommand(announcementUs, { endpointKey: "insight.announcement-us.download", idOption: "--announcement-id", idField: "announcementId", fallbackPrefix: "announcement-us", fileType: { description: "File type: 1=original PDF 2=Markdown", choices: ["1", "2"], default: "1" }, titleListEndpoint: "insight.announcement-us.list" });
|
|
303
|
-
addTimeFilters(foreignOpinion.command("list").addOption(new Option("--rank-type <number>", "Rank type: 1=composite 2=time desc").choices(["1", "2"]).default("1")).option("--security <code>", "Security code (e.g. UBER.N)", collectList, []).option("--region <code>", "Region code --
|
|
308
|
+
addTimeFilters(foreignOpinion.command("list").addOption(new Option("--rank-type <number>", "Rank type: 1=composite 2=time desc").choices(["1", "2"]).default("1")).option("--security <code>", "Security code (e.g. UBER.N)", collectList, []).option("--region <code>", "Region code -- this endpoint accepts only cn/cnHk/cnTw/us/jp/uk; the other 13 values of regionCategory (sea/gl/fr/de/kr/in/ca/me/othAs/othEur/latAm/oce/af) are rejected here with 100005 though they all work on foreign-report", collectList, []).option("--industry <id>", "Industry ID -- swIndustry codes only (104xx0000); citicIndustry codes are rejected with 100005 even where constant-category declares them", collectList, []).option("--broker <id>", "Broker ID", collectList, []).option("--rating <name>", "Rating", collectList, []).option("--rating-change <name>", "Rating change", collectList, []).option("--format <format>", "Output format", "table").option("--output <path>", "Output path")).action((options) => emit(options, (client) => client.call("insight.foreign-opinion.list", {
|
|
304
309
|
from: parseFrom(options.from), size: parseSize(options.size),
|
|
305
310
|
startTime: options.startTime, endTime: options.endTime,
|
|
306
311
|
rankType: parseNumberOption(options.rankType, "--rank-type", { integer: true, min: 1 }),
|
|
@@ -309,7 +314,7 @@ addTimeFilters(foreignOpinion.command("list").addOption(new Option("--rank-type
|
|
|
309
314
|
securityList: maybeArray(options.security), brokerList: maybeArray(options.broker),
|
|
310
315
|
ratingList: maybeArray(options.rating), ratingChangeList: maybeArray(options.ratingChange),
|
|
311
316
|
})));
|
|
312
|
-
addTimeFilters(independentOpinion.command("list").addOption(new Option("--rank-type <number>", "Rank type: 1=composite 2=time desc").choices(["1", "2"]).default("1")).option("--security <code>", "Security code (e.g. GSK.N)", collectList, []).option("--industry <id>", "Industry ID --
|
|
317
|
+
addTimeFilters(independentOpinion.command("list").addOption(new Option("--rank-type <number>", "Rank type: 1=composite 2=time desc").choices(["1", "2"]).default("1")).option("--security <code>", "Security code (e.g. GSK.N)", collectList, []).option("--industry <id>", "Industry ID -- swIndustry codes only (104xx0000); citicIndustry codes are rejected with 100005 even where constant-category declares them", collectList, []).option("--rating <name>", "Rating", collectList, []).option("--rating-change <name>", "Rating change", collectList, []).option("--format <format>", "Output format", "table").option("--output <path>", "Output path")).action((options) => emit(options, (client) => client.call("insight.independent-opinion.list", {
|
|
313
318
|
from: parseFrom(options.from), size: parseSize(options.size),
|
|
314
319
|
startTime: options.startTime, endTime: options.endTime,
|
|
315
320
|
rankType: parseNumberOption(options.rankType, "--rank-type", { integer: true, min: 1 }),
|
|
@@ -421,7 +426,7 @@ quote.command("realtime").description("Realtime quote snapshot (A-share / HK / U
|
|
|
421
426
|
checkMarketKeywords(options.security, REALTIME_MARKETS, "quote realtime");
|
|
422
427
|
return emit(options, (client) => client.call("quote.realtime", { securityList: maybeArray(options.security), fieldList: maybeArray(options.field) }));
|
|
423
428
|
});
|
|
424
|
-
quote.command("fund-flow").description("A-share daily fund flow (SH/SZ/BJ)").option("--security <code>", "Security code (e.g. 600519.SH /
|
|
429
|
+
quote.command("fund-flow").description("A-share daily fund flow (SH/SZ/BJ)").option("--security <code>", "Security code (e.g. 600519.SH / 920982.BJ), or 'aShares' for full A-share market — auto-sharded by day (repeat)", collectList, []).option("--start-date <date>", "Start date yyyy-MM-dd (default: endDate minus 1 year)", dateArg("--start-date")).option("--end-date <date>", "End date yyyy-MM-dd (default: latest trading day)", dateArg("--end-date")).option("--limit <number>", "Max rows per request (default: 6000, max: 10000; single-security cap — aShares auto-shards by day)").option("--field <field>", "Field, e.g. mainNetInflow/largeInflow/xlargeOutflow (repeat); omit for all", collectList, []).option("--format <format>", "Output format", "table").option("--output <path>").action((options) => {
|
|
425
430
|
checkMarketKeywords(options.security, FUND_FLOW_MARKETS, "quote fund-flow");
|
|
426
431
|
options.security = canonicalizeMarketKeywords(options.security, FUND_FLOW_MARKETS);
|
|
427
432
|
return withClient(async (client) => {
|
package/dist/src/core/client.js
CHANGED
|
@@ -378,6 +378,7 @@ export class GangtiseClient {
|
|
|
378
378
|
url.searchParams.set(key, String(value));
|
|
379
379
|
});
|
|
380
380
|
const authState = { retried: false };
|
|
381
|
+
const timeoutMs = resolveTimeoutMs(this.config.timeoutMs, endpoint);
|
|
381
382
|
return withRetry(async () => {
|
|
382
383
|
const authorization = await this.getAuthorizationHeader();
|
|
383
384
|
const startedAt = Date.now();
|
|
@@ -390,8 +391,8 @@ export class GangtiseClient {
|
|
|
390
391
|
? { Authorization: authorization, 'content-type': 'application/json' }
|
|
391
392
|
: { Authorization: authorization },
|
|
392
393
|
body: isPost ? JSON.stringify(body ?? {}) : undefined,
|
|
393
|
-
headersTimeout:
|
|
394
|
-
bodyTimeout:
|
|
394
|
+
headersTimeout: timeoutMs,
|
|
395
|
+
bodyTimeout: timeoutMs,
|
|
395
396
|
dispatcher,
|
|
396
397
|
});
|
|
397
398
|
for (let hops = 0; hops < 3 && response.statusCode >= 300 && response.statusCode < 400; hops++) {
|
|
@@ -407,8 +408,8 @@ export class GangtiseClient {
|
|
|
407
408
|
response = await request(currentUrl, {
|
|
408
409
|
method: 'GET',
|
|
409
410
|
headers: auth ? { Authorization: auth } : {},
|
|
410
|
-
headersTimeout:
|
|
411
|
-
bodyTimeout:
|
|
411
|
+
headersTimeout: timeoutMs,
|
|
412
|
+
bodyTimeout: timeoutMs,
|
|
412
413
|
dispatcher,
|
|
413
414
|
});
|
|
414
415
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { maybeArray, parseFrom, parseIndicatorParams, parseOptionalNumberOption, parseScreenerIndicators, parseSize } from "./args.js";
|
|
2
|
+
import { ValidationError } from "./errors.js";
|
|
2
3
|
export function buildQuoteKlineBody(options) {
|
|
3
4
|
return {
|
|
4
5
|
securityList: maybeArray(options.security),
|
|
@@ -35,6 +36,16 @@ export function buildStockPoolStocksBody(options) {
|
|
|
35
36
|
};
|
|
36
37
|
}
|
|
37
38
|
const DATE_PARAM_KEYS = new Set(["tradeDate", "reportDate"]);
|
|
39
|
+
function assertParamCodesBound(groups, codes) {
|
|
40
|
+
if (!groups?.length)
|
|
41
|
+
return;
|
|
42
|
+
const bound = new Set(codes);
|
|
43
|
+
for (const group of groups) {
|
|
44
|
+
if (!bound.has(group.indicatorCode)) {
|
|
45
|
+
throw new ValidationError(`--indicator-param references "${group.indicatorCode}", which no --indicator names`);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
38
49
|
function withQueryDate(groups, codes, date) {
|
|
39
50
|
const merged = new Map();
|
|
40
51
|
for (const group of groups ?? [])
|
|
@@ -55,15 +66,19 @@ function stripMarker(item) {
|
|
|
55
66
|
return rest;
|
|
56
67
|
}
|
|
57
68
|
export function buildIndicatorCrossSectionBody(options) {
|
|
69
|
+
const groups = parseIndicatorParams(options.indicatorParam);
|
|
70
|
+
assertParamCodesBound(groups, options.indicator);
|
|
58
71
|
return {
|
|
59
72
|
indicatorCodeList: maybeArray(options.indicator),
|
|
60
73
|
universe: maybeArray(options.security),
|
|
61
74
|
currency: options.currency,
|
|
62
75
|
scale: options.scale,
|
|
63
|
-
indicatorParamList: withQueryDate(
|
|
76
|
+
indicatorParamList: withQueryDate(groups, options.indicator, options.date),
|
|
64
77
|
};
|
|
65
78
|
}
|
|
66
79
|
export function buildIndicatorTimeSeriesBody(options) {
|
|
80
|
+
const groups = parseIndicatorParams(options.indicatorParam);
|
|
81
|
+
assertParamCodesBound(groups, options.indicator);
|
|
67
82
|
return {
|
|
68
83
|
indicatorCodeList: maybeArray(options.indicator),
|
|
69
84
|
universe: maybeArray(options.security),
|
|
@@ -72,7 +87,7 @@ export function buildIndicatorTimeSeriesBody(options) {
|
|
|
72
87
|
calendarType: options.calendarType,
|
|
73
88
|
currency: options.currency,
|
|
74
89
|
scale: options.scale,
|
|
75
|
-
indicatorParamList: (
|
|
90
|
+
indicatorParamList: (groups ?? []).map(stripMarker),
|
|
76
91
|
};
|
|
77
92
|
}
|
|
78
93
|
export function buildIndicatorScreenerBody(options) {
|
|
@@ -2,7 +2,7 @@ import fs from "node:fs/promises";
|
|
|
2
2
|
import { extname } from "node:path";
|
|
3
3
|
import { DownloadError } from "./errors.js";
|
|
4
4
|
import { saveOutputIfNeeded } from "./output.js";
|
|
5
|
-
import { lookupTitleCache, readTitleCache, TITLE_LOOKUP_SIZE } from "./titleCache.js";
|
|
5
|
+
import { extractTitles, lookupTitleCache, readTitleCache, TITLE_LOOKUP_SIZE, writeTitleCache } from "./titleCache.js";
|
|
6
6
|
function sanitizeFilename(name) {
|
|
7
7
|
return name.replace(/[/\\:*?"<>|\u0000-\u001f]/g, "_");
|
|
8
8
|
}
|
|
@@ -60,7 +60,8 @@ export function extFromContentType(contentType) {
|
|
|
60
60
|
const mime = contentType.split(";")[0].trim().toLowerCase();
|
|
61
61
|
return MIME_EXT[mime] ?? "";
|
|
62
62
|
}
|
|
63
|
-
export async function resolveTitle(client, result, listEndpoint, idField, idValue,
|
|
63
|
+
export async function resolveTitle(client, result, listEndpoint, idField, idValue, options = {}) {
|
|
64
|
+
const titleField = options.titleField ?? "title";
|
|
64
65
|
const file = result;
|
|
65
66
|
const serverExt = file.filename ? extname(file.filename) : extFromContentType(file.contentType);
|
|
66
67
|
function buildFilename(rawTitle) {
|
|
@@ -78,17 +79,26 @@ export async function resolveTitle(client, result, listEndpoint, idField, idValu
|
|
|
78
79
|
}
|
|
79
80
|
catch {
|
|
80
81
|
}
|
|
82
|
+
if (!options.allowLookup)
|
|
83
|
+
return undefined;
|
|
84
|
+
const previousExitCode = process.exitCode;
|
|
81
85
|
try {
|
|
82
86
|
const resp = await client.call(listEndpoint, { from: 0, size: TITLE_LOOKUP_SIZE });
|
|
83
|
-
const items = Array.isArray(resp) ? resp : (resp
|
|
84
|
-
const
|
|
85
|
-
|
|
86
|
-
|
|
87
|
+
const items = Array.isArray(resp) ? resp : (resp?.list ?? []);
|
|
88
|
+
const titles = extractTitles(items, { endpointKey: listEndpoint, idField, titleField });
|
|
89
|
+
if (Object.keys(titles).length > 0) {
|
|
90
|
+
await writeTitleCache(listEndpoint, titles).catch(() => { });
|
|
91
|
+
}
|
|
92
|
+
const rawTitle = titles[String(idValue)];
|
|
93
|
+
if (rawTitle)
|
|
87
94
|
return buildFilename(rawTitle);
|
|
88
95
|
}
|
|
89
96
|
catch {
|
|
90
97
|
return undefined;
|
|
91
98
|
}
|
|
99
|
+
finally {
|
|
100
|
+
process.exitCode = previousExitCode;
|
|
101
|
+
}
|
|
92
102
|
return undefined;
|
|
93
103
|
}
|
|
94
104
|
async function downloadUrlTo(url, outputPath) {
|
package/dist/src/version.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export const CLI_VERSION = "0.
|
|
1
|
+
export const CLI_VERSION = "0.37.1";
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: gangtise-openapi
|
|
3
|
-
version: "0.
|
|
3
|
+
version: "0.37.1"
|
|
4
4
|
description: |-
|
|
5
5
|
通过 gangtise CLI 直接调用 Gangtise OpenAPI,拉取投研原始数据、批量导出、下载文件、调用 AI 能力。
|
|
6
6
|
|
|
@@ -38,7 +38,7 @@ description: |-
|
|
|
38
38
|
8. **参数命名差异**:Insight/Quote/Vault 用 `--security`,Fundamental/AI 用 `--security-code`(例外:`ai stock-summary` 用 `--security`,`ai security-clue` 用 `--gts-code`)。
|
|
39
39
|
9. **调试**:`--verbose` 或 `GANGTISE_VERBOSE=1` 打印每个请求的耗时/字节数到 stderr。
|
|
40
40
|
10. **`--field` 字段名必须核对,不确定就别传**(返回全量最稳):`quote realtime` / `fundamental main-business` / `valuation-analysis` 遇到不存在的字段名时,上游只丢**值**、字段名照请求**回显**,按位置拍平会把值贴到错误的字段上(实测 realtime 传 `close`——它没有这个字段——换手率 28.5573 被贴成 `close`,茅台真实价 1297.41)。v0.28.3 起 CLI 检测到长度不匹配直接报错(退出码 1):**带 `--field` 的命令看到这个报错,先去 `references/fields.md` 核对字段名**(没有 `--field` 的命令如 `alternative edb-data` 报此错则是上游响应结构异常,报障时若报错末尾附了 `(trace …)` 就一并带上)。另:realtime **无 `close`**(用 `latestPrice`)、**无市值**(总市值走 `indicator cross-section --indicator qte_mkt_cptl`,2026-08-03 起 A/港/美股均有数)。
|
|
41
|
-
11. 🔴 **EDE
|
|
41
|
+
11. 🔴 **EDE 取不到数时返 `null` 占位,行列都保留**(`indicator` 截面 / 时序 / 选股),无告警、退出码 0。**报告期类指标(`is_*`)的时序尤其要当心**:按日返回,**只有报告期末那几行是真值**——茅台 `is_dnrpnp` 查 5 个月共 104 行,只有 2 行有数,其余全是 `null`,而时序没有任何参数能只返回报告期末。`null` 会被 Excel / pandas / SQL 的聚合跳过(**但 `jq` 不跳过**——`add/length` 会把 `null` 计入分母,得到偏低几十倍的值,要先 `map(select(. != null))`),且**行数不会变**,手工「总和 ÷ 行数」同样会差几十倍。截面上日期不落在报告期末时整批返 `null`,`screener` 会筛出空集——**那是日期用错了,不是「没有符合条件的标的」**。所以:报告期类指标的日期一律落**报告期末**(`03-31` / `06-30` / `09-30` / `12-31`),截面用 `--indicator-param "F1:reportDate=..."` 显式给;**别对时序整列直接求均值 / 求和**。详见 `references/commands/indicator.md`。
|
|
42
42
|
|
|
43
43
|
## 工作流(3 步)
|
|
44
44
|
|
|
@@ -52,7 +52,7 @@ description: |-
|
|
|
52
52
|
- `gangtise auth status` 未登录 → 提示配置 AK/SK 并中止
|
|
53
53
|
- 多个命令同时匹配 → 复述理解让用户挑(如"搜索研报" → research list 还是 knowledge-batch?)
|
|
54
54
|
- 用户说"全部 / 全量 / 全市场" → 确认量级再拉:省略 `--size` 就是拉全量(自动翻页,上限 1000 页);先 `--size 1` 看 stderr 的 `Total: N` 再决定(探量这步别加 `--format json`——json 下不打 `Total` 行);全市场/跨一年分片等大批量可 `GANGTISE_PAGE_CONCURRENCY=10` 提速(默认 5,同时管翻页与 K 线分片)
|
|
55
|
-
- **高积分操作先确认**:任何 50 积分/次及以上、或"按条 × 大批量"(如 `stock-summary`
|
|
55
|
+
- **高积分操作先确认**:任何 50 积分/次及以上、或"按条 × 大批量"(如 `stock-summary` 按代码批量数千只、`opinion` 全量翻页、`concept-info` 500/次)→ 先估总积分告知用户再执行(单价见下「积分计费速查」)
|
|
56
56
|
- 下载**必选**格式未定才问:`independent-opinion --file-type`(必选)、`vault record/my-conference --content-type`(record 三种 original/asr/summary、my-conference 两种 asr/summary);其余 download 有默认(多为 `1`=PDF/原始),用户没提格式就用默认、不必问
|
|
57
57
|
- list→download 用户没指定具体文件 → 展示前 10 条让用户挑
|
|
58
58
|
|
|
@@ -80,6 +80,28 @@ description: |-
|
|
|
80
80
|
- ✅ **按篇 / 按条计费的接口,没查到内容就不扣分**(空结果 = 0 积分):各 download(`pamirs-summary` 除外,见 ②)、`ai hot-topic`(50/篇)、`ai stock-summary`(3/条,无看点总结的个股不进返回列表也不计费)。**所以「先小范围试探再放大」是安全的**——先用窄条件确认能查到东西,再扩范围。⚠️ **两类不适用**:① **按次计费的**——`ai knowledge-batch` / `management-discuss-*`、AI Agent 那批 50/次、`alternative concept-info` / `concept-securities` 500/次,不管有没有内容都扣,超时报错也可能已经扣过;② **单价未公布的**——`pamirs-summary`(见下),别据此假定
|
|
81
81
|
- ⚠️ **同参数重复调用不免费**:按次计费的那批无缓存命中豁免(2026-07-11 实测 `one-pager` 重复调用每次扣分,即使秒回缓存内容);**按篇/按条的也一样**——重拉同一批 `hot-topic` 就是按条数再计一次费。生成类与列表结果拿到后自行留存复用,别为「刷新」重调
|
|
82
82
|
- ⚠️ **贵档端点超时/5xx 不自动重放**(共 18 个:AI Agent 那批 + `ai knowledge-batch` / `management-discuss-*` / `hot-topic`、`alternative concept-info`·`concept-securities`、50/篇 的 `summary`·`foreign-report`·`my-conference` download 与同档处理的 `pamirs-summary` download、`tool file-parse` 提交)。**理由是重放会重复扣分**——服务端可能已经执行并计费,重发按次计费的会再扣一次,重发按篇/按条计费的会把**已交付的行**再计一次;两种都亏。仅连接失败、429 与 token 自愈会重试
|
|
83
|
+
|
|
84
|
+
<!-- no-replay-endpoints
|
|
85
|
+
上面那句点名的「不重放」端点,完整清单如下(endpoint key,与 `gangtise raw list` 一致):
|
|
86
|
+
ai.earnings-review.get-id
|
|
87
|
+
ai.hot-topic
|
|
88
|
+
ai.investment-logic
|
|
89
|
+
ai.knowledge-batch
|
|
90
|
+
ai.management-discuss-announcement
|
|
91
|
+
ai.management-discuss-earnings-call
|
|
92
|
+
ai.one-pager
|
|
93
|
+
ai.peer-comparison
|
|
94
|
+
ai.research-outline
|
|
95
|
+
ai.theme-tracking
|
|
96
|
+
ai.viewpoint-debate.get-id
|
|
97
|
+
alternative.concept-info
|
|
98
|
+
alternative.concept-securities
|
|
99
|
+
insight.foreign-report.download
|
|
100
|
+
insight.pamirs-summary.download
|
|
101
|
+
insight.summary.download
|
|
102
|
+
tool.file-parse.submit
|
|
103
|
+
vault.my-conference.download
|
|
104
|
+
-->
|
|
83
105
|
- **按单元格**:`indicator cross-section` / `time-series` / `screener`(A股 0.05 / 港股 0.1 / 美股 0.2 积分每 100 单元格;screener 按**筛选前**范围计费,见 `indicator.md`);`ai knowledge-resource-download` 按下游资源计费
|
|
84
106
|
- **单价未公布**:`insight pamirs-summary list` / `download`——spec 只写了「需购买专家纪要数据库」这个准入门槛,没给单次价格。**别据此假定免费**;大批量拉取前先小量试,或向平台确认
|
|
85
107
|
|
|
@@ -95,7 +117,7 @@ description: |-
|
|
|
95
117
|
| 管理层讨论 / A·港·美股公告 / `alternative edb-*` 行业指标 | 前溯 **3 年**(原 1 年) |
|
|
96
118
|
| `insight pamirs-summary` 帕米尔纪要 | **不限**(但需单独购买专家纪要库) |
|
|
97
119
|
|
|
98
|
-
⚠️
|
|
120
|
+
⚠️ **这是官方口径,不是硬边界**:服务端按**账号**配这个时间窗口、不按接口配——**换接口绕不过去**(实测 `indicator` 三接口与 `quote day-kline` 逐日同界)。超范围查询返回 `110003`,**不是空结果**——拿到 `110003` 就是撞了权限边界,缩窗口对「整段都在界外」的查询无效,要把日期移进范围或联系客户经理。
|
|
99
121
|
|
|
100
122
|
### 下载规则(`--file-type` / `--content-type`)
|
|
101
123
|
|
|
@@ -113,7 +135,9 @@ description: |-
|
|
|
113
135
|
| `vault record-download` | `--content-type` | `original` 原始文件 / `asr` 语音识别 / `summary` AI 速记 |
|
|
114
136
|
| `vault my-conference-download` | `--content-type` | `asr` 语音识别 / `summary` AI 速记 |
|
|
115
137
|
|
|
116
|
-
省略 `--output` 时 CLI
|
|
138
|
+
省略 `--output` 时 CLI 用本地 title-cache 里的真实标题做文件名——**只读缓存**,命中就零额外调用。缓存由同端点的 `list` 写入,所以「先 `list` 再 `download`」这个正常工作流本来就免费拿到正确文件名。
|
|
139
|
+
|
|
140
|
+
🔴 **未命中时默认不回查**(v0.37.0 起),退回服务端文件名或 `<type>-<id>.<ext>`。要回查得显式加 `--resolve-title`——它拉最近 200 条(4 次请求),而这些 list 多数按 **0.1 积分/条**计费,约 20 积分,只用于取一个更易读的文件名(下载本身 10–50)。**批量下载或按 ID 下旧文件**时:要么先跑一次 `list` 把标题灌进缓存,要么直接 `--output ./<名>.<ext>` 自己定名;`--resolve-title` 会把取回的 200 条一并写回缓存,同批后续下载不再重复消耗。
|
|
117
141
|
|
|
118
142
|
## 意图路由表
|
|
119
143
|
|
|
@@ -194,8 +218,8 @@ description: |-
|
|
|
194
218
|
- EDE 取数前必须用 `search --format json` 同时核对:`indicatorName` + `description` 语义准确、`scopeList` 覆盖全部目标市场 / 证券类型、`parameterList` 必填参数与枚举可满足;`scopeList` 缺失 / `null` / 空或任一项不符,都视为无法证明覆盖并回退专用接口。专用接口也不覆盖目标市场时,说明当前不可用,不要硬调。`scopeList` 按指标各不相同,不能因 EDE 服务支持 A / 港 / 美股就假定某个指标三市场都覆盖
|
|
195
219
|
- `indicator search` 免费,`cross-section` / `time-series` 按单元格计费;除多证券批量的效率收益外,仍优先免费 / 低价的 `quote` 或 `fundamental`
|
|
196
220
|
- 行业 / 宏观指标(空调销量、社融等,无证券维度)走 `alternative edb-*`(EDB),不要与证券级 EDE 混用
|
|
197
|
-
- **EDE「没数据」和「代码写错」是两回事**(2026-08-15 实测):**①代码写错 → 直接报 `100003` 并指名是哪个**(指标写错报「指标 xxx 不存在」,证券写错报「xxx 不是有效证券或者板块ID」,美股用 `.US` 而非 `.O`/`.N` 同理),**无论同批有没有其它正确的 code 都会报**,所以拼写错误现在是一眼可见的、不用再靠对照推断;**②代码有效但无数据 / 无覆盖 / 未来日期 → 行列都保留**(含单指标 × 单证券的 1×1)并给一个占位单元格,**退出码 0
|
|
198
|
-
- **EDE 指标参数名一律以 `indicator search --format json` 的 `parameterList` 为准**,不要凭记忆或照抄示例。参数名写错会报 `100003` 并指出是哪个指标的哪个参数(如复权参数是 `adjustType`,写成 `adjustmentType`
|
|
221
|
+
- **EDE「没数据」和「代码写错」是两回事**(2026-08-15 实测):**①代码写错 → 直接报 `100003` 并指名是哪个**(指标写错报「指标 xxx 不存在」,证券写错报「xxx 不是有效证券或者板块ID」,美股用 `.US` 而非 `.O`/`.N` 同理),**无论同批有没有其它正确的 code 都会报**,所以拼写错误现在是一眼可见的、不用再靠对照推断;**②代码有效但无数据 / 无覆盖 / 未来日期 → 行列都保留**(含单指标 × 单证券的 1×1)并给一个占位单元格,**退出码 0**。占位值**统一为 `null`**(2026-08-24 实测跨 4 指标 × 4 市场 + 243 行时序确认)。⚠️ **仍要当心报告期类指标的时序**:只有报告期末那几行是真值,其余全是 `null`(茅台 5 个月 104 行只有 2 行有数),整列手工求均值会差几十倍;截面日期不落在报告期末则整批 `null`、`screener` 筛出空集。详见 `references/commands/indicator.md`。日期语义按指标分两类:财务报表指标=报告期末(可为非交易日)、`finc_pe_ttm` / `finc_pb_mrq` 等日频估值=最新交易日(⚠️ `finc_pb_mrq` 是日频的,用报告期末日期会取到几个月前的陈值);混合取数按各自有效日期分次 `cross-section` 再按证券合并,别塞进同一个 `--date`。详见 `references/commands/indicator.md`
|
|
222
|
+
- **EDE 指标参数名一律以 `indicator search --format json` 的 `parameterList` 为准**,不要凭记忆或照抄示例。参数名写错会报 `100003` 并指出是哪个指标的哪个参数(如复权参数是 `adjustType`,写成 `adjustmentType` 直接报错),按报错信息改即可。🔴 **日期参数不能按 code 前缀推**——**唯一判据是 `parameterList` 里必填的是哪个**:有 `tradeDate` 就用 `--date`,有 `reportDate` 就补 `--indicator-param "code:reportDate=YYYY-MM-DD"`。多数报告期类指标(`is_*` 利润表等)确实要 `reportDate`(只传 `--date` 会报「不支持参数 tradeDate; 缺少必填参数 reportDate」),**但 `_ttm` 后缀整族相反、必填 `tradeDate`**(`is_op_rev_ttm` / `is_net_prft_ttm` / `cf_op_cf_ttm` / `div_cash_ttm` … 跨 `is_`/`cf_`/`div_`/`finc_` 四族都有),传 `reportDate` 会报「不支持参数 reportDate」。行情 / 估值类(`qte_*` / `finc_pe_ttm` 等)用 `--date` 即可。`--security` 支持板块 ID(`reference sector-search` 的 10 位 `sectorId`;`--indicator` 只收指标编码)。根级 `--scale` 只作用于声明了 `scale` 的指标,价格与金额可以混查。
|
|
199
223
|
- **新增指标**:融资融券 21 个 `mgn_*`(`mgn_bal` 两融余额 / `mgn_fin_*` 融资 / `mgn_sl_*` 融券 / `mgn_flag` 是否标的,**仅 A 股有数**;区间类的 `changePeriod` 2026-08-14 起改为**可选**);行业分类 `scr_indu`(一个指标覆盖申万/中信/恒生/GICS 四套,**必填** `industryType` 1-4 + `industryLevel` 0-4,A/港/美股均支持,返回字符串),2026-08-14 又加了三个**行业组合指标** `scr_indu_citic` / `scr_indu_sw` / `scr_indu_gics`(体系写进编码,只需可选的 `industryLevel`;单套体系用它们更省事,横比多套仍用 `scr_indu`)
|
|
200
224
|
- "业绩点评"双义消歧:**检索已有**(研报/纪要里的业绩点评内容)走 `insight ... list --llm-tag earningsReview`(0.1/条);**AI 现生成**一份走 `ai earnings-review`(异步、50/次)。不确定问一句
|
|
201
225
|
|
|
@@ -287,7 +311,7 @@ gangtise reference securities-search --keyword <公司名> --category stock --to
|
|
|
287
311
|
| 错误码 | 含义 | CLI 行为 | Agent 是否介入 |
|
|
288
312
|
|--------|------|---------|--------------|
|
|
289
313
|
| ✅ `100003` | 参数值非法——**最宽的兜底码**:类型错、`limit` 越界都归这里。**msg 通常已指明字段**(如「请求体字段类型不匹配: size 期望类型 Integer」「limit 最小为 1,最大为 10000」),先读 msg 再猜 | — | 按 msg 指的字段改;msg 没指明才对照 `--help` 查枚举拼写,**不要重试同命令** |
|
|
290
|
-
| ✅ `999999` | 系统错误。**`indicator`(EDE)2026-08-01 前用此码表示查询无数据,之后改为返回数据体**,所以这个码基本只剩真故障。⚠️
|
|
314
|
+
| ✅ `999999` | 系统错误。**`indicator`(EDE)2026-08-01 前用此码表示查询无数据,之后改为返回数据体**,所以这个码基本只剩真故障。⚠️ 现在「无数据」是保留行列的占位单元格(统一 `null`,见 `indicator.md`),**不是空表**;空表另有含义(整轴 code 未识别) | 普通端点自动重试 ×2;🔴 贵档与 `indicator` 端点不重试 | 确认参数无误仍报此码即服务端故障 |
|
|
291
315
|
| ✅ `410110` | **异步生成中**(HTTP 400,旧码未切)。新码 `140001`,CLI 两码都认 | 轮询视为 pending | 继续等 |
|
|
292
316
|
| ✅ `410111` | **异步生成失败**(HTTP 400,旧码未切)。新码 `140002`,CLI 两码都认 | 终态 | **不重试**,换参数 |
|
|
293
317
|
| ✅ `130002` | 资源不存在——下载类的常见码:`reportId` 不存在 / 非数字多归此码。另有更具体的 `130003`(资源未生成 / 无附件)与 `130005`(`fileType` 非法) | — | 确认 ID 有效且本账号可见;换 `--file-type` 或换一篇验证 |
|
|
@@ -295,7 +319,7 @@ gangtise reference securities-search --keyword <公司名> --category stock --to
|
|
|
295
319
|
| ✅ `100001` | 缺必填参数——**msg 带字段名**(「缺少必填参数: reportId」) | — | 按 msg 指的字段补上 |
|
|
296
320
|
| ✅ `110001` / `110002` | 日期格式错(msg 带字段名)/ 起晚于止。⚠️ **服务端 2026-08-14 起对多种格式做宽松解析**(`2026/07/01`、`20260701`、`07/01/2026` 都能被接受),所以「没报 110001」不等于「格式被按你的意思理解了」 | — | 按参数名:`--*-date` 用 `YYYY-MM-DD`、`--*-time` 用 `YYYY-MM-DD HH:mm:ss`;`ai knowledge-batch` 的 --start-time/--end-time 收时间戳或 datetime,CLI 统一转 13 位毫秒 |
|
|
297
321
|
| ✅ `120001` | 证券代码无效——msg 带原因(「非有效A股」)。Fundamental 系与 `quote day-kline`/`realtime`/`minute-kline`/`fund-flow` 都会报;**旧版 `day-kline-hk`/`day-kline-us`/`index-day-kline` 仍静默返回空** | — | `reference securities-search` 确认代码与后缀(`600519.SH` / `00700.HK`) |
|
|
298
|
-
| ✅ `110003` |
|
|
322
|
+
| ✅ `110003` | **超出账号数据权限的时间范围**。范围按账号等级而定、**不是平台常量**;窗口按**账号**配、不按接口配 | — | 把日期移进权限范围内;整个区间都早于下界时缩短窗口无用(`--fiscal-year 2015` 无论怎么缩都报错);**换接口绕不过去**,要更长历史联系客户经理开通 |
|
|
299
323
|
| ✅ `100006` | 查询/下载数量超限——**取代旧 `430007`**;实测 `fund-flow` 全市场不传日期即此码 | — | 缩短日期范围或调小 `--size`/`--limit`;全市场场景应已自动分片 |
|
|
300
324
|
| ✅ `240001` | 财报期未披露或超出查询期(`earnings-review` 提交阶段就报,**不扣积分**) | — | 换更早的 `--period`(`2025q3` → `2025interim`) |
|
|
301
325
|
| ✅ `250001` | 不支持的数据源——**取代旧 `433007`** | — | 检查 `resourceType + sourceId` 组合 |
|
|
@@ -311,7 +335,7 @@ gangtise reference securities-search --keyword <公司名> --category stock --to
|
|
|
311
335
|
- **日期用「年在前」写法**:`YYYY-MM-DD`(首选)、`YYYY/MM/DD`、`YYYYMMDD` 三种 CLI 都收,并**统一归一成 `YYYY-MM-DD` 再发出**;时间加 `[ HH:mm[:ss]]`(秒可省、空格或 `T` 分隔)或用 10/13 位时间戳。🔴 **「年在后」写法(`01-07-2026`、`07/01/2026`)CLI 直接报 `ValidationError`,这是有意的**——接口本身会解析它,且**一律按美式「月在前」**(`01-07-2026` = 1 月 7 日,`07-01-2026` = 7 月 1 日)。按欧洲/国际习惯写 `01-07-2026` 想表达「7 月 1 日」的,会拿到差半年的数据且**不报错**;本地拒掉才有信号,还省一次请求与计费。绕过 CLI 直连接口时务必自己统一用 `YYYY-MM-DD`
|
|
312
336
|
- **财报接口的日期按「报告期末」过滤**,不是公告日:`fundamental balance-sheet` 等的 `--start-date`/`--end-date` 匹配的是 `endDate` 字段(如 `20200630`);公告日看 `earliestAnncDate`(首次公告日,做时点对齐用这个)而不是 `announcementDate`。**查某期财报要传季度末日期**(`2020-06-30` / `2020-03-31` / `2020-09-30` / `2020-12-31`);传 `2020-07-01` 这类非报告期日期会返回 0 行,属正常行为,不是没数据
|
|
313
337
|
- **非法证券代码**:`quote day-kline` / `realtime` / `minute-kline` / `fund-flow` 与 Fundamental 系都会报 `120001`,按报错核对后缀即可。⚠️ **三个已下线的旧端点 `quote day-kline-hk` / `day-kline-us` / `index-day-kline` 则返回 `total:0`**,与"该票该区间真无数据"无法区分——**用这三个拿到空结果时先回头核对代码后缀**。它们的能力已并入统一 `day-kline`(支持 A 股 / 港股 / 美股 / 交易所指数 / 概念指数 `.GT` / 申万行业指数 `.SWI`),新代码直接用 `day-kline`
|
|
314
|
-
-
|
|
338
|
+
- **枚举值拼错基本都会报 `100005`,但「字段名不被该端点支持」仍然静默**:纪要 `summary`、三个公告 list、路演 `roadshow`、调研 `site-visit` 的 `--search-type` / `--rank-type` / `--category` / `--market` 等传非法值报 `100005`;`insight research`(内资研报)、`foreign-report`(外资研报)、`official-account` 的 `--search-type` / `--rank-type` 现在同样报 `100005`。⚠️ **剩下的口子是「该端点根本没有这个参数」**:传一个端点不支持的字段名(如给 `opinion` 传 `searchType`——它只有 `--rank-type`)会被静默丢弃、按未传处理,返回未经筛选的全库而不报错。**v0.32.0 起 CLI 本地拦截**:全部 `--search-type` / `--rank-type`(19 处)、全部 `--file-type`(9 处下载,`foreign-report` 为 1–4、其余 1–2)、`pamirs-summary` 的 `--category` / `--market`、`--top` 上限、以及 `reference securities-search` / `institution-search` / `official-account-search` 的 `--category`。**仍未覆盖**:`insight research/summary --category`、`--market`、`--source`、`--llm-tag` 等仍是自由字符串,拼错不报错也不生效——这些要自己核对。**拼错的筛选条件会伪装成"结果正常",枚举拼写要自己保证**
|
|
315
339
|
- **`viewpoint-debate` 传敏感内容不会被提前拦截**——实测不返回 `240002`,而是照常受理、扣满 50 积分、生成阶段才以 `410111` 失败。**提交前自己把关措辞**
|
|
316
340
|
- **`ai one-pager` 的非法 `mode` 被静默忽略**,照常生成并扣 50 积分
|
|
317
341
|
|
|
@@ -323,7 +347,7 @@ gangtise reference securities-search --keyword <公司名> --category stock --to
|
|
|
323
347
|
| `999007` / `999008` / `999009` | 方法/媒体类型/请求体不支持 | 实际返回 `900002` / `999999` / `100003` |
|
|
324
348
|
| `999003` / `999005` / `999006` | 无接口权限 / 积分不足 / 限流 | 未构造出(需特定账号状态) |
|
|
325
349
|
| `999012`–`999016` | 账号禁用/过期、租户失效、无长期 token、IP 不合规 | 未构造出 |
|
|
326
|
-
| `100002` / `100004` / `100005` | 类型错 / 分页非法 / 枚举非法 | 类型错归 `100003`。**`100005
|
|
350
|
+
| `100002` / `100004` / `100005` | 类型错 / 分页非法 / 枚举非法 | 类型错归 `100003`。**`100005`(枚举非法)与 `100006`(`size` 超 50)现在在各 list 端点上普遍触发**——`size=51` 实测七端点一致报 `100006`(`official-account` / `research` / `foreign-report` / 三个 opinion / `summary`)。仍按未传处理的只剩「该端点不支持的字段名」,见上方「实测发现的坑」 |
|
|
327
351
|
| `130004` | 下载 ID 非数字 | 多归 `130002` |
|
|
328
352
|
| `140001` / `140002` | 结果生成中 / 处理失败 | 异步端点仍用 `410110` / `410111` |
|
|
329
353
|
| `210001` / `220001` / `230001` | 研报/观点/分享文件不支持下载 | 未构造出 |
|
|
@@ -342,8 +366,8 @@ gangtise reference securities-search --keyword <公司名> --category stock --to
|
|
|
342
366
|
- CLI 未安装 → `npm install -g gangtise-openapi-cli`
|
|
343
367
|
- **退出码 3 = `partial: true`,结果少了数据**(保留已取到的部分;stderr 有 warning,`--format json` 才看得见标记,table/csv/jsonl 只有数据行、看不出问题):
|
|
344
368
|
- 触发场景:翻页/K线分片有页失败、服务端返回行数与 `total` 矛盾(提前短页)、`total` 撞服务端上限(`totalCapped`,见 opinion 家族)。附带定位字段:页失败 `failedPages`;分片失败 `failedShards`、分片撞行数上限 `truncatedShards`(均带日期区间可缩窗补拉)。⚠️ EDE 的 `omittedIndicators` / `omittedSecurities` 仍在代码里,但 2026-08-15 起写错的 code 在服务端就被 `100003` 拒了(退出 1),这条路基本收不到样本
|
|
345
|
-
- **EDE 代码写错现在是退出码 1 + `100003`,msg 里直接点名是哪个 code**(美股后缀用 `.O`/`.N`,不是 `.US`),不用再从退出码 3
|
|
346
|
-
- **`screener` 的缺列按表达式的布尔结构判**:把缺列的变量当作「无法求值」,看整个表达式**是否还有一条能成立的分支**——`A && B` 要两边都可求值,`A || B` 只要一边。**一条分支都不剩 → 退出码 1、不输出任何结果**(返回的行以「通过了该条件」的名义呈现,而条件根本无法证明被执行过);**还有分支可求值,或缺的只是未参与表达式的辅助变量 → `partial` + 退出码 3**。所以 `F1 || F2` 缺 F1 是降级(行可能靠 F2 正当命中),缺两个则是致命;`F1 && (F2 || F3)` 缺 F1 仍是致命(F1 是必选合取项)。⚠️ **前提是服务端返回了命中行**——零命中时走「nothing matched」+ **退出码 0**。**空集别急着当成「条件成立但无标的符合」**:指标码写错现在会直接报 `100003`(退出 1
|
|
369
|
+
- **EDE 代码写错现在是退出码 1 + `100003`,msg 里直接点名是哪个 code**(美股后缀用 `.O`/`.N`,不是 `.US`),不用再从退出码 3 反推。真的没覆盖仍是占位单元格(统一 `null`)+ 退出码 0
|
|
370
|
+
- **`screener` 的缺列按表达式的布尔结构判**:把缺列的变量当作「无法求值」,看整个表达式**是否还有一条能成立的分支**——`A && B` 要两边都可求值,`A || B` 只要一边。**一条分支都不剩 → 退出码 1、不输出任何结果**(返回的行以「通过了该条件」的名义呈现,而条件根本无法证明被执行过);**还有分支可求值,或缺的只是未参与表达式的辅助变量 → `partial` + 退出码 3**。所以 `F1 || F2` 缺 F1 是降级(行可能靠 F2 正当命中),缺两个则是致命;`F1 && (F2 || F3)` 缺 F1 仍是致命(F1 是必选合取项)。⚠️ **前提是服务端返回了命中行**——零命中时走「nothing matched」+ **退出码 0**。**空集别急着当成「条件成立但无标的符合」**:指标码写错现在会直接报 `100003`(退出 1),剩下**三种成因产生逐字相同的输出**——① 真的没有标的满足条件;② **日期没落在报告期末**(报告期类指标此时整批 `null`);③ **该指标不覆盖这批证券**(拿 A 股专属指标查港美股,如 `finc_pb_mrq` / `mgn_*`)。②③ 都要靠单查一行确认,不能只改日期
|
|
347
371
|
- 拿到 3 就必须告知用户缺了哪段,不能当成功静默继续
|
|
348
372
|
- 空结果(list 为空数组) → 建议扩大时间范围、换关键词、去掉部分筛选
|
|
349
373
|
- 模糊公司名匹配多只("平安" → 中国平安 / 平安银行 / ...) → 列出让用户选
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
> 本组覆盖 `/application/open-indicator/*`:证券级**数据指标**的检索与取数,主要用于多证券批量取已实现财务 / 估值指标。即使能搜到收盘价、成交量等行情指标,常规行情与 K 线仍走免费的 `quote`。
|
|
4
4
|
> 与 `alternative edb-*`(EDB 行业/宏观指标,无证券维度)是两套接口,别混。
|
|
5
5
|
>
|
|
6
|
-
> **取数前先 `indicator search` 拿 `indicatorCode` 和 `parameterList
|
|
6
|
+
> **取数前先 `indicator search` 拿 `indicatorCode` 和 `parameterList`**,绝不猜测指标编码或参数名——参数名与枚举会随版本调整,写错会直接报 `100003` 并指出是哪个指标的哪个参数,照报错改即可;照抄示例里的旧参数名则会白跑一次。
|
|
7
7
|
|
|
8
8
|
## EDE 与专用接口的优先级
|
|
9
9
|
|
|
@@ -15,9 +15,10 @@
|
|
|
15
15
|
| A股估值历史分位 | `fundamental valuation-analysis` |
|
|
16
16
|
| **估值指标的历史序列**(分位 / 回测 / 择时) | 两个接口口径不同、都要交叉核——EDE 按正式财报披露日切换财报口径,`valuation-analysis` 按业绩快报切,见下方专门小节 |
|
|
17
17
|
| 开高低收 / 成交量等行情与 K 线 | `quote`;免费且支持多证券批量 |
|
|
18
|
+
| 单证券资金流向(要占比字段) | `quote fund-flow`;免费,且有 EDE 没有的 `*Ratio` 占比。多证券批量取某一两个档位才用 EDE 的 `flow_*` |
|
|
18
19
|
| 单证券三大报表全部科目 | 对应 `fundamental` 利润表 / 资产负债表 / 现金流量表命令 |
|
|
19
20
|
|
|
20
|
-
EDE 不是“搜到就优先”。取数前必须核对:① `indicatorName` + `description` 与目标语义一致;② `scopeList` 覆盖**全部**目标市场和证券类型;③ `parameterList` 的必填参数与枚举可满足。`scopeList` 缺失 / `null` / 空或任一项不符,都视为无法证明覆盖并回退上表的专用接口;专用接口也不支持目标市场时,如实说明当前 CLI 无可用口径,不能用其他语义代替。实测 `valuation-analysis` / `earning-forecast` 仅支持 A 股,港 / 美股的**估值历史分位**与**盈利预测**当前无可用口径。但**估值指标本身别照抄旧结论**:`finc_pe_ttm`(PE TTM) 2026-08-03 起港股已有数(腾讯 16.15 / 泡泡玛特 14.93
|
|
21
|
+
EDE 不是“搜到就优先”。取数前必须核对:① `indicatorName` + `description` 与目标语义一致;② `scopeList` 覆盖**全部**目标市场和证券类型;③ `parameterList` 的必填参数与枚举可满足。`scopeList` 缺失 / `null` / 空或任一项不符,都视为无法证明覆盖并回退上表的专用接口;专用接口也不支持目标市场时,如实说明当前 CLI 无可用口径,不能用其他语义代替。实测 `valuation-analysis` / `earning-forecast` 仅支持 A 股,港 / 美股的**估值历史分位**与**盈利预测**当前无可用口径。但**估值指标本身别照抄旧结论**:`finc_pe_ttm`(PE TTM) 2026-08-03 起港股已有数(腾讯 16.15 / 泡泡玛特 14.93);`finc_pb_mrq`(PB MRQ) 的港股覆盖是**部分**的(2026-08-24 实测:建设银行 0.6318 / 中国移动 1.2222 / 中芯国际 28.8783 / 小米 −5.5223 / 中国平安 0.9656 有数,而腾讯 / 阿里 / 泡泡玛特为 `null`)。⚠️ **本文里所有「仅 A 股」「无数据」这类否定结论都只是某个时点的抽查**——服务端在持续补数据,正面结论过期会给错数,负面结论过期则会让你白白拒掉一个现在能跑的查询(不报错、不告警,只是少调一次)。**一律以当次 `scopeList` + 抽查为准,本段所引实测截至 2026-08-24。**`search` 免费,EDE 取数按单元格计费;除多证券批量的效率收益外,仍优先免费 / 低价的 `quote` 或 `fundamental`。
|
|
21
22
|
|
|
22
23
|
## 指标搜索 `indicator search`
|
|
23
24
|
|
|
@@ -29,9 +30,9 @@ gangtise indicator search --keyword <text> [--limit <n>]
|
|
|
29
30
|
- `--limit`:返回条数上限,默认 50,最大 100
|
|
30
31
|
- 默认 `--format table` 只适合浏览名称;正式路由 / 取数前必须加 `--format json`,才能完成语义、`scopeList`、`parameterList` 三项校验
|
|
31
32
|
- 返回字段:`indicatorCode` / `indicatorName` / `description`(算法与口径)/ `scopeList`(该指标适用的市场 + 证券类型 + `usageRestriction`)/ `parameterList`(可传的 `--indicator-param` 参数名及枚举)/ `score`
|
|
32
|
-
- **市场范围按指标判断**:`scopeList` 会返回实际覆盖范围,且指标之间不同;不能笼统写成每个指标都覆盖 A / 港 / 美股。覆盖面在持续扩,别把抽查结论当常量:截至 **2026-08-03** 实测 `qte_mkt_cptl`/`shr_tot` 已覆盖 A/港/美股,`finc_pe_ttm` 覆盖 A/港股,`finc_pb_mrq`
|
|
33
|
+
- **市场范围按指标判断**:`scopeList` 会返回实际覆盖范围,且指标之间不同;不能笼统写成每个指标都覆盖 A / 港 / 美股。覆盖面在持续扩,别把抽查结论当常量:截至 **2026-08-03** 实测 `qte_mkt_cptl`/`shr_tot` 已覆盖 A/港/美股,`finc_pe_ttm` 覆盖 A/港股,`finc_pb_mrq` 覆盖 A 股 + **部分**港股(2026-08-24 实测 TOP 港股约三分之一有数),`is_op_rev_ttm`/`is_shnp_ttm` 覆盖 A/港股。目标列表含任一 scope 外证券时,本批 EDE 校验不通过,应回退专用接口
|
|
33
34
|
- **`scopeList[].usageRestriction`**:该指标在具体接口上的限制,`null` = 无限制。⚠️ **它是提示不是硬约束**——标着「不支持指标时间序列接口」的 `qte_vol_intvl` 实测调时序照样返数据、不会被拦下(2026-08-02)。当成「口径可能不对、结果别当真」看,别指望它会报错
|
|
34
|
-
- ⚠️ **`scopeList`
|
|
35
|
+
- ⚠️ **`scopeList` 是声明不是保证**:它可能**超前于数据**,也可能**滞后于你上次的抽查**——`finc_pb_mrq` 声称覆盖 A股+港股,2026-08-08 实测港股无数据,**但 2026-08-24 复测已有约三分之一的港股有数**(建设银行 / 中国移动 / 中芯国际 / 小米 / 中国平安有值,腾讯 / 阿里 / 泡泡玛特仍 `null`)。同向的例子:`qte_mkt_cptl`/`shr_tot` 在 08-02 声称覆盖港/美股却无数据,08-03 就补上了。**「某某仍无数据」这类否定结论过期得和正面结论一样快**,照着它走会白白拒掉一个现在能跑的查询,而且不报错。**判断成本已经很低**:无数据会保留行列、给一个占位单元格,抽查一行就能看出覆盖情况;code 写错则直接报 `100003`,两种情形不会再混淆。占位值统一是 `null`(详见下方「缺数据 vs 代码写错」)
|
|
35
36
|
- 美股代码用交易所后缀 `.O`(NASDAQ) / `.N`(NYSE):用 `AAPL.O`,`AAPL.US` 取不到数据
|
|
36
37
|
|
|
37
38
|
```bash
|
|
@@ -48,7 +49,7 @@ gangtise indicator cross-section --indicator <code> [--indicator <code2>] \
|
|
|
48
49
|
|
|
49
50
|
- `--indicator`(**至少 1 个**):指标编码,来自 `search`,可重复传多个
|
|
50
51
|
- `--security`(**至少 1 个**):证券代码,如 `600519.SH`(A股)/ `09992.HK`(港股)/ `AAPL.O`(美股,用 `.O`/`.N` 后缀,非 `.US`),可重复传多个。**也接受板块 ID**(`reference sector-search` 返回的 10 位 `sectorId`,如 `1000000287` 中信白酒 → 19 只成分股),代码与板块可混传,服务端取并集去重。⚠️ 中信行业码那类 9 位 ID(`100800109`)**不是** `sectorId`,传进去返 0 只
|
|
51
|
-
- `--date`(**必选**):数据日期 `yyyy-MM-dd`。**CLI 把它下发为每个指标各自的 `tradeDate`**(2026-08-01 起服务端取消了根级 date)。日期语义按指标分两类——财务报表指标=报告期末(可为非交易日,实测 `2024-03-31`
|
|
52
|
+
- `--date`(**必选**):数据日期 `yyyy-MM-dd`。**CLI 把它下发为每个指标各自的 `tradeDate`**(2026-08-01 起服务端取消了根级 date)。日期语义按指标分两类——财务报表指标=报告期末(可为非交易日,实测 `2024-03-31` 可取数;**⚠️ `_ttm` 后缀整族例外,走交易日,见下方「日期路由」**)、`finc_pe_ttm` / `finc_pb_mrq` 等日频估值=交易日(详见下方「日期路由」)
|
|
52
53
|
- `--date` 必填是 CLI 的**护栏**,不是协议要求:`cross-section` 本身接受 `indicatorParamList: []`。但绝大多数指标吃 `tradeDate`,漏传就是一张空表且退出码 0,所以宁可多带一个。(`screener` 的 `--date` 也必填,同理)
|
|
53
54
|
- 🔴 **判据一句话:该指标的 `parameterList` 里有 `tradeDate` 就不用管;没有,`--date` 下发的 `tradeDate` 就可能被拒。** 按这条走,四种情形四种写法(`parameterList` 从 `indicator search --keyword <code> --format json` 读,别按 code 前缀推断):
|
|
54
55
|
|
|
@@ -147,11 +148,11 @@ gangtise indicator screener --indicator F1:qte_close --indicator F2:qte_close \
|
|
|
147
148
|
> `contains` / `notcontains` 对大小写不敏感(`CONTAINS` / `contains` / 混合写法等价)。
|
|
148
149
|
|
|
149
150
|
```bash
|
|
150
|
-
#
|
|
151
|
+
# 文本筛选:白酒板块里经营范围提到葡萄酒的公司
|
|
151
152
|
# ⚠️ pty_op_scope 的 parameterList 为空 → 必须带 "F1:" 声明它不吃日期,否则整条请求报 100003
|
|
152
153
|
gangtise indicator screener --indicator F1:pty_op_scope \
|
|
153
154
|
--indicator-param "F1:" \
|
|
154
|
-
--security 1000000287 --expression "F1 contains '
|
|
155
|
+
--security 1000000287 --expression "F1 contains '葡萄酒'" \
|
|
155
156
|
--date 2026-08-13 --format table
|
|
156
157
|
# 有日期参数的字符串指标不需要 "F1:",直接筛:
|
|
157
158
|
gangtise indicator screener --indicator F1:mgn_flag \
|
|
@@ -185,35 +186,54 @@ gangtise indicator cross-section --indicator qte_close --security 600519.SH \
|
|
|
185
186
|
- ⚠️ **参数名是 `adjustType`**(不是 `adjustmentType`)。写错名会报 `100003` 并指出是哪个指标的哪个参数,按报错改即可
|
|
186
187
|
- 前复权以最新交易日为基准,所以在**最新交易日上前复权价 == 不复权价**;验证复权是否生效要用历史日期
|
|
187
188
|
- 同一指标多个参数 → 重复 `--indicator-param "code:k1=v1" --indicator-param "code:k2=v2"`
|
|
188
|
-
-
|
|
189
|
+
- 🔴 **冒号左边的 code 必须是 `--indicator` 列出过的**:写了别的(多为拼写错误)会在发请求前报 `--indicator-param references "xxx", which no --indicator names`(v0.37.0 起)。这条拦的是「参数没落到你要查的指标上」——按报错核对拼写即可。`screener` 上是同款检查,只是按变量:变量必须被 `--indicator` 绑定
|
|
190
|
+
- **参数名与取值一律以 `indicator search --format json` 的 `parameterList` 为准**,不要照抄任何文档里的示例名——参数名会随版本调整。写错会报 `100003` 并指出是哪个指标的哪个参数(2026-08-15 起),按报错改即可。币种枚举**统一大写**(`DFT`/`CNY`/`HKD`…),小写形式不生效
|
|
189
191
|
- `--indicator-param` 与根级 `--currency`/`--scale` 冲突时,以 `--indicator-param` 为准
|
|
190
192
|
|
|
191
193
|
## 必填参数与错误码(取数前必读)
|
|
192
194
|
|
|
195
|
+
### 取数可靠性:`qte_vol` 等指标在某些日期上会随机返 `null`
|
|
196
|
+
|
|
197
|
+
🔴 **同一条请求多次调用,结果会在「有值」和 `null` 之间跳。** 这**与「是不是最新交易日」无关**——是**特定日期**的数据在部分副本上缺失。
|
|
198
|
+
|
|
199
|
+
实测(2026-08-24,`00941.HK` 各 8 次):
|
|
200
|
+
|
|
201
|
+
| 日期 | 结果 |
|
|
202
|
+
| :-- | :-- |
|
|
203
|
+
| `2026-08-24`(当时的最新交易日) | `########` 8/8 有值 |
|
|
204
|
+
| **`2026-08-21`** | `0#0#0#00` **多数请求返 `null`** |
|
|
205
|
+
| `2026-08-20` / `08-19` | `########` 8/8 有值 |
|
|
206
|
+
|
|
207
|
+
受影响的**只是部分标的**:同一批里 A股、美股、腾讯、阿里都稳定。同一条请求内,受影响的证券**全有或全无**(不会一半有一半没有)。
|
|
208
|
+
|
|
209
|
+
**做法,按优先级**:
|
|
210
|
+
|
|
211
|
+
1. 🟢 **只要日成交量 / 成交额,别用 EDE,直接用 `quote day-kline`** —— 同一天同一只票实测 6/6 稳定,`amount` 与分钟线加总精确相等。**不用重试、不用换日期、不丢数据**;它的 `volume` 与 EDE `qte_vol` **逐位相同**(2026-08-28 实测 7 只,A股 / 港股 / 美股,单位同为股),**没有精度损失**
|
|
212
|
+
2. 确实需要 EDE 才有的口径时(周 / 月 / 季 / 年 / 区间成交量等 `quote` 不提供的),**重试,但不要设固定次数上限** —— 实测出现过**连续 8 次全 `null`**。**若必须设上限,超限时要显式报错退出,绝不能把最后一次的 `null` 当成「无数据」写进结果**
|
|
213
|
+
|
|
214
|
+
⚠️ **不要用「改取前一个交易日」当通用兜底**:它在 `2026-08-21` 这个个案上碰巧有效,但坏的是哪一天并无规律,而且会丢掉那一整天的数据。
|
|
215
|
+
|
|
216
|
+
**单次 `null` 不能读成「该股当日无数据」** —— 它与真无数据无法区分,且退出码 0。判别法:**同一条请求再打几次**,只要出现过非 `null` 就说明数据是有的。
|
|
217
|
+
|
|
218
|
+
---
|
|
219
|
+
|
|
193
220
|
**缺数据 vs 代码写错(2026-08-08 服务端改版,判据整个换了)**:
|
|
194
221
|
|
|
195
222
|
**缺数据一律保留行列并给一个占位单元格**,连单指标 × 单证券的 1×1 缺口也有行有列、不是空表。判据是**代码认不认识**,跟有没有数据无关:
|
|
196
223
|
|
|
197
|
-
> 🔴
|
|
198
|
-
>
|
|
199
|
-
> 多数指标缺数据填 `null`,但**个别指标填 `0`**,其中最常用的是 `is_dnrpnp`(扣非归母净利润)。同一天同一只股票:`is_dnrpnp` 给 `0`、`is_op_rev` 给 `null`。**与日期对不对无关**——日期完全正确(报告期末)时,覆盖不到的证券(如美股)同样给 `0`:同一次请求里茅台、泡泡玛特返真值,苹果、微软的 `is_dnrpnp` 返 `0`、`is_op_rev` 返 `null`,四行都在、无告警、退出码 0。
|
|
200
|
-
>
|
|
201
|
-
> **`0` 会照常穿过比较与比率计算**,`null` 不会。实测 `screener`(`F1 = is_dnrpnp`,三只 A 股):
|
|
224
|
+
> 🔴 **报告期类指标(`is_*`)取不到数时返 `null`,而时序上大部分行都是 `null`——这一条会直接影响聚合结果**
|
|
202
225
|
>
|
|
203
|
-
>
|
|
204
|
-
> | :--- | :--- | :--- |
|
|
205
|
-
> | `F1 > 0` | **命中 0 只** | 命中 3 只 |
|
|
206
|
-
> | `F1 < 50亿` | **命中 3 只**(值全是 `0`) | 命中 1 只 |
|
|
226
|
+
> 占位值统一是 `null`(2026-08-24 实测:4 个指标 × 4 个市场的截面、243 行 × 3 指标的时序,无一格是 `0`)。`null` 在宽表里一眼可见,**Excel `AVERAGE` / pandas `mean()` / SQL `AVG` 会跳过它**,但**行数不会变**。🔴 **`jq` 不跳过**:`[1,null,2,null,null] | add/length` 得 **0.6**(正确值 1.5),`add` 把 `null` 当加法单位元而 `length` 照数——正是「整列求均值差几十倍」那个错法本身;全为 `null` 时 `add/length` 直接报错。用 jq 聚合前先 `map(select(. != null))`。
|
|
207
227
|
>
|
|
208
|
-
>
|
|
228
|
+
> **时序这一档最容易踩**:报告期类指标按日返回,**只有报告期末那几行是真值**,其余全是 `null`——茅台 `is_dnrpnp` 查 2025-03-01→07-31 共 **104 行,只有 03-31 和 06-30 两行有数**。而**时序没有任何参数能让它只返回报告期末**(传 `tradeDate` / `reportDate` 都会被拒)。用「总和 ÷ 行数」手工求均值会得到偏低 50 倍的结果;用会跳过 `null` 的聚合(如多数 DataFrame 的 `mean()`)才是对的。
|
|
209
229
|
>
|
|
210
|
-
>
|
|
230
|
+
> **截面这一档**:日期不落在报告期末(如 `2025-05-15`)时整批返 `null`,`screener` 的任何比较都不成立、筛出空集——**这不是「没有符合条件的标的」,是日期用错了**。
|
|
211
231
|
>
|
|
212
|
-
> **怎么办**:① 报告期类指标一律把日期落在**报告期末**(`2025-03-31` / `06-30` / `09-30` / `12-31
|
|
232
|
+
> **怎么办**:① 报告期类指标一律把日期落在**报告期末**(`2025-03-31` / `06-30` / `09-30` / `12-31`),截面用 `--indicator-param "F1:reportDate=..."` 显式指定;② **别对时序整列直接求均值 / 求和**,先按报告期末取子集,或确认你的聚合会跳过 `null`。
|
|
213
233
|
|
|
214
234
|
| 情况 | 服务端怎么返 | CLI |
|
|
215
235
|
| :--- | :--- | :--- |
|
|
216
|
-
| 代码有效、但**无数据 / 无覆盖 / 非交易日 / 未来日期** |
|
|
236
|
+
| 代码有效、但**无数据 / 无覆盖 / 非交易日 / 未来日期** | 占位单元格(统一 `null`),行列都在 | **退出 0**,不标 partial |
|
|
217
237
|
| **指标码无法解析**(拼错、不存在) | `100003「指标 xxx 不存在」` | **退出 1**,报错 |
|
|
218
238
|
| **证券码无法解析**(拼错、后缀错,如 `AAPL.US`) | `100003「xxx 不是有效证券或者板块ID」` | **退出 1**,报错 |
|
|
219
239
|
| **参数名写错 / 同 code 重复配置** | `100003` 并指名参数 / 「重复配置」 | **退出 1**,报错 |
|
|
@@ -222,7 +242,7 @@ gangtise indicator cross-section --indicator qte_close --security 600519.SH \
|
|
|
222
242
|
|
|
223
243
|
| 查法 | 服务端返回 |
|
|
224
244
|
| :--- | :--- |
|
|
225
|
-
| `--indicator finc_pb_mrq --security 09992.HK
|
|
245
|
+
| `--indicator finc_pb_mrq --security 09992.HK`(**这一只**港股无 PB 数据;同指标下 `00939.HK`/`00941.HK` 等是有数的) | 1 行,`finc_pb_mrq: null`,**退出 0** |
|
|
226
246
|
| `--indicator qte_close --date 2027-01-04`(未来日期) | 1 行,`qte_close: null`,**退出 0** |
|
|
227
247
|
| `--indicator qte_close --indicator not_a_real_code`(有对照物) | `100003 指标 not_a_real_code 不存在` |
|
|
228
248
|
| `--indicator not_a_real_code`(**无对照物**) | `100003 指标 not_a_real_code 不存在` ← 同样报错 |
|
|
@@ -230,13 +250,21 @@ gangtise indicator cross-section --indicator qte_close --security 600519.SH \
|
|
|
230
250
|
|
|
231
251
|
**代码写错现在一律报错、且消息里带上那个代码**,无论同批有没有别的正确代码——不用再靠「和一个已知有数的标的一起查」推断是哪个写错了。**所以「空表」的含义变干净了:它现在基本只意味着真的没数据**(此前空表既可能是没数据、也可能是整个轴写错)。
|
|
232
252
|
|
|
233
|
-
|
|
253
|
+
**占位值统一为 `null` 后,「和一个已知有数的标的一起查」这套对照法不再必要**——缺数据一眼可见。仍要留意的是**日期语义**(见上方 🔴 段):日期用错时整批返 `null`,形态与「真的没覆盖」一样。
|
|
234
254
|
|
|
235
255
|
> CLI 侧仍保留 `partial` + `omittedIndicators` / `omittedSecurities` + 退出码 3 的差集检测,但在当前服务端行为下基本收不到样本(错代码在服务端就被拒了)。留着是为了万一服务端回退时还有兜底,不影响正常使用。
|
|
236
256
|
|
|
237
257
|
`screener` 上指标码写错同样直接报 `100003`,不会再走到「缺列」那条路。CLI 的缺列判据(按表达式布尔结构判,整个表达式再无可成立分支 → 退出码 1 且不输出;仍有分支可求值如 `F1 || F2` 只缺 F1 → `partial` + 退出码 3)保留作兜底。
|
|
238
258
|
|
|
239
|
-
⚠️ **`screener`
|
|
259
|
+
⚠️ **`screener` 的空集仍要当心:三种成因产生逐字相同的输出(都是退出码 0 + 同一句 note)**
|
|
260
|
+
|
|
261
|
+
| # | 成因 | 怎么区分 |
|
|
262
|
+
| :-- | :-- | :-- |
|
|
263
|
+
| ① | 真的没有标的满足条件 | —— |
|
|
264
|
+
| ② | **日期没落在报告期末**(报告期类指标整批返 `null`,任何比较都不成立) | 改用报告期末日期重跑 |
|
|
265
|
+
| ③ | **该指标不覆盖这批证券**(如拿 A 股专属指标查港美股:`mgn_*` 融资融券系列仅 A 股,2026-08-24 实测港/美股均 `null`) | 用 `cross-section` 单查一行看是不是 `null`。⚠️ **覆盖面是逐只的、且会变**,别按「某指标只有 A 股」这种整体结论排除 |
|
|
266
|
+
|
|
267
|
+
实测:`is_dnrpnp` + `F1 > 0`,「AAPL+MSFT 且日期完全正确」与「茅台+五粮液但日期错」两种查法的输出**逐字相同**。**所以只改日期改不出来时,要怀疑覆盖面。** 指标码拼错已不在其列(会直接报错)。
|
|
240
268
|
|
|
241
269
|
标 `partial` 的那档会在 stderr 打印被略过的 code(`--format json` 下 stdout 仍是干净 JSON)。脚本按 `!= 0` 判失败的要注意:3 表示「有数据但不完整」,不是硬失败。
|
|
242
270
|
|
|
@@ -247,8 +275,8 @@ gangtise indicator cross-section --indicator qte_close --security 600519.SH \
|
|
|
247
275
|
| `100001` | **缺少必填参数**:如 `universe` 没传 | 补齐 `--indicator`/`--security` |
|
|
248
276
|
| `100003`@400 | 入参/表达式错误:`time-series` 传了「多指标 × 多证券」、`expression` 引用未声明变量、`indicatorParamList` 的 code 不在 `indicatorCodeList` 里 | 按 msg 改;多 × 多改用 `cross-section`。CLI 已在本地拦截「表达式引用未绑定变量」,不会白发一次请求 |
|
|
249
277
|
| `140002`@500 | **终态参数错**:指标必填参数缺失、枚举越界(如「参数 adjustType 的值 99 不在有效范围内 [1,2,3,4]」)、表达式语法错误 | **不重试**(CLI 已把 140002 列为终态码)。读 `search --format json` 的 `parameterList` 改参数名/取值 |
|
|
250
|
-
| `999999` | 系统故障。2026-08-01 起「无数据」不再用此码,所以它基本只剩真故障(2026-07-26 曾出现 EDE 取数端全线 999999,08-01 已恢复)。⚠️
|
|
251
|
-
| `110003` |
|
|
278
|
+
| `999999` | 系统故障。2026-08-01 起「无数据」不再用此码,所以它基本只剩真故障(2026-07-26 曾出现 EDE 取数端全线 999999,08-01 已恢复)。⚠️ 别把它和空表混为一谈:无数据现在是占位单元格(统一 `null`),空表表示整轴 code 未识别 | CLI 对 indicator 端点**不重试此码**(v0.27.0);确认参数无误仍报错就是服务端问题 |
|
|
279
|
+
| `110003` | **超出账号数据权限的时间范围**。窗口按**账号**配、不按接口配——`cross-section` / `time-series` / `screener` 同界,实测 `quote day-kline` 也在同一条界上 | 把日期移进范围;整段区间都早于下界时缩短窗口无用,**换接口绕不过去**,要更长历史联系客户经理开通 |
|
|
252
280
|
| `130001`(旧 `410004`) | 数据未找到,或**该指标无权限**(内层信封失败会带具体 msg,如"指标无权限";此码被服务端复用) | 检查查询条件与指标权限;换证券/日期仍失败多为无权限,联系管理员开通 |
|
|
253
281
|
|
|
254
282
|
### 必填参数(`140002` 的根因)
|
|
@@ -264,6 +292,30 @@ gangtise indicator cross-section --indicator qte_close --security 600519.SH \
|
|
|
264
292
|
|
|
265
293
|
> `paramValue` 一律按**字符串**约定传(`periodNum=4` 内部即 `"4"`,CLI 已处理)。
|
|
266
294
|
|
|
295
|
+
### 个股资金流向(17 个 `flow_*`)
|
|
296
|
+
|
|
297
|
+
`scopeList` 与实测都只有 **A 股**(港 / 美股返 `null`)。必填 `tradeDate`,可选 `currency` / `scale`;**单位是元**(`scale` 默认 0 不缩放)。
|
|
298
|
+
|
|
299
|
+
| 档位 | 流入额 | 流出额 | 净流入额 |
|
|
300
|
+
| :--- | :--- | :--- | :--- |
|
|
301
|
+
| 小单 | `flow_small_in_amt` | `flow_small_out_amt` | `flow_small_net_in_amt` |
|
|
302
|
+
| 中单 | `flow_med_in_amt` | `flow_med_out_amt` | `flow_med_net_in_amt` |
|
|
303
|
+
| 大单 | `flow_lrg_in_amt` | `flow_lrg_out_amt` | `flow_lrg_net_in_amt` |
|
|
304
|
+
| 超大单 | `flow_xl_in_amt` | `flow_xl_out_amt` | `flow_xl_net_in_amt` |
|
|
305
|
+
| **主力** = 大单 + 超大单 | `flow_main_in_amt` | `flow_main_out_amt` | `flow_main_net_in_amt` |
|
|
306
|
+
| **全单** = 四档合计 | `flow_all_in_amt` | `flow_all_out_amt` | — |
|
|
307
|
+
|
|
308
|
+
**为什么全单没有净额**:`flow_all_in_amt` 与 `flow_all_out_amt` **恒相等**(每笔成交都同时是一买一卖),净额恒为 0,所以只有 17 个而不是 18 个。这两个数就是当日成交额。
|
|
309
|
+
|
|
310
|
+
🔴 **与 `quote fund-flow` 是同一套数,逐位相同**(实测 600519.SH:小单 38740 / 中单 1660538795 / 大单 1042050312 / 超大单 501475504 两边完全一致)。**选哪个**:
|
|
311
|
+
|
|
312
|
+
| 场景 | 用 |
|
|
313
|
+
| :--- | :--- |
|
|
314
|
+
| 单只或少量证券、要全部档位和占比 | `quote fund-flow` —— **免费**,且额外给 `*Ratio` 占比字段(EDE 没有) |
|
|
315
|
+
| 多证券批量、只要其中一两个档位 | `indicator cross-section` —— 一次请求取回,但**按单元格计费** |
|
|
316
|
+
|
|
317
|
+
⚠️ 档位名易混:`main`(主力)= 大单 + 超大单,**不是**中单;中单是 `med`。
|
|
318
|
+
|
|
267
319
|
### 2026-08-07 新增指标
|
|
268
320
|
|
|
269
321
|
**融资融券(21 个 `mgn_*`)**——`scopeList` 与实测都只有 **A 股**(港/美股返 `null`):
|
|
@@ -315,21 +367,21 @@ gangtise indicator cross-section --indicator scr_indu_citic --indicator scr_indu
|
|
|
315
367
|
|
|
316
368
|
## 取数最佳实践
|
|
317
369
|
|
|
318
|
-
- **先 search 做三项校验**:看 `indicatorName` + `description` 确认语义和口径,看 `scopeList` 确认覆盖全部目标市场 / 证券类型(并看 `usageRestriction` 有无接口限制),再看 `parameterList` 补齐必填参数(required)并核对专属参数**名称**与枚举(`adjustType`/`scale`/`currency`
|
|
319
|
-
- **`scopeList` 声称覆盖 ≠
|
|
370
|
+
- **先 search 做三项校验**:看 `indicatorName` + `description` 确认语义和口径,看 `scopeList` 确认覆盖全部目标市场 / 证券类型(并看 `usageRestriction` 有无接口限制),再看 `parameterList` 补齐必填参数(required)并核对专属参数**名称**与枚举(`adjustType`/`scale`/`currency` 等);任一不符就回退专用接口。**参数名一律以 search 返回的 `parameterList` 为准,不要照抄任何示例里的参数名**——参数名会随版本调整,写错会报 `100003` 并指出是哪个指标的哪个参数,按报错改即可。
|
|
371
|
+
- **`scopeList` 声称覆盖 ≠ 每只都有数**:`finc_pb_mrq` 的 `scopeList` 写着 A股+港股,2026-08-08 实测港股无数据,**2026-08-24 复测已有约三分之一港股有数**——所以它是**部分覆盖**,既不能当「全覆盖」也不能当「无覆盖」。**判断成本很低**:无覆盖会留下占位单元格(行列都在,跟同批查了什么无关),抽查一行即可判定,不用再靠对照组反推。占位值统一为 `null` 后这一步是可靠的(2026-08-24 实测)。跨市场批量取数后仍建议**逐市场抽查一行**,别默认 scopeList 就是事实——反过来也一样,`qte_mkt_cptl`/`shr_tot` 在 08-02 还是港/美无数据、08-03 就补上了,**否定结论同样会过期**。
|
|
320
372
|
- **公司类型决定有没有这个科目**:财务科目分公司类型——银行有「存放同业」、券商有「客户资金存款」、保险有「预收保费」,一般企业没有。某指标对茅台返回 `null`(无此科目),换到对应类型证券(招行/中信/平安)就有数。
|
|
321
373
|
- **日期路由**:
|
|
322
|
-
- 财务报表类(`bs_`/`is_`/`cf_`/`div_`/`shr_`,以及 description 明确按报告期统计的 `finc_`)→
|
|
374
|
+
- 财务报表类(`bs_`/`is_`/`cf_`/`div_`/`shr_`,以及 description 明确按报告期统计的 `finc_`)→ 多数用**报告期末**(Q1 `2026-03-31`、年报 `2025-12-31`,无需是交易日)。🔴 **但 `_ttm` 后缀是整族例外,必填 `tradeDate`**——`is_*_ttm` / `cf_*_ttm` / `div_cash_ttm` / `finc_*_ttm` 一律走交易日。**一眼验证**:在一个**非报告期末的普通交易日**(如 `2026-08-19`)直接 `--date` 取 `is_op_rev_ttm`,照样返真值(茅台 170152009062.43);反过来给它传 `reportDate` 会报 `100003 不支持参数 reportDate; 缺少必填参数 tradeDate`。同族对照:普通 `is_op_rev` 只传 `--date` 则报「不支持参数 tradeDate; 缺少必填参数 reportDate」——**两者恰好相反**。**所以前缀只是提示,判据仍是上面 `--date` 那条:读 `parameterList` 里必填的是哪个,别按 code 前缀推断**
|
|
323
375
|
- 日频估值类(如 `finc_pe_ttm` / `finc_pb_mrq`)→ 用最新已入库的**交易日**。⚠️ `finc_pb_mrq` 是**日频**的:任意交易日都有数且逐日变动(茅台 `07-31`=6.2325、`07-22`=6.0221、`06-30`=5.4706、`03-31`=7.0634;五粮液/宁德时代同样)。**别用季度末日期**——那会拿到几个月前的陈值(茅台季末 7.0634 比当日 6.2325 高 13.5%,估值指标上就是错数)。别因 code 都以 `finc_` 开头就一律套报告期末,按 `description`/实测区分
|
|
324
376
|
- 现金流量表附注/间接法科目(多数 `cf_`)→ **只在年报/半年报披露**,季报日期取不到,改用年报日期 `2025-12-31`
|
|
325
377
|
- 行情类(`qte_` 等)→ 用**交易日**,但常规行情仍应改走 `quote`
|
|
326
378
|
- **混合日期语义要拆查询**:同时要“某报告期营收 / EPS”和“估值 PE / PB”时,按各自有效日期分别调用 `cross-section` 再按 `security` 合并(财务=报告期末、PE/PB=最新交易日);不要把不同日期语义的指标塞进同一个 `--date`
|
|
327
|
-
- **探索性取数**:缺值会保留行列并给占位单元格(含 1×1
|
|
379
|
+
- **探索性取数**:缺值会保留行列并给占位单元格(含 1×1 的最简形态),占位值统一为 `null`;code 写错会直接报 `100003`,不会伪装成缺值。看趋势用 `time-series` + 覆盖报告期的区间,但不能把缺值当成通过语义 / scope 校验。
|
|
328
380
|
- **名称反查 code 要核对,别取首条**:存在同显示名的兄弟指标——单季 `cf_finc_exp_qtr` 与累计 `cf_finc_exp` 都叫「财务费用」,`bs_fmt`/`cf_fmt`/`is_fmt` 都叫「报表格式」。`search` 按名称模糊匹配,目标 code 高概率在 top1 但不绝对,要看 `indicatorCode` 确认。
|
|
329
381
|
- **批量查询做失败拆分**:某指标**缺必填参数**或入参错误时会整批报 `140002`,逐指标单查能定位是哪个指标缺参/不可查。留意 stderr 的「整列/整行被略过」警告——那不是报错,而是**有 code 没被服务端认出来**,先查拼写和证券后缀。
|
|
330
382
|
- **市值量纲**:`qte_mkt_cptl`(总市值)与 `shr_tot`(总股本)**A/港/美股均有数**;**默认返原始「元」**(茅台 ≈ `1.7e12`,即 1.7 万亿),别误当天文数字。用 `scale` 数字码缩放(`0`元 / `3`千 / `4`万 / `6`百万 / `8`亿 / `9`十亿——`scale=8` → `16883` 亿元)、`currency` 换币种(**大写** `DFT`本币 / `CNY` / `HKD` / `USD` …)。**跨证券比市值前先统一 `scale`+`currency`**。
|
|
331
383
|
- **币种与汇率**:`DFT`(原始币种)按市场识别——A股=CNY、港股行情=HKD、美股=USD;汇率换算自洽(互逆且三角一致)。⚠️ 但**同一只港股,行情类的原始币种是 HKD、财务类可能是 CNY**(如泡泡玛特财报以人民币计),跨市场比财务数据时显式传 `--currency CNY` 别依赖 `DFT`。另:财务类指标的汇率按**报告期**折算、行情类按查询日折算,两者隐含汇率会有细微差异,属正常口径差别。
|
|
332
|
-
- **EDE 财务指标的 `reportType
|
|
384
|
+
- **EDE 财务指标的 `reportType`**:`enumList` 的 label 与实际取数**一致**,按 label 传即可(取值以 `enumList` 为准):
|
|
333
385
|
|
|
334
386
|
| value | 口径 | 说明 |
|
|
335
387
|
|-------|---------|------|
|
|
@@ -370,6 +422,6 @@ gangtise indicator cross-section --indicator scr_indu_citic --indicator scr_indu
|
|
|
370
422
|
|
|
371
423
|
- **发现流程**:`indicator search --format json` → 核对 `indicatorName` + `description`、`scopeList`(含 `usageRestriction`)、`parameterList`(**参数名以此为准**)→ 三项都通过才用 `cross-section` / `time-series` / `screener`
|
|
372
424
|
- **积分**:`search` 免费;`cross-section` / `time-series` / `screener` 按请求单元格数量计费,标价为每 100 单元格 A 股 0.05 / 港股 0.1 / 美股 0.2 积分,每次查询不足 100 单元格按 100 计
|
|
373
|
-
-
|
|
374
|
-
- **数据权限**:正式账号行情 / 财务 /
|
|
425
|
+
- **空结果排查顺序**:真无数据会返回占位单元格(统一 `null`)而不是空表,所以**空表基本等于「没有任何 code 被认出来」或参数名写错**。按序排查:① 证券代码与后缀对不对(美股 `.O`/`.N`,不是 `.US`)② 指标 code 拼写对不对 ③ 参数名对不对(`indicator search` 的 `parameterList`)④ 日期语义对不对(`tradeDate` vs `reportDate`——报告期类指标日期用错会整批返 `null`,看着像「没数据」)
|
|
426
|
+
- **数据权限**:正式账号行情 / 财务 / 指标类可回溯的年限按服务等级而定,试用账号更短。这个时间窗口按**账号**配、不按接口配——三个 EDE 接口同界(实测 `quote day-kline` 也在同一条界上),撞界统一返 `110003`,**换接口绕不过去**;整段区间都早于下界时缩短窗口无用,要更长历史联系客户经理开通
|
|
375
427
|
- 所有格式(table/json/jsonl/csv/markdown)均可用;导出宽表给 Excel 直接用 `--format csv --output xxx.csv`
|
|
@@ -94,7 +94,7 @@ gangtise insight pamirs-summary download --summary-id <id> [--file-type <n>] [--
|
|
|
94
94
|
- **不带筛选时经常整条为空**,用 `--category` 或 `--market` 过滤时回填率明显更高(这两个字段是绑定的:用任一过滤,两个都会有值)。有值时给的是该记录的**全部**值(多市场纪要按 `aShares` 过滤也回 `["aShares","hkStocks"]`,不是"回显过滤值")
|
|
95
95
|
- **所以别拉全量再本地分组**——会漏掉大量记录。要按类别/市场分组就逐个枚举值各查一遍再合并(请求数放大 2~4 倍),或直接让服务端筛
|
|
96
96
|
- **反过来也别据此断言某条记录没有该属性**——标签为空只说明这次查询没回填,不代表该纪要真的没有概念/分类/市场归属
|
|
97
|
-
- `researchAreaList` 和 `securityList`
|
|
97
|
+
- `researchAreaList` 和 `securityList` 的回填要完整得多,不受上面这条影响,可以直接用来做本地分组
|
|
98
98
|
|
|
99
99
|
```bash
|
|
100
100
|
# 近一周的帕米尔纪要
|
|
@@ -144,7 +144,7 @@ gangtise insight performance-calendar download --performance-report-id <id> [--o
|
|
|
144
144
|
- 只给 `--security`(不给日期/`--size`)时,CLI 额外套一个 **1000 行隐式上限**:单只证券的整段日历只有几十条,正常查询感知不到;万一服务端哪天不再按 `securityList` 过滤,结果会在 1000 行截断并标 `partial`(stderr 警告 + 退出码 3),而不是闷头翻完全表。判据是 `total`:只有「取满 1000 行且 total 显示还有更多」才告警——恰好 1000 行且 total=1000 是完整结果,退出码仍是 0。看到告警说明筛选**可能**没生效,改用日期范围重查
|
|
145
145
|
- 返回字段:`performanceReportId`(下载用)/ `securityCodeList[]`(A+H 同时上市会有多个代码)/ `securityName` / `category` / `publishDate` / `title` / `hasAttachment`
|
|
146
146
|
- 实测 `publishDate` 返回的是 `yyyy-MM-dd 00:00:00`(文档写 `yyyy-MM-dd`),取日期请截前 10 位
|
|
147
|
-
- download:**只有 `hasAttachment: true` 的记录能下**(先 list 确认);省略 `--output`
|
|
147
|
+
- download:**只有 `hasAttachment: true` 的记录能下**(先 list 确认);省略 `--output` 用 title-cache 里的真实标题命名,**未命中不再自动回查**(v0.37.0 起),退回服务端文件名或 `<type>-<id>`。要回查加 `--resolve-title`——拉 200 条、按 0.1/条 约 20 积分,取回的标题会写回缓存供同批复用
|
|
148
148
|
- **积分**:list 0.1/条;download A 股 10/篇、港美股 20/篇
|
|
149
149
|
|
|
150
150
|
## 研报 `insight research list/download`
|
|
@@ -216,8 +216,8 @@ gangtise insight foreign-opinion list [--rank-type <n>] [--security <code>] [--r
|
|
|
216
216
|
```
|
|
217
217
|
|
|
218
218
|
- `--security`:境外证券代码,如 `UBER.N`
|
|
219
|
-
- ⚠️ `--region
|
|
220
|
-
- ⚠️ `--industry
|
|
219
|
+
- ⚠️ `--region`:**本端点只接受 6 个取值**——`cn` | `cnHk` | `cnTw` | `us` | `jp` | `uk`。`regionCategory` 常量表里另外 13 个(`sea` / `gl` / `fr` / `de` / `kr` / `in` / `ca` / `me` / `othAs` / `othEur` / `latAm` / `oce` / `af`)在这里一律报 `100005 枚举值非法`,**而它们在 `insight foreign-report` 上全部合法且能正常收窄**。要按这 13 个区域筛,只能用 `foreign-report`,或不带该参数取回后按 `region` 字段本地筛
|
|
220
|
+
- ⚠️ `--industry`:**只认申万码**(`104xx0000`)。中信码报 `100005 枚举值非法`——即使 `reference constant-category` 把本端点列在 `citicIndustry` 的 `usageScopes` 里也一样。⚠️ **返回记录的 `industryList[]` 同时带两套码**(如 `100800122 中信非银` + `104490000 申万非银金融`),**回查时要挑申万那条**,拿中信码回查会报错
|
|
221
221
|
- `--broker`:外资券商 ID(见 `references/lookup-ids.md`)
|
|
222
222
|
- `--rating` / `--rating-change`:同研报
|
|
223
223
|
- 返回字段:`foreignOpinionId` / `title` / `titleTranslate` / `content` / `contentTranslate` / `publishTime` / `publisher{brokerId, brokerName}` / `securityList[]{securityCode, rating, targetPrice, currency}` / `region`
|
|
@@ -230,7 +230,7 @@ gangtise insight independent-opinion download --independent-opinion-id <id> --fi
|
|
|
230
230
|
```
|
|
231
231
|
|
|
232
232
|
- `--security`:境外证券代码,如 `GSK.N`
|
|
233
|
-
- ⚠️ `--industry
|
|
233
|
+
- ⚠️ `--industry`:**只认申万码**(`104xx0000`),中信码报 `100005 枚举值非法`(同 `foreign-opinion`,见上)。返回记录的 `industryList[]` 两套码都带,回查挑申万那条
|
|
234
234
|
- `--rating` / `--rating-change`:同外资观点
|
|
235
235
|
- `--file-type`(download **必选**):`1` 原文 HTML | `2` 中文翻译 HTML
|
|
236
236
|
- 返回字段:`independentOpinionId` / `title` / `titleTranslate` / `brief` / `briefTranslate` / `publishTime` / `analyst{analystId, analystName}` / `securityList[]` / `industryList[]`
|
|
@@ -108,7 +108,7 @@ gangtise reference constant-category [--format json]
|
|
|
108
108
|
>
|
|
109
109
|
> 先记住三套码的归属,**别把行业码算到 `gangtiseIndustry` 头上**:`citicIndustry` = 30 条行业码 `1008001xx`;`swIndustry` = 31 条行业码 `104xx0000`;`gangtiseIndustry` = **只有 6 条方向码** `122000xxx`(宏观 `122000001` / 策略 `122000002` / 固收 `122000003` / 金工 `122000004` / 海外 `122000005` / 其他 `122000007`),里面**没有任何行业**,去它那里找「食品饮料」永远找不到。
|
|
110
110
|
>
|
|
111
|
-
> - **`--industry`(industryList)→ 用 `citicIndustry`(`1008001xx`)**:opinion / research / foreign-report / official-account 正确过滤。`swIndustry`(`104xx0000`)在这 4 个上**也生效,但不是等效**——两套码的行业成分不同,4 个里有 2 个结果集对不上(research / foreign-report 完全一致;**opinion 与 official-account 传两套码取回的条数相差约 2%–5%**)。所以**统一用中信码**,同一批查询里别把两套码混着传。方向码 `122000xxx` 在 `--industry` 上一律返 0。⚠️ 一个例外:`insight foreign-opinion` / `independent-opinion`
|
|
111
|
+
> - **`--industry`(industryList)→ 用 `citicIndustry`(`1008001xx`)**:opinion / research / foreign-report / official-account 正确过滤。`swIndustry`(`104xx0000`)在这 4 个上**也生效,但不是等效**——两套码的行业成分不同,4 个里有 2 个结果集对不上(research / foreign-report 完全一致;**opinion 与 official-account 传两套码取回的条数相差约 2%–5%**)。所以**统一用中信码**,同一批查询里别把两套码混着传。方向码 `122000xxx` 在 `--industry` 上一律返 0。⚠️ 一个例外:`insight foreign-opinion` / `independent-opinion` 的 `--industry` **只认申万码 `104xx0000`**,传中信码报 `100005 枚举值非法`(详见 `insight.md`)。`vault wechat-message-list` 反过来**只认中信码**,传申万码报 `100005`(详见 `vault.md`)。
|
|
112
112
|
> - **`--research-area`(researchAreaList)→ 用 `citicIndustry` 行业码 `1008001xx`,方向再叠 `gangtiseIndustry` 的 `122000xxx`**。⚠️ **申万码 `104xx0000` 只有 `summary` / `pamirs-summary` 认**,其余端点返 0(与传乱码表现一致,不报错)。逐端点实测(同一行业分别传三套码,✅ = 正常过滤,❌ = 返 0):
|
|
113
113
|
>
|
|
114
114
|
> | 端点 | 中信 `1008001xx` | 申万 `104xx0000` | 方向 `122000xxx` |
|
|
@@ -224,9 +224,9 @@ gangtise lookup meeting-org list # 会议/牵头机构全量(--instit
|
|
|
224
224
|
| 银行 / 银行股 | 银行 | `104480000` | `821047.SWI` |
|
|
225
225
|
| 汽车 / 新车 | 汽车 | `104280000` | `821036.SWI` |
|
|
226
226
|
|
|
227
|
-
> ¹ 第 3 列是**申万码**(`104xx0000`),仅在 opinion / research / foreign-report / official-account 上可作 `--industry` 使用,且**与中信码不等效**(opinion / official-account 两套码结果集不同,见上方 ⭐ 权威口径);用于 `--research-area` 时只有 summary / pamirs-summary 认,其余端点返 0。`vault wechat-message-list` 的 `--industry`
|
|
227
|
+
> ¹ 第 3 列是**申万码**(`104xx0000`),仅在 opinion / research / foreign-report / official-account 上可作 `--industry` 使用,且**与中信码不等效**(opinion / official-account 两套码结果集不同,见上方 ⭐ 权威口径);用于 `--research-area` 时只有 summary / pamirs-summary 认,其余端点返 0。`vault wechat-message-list` 的 `--industry` **只认中信码,传申万码报 `100005`**。通用/推荐的**中信码**(`1008001xx`)见 `references/lookup-ids.md` 中信表或 `constant-list --category citicIndustry`。
|
|
228
228
|
|
|
229
|
-
> **参数名选择**:`--industry`(industryList,用 `citicIndustry` 码 `1008001xx`)用于 opinion / research / foreign-report / official-account / `vault wechat-message-list`(后者只认中信码);`foreign-opinion` / `independent-opinion`
|
|
229
|
+
> **参数名选择**:`--industry`(industryList,用 `citicIndustry` 码 `1008001xx`)用于 opinion / research / foreign-report / official-account / `vault wechat-message-list`(后者只认中信码);`foreign-opinion` / `independent-opinion` 的这个参数**只认申万码 `104xx0000`**,见上方 ⭐ 权威口径;`--research-area`(researchAreaList,行业用 `citicIndustry` 码 `1008001xx`、方向用 `gangtiseIndustry` 码 `122000xxx`)用于 opinion / summary / pamirs-summary / roadshow / site-visit / forum / my-conference;`--gts-code` 仅用于 `ai security-clue`(需申万格式 `821xxx.SWI`,不是数字 ID)。注意 strategy(线下策略会)无 `--research-area`,只按 `--institution` / `--location` 筛。
|
|
230
230
|
|
|
231
231
|
> **"消费"歧义**:用户说"消费/大消费"覆盖多个子行业(食品饮料 `104340000` / 商贸零售 `104450000` / 社会服务 `104460000` / 家电 `104330000` / 纺织服饰 `104350000` / 美容护理 `104770000`),需向用户确认具体方向,或用 `--keyword 消费` 做宽泛搜索。
|
|
232
232
|
|
|
@@ -49,7 +49,7 @@ gangtise vault wechat-message-list [--keyword <text>] [--security <code>] [--wec
|
|
|
49
49
|
|
|
50
50
|
- 数据权限:仅用户已绑定并激活群消息助理、且助理已入群的群消息
|
|
51
51
|
- `--security`:按证券代码过滤(如 `000001.SZ`),可重复
|
|
52
|
-
- `--industry`:**只认中信码**(`1008001xx`,见 `reference constant-list --category citicIndustry`)。⚠️ 申万码(`104xx0000
|
|
52
|
+
- `--industry`:**只认中信码**(`1008001xx`,见 `reference constant-list --category citicIndustry`)。⚠️ 申万码(`104xx0000`)与任何不认识的值都报 `100005 枚举值非法`——**换中信码即可**。返回行里不含行业标签字段,过滤在服务端完成
|
|
53
53
|
- 🔴 **`--industry` 是收窄工具,不是全量召回**:行业标签由服务端标注,**同一条消息可能挂多个行业,也可能一个都没挂**。实测同一个关键词加上「本行业」过滤后,命中数掉到三到四成——**少掉的既有没打标签的,也有被标到相邻行业去的**(如半导体相关的消息在计算机 / 机械 / 通信下同样查得到)。所以「按行业筛出 N 条」不能读成「该行业只有 N 条」;要尽量全,用 `--keyword` 取回后本地判断,或把相邻行业码一起查再去重
|
|
54
54
|
- `--wechat-group-id`:先用 `vault wechat-chatroom-list` 查;可重复
|
|
55
55
|
- `--category`:`text` | `image` | `documents` | `url`(可重复)
|
|
@@ -105,7 +105,7 @@
|
|
|
105
105
|
3. Pre-flight:"那个"暗示特定文件 → 🔴 展示结果让用户选择
|
|
106
106
|
4. gangtise vault drive-list --keyword AI --file-type 1 --format json
|
|
107
107
|
5. 展示前 10 条让用户挑 → gangtise vault drive-download --file-id <id>
|
|
108
|
-
|
|
108
|
+
(第 4 步的 drive-list 已把标题写进 title-cache,省略 --output 即自动用真实标题做文件名)
|
|
109
109
|
```
|
|
110
110
|
|
|
111
111
|
## 例 8:跨资源类型语义搜索
|
|
@@ -257,7 +257,7 @@
|
|
|
257
257
|
--date 2026-07-31 --key-by code --format json
|
|
258
258
|
4. 按 security 合并两张宽表(列头即 indicatorCode,各取所需日期的值);不要把不同日期语义的指标塞进同一个 --date。
|
|
259
259
|
5. 计费:search 免费;两次取数各按请求单元格数量计费,每次不足 100 单元格按 100 计。
|
|
260
|
-
6. 无数据(无覆盖 / 非交易日 / 未来日期)一律保留行列并给占位单元格,退出码 0
|
|
260
|
+
6. 无数据(无覆盖 / 非交易日 / 未来日期)一律保留行列并给占位单元格,退出码 0——占位值统一是 null(见 commands/indicator.md);⚠️ 报告期类指标(is_*)的时序只有报告期末那几行是真值,别对整列手工求均值。代码写错或参数名写错则直接报 100003 并点名是哪个(指标码拼错、证券后缀错如美股写成 .US、参数名写错、同 code 重复配置),按报错改即可。
|
|
261
261
|
```
|
|
262
262
|
|
|
263
263
|
## 例 15b:帕米尔专家纪要(新库,筛选项与踩坑都和 summary 不同)
|
|
@@ -6,6 +6,23 @@
|
|
|
6
6
|
|
|
7
7
|
## Quote 行情
|
|
8
8
|
|
|
9
|
+
> ⚠️ **`volume` 的单位是「股」**。四个端点同一口径——`day-kline` / `realtime` / `minute-kline` / `index-day-kline`,A股 / 港股 / 美股一致,历史数据同口径。
|
|
10
|
+
>
|
|
11
|
+
> 🔴 **存量脚本里若对 `volume` 做过 `× 100` 还原股数,要撤掉**——现在会差 100 倍,而数字看着仍然「像个成交量」,不会报错。
|
|
12
|
+
>
|
|
13
|
+
> **一眼自检(仅适用于个股)**:`amount ÷ volume` 得到的均价应落在当日 `[low, high]` 区间内。
|
|
14
|
+
>
|
|
15
|
+
> ⚠️ **这个自检有两类必然失败,不要据此判定数据有问题**:
|
|
16
|
+
>
|
|
17
|
+
> 1. **指数不适用**。指数的 OHLC 是**点位**,而 `amount` / `volume` 是成分股合计,两者量纲不同——比值算出来是成分股均价(上证 / 深成 ≈ 20 元),永远落不进四千点的区间,**数据本身是对的**。
|
|
18
|
+
> 2. 🔴 **美股的 `quote realtime`**。它的 `amount` **恒为 `0`**(见下方 realtime 字段表),自检值必然算出 0。**要美股的实时成交额,只能用别的口径**(收盘后用 `day-kline`,或 EDE `qte_amt`)。
|
|
19
|
+
>
|
|
20
|
+
> 🔴 **分钟线加总对日线时,先看收盘那根**:正常情况下 **Σ分钟 `volume` = 日线 `volume`、Σ分钟 `amount` = 日线 `amount`**,两者都**精确相等**(正常交易日 241 根,逐根加总与日线一致)。
|
|
21
|
+
>
|
|
22
|
+
> ⚠️ **但 `15:00` 那根(收盘集合竞价)会随机返 `volume=0, amount=0`**,此时 Σ分钟比日线少约 1.2%。**这是逐只、逐日、且同一只票重复取也未必一致的**——同一个交易日里,有的标的每次都对得上(Σ分钟 `amount` 与日线只差浮点级),有的则时有时无。**所以不能拿一只票的一次结果推断当天整批数据**,也与「是不是最新交易日」无关。
|
|
23
|
+
>
|
|
24
|
+
> **最省事的对账法:直接拿 `quote day-kline` 的 `amount` 比**——差额若恰好等于某一根,就是那一根在翻。(`14:58` / `14:59` 恒为 0 是**正常的**:14:57 后进入收盘集合竞价,只申报不撮合,成交在 15:00 一次性发生。)
|
|
25
|
+
|
|
9
26
|
### 日K线 `quote day-kline`(A股 / 港股 / 美股 / 各类指数;旧的 `day-kline-hk` / `day-kline-us` 已下线,字段相同)
|
|
10
27
|
|
|
11
28
|
各市场字段相同(货币单位随市场:A股=元、港股=港元、美股=美元;**指数为点位、无货币单位,且 `adjustFactor` 恒为 `null`**):
|
|
@@ -29,8 +46,12 @@
|
|
|
29
46
|
| `open` | 开盘价 | `high` | 最高价 |
|
|
30
47
|
| `low` | 最低价 | `change` | 涨跌额 |
|
|
31
48
|
| `pctChange` | 涨跌幅(%) | `volume` | 成交量(股,当日累计) |
|
|
32
|
-
| `amount` | 成交总额(当日累计) | `amplitude` | 振幅(%) |
|
|
33
|
-
| `turnoverRate` | 换手率(%) | `volumeRatio` | 量比 |
|
|
49
|
+
| `amount` | 成交总额(当日累计)🔴 **美股恒 0** | `amplitude` | 振幅(%) |
|
|
50
|
+
| `turnoverRate` | 换手率(%)🔴 **美股恒 0** | `volumeRatio` | 量比 🔴 **美股恒 0** |
|
|
51
|
+
|
|
52
|
+
> 🔴 **美股的 `amount` / `turnoverRate` / `volumeRatio` 这三个字段恒为 `0`,A股 / 港股正常。** 全市场拉取核对过(2026-08-24):美股有成交的记录里这三个字段全部为 `0`,同一时刻的港股与 A 股则没有一行是 `0`。
|
|
53
|
+
>
|
|
54
|
+
> ⚠️ **`0` 不是「没有成交」**——同一行的 `volume` 是有值的(如 `DTSS.O` `volume=174` 而 `amount=0`)。**取美股实时成交额会静默拿到 `0`、退出码 0、无告警**,直接写进结论就是错数。要美股成交额:收盘后用 `quote day-kline`,或用 EDE `indicator cross-section --indicator qte_amt`。
|
|
34
55
|
|
|
35
56
|
**以上 16 个就是全部**(实测 2026-07-24):**无 `close`**(用 `latestPrice`)、**无市值**(走 `indicator cross-section --indicator qte_mkt_cptl`)。realtime 传了不存在的字段名不会被忽略——上游只丢值、字段名照回显,CLI 检测到长度不匹配会直接报错(v0.28.3 起)。
|
|
36
57
|
|
|
@@ -43,7 +64,7 @@
|
|
|
43
64
|
| `high` | 最高价 | `low` | 最低价 |
|
|
44
65
|
| `close` | 收盘价 | `preClose` | 昨收价 |
|
|
45
66
|
| `change` | 涨跌额 | `pctChange` | 涨跌幅(%) |
|
|
46
|
-
| `volume` | 成交量(
|
|
67
|
+
| `volume` | 成交量(股) | `amount` | 成交总额(元) |
|
|
47
68
|
|
|
48
69
|
---
|
|
49
70
|
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
|
|
7
7
|
## 中信行业分类(--industry 参数)
|
|
8
8
|
|
|
9
|
-
完整列表用 `reference constant-list --category citicIndustry`(30 条)。**`--industry` 全命令通用首选用这套(`1008001xx`)**——opinion / research / foreign-report / official-account 都正确过滤,`vault wechat-message-list` 也认这一套(⚠️ 两个例外:`insight foreign-opinion` / `independent-opinion`
|
|
9
|
+
完整列表用 `reference constant-list --category citicIndustry`(30 条)。**`--industry` 全命令通用首选用这套(`1008001xx`)**——opinion / research / foreign-report / official-account 都正确过滤,`vault wechat-message-list` 也认这一套(⚠️ 两个例外:`insight foreign-opinion` / `independent-opinion` 的 `--industry` **只认申万码 `104xx0000`,传中信码报 `100005`**);这套 ID 同时也是 `--research-area` **行业维度唯一全端点通吃的一套**(见下方研究方向)。
|
|
10
10
|
|
|
11
11
|
| ID | 行业 | ID | 行业 |
|
|
12
12
|
|----|------|----|------|
|
|
@@ -30,7 +30,7 @@
|
|
|
30
30
|
|
|
31
31
|
## 申万行业(--industry 参数)
|
|
32
32
|
|
|
33
|
-
完整列表用 `reference constant-list --category swIndustry`(31 条)。⚠️ 申万码(`104xx0000`)只在**部分** insight list 上可作 `--industry` 使用,且**与中信码不等效**——两套码行业成分不同,实测 opinion 与 official-account 上取回的结果集就对不上(同一行业相差约 2%–5%),别混用;用于 `--research-area` 时**只有 `summary` / `pamirs-summary` 认,其余端点返 0**(不报错,与传乱码表现一致)。`vault wechat-message-list` 的 `--industry`
|
|
33
|
+
完整列表用 `reference constant-list --category swIndustry`(31 条)。⚠️ 申万码(`104xx0000`)只在**部分** insight list 上可作 `--industry` 使用,且**与中信码不等效**——两套码行业成分不同,实测 opinion 与 official-account 上取回的结果集就对不上(同一行业相差约 2%–5%),别混用;用于 `--research-area` 时**只有 `summary` / `pamirs-summary` 认,其余端点返 0**(不报错,与传乱码表现一致)。`vault wechat-message-list` 的 `--industry` **只认中信码**,传申万码报 `100005`——哪套码用于哪些命令的**权威口径见 `references/commands/reference-and-lookup.md`「行业 / 研究方向过滤——选哪套 category」**(含逐端点实测矩阵),勿在此重复枚举。拿不准就统一用上方中信码。
|
|
34
34
|
|
|
35
35
|
| ID | 行业 | ID | 行业 | ID | 行业 |
|
|
36
36
|
|----|------|----|------|----|------|
|
|
@@ -4,7 +4,7 @@ CLI 自动处理 envelope:`{code, msg, data}` 信封会按 `code === "000000"`
|
|
|
4
4
|
|
|
5
5
|
> 例外:`indicator`(EDE)四个接口(`search` / `cross-section` / `time-series` / `screener`)成功时**双层信封**(`data` 里再裹一层 `{code, status, data}`)。内层字段名 2026-08-01 起为 `securityCodeList` / `securityNameList` / `indicatorList[{code,name,dataType}]`(screener 另带 `field`),`values` 是 2D 矩阵:**截面与 screener 为 `[证券][指标]`**(该版转置过,此前是 `[指标][证券]`)、时序仍为 `[序列][日期]`。
|
|
6
6
|
>
|
|
7
|
-
> **缺数据 vs 代码写错**(2026-08-15 实测):无数据 /
|
|
7
|
+
> **缺数据 vs 代码写错**(2026-08-15 实测):无数据 / 无覆盖一律保留行列并给占位单元格——**占位值统一为 `null`**;⚠️ 报告期类指标(`is_*`)的时序只有报告期末那几行是真值,其余全是 `null`,详见 `commands/indicator.md`。**代码写错则直接报 `100003` 并点名**(指标 code 拼错 →「指标 xxx 不存在」;证券 code 后缀错 →「xxx 不是有效证券或者板块ID」,美股是 `.O`/`.N` 不是 `.US`),**无论同批有没有正确的 code 都会报**。CLI 的 `indicator` 子命令已二次解包、拍平成宽表;`partial` + `omittedIndicators`/`omittedSecurities` + 退出码 3 的差集检测仍保留作兜底,但当前服务端行为下基本收不到样本。**`screener` 例外**:把缺列的变量当作无法求值,按表达式的**布尔结构**判断是否还有分支能成立(`A && B` 要两边、`A || B` 只要一边)。一条都不剩 → **退出码 1 且不输出**(那些行以「通过了该条件」的名义呈现,而条件根本无法证明被执行过);仍有分支可求值、或缺的只是输出用的辅助变量 → `partial` + 退出码 3。直接 `raw call indicator.*` 只会剥外层,内层需自行处理。
|
|
8
8
|
|
|
9
9
|
## 通用模式(5 类)
|
|
10
10
|
|