echopai 2.1.0 → 2.3.0

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
@@ -125,13 +125,16 @@ Available MCP tools (subset shown to LLM depends on token scopes):
125
125
  | `digest` | One-shot research digest: 5 buckets in one call | `digest.get` + fan-out fallback |
126
126
  | `quote` | Real-time quote for 1-200 codes | `quote` |
127
127
  | `views` | **PRIMARY** research source (analyst views w/ entity attribution) | `views.recent` |
128
- | `research` | Research-entity performance (hit rate / coverage) | `research.entity-performance-list` |
129
128
  | `news` | **SUPPLEMENTARY** news / market briefs | `news.search` / `news.feed` |
130
129
  | `sentiment` | Aggregate market sentiment | `sentiment.overview` |
131
130
  | `hot` | Today's hot-stock leaderboard | `stocks.hot` |
132
131
  | `chart` | Single-security K-line (daily / minute) | `bars.daily` / `bars.minute` |
133
132
  | `bars_batch` | Batch K-line (≤100 codes × 1yr daily; ≤20 × 7d minute) | `bars.daily-batch` / `bars.minute-batch` |
134
133
  | `scan` | Full-market quote snapshot (~5800 securities) | `quote.scan` |
134
+ | `financials_quote_snapshot` | **Headline** valuation snapshot (PE / PB / PS / 换手率 / 股息率 / 量比 14 fields, TDX + Sina 自算) | `financials.quote-snapshot` |
135
+ | `financials_pit` | Point-in-time financial indicators at a given trade_date (anti-future-fn for backtests) | `financials.pit` |
136
+ | `financials_reports` | Last N report-period snapshots (~25 fields × period, filter by Q1/H1/Q3/annual) | `financials.reports` |
137
+ | `financials_series` | Time series of a single financial metric across report periods | `financials.series` |
135
138
 
136
139
  The agent should prefer `views` over `news` when forming an investment
137
140
  opinion (views carries research-entity attribution; news is breadth-only).
@@ -159,6 +162,15 @@ echopai raw views feed --since-days 7 --all | jq '.title'
159
162
 
160
163
  # One-shot research digest (server-side composite, 5 buckets, partial-failure tolerant)
161
164
  echopai digest --code SSE:600519
