gangtise-openapi-cli 0.28.0 → 0.28.2

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 CHANGED
@@ -4,6 +4,34 @@
4
4
 
5
5
  ## Changelog
6
6
 
7
+ ### v0.28.2 — 2026-07-24
8
+
9
+ EDE 指标批量取数优化(基于对上游 990 个指标的实测)。
10
+
11
+ **新增**
12
+ - `indicator cross-section` / `time-series` 加 `--key-by name|code`(默认 `name`):`code` 模式列头用 `indicatorCode`(时序多证券侧用 `securityCode`),唯一且与服务端返回列序无关。**多证券批量按 code 回填必用**——此前拍平只按指标显示名,而多个指标同名(如 `cf_finc_exp`/`_qtr` 都叫「财务费用」)+ 服务端会重排返回列序,导致按名/按位置都错位、只能绕道 raw API 手工回填
13
+
14
+ **修复**
15
+ - EDE `999999` 无数据提示只对取数端点(`cross-section`/`time-series`)套用,`indicator.search`(同为 no-999999 策略、仅关键词入参)回落通用提示;文案改为「日期匹配指标周期(财务/MRQ 用报告期末、日频估值用交易日)、`scopeList`、`parameterList` 中 required 参数」——修正此前「行情/估值用交易日」与 `finc_pb_mrq` 仅报告期末的矛盾
16
+
17
+ **文档(随包 skill)**
18
+ - `indicator.md`:`--key-by` 文档 + 两处 synopsis;`periodNum` 补「部分需配年报日期」、`startDate` 补「取值须匹配指标周期」
19
+ - `examples.md` 例15:批量三截面示例改用 `--key-by code`
20
+
21
+ ### v0.28.1 — 2026-07-23
22
+
23
+ Agent Skill 文档取数路由对齐(对齐 gangtise-mcp 0.1.46):多证券取一批**已实现**财务/估值指标优先走 EDE `indicator cross-section`/`time-series` 一次拉取,替代逐只 `fundamental` 循环。**本版仅改随包分发的 skill 文档(`gangtise-openapi/`),无 CLI 代码/命令/参数变更。**
24
+
25
+ **路由规则**
26
+ - 单票财务/估值/盈利预测/股东/主营、单票完整三大报表 → 仍走 `fundamental` 专用命令;行情/K 线 → `quote`(免费批量)
27
+ - 多证券已实现财务/估值指标 → 优先 EDE(`cross-section` 单日快照 / `time-series` 单指标×多证券区间)
28
+ - 始终排除 EDE:盈利预测·一致预期、估值历史分位(实测 EDE 无此两类)、OHLCV/K 线、单票完整报表
29
+ - EDE 取数前三项校验:`indicatorName`+`description` 语义 / `scopeList` 覆盖全部目标市场 / `parameterList` 必填参数,任一不符即回退专用接口
30
+
31
+ **实测校正(2026-07-23)**
32
+ - `scope` 字段更正为 `scopeList[].market/.securityType`(服务端已返回实际覆盖),覆盖按指标而异:`finc_pe_ttm`/`finc_pb_mrq` 仅 A 股、`is_op_rev` A 股+港股,均不含美股;`valuation-analysis`/`earning-forecast` 仅 A 股
33
+ - `finc_pb_mrq`(市净率 MRQ) 只在报告期末打值(交易日取 `null`),非日频;EDE 财务指标 `reportType` 枚举 label 与实测取数不符(`value=2/4` 直接 `999999`),要指定报表口径改用 `fundamental` 三大报表 `--report-type`
34
+
7
35
  ### v0.28.0 — 2026-07-21
8
36
 
9
37
  对齐服务端 2026-07-17 更新(内资研报下载调价 + 41 个公开错误码重排)。**41 个码逐个打了线上探针**,结论是迁移按「错误处理层」而非按业务模块进行、文档并不等于现状:同一个接口内,参数校验层与路由层已发新码,方法路由层和 token 过滤器仍发旧码,异步生成状态也仍是旧码。CLI 对两代都识别。
package/dist/src/cli.js CHANGED
@@ -632,15 +632,15 @@ indicator.command("search").requiredOption("--keyword <text>", "Search keyword,
632
632
  });
633
633
  await printData(unwrapIndicatorData(raw), format, options.output);
634
634
  }));
