gangtise-openapi-cli 0.28.1 → 0.28.3
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 +29 -0
- package/dist/src/cli.js +7 -9
- package/dist/src/core/client.js +7 -3
- package/dist/src/core/indicatorMatrix.js +9 -5
- package/dist/src/core/normalize.js +32 -8
- package/dist/src/version.js +1 -1
- package/gangtise-openapi/SKILL.md +4 -3
- package/gangtise-openapi/references/commands/fundamental.md +5 -0
- package/gangtise-openapi/references/commands/indicator.md +19 -6
- package/gangtise-openapi/references/commands/quote.md +4 -0
- package/gangtise-openapi/references/examples.md +5 -5
- package/gangtise-openapi/references/fields.md +3 -0
- package/gangtise-openapi/references/response-schema.md +4 -4
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -4,6 +4,34 @@
|
|
|
4
4
|
|
|
5
5
|
## Changelog
|
|
6
6
|
|
|
7
|
+
### v0.28.3 — 2026-07-24
|
|
8
|
+
|
|
9
|
+
🔴 **数据完整性修复**:`--field` 传错字段名会导致**静默错列**(值贴到错误的字段上)。
|
|
10
|
+
|
|
11
|
+
**修复**
|
|
12
|
+
- 列式响应(`{fieldList, list}`)拍平时校验字段数与行长度,不匹配直接报错(`ValidationError`,退出码 1),不再输出错位数据。上游对不存在的字段名有两套处理:`day-kline` / `minute-kline` / `fund-flow` 名值同丢、三大报表补 `null`(长度相等,安全);但 **`quote realtime` / `fundamental main-business` / `valuation-analysis` 只丢值、字段名照请求回显**——实测 `quote realtime --field securityCode --field close --field turnoverRate`(realtime 根本没有 `close`)把换手率 `28.5573` 拍成了 `close`,茅台真实价 1297.41。不报错、数字看着合理、却完全是另一个指标。`alternative edb-data` 的同款拍平一并纳入校验
|
|
13
|
+
|
|
14
|
+
**文档(随包 skill)**
|
|
15
|
+
- SKILL.md 必备规则加第 10 条:`--field` 不确定就别传;`quote realtime` **无 `close`**(用 `latestPrice`)、**无市值**(总市值走 `indicator cross-section --indicator qte_mkt_cptl`,仅 A 股)
|
|
16
|
+
- `quote realtime` 补全 16 个实测字段(此前 `fields.md` 漏 `turnoverRate` / `volumeRatio`);`valuation-analysis` 标注只有 7 个字段、无 `securityCode`(误传会拿到一列重复的 `tradeDate`,长度相等拦不住)
|
|
17
|
+
- **推翻 07-23 关于 EDE `reportType` 的结论**(复测 2026-07-24):旧文档写「枚举不可信、`value=2/4` 直接 `999999`、指定口径请改用 `fundamental --report-type`」。实测是 label 与 value **错位但映射稳定**:`1`=合并(默认)、`2`=合并(调整)、`3`=母公司、`4`=母公司(调整),四值与三大报表逐一对得上;`2`/`4` 为空只是该报告期尚无调整表。**EDE 可以指定口径——母公司传 `3`,合并省略即可**
|
|
18
|
+
- 修正 `response-schema.md` 里会**反向诱导传错字段**的陈旧记录:`main-business` 行原写 `endDate` / `breakdownName` / `revenue`(实测均不存在),改为真实的 `periodName` / `periodEndDate` / `categoryName` + `opRevenue` / `grossProfit` 等 15 个字段
|
|
19
|
+
- 标注上游 meta 字段错位(实测边界):**A 股累计口径的 `balance-sheet` / `cash-flow`** 的 `companyType` 与 `currency` 值互换(`companyType=人民币`、`currency=银行`),A 股 `income-statement`、港股/美股三表均正确;A 股 `*-quarterly` 单季表另有 `companyType` 返回未映射数字码(`102119999`)的问题——读这两列按值判断语义,科目数字不受影响
|
|
20
|
+
|
|
21
|
+
### v0.28.2 — 2026-07-24
|
|
22
|
+
|
|
23
|
+
EDE 指标批量取数优化(基于对上游 990 个指标的实测)。
|
|
24
|
+
|
|
25
|
+
**新增**
|
|
26
|
+
- `indicator cross-section` / `time-series` 加 `--key-by name|code`(默认 `name`):`code` 模式列头用 `indicatorCode`(时序多证券侧用 `securityCode`),唯一且与服务端返回列序无关。**多证券批量按 code 回填必用**——此前拍平只按指标显示名,而多个指标同名(如 `cf_finc_exp`/`_qtr` 都叫「财务费用」)+ 服务端会重排返回列序,导致按名/按位置都错位、只能绕道 raw API 手工回填
|
|
27
|
+
|
|
28
|
+
**修复**
|
|
29
|
+
- EDE `999999` 无数据提示只对取数端点(`cross-section`/`time-series`)套用,`indicator.search`(同为 no-999999 策略、仅关键词入参)回落通用提示;文案改为「日期匹配指标周期(财务/MRQ 用报告期末、日频估值用交易日)、`scopeList`、`parameterList` 中 required 参数」——修正此前「行情/估值用交易日」与 `finc_pb_mrq` 仅报告期末的矛盾
|
|
30
|
+
|
|
31
|
+
**文档(随包 skill)**
|
|
32
|
+
- `indicator.md`:`--key-by` 文档 + 两处 synopsis;`periodNum` 补「部分需配年报日期」、`startDate` 补「取值须匹配指标周期」
|
|
33
|
+
- `examples.md` 例15:批量三截面示例改用 `--key-by code`
|
|
34
|
+
|
|
7
35
|
### v0.28.1 — 2026-07-23
|
|
8
36
|
|
|
9
37
|
Agent Skill 文档取数路由对齐(对齐 gangtise-mcp 0.1.46):多证券取一批**已实现**财务/估值指标优先走 EDE `indicator cross-section`/`time-series` 一次拉取,替代逐只 `fundamental` 循环。**本版仅改随包分发的 skill 文档(`gangtise-openapi/`),无 CLI 代码/命令/参数变更。**
|
|
@@ -17,6 +45,7 @@ Agent Skill 文档取数路由对齐(对齐 gangtise-mcp 0.1.46):多证券
|
|
|
17
45
|
**实测校正(2026-07-23)**
|
|
18
46
|
- `scope` 字段更正为 `scopeList[].market/.securityType`(服务端已返回实际覆盖),覆盖按指标而异:`finc_pe_ttm`/`finc_pb_mrq` 仅 A 股、`is_op_rev` A 股+港股,均不含美股;`valuation-analysis`/`earning-forecast` 仅 A 股
|
|
19
47
|
- `finc_pb_mrq`(市净率 MRQ) 只在报告期末打值(交易日取 `null`),非日频;EDE 财务指标 `reportType` 枚举 label 与实测取数不符(`value=2/4` 直接 `999999`),要指定报表口径改用 `fundamental` 三大报表 `--report-type`
|
|
48
|
+
- ⚠️ **本条 `reportType` 结论已被 v0.28.3 复测推翻,勿据此路由**:实际是 `1`=合并 / `2`=合并(调整) / `3`=母公司 / `4`=母公司(调整),EDE 可直接指定口径,见上方 v0.28.3 条目(`finc_pb_mrq` 部分仍成立)
|
|
20
49
|
|
|
21
50
|
### v0.28.0 — 2026-07-21
|
|
22
51
|
|
package/dist/src/cli.js
CHANGED
|
@@ -10,7 +10,7 @@ import { loadConfig } from "./core/config.js";
|
|
|
10
10
|
import { resolveTitle, saveDownloadResult, uniquePath } from "./core/download.js";
|
|
11
11
|
import { ENDPOINTS, listEndpoints } from "./core/endpoints.js";
|
|
12
12
|
import { ApiError, ConfigError, ValidationError } from "./core/errors.js";
|
|
13
|
-
import { normalizeRows } from "./core/normalize.js";
|
|
13
|
+
import { normalizeRows, zipFieldRow } from "./core/normalize.js";
|
|
14
14
|
import { parseOutputFormat } from "./core/output.js";
|
|
15
15
|
import { printData } from "./core/printer.js";
|
|
16
16
|
// --- Lazy-loaded modules (deferred to action handlers) ---
|
|
@@ -612,10 +612,8 @@ alternative.command("edb-data").option("--indicator-id <id>", "Indicator ID (rep
|
|
|
612
612
|
});
|
|
613
613
|
let data = raw;
|
|
614
614
|
if (raw && Array.isArray(raw.fieldList) && Array.isArray(raw.dataList)) {
|
|
615
|
-
const
|
|
616
|
-
|
|
617
|
-
return acc;
|
|
618
|
-
}, {}));
|
|
615
|
+
const fields = raw.fieldList;
|
|
616
|
+
const list = raw.dataList.map((row) => zipFieldRow(fields, row, raw));
|
|
619
617
|
data = { list, total: list.length };
|
|
620
618
|
}
|
|
621
619
|
await printData(data, format, options.output);
|
|
@@ -632,15 +630,15 @@ indicator.command("search").requiredOption("--keyword <text>", "Search keyword,
|
|
|
632
630
|
});
|
|
633
631
|
await printData(unwrapIndicatorData(raw), format, options.output);
|
|
634
632
|
}));
|
|
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) => {
|
|
633
|
+
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
634
|
const format = parseOutputFormat(options.format);
|
|
637
635
|
const raw = await client.call("indicator.cross-section", buildIndicatorCrossSectionBody(options));
|
|
638
|
-
await printData(flattenCrossSection(unwrapIndicatorData(raw)), format, options.output);
|
|
636
|
+
await printData(flattenCrossSection(unwrapIndicatorData(raw), options.keyBy), format, options.output);
|
|
639
637
|
}));
|
|
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) => {
|
|
638
|
+
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
639
|
const format = parseOutputFormat(options.format);
|
|
642
640
|
const raw = await client.call("indicator.time-series", buildIndicatorTimeSeriesBody(options));
|
|
643
|
-
await printData(flattenTimeSeries(unwrapIndicatorData(raw)), format, options.output);
|
|
641
|
+
await printData(flattenTimeSeries(unwrapIndicatorData(raw), options.keyBy), format, options.output);
|
|
644
642
|
}));
|
|
645
643
|
program.addCommand(indicator);
|
|
646
644
|
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) => {
|
package/dist/src/core/client.js
CHANGED
|
@@ -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
|
|
427
|
-
|
|
428
|
-
|
|
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
|
-
|
|
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,3 +1,33 @@
|
|
|
1
|
+
import { ENVELOPE_TRACE_ID, ValidationError } from "./errors.js";
|
|
2
|
+
/** 信封 traceId 由 `client.ts` 挂在每个成功响应的 payload 上(非枚举 symbol)。
|
|
3
|
+
* 结构异常报障没这个 id 服务端查不了,所以拍平失败时要一并带出。 */
|
|
4
|
+
function traceSuffix(source) {
|
|
5
|
+
if (!source || typeof source !== "object")
|
|
6
|
+
return "";
|
|
7
|
+
const traceId = source[ENVELOPE_TRACE_ID];
|
|
8
|
+
return typeof traceId === "string" ? `(trace ${traceId})` : "";
|
|
9
|
+
}
|
|
10
|
+
/** 按位置把列式响应的一行值拍平成对象。
|
|
11
|
+
*
|
|
12
|
+
* 上游对「fieldList 里有该接口不存在的字段名」有两套处理,实测 2026-07-24:
|
|
13
|
+
* day-kline / minute-kline / fund-flow 把名和值一起丢、三大报表补 null——长度仍相等,安全;
|
|
14
|
+
* 但 realtime / main-business / valuation-analysis 是**值只按有效字段返回、字段名却按请求
|
|
15
|
+
* 原样回显**。长度一旦不等,按位置拍平就会把值贴到错误的字段上:realtime 传
|
|
16
|
+
* ["securityCode","close","turnoverRate"](realtime 根本没有 close)只回 2 个值,
|
|
17
|
+
* 换手率 28.5573 被贴成 close,读起来就是「茅台收盘价 28.56」(真实价 1297.41)。
|
|
18
|
+
* 不报错、数字看着还合理、却完全是另一个指标——静默错列必须变成显式失败。
|
|
19
|
+
*
|
|
20
|
+
* 文案不能一口咬定「字段名传错」:`alternative edb-data` 走同一个拍平却根本没有
|
|
21
|
+
* `--field`(只有 `--indicator-id`),那里长度不等只可能是上游响应结构变了。 */
|
|
22
|
+
export function zipFieldRow(fields, row, source) {
|
|
23
|
+
if (row.length !== fields.length) {
|
|
24
|
+
throw new ValidationError(`响应字段数与 fieldList 不匹配(fieldList ${fields.length} 项、该行返回 ${row.length} 个值)——按位置拍平会把值贴到错误的字段上,已拒绝输出。带 --field 的命令多为传了该接口不存在的字段名(上游只返回有效字段的值、字段名却按请求回显):核对 --field 取值(如 quote realtime 没有 close,最新价是 latestPrice),不确定就不传 --field(返回全量字段最稳)。没有 --field 的命令(如 alternative edb-data)出现此错,是上游响应结构异常,请报障${traceSuffix(source)}。`);
|
|
25
|
+
}
|
|
26
|
+
return fields.reduce((acc, field, index) => {
|
|
27
|
+
acc[String(field)] = row[index];
|
|
28
|
+
return acc;
|
|
29
|
+
}, {});
|
|
30
|
+
}
|
|
1
31
|
export function normalizeRows(value) {
|
|
2
32
|
if (!value || typeof value !== "object") {
|
|
3
33
|
return value;
|
|
@@ -7,14 +37,8 @@ export function normalizeRows(value) {
|
|
|
7
37
|
}
|
|
8
38
|
const record = value;
|
|
9
39
|
if (Array.isArray(record.fieldList) && Array.isArray(record.list)) {
|
|
10
|
-
const
|
|
11
|
-
|
|
12
|
-
return row;
|
|
13
|
-
return record.fieldList.reduce((acc, field, index) => {
|
|
14
|
-
acc[String(field)] = row[index];
|
|
15
|
-
return acc;
|
|
16
|
-
}, {});
|
|
17
|
-
});
|
|
40
|
+
const fields = record.fieldList;
|
|
41
|
+
const normalizedList = record.list.map((row) => (Array.isArray(row) ? zipFieldRow(fields, row, record) : row));
|
|
18
42
|
const { fieldList, list, ...meta } = record;
|
|
19
43
|
const hasMeta = Object.keys(meta).length > 0;
|
|
20
44
|
return hasMeta ? { ...meta, list: normalizedList } : normalizedList;
|
package/dist/src/version.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
// Auto-generated — DO NOT EDIT
|
|
2
|
-
export const CLI_VERSION = "0.28.
|
|
2
|
+
export const CLI_VERSION = "0.28.3";
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: gangtise-openapi
|
|
3
|
-
version: "0.28.
|
|
3
|
+
version: "0.28.3"
|
|
4
4
|
description: |-
|
|
5
5
|
通过 gangtise CLI 直接调用 Gangtise OpenAPI,拉取投研原始数据、批量导出、下载文件、调用 AI 能力。
|
|
6
6
|
|
|
@@ -36,6 +36,7 @@ description: |-
|
|
|
36
36
|
- Token 失效(`0000001008` / `999002`,含已废弃的 `8000014`/`8000015`)→ 自动重新登录并重试一次;凭证错 `999011` → **不重试**(AK/SK 不对不会自己好),查环境变量
|
|
37
37
|
8. **参数命名差异**:Insight/Quote/Vault 用 `--security`,Fundamental/AI 用 `--security-code`(例外:`ai stock-summary` 用 `--security`,`ai security-clue` 用 `--gts-code`)。
|
|
38
38
|
9. **调试**:`--verbose` 或 `GANGTISE_VERBOSE=1` 打印每个请求的耗时/字节数到 stderr。
|
|
39
|
+
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`,仅 A 股)。
|
|
39
40
|
|
|
40
41
|
## 工作流(3 步)
|
|
41
42
|
|
|
@@ -162,8 +163,8 @@ description: |-
|
|
|
162
163
|
- "成分股" → 题材深度(分组/重点标记/纳入理由)走 `alternative concept-securities`;板块(行业/概念分类树,纯代码名单)走 `reference sector-constituents`
|
|
163
164
|
- **证券基本面 / 指标先按任务形态路由,不是搜到 EDE 就一律走 EDE**:
|
|
164
165
|
- 单证券先优先对应 `fundamental` 专用命令(财务、估值、盈利预测、股东、主营或完整三大报表,多数免费 / 低价)。其中 `valuation-analysis` / `earning-forecast` 实测仅支持 A 股;港 / 美股的估值历史分位、盈利预测、以及 PE/PB 等核心估值(EDE 也仅 A 股)当前 CLI 均无可用接口,如实说明不支持、勿用别的语义顶替
|
|
165
|
-
- 多证券批量取一组**已实现**财务 / 估值指标 → 优先 `indicator search` 后用 EDE 一次拉取,替代逐只循环;单日或同一报告期横向比较用 `cross-section`,区间走势用 `time-series`(后者不能多指标 ×
|
|
166
|
-
- 始终排除 EDE:A股盈利预测 / 一致预期(含预测 EPS)→ `fundamental earning-forecast`;A股估值历史分位 → `fundamental valuation-analysis`;开高低收 / 成交量等行情与 K 线 → `quote`;单证券完整报表 →
|
|
166
|
+
- 多证券批量取一组**已实现**财务 / 估值指标 → 优先 `indicator search` 后用 EDE 一次拉取,替代逐只循环;单日或同一报告期横向比较用 `cross-section`,区间走势用 `time-series`(后者不能多指标 × 多证券同时)。**批量按 code 回填加 `--key-by code`**(列头用 `indicatorCode`,防同名指标碰撞 + 服务端重排列序导致的错位)
|
|
167
|
+
- 始终排除 EDE:A股盈利预测 / 一致预期(含预测 EPS)→ `fundamental earning-forecast`;A股估值历史分位 → `fundamental valuation-analysis`;开高低收 / 成交量等行情与 K 线 → `quote`;单证券完整报表 → 对应三大报表命令。**例外:总市值只有 EDE 有**——`quote realtime` / `day-kline` 都不返回市值,走 `indicator cross-section --indicator qte_mkt_cptl`(仅 A 股,默认单位「元」,用 `--scale` 缩放)。EDE 搜到的基本 / 稀释 EPS 是已实现值,**不能冒充预测 EPS**;港 / 美股缺少上述专用能力时应如实说明不支持,不能用别的语义代替
|
|
167
168
|
- EDE 取数前必须用 `search --format json` 同时核对:`indicatorName` + `description` 语义准确、`scopeList` 覆盖全部目标市场 / 证券类型、`parameterList` 必填参数与枚举可满足;`scopeList` 缺失 / `null` / 空或任一项不符,都视为无法证明覆盖并回退专用接口。专用接口也不覆盖目标市场时,说明当前不可用,不要硬调。`scopeList` 按指标各不相同,不能因 EDE 服务支持 A / 港 / 美股就假定某个指标三市场都覆盖
|
|
168
169
|
- `indicator search` 免费,`cross-section` / `time-series` 按单元格计费;除多证券批量的效率收益外,仍优先免费 / 低价的 `quote` 或 `fundamental`
|
|
169
170
|
- 行业 / 宏观指标(空调销量、社融等,无证券维度)走 `alternative edb-*`(EDB),不要与证券级 EDE 混用
|
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
通用:所有命令都需 `--security-code`(如 `600519.SH`,注意是 `--security-code` 不是 `--security`)。`--field` 可重复,可用字段见 `references/fields.md`;A / 港 / 美股三大报表命令都在省略 `--field` 时返回完整报表,指定后只保留基础字段与所选科目。
|
|
4
4
|
|
|
5
|
+
**`--field` 字段名必须核对**(v0.28.3 起传错直接报错):三大报表遇到不存在的字段名会补 `null`(安全),但 `main-business` / `valuation-analysis` 是**只丢值、字段名照请求回显**,按位置拍平会把值贴到错误的字段上(同 `quote realtime`,详见 `references/commands/quote.md`)。CLI 现在长度不匹配就直接失败(退出码 1),不输出错位数据。不确定字段名就别传 `--field`。
|
|
6
|
+
|
|
5
7
|
---
|
|
6
8
|
|
|
7
9
|
## A股三大报表(累计) `income-statement` / `balance-sheet` / `cash-flow`
|
|
@@ -15,6 +17,7 @@ gangtise fundamental <income-statement|balance-sheet|cash-flow> --security-code
|
|
|
15
17
|
- `--fiscal-year` 可重复:`--fiscal-year 2023 --fiscal-year 2024`
|
|
16
18
|
- `--start-date`/`--end-date` 有值时覆盖 `--fiscal-year`
|
|
17
19
|
- **固定返回字段**(无需 `--field` 指定):`securityCode` `companyName` `category` `announcementDate` `endDate` `fiscalYear` `period` `reportType` `companyType` `currency` `unit`
|
|
20
|
+
- ⚠️ **本节两个命令的 `companyType` / `currency` 值是反的**(实测 2026-07-24,服务端字段名映射问题,与公司类型无关):A 股累计口径的 `balance-sheet` / `cash-flow` 返回 `companyType=人民币`、`currency=一般企业`(工行则是 `currency=银行`);**`income-statement` 是对的**。另:A 股 `*-quarterly` 单季表的 `companyType` 返回未映射的数字码(如 `102119999`)、`currency` 正确;**港股 / 美股三表实测均正常**(`companyType=一般企业`、`currency=人民币`/`美元`)。读这两列时按**值**判断语义,别按列名——科目数字本身不受影响
|
|
18
21
|
|
|
19
22
|
**常用字段速查:**
|
|
20
23
|
- 利润表:`totalOpRev` 营收 | `netProfit` 净利润 | `netProfitAttrParent` 归母 | `basicEPS` EPS | `rdExp` 研发
|
|
@@ -75,6 +78,7 @@ gangtise fundamental main-business --security-code <code> [--breakdown <type>] [
|
|
|
75
78
|
- `--period`:`interim` 中报 | `annual` 年报(可重复)
|
|
76
79
|
- 默认时间窗:`endDate` 当前日期、`startDate` 三年前
|
|
77
80
|
- **不支持 `--fiscal-year`**(误传触发 `100001`/`100003`,旧 `900001`);按年份筛选用 `--start-date`/`--end-date`
|
|
81
|
+
- `--field` 只认 `references/fields.md` 「主营业务」小节的字段(`opRevenue` / `grossProfit` 等);`securityCode`、`itemName` 这类**不是**该接口字段,传了会报「响应字段数与 fieldList 不匹配」(前 3 列 `periodName` / `periodEndDate` / `categoryName` 恒定返回)
|
|
78
82
|
|
|
79
83
|
## A股估值分析 `fundamental valuation-analysis`
|
|
80
84
|
|
|
@@ -86,6 +90,7 @@ gangtise fundamental valuation-analysis --security-code <code> --indicator <name
|
|
|
86
90
|
- `--indicator`(**必选**):`peTtm` 滚动PE | `pbMrq` PB | `peg` PEG | `psTtm` 滚动PS | `pcfTtm` 滚动PCF | `em` 企业倍数
|
|
87
91
|
- `--limit` 默认 2000,省略 `--start-date` 时自动查近一年
|
|
88
92
|
- `--skip-null`:丢弃 `value`/`percentileRank` 为 null 的行(最新交易日可能未入库)
|
|
93
|
+
- **返回字段只有 7 个**(实测 2026-07-24):`tradeDate` `value` `percentileRank` `average` `median` `upper1Std` `lower1Std`。**没有 `securityCode`**——误传会拿到一列重复的 `tradeDate`(长度相等,CLI 拦不住),传其他不存在的字段名则直接报错。**建议不传 `--field`**,证券代码本来就是你自己传进去的
|
|
89
94
|
|
|
90
95
|
## A股盈利预测 `fundamental earning-forecast`
|
|
91
96
|
|
|
@@ -40,7 +40,7 @@ gangtise indicator search --keyword 营业收入 --limit 10 --format json #
|
|
|
40
40
|
```bash
|
|
41
41
|
gangtise indicator cross-section --indicator <code> [--indicator <code2>] \
|
|
42
42
|
--security <code> [--security <code2>] --date <yyyy-MM-dd> \
|
|
43
|
-
[--currency <c>] [--scale <s>] [--indicator-param <spec>]
|
|
43
|
+
[--currency <c>] [--scale <s>] [--indicator-param <spec>] [--key-by name|code]
|
|
44
44
|
```
|
|
45
45
|
|
|
46
46
|
- `--indicator`(**至少 1 个**):指标编码,来自 `search`,可重复传多个
|
|
@@ -50,6 +50,7 @@ gangtise indicator cross-section --indicator <code> [--indicator <code2>] \
|
|
|
50
50
|
- `--scale`:量纲 `0`(个,默认)/`3`(千)/`4`(万)/`6`(百万)/`8`(亿)/`9`(十亿)
|
|
51
51
|
- **支持多指标 × 多证券**(单日横截面)
|
|
52
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 手工回填)
|
|
53
54
|
|
|
54
55
|
```bash
|
|
55
56
|
# 多证券 × 同一报告期的已实现财务指标
|
|
@@ -58,7 +59,7 @@ gangtise indicator cross-section \
|
|
|
58
59
|
--security 600519.SH --security 000858.SZ --security 300750.SZ \
|
|
59
60
|
--date 2025-12-31 --format table
|
|
60
61
|
# 列:date / security / name / 营业收入(利润表,累计) / 基本每股收益(利润表,累计)
|
|
61
|
-
# 省略 reportType
|
|
62
|
+
# 省略 reportType 即取合并口径(茅台2025=1688亿)。⚠️ 服务端 label 与实际取数错位:实际 1=合并 2=合并(调整) 3=母公司 4=母公司(调整),按 label 传会取反(详见下方「reportType 口径」)
|
|
62
63
|
```
|
|
63
64
|
|
|
64
65
|
## 指标时间序列 `indicator time-series`
|
|
@@ -66,7 +67,7 @@ gangtise indicator cross-section \
|
|
|
66
67
|
```bash
|
|
67
68
|
gangtise indicator time-series --indicator <code> [--indicator <code2>] \
|
|
68
69
|
--security <code> [--security <code2>] --start-date <date> --end-date <date> \
|
|
69
|
-
[--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]
|
|
70
71
|
```
|
|
71
72
|
|
|
72
73
|
- `--indicator` / `--security`:同上,但**只允许「多指标 × 单证券」或「单指标 × 多证券」**,不能两边都多个(要多 × 多用 `cross-section`,否则报 `410001`)
|
|
@@ -74,6 +75,7 @@ gangtise indicator time-series --indicator <code> [--indicator <code2>] \
|
|
|
74
75
|
- `--calendar-type`:日期类型 `ND`(自然日)/`TD`(交易日,默认)/`WD`(工作日)
|
|
75
76
|
- `--currency` / `--scale`:同 `cross-section`
|
|
76
77
|
- **输出(宽表)**:每行一个日期,列为 `date / <各序列名>…`;序列在「单证券」时是各**指标**,在「多证券」时是各**证券**
|
|
78
|
+
- **`--key-by name|code`**(默认 `name`):同 `cross-section`;`code` 模式下单证券列=各 `indicatorCode`、多证券列=各 `securityCode`,批量按 code 回填用它
|
|
77
79
|
|
|
78
80
|
```bash
|
|
79
81
|
# 单个已实现估值指标 × 多证券:列 = 证券
|
|
@@ -116,8 +118,8 @@ gangtise indicator cross-section --indicator qte_close --security 600519.SH \
|
|
|
116
118
|
|
|
117
119
|
| 参数 | 适用指标 | 示例 |
|
|
118
120
|
| :--- | :--- | :--- |
|
|
119
|
-
| `periodNum` | N 期统计(N 期均值/最值,如 `finc_roe_avg_avg` 平均ROE N期均值) | `--indicator-param "finc_roe_avg_avg:periodNum=4"` |
|
|
120
|
-
| `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`) |
|
|
121
123
|
| `fiscalYear` | 年度/报告期类(如 `div_cash_yr` 年度现金分红) | `--indicator-param "div_cash_yr:fiscalYear=2025"` |
|
|
122
124
|
|
|
123
125
|
> `paramValue` 一律按**字符串**约定传(`periodNum=4` 内部即 `"4"`,CLI 已处理)。
|
|
@@ -136,7 +138,18 @@ gangtise indicator cross-section --indicator qte_close --security 600519.SH \
|
|
|
136
138
|
- **名称反查 code 要核对,别取首条**:存在同显示名的兄弟指标——单季 `cf_finc_exp_qtr` 与累计 `cf_finc_exp` 都叫「财务费用」,`bs_fmt`/`cf_fmt`/`is_fmt` 都叫「报表格式」。`search` 按名称模糊匹配,目标 code 高概率在 top1 但不绝对,要看 `indicatorCode` 确认。
|
|
137
139
|
- **批量查询做失败拆分**:某指标**缺必填参数**或入参错误时会整批报错(单元格级无数据按 `null` 返回;整个查询无数据的 `999999` 例外见上),逐指标单查能定位是哪个指标缺参/不可查。
|
|
138
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`**。
|
|
139
|
-
- **EDE 财务指标的 `reportType
|
|
141
|
+
- **EDE 财务指标的 `reportType`:label 与 value 错位,但映射本身稳定可用(复测 2026-07-24,修正 07-23 的结论)**。服务端 label 标 `1`母公司/`2`合并/`3`母公司调整/`4`合并调整,**实际取数是**:
|
|
142
|
+
|
|
143
|
+
| value | 实际口径 | 说明 |
|
|
144
|
+
|-------|---------|------|
|
|
145
|
+
| `1`(默认,省略即此值) | **合并报表** | 绝大多数场景要的就是这个 |
|
|
146
|
+
| `2` | **合并报表(调整)** | 该报告期无重述数时为空 |
|
|
147
|
+
| `3` | **母公司报表** | |
|
|
148
|
+
| `4` | **母公司报表(调整)** | 该报告期无重述数时为空 |
|
|
149
|
+
|
|
150
|
+
实测对照(中信证券 `600030.SH` FY2024 营业收入,与 `fundamental income-statement --report-type` 逐一相等):`1`→637.9亿(合并)、`2`→581.2亿(合并调整)、`3`→321.9亿(母公司)、`4`→321.9亿(母公司调整);中国神华 `601088.SH` 同期 `1`→3383.75亿、`2`→3397.88亿,两值不同,可排除「2 就是合并原值」。**按 label 传会取反**(想要母公司却传 `1` 拿到合并)——认 value 不认 label:合并省略即可,母公司传 `3`。
|
|
151
|
+
|
|
152
|
+
`2`/`4` 返回空值**不是枚举失效**,是该报告期尚无调整表(如最新年报 FY2025:`1`/`3` 有数、`2`/`4` 无值,与 `fundamental --report-type consolidatedRestated` 同期无数据一致);查询内所有单元格都无值时才会升级成 `999999`。港股默认口径同样是合并(腾讯 FY2024 营收 6602.57亿)。
|
|
140
153
|
|
|
141
154
|
## 通用说明
|
|
142
155
|
|
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
通用:`--field` 可重复(`--field open --field close`),可用字段见 `references/fields.md`。
|
|
4
4
|
|
|
5
|
+
**`--field` 字段名必须核对**(v0.28.3 起传错直接报错):上游对不存在的字段名有两套处理——day-kline / minute-kline / fund-flow 把字段名和值一起丢掉(安全);但 `quote realtime`(及 `fundamental main-business` / `valuation-analysis`)**只丢值、字段名照请求回显**,按位置拍平就把值贴到了错误的字段上。实测 `quote realtime --field securityCode --field close --field turnoverRate`:realtime 根本没有 `close`,返回的 2 个值被拍成 `close = 28.5573`(那是换手率,茅台真实价 1297.41)——不报错、数字看着合理、却完全是另一个指标。CLI 现在长度不匹配就直接失败(退出码 1),不输出错位数据。**不确定字段名就别传 `--field`**(返回全量最稳)。
|
|
6
|
+
|
|
5
7
|
**关键规则**:查"最近"K线必须显式 `--start-date`/`--end-date` 拉范围,再从 `tradeDate` 取尾部最近 N 条;不要只用 `--limit N`(会截取查询窗口开头)。
|
|
6
8
|
|
|
7
9
|
**自动分片**(v0.12.0;v0.14.2 修正分片粒度并注入 limit=10000):`--security all` 跨日期范围 CLI 会自动按日切片并并发执行(A 股 1 天/片,美股 1 天/片,HK 2 天/片,指数 30 天/片),合并结果返回。CLI 在 `--security all` 路径会自动把 `limit` 抬到 10000(API 上限),避免默认 6000 行截断。无需手动按季度分批。
|
|
@@ -50,6 +52,8 @@ gangtise quote realtime [--security <code>] [--field <name>]
|
|
|
50
52
|
- **全市场关键字**:`--security aShares` 全部 A 股 / `--security hkStocks` 全部港股 / `--security usStocks` 全部美股;建议配合 `--field` 精简返回字段
|
|
51
53
|
- 返回**最新时刻**的行情快照(最新价/开高低/涨跌/成交量额/振幅)
|
|
52
54
|
- 非交易时间返回最近一个交易日的收盘快照;停牌证券返回停牌前最后一个有效快照
|
|
55
|
+
- **实测全量字段(16 个,2026-07-24)**:`securityCode` `exchange` `tradeDate` `tradeTime` `open` `high` `low` `latestPrice` `preClose` `change` `pctChange` `volume` `amount` `turnoverRate` `amplitude` `volumeRatio`
|
|
56
|
+
- **没有 `close`**——收盘价语义用 `latestPrice`(非交易时间即为收盘价),或改用 `quote day-kline` 的 `close`;**也没有市值**,总市值走 `indicator cross-section --indicator qte_mkt_cptl`(仅 A 股)
|
|
53
57
|
- 字段速查:见 `references/fields.md` 中的"实时行情"小节
|
|
54
58
|
|
|
55
59
|
## A股资金流向 `quote fund-flow`
|
|
@@ -241,21 +241,21 @@
|
|
|
241
241
|
- scopeList:覆盖全部三只 A 股;缺失/null/空也视为不通过
|
|
242
242
|
- parameterList:补 required 参数并核对枚举
|
|
243
243
|
任一不符 → 回退相应专用接口。
|
|
244
|
-
3. 三类指标日期语义不同 →
|
|
244
|
+
3. 三类指标日期语义不同 → 拆三次截面,均加 `--key-by code`(列头用 indicatorCode,跨三张表按 code 稳定合并、免受同名/服务端重排干扰;省略 reportType 即取合并口径,⚠️ 该枚举 label 与实际取数错位——实际 1=合并 2=合并(调整) 3=母公司 4=母公司(调整),要母公司口径传 3、别按 label 传 1):
|
|
245
245
|
a) 财务(营收/EPS)用报告期末 2025-12-31:
|
|
246
246
|
gangtise indicator cross-section \
|
|
247
247
|
--indicator is_op_rev --indicator is_eps_bas \
|
|
248
248
|
--security 600519.SH --security 000858.SZ --security 300750.SZ \
|
|
249
|
-
--date 2025-12-31 --format json
|
|
249
|
+
--date 2025-12-31 --key-by code --format json
|
|
250
250
|
b) PE 日频,用最新交易日 2026-07-22(此日 PB 为 null,勿并入):
|
|
251
251
|
gangtise indicator cross-section --indicator finc_pe_ttm \
|
|
252
252
|
--security 600519.SH --security 000858.SZ --security 300750.SZ \
|
|
253
|
-
--date 2026-07-22 --format json
|
|
253
|
+
--date 2026-07-22 --key-by code --format json
|
|
254
254
|
c) PB(MRQ) 只在报告期末打值,用最近报告期末 2026-03-31:
|
|
255
255
|
gangtise indicator cross-section --indicator finc_pb_mrq \
|
|
256
256
|
--security 600519.SH --security 000858.SZ --security 300750.SZ \
|
|
257
|
-
--date 2026-03-31 --format json
|
|
258
|
-
4. 按 security
|
|
257
|
+
--date 2026-03-31 --key-by code --format json
|
|
258
|
+
4. 按 security 合并三张宽表(列头即 indicatorCode,各取所需日期的值);不要把不同日期语义的指标塞进同一个 --date。
|
|
259
259
|
5. 计费:search 免费;三次取数各按请求单元格数量计费,每次不足 100 单元格按 100 计。
|
|
260
260
|
6. 无数据:单元格缺值返回 null 且不丢证券行;整个查询无数据仍可能报 999999,先核对日期语义、scopeList、公司类型和指标参数。
|
|
261
261
|
```
|
|
@@ -30,6 +30,9 @@
|
|
|
30
30
|
| `low` | 最低价 | `change` | 涨跌额 |
|
|
31
31
|
| `pctChange` | 涨跌幅(%) | `volume` | 成交量(股,当日累计) |
|
|
32
32
|
| `amount` | 成交总额(当日累计) | `amplitude` | 振幅(%) |
|
|
33
|
+
| `turnoverRate` | 换手率(%) | `volumeRatio` | 量比 |
|
|
34
|
+
|
|
35
|
+
**以上 16 个就是全部**(实测 2026-07-24):**无 `close`**(用 `latestPrice`)、**无市值**(走 `indicator cross-section --indicator qte_mkt_cptl`)。realtime 传了不存在的字段名不会被忽略——上游只丢值、字段名照回显,CLI 检测到长度不匹配会直接报错(v0.28.3 起)。
|
|
33
36
|
|
|
34
37
|
### 指数日K线(沪深京 `quote index-day-kline`)
|
|
35
38
|
|
|
@@ -51,11 +51,11 @@ CLI 自动处理 envelope:`{code, msg, data}` 信封会按 `code === "000000"`
|
|
|
51
51
|
| reference sector-constituents | `{total, list}` | `list[].gtsCode` / `list[].gtsName`;total=0 说明 sectorId 不对(先 sector-search 确认) |
|
|
52
52
|
| quote day-kline / day-kline-hk / day-kline-us / index-day-kline | `{fieldList, list}` 或规范化后 `{list: [{...}]}` | `tradeDate` / `securityCode` / `open` / `close` / `pctChange` / `volume`;index 另含 `securityName`(指数名称,v0.15.0 起) |
|
|
53
53
|
| quote minute-kline | `{list: [{...}]}` | `tradeTime` / `open` / `close` / `volume` |
|
|
54
|
-
| quote realtime | `{fieldList, list, total}` 或规范化后 `{list: [{...}]}` | `securityCode` / `exchange` / `tradeDate` / `tradeTime` / `latestPrice` / `pctChange` / `volume` / `amount` / `amplitude` |
|
|
54
|
+
| quote realtime | `{fieldList, list, total}` 或规范化后 `{list: [{...}]}` | `securityCode` / `exchange` / `tradeDate` / `tradeTime` / `open` / `high` / `low` / `latestPrice` / `preClose` / `change` / `pctChange` / `volume` / `amount` / `turnoverRate` / `amplitude` / `volumeRatio`(共 16 个,**无 `close`、无市值**) |
|
|
55
55
|
| quote fund-flow | `{fieldList, list, total}` 列式 → 规范化后 `{list: [{...}], total}` 宽表 | `securityCode` / `tradeDate` + 请求的字段(`mainNetInflow` / `largeInflow` / `xlargeOutflow` / …) |
|
|
56
|
-
| fundamental income-statement / balance-sheet / cash-flow(含 quarterly / -hk / -us) | `{total, list: [{...}]}` | `fiscalYear` / `period` / `endDate` / `companyName` / `companyType
|
|
57
|
-
| fundamental main-business | `{list: [{...}]}` | `
|
|
58
|
-
| fundamental valuation-analysis(仅 A 股) | `{list: [{...}]}` | `tradeDate` / `value` / `percentileRank` |
|
|
56
|
+
| fundamental income-statement / balance-sheet / cash-flow(含 quarterly / -hk / -us) | `{total, list: [{...}]}` | `fiscalYear` / `period` / `endDate` / `companyName` / `companyType` / `currency` / `unit` + 各 `--field` 字段;港股/美股另含 `timeCovered`(不规则跨度)。⚠️ **A 股累计口径的 `balance-sheet` / `cash-flow` 两个命令**,`companyType` 与 `currency` 的值是互换的(实测 2026-07-24:`companyType=人民币`、`currency=银行`/`一般企业`;A 股 `income-statement` 正确,港股/美股三表均正确);A 股 `*-quarterly` 单季表则是 `companyType` 返回未映射的数字码(如 `102119999`)、`currency` 正确。读这两列按**值**判断语义,别按列名;科目数字不受影响 |
|
|
57
|
+
| fundamental main-business | `{fieldList, list}` 列式 → 规范化后 `{list: [{...}]}` | 前 3 列恒定:`periodName` / `periodEndDate` / `categoryName`(分项名,随 `--breakdown` 变)+ `opRevenue` / `opRevenueYoy` / `opRevenueRatio` / `opCost` / `opCostYoy` / `opCostRatio` / `grossProfit` / `grossProfitYoy` / `grossProfitRatio` / `grossMargin` / `grossMarginYoy` / `grossMarginRatio`(共 15 个,实测 2026-07-24)。`--field` 只能从后 12 个里选 |
|
|
58
|
+
| fundamental valuation-analysis(仅 A 股) | `{fieldList, list}` 列式 → 规范化后 `{list: [{...}]}` | `tradeDate` / `value` / `percentileRank` / `average` / `median` / `upper1Std` / `lower1Std`(共 7 个,实测 2026-07-24);**无 `securityCode`**——误传会拿到一列重复的 `tradeDate` |
|
|
59
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` |
|