165
+
166
+ # Headline valuation snapshot: 14 fields (PE / PB / PS / 换手率 / 股息率 / 量比 ...)
167
+ echopai financials quote-snapshot --code SSE:600519
168
+ echopai financials quote-snapshot --code SSE:600519 --date 2026-05-13 # historical
169
+
170
+ # Deeper fundamentals
171
+ echopai financials pit --code SSE:600519 --date 2024-11-01
172
+ echopai financials reports --code SSE:600519 --kind annual --limit 5
173
+ echopai financials series --code SSE:600519 --metric roe_simple
162
174
  ```
163
175
 
164
176
  ## Output formats
@@ -76,27 +76,27 @@ export function buildCommandTree(program, dispatch) {
76
76
  }
77
77
  }
78
78
  {
79
- const noun = program.command("auth");
80
- noun.description("auth commands");
79
+ const noun = program.command("announcements");
80
+ noun.description("announcements commands");
81
81
  {
82
- const cmd = noun.command("whoami");
83
- attachOperation(cmd, OPERATIONS["auth.whoami"], dispatch);
82
+ const cmd = noun.command("detail");
83
+ attachOperation(cmd, OPERATIONS["announcements.detail"], dispatch);
84
84
  }
85
- }
86
- {
87
- const noun = program.command("backtest");
88
- noun.description("backtest commands");
89
85
  {
90
- const cmd = noun.command("excess-distribution");
91
- attachOperation(cmd, OPERATIONS["backtest.excess-distribution"], dispatch);
86
+ const cmd = noun.command("feed");
87
+ attachOperation(cmd, OPERATIONS["announcements.feed"], dispatch);
92
88
  }
93
89
  {
94
- const cmd = noun.command("rolling-win-rate");
95
- attachOperation(cmd, OPERATIONS["backtest.rolling-win-rate"], dispatch);
90
+ const cmd = noun.command("stock");
91
+ attachOperation(cmd, OPERATIONS["announcements.stock"], dispatch);
96
92
  }
93
+ }
94
+ {
95
+ const noun = program.command("auth");
96
+ noun.description("auth commands");
97
97
  {
98
- const cmd = noun.command("summary");
99
- attachOperation(cmd, OPERATIONS["backtest.summary"], dispatch);
98
+ const cmd = noun.command("whoami");
99
+ attachOperation(cmd, OPERATIONS["auth.whoami"], dispatch);
100
100
  }
101
101
  }
102
102
  {
@@ -119,6 +119,46 @@ export function buildCommandTree(program, dispatch) {
119
119
  attachOperation(cmd, OPERATIONS["bars.minute-batch"], dispatch);
120
120
  }
121
121
  }
122
+ {
123
+ const noun = program.command("concepts");
124
+ noun.description("concepts commands");
125
+ {
126
+ const cmd = noun.command("alerts");
127
+ attachOperation(cmd, OPERATIONS["concepts.alerts"], dispatch);
128
+ }
129
+ {
130
+ const cmd = noun.command("alerts-history");
131
+ attachOperation(cmd, OPERATIONS["concepts.alerts-history"], dispatch);
132
+ }
133
+ {
134
+ const cmd = noun.command("daily-bars");
135
+ attachOperation(cmd, OPERATIONS["concepts.daily-bars"], dispatch);
136
+ }
137
+ {
138
+ const cmd = noun.command("list");
139
+ attachOperation(cmd, OPERATIONS["concepts.list"], dispatch);
140
+ }
141
+ {
142
+ const cmd = noun.command("minute-bars");
143
+ attachOperation(cmd, OPERATIONS["concepts.minute-bars"], dispatch);
144
+ }
145
+ {
146
+ const cmd = noun.command("news");
147
+ attachOperation(cmd, OPERATIONS["concepts.news"], dispatch);
148
+ }
149
+ {
150
+ const cmd = noun.command("show");
151
+ attachOperation(cmd, OPERATIONS["concepts.show"], dispatch);
152
+ }
153
+ {
154
+ const cmd = noun.command("snapshot");
155
+ attachOperation(cmd, OPERATIONS["concepts.snapshot"], dispatch);
156
+ }
157
+ {
158
+ const cmd = noun.command("views");
159
+ attachOperation(cmd, OPERATIONS["concepts.views"], dispatch);
160
+ }
161
+ }
122
162
  {
123
163
  const noun = program.command("digest");
124
164
  noun.description("digest commands");
@@ -134,6 +174,10 @@ export function buildCommandTree(program, dispatch) {
134
174
  const cmd = noun.command("pit");
135
175
  attachOperation(cmd, OPERATIONS["financials.pit"], dispatch);
136
176
  }
177
+ {
178
+ const cmd = noun.command("quote-snapshot");
179
+ attachOperation(cmd, OPERATIONS["financials.quote-snapshot"], dispatch);
180
+ }
137
181
  {
138
182
  const cmd = noun.command("reports");
139
183
  attachOperation(cmd, OPERATIONS["financials.reports"], dispatch);
@@ -159,6 +203,46 @@ export function buildCommandTree(program, dispatch) {
159
203
  attachOperation(cmd, OPERATIONS["index.snapshot"], dispatch);
160
204
  }
161
205
  }
206
+ {
207
+ const noun = program.command("industries");
208
+ noun.description("industries commands");
209
+ {
210
+ const cmd = noun.command("alerts");
211
+ attachOperation(cmd, OPERATIONS["industries.alerts"], dispatch);
212
+ }
213
+ {
214
+ const cmd = noun.command("daily-bars");
215
+ attachOperation(cmd, OPERATIONS["industries.daily-bars"], dispatch);
216
+ }
217
+ {
218
+ const cmd = noun.command("list");
219
+ attachOperation(cmd, OPERATIONS["industries.list"], dispatch);
220
+ }
221
+ {
222
+ const cmd = noun.command("show");
223
+ attachOperation(cmd, OPERATIONS["industries.show"], dispatch);
224
+ }
225
+ {
226
+ const cmd = noun.command("snapshot");
227
+ attachOperation(cmd, OPERATIONS["industries.snapshot"], dispatch);
228
+ }
229
+ }
230
+ {
231
+ const noun = program.command("limit-up");
232
+ noun.description("limit-up commands");
233
+ {
234
+ const cmd = noun.command("history");
235
+ attachOperation(cmd, OPERATIONS["limit-up.history"], dispatch);
236
+ }
237
+ {
238
+ const cmd = noun.command("pool");
239
+ attachOperation(cmd, OPERATIONS["limit-up.pool"], dispatch);
240
+ }
241
+ {
242
+ const cmd = noun.command("summary");
243
+ attachOperation(cmd, OPERATIONS["limit-up.summary"], dispatch);
244
+ }
245
+ }
162
246
  {
163
247
  const noun = program.command("market");
164
248
  noun.description("market commands");
@@ -186,10 +270,6 @@ export function buildCommandTree(program, dispatch) {
186
270
  const cmd = noun.command("search");
187
271
  attachOperation(cmd, OPERATIONS["news.search"], dispatch);
188
272
  }
189
- {
190
- const cmd = noun.command("sources");
191
- attachOperation(cmd, OPERATIONS["news.sources"], dispatch);
192
- }
193
273
  }
194
274
  {
195
275
  const noun = program.command("payment");
@@ -211,18 +291,6 @@ export function buildCommandTree(program, dispatch) {
211
291
  attachOperation(cmd, OPERATIONS["quote.scan"], dispatch);
212
292
  }
213
293
  }
214
- {
215
- const noun = program.command("research");
216
- noun.description("research commands");
217
- {
218
- const cmd = noun.command("entity-performance");
219
- attachOperation(cmd, OPERATIONS["research.entity-performance"], dispatch);
220
- }
221
- {
222
- const cmd = noun.command("entity-performance-list");
223
- attachOperation(cmd, OPERATIONS["research.entity-performance-list"], dispatch);
224
- }
225
- }
226
294
  {
227
295
  const noun = program.command("search");
228
296
  noun.description("search commands");
@@ -267,18 +335,6 @@ export function buildCommandTree(program, dispatch) {
267
335
  attachOperation(cmd, OPERATIONS["sentiment.turnover"], dispatch);
268
336
  }
269
337
  }
270
- {
271
- const noun = program.command("signals");
272
- noun.description("signals commands");
273
- {
274
- const cmd = noun.command("outcome");
275
- attachOperation(cmd, OPERATIONS["signals.outcome"], dispatch);
276
- }
277
- {
278
- const cmd = noun.command("outcomes");
279
- attachOperation(cmd, OPERATIONS["signals.outcomes"], dispatch);
280
- }
281
- }
282
338
  {
283
339
  const noun = program.command("squawk");
284
340
  noun.description("squawk commands");
@@ -17,26 +17,26 @@ export const HELP = {
17
17
  "description": "返回 session 内累计 billable 调用次数、各 scope 配额消耗。",
18
18
  "example": "echopai agent session-usage VALUE"
19
19
  },
20
+ "announcements.detail": {
21
+ "summary": "Fetch a single announcement by id",
22
+ "description": "返回公告完整内容:content_md、content_text、cninfo 元数据、解析状态。",
23
+ "example": "echopai announcements detail VALUE"
24
+ },
25
+ "announcements.feed": {
26
+ "summary": "List recent A-share announcements",
27
+ "description": "A 股公告 feed,按 published_at 降序、同日按 cninfo source_id 降序。可按 type / since 过滤。需要 `announcements:read` scope。",
28
+ "example": "echopai announcements feed"
29
+ },
30
+ "announcements.stock": {
31
+ "summary": "List announcements for a specific A-share security",
32
+ "description": "指定股票代码的公告列表(含历史窗口)。代码接受 6 位纯数字或 SSE:600519 / SZSE:000001 / BSE:430000 形式。需要 `announcements:read` scope。",
33
+ "example": "echopai announcements stock --code SSE:600519"
34
+ },
20
35
  "auth.whoami": {
21
36
  "summary": "Token introspection (CLI/MCP capability discovery)",
22
37
  "description": "Returns the calling token's kind, scopes, audience, app metadata,\nrate_limit, allowed_clients, agent_budget (if kind=agent), api_version,\nfeature_flags. Any valid JWT can call — no specific scope required.\n\nCLI/MCP call this once at startup, cache 5 minutes in-process, and use\nthe response to derive `verbs.available` (intersection of curated verb\nscopes with token scopes) and to populate `echopai doctor` checks.\n\nSee `docs/PLAN_CLI_V2_AGENT_SURFACE.md` §5.1.\n",
23
38
  "example": "echopai auth whoami"
24
39
  },
25
- "backtest.excess-distribution": {
26
- "summary": "Excess-return distribution over a benchmark",
27
- "description": "信号相对基准(沪深 300 / 中证 1000 等)持有期超额收益的直方分布。",
28
- "example": "echopai backtest excess-distribution"
29
- },
30
- "backtest.rolling-win-rate": {
31
- "summary": "Rolling win rate of a signal series",
32
- "description": "信号在滚动窗口(默认 60 个交易日)内的胜率时间序列。",
33
- "example": "echopai backtest rolling-win-rate"
34
- },
35
- "backtest.summary": {
36
- "summary": "Backtest summary metrics for a signal series",
37
- "description": "信号回测汇总:胜率、平均超额收益、Sharpe-like 评分、最大回撤等。",
38
- "example": "echopai backtest summary"
39
- },
40
40
  "bars.daily": {
41
41
  "summary": "Daily OHLC bars for one A-share security",
42
42
  "description": "Daily OHLC bars for one A-share security over a date range. Returns open / high / low / close / volume / turnover per trading day. Requires `bars:30d` (last 30 trading days) or `bars:full` (full history) scope.",
@@ -57,19 +57,69 @@ export const HELP = {
57
57
  "description": "Batch minute OHLC bars for multiple A-share securities. Up to 20 codes\nper call, up to 7 calendar days (≈5 trading days) date range. Single\nClickHouse round-trip; app groups rows by canonical_code.\n\nPartial success envelope same as daily-batch: codes denied by\n`allowed_securities` go to `errors[]`; others to `items[]` with flat\n`bars[]` (each bar carries its own `trade_date` for client grouping).\n\nRequires `bars:30d` or `bars:full` scope.\n",
58
58
  "example": "echopai bars minute-batch --codes ['SSE:600519', 'SZSE:000001']"
59
59
  },
60
+ "concepts.alerts": {
61
+ "summary": "Currently active concept alerts (big_move / limit_up_cluster)",
62
+ "description": "Returns the live `concept_alerts:active` hash. Two rules:\n - big_move: abs(pct_change) > 3%\n - limit_up_cluster: limit_up_count >= 3 AND stock_count >= 5\nSee PLAN_CONCEPT_INDUSTRY_QUOTE §5.5 \"异动检测与推送\".\n",
63
+ "example": "echopai concepts alerts"
64
+ },
65
+ "concepts.alerts-history": {
66
+ "summary": "Concept alerts history (last 24h)",
67
+ "description": "Concept异动 historical events (default last 24h). Filter by rule (big_move / limit_up_cluster) and time window. Used by AI agent / admin review.",
68
+ "example": "echopai concepts alerts-history"
69
+ },
70
+ "concepts.daily-bars": {
71
+ "summary": "Concept index daily bars (chain-linked equal-weight, base 1000)",
72
+ "description": "Returns daily OHLC (concept index points, not stock prices average),\nbreadth fields, and is_backfilled flag. See PLAN §5.4 algorithm.\n",
73
+ "example": "echopai concepts daily-bars VALUE"
74
+ },
75
+ "concepts.list": {
76
+ "summary": "List concepts with live snapshot (6 fields)",
77
+ "description": "Concept list joining CH `v_concept_meta` with Redis snapshot hash\n`stockpulse:concept_snapshots:latest`. Each item includes 6 live\nfields (pct_change / index_value / up/down_count / limit_up_count /\namount) refreshed every ~15s by stockpulse-rs collector.\n\nSource / status / index are computed per PLAN_CONCEPT_INDUSTRY_QUOTE\n§5.4 algorithm (chain-linked equal-weight returns, base = 1000).\n",
78
+ "example": "echopai concepts list"
79
+ },
80
+ "concepts.minute-bars": {
81
+ "summary": "Concept index minute bars (max 7 days)",
82
+ "description": "Concept index minute-level OHLC (chain-linked equal-weight, base = 1000), max 7 days per request. See PLAN_CONCEPT_INDUSTRY_QUOTE §5.4.",
83
+ "example": "echopai concepts minute-bars VALUE"
84
+ },
85
+ "concepts.news": {
86
+ "summary": "Related news matching concept name (ILIKE)",
87
+ "description": "Short-term implementation: ILIKE on news.title + content with the\nconcept name and full_name. Long-term: news AI tagging.\n",
88
+ "example": "echopai concepts news VALUE"
89
+ },
90
+ "concepts.show": {
91
+ "summary": "Concept detail (meta + member securities)",
92
+ "description": "Detail view for one concept: meta (full_name / source / status / approved_at / first_listed_at) plus current member securities with their latest snapshots.",
93
+ "example": "echopai concepts show VALUE"
94
+ },
95
+ "concepts.snapshot": {
96
+ "summary": "Bulk Redis snapshot of all concepts",
97
+ "description": "Returns the full concept_snapshots:latest hash. Use ?codes= to filter.",
98
+ "example": "echopai concepts snapshot"
99
+ },
100
+ "concepts.views": {
101
+ "summary": "Broker views associated with this concept",
102
+ "description": "JOIN concept_views × broker_views (ai_status=done) sorted by published_at desc.",
103
+ "example": "echopai concepts views VALUE"
104
+ },
60
105
  "digest.get": {
61
106
  "summary": "One-shot research digest for a single security (composite)",
62
- "description": "Composite endpoint: in one HTTP call returns views (PRIMARY research),\nresearch-entity performance (quality layer), real-time quote, market\nsentiment context, and supplementary news. Partial-failure tolerant:\neach bucket is independently fetched and per-bucket failures surface\nin `meta.partial_failures[]` rather than poisoning the response. If\nevery sub-bucket fails the endpoint returns 502.\n\nBucket scopes are checked *per bucket* (not at gateway level): a\ntoken with only `views:read` gets the views bucket populated and the\nrest reported as `scope_insufficient` partial failures. This mirrors\nthe CLI fan-out contract exactly so `echopai digest` can either call\nthis endpoint (preferred, single round-trip) or fall back to local\nfan-out without behavior drift.\n\nSee `docs/PLAN_CLI_V2_AGENT_SURFACE.md` §3.3 (digest spec) and §11\nPhase 5.2 (server endpoint).\n",
63
- "example": "echopai digest get VALUE"
107
+ "description": "Composite endpoint: in one HTTP call returns views (PRIMARY research),\nreal-time quote, valuation snapshot (PE/PB/PS/换手率/股息率/量比 14 字段),\nmarket sentiment context, and supplementary news.\nPartial-failure tolerant:\neach bucket is independently fetched and per-bucket failures surface\nin `meta.partial_failures[]` rather than poisoning the response. If\nevery sub-bucket fails the endpoint returns 502.\n\nBucket scopes are checked *per bucket* (not at gateway level): a\ntoken with only `views:read` gets the views bucket populated and the\nrest reported as `scope_insufficient` partial failures. This mirrors\nthe CLI fan-out contract exactly so `echopai digest` can either call\nthis endpoint (preferred, single round-trip) or fall back to local\nfan-out without behavior drift.\n\nSee `docs/PLAN_CLI_V2_AGENT_SURFACE.md` §3.3 (digest spec) and §11\nPhase 5.2 (server endpoint).\n",
108
+ "example": "echopai digest get SSE:600519"
64
109
  },
65
110
  "financials.pit": {
66
111
  "summary": "Point-in-time financial indicators for one A-share at a given date",
67
112
  "description": "基于 TDX 财务数据的 Point-in-time 查询。给定 `code` 和 `date`,返回该\n`trade_date` 当时市场上可见的最新一期财务报告(`announce_date <= date`,\n无公告日时保守延迟 90 天)。专为回测、AI agent、量化策略防未来函数泄漏。\n\n返回字段包括:EPS(基本/扣非/稀释)、BPS、ROE、毛利率、营收/净利润/总资产/\n归母权益等核心 ~25 字段。\n",
68
113
  "example": "echopai financials pit --code SSE:600519 --date 2024-11-01"
69
114
  },
115
+ "financials.quote-snapshot": {
116
+ "summary": "Real-time valuation / share / turnover snapshot for one A-share",
117
+ "description": "一站式估值快照 —— 一次返回 14 个字段,**全部基于 TDX 原始数据 + Sina 实时\n价自算,不依赖 Tushare**:\n\n- 估值: `pe` / `pe_ttm` / `pb` / `ps` / `ps_ttm`\n- 股本(万股): `total_share` / `float_share` / `free_share`\n- 市值(万元): `total_mv` / `circ_mv`\n- 流动性: `turnover_rate` / `turnover_rate_f`(%)/ `volume_ratio`(倍)\n- 分红: `dv_ratio` / `dv_ttm`(%)\n\n计算口径:\n- PE-TTM = 当前总市值 / 近 4 季度滚动净利润(PIT 表 `ni_parent_ttm`)\n- PE = 当前总市值 / 上年报净利润(`ni_parent_last1y`)\n- PB = 当前总市值 / 归母净资产(`equity_parent`,PIT 防穿越)\n- 换手率 = 当日累计成交量 / 流通股本 × 100\n- 量比 = 当日累计 / 近 5 日同时段累计平均(实时模式)\n / 近 5 日全日成交量平均(指定历史日期模式)\n- 股息率 = Σ(去年 / 近12月内派息事件 派现/10) / 现价 × 100\n\n默认 `date` 留空 → 实时(Sina 5s 快照价 + 当日累计成交量);\n给 `date=YYYY-MM-DD` 则按当日 close 取值(用于历史回测 / 校验)。\n\n财报数据走 `security_financial_indicators_pit` PIT 视图:保证 `visible_date`\n≤ trade_date,避免未来函数。\n\n准确性已对照 Tushare `daily_basic` 校验(见 `scripts/validation/validate_quote_snapshot_vs_tushare.py`)。\n",
118
+ "example": "echopai financials quote-snapshot --code SSE:600519 --date 2026-05-13"
119
+ },
70
120
  "financials.reports": {
71
121
  "summary": "Recent financial reports for one A-share security",
72
- "description": "返回该股票最近 N 期财务报告的核心指标(EPS/BPS/ROE/毛利率/营收/净利润/总\n资产/归母权益/经营现金流/总股本 等 ~25 字段)。可按 `kind` 过滤季报/半年报/\n年报。每期 `announce_date` 字段告知何时市场可见,建议结合回测时使用。\n",
122
+ "description": "返回该股票最近 N 期财务报告的核心指标(EPS/BPS/ROE/毛利率/营收/净利润/总\n资产/归母权益/经营现金流/总股本 等 ~25 字段)。可按 `kind` 过滤季报/半年报/\n年报。每期 `announce_date` 字段告知何时市场可见,建议结合回测时使用。\n\n**`kind` 口径说明**:\n\n- `Q1` / `H1` / `Q3` / `annual` —— 四个标准季度末快照(3-31 / 6-30 /\n 9-30 / 12-31),TDX 财务源数据全部落在这四个 report_date。\n- `preliminary` —— **当前数据源结构上不存在**。业绩预告 / 快报 是 indicators\n 行内的字段(`forecast_ni_lower` / `forecast_ni_upper` /\n `express_ni_parent` / `express_revenue` 等),通过 `financials.series`\n metric 参数访问,不是单独的 report_kind 行。`kind=preliminary` 会返\n 空列表 + meta.note。\n",
73
123
  "example": "echopai financials reports --code SSE:600519"
74
124
  },
75
125
  "financials.series": {
@@ -79,18 +129,58 @@ export const HELP = {
79
129
  },
80
130
  "index.daily-bars": {
81
131
  "summary": "Daily OHLC bars for one A-share index",
82
- "description": "指数日线 OHLC。覆盖 v2 表中的指数(上证综指 000001.SH / 深证成指\n399001.SZ / 沪深300 000300.SH / 北证50 899050.BJ / 中证系列 000922.CSI 等)。\n与 `/v1/bars/daily` 同语义,但 index 没有 `turnover_rate` / `paused` 等股票特有字段。\n",
83
- "example": "echopai index daily-bars --code 000001.SH --from 2024-01-01 --to 2024-12-31"
132
+ "description": "指数日线 OHLC。覆盖 v2 表中的指数(上证综指 `SSE:000001` / 深证成指\n`SZSE:399001` / 沪深300 `SSE:000300` / 北证50 `BSE:899050` / 中证系列 `CSI:000922` 等)。\n与 `/v1/bars/daily` 同语义,但 index 没有 `turnover_rate` / `paused` 等股票特有字段。\n",
133
+ "example": "echopai index daily-bars --code SSE:000001 --from 2024-01-01 --to 2024-12-31"
84
134
  },
85
135
  "index.minute-bars": {
86
136
  "summary": "Minute OHLC bars for one A-share index",
87
137
  "description": "指数 1min OHLC。日期范围 ≤ 7 天(与 `/v1/bars/minute-batch` 对齐)。\n返回 `bar_time` / `trade_date` / OHLC / volume / amount / pct_change。\n",
88
- "example": "echopai index minute-bars --code 000001.SH"
138
+ "example": "echopai index minute-bars --code SSE:000001"
89
139
  },
90
140
  "index.snapshot": {
91
141
  "summary": "Real-time snapshot of all Sina-OK A-share indices (172 indices)",
92
- "description": "Returns the latest real-time snapshot for the 172 indices that Sina\nexposes a quote for (SSE / SZSE / BSE — includes 北证50 `899050.BJ`\nand 专精特新 `899601.BJ`). Source is the Redis hash\n`stockpulse:index_snapshots:latest` which the Rust collector refreshes\nevery ~15 seconds during market hours; outside trading hours the last\nintraday snapshot is returned.\n\nUse `codes` to narrow to a subset (canonical format like `000001.SH`).\nOmit to receive all 172.\n\nNote: CSI-series indices (e.g. `000922.CSI`) are not available here —\nSina has no quote feed for them. Daily/minute history for those still\nlives behind `/api/internal/index/{daily-bars,minute-bars-range}`.\n\nRequires `quote:l1`, `quote:l2`, or `quote:delayed` scope.\n",
93
- "example": "echopai index snapshot --codes 000001.SH,399001.SZ,899050.BJ"
142
+ "description": "Returns the latest real-time snapshot for the 172 indices that Sina\nexposes a quote for (SSE / SZSE / BSE — includes 北证50 `BSE:899050`\nand 专精特新 `899601.BJ`). Source is the Redis hash\n`stockpulse:index_snapshots:latest` which the Rust collector refreshes\nevery ~15 seconds during market hours; outside trading hours the last\nintraday snapshot is returned.\n\nUse `codes` to narrow to a subset (canonical format `SSE:000001` (exchange-prefix; legacy `000001.SH` is also accepted but discouraged)).\nOmit to receive all 172.\n\nNote: CSI-series indices (e.g. `CSI:000922`) are not available here —\nSina has no quote feed for them. Daily/minute history for those still\nlives behind `/api/internal/index/{daily-bars,minute-bars-range}`.\n\nRequires `quote:l1`, `quote:l2`, or `quote:delayed` scope.\n",
143
+ "example": "echopai index snapshot --codes SSE:000001,SZSE:399001,BSE:899050"
144
+ },
145
+ "industries.alerts": {
146
+ "summary": "Currently active industry alerts",
147
+ "description": "Currently active industry alerts (big_move / limit_up_cluster). Same rule set as concepts.",
148
+ "example": "echopai industries alerts"
149
+ },
150
+ "industries.daily-bars": {
151
+ "summary": "Industry index daily bars",
152
+ "description": "Industry index daily OHLC (chain-linked equal-weight, base = 1000). Path key format `<sw_industry_code>:<sw_level>` (e.g. `401001:1`).",
153
+ "example": "echopai industries daily-bars 401001:1"
154
+ },
155
+ "industries.list": {
156
+ "summary": "List industries (申万 L1/L2) with live snapshot",
157
+ "description": "Industry index list joining CH `v_industry_meta` with Redis snapshot.\n申万一级 (level=1) ≈ 127 industries, 申万二级 (level=2) ≈ 348.\nChain-linked equal-weight algorithm identical to concepts (PLAN §5.4).\n",
158
+ "example": "echopai industries list"
159
+ },
160
+ "industries.show": {
161
+ "summary": "Industry detail (meta + today members)",
162
+ "description": "Path key format: `<sw_industry_code>:<sw_level>` (e.g. `401001:1`).",
163
+ "example": "echopai industries show 401001:1"
164
+ },
165
+ "industries.snapshot": {
166
+ "summary": "Bulk Redis snapshot of all industries",
167
+ "description": "Bulk Redis snapshot for 申万 industries (level 1 ≈ 127, level 2 ≈ 348). Use `codes` to narrow. Mirrors `/v1/concepts/snapshot` shape.",
168
+ "example": "echopai industries snapshot"
169
+ },
170
+ "limit-up.history": {
171
+ "summary": "A-share limit-up daily trend (last N days)",
172
+ "description": "近 N 个交易日每日涨停数 + 最高连板 + 炸板数。涨停数 / 最高连板来源\n`market_limit_up_pool` (仅 status=limit_up);炸板数来源\n`market_breadth_intraday`(all_a_ex_st 当日最新分钟行)。\n\n响应按 trade_date asc 排序(旧日期在前)。需要 `quote:*` scope。\n",
173
+ "example": "echopai limit-up history"
174
+ },
175
+ "limit-up.pool": {
176
+ "summary": "A-share limit-up pool (per-stock detail) for a given trade date",
177
+ "description": "当日(或指定 `trade_date`)涨停股池逐股明细:首/末次封板时间、最终涨幅、\n封单金额/封单量、炸板次数、连板数、N 日板内统计、一字板标记、当前 status\n(limit_up / broken)、板块分类。\n\n盘前回退规则(与所有行情类页面一致):\n - `< 9:00`:返回 max(trade_date) 的最新一日数据(昨日)\n - `9:00-9:14`:集合竞价前空窗期,items=[] / trade_date=null\n - `>= 9:15`:collector 已写入今日数据\n\n排序:连板数 desc → 板内板数 desc → 封单金额 desc。需要 `quote:*` scope。\n",
178
+ "example": "echopai limit-up pool"
179
+ },
180
+ "limit-up.summary": {
181
+ "summary": "A-share limit-up summary (counts + height ladder) for a given trade date",
182
+ "description": "涨停股池聚合统计:涨停数、炸板数、跌停数、最高连板高度、连板梯队\n`ladder: [{ height, count }, ...]`。\n\n炸板数 / 跌停数 与情绪页同源(`market_breadth_intraday` 当日最新分钟行);\n连板梯队仅统计当前封板 status=limit_up 的个股。\n\n盘前回退规则与 `limit-up/pool` 一致。需要 `quote:*` scope。\n",
183
+ "example": "echopai limit-up summary"
94
184
  },
95
185
  "market.status": {
96
186
  "summary": "Current A-share market session state",
@@ -110,18 +200,13 @@ export const HELP = {
110
200
  "news.list": {
111
201
  "summary": "List news mentioning a specific security",
112
202
  "description": "List news mentioning a specific A-share security, ordered by published_at desc. Requires `news:read` scope.",
113
- "example": "echopai news list --security SSE:600519"
203
+ "example": "echopai news list --security HK:00700"
114
204
  },
115
205
  "news.search": {
116
206
  "summary": "Full-text search recent news",
117
207
  "description": "Full-text search recent news / market briefs. Returns title, published_at, snippet, tagged securities. (Internal collector identifiers — `source`/`source_id`/`source_url` — are NOT exposed publicly; admin tools see them via /v1/admin/*.) Requires `news:read` scope. Note: news fields are user-generated; meta.untrusted_text_fields lists fields that need sanitization before passing to an LLM.",
118
208
  "example": "echopai news search --query 光伏龙头"
119
209
  },
120
- "news.sources": {
121
- "summary": "List canonical news source identifiers",
122
- "description": "返回新闻 source 标识列表(如 `cls`、`jin10`、`twitter`、`wallstreetcn`),可用于 list/search 的 source 过滤。",
123
- "example": "echopai news sources"
124
- },
125
210
  "payment.plans": {
126
211
  "summary": "List subscription plans",
127
212
  "description": "返回订阅计划清单(plan_id + 价格 + 时长 + 描述)。",
@@ -137,16 +222,6 @@ export const HELP = {
137
222
  "description": "Dumps the entire Redis snapshot of A-share real-time quotes in a single\nround-trip. Use for \"全市场扫描\" / agent universe-of-interest discovery\nwhen you don't yet know which codes to query.\n\nFiltering:\n- `exchange=SSE|SZSE|BSE` narrows to one exchange (canonical_code prefix)\n- `app.allowed_securities` is ALWAYS applied; codes outside drop silently\n\nResponse size: ~3 MB unfiltered (~5800 items). CLI users should pair\nwith `--max-bytes` / `--fields` / `--query` from Phase 1.4.\n\n9:00–9:14 集合竞价时段返回空 items + `note` 字段说明。\n\nRequires `quote:l1`, `quote:l2`, or `quote:delayed` scope.\n",
138
223
  "example": "echopai quote scan"
139
224
  },
140
- "research.entity-performance": {
141
- "summary": "Performance of one research entity",
142
- "description": "单个研究实体的细化绩效指标,对照 `/v1/research-entities/performance`。",
143
- "example": "echopai research entity-performance VALUE"
144
- },
145
- "research.entity-performance-list": {
146
- "summary": "Aggregate performance of research entities",
147
- "description": "全体研究实体(analyst / team / institution)的命中率、平均目标价达成率、覆盖股票数等汇总。需要 `research:read` scope。",
148
- "example": "echopai research entity-performance-list"
149
- },
150
225
  "search.semantic": {
151
226
  "summary": "Hybrid semantic search across news + analyst views",
152
227
  "description": "语义 + 模糊泛化搜索。结合 entity 精确匹配(公司代码/分析师)、向量召回(pgvector\n+ DashScope embedding)、trigram 模糊、ILIKE 精确四路召回,RRF 融合后用 reranker\n精排,叠时间衰减 + views 加权(views 主源优先)。\n\n- 搜\"锂电池\"会带出新能源产业链(正极/负极/碳酸锂/宁德时代…)\n- 搜\"芯片\"会带出存储芯片/洁净室/晶圆代工…\n- mode=exact 兼容老 ILIKE 行为,仅在精确关键词命中时返回。\n",
@@ -164,12 +239,12 @@ export const HELP = {
164
239
  },
165
240
  "sentiment.breadth": {
166
241
  "summary": "Intraday breadth time series",
167
- "description": "Intraday breadth time series. Requires `sentiment:read` scope.",
242
+ "description": "Intraday breadth time series for one trading day.\n`trade_date` 缺省 → 今日(盘前 9:00 前返回空 items);显式传 YYYY-MM-DD 可\n拉历史任意交易日(来源 ClickHouse `market_breadth_intraday`,剔除 13:00\n稀疏分钟,单日最多 241 行)。Requires `sentiment:read` scope.\n",
168
243
  "example": "echopai sentiment breadth"
169
244
  },
170
245
  "sentiment.overview": {
171
246
  "summary": "Aggregate market sentiment indicators",
172
- "description": "Aggregate sentiment: limit-up/down counts, breadth, divergence index, top movers. Requires `sentiment:read` scope.",
247
+ "description": "Aggregate sentiment snapshot for one trading day's latest minute:\nlimit-up/down counts, breadth, divergence index, MA / 52w breadth.\n`trade_date` 缺省 → 今日(Redis 实时,盘前 9:00 前返空结构);显式传\nYYYY-MM-DD 拉历史任意日(最后一分钟聚合行,来源 ClickHouse\n`market_breadth_intraday`)。Requires `sentiment:read` scope.\n",
173
248
  "example": "echopai sentiment overview --scope main_board"
174
249
  },
175
250
  "sentiment.pct-distribution": {
@@ -179,19 +254,9 @@ export const HELP = {
179
254
  },
180
255
  "sentiment.turnover": {
181
256
  "summary": "Intraday turnover time series",
182
- "description": "Intraday turnover time series. Requires `sentiment:read` scope.",
257
+ "description": "Intraday turnover time series across one or more trading days.\n`trade_date` 缺省 → 今日(盘前 9:00 前返空 items);显式 YYYY-MM-DD 拉\n历史任意交易日的当日 + 之前 `days-1` 天。Response 含 `current_turnover`\n/ `predicted_total` / `delta_vs_yesterday` headline 字段。Requires\n`sentiment:read` scope.\n",
183
258
  "example": "echopai sentiment turnover"
184
259
  },
185
- "signals.outcome": {
186
- "summary": "Outcome trace for a single signal",
187
- "description": "单条 signal 的细化结果追踪。",
188
- "example": "echopai signals outcome VALUE"
189
- },
190
- "signals.outcomes": {
191
- "summary": "Outcomes of analyst-view-derived signals",
192
- "description": "返回分析师 views 派生信号的实际结果(目标价命中 / 止损 / 到期),含命中时长、最大回撤等。",
193
- "example": "echopai signals outcomes"
194
- },
195
260
  "squawk.audio": {
196
261
  "summary": "Stream squawk TTS audio",
197
262
  "description": "返回 squawk 项的 TTS 音频(MP3)。直接 stream,可作为 `<audio>` src 用。",
@@ -225,6 +290,6 @@ export const HELP = {
225
290
  "views.recent": {
226
291
  "summary": "Recent broker / analyst views",
227
292
  "description": "List recent broker / analyst views (research notes, price targets, ratings). Filter by analyst, institution, or a specific security. Requires `views:read` scope.",
228
- "example": "echopai views recent"
293
+ "example": "echopai views recent --security HK:00700"
229
294
  }
230
295
  };