635
- indicator.command("cross-section").option("--indicator <code>", "Indicator code, e.g. qte_close (repeat for multiple)", collectList, []).option("--security <code>", "Security code, e.g. 600519.SH (repeat for multiple)", collectList, []).requiredOption("--date <date>", "Data date (yyyy-MM-dd)", dateArg("--date")).option("--currency <code>", "Currency: DFT/CNY/HKD/USD/EUR/GBP/JPY/TWD/MOP/AUD (default DFT)").option("--scale <code>", "Scale: 0=个 3=千 4=万 6=百万 8=亿 9=十亿 (default 0)").option("--indicator-param <spec>", "Per-indicator param 'code:key=value', e.g. qte_close:adjustmentType=2 for 前复权 (repeat)", collectList, []).option("--format <format>", "Output format", "table").option("--output <path>").action((options) => withClient(async (client) => {
635
+ indicator.command("cross-section").option("--indicator <code>", "Indicator code, e.g. qte_close (repeat for multiple)", collectList, []).option("--security <code>", "Security code, e.g. 600519.SH (repeat for multiple)", collectList, []).requiredOption("--date <date>", "Data date (yyyy-MM-dd)", dateArg("--date")).option("--currency <code>", "Currency: DFT/CNY/HKD/USD/EUR/GBP/JPY/TWD/MOP/AUD (default DFT)").option("--scale <code>", "Scale: 0=个 3=千 4=万 6=百万 8=亿 9=十亿 (default 0)").option("--indicator-param <spec>", "Per-indicator param 'code:key=value', e.g. qte_close:adjustmentType=2 for 前复权 (repeat)", collectList, []).addOption(new Option("--key-by <mode>", "Column key: name=display name (default) | code=indicatorCode, unique & order-stable for batch code→value mapping").choices(["name", "code"]).default("name")).option("--format <format>", "Output format", "table").option("--output <path>").action((options) => withClient(async (client) => {
636
636
  const format = parseOutputFormat(options.format);
637
637
  const raw = await client.call("indicator.cross-section", buildIndicatorCrossSectionBody(options));
638
- await printData(flattenCrossSection(unwrapIndicatorData(raw)), format, options.output);
638
+ await printData(flattenCrossSection(unwrapIndicatorData(raw), options.keyBy), format, options.output);
639
639
  }));
640
- indicator.command("time-series").option("--indicator <code>", "Indicator code, e.g. qte_close (repeat for multiple)", collectList, []).option("--security <code>", "Security code, e.g. 600519.SH (repeat for multiple)", collectList, []).requiredOption("--start-date <date>", "Start date (yyyy-MM-dd)", dateArg("--start-date")).requiredOption("--end-date <date>", "End date (yyyy-MM-dd)", dateArg("--end-date")).option("--calendar-type <type>", "Calendar: ND=natural TD=trading WD=weekday (default TD)").option("--currency <code>", "Currency: DFT/CNY/HKD/USD/EUR/GBP/JPY/TWD/MOP/AUD (default DFT)").option("--scale <code>", "Scale: 0=个 3=千 4=万 6=百万 8=亿 9=十亿 (default 0)").option("--indicator-param <spec>", "Per-indicator param 'code:key=value', e.g. qte_close:adjustmentType=2 for 前复权 (repeat)", collectList, []).option("--format <format>", "Output format", "table").option("--output <path>").action((options) => withClient(async (client) => {
640
+ indicator.command("time-series").option("--indicator <code>", "Indicator code, e.g. qte_close (repeat for multiple)", collectList, []).option("--security <code>", "Security code, e.g. 600519.SH (repeat for multiple)", collectList, []).requiredOption("--start-date <date>", "Start date (yyyy-MM-dd)", dateArg("--start-date")).requiredOption("--end-date <date>", "End date (yyyy-MM-dd)", dateArg("--end-date")).option("--calendar-type <type>", "Calendar: ND=natural TD=trading WD=weekday (default TD)").option("--currency <code>", "Currency: DFT/CNY/HKD/USD/EUR/GBP/JPY/TWD/MOP/AUD (default DFT)").option("--scale <code>", "Scale: 0=个 3=千 4=万 6=百万 8=亿 9=十亿 (default 0)").option("--indicator-param <spec>", "Per-indicator param 'code:key=value', e.g. qte_close:adjustmentType=2 for 前复权 (repeat)", collectList, []).addOption(new Option("--key-by <mode>", "Column key: name=display name (default) | code=indicatorCode/securityCode, unique & order-stable for batch mapping").choices(["name", "code"]).default("name")).option("--format <format>", "Output format", "table").option("--output <path>").action((options) => withClient(async (client) => {
641
641
  const format = parseOutputFormat(options.format);
642
642
  const raw = await client.call("indicator.time-series", buildIndicatorTimeSeriesBody(options));
643
- await printData(flattenTimeSeries(unwrapIndicatorData(raw)), format, options.output);
643
+ await printData(flattenTimeSeries(unwrapIndicatorData(raw), options.keyBy), format, options.output);
644
644
  }));
645
645
  program.addCommand(indicator);
646
646
  program.command("raw").description("Raw API calls").addCommand(new Command("call").argument("<endpointKey>").option("--body <json>").option("--query <key=value>", "Query string pair", collectKeyValue, {}).option("--format <format>", "Output format", "json").option("--output <path>").action(async (endpointKey, options) => {
@@ -423,9 +423,13 @@ export class GangtiseClient {
423
423
  }).catch((error) => {
424
424
  // EDE uses 999999 for "no data for this query" (probed 2026-07-11) — the
425
425
  // generic "系统错误,请稍后重试" hint would send the user retrying a query
426
- // that will never have data. Swap in a context-specific hint.
427
- if (endpoint.retry === 'no-999999' && error instanceof ApiError && error.code === '999999') {
428
- throw new ApiError(error.message, error.code, error.statusCode, error.details, error.retryAfterMs, 'EDE 999999 多为查询无数据(节假日 / 未来日期 / 未覆盖标的)——先检查查询条件,确认应有数据再重试。');
426
+ // that will never have data. Swap in a fetch-specific hint. Only the data
427
+ // endpoints take a date/security/params; indicator.search shares the
428
+ // no-999999 policy but has just a keyword, so it keeps the generic hint
429
+ // instead of nonsensical date/scope/param guidance.
430
+ const isIndicatorFetch = endpoint.key === 'indicator.cross-section' || endpoint.key === 'indicator.time-series';
431
+ if (isIndicatorFetch && error instanceof ApiError && error.code === '999999') {
432
+ throw new ApiError(error.message, error.code, error.statusCode, error.details, error.retryAfterMs, 'EDE 的 999999 多为查询无数据——先核对:日期匹配指标周期(财务/MRQ 用报告期末如 2025-12-31、日频估值用交易日)、标的在 scopeList 覆盖内、parameterList 中 required 参数已补;确认应有数据再重试。');
429
433
  }
430
434
  throw error;
431
435
  });
@@ -59,7 +59,11 @@ function buildHeaders(names, codes, count) {
59
59
  // Cross-section: one row per security, one column per indicator. The live
60
60
  // `values` is a 2D [numIndicators][numSecurities] matrix in indicator-major
61
61
  // order, so indicator i on security j is values[i][j].
62
- export function flattenCrossSection(data) {
62
+ // keyBy "code" makes each indicator column its `indicatorCode` (unique, and
63
+ // independent of the display name or the server's column order) instead of the
64
+ // human name — required for batch code→value mapping, where names collide
65
+ // (many indicators share a display name) and the server reorders columns.
66
+ export function flattenCrossSection(data, keyBy = "name") {
63
67
  if (!data || typeof data !== "object")
64
68
  return data;
65
69
  const d = data;
@@ -68,7 +72,7 @@ export function flattenCrossSection(data) {
68
72
  if (!Array.isArray(d.values) || !securityCode || !indicators)
69
73
  return data;
70
74
  const securityName = asStringArray(d.securityNameList);
71
- const headers = buildHeaders(asStringArray(d.indicatorNameList), indicators, indicators.length);
75
+ const headers = buildHeaders(keyBy === "code" ? indicators : asStringArray(d.indicatorNameList), indicators, indicators.length);
72
76
  const list = securityCode.map((code, j) => {
73
77
  const row = { date: d.date, security: code, name: securityName?.[j] };
74
78
  for (let i = 0; i < indicators.length; i++) {
@@ -81,7 +85,7 @@ export function flattenCrossSection(data) {
81
85
  // Time-series: one row per date. Columns are the indicators (single-security
82
86
  // case) or the securities (single-indicator case) — exactly one dimension
83
87
  // varies, per the API contract. `values` is a 2D [series][date] matrix.
84
- export function flattenTimeSeries(data) {
88
+ export function flattenTimeSeries(data, keyBy = "name") {
85
89
  if (!data || typeof data !== "object")
86
90
  return data;
87
91
  const d = data;
@@ -92,8 +96,8 @@ export function flattenTimeSeries(data) {
92
96
  return data;
93
97
  const seriesAreIndicators = securityCode.length <= 1;
94
98
  const headers = seriesAreIndicators
95
- ? buildHeaders(asStringArray(d.indicatorNameList), indicators, indicators.length)
96
- : buildHeaders(asStringArray(d.securityNameList), securityCode, securityCode.length);
99
+ ? buildHeaders(keyBy === "code" ? indicators : asStringArray(d.indicatorNameList), indicators, indicators.length)
100
+ : buildHeaders(keyBy === "code" ? securityCode : asStringArray(d.securityNameList), securityCode, securityCode.length);
97
101
  const list = dates.map((date, k) => {
98
102
  const row = { date };
99
103
  for (let i = 0; i < headers.length; i++) {
@@ -1,2 +1,2 @@
1
1
  // Auto-generated — DO NOT EDIT
2
- export const CLI_VERSION = "0.28.0";
2
+ export const CLI_VERSION = "0.28.2";
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: gangtise-openapi
3
- version: "0.28.0"
3
+ version: "0.28.2"
4
4
  description: |-
5
5
  通过 gangtise CLI 直接调用 Gangtise OpenAPI,拉取投研原始数据、批量导出、下载文件、调用 AI 能力。
6
6
 
@@ -127,12 +127,12 @@ description: |-
127
127
  | 分钟 K(A 股) | `quote minute-kline` |
128
128
  | 实时行情(A / 港 / 美) | `quote realtime` |
129
129
  | A股资金流向(主力/大单净流入,日频) | `quote fund-flow`(`--security` 或 `aShares` 全市场〔须带 `--start-date`/`--end-date`,按日自动分片〕;免费) |
130
- | A股利润表 / 资产负债 / 现金流(累计 / 单季) | `fundamental income-statement[-quarterly] / balance-sheet / cash-flow[-quarterly]` |
131
- | 港股利润表 / 资产负债 / 现金流 | `fundamental income-statement-hk / balance-sheet-hk / cash-flow-hk` |
132
- | 美股利润表 / 资产负债 / 现金流 | `fundamental income-statement-us / balance-sheet-us / cash-flow-us` |
133
- | 主营业务 / 收入结构 | `fundamental main-business` |
134
- | 估值 / PE / PB | `fundamental valuation-analysis` |
135
- | 盈利预测 / 一致预期 | `fundamental earning-forecast` |
130
+ | 单证券 A股完整利润表 / 资产负债 / 现金流(累计 / 单季) | `fundamental income-statement[-quarterly] / balance-sheet / cash-flow[-quarterly]` |
131
+ | 单证券 港股完整利润表 / 资产负债 / 现金流 | `fundamental income-statement-hk / balance-sheet-hk / cash-flow-hk` |
132
+ | 单证券 美股完整利润表 / 资产负债 / 现金流 | `fundamental income-statement-us / balance-sheet-us / cash-flow-us` |
133
+ | 单证券主营业务 / 收入结构 | `fundamental main-business` |
134
+ | A股单证券估值序列 / PE / PB / 历史分位 | `fundamental valuation-analysis` |
135
+ | A股盈利预测 / 一致预期 | `fundamental earning-forecast` |
136
136
  | 前十大股东 | `fundamental top-holders` |
137
137
  | 云盘文件 | `vault drive-list / drive-download` |
138
138
  | 录音速记 | `vault record-list / record-download` |
@@ -143,9 +143,9 @@ description: |-
143
143
  | 行业指标时序数据(EDB) | `alternative edb-data` |
144
144
  | 题材画像 / 投资逻辑 / 行业空间 / 竞争格局 / 催化事件 | `alternative concept-info`(前置:`reference concept-search` 拿 `concept-id`) |
145
145
  | 题材成分股 / 题材深度 F8 / 题材龙头 | `alternative concept-securities`(前置:`reference concept-search` 拿 `concept-id`) |
146
- | 指标搜索 / 找指标编码(收盘价/成交量/总市值/财务指标的 code) | `indicator search` |
147
- | 指标截面数据(多指标 × 多证券,单日快照) | `indicator cross-section`(前置:`indicator search` indicatorCode) |
148
- | 指标时间序列(多指标 × 单证券 或 单指标 × 多证券,按区间) | `indicator time-series`(前置:`indicator search` indicatorCode) |
146
+ | 多证券已实现财务 / 估值指标搜索(含总市值) | `indicator search` |
147
+ | 多证券已实现指标截面(多指标 × 多证券,同一查询日期) | `indicator cross-section`(前置:`indicator search --format json` 通过三项校验) |
148
+ | 多证券已实现指标时序(单指标 × 多证券,按区间) | `indicator time-series`(前置:`indicator search --format json` 通过三项校验) |
149
149
  | 证券代码 / gtsCode 搜索 | `reference securities-search` |
150
150
  | 首席 ID / 分析师 ID 搜索 | `reference chiefs-search`(按姓名/机构/团队,用于 `insight opinion --chief`) |
151
151
  | 机构 ID 搜索(内资券商/外资/牵头/观点机构) | `reference institution-search`(按机构名,用于 `--institution` / `--broker`;免费) |
@@ -160,11 +160,15 @@ description: |-
160
160
  - "搜索 X" → 数据维度精确(按行业/券商)走对应 `insight ... list`;跨类型语义搜索走 `ai knowledge-batch`
161
161
  - 港股代码用在 `insight foreign-opinion --security` 还是 `quote day-kline-hk --security`?前者要"境外"格式(`UBER.N`),后者要 `.HK`
162
162
  - "成分股" → 题材深度(分组/重点标记/纳入理由)走 `alternative concept-securities`;板块(行业/概念分类树,纯代码名单)走 `reference sector-constituents`
163
- - "指标" 证券级指标(总市值/估值分位/财务指标等,需 `--security` 证券代码)走 `indicator`(EDE);**但基础行情(收盘价/开高低收/成交量/成交额/涨跌幅)优先 `quote`**(免费、可 `--security all` 自动分片;`indicator` 按单元格计费且需先 search 拿 code);行业/宏观指标(空调销量、社融等,无证券维度)走 `alternative edb-*`(EDB),三套接口不同
164
- - `indicator` 取数二选一:单日多标的横向对比 `cross-section`;时间区间纵向走势 `time-series`(且 `time-series` 不能多指标 × 多证券同时,截面才可以)
165
- - `indicator` 取数前**先 `search --format json` `parameterList`**:很多指标有必填参数(`periodNum`/`startDate`/`fiscalYear`),不补会报错(服务端现直接指明「必填参数 X 不能为空」);**无数据已统一返回 `null`**(截面不再抛 `999999`、不丢行),换公司类型/年报日期可取到对应类型科目的数。**取"最新"值别踩空**:行情类 `--date` 填当天且盘中/未入库会整行 `null`(≠无数据,别据此报"无数据"),改用 T-1 交易日;财务类用报告期末(如 `2025-12-31`)。详见 `references/commands/indicator.md`
163
+ - **证券基本面 / 指标先按任务形态路由,不是搜到 EDE 就一律走 EDE**:
164
+ - 单证券先优先对应 `fundamental` 专用命令(财务、估值、盈利预测、股东、主营或完整三大报表,多数免费 / 低价)。其中 `valuation-analysis` / `earning-forecast` 实测仅支持 A 股;港 / 美股的估值历史分位、盈利预测、以及 PE/PB 等核心估值(EDE 也仅 A 股)当前 CLI 均无可用接口,如实说明不支持、勿用别的语义顶替
165
+ - 多证券批量取一组**已实现**财务 / 估值指标 优先 `indicator search` 后用 EDE 一次拉取,替代逐只循环;单日或同一报告期横向比较用 `cross-section`,区间走势用 `time-series`(后者不能多指标 × 多证券同时)。**批量按 code 回填加 `--key-by code`**(列头用 `indicatorCode`,防同名指标碰撞 + 服务端重排列序导致的错位)
166
+ - 始终排除 EDE:A股盈利预测 / 一致预期(含预测 EPS)→ `fundamental earning-forecast`;A股估值历史分位 → `fundamental valuation-analysis`;开高低收 / 成交量等行情与 K 线 → `quote`;单证券完整报表 → 对应三大报表命令。EDE 搜到的基本 / 稀释 EPS 是已实现值,**不能冒充预测 EPS**;港 / 美股缺少上述专用能力时应如实说明不支持,不能用别的语义代替
167
+ - EDE 取数前必须用 `search --format json` 同时核对:`indicatorName` + `description` 语义准确、`scopeList` 覆盖全部目标市场 / 证券类型、`parameterList` 必填参数与枚举可满足;`scopeList` 缺失 / `null` / 空或任一项不符,都视为无法证明覆盖并回退专用接口。专用接口也不覆盖目标市场时,说明当前不可用,不要硬调。`scopeList` 按指标各不相同,不能因 EDE 服务支持 A / 港 / 美股就假定某个指标三市场都覆盖
168
+ - `indicator search` 免费,`cross-section` / `time-series` 按单元格计费;除多证券批量的效率收益外,仍优先免费 / 低价的 `quote` 或 `fundamental`
169
+ - 行业 / 宏观指标(空调销量、社融等,无证券维度)走 `alternative edb-*`(EDB),不要与证券级 EDE 混用
170
+ - EDE 单元格级缺值返回 `null` 且保留证券行;**整个查询无数据仍可能报 `999999`**。日期语义按指标分三类:财务报表指标=报告期末(可为非交易日)、`finc_pe_ttm` 等日频估值=最新交易日、`finc_pb_mrq`(MRQ) 等=最近报告期末(交易日取 `null`);混合取数按各自有效日期分次 `cross-section` 再按证券合并,别塞进同一个 `--date`。详见 `references/commands/indicator.md`
166
171
  - "业绩点评"双义消歧:**检索已有**(研报/纪要里的业绩点评内容)走 `insight ... list --llm-tag earningsReview`(0.1/条);**AI 现生成**一份走 `ai earnings-review`(异步、50/次)。不确定问一句
167
- - "多公司最新 PE / 总市值":单证券估值序列走 `fundamental valuation-analysis`(免费、默认近一年日频、**无总市值指标**);要总市值或多证券横向快照走 `indicator cross-section`(先 search 拿 code,按单元格计费)。总市值 `qte_mkt_cptl` **仅 A 股**、默认原始「元」(茅台 ≈1.5e12),比大小前用 `scale`/`currency` 统一(详见 indicator.md)
168
172
 
169
173
  ## 公司名 → 证券代码
170
174
 
@@ -1,6 +1,6 @@
1
1
  # Fundamental 命令详细参数
2
2
 
3
- 通用:所有命令都需 `--security-code`(如 `600519.SH`,注意是 `--security-code` 不是 `--security`)。`--field` 可重复,可用字段见 `references/fields.md`。
3
+ 通用:所有命令都需 `--security-code`(如 `600519.SH`,注意是 `--security-code` 不是 `--security`)。`--field` 可重复,可用字段见 `references/fields.md`;A / 港 / 美股三大报表命令都在省略 `--field` 时返回完整报表,指定后只保留基础字段与所选科目。
4
4
 
5
5
  ---
6
6
 
@@ -76,22 +76,24 @@ gangtise fundamental main-business --security-code <code> [--breakdown <type>] [
76
76
  - 默认时间窗:`endDate` 当前日期、`startDate` 三年前
77
77
  - **不支持 `--fiscal-year`**(误传触发 `100001`/`100003`,旧 `900001`);按年份筛选用 `--start-date`/`--end-date`
78
78
 
79
- ## 估值分析 `fundamental valuation-analysis`
79
+ ## A股估值分析 `fundamental valuation-analysis`
80
80
 
81
81
  ```bash
82
82
  gangtise fundamental valuation-analysis --security-code <code> --indicator <name> [--start-date <date>] [--end-date <date>] [--limit <n>] [--field <name>] [--skip-null]
83
83
  ```
84
84
 
85
+ - **市场与路由**:本命令实测仅支持 A 股(港股 / 美股会报 `120001`「非有效A股」)。A股单证券估值序列与估值历史分位始终优先本命令;多证券批量取一组已实现估值点值,且 `indicator search` 三项校验都通过时,才优先 EDE `cross-section` / `time-series`。港 / 美股估值历史分位当前 CLI 不支持,不能用普通 EDE 点值冒充
85
86
  - `--indicator`(**必选**):`peTtm` 滚动PE | `pbMrq` PB | `peg` PEG | `psTtm` 滚动PS | `pcfTtm` 滚动PCF | `em` 企业倍数
86
87
  - `--limit` 默认 2000,省略 `--start-date` 时自动查近一年
87
88
  - `--skip-null`:丢弃 `value`/`percentileRank` 为 null 的行(最新交易日可能未入库)
88
89
 
89
- ## 盈利预测 `fundamental earning-forecast`
90
+ ## A股盈利预测 `fundamental earning-forecast`
90
91
 
91
92
  ```bash
92
93
  gangtise fundamental earning-forecast --security-code <code> [--start-date <date>] [--end-date <date>] [--consensus <name>]
93
94
  ```
94
95
 
96
+ - **市场与路由**:本命令实测仅支持 A 股(港股 / 美股会报 `120001`「非有效A股」)。A股盈利预测 / 一致预期始终走本命令,不走 EDE;EDE 搜索目前没有一致预期语义,搜到的基本 / 稀释 EPS 是已实现值,不能冒充预测 EPS。港 / 美股盈利预测当前 CLI 不支持
95
97
  - `--start-date` / `--end-date`:默认近一年
96
98
  - `--consensus` 可重复:`netIncome` 归母净利润 | `netIncomeYoy` 同比增速 | `eps` 每股收益 | `pe` 市盈率 | `bps` 每股净资产 | `pb` 市净率 | `peg` PEG | `roe` 净资产收益率 | `ps` 市销率
97
99
  - 返回结构:`{securityCode, securityName, updateList: [{date, fieldList: [{forecastYear, ...consensus}]}]}` — 每个日期固定返回 3 年预测(如 `2026E` / `2027E` / `2028E`)
@@ -1,24 +1,38 @@
1
1
  # Indicator 命令详细参数(数据指标 EDE:证券级指标截面 / 时序)
2
2
 
3
- > 本组覆盖 `/application/open-indicator/EDE/*`:证券级**数据指标**的检索与取数(收盘价、成交量、总市值、财务指标等,按个股取值)。
3
+ > 本组覆盖 `/application/open-indicator/EDE/*`:证券级**数据指标**的检索与取数,主要用于多证券批量取已实现财务 / 估值指标。即使能搜到收盘价、成交量等行情指标,常规行情与 K 线仍走免费的 `quote`。
4
4
  > 与 `alternative edb-*`(EDB 行业/宏观指标,无证券维度)是两套接口,别混。
5
5
  >
6
6
  > **取数前先 `indicator search` 拿 `indicatorCode`**,绝不猜测指标编码。
7
7
 
8
+ ## EDE 与专用接口的优先级
9
+
10
+ | 请求形态 | 优先接口 |
11
+ | :--- | :--- |
12
+ | 单证券的财务 / 股东 / 主营,或 A股单证券估值 | 对应 `fundamental` 专用命令;多数免费,且字段口径固定 |
13
+ | 多证券批量取一组**已实现**财务 / 估值指标 | 先 `indicator search`,通过下方三项校验后用 `cross-section` / `time-series` 一次拉取,避免逐只循环 |
14
+ | A股盈利预测 / 一致预期(含预测 EPS) | `fundamental earning-forecast`;EDE 搜到的基本 / 稀释 EPS 是已实现值,不能替代预测 |
15
+ | A股估值历史分位 | `fundamental valuation-analysis` |
16
+ | 开高低收 / 成交量等行情与 K 线 | `quote`;免费且支持多证券批量 |
17
+ | 单证券三大报表全部科目 | 对应 `fundamental` 利润表 / 资产负债表 / 现金流量表命令 |
18
+
19
+ EDE 不是“搜到就优先”。取数前必须核对:① `indicatorName` + `description` 与目标语义一致;② `scopeList` 覆盖**全部**目标市场和证券类型;③ `parameterList` 的必填参数与枚举可满足。`scopeList` 缺失 / `null` / 空或任一项不符,都视为无法证明覆盖并回退上表的专用接口;专用接口也不支持目标市场时,如实说明当前 CLI 无可用口径,不能用其他语义代替。实测 `valuation-analysis` / `earning-forecast` 仅支持 A 股,港 / 美股估值历史分位与盈利预测当前无可用口径;PE/PB 等核心估值指标 EDE 也只有 A 股(`finc_pe_ttm`/`finc_pb_mrq` 均 `[A股]`),别假定港 / 美股估值能从 EDE 取,一律以 `scopeList` 为准。`search` 免费,EDE 取数按单元格计费;除多证券批量的效率收益外,仍优先免费 / 低价的 `quote` 或 `fundamental`。
20
+
8
21
  ## 指标搜索 `indicator search`
9
22
 
10
23
  ```bash
11
24
  gangtise indicator search --keyword <text> [--limit <n>]
12
25
  ```
13
26
 
14
- - `--keyword`(**必选**):按指标名称模糊匹配。用具体词,如 `收盘价` / `成交量` / `营业收入` / `总市值`,**不能用整句白话**("我想查茅台的收盘价" ✗)
27
+ - `--keyword`(**必选**):按指标名称模糊匹配。用具体词,如 `营业收入` / `基本每股收益` / `市盈率` / `总市值`,**不能用整句白话**("我想查一批公司的财务估值" ✗)
15
28
  - `--limit`:返回条数上限,默认 50,最大 100
16
- - 默认 `--format table`(看 `indicatorCode` / `indicatorName` / `description` 即可);要看每个指标支持哪些参数(`parameterList`),用 `--format json`
17
- - 返回字段:`indicatorCode` / `indicatorName` / `description`(算法)/ `parameterList`(可传的 `--indicator-param` 参数及枚举)/ `score`(`scope` 适用市场/品种字段服务端当前多返 `null`)
18
- - **市场范围**:指标数据覆盖 A / 港股 / 美股(2026-07 起扩展,此前仅 A 股)。美股代码用交易所后缀 `.O`(NASDAQ) / `.N`(NYSE),**不是 `.US`**——实测 `AAPL.US` 查不到数据,须用 `AAPL.O`(官方示例里的 `AAPL.US` 是笔误)
29
+ - 默认 `--format table` 只适合浏览名称;正式路由 / 取数前必须加 `--format json`,才能完成语义、`scopeList`、`parameterList` 三项校验
30
+ - 返回字段:`indicatorCode` / `indicatorName` / `description`(算法与口径)/ `scopeList`(该指标适用的市场 + 证券类型)/ `parameterList`(可传的 `--indicator-param` 参数及枚举)/ `score`
31
+ - **市场范围按指标判断**:`scopeList` 现在会返回实际覆盖范围,且指标之间不同;不能笼统写成每个指标都覆盖 A / / 美股。实测 `finc_pe_ttm` / `finc_pb_mrq` A 股,`is_op_rev` 覆盖 A + 港股,这些财务 / 估值指标均不含美股。目标列表含任一 scope 外证券时,本批 EDE 校验不通过,应回退专用接口
32
+ - 美股代码用交易所后缀 `.O`(NASDAQ) / `.N`(NYSE),**不是 `.US`**——实测 `AAPL.US` 查不到数据,须用 `AAPL.O`(官方示例里的 `AAPL.US` 是笔误)
19
33
 
20
34
  ```bash
21
- gangtise indicator search --keyword 收盘价 --limit 5 --format json # parameterList
35
+ gangtise indicator search --keyword 营业收入 --limit 10 --format json # 做语义 + scopeList + parameterList 三项校验
22
36
  ```
23
37
 
24
38
  ## 指标截面数据 `indicator cross-section`
@@ -26,25 +40,26 @@ gangtise indicator search --keyword 收盘价 --limit 5 --format json # 看 pa
26
40
  ```bash
27
41
  gangtise indicator cross-section --indicator <code> [--indicator <code2>] \
28
42
  --security <code> [--security <code2>] --date <yyyy-MM-dd> \
29
- [--currency <c>] [--scale <s>] [--indicator-param <spec>]
43
+ [--currency <c>] [--scale <s>] [--indicator-param <spec>] [--key-by name|code]
30
44
  ```
31
45
 
32
46
  - `--indicator`(**至少 1 个**):指标编码,来自 `search`,可重复传多个
33
47
  - `--security`(**至少 1 个**):证券代码,如 `600519.SH`(A股)/ `09992.HK`(港股)/ `AAPL.O`(美股,用 `.O`/`.N` 后缀,非 `.US`),可重复传多个
34
- - `--date`(**必选**):数据日期 `yyyy-MM-dd`(须为交易日,非交易日/无数据日返回空)
48
+ - `--date`(**必选**):数据日期 `yyyy-MM-dd`;日期语义按指标分三类——财务报表指标=报告期末(可为非交易日,实测 `2024-03-31` 可取数)、`finc_pe_ttm` 等日频估值=交易日、`finc_pb_mrq`(MRQ) 等=最近报告期末(交易日取 `null`,详见下方「日期路由」)。单元格级缺值返回 `null`,整个查询无数据可能报 `999999`
35
49
  - `--currency`:币种 `DFT`(原始,默认)/`CNY`/`HKD`/`USD`/`EUR`/`GBP`/`JPY`/`TWD`/`MOP`/`AUD`
36
50
  - `--scale`:量纲 `0`(个,默认)/`3`(千)/`4`(万)/`6`(百万)/`8`(亿)/`9`(十亿)
37
51
  - **支持多指标 × 多证券**(单日横截面)
38
52
  - **输出(宽表)**:每行一只证券,列为 `date / security / name / <各指标名>…`
53
+ - **`--key-by name|code`**(默认 `name`):指标列头用显示名还是 `indicatorCode`。**批量按 code 回填必用 `--key-by code`**——指标名会碰撞(多个指标同显示名,如 `cf_finc_exp`/`_qtr` 都叫「财务费用」)、服务端还会重排返回列序,唯有 code 唯一且与顺序无关(行轴 `security` 本就是 code,`code` 模式整表可按 code 寻址,免去 raw API 手工回填)
39
54
 
40
55
  ```bash
56
+ # 多证券 × 同一报告期的已实现财务指标
41
57
  gangtise indicator cross-section \
42
- --indicator qte_close --indicator qte_vol --indicator qte_mkt_cptl \
43
- --security 600519.SH --security 09992.HK \
44
- --date 2026-05-18 --format table
45
- # date security name 日收盘价 成交量 总市值
46
- # 2026-05-18 600519.SH 贵州茅台 1323 4966097 1656753494445
47
- # 2026-05-18 09992.HK 泡泡玛特 150.7 15301079 20209520.2705
58
+ --indicator is_op_rev --indicator is_eps_bas \
59
+ --security 600519.SH --security 000858.SZ --security 300750.SZ \
60
+ --date 2025-12-31 --format table
61
+ # 列:date / security / name / 营业收入(利润表,累计) / 基本每股收益(利润表,累计)
62
+ # 省略 reportType 即取到合并口径数(茅台2025=1688亿)。⚠️ 该枚举 label 与实测不符:label 标 1母公司/2合并/3母公司调整/4合并调整,实测 value=2/4 直接 999999、value=1 反返合并值——要指定报表口径改用 `fundamental income-statement --report-type`,勿在 EDE 按 label 传 reportType
48
63
  ```
49
64
 
50
65
  ## 指标时间序列 `indicator time-series`
@@ -52,7 +67,7 @@ gangtise indicator cross-section \
52
67
  ```bash
53
68
  gangtise indicator time-series --indicator <code> [--indicator <code2>] \
54
69
  --security <code> [--security <code2>] --start-date <date> --end-date <date> \
55
- [--calendar-type <ND|TD|WD>] [--currency <c>] [--scale <s>] [--indicator-param <spec>]
70
+ [--calendar-type <ND|TD|WD>] [--currency <c>] [--scale <s>] [--indicator-param <spec>] [--key-by name|code]
56
71
  ```
57
72
 
58
73
  - `--indicator` / `--security`:同上,但**只允许「多指标 × 单证券」或「单指标 × 多证券」**,不能两边都多个(要多 × 多用 `cross-section`,否则报 `410001`)
@@ -60,24 +75,19 @@ gangtise indicator time-series --indicator <code> [--indicator <code2>] \
60
75
  - `--calendar-type`:日期类型 `ND`(自然日)/`TD`(交易日,默认)/`WD`(工作日)
61
76
  - `--currency` / `--scale`:同 `cross-section`
62
77
  - **输出(宽表)**:每行一个日期,列为 `date / <各序列名>…`;序列在「单证券」时是各**指标**,在「多证券」时是各**证券**
78
+ - **`--key-by name|code`**(默认 `name`):同 `cross-section`;`code` 模式下单证券列=各 `indicatorCode`、多证券列=各 `securityCode`,批量按 code 回填用它
63
79
 
64
80
  ```bash
65
- # 多指标 × 单证券:列 = 指标
66
- gangtise indicator time-series --indicator qte_close --indicator qte_vol \
67
- --security 600519.SH --start-date 2026-05-18 --end-date 2026-05-22
68
- # date 日收盘价 成交量
69
- # 2026-05-18 1323 4966097 ...
70
-
71
- # 单指标 × 多证券:列 = 证券
72
- gangtise indicator time-series --indicator qte_close \
73
- --security 600519.SH --security 09992.HK --start-date 2026-05-18 --end-date 2026-05-22
74
- # date 贵州茅台 泡泡玛特
75
- # 2026-05-18 1323 150.7 ...
81
+ # 单个已实现估值指标 × 多证券:列 = 证券
82
+ gangtise indicator time-series --indicator finc_pe_ttm \
83
+ --security 600519.SH --security 000858.SZ --security 300750.SZ \
84
+ --start-date 2026-05-18 --end-date 2026-05-22
85
+ # date 贵州茅台 五粮液 宁德时代
76
86
  ```
77
87
 
78
88
  ## 复权 / 指标专属参数 `--indicator-param`
79
89
 
80
- 通用的币种/量纲用 `--currency` / `--scale`;指标**专属**参数(如行情复权方式)用 `--indicator-param`,格式 `指标code:参数key=值`,可重复:
90
+ 通用的币种/量纲用 `--currency` / `--scale`;指标**专属**参数用 `--indicator-param`,格式 `指标code:参数key=值`,可重复。下面的行情复权仅演示底层参数语法;常规行情 / K 线仍优先 `quote`,不要照此例改走 EDE:
81
91
 
82
92
  ```bash
83
93
  # 茅台收盘价后复权(adjustmentType=3)
@@ -88,7 +98,7 @@ gangtise indicator cross-section --indicator qte_close --security 600519.SH \
88
98
 
89
99
  - `adjustmentType`(复权方式):`1`=不复权 `2`=前复权 `3`=后复权 `4`=定点复权
90
100
  - 同一指标多个参数 → 重复 `--indicator-param "code:k1=v1" --indicator-param "code:k2=v2"`
91
- - 某指标支持哪些 `paramKey` 及其枚举值,用 `indicator search --format json` 看该指标的 `parameterList`(**参数 key 与取值(含大小写)均以 search 返回为准**——如 `currency` 在 parameterList 中可能为小写 `dft`/`cny`)
101
+ - 三项校验通过后,再从 `indicator search --format json` `parameterList` 读取该指标支持的 `paramKey` 及枚举值(**参数 key 与取值(含大小写)均以 search 返回为准**——如 `currency` 在 parameterList 中可能为小写 `dft`/`cny`)
92
102
  - `--indicator-param` 与根级 `--currency`/`--scale` 冲突时,以 `--indicator-param` 为准
93
103
 
94
104
  ## 必填参数与错误码(取数前必读)
@@ -99,38 +109,41 @@ gangtise indicator cross-section --indicator qte_close --security 600519.SH \
99
109
  | :--- | :--- | :--- |
100
110
  | `410001` | 入参错误:没传指标/证券,或 `time-series` 传了「多指标 × 多证券」 | 补齐 `--indicator`/`--security`;多 × 多改用 `cross-section` |
101
111
  | 缺参报错(曾为 `410106`) | **缺必填参数**:服务端现已直接指明缺哪个,如「指标 X 的必填参数 periodNum(期数) 不能为空」(仍以 HTTP 500 返回,CLI 重试 2 次后透出该消息) | 读 `search --format json` 的 `parameterList`,把 `required:true` 的参数用 `--indicator-param` 补上 |
102
- | `999999` | **多为整查询无数据**(节假日 / 未来日期 / 未覆盖标的;单元格级缺值才是 `null`),也可能是真系统故障——服务端不区分两者 | CLI 对 indicator 端点**不重试此码**(v0.27.0)并在 hint 中提示;先核对日期是交易日、标的在覆盖范围,确认应有数据仍报错才按系统故障处理 |
112
+ | `999999` | **多为整查询无数据**(日期语义不符 / 未来日期 / 未覆盖标的;单元格级缺值才是 `null`),也可能是真系统故障——服务端不区分两者 | CLI 对 indicator 端点**不重试此码**(v0.27.0)并在 hint 中提示;先核对日期符合指标语义、标的在覆盖范围,确认应有数据仍报错才按系统故障处理 |
103
113
  | `130001`(旧 `410004`) | 数据未找到,或**该指标无权限**(内层信封失败会带具体 msg,如"指标无权限";此码被服务端复用) | 检查查询条件与指标权限;换证券/日期仍失败多为无权限,联系管理员开通 |
104
114
 
105
115
  ### 必填参数(`410106` 的根因)
106
116
 
107
- 相当一部分指标默认调用就报 `410106`,因为有必填参数没传。**取数前先 `search --format json` `parameterList`,凡 `required:true` 的都用 `--indicator-param "指标code:参数=值"` 补上。** 三类高频必填参数:
117
+ 相当一部分指标默认调用就报 `410106`,因为有必填参数没传。**先完成语义 + `scopeList` + `parameterList` 三项校验;其中凡 `required:true` 的参数都用 `--indicator-param "指标code:参数=值"` 补上。** 三类高频必填参数:
108
118
 
109
119
  | 参数 | 适用指标 | 示例 |
110
120
  | :--- | :--- | :--- |
111
- | `periodNum` | N 期统计(N 期均值/最值,如 `finc_roe_avg_avg` 平均ROE N期均值) | `--indicator-param "finc_roe_avg_avg:periodNum=4"` |
112
- | `startDate` | 区间/周期类,整数 `YYYYMMDD`(含全部 `qte` 周期变体,如 `qte_amp_mo` 月振幅、换手率) | `--indicator-param "qte_amp_mo:startDate=20260401"` |
121
+ | `periodNum` | N 期统计(N 期均值/最值,如 `finc_roe_avg_avg` 平均ROE N期均值) | `--indicator-param "finc_roe_avg_avg:periodNum=4"`;部分还需配**年报日期**才出数(实测 `finc_roe_avg_avg`@`2026-03-31` 空、@`2025-12-31` 有) |
122
+ | `startDate` | 区间/周期类,整数 `YYYYMMDD`(含全部 `qte` 周期变体,如 `qte_amp_mo` 月振幅、换手率) | `--indicator-param "qte_amp_mo:startDate=20260401"`;取值须匹配该指标**周期**(月/季/周/年窗口不同,`20260101` 未必命中,空则按变体周期调 `startDate`) |
113
123
  | `fiscalYear` | 年度/报告期类(如 `div_cash_yr` 年度现金分红) | `--indicator-param "div_cash_yr:fiscalYear=2025"` |
114
124
 
115
125
  > `paramValue` 一律按**字符串**约定传(`periodNum=4` 内部即 `"4"`,CLI 已处理)。
116
126
 
117
127
  ## 取数最佳实践
118
128
 
119
- - **先 search parameterList**:一步拿到 code、必填参数(required)、专属参数枚举(`adjustmentType`/`scale`/`currency` 等)。
129
+ - **先 search 做三项校验**:看 `indicatorName` + `description` 确认语义和口径,看 `scopeList` 确认覆盖全部目标市场 / 证券类型,再看 `parameterList` 补齐必填参数(required)并核对专属参数枚举(`adjustmentType`/`scale`/`currency` 等);任一不符就回退专用接口。
120
130
  - **公司类型决定有没有这个科目**:财务科目分公司类型——银行有「存放同业」、券商有「客户资金存款」、保险有「预收保费」,一般企业没有。某指标对茅台返回 `null`(无此科目),换到对应类型证券(招行/中信/平安)就有数。
121
131
  - **日期路由**:
122
- - 财务类(`bs_`/`is_`/`cf_`/`finc_`/`div_`/`shr_` 等)→ 用**报告期末**(Q1 `2026-03-31`、年报 `2025-12-31`)
132
+ - 财务报表类(`bs_`/`is_`/`cf_`/`div_`/`shr_`,以及 description 明确按报告期统计的 `finc_`)→ 用**报告期末**(Q1 `2026-03-31`、年报 `2025-12-31`,无需是交易日)
133
+ - 日频估值类(如 `finc_pe_ttm`)→ 用最新已入库的交易日;但 `finc_pb_mrq`(市净率 MRQ) 等 MRQ 口径**只在报告期末打值**,交易日会取到 `null`,要用季度末日期(实测 `2026-07-22` PB 空、`2026-03-31` 有)。别因 code 都以 `finc_` 开头就一律套报告期末、也别一律套交易日——按 `description`/实测区分
123
134
  - 现金流量表附注/间接法科目(多数 `cf_`)→ **只在年报/半年报披露**,季报日期取不到,改用年报日期 `2025-12-31`
124
- - 行情/基本资料(`qte_`/`pty_`/`scr_`/`frcst_`)→ 用**交易日**
125
- - **探索性取数**:截面与时序现在对无数据都优雅处理(截面返 `null` 单元格、时序返空行),都适合"先看有没有数";看趋势仍优先 `time-series` + 覆盖报告期的区间。
135
+ - 行情类(`qte_` 等)→ 用**交易日**,但常规行情仍应改走 `quote`
136
+ - **混合日期语义要拆查询**:同时要“某报告期营收 / EPS”和“估值 PE / PB”时,按各自有效日期分别调用 `cross-section` 再按 `security` 合并(财务=报告期末、PE=最新交易日、PB(MRQ)=最近报告期末);不要把不同日期语义的指标塞进同一个 `--date`
137
+ - **探索性取数**:单元格级缺值返回 `null` 且保留证券行,时序局部无值可为空行;**整个查询无数据仍可能报 `999999`**。看趋势用 `time-series` + 覆盖报告期的区间,但不能把缺值当成通过语义 / scope 校验。
126
138
  - **名称反查 code 要核对,别取首条**:存在同显示名的兄弟指标——单季 `cf_finc_exp_qtr` 与累计 `cf_finc_exp` 都叫「财务费用」,`bs_fmt`/`cf_fmt`/`is_fmt` 都叫「报表格式」。`search` 按名称模糊匹配,目标 code 高概率在 top1 但不绝对,要看 `indicatorCode` 确认。
127
- - **批量查询做失败拆分**:某指标**缺必填参数**或入参错误时会整批报错(无数据不会——按 `null` 返回),逐指标单查能定位是哪个指标缺参/不可查。
139
+ - **批量查询做失败拆分**:某指标**缺必填参数**或入参错误时会整批报错(单元格级无数据按 `null` 返回;整个查询无数据的 `999999` 例外见上),逐指标单查能定位是哪个指标缺参/不可查。
128
140
  - **市值量纲(实测 2026-07)**:`qte_mkt_cptl`(总市值)**仅 A 股**——港股/美股返 `null`(换 `currency` 也没用,是 scope 外 ≠ 无数据);**默认返原始「元」**(茅台 ≈ `1.5e12`,即 1.5 万亿),别误当天文数字。用 `scale` 数字码缩放(`0`元 / `3`千 / `4`万 / `6`百万 / `8`亿 / `9`十亿——`scale=8` → `15038` 亿元)、`currency` 换币种(`dft`本币 / `cny` / `hkd` / `usd` …)。**跨证券比市值前先统一 `scale`+`currency`**。
141
+ - **EDE 财务指标的 `reportType` 枚举不可信(实测 2026-07-23)**:服务端 label(`1`母公司/`2`合并/`3`母公司调整/`4`合并调整)与实际取数不符——`value=2/4` 常直接 `999999`、`value=1` 反而返合并数(茅台2025营收 `value=1`→1688亿、`=3`→983亿、`=2/4`→999999)。**省略即用默认(合并口径,已实测有数)**;要明确指定合并/母公司口径请改用 `fundamental` 三大报表的 `--report-type`(口径语义可靠)。
129
142
 
130
143
  ## 通用说明
131
144
 
132
- - **发现流程**:`indicator search`(拿 code + parameterList)→ `cross-section` / `time-series` 取数
133
- - **积分**:`search` 免费;`cross-section` / `time-series` 按单元格计费(A 股 0.05 / 港股 0.1 / 美股 0.2 积分每 100 单元格,不足 100 按 100)
134
- - **空结果**:日期区间无数据时返回空表(不报错),换交易日/有效区间重试
145
+ - **发现流程**:`indicator search --format json` → 核对 `indicatorName` + `description`、`scopeList`、`parameterList` → 三项都通过才用 `cross-section` / `time-series`
146
+ - **积分**:`search` 免费;`cross-section` / `time-series` 按请求单元格数量计费,标价为每 100 单元格 A 股 0.05 / 港股 0.1 / 美股 0.2 积分,每次查询不足 100 单元格按 100
147
+ - **空结果 / 整查询无数据**:时序可能返回空表,截面或整批无数据也可能报 `999999`;先改用符合指标语义的日期 / 有效区间并核对 `scopeList`
135
148
  - **数据权限**:试用账号默认可取近 3 年;正式账号按服务等级
136
149
  - 所有格式(table/json/jsonl/csv/markdown)均可用;导出宽表给 Excel 直接用 `--format csv --output xxx.csv`
@@ -222,37 +222,42 @@
222
222
  5. 呈现:total + 前 20 只列表
223
223
  ```
224
224
 
225
- ## 例 15:指标取数(search cross-section / time-series)
226
-
227
- **用户**:"茅台和泡泡玛特上周的收盘价、成交量对比一下"
228
-
229
- ```
230
- 1. 路由 → indicator(证券级指标,需证券代码 → EDE,不是 alternative edb)
231
- 2. 先拿 indicatorCode(绝不猜):
232
- gangtise indicator search --keyword 收盘价 --format table → qte_close
233
- gangtise indicator search --keyword 成交量 --format table → qte_vol
234
- 3. 取数二选一:
235
- - 单日横向对比 cross-section(多指标 × 多证券):
236
- gangtise indicator cross-section \
237
- --indicator qte_close --indicator qte_vol \
238
- --security 600519.SH --security 09992.HK \
239
- --date 2026-05-22 --format table
240
- 每行一只证券,列 = date/security/name/日收盘价/成交量
241
- - 一段区间走势 time-series(这里两只证券 → 只能单指标 × 多证券):
242
- gangtise indicator time-series --indicator qte_close \
243
- --security 600519.SH --security 09992.HK \
244
- --start-date 2026-05-18 --end-date 2026-05-22 --format table
245
- 每行一个日期,列 = date/贵州茅台/泡泡玛特
246
- 4. 复权:要前复权收盘价加 --indicator-param "qte_close:adjustmentType=2"
247
- (参数 key 以 indicator search --format json 的 parameterList 为准)
248
- 5. 陷阱:time-series 不能多指标 × 多证券同时(报 410001),那种情况用 cross-section
249
- 6. 必填参数:很多指标默认调用会缺参报错(服务端指明缺哪个,如「必填参数 periodNum 不能为空」)→ 先看 parameterList 的 required,补
250
- periodNum(N期统计)/startDate(区间周期类,如 qte_amp_mo)/fiscalYear(年度分红):
251
- gangtise indicator cross-section --indicator finc_roe_avg_avg --security 600519.SH \
252
- --date 2026-03-31 --indicator-param "finc_roe_avg_avg:periodNum=4"
253
- 7. 无数据:截面/时序对无此科目的**格**返回 null(不丢行);**整个查询无数据**(节假日/未来日期/未覆盖标的)
254
- 仍报 999999+HTTP 500,CLI 不重试并提示检查条件 → 财务用报告期末、现金流附注用年报
255
- 日期(2025-12-31)、行情用交易日;银行/券商/保险科目不同,换对公司类型。详见 commands/indicator.md
225
+ ## 例 15:多证券已实现财务 / 估值指标(EDE 多截面,按日期语义拆分)
226
+
227
+ **用户**:"把茅台、五粮液、宁德时代 2025 年营收和已实现 EPS,与最新 PE/PB 做成一张表"
228
+
229
+ > 示例日期为**截至 2026-07-23 的实测快照**:`2026-07-22`=当时最新交易日、`2026-03-31`=当时最近有 PB 的报告期末;实跑时替换为当下的最新交易日 / 最近报告期末。
230
+
231
+ ```
232
+ 1. 路由 indicator:多证券批量取一组已实现财务 / 估值指标;不是逐只 fundamental,也不是 EDB。
233
+ 若改成单票、盈利预测/一致预期、估值历史分位、完整报表或 OHLCV/K 线,则分别走 fundamental / quote 专用命令。
234
+ 2. 每个概念都先 search --format json(绝不猜 code,也不能只取第一条):
235
+ gangtise indicator search --keyword 营业收入 --limit 10 --format json
236
+ gangtise indicator search --keyword 基本每股收益 --limit 10 --format json
237
+ gangtise indicator search --keyword 市盈率 --limit 10 --format json
238
+ gangtise indicator search --keyword 市净率 --limit 10 --format json
239
+ 对每个候选同时核对:
240
+ - indicatorName + description:累计/单季、营业收入/营业总收入、已实现/预测等语义准确
241
+ - scopeList:覆盖全部三只 A 股;缺失/null/空也视为不通过
242
+ - parameterList:补 required 参数并核对枚举
243
+ 任一不符 回退相应专用接口。
244
+ 3. 三类指标日期语义不同 → 拆三次截面,均加 `--key-by code`(列头用 indicatorCode,跨三张表按 code 稳定合并、免受同名/服务端重排干扰;省略 reportType 即取合并口径,⚠️ 该枚举 label 与实测不符、value=2/4 会 999999,需指定口径改用 fundamental income-statement --report-type):
245
+ a) 财务(营收/EPS)用报告期末 2025-12-31:
246
+ gangtise indicator cross-section \
247
+ --indicator is_op_rev --indicator is_eps_bas \
248
+ --security 600519.SH --security 000858.SZ --security 300750.SZ \
249
+ --date 2025-12-31 --key-by code --format json
250
+ b) PE 日频,用最新交易日 2026-07-22(此日 PB 为 null,勿并入):
251
+ gangtise indicator cross-section --indicator finc_pe_ttm \
252
+ --security 600519.SH --security 000858.SZ --security 300750.SZ \
253
+ --date 2026-07-22 --key-by code --format json
254
+ c) PB(MRQ) 只在报告期末打值,用最近报告期末 2026-03-31:
255
+ gangtise indicator cross-section --indicator finc_pb_mrq \
256
+ --security 600519.SH --security 000858.SZ --security 300750.SZ \
257
+ --date 2026-03-31 --key-by code --format json
258
+ 4. 按 security 合并三张宽表(列头即 indicatorCode,各取所需日期的值);不要把不同日期语义的指标塞进同一个 --date。
259
+ 5. 计费:search 免费;三次取数各按请求单元格数量计费,每次不足 100 单元格按 100 计。
260
+ 6. 无数据:单元格缺值返回 null 且不丢证券行;整个查询无数据仍可能报 999999,先核对日期语义、scopeList、公司类型和指标参数。
256
261
  ```
257
262
 
258
263
  ## 例 16:A 股资金流向(个股 vs 全市场按日分片)
@@ -55,8 +55,8 @@ CLI 自动处理 envelope:`{code, msg, data}` 信封会按 `code === "000000"`
55
55
  | quote fund-flow | `{fieldList, list, total}` 列式 → 规范化后 `{list: [{...}], total}` 宽表 | `securityCode` / `tradeDate` + 请求的字段(`mainNetInflow` / `largeInflow` / `xlargeOutflow` / …) |
56
56
  | fundamental income-statement / balance-sheet / cash-flow(含 quarterly / -hk / -us) | `{total, list: [{...}]}` | `fiscalYear` / `period` / `endDate` / `companyName` / `companyType`(企业类型名称,如 `一般企业`/`银行`)+ 各 `--field` 字段;港股/美股另含 `timeCovered`(不规则跨度) |
57
57
  | fundamental main-business | `{list: [{...}]}` | `endDate` / `breakdownName` / `revenue` / `revenueRatio` / `grossProfitRatio` |
58
- | fundamental valuation-analysis | `{list: [{...}]}` | `tradeDate` / `value` / `percentileRank` |
59
- | fundamental earning-forecast | `{securityCode, securityName, updateList: [...]}` | `updateList[].date` / `updateList[].fieldList[].forecastYear` + 各 consensus 指标 |
58
+ | fundamental valuation-analysis(仅 A 股) | `{list: [{...}]}` | `tradeDate` / `value` / `percentileRank` |
59
+ | fundamental earning-forecast(仅 A 股) | `{securityCode, securityName, updateList: [...]}` | `updateList[].date` / `updateList[].fieldList[].forecastYear` + 各 consensus 指标 |
60
60
  | fundamental top-holders | `{holderType, list: [{...}]}` | `reportPeriod` / `rank` / `shareholderName` / `holdingNum` / `holdingPct` / `chgNum` / `chgPct` |
61
61
  | ai knowledge-batch | `{list: [{...}]}` | `list[].resourceType` / `list[].sourceId` / `list[].title` / `list[].summary` |
62
62
  | ai security-clue | `{list, total}` | `list[].securityCode` / `list[].title` / `list[].clueType` / `list[].clueDate` |
@@ -79,7 +79,7 @@ CLI 自动处理 envelope:`{code, msg, data}` 信封会按 `code === "000000"`
79
79
  | alternative edb-data | 列表,每行 `{date, <indicatorId>: value, ...}` 宽表 | `date` + 每个 `--indicator-id` 一列(该日指标值) |
80
80
  | alternative concept-info | `{conceptId, conceptName, ...}`(单对象,**非列表**) | `conceptName` / `definition` / `investmentLogic` / `industrySpace` / `competitiveLandscape` / `keyEvents[].date` / `keyEvents[].content`;文本字段未配置为 `null` |
81
81
  | alternative concept-securities | `{conceptId, conceptName, securityCount, securityDetail}`(单对象,分组) | `securityCount` / `securityDetail[].groupName` / `securityDetail[].securityList[].securityCode` / `.securityName` / `.isKey` / `.inclusionReason`;无成分股时 `securityDetail` 为 `null` |
82
- | indicator search | `[{indicatorCode, indicatorName, ...}]`(列表) | `indicatorCode` / `indicatorName` / `description` / `scope` / `parameterList[].paramKey` / `.enumList[].value`(专属参数及枚举) / `score` |
82
+ | indicator search | `[{indicatorCode, indicatorName, ...}]`(列表) | `indicatorCode` / `indicatorName` / `description` / `scopeList[].market` / `scopeList[].securityType` / `parameterList[].paramKey` / `.enumList[].value`(专属参数及枚举) / `score` |
83
83
  | indicator cross-section | CLI 拍平为宽表 `{list, total}` | `list[].date` / `list[].security` / `list[].name` + 每个指标名一列;**单日多指标 × 多证券**,每行一只证券 |
84
84
  | indicator time-series | CLI 拍平为宽表 `{list, total}` | `list[].date` + 序列列:单证券时列=各指标、多证券时列=各证券;每行一个日期 |
85
85
  | lookup broker-org / meeting-org list | `[...]` | `[].id` / `[].name` |
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gangtise-openapi-cli",
3
- "version": "0.28.0",
3
+ "version": "0.28.2",
4
4
  "description": "CLI for Gangtise OpenAPI",
5
5
  "license": "MIT",
6
6
  "repository": {