gangtise-openapi-cli 0.33.0 → 0.34.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 +22 -20
- package/dist/src/cli.js +151 -55
- package/dist/src/core/commandBodies.js +9 -7
- package/dist/src/core/errors.js +38 -4
- package/dist/src/core/quoteSharding.js +11 -11
- package/dist/src/core/titleCache.js +88 -22
- package/dist/src/version.js +1 -1
- package/gangtise-openapi/SKILL.md +36 -35
- package/gangtise-openapi/references/commands/ai.md +2 -3
- package/gangtise-openapi/references/commands/fundamental.md +3 -2
- package/gangtise-openapi/references/commands/indicator.md +49 -33
- package/gangtise-openapi/references/commands/insight.md +10 -11
- package/gangtise-openapi/references/commands/quote.md +44 -25
- package/gangtise-openapi/references/commands/reference-and-lookup.md +3 -3
- package/gangtise-openapi/references/commands/vault.md +2 -1
- package/gangtise-openapi/references/examples.md +7 -7
- package/gangtise-openapi/references/fields.md +2 -2
- package/gangtise-openapi/references/lookup-ids.md +2 -2
- package/gangtise-openapi/references/response-schema.md +4 -4
- package/package.json +1 -1
|
@@ -20,39 +20,80 @@ export const MAX_TITLES_PER_ENDPOINT = 5_000;
|
|
|
20
20
|
let memoryCache = null;
|
|
21
21
|
let memoryCachePath = null;
|
|
22
22
|
let pendingWrite = null;
|
|
23
|
+
let pendingLoad = null;
|
|
24
|
+
/** Which file `pendingLoad` is loading. Keyed alongside the promise because the
|
|
25
|
+
* cache is a single-slot module global: coalescing on the promise ALONE would hand
|
|
26
|
+
* a caller asking for file B the contents of file A. */
|
|
27
|
+
let pendingLoadPath = null;
|
|
23
28
|
let dirty = false;
|
|
24
29
|
async function loadInto(filePath) {
|
|
25
30
|
if (memoryCache && memoryCachePath === filePath)
|
|
26
31
|
return memoryCache;
|
|
32
|
+
// Coalesce concurrent first-loads. Without this, two callers that both miss the
|
|
33
|
+
// cache each run their own readFile and each assign their OWN object to
|
|
34
|
+
// `memoryCache`; the last assignment wins, and entries written against the
|
|
35
|
+
// loser's reference are silently dropped. Sharing one promise means every
|
|
36
|
+
// caller gets the same object, so merges land in one place.
|
|
37
|
+
//
|
|
38
|
+
// The path check is what keeps that from becoming a worse bug than the one it
|
|
39
|
+
// fixes: same promise for the same file is deduplication, same promise for a
|
|
40
|
+
// different file is handing back the wrong file's data.
|
|
41
|
+
if (pendingLoad && pendingLoadPath === filePath)
|
|
42
|
+
return pendingLoad;
|
|
43
|
+
const load = (async () => {
|
|
44
|
+
try {
|
|
45
|
+
const content = await fs.readFile(filePath, "utf8");
|
|
46
|
+
const parsed = JSON.parse(content);
|
|
47
|
+
memoryCache = parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : {};
|
|
48
|
+
}
|
|
49
|
+
catch {
|
|
50
|
+
memoryCache = {};
|
|
51
|
+
}
|
|
52
|
+
memoryCachePath = filePath;
|
|
53
|
+
return memoryCache;
|
|
54
|
+
})();
|
|
55
|
+
pendingLoad = load;
|
|
56
|
+
pendingLoadPath = filePath;
|
|
27
57
|
try {
|
|
28
|
-
|
|
29
|
-
const parsed = JSON.parse(content);
|
|
30
|
-
memoryCache = parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : {};
|
|
58
|
+
return await load;
|
|
31
59
|
}
|
|
32
|
-
|
|
33
|
-
|
|
60
|
+
finally {
|
|
61
|
+
// Only clear if still ours — a load for another path may have replaced it.
|
|
62
|
+
if (pendingLoad === load) {
|
|
63
|
+
pendingLoad = null;
|
|
64
|
+
pendingLoadPath = null;
|
|
65
|
+
}
|
|
34
66
|
}
|
|
35
|
-
memoryCachePath = filePath;
|
|
36
|
-
return memoryCache;
|
|
37
67
|
}
|
|
38
68
|
export async function readTitleCache(filePath = DEFAULT_TITLE_CACHE_PATH) {
|
|
39
69
|
return loadInto(filePath);
|
|
40
70
|
}
|
|
41
71
|
async function flush(filePath) {
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
72
|
+
// Loop rather than snapshot once. `dirty` is cleared before the snapshot, so an
|
|
73
|
+
// entry added while we await the rename sets it again — and `writeTitleCache`
|
|
74
|
+
// hands that caller THIS in-flight promise instead of starting a second flush.
|
|
75
|
+
// Returning after one pass would leave that entry in memory only, never on disk.
|
|
76
|
+
for (;;) {
|
|
77
|
+
// Deciding to stop and releasing the in-flight handle must happen in ONE
|
|
78
|
+
// synchronous block. If they were split by an await, a write landing between
|
|
79
|
+
// them would attach to an already-resolving flush and never be written.
|
|
80
|
+
if (!dirty || !memoryCache) {
|
|
81
|
+
pendingWrite = null;
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
dirty = false;
|
|
85
|
+
const snapshot = JSON.stringify(memoryCache);
|
|
86
|
+
await fs.mkdir(path.dirname(filePath), { recursive: true });
|
|
87
|
+
// Atomic-ish: write to temp file then rename (rename is atomic within a fs).
|
|
88
|
+
const tmp = `${filePath}.tmp-${process.pid}-${Date.now()}`;
|
|
89
|
+
await fs.writeFile(tmp, snapshot, { encoding: "utf8", mode: 0o600 });
|
|
90
|
+
try {
|
|
91
|
+
await fs.rename(tmp, filePath);
|
|
92
|
+
}
|
|
93
|
+
catch (error) {
|
|
94
|
+
await fs.unlink(tmp).catch(() => { });
|
|
95
|
+
throw error;
|
|
96
|
+
}
|
|
56
97
|
}
|
|
57
98
|
}
|
|
58
99
|
/**
|
|
@@ -118,14 +159,34 @@ export async function writeTitleCache(endpoint, titles, filePath = DEFAULT_TITLE
|
|
|
118
159
|
pruneCache(data, endpoint, Object.keys(titles));
|
|
119
160
|
dirty = true;
|
|
120
161
|
// Coalesce concurrent writes: the in-flight flush picks up everything dirty.
|
|
162
|
+
//
|
|
163
|
+
// `flush` clears `pendingWrite` itself, in the same synchronous block as the
|
|
164
|
+
// `if (!dirty || !memoryCache)` test that decides to stop looping. Clearing it out
|
|
165
|
+
// here — in a `finally` after `await flush(...)` — would leave a gap of microtasks
|
|
166
|
+
// between "flush decided nothing is left" and "flush is no longer in flight": a
|
|
167
|
+
// write landing in that gap sets `dirty`, sees a non-null `pendingWrite`, and
|
|
168
|
+
// attaches to a promise that is already resolving, so its entry never reaches
|
|
169
|
+
// disk while its `await` still resolves normally. Same silent loss the loop was
|
|
170
|
+
// added to fix, just a narrower window.
|
|
121
171
|
if (pendingWrite)
|
|
122
172
|
return pendingWrite;
|
|
123
173
|
pendingWrite = (async () => {
|
|
124
174
|
try {
|
|
125
175
|
await flush(filePath);
|
|
126
176
|
}
|
|
127
|
-
|
|
177
|
+
catch (error) {
|
|
178
|
+
// flush throws before reaching its own clear, so release the handle here.
|
|
179
|
+
// Safe to null unconditionally: nothing else can have replaced it, since a
|
|
180
|
+
// non-null pendingWrite is exactly what stops another flush from starting.
|
|
181
|
+
//
|
|
182
|
+
// ⚠️ Only the SUCCESS path is atomic. A write landing between the throw and
|
|
183
|
+
// this line still attaches to the rejecting promise and never reaches disk;
|
|
184
|
+
// it recovers on the next successful write (which re-serialises the whole
|
|
185
|
+
// in-memory cache), and is lost only if no write ever follows. Left as-is
|
|
186
|
+
// deliberately — retrying against a filesystem that is already failing is
|
|
187
|
+
// worse than deferring to the next write.
|
|
128
188
|
pendingWrite = null;
|
|
189
|
+
throw error;
|
|
129
190
|
}
|
|
130
191
|
})();
|
|
131
192
|
return pendingWrite;
|
|
@@ -156,5 +217,10 @@ export function __resetTitleCacheForTests() {
|
|
|
156
217
|
memoryCache = null;
|
|
157
218
|
memoryCachePath = null;
|
|
158
219
|
pendingWrite = null;
|
|
220
|
+
// Must include the load handles: a reset that leaves `pendingLoad` set would hand
|
|
221
|
+
// the next readTitleCache the pre-reset promise, breaking the "force a fresh read
|
|
222
|
+
// from disk" contract this helper exists to provide.
|
|
223
|
+
pendingLoad = null;
|
|
224
|
+
pendingLoadPath = null;
|
|
159
225
|
dirty = false;
|
|
160
226
|
}
|
package/dist/src/version.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
// Auto-generated — DO NOT EDIT
|
|
2
|
-
export const CLI_VERSION = "0.
|
|
2
|
+
export const CLI_VERSION = "0.34.1";
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: gangtise-openapi
|
|
3
|
-
version: "0.
|
|
3
|
+
version: "0.34.1"
|
|
4
4
|
description: |-
|
|
5
5
|
通过 gangtise CLI 直接调用 Gangtise OpenAPI,拉取投研原始数据、批量导出、下载文件、调用 AI 能力。
|
|
6
6
|
|
|
@@ -27,11 +27,12 @@ description: |-
|
|
|
27
27
|
4. **时间格式**:datetime `"YYYY-MM-DD HH:mm:ss"`(引号包裹),date `YYYY-MM-DD`。
|
|
28
28
|
5. **多值参数**:优先重复传(最稳、最明确):`--security 600519.SH --security 000858.SZ`。CLI 也支持半/全角逗号分隔(`args.ts` 为语音输入容错),但重复传不易被 shell 吞。
|
|
29
29
|
6. **K 线"最近 N 条"**:必须用 `--start-date`/`--end-date` 拉日期范围,从结果按 `tradeDate` 取尾部最近 N 条。**不要只用 `--limit N`**(截取的是窗口开头)。
|
|
30
|
-
6.1. **日 K 仅历史**:`day-kline`
|
|
31
|
-
6.
|
|
30
|
+
6.1. **日 K 仅历史**:`day-kline` **不返回盘中实时数据**。当日数据入库时间:A 股 ~15:30 / 港股 ~16:30 / 美股 ~07:00(北京时间)。需要盘中快照请走 `quote realtime`。
|
|
31
|
+
6.1.1. 🔴 **`quote day-kline` 一个命令覆盖 A 股 / 港股 / 美股 / 指数**(2026-08-14 合并),可混着传代码。**全市场关键字是 `aShares` / `hkStocks` / `usStocks`,`--security all` 已废弃**(CLI 会报错并提示改用哪个),且关键字**必须单独传**,不能与代码或另一个关键字混填。指数(`.SH`/`.SZ`/`.BJ` 交易所指数、`.GT` 概念、`.CI`/`.SWI` 行业)不支持全市场关键字,须逐个传代码。`day-kline-hk` / `day-kline-us` / `index-day-kline` 已下线(接口仍可调、仍用 `all`),**新代码别用**——它们不校验证券代码,传错返 `total:0` 而不报错。
|
|
32
|
+
6.2. **多标的日 K 不自动分片**:只有全市场关键字才按日切片提额;显式传多个 `--security` 时走单请求(默认 `--limit 6000` / 上限 10000)。**v0.23.0 起:返回行数撞上 `--limit` 时结果会标 `partial`、退出码 3、stderr 警告**(不再静默截断;`--limit` 超 10000 本地直接报错)。仍建议先估 标的数 × 交易日数,接近/超 6000 → 逐只分开拉、或显式 `--limit 10000` 并按日期区间分批。
|
|
32
33
|
7. **CLI 已内置自动化,不要手动复刻**:
|
|
33
34
|
- 翻页 → 首页拿 total 后剩余页并发拉取;🔴 **全量拉取结束会多探一行验证 `total` 是不是服务端封顶**(`opinion` / `foreign-opinion` / `independent-opinion` 的 `total` 恒为 10000 但实际远不止)——探到就标 `partial` + `totalCapped` + 退出 3,**这时导出的是截断结果,要缩小时间范围分片拉**
|
|
34
|
-
- K
|
|
35
|
+
- K 线全市场关键字(`aShares` / `hkStocks` / `usStocks`;旧命令 `all`)跨日期 → 自动按日切片并合并,粒度按各市场单日行数定(A 1 天 / 港 2 天 / 美 1 天)
|
|
35
36
|
- 5xx / `429` / 网络错误 / `999999` → 自动指数退避重试(🔴 贵档端点例外:仅连接失败 / 429 / token 自愈重试,5xx/超时不重放防重复扣分,v0.26.0;`indicator` 端点对 `999999` 不重试,v0.27.0)
|
|
36
37
|
- Token 失效(`0000001008` / `999002`,含已废弃的 `8000014`/`8000015`)→ 自动重新登录并重试一次;凭证错 `999011` → **不重试**(AK/SK 不对不会自己好),查环境变量
|
|
37
38
|
8. **参数命名差异**:Insight/Quote/Vault 用 `--security`,Fundamental/AI 用 `--security-code`(例外:`ai stock-summary` 用 `--security`,`ai security-clue` 用 `--gts-code`)。
|
|
@@ -81,7 +82,7 @@ description: |-
|
|
|
81
82
|
|
|
82
83
|
### 数据范围(能查多久)
|
|
83
84
|
|
|
84
|
-
|
|
85
|
+
正式账号口径(下表为官方公布值;实际可查范围随账号服务等级而定,以自己账号实测为准):
|
|
85
86
|
|
|
86
87
|
| 命令组 | 可回溯 |
|
|
87
88
|
|--------|--------|
|
|
@@ -123,7 +124,7 @@ description: |-
|
|
|
123
124
|
| 纪要 / 会议纪要(外部) | `insight summary list` |
|
|
124
125
|
| 帕米尔纪要 / 帕米尔专家纪要 / Pamirs | `insight pamirs-summary list`(专家纪要库,需单独购买;筛选项比 `summary` 少,无 `--source`/`--institution`/`--participant-role`) |
|
|
125
126
|
| 路演 / 调研 / 策略会 / 论坛 | `insight roadshow / site-visit / strategy / forum list` |
|
|
126
|
-
| 财报日历 / 业绩预告 / 业绩快报 / 财报披露排期 | `insight performance-calendar list`(**用 `--start-date`/`--end-date`,不是 `--start-time
|
|
127
|
+
| 财报日历 / 业绩预告 / 业绩快报 / 财报披露排期 | `insight performance-calendar list`(**用 `--start-date`/`--end-date`,不是 `--start-time`**;全表体量很大且按条计费,CLI 强制要求日期范围 / `--security` / `--size` 三者至少其一;只给 `--security` 时另有 1000 行隐式上限,撞上限且 total 还有剩余=筛选可能没生效(标 `partial`、退出码 3),改用日期范围重查。下载原文 `performance-calendar download --performance-report-id`,仅 `hasAttachment: true` 可下) |
|
|
127
128
|
| A 股公告 / 公告 | `insight announcement list` |
|
|
128
129
|
| 港股公告 / HK 公告 | `insight announcement-hk list` |
|
|
129
130
|
| 美股公告 / US 公告 | `insight announcement-us list` |
|
|
@@ -133,7 +134,7 @@ description: |-
|
|
|
133
134
|
| 跨类型语义搜索(研报+纪要+...) | `ai knowledge-batch`(多个 `--resource-type`) |
|
|
134
135
|
| 知识库原文下载(搜到后取全文) | `ai knowledge-resource-download`(前置:`knowledge-batch` 拿 `resourceType`+`sourceId`;`250001`/旧 `433007`=组合不匹配) |
|
|
135
136
|
| 一页通 / 投资逻辑 / 同业对比 / 调研提纲 | `ai one-pager / investment-logic / peer-comparison / research-outline` |
|
|
136
|
-
| 个股看点 / 投研总结 / 公司速览 | `ai stock-summary`(`--security`
|
|
137
|
+
| 个股看点 / 投研总结 / 公司速览 | `ai stock-summary`(`--security` **只收具体代码**,单次最多 6000 个;仅 A 股/港股。⚠️ 2026-08-14 起**不再支持** `aShares`/`hkStocks` 全市场批量) |
|
|
137
138
|
| 业绩点评(异步) | `ai earnings-review` |
|
|
138
139
|
| 观点 PK / 多空辩论(异步) | `ai viewpoint-debate` |
|
|
139
140
|
| 投研线索 | `ai security-clue`(前置:`reference securities-search` 拿 `gts-code`) |
|
|
@@ -141,11 +142,10 @@ description: |-
|
|
|
141
142
|
| 热点话题 / 早午晚报 | `ai hot-topic` |
|
|
142
143
|
| 管理层讨论(财报) | `ai management-discuss-announcement` |
|
|
143
144
|
| 管理层讨论(业绩会) | `ai management-discuss-earnings-call` |
|
|
144
|
-
| A
|
|
145
|
-
|
|
|
146
|
-
| 美股日 K
|
|
147
|
-
|
|
|
148
|
-
| 分钟 K(A 股) | `quote minute-kline` |
|
|
145
|
+
| 日 K(历史,A 股 / 港股 / 美股 / 各类指数,可混查) | `quote day-kline` |
|
|
146
|
+
| 全部沪深京指数日 K / 要指数名称 | `quote index-day-kline`(**旧命令仍有两处 `day-kline` 做不到**:`--security all` 一次拿全部指数;返回 `securityName` 指数名称——`day-kline` 查指数只有代码没有名称) |
|
|
147
|
+
| ~~港股 / 美股日 K~~ | ⚠️ 已下线,用 `quote day-kline`(`day-kline-hk` / `day-kline-us` 仍可调但不校验代码) |
|
|
148
|
+
| 分钟 K(沪深 A 股 + 指数) | `quote minute-kline`(一次一只) |
|
|
149
149
|
| 实时行情(A / 港 / 美) | `quote realtime` |
|
|
150
150
|
| A股资金流向(主力/大单净流入,日频) | `quote fund-flow`(`--security` 或 `aShares` 全市场〔须带 `--start-date`/`--end-date`,按日自动分片〕;免费) |
|
|
151
151
|
| 单证券 A股完整利润表 / 资产负债 / 现金流(累计 / 单季) | `fundamental income-statement[-quarterly] / balance-sheet / cash-flow[-quarterly]` |
|
|
@@ -184,16 +184,16 @@ description: |-
|
|
|
184
184
|
- 港股代码用在 `insight foreign-opinion --security` 还是 `quote day-kline-hk --security`?前者要"境外"格式(`UBER.N`),后者要 `.HK`
|
|
185
185
|
- "成分股" → 题材深度(分组/重点标记/纳入理由)走 `alternative concept-securities`;板块(行业/概念分类树,纯代码名单)走 `reference sector-constituents`
|
|
186
186
|
- **证券基本面 / 指标先按任务形态路由,不是搜到 EDE 就一律走 EDE**:
|
|
187
|
-
- 单证券先优先对应 `fundamental` 专用命令(财务、估值、盈利预测、股东、主营或完整三大报表,多数免费 / 低价)。其中 `valuation-analysis` / `earning-forecast`
|
|
187
|
+
- 单证券先优先对应 `fundamental` 专用命令(财务、估值、盈利预测、股东、主营或完整三大报表,多数免费 / 低价)。其中 `valuation-analysis` / `earning-forecast` 当前仅支持 A 股,港 / 美股的**估值历史分位**与**盈利预测**无可用口径。但**估值指标本身别照抄旧结论**:`finc_pe_ttm` 港股、`qte_mkt_cptl`/`shr_tot` 港美股都已有数。⚠️ **凡「仅 A 股」「无数据」这类否定结论都只是某时点抽查**,数据覆盖在持续扩展;负面结论过期不会报错、只会让你白白拒掉一个能跑的查询。**一律以当次 `scopeList` + 抽查为准**
|
|
188
188
|
- 多证券批量取一组**已实现**财务 / 估值指标 → 优先 `indicator search` 后用 EDE 一次拉取,替代逐只循环;单日或同一报告期横向比较用 `cross-section`,区间走势用 `time-series`(后者不能多指标 × 多证券同时)。**批量按 code 回填加 `--key-by code`**(列头用 `indicatorCode`,防同名指标碰撞)。⚠️ **两个轴的顺序规则不同**:`indicatorList` = 请求顺序,但 **`securityCodeList` 是按代码升序重排的**(请求 `000858,600519,000001` → 回 `000001,000858,600519`)——**行绝不能按请求下标对位**,一律按 `security` 字段取值
|
|
189
|
-
- ⚠️ **估值指标的历史序列:两个接口的财报口径切换时点不同**——`indicator time-series`(EDE)按**正式财报披露日**切,`fundamental valuation-analysis` 按**业绩快报**口径切、通常更早,所以同一天取到的估值指标可能不一样(已验证 `finc_pe_ttm`/`peTtm`;`finc_pb_mrq` 等非 TTM 口径同样在报告期节点变化,规则未单独验证)。做估值分位 / 回测时**两个接口都拉一遍交叉核**,尤其业绩大幅变动的标的(抽查中出现过个别标的在 `valuation-analysis` 侧长期未更新)。分叉时用「总市值 ÷ PE 反推隐含净利润」对照利润表滚动 TTM
|
|
189
|
+
- ⚠️ **估值指标的历史序列:两个接口的财报口径切换时点不同**——`indicator time-series`(EDE)按**正式财报披露日**切,`fundamental valuation-analysis` 按**业绩快报**口径切、通常更早,所以同一天取到的估值指标可能不一样(已验证 `finc_pe_ttm`/`peTtm`;`finc_pb_mrq` 等非 TTM 口径同样在报告期节点变化,规则未单独验证)。做估值分位 / 回测时**两个接口都拉一遍交叉核**,尤其业绩大幅变动的标的(抽查中出现过个别标的在 `valuation-analysis` 侧长期未更新)。分叉时用「总市值 ÷ PE 反推隐含净利润」对照利润表滚动 TTM,即可判出哪侧是陈值。**判断某财报在某日是否已公开,用三大报表返回的 `earliestAnncDate`(首次公告日)**,不要用同一响应里的 `announcementDate`(它在部分证券上各期取值相同);要交叉核实就查 `insight announcement list` 的公告披露日。
|
|
190
190
|
- 始终排除 EDE:A股盈利预测 / 一致预期(含预测 EPS)→ `fundamental earning-forecast`;A股估值历史分位 → `fundamental valuation-analysis`;开高低收 / 成交量等行情与 K 线 → `quote`;单证券完整报表 → 对应三大报表命令。**例外:总市值只有 EDE 有**——`quote realtime` / `day-kline` 都不返回市值,走 `indicator cross-section --indicator qte_mkt_cptl`(2026-08-03 起 A/港/美股均有数,默认单位「元」,用 `--scale` 缩放)。EDE 搜到的基本 / 稀释 EPS 是已实现值,**不能冒充预测 EPS**;港 / 美股缺少上述专用能力时应如实说明不支持,不能用别的语义代替
|
|
191
191
|
- EDE 取数前必须用 `search --format json` 同时核对:`indicatorName` + `description` 语义准确、`scopeList` 覆盖全部目标市场 / 证券类型、`parameterList` 必填参数与枚举可满足;`scopeList` 缺失 / `null` / 空或任一项不符,都视为无法证明覆盖并回退专用接口。专用接口也不覆盖目标市场时,说明当前不可用,不要硬调。`scopeList` 按指标各不相同,不能因 EDE 服务支持 A / 港 / 美股就假定某个指标三市场都覆盖
|
|
192
192
|
- `indicator search` 免费,`cross-section` / `time-series` 按单元格计费;除多证券批量的效率收益外,仍优先免费 / 低价的 `quote` 或 `fundamental`
|
|
193
193
|
- 行业 / 宏观指标(空调销量、社融等,无证券维度)走 `alternative edb-*`(EDB),不要与证券级 EDE 混用
|
|
194
|
-
- **EDE「没数据」和「代码写错」是两回事**(2026-08-
|
|
195
|
-
- **EDE 指标参数名一律以 `indicator search --format json` 的 `parameterList`
|
|
196
|
-
-
|
|
194
|
+
- **EDE「没数据」和「代码写错」是两回事**(2026-08-15 实测):**①代码写错 → 直接报 `100003` 并指名是哪个**(指标写错报「指标 xxx 不存在」,证券写错报「xxx 不是有效证券或者板块ID」,美股用 `.US` 而非 `.O`/`.N` 同理),**无论同批有没有其它正确的 code 都会报**,所以拼写错误现在是一眼可见的、不用再靠对照推断;**②代码有效但无数据 / 无覆盖 / 未来日期 → 行列都保留**(含单指标 × 单证券的 1×1)并给一个占位单元格,**退出码 0**。🔴 **占位值不统一、由指标决定**:多数是 `null`,但个别(最常用的是 `is_dnrpnp` 扣非归母净利润)填 **`0`**,而 `0` 会照常穿过比较与聚合——`screener` 的 `F1 > 0` 因此可能筛出空集、整列求均值可能差几十倍(茅台时序实测差 52 倍)。**别把 `0` 当真值**,无覆盖时它与真值无法区分,**和已知有数的标的一起查做对照仍然必要**,详见 `references/commands/indicator.md`。日期语义按指标分两类:财务报表指标=报告期末(可为非交易日)、`finc_pe_ttm` / `finc_pb_mrq` 等日频估值=最新交易日(⚠️ `finc_pb_mrq` 是日频的,用报告期末日期会取到几个月前的陈值);混合取数按各自有效日期分次 `cross-section` 再按证券合并,别塞进同一个 `--date`。详见 `references/commands/indicator.md`
|
|
195
|
+
- **EDE 指标参数名一律以 `indicator search --format json` 的 `parameterList` 为准**,不要凭记忆或照抄示例。参数名写错会报 `100003` 并指出是哪个指标的哪个参数(如复权参数是 `adjustType`,写成 `adjustmentType` 直接报错),按报错信息改即可。⚠️ **报告期类指标(`is_*` 利润表等)必填 `reportDate`,不吃 `tradeDate`**——只传 `--date` 会报「不支持参数 tradeDate; 缺少必填参数 reportDate」,要补 `--indicator-param "code:reportDate=YYYY-MM-DD"`;行情 / 估值类(`qte_*` / `finc_*`)用 `--date` 即可。`--security` 支持板块 ID(`reference sector-search` 的 10 位 `sectorId`;`--indicator` 只收指标编码)。根级 `--scale` 只作用于声明了 `scale` 的指标,价格与金额可以混查。
|
|
196
|
+
- **新增指标**:融资融券 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`)
|
|
197
197
|
- "业绩点评"双义消歧:**检索已有**(研报/纪要里的业绩点评内容)走 `insight ... list --llm-tag earningsReview`(0.1/条);**AI 现生成**一份走 `ai earnings-review`(异步、50/次)。不确定问一句
|
|
198
198
|
|
|
199
199
|
## 公司名 → 证券代码
|
|
@@ -265,7 +265,7 @@ gangtise reference securities-search --keyword <公司名> --category stock --to
|
|
|
265
265
|
|
|
266
266
|
日期参数**按参数名判断、不按命令组**(命令组会误导——AI 里既有 `--start-time` 又有 `--date`/`--report-date`;Insight 里 `performance-calendar` 是唯一用 `--start-date`/`--end-date` 的 list):名字带 `-date` 的(`--start-date`/`--end-date`/`--date`/`--report-date`)一律 `YYYY-MM-DD`,覆盖 Quote/Fundamental、`insight performance-calendar`、AI 的 `theme-tracking`(`--date`)/`hot-topic`/`management-discuss-*`(`--report-date`)、Alternative `edb-data`、Indicator `cross-section`(`--date`)/`time-series`;名字带 `-time` 的(`--start-time`/`--end-time`)用 `YYYY-MM-DD[ HH:mm[:ss]]`(秒可省、空格或 `T` 分隔)或 10/13 位时间戳,覆盖 Insight/Vault 各 list、`quote minute-kline`、`ai security-clue`、`ai knowledge-batch`。其中 **A 股公告(`insight announcement list`)与 `knowledge-batch` 会把输入转成 13 位毫秒**(10 位秒自动 ×1000),其余 `-time` 命令(含 `announcement-hk`/`announcement-us`)原样透传字符串;CLI 输入统一接受 10/13 位纯数字或 `YYYY-MM-DD[ HH:mm[:ss]]`(同上:秒可省、空格或 `T` 分隔)。
|
|
267
267
|
|
|
268
|
-
|
|
268
|
+
支持排序切换的命令:opinion / summary / pamirs-summary / research / foreign-report / announcement / announcement-hk / announcement-us / foreign-opinion / independent-opinion / official-account。**要最新的加 `--rank-type 2`(严格按 `publishTime` 倒序);要最相关的用默认 `--rank-type 1` + `--keyword` + `--search-type 2`(综合排序按相关度挑条目)**——两者从同一结果集里取的是**不同的子集**,不是同一批内容换个排法。⚠️ 综合排序**挑完之后仍按时间倒序排列**,所以别用「结果是不是时间倒序」判断它有没有生效,要比条目 ID。没有 `--keyword` 时两者无差异,属正常。详见 `insight.md` 开头。其他 list 命令按 API 默认排序。
|
|
269
269
|
|
|
270
270
|
## 异常处理
|
|
271
271
|
|
|
@@ -287,12 +287,12 @@ gangtise reference securities-search --keyword <公司名> --category stock --to
|
|
|
287
287
|
| ✅ `999999` | 系统错误。**`indicator`(EDE)2026-08-01 前用此码表示查询无数据,之后改为返回数据体**,所以这个码基本只剩真故障。⚠️ 现在「无数据」是保留行列的占位单元格(多为 `null`,个别指标是 `0`,见 `indicator.md`),**不是空表**;空表另有含义(整轴 code 未识别) | 普通端点自动重试 ×2;🔴 贵档与 `indicator` 端点不重试 | 确认参数无误仍报此码即服务端故障 |
|
|
288
288
|
| ✅ `410110` | **异步生成中**(HTTP 400,旧码未切)。新码 `140001`,CLI 两码都认 | 轮询视为 pending | 继续等 |
|
|
289
289
|
| ✅ `410111` | **异步生成失败**(HTTP 400,旧码未切)。新码 `140002`,CLI 两码都认 | 终态 | **不重试**,换参数 |
|
|
290
|
-
| ✅ `130002` |
|
|
290
|
+
| ✅ `130002` | 资源不存在——下载类的常见码:`reportId` 不存在 / 非数字多归此码。另有更具体的 `130003`(资源未生成 / 无附件)与 `130005`(`fileType` 非法) | — | 确认 ID 有效且本账号可见;换 `--file-type` 或换一篇验证 |
|
|
291
291
|
| ✅ `130001` | 数据未找到,或**该指标无权限**(`indicator` 内层失败会带具体 msg 如"指标无权限") | — | 检查查询条件与指标权限 |
|
|
292
292
|
| ✅ `100001` | 缺必填参数——**msg 带字段名**(「缺少必填参数: reportId」) | — | 按 msg 指的字段补上 |
|
|
293
|
-
| ✅ `110001` / `110002` | 日期格式错(msg 带字段名)/
|
|
294
|
-
| ✅ `120001` | 证券代码无效——msg 带原因(「非有效A
|
|
295
|
-
| ✅ `110003` |
|
|
293
|
+
| ✅ `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 位毫秒 |
|
|
294
|
+
| ✅ `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`) |
|
|
295
|
+
| ✅ `110003` | **超出账号数据权限的时间范围**。范围按账号等级而定、**不是平台常量**,且**同一账号下按接口还可能不一样**——出现过同日同指标同证券 `cross-section` 取得到、`indicator screener` 却报此码的情况 | — | 把日期移进权限范围内;整个区间都早于下界时缩短窗口无用(`--fiscal-year 2015` 无论怎么缩都报错)。`screener` 撞界改用 `cross-section` 拉数再本地筛,否则联系客户经理开通 |
|
|
296
296
|
| ✅ `100006` | 查询/下载数量超限——**取代旧 `430007`**;实测 `fund-flow` 全市场不传日期即此码 | — | 缩短日期范围或调小 `--size`/`--limit`;全市场场景应已自动分片 |
|
|
297
297
|
| ✅ `240001` | 财报期未披露或超出查询期(`earnings-review` 提交阶段就报,**不扣积分**) | — | 换更早的 `--period`(`2025q3` → `2025interim`) |
|
|
298
298
|
| ✅ `250001` | 不支持的数据源——**取代旧 `433007`** | — | 检查 `resourceType + sourceId` 组合 |
|
|
@@ -304,11 +304,11 @@ gangtise reference securities-search --keyword <公司名> --category stock --to
|
|
|
304
304
|
| ✅ `900002` | **请求方法不正确**(msg「请求类型有误」,HTTP 405) | — | `raw call` 时确认该 endpoint 是 GET 还是 POST |
|
|
305
305
|
| ✅ `140002` | 终态参数错:AI 异步生成失败,或 `indicator` 的指标必填参数缺失 / 枚举越界 / 表达式语法错(实测 2026-08-02) | **不重试**(终态码) | 按 msg 改参数重提;EDE 的参数名与枚举读 `indicator search --format json` 的 `parameterList` |
|
|
306
306
|
|
|
307
|
-
**⚠️
|
|
308
|
-
-
|
|
309
|
-
- **财报接口的日期按「报告期末」过滤**,不是公告日:`fundamental balance-sheet` 等的 `--start-date`/`--end-date` 匹配的是 `endDate` 字段(如 `20200630
|
|
310
|
-
-
|
|
311
|
-
-
|
|
307
|
+
**⚠️ 几类"不报错"的坑(最难发现,逐条都关系到拿没拿到对的数)**
|
|
308
|
+
- **日期只写 `YYYY-MM-DD`、时间只写 `YYYY-MM-DD HH:mm:ss`(或 10/13 位时间戳)**。CLI v0.28.0 起 date 与 datetime 两类(含所有 insight/vault 透传参数)都在发请求前校验,其余写法直接报 `ValidationError`。接口本身能接受多种格式,但**「年在后」写法(`01-07-2026`)存在月/日歧义**——会按月在前读作 1 月 7 日,本意写 7 月 1 日的就拿到差半年的数据且不报错。**CLI 只放行 `YYYY-MM-DD` 就是为了堵掉这个歧义,这是有意的**;绕过 CLI 直连接口时务必自己用标准格式
|
|
309
|
+
- **财报接口的日期按「报告期末」过滤**,不是公告日:`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 行,属正常行为,不是没数据
|
|
310
|
+
- **非法证券代码**:`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`
|
|
311
|
+
- **枚举值拼错的后果按端点不同,且部分端点不报错**:纪要 `summary`、三个公告 list、路演 `roadshow`、调研 `site-visit` 的 `--search-type` / `--rank-type` / `--category` / `--market` 等传非法值会报 `100005`;而 `insight research`(内资研报)、`foreign-report`(外资研报)、`official-account`、`opinion` 上非法值被**静默忽略**,该筛选按未传处理。🔴 **最坏的一种**:`research` / `foreign-report` 上非法的 `--search-type` 会**连带吞掉 `--keyword`**——`research list --keyword 茅台 --search-type 99` 拿到的是**未经筛选的全库**,与不传 `--keyword` 的结果一致,而不是搜索结果。**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` 等仍是自由字符串,拼错不报错也不生效——这些要自己核对。**拼错的筛选条件会伪装成"结果正常",枚举拼写要自己保证**
|
|
312
312
|
- **`viewpoint-debate` 传敏感内容不会被提前拦截**——实测不返回 `240002`,而是照常受理、扣满 50 积分、生成阶段才以 `410111` 失败。**提交前自己把关措辞**
|
|
313
313
|
- **`ai one-pager` 的非法 `mode` 被静默忽略**,照常生成并扣 50 积分
|
|
314
314
|
|
|
@@ -320,8 +320,8 @@ gangtise reference securities-search --keyword <公司名> --category stock --to
|
|
|
320
320
|
| `999007` / `999008` / `999009` | 方法/媒体类型/请求体不支持 | 实际返回 `900002` / `999999` / `100003` |
|
|
321
321
|
| `999003` / `999005` / `999006` | 无接口权限 / 积分不足 / 限流 | 未构造出(需特定账号状态) |
|
|
322
322
|
| `999012`–`999016` | 账号禁用/过期、租户失效、无长期 token、IP 不合规 | 未构造出 |
|
|
323
|
-
| `100002` / `100004` / `100005` | 类型错 / 分页非法 / 枚举非法 | 类型错归 `100003
|
|
324
|
-
| `
|
|
323
|
+
| `100002` / `100004` / `100005` | 类型错 / 分页非法 / 枚举非法 | 类型错归 `100003`。**`100005` 与 `100006` 2026-08-14 起在部分 list 上真会触发**(枚举非法、`size` 超 50);未覆盖的端点(`research` / `foreign-report` / `opinion` / `official-account`)仍按未传处理,见上方「实测发现的坑」 |
|
|
324
|
+
| `130004` | 下载 ID 非数字 | 多归 `130002` |
|
|
325
325
|
| `140001` / `140002` | 结果生成中 / 处理失败 | 异步端点仍用 `410110` / `410111` |
|
|
326
326
|
| `210001` / `220001` / `230001` | 研报/观点/分享文件不支持下载 | 未构造出 |
|
|
327
327
|
| `230002` | 微信账号未绑定(私域,2026-08-07 新增)。⚠️ **`vault wechat-*` 就在该模块下、够得着**:要求先绑定并激活群消息助理且助理已入群 | 未构造出(本账号已绑定) |
|
|
@@ -338,11 +338,10 @@ gangtise reference securities-search --keyword <公司名> --category stock --to
|
|
|
338
338
|
**其他场景**:
|
|
339
339
|
- CLI 未安装 → `npm install -g gangtise-openapi-cli`
|
|
340
340
|
- **退出码 3 = `partial: true`,结果少了数据**(保留已取到的部分;stderr 有 warning,`--format json` 才看得见标记,table/csv/jsonl 只有数据行、看不出问题):
|
|
341
|
-
- 触发场景:翻页/K线分片有页失败、服务端返回行数与 `total`
|
|
342
|
-
- **EDE
|
|
343
|
-
- **`screener` 的缺列按表达式的布尔结构判**:把缺列的变量当作「无法求值」,看整个表达式**是否还有一条能成立的分支**——`A && B` 要两边都可求值,`A || B` 只要一边。**一条分支都不剩 → 退出码 1、不输出任何结果**(返回的行以「通过了该条件」的名义呈现,而条件根本无法证明被执行过);**还有分支可求值,或缺的只是未参与表达式的辅助变量 → `partial` + 退出码 3**。所以 `F1 || F2` 缺 F1 是降级(行可能靠 F2 正当命中),缺两个则是致命;`F1 && (F2 || F3)` 缺 F1 仍是致命(F1 是必选合取项)。⚠️
|
|
341
|
+
- 触发场景:翻页/K线分片有页失败、服务端返回行数与 `total` 矛盾(提前短页)、`total` 撞服务端上限(`totalCapped`,见 opinion 家族)。附带定位字段:页失败 `failedPages`;分片失败 `failedShards`、分片撞行数上限 `truncatedShards`(均带日期区间可缩窗补拉)。⚠️ EDE 的 `omittedIndicators` / `omittedSecurities` 仍在代码里,但 2026-08-15 起写错的 code 在服务端就被 `100003` 拒了(退出 1),这条路基本收不到样本
|
|
342
|
+
- **EDE 代码写错现在是退出码 1 + `100003`,msg 里直接点名是哪个 code**(美股后缀用 `.O`/`.N`,不是 `.US`),不用再从退出码 3 反推。真的没覆盖仍是占位单元格(多数 `null`、个别指标 `0`)+ 退出码 0
|
|
343
|
+
- **`screener` 的缺列按表达式的布尔结构判**:把缺列的变量当作「无法求值」,看整个表达式**是否还有一条能成立的分支**——`A && B` 要两边都可求值,`A || B` 只要一边。**一条分支都不剩 → 退出码 1、不输出任何结果**(返回的行以「通过了该条件」的名义呈现,而条件根本无法证明被执行过);**还有分支可求值,或缺的只是未参与表达式的辅助变量 → `partial` + 退出码 3**。所以 `F1 || F2` 缺 F1 是降级(行可能靠 F2 正当命中),缺两个则是致命;`F1 && (F2 || F3)` 缺 F1 仍是致命(F1 是必选合取项)。⚠️ **前提是服务端返回了命中行**——零命中时走「nothing matched」+ **退出码 0**。**空集别急着当成「条件成立但无标的符合」**:指标码写错现在会直接报 `100003`(退出 1),所以剩下的头号嫌疑是**占位值 `0`** —— `F1 > 0` 在 `is_dnrpnp` 这类填 `0` 的指标上必然筛出空集
|
|
344
344
|
- 拿到 3 就必须告知用户缺了哪段,不能当成功静默继续
|
|
345
|
-
- (历史:条件选股把同一指标绑到多个变量曾触发 `unreliable: true` + `duplicatedIndicators`,因服务端把所有绑定按最早日期取数。2026-08-08 服务端已修复,该标记**已从 CLI 移除**,这类查询现在正常可用)
|
|
346
345
|
- 空结果(list 为空数组) → 建议扩大时间范围、换关键词、去掉部分筛选
|
|
347
346
|
- 模糊公司名匹配多只("平安" → 中国平安 / 平安银行 / ...) → 列出让用户选
|
|
348
347
|
- 下载文件路径冲突 → 询问覆盖
|
|
@@ -363,7 +362,7 @@ gangtise reference securities-search --keyword <公司名> --category stock --to
|
|
|
363
362
|
3. 行业 ID 用错体系:`--industry`(用 `citicIndustry` 码 `1008001xx`)/ `--research-area`(行业同样用 `citicIndustry` 码 `1008001xx`,方向才用 `gangtiseIndustry` 码 `122000xxx`——`gangtiseIndustry` 里**只有 6 条方向码、没有行业**)/ `--gts-code`(申万 `821xxx.SWI`)。申万数字码 `104xx0000` 用于 `--research-area` 时多数端点返 0,详见 `references/commands/reference-and-lookup.md`
|
|
364
363
|
4. `--rating` / `--category` 等枚举值拼错(参考对应命令的 references 文件)
|
|
365
364
|
|
|
366
|
-
**`999011` 凭证无效**(旧码 `8000014`/`8000015
|
|
365
|
+
**`999011` 凭证无效**(旧码 `8000014`/`8000015`;不区分是 AK 错还是 SK 错,**登录直接失败、CLI 不重试**)
|
|
367
366
|
1. `echo $GANGTISE_ACCESS_KEY` 验环境变量是否 export
|
|
368
367
|
2. AK 和 SK 是否写反
|
|
369
368
|
3. 账号是否到期 / 异常(`gangtise auth status`;对应 `999012`/`999013`)
|
|
@@ -379,7 +378,9 @@ gangtise reference securities-search --keyword <公司名> --category stock --to
|
|
|
379
378
|
|
|
380
379
|
**翻页很慢 / 卡住** → `--verbose` 看哪一页慢;可 `GANGTISE_PAGE_CONCURRENCY=10` 提速,或缩小时间范围。
|
|
381
380
|
|
|
382
|
-
|
|
381
|
+
**全市场 K 线报 `100006`**(旧码 `430007`)→ 单日数据仍超 10K 行(极端情况)→ 临时改用更窄的 `--start-date`/`--end-date`,或改为单只 `--security` 单独拉。
|
|
382
|
+
|
|
383
|
+
**`quote day-kline --security all` 被 CLI 拒**(`'all' is not a whole-market keyword`)→ 服务端 2026-08-14 停止支持该写法 → 换成 `aShares` / `hkStocks` / `usStocks` 之一,单独传。
|
|
383
384
|
|
|
384
385
|
**AI agent 命令(one-pager 等)超时** → 服务端生成耗时长,CLI 默认 30s → `GANGTISE_TIMEOUT_MS=120000` 后重试。
|
|
385
386
|
|
|
@@ -53,10 +53,10 @@ gangtise ai peer-comparison --security-code <code>
|
|
|
53
53
|
|
|
54
54
|
```bash
|
|
55
55
|
gangtise ai stock-summary --security <code> [--security <code2> ...]
|
|
56
|
-
gangtise ai stock-summary --security <aShares|hkStocks>
|
|
57
56
|
```
|
|
58
57
|
|
|
59
|
-
- `--security
|
|
58
|
+
- `--security`(**必选**,可重复):**只收具体证券代码**,单次最多 6000 个
|
|
59
|
+
- 🔴 **2026-08-14 起不再支持全市场批量**:`aShares` / `hkStocks` 这类市场关键词已被移除,CLI 会本地报错(服务端对它们返 `120001`,读起来像代码写错,容易误判)。需要覆盖一批标的就先用 `reference securities-search` 或自有清单取到代码,再分批传入
|
|
60
60
|
- **仅支持 A 股和港股**
|
|
61
61
|
- **积分**:`3`/条;个股若无看点总结则不在返回列表中,也不扣分
|
|
62
62
|
- 返回字段:`securityCode` / `securityName` / `summary`(精炼投研总结)/ `date`(更新日期 `yyyy-MM-dd`)
|
|
@@ -64,7 +64,6 @@ gangtise ai stock-summary --security <aShares|hkStocks>
|
|
|
64
64
|
**示例:**
|
|
65
65
|
```bash
|
|
66
66
|
GANGTISE_TIMEOUT_MS=120000 gangtise ai stock-summary --security 600519.SH --security 00700.HK --format json # 茅台 / 腾讯看点
|
|
67
|
-
GANGTISE_TIMEOUT_MS=120000 gangtise ai stock-summary --security hkStocks --format json # 全部港股,total 2662
|
|
68
67
|
```
|
|
69
68
|
|
|
70
69
|
## 调研提纲 `ai research-outline`
|
|
@@ -16,8 +16,9 @@ gangtise fundamental <income-statement|balance-sheet|cash-flow> --security-code
|
|
|
16
16
|
- `--report-type`:`consolidated`(默认)| `consolidatedRestated` | `standalone` | `standaloneRestated`
|
|
17
17
|
- `--fiscal-year` 可重复:`--fiscal-year 2023 --fiscal-year 2024`
|
|
18
18
|
- `--start-date`/`--end-date` 有值时覆盖 `--fiscal-year`
|
|
19
|
-
- **固定返回字段**(无需 `--field` 指定):`securityCode` `companyName` `category` `announcementDate` `endDate` `fiscalYear` `period` `reportType` `companyType` `currency` `unit`
|
|
20
|
-
-
|
|
19
|
+
- **固定返回字段**(无需 `--field` 指定):`securityCode` `companyName` `category` `announcementDate` **`earliestAnncDate`** `endDate` `fiscalYear` `period` `reportType` `companyType` `currency` `unit`
|
|
20
|
+
- 🔴 **做时点对齐(「这份财报在某日是否已公开」)用 `earliestAnncDate`(首次公告日),不要用 `announcementDate`**:`announcementDate` 在部分证券上会把同一财年各期都填成同一个日期,据此判断「某期数据在某日是否已公开」会得出相反的结论;`earliestAnncDate` 是该报告期自身的首次公告日。盘后披露的报告计次日,即**永不早于**真实披露时点,用来做 point-in-time 是安全的方向。要交叉核实披露日可查 `insight announcement list`
|
|
21
|
+
- `companyType` / `currency` 在三张累计口径表上均正确(`companyType=一般企业`/`银行`/`保险公司`/`证券公司`,`currency=人民币`)。⚠️ **仅 A 股 `*-quarterly` 单季表例外**:`companyType` 返回未映射的数字码(如 `102119999`),`currency` 正确——单季表读公司类型时按需自行映射,科目数字本身不受影响
|
|
21
22
|
|
|
22
23
|
**常用字段速查:**
|
|
23
24
|
- 利润表:`totalOpRev` 营收 | `netProfit` 净利润 | `netProfitAttrParent` 归母 | `basicEPS` EPS | `rdExp` 研发
|