dsh-plugin-show-me-data 0.1.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.
Files changed (130) hide show
  1. package/LICENSE +27 -0
  2. package/README.md +96 -0
  3. package/cordis.patch.yml +40 -0
  4. package/docs/01-product-effect.md +178 -0
  5. package/docs/02-architecture.md +275 -0
  6. package/docs/03-data-contracts.md +291 -0
  7. package/docs/04-sources.md +342 -0
  8. package/docs/05-ui-spec.md +167 -0
  9. package/docs/06-ai-layer.md +194 -0
  10. package/docs/07-implementation-plan.md +399 -0
  11. package/docs/08-test-plan.md +133 -0
  12. package/docs/09-packaging-install.md +249 -0
  13. package/docs/10-kickoff-prompt.md +94 -0
  14. package/docs/11-decisions.md +203 -0
  15. package/docs/12-runtime-verified.md +115 -0
  16. package/docs/13-acceptance.md +153 -0
  17. package/docs/14-progress.md +150 -0
  18. package/docs/15-publish.md +185 -0
  19. package/lib/app/ai-deterministic.js +327 -0
  20. package/lib/app/ai-validate.js +284 -0
  21. package/lib/app/ai.js +440 -0
  22. package/lib/app/health.js +77 -0
  23. package/lib/app/overview.js +349 -0
  24. package/lib/app/propose-indicator.js +122 -0
  25. package/lib/app/refresh.js +251 -0
  26. package/lib/app/series-view.js +195 -0
  27. package/lib/app/watchlist.js +102 -0
  28. package/lib/client.js +4322 -0
  29. package/lib/core/ai/prompts.js +213 -0
  30. package/lib/core/chart/axis.js +133 -0
  31. package/lib/core/chart/bar.js +58 -0
  32. package/lib/core/chart/candle.js +216 -0
  33. package/lib/core/chart/line.js +186 -0
  34. package/lib/core/chart/scale.js +132 -0
  35. package/lib/core/format.js +143 -0
  36. package/lib/core/indicators/catalog.js +1011 -0
  37. package/lib/core/indicators/resolve.js +196 -0
  38. package/lib/core/insight/digest.js +250 -0
  39. package/lib/core/insight/rank.js +115 -0
  40. package/lib/core/insight/related.js +90 -0
  41. package/lib/core/insight/rules.js +417 -0
  42. package/lib/core/stats/derive.js +123 -0
  43. package/lib/core/stats/series.js +465 -0
  44. package/lib/core/time/range.js +242 -0
  45. package/lib/core/types.js +478 -0
  46. package/lib/host/ai/discussion.js +559 -0
  47. package/lib/host/ai/dsh-llm-gateway.js +333 -0
  48. package/lib/host/config.js +194 -0
  49. package/lib/host/http/respond.js +165 -0
  50. package/lib/host/http/routes.js +689 -0
  51. package/lib/host/index.js +293 -0
  52. package/lib/host/infra/fs-repos.js +179 -0
  53. package/lib/host/infra/memory-fallback.js +64 -0
  54. package/lib/host/tools/define-tool.js +295 -0
  55. package/lib/host/tools/register.js +431 -0
  56. package/lib/host.js +7 -0
  57. package/lib/ports/clock.js +57 -0
  58. package/lib/ports/snapshot-repo.js +48 -0
  59. package/lib/sources/eastmoney-macro.js +197 -0
  60. package/lib/sources/eastmoney-quote.js +201 -0
  61. package/lib/sources/ecb.js +179 -0
  62. package/lib/sources/fred.js +207 -0
  63. package/lib/sources/http.js +136 -0
  64. package/lib/sources/ohlc.js +36 -0
  65. package/lib/sources/quote-cascade.js +177 -0
  66. package/lib/sources/registry.js +153 -0
  67. package/lib/sources/sina-cn.js +197 -0
  68. package/lib/sources/sina-us.js +187 -0
  69. package/lib/sources/tencent.js +158 -0
  70. package/lib/sources/us-treasury-rates.js +275 -0
  71. package/lib/sources/us-treasury.js +196 -0
  72. package/lib/sources/worldbank.js +170 -0
  73. package/package.json +69 -0
  74. package/src/app/ai-deterministic.js +327 -0
  75. package/src/app/ai-validate.js +284 -0
  76. package/src/app/ai.js +440 -0
  77. package/src/app/health.js +77 -0
  78. package/src/app/overview.js +349 -0
  79. package/src/app/propose-indicator.js +122 -0
  80. package/src/app/refresh.js +251 -0
  81. package/src/app/series-view.js +195 -0
  82. package/src/app/watchlist.js +102 -0
  83. package/src/client/api.js +323 -0
  84. package/src/client/components.js +1877 -0
  85. package/src/client/copy.js +368 -0
  86. package/src/client/index.js +169 -0
  87. package/src/client/store.js +219 -0
  88. package/src/core/ai/prompts.js +213 -0
  89. package/src/core/chart/axis.js +133 -0
  90. package/src/core/chart/bar.js +58 -0
  91. package/src/core/chart/candle.js +216 -0
  92. package/src/core/chart/line.js +186 -0
  93. package/src/core/chart/scale.js +132 -0
  94. package/src/core/format.js +143 -0
  95. package/src/core/indicators/catalog.js +1011 -0
  96. package/src/core/indicators/resolve.js +196 -0
  97. package/src/core/insight/digest.js +250 -0
  98. package/src/core/insight/rank.js +115 -0
  99. package/src/core/insight/related.js +90 -0
  100. package/src/core/insight/rules.js +417 -0
  101. package/src/core/stats/derive.js +123 -0
  102. package/src/core/stats/series.js +465 -0
  103. package/src/core/time/range.js +242 -0
  104. package/src/core/types.js +478 -0
  105. package/src/host/ai/discussion.js +559 -0
  106. package/src/host/ai/dsh-llm-gateway.js +333 -0
  107. package/src/host/config.js +194 -0
  108. package/src/host/http/respond.js +165 -0
  109. package/src/host/http/routes.js +689 -0
  110. package/src/host/index.js +293 -0
  111. package/src/host/infra/fs-repos.js +179 -0
  112. package/src/host/infra/memory-fallback.js +64 -0
  113. package/src/host/tools/define-tool.js +295 -0
  114. package/src/host/tools/register.js +431 -0
  115. package/src/ports/clock.js +57 -0
  116. package/src/ports/snapshot-repo.js +48 -0
  117. package/src/sources/eastmoney-macro.js +197 -0
  118. package/src/sources/eastmoney-quote.js +201 -0
  119. package/src/sources/ecb.js +179 -0
  120. package/src/sources/fred.js +207 -0
  121. package/src/sources/http.js +136 -0
  122. package/src/sources/ohlc.js +36 -0
  123. package/src/sources/quote-cascade.js +177 -0
  124. package/src/sources/registry.js +153 -0
  125. package/src/sources/sina-cn.js +197 -0
  126. package/src/sources/sina-us.js +187 -0
  127. package/src/sources/tencent.js +158 -0
  128. package/src/sources/us-treasury-rates.js +275 -0
  129. package/src/sources/us-treasury.js +196 -0
  130. package/src/sources/worldbank.js +170 -0
@@ -0,0 +1,1011 @@
1
+ /**
2
+ * The seed indicator catalog — **data, not logic** (docs/02 §5.1, docs/03 §3).
3
+ *
4
+ * Adding an indicator is adding one object here (plus a recorded fixture for its
5
+ * series): cards, charts, statistics, insight rules, the AI context and the
6
+ * conversational lookup all pick it up with no code change. That promise is
7
+ * enforced by 'test/core/indicators-catalog.test.js'.
8
+ *
9
+ * Every 'seriesRef' below was verified against the live source while recording
10
+ * 'test/fixtures/**'; anything that could not be verified is listed in
11
+ * {@link UNSUPPORTED} with its investigation result instead of a guessed id.
12
+ *
13
+ * @module core/indicators/catalog
14
+ */
15
+
16
+ /**
17
+ * @typedef {Object} IndicatorDef
18
+ * @property {string} id
19
+ * @property {'US'|'CN'|'GLOBAL'|'CUSTOM'} group
20
+ * @property {{ zh: string, en: string }} label
21
+ * @property {string} unit
22
+ * @property {'daily'|'weekly'|'monthly'|'quarterly'|'annual'} freq
23
+ * @property {'SA'|'NSA'|'NA'} seasonal
24
+ * @property {1|2|3|4|5} importance
25
+ * @property {{ adapter: string, seriesRef: string, params?: object }} [source]
26
+ * @property {{ op: 'spread'|'ratio'|'avg', operands: string[] }} [derive]
27
+ * @property {{ transform: string, window?: number, decimals?: number, polarity?: 'up-is-good'|'down-is-good'|'neutral' }} display
28
+ * @property {{ zh: string, en?: string }} [notes]
29
+ * @property {string[]} [tags]
30
+ * @property {string[]} [aliases]
31
+ */
32
+
33
+ /** United States — mostly FRED, which needs no API key (docs/04 §1). */
34
+ const US = [
35
+ {
36
+ id: 'us.cpi.yoy',
37
+ group: 'US',
38
+ label: { zh: '美国 CPI 同比', en: 'US CPI YoY' },
39
+ unit: '%',
40
+ freq: 'monthly',
41
+ seasonal: 'SA',
42
+ importance: 5,
43
+ source: { adapter: 'fred', seriesRef: 'CPIAUCSL' },
44
+ display: { transform: 'yoy', decimals: 1, polarity: 'down-is-good' },
45
+ notes: { zh: 'CPI 同比由指数序列现算:FRED 的 CSUS 系列只给指数,页面上的同比是它自己算的。' },
46
+ tags: ['inflation', 'us', 'policy'],
47
+ aliases: ['CPI', '通胀', '消费者物价', 'inflation'],
48
+ },
49
+ {
50
+ id: 'us.cpi',
51
+ group: 'US',
52
+ label: { zh: '美国 CPI 指数', en: 'US CPI Index' },
53
+ unit: '指数',
54
+ freq: 'monthly',
55
+ seasonal: 'SA',
56
+ importance: 2,
57
+ source: { adapter: 'fred', seriesRef: 'CPIAUCSL' },
58
+ display: { transform: 'raw', decimals: 2, polarity: 'neutral' },
59
+ notes: { zh: '1982–84 = 100。同比的分子分母都来自这条水平序列。' },
60
+ tags: ['inflation', 'us'],
61
+ aliases: ['CPI index', '物价指数'],
62
+ },
63
+ {
64
+ id: 'us.core.cpi.yoy',
65
+ group: 'US',
66
+ label: { zh: '美国核心 CPI 同比', en: 'US Core CPI YoY' },
67
+ unit: '%',
68
+ freq: 'monthly',
69
+ seasonal: 'SA',
70
+ importance: 5,
71
+ source: { adapter: 'fred', seriesRef: 'CPILFESL' },
72
+ display: { transform: 'yoy', decimals: 1, polarity: 'down-is-good' },
73
+ notes: { zh: '剔除食品与能源,是美联储更看重的通胀口径。' },
74
+ tags: ['inflation', 'us', 'policy'],
75
+ aliases: ['核心CPI', 'core CPI', 'core inflation'],
76
+ },
77
+ {
78
+ id: 'us.unrate',
79
+ group: 'US',
80
+ label: { zh: '美国失业率', en: 'US Unemployment Rate' },
81
+ unit: '%',
82
+ freq: 'monthly',
83
+ seasonal: 'SA',
84
+ importance: 5,
85
+ source: { adapter: 'fred', seriesRef: 'UNRATE' },
86
+ display: { transform: 'raw', decimals: 1, polarity: 'down-is-good' },
87
+ notes: { zh: 'U-3 口径(16 岁以上、积极求职者)。上升代表就业市场转弱。' },
88
+ tags: ['labor', 'us'],
89
+ aliases: ['失业率', 'unemployment', 'jobless rate'],
90
+ },
91
+ {
92
+ id: 'us.payrolls.change',
93
+ group: 'US',
94
+ label: { zh: '美国非农就业(月增)', en: 'US Nonfarm Payrolls (MoM)' },
95
+ unit: '万人',
96
+ freq: 'monthly',
97
+ seasonal: 'SA',
98
+ importance: 5,
99
+ source: { adapter: 'fred', seriesRef: 'PAYEMS' },
100
+ display: { transform: 'diff', window: 1, decimals: 1, polarity: 'up-is-good' },
101
+ notes: { zh: '由水平序列(千人)差分得到月增,单位换算为万人;发布时会同时修正前两月。' },
102
+ tags: ['labor', 'us'],
103
+ aliases: ['非农', 'nonfarm', 'payrolls', '就业'],
104
+ },
105
+ {
106
+ id: 'us.payrolls.level',
107
+ group: 'US',
108
+ label: { zh: '美国非农就业(总人数)', en: 'US Nonfarm Payrolls (Level)' },
109
+ unit: '万人',
110
+ freq: 'monthly',
111
+ seasonal: 'SA',
112
+ importance: 2,
113
+ source: { adapter: 'fred', seriesRef: 'PAYEMS' },
114
+ display: { transform: 'raw', decimals: 0, polarity: 'up-is-good' },
115
+ tags: ['labor', 'us'],
116
+ aliases: ['非农总数', 'payrolls level'],
117
+ },
118
+ {
119
+ id: 'us.payrolls.3m.avg',
120
+ group: 'US',
121
+ label: { zh: '美国非农 3 月均值', en: 'US Payrolls 3-Month Average' },
122
+ unit: '万人',
123
+ freq: 'monthly',
124
+ seasonal: 'SA',
125
+ importance: 3,
126
+ source: { adapter: 'fred', seriesRef: 'PAYEMS' },
127
+ display: { transform: 'diff', movingAvg: 3, decimals: 1, polarity: 'up-is-good' },
128
+ notes: { zh: '平滑单月波动;由月增序列的移动平均得到(见 core/stats/series.movingAverage)。' },
129
+ tags: ['labor', 'us'],
130
+ aliases: ['非农三月均值', 'payrolls 3m'],
131
+ },
132
+ {
133
+ id: 'us.fedfunds.daily',
134
+ group: 'US',
135
+ label: { zh: '联邦基金利率(日度)', en: 'Effective Fed Funds Rate (Daily)' },
136
+ unit: '%',
137
+ freq: 'daily',
138
+ seasonal: 'NA',
139
+ importance: 4,
140
+ source: { adapter: 'fred', seriesRef: 'DFF' },
141
+ display: { transform: 'raw', decimals: 2, polarity: 'down-is-good' },
142
+ notes: { zh: '有效联邦基金利率(EFFR),政策利率的实际成交口径。' },
143
+ tags: ['rates', 'us', 'policy'],
144
+ aliases: ['联邦基金利率', 'fed funds', 'EFFR', 'policy rate'],
145
+ },
146
+ {
147
+ id: 'us.fedfunds.monthly',
148
+ group: 'US',
149
+ label: { zh: '联邦基金利率(月均)', en: 'Effective Fed Funds Rate (Monthly)' },
150
+ unit: '%',
151
+ freq: 'monthly',
152
+ seasonal: 'NA',
153
+ importance: 3,
154
+ source: { adapter: 'fred', seriesRef: 'FEDFUNDS' },
155
+ display: { transform: 'raw', decimals: 2, polarity: 'down-is-good' },
156
+ tags: ['rates', 'us'],
157
+ aliases: ['月均联邦基金利率'],
158
+ },
159
+ {
160
+ id: 'us.dgs10',
161
+ group: 'US',
162
+ label: { zh: '美国 10Y 国债收益率', en: 'US 10-Year Treasury Yield' },
163
+ unit: '%',
164
+ freq: 'daily',
165
+ seasonal: 'NA',
166
+ importance: 5,
167
+ source: { adapter: 'us-treasury-rates', seriesRef: 'daily_treasury_yield_curve', params: { tenor: '10y' } },
168
+ display: { transform: 'raw', decimals: 2, polarity: 'neutral' },
169
+ notes: { zh: '恒定到期日(constant maturity)收益率,全球资产定价的锚。休市日上游返回 "."。' },
170
+ tags: ['rates', 'bond', 'us'],
171
+ aliases: ['10年期美债', '美债收益率', '10 year treasury', 'DGS10'],
172
+ },
173
+ {
174
+ id: 'us.dgs2',
175
+ group: 'US',
176
+ label: { zh: '美国 2Y 国债收益率', en: 'US 2-Year Treasury Yield' },
177
+ unit: '%',
178
+ freq: 'daily',
179
+ seasonal: 'NA',
180
+ importance: 4,
181
+ source: { adapter: 'us-treasury-rates', seriesRef: 'daily_treasury_yield_curve', params: { tenor: '2y' } },
182
+ display: { transform: 'raw', decimals: 2, polarity: 'neutral' },
183
+ notes: { zh: '对政策利率预期最敏感的一段。' },
184
+ tags: ['rates', 'bond', 'us'],
185
+ aliases: ['2年期美债', 'two year treasury'],
186
+ },
187
+ {
188
+ id: 'us.dgs3m',
189
+ group: 'US',
190
+ label: { zh: '美国 3M 国债收益率', en: 'US 3-Month Treasury Yield' },
191
+ unit: '%',
192
+ freq: 'daily',
193
+ seasonal: 'NA',
194
+ importance: 3,
195
+ source: { adapter: 'us-treasury-rates', seriesRef: 'daily_treasury_yield_curve', params: { tenor: '3m' } },
196
+ display: { transform: 'raw', decimals: 2, polarity: 'neutral' },
197
+ tags: ['rates', 'bond', 'us'],
198
+ aliases: ['3月期美债'],
199
+ },
200
+ {
201
+ id: 'us.curve.10y2y',
202
+ group: 'US',
203
+ label: { zh: '10Y−2Y 利差', en: '10Y−2Y Treasury Spread' },
204
+ unit: 'pp',
205
+ freq: 'daily',
206
+ seasonal: 'NA',
207
+ importance: 5,
208
+ source: { adapter: 'fred', seriesRef: 'T10Y2Y' },
209
+ display: { transform: 'raw', decimals: 2, polarity: 'up-is-good' },
210
+ notes: { zh: '负值 = 收益率曲线倒挂,历史上是衰退的领先信号之一;转正(解除倒挂)同样值得关注。' },
211
+ tags: ['rates', 'bond', 'us', 'signal'],
212
+ aliases: ['利差', '收益率曲线', '倒挂', 'yield curve', 'inversion'],
213
+ },
214
+ {
215
+ id: 'us.curve.10y3m',
216
+ group: 'US',
217
+ label: { zh: '10Y−3M 利差', en: '10Y−3M Treasury Spread' },
218
+ unit: 'pp',
219
+ freq: 'daily',
220
+ seasonal: 'NA',
221
+ importance: 3,
222
+ derive: { op: 'spread', operands: ['us.dgs10', 'us.dgs3m'] },
223
+ display: { transform: 'raw', decimals: 2, polarity: 'up-is-good' },
224
+ notes: { zh: '现算利差(10Y − 3M),与 FRED 的 T10Y3M 口径一致但由我们保证时间对齐。' },
225
+ tags: ['rates', 'bond', 'us'],
226
+ aliases: ['10y3m', '短端利差'],
227
+ },
228
+ {
229
+ id: 'us.breakeven10y',
230
+ group: 'US',
231
+ label: { zh: '美国 10Y 通胀预期', en: 'US 10-Year Breakeven Inflation' },
232
+ unit: '%',
233
+ freq: 'daily',
234
+ seasonal: 'NA',
235
+ importance: 4,
236
+ source: { adapter: 'fred', seriesRef: 'T10YIE' },
237
+ display: { transform: 'raw', decimals: 2, polarity: 'neutral' },
238
+ notes: { zh: '10Y 名义收益率 − 10Y TIPS 实际收益率,市场隐含的通胀补偿。' },
239
+ tags: ['inflation', 'rates', 'us'],
240
+ aliases: ['通胀预期', 'breakeven', 'T10YIE'],
241
+ },
242
+ {
243
+ id: 'us.real10y',
244
+ group: 'US',
245
+ label: { zh: '美国 10Y 实际利率', en: 'US 10-Year Real Rate' },
246
+ unit: '%',
247
+ freq: 'daily',
248
+ seasonal: 'NA',
249
+ importance: 4,
250
+ derive: { op: 'spread', operands: ['us.dgs10', 'us.breakeven10y'] },
251
+ display: { transform: 'raw', decimals: 2, polarity: 'down-is-good' },
252
+ notes: { zh: '名义 10Y 减通胀预期,衡量真实融资成本。' },
253
+ tags: ['rates', 'us'],
254
+ aliases: ['实际利率', 'real rate', 'real yield'],
255
+ },
256
+ {
257
+ id: 'us.gdp.real',
258
+ group: 'US',
259
+ label: { zh: '美国实际 GDP', en: 'US Real GDP' },
260
+ unit: '十亿美元',
261
+ freq: 'quarterly',
262
+ seasonal: 'SA',
263
+ importance: 4,
264
+ source: { adapter: 'fred', seriesRef: 'GDPC1' },
265
+ display: { transform: 'raw', decimals: 0, polarity: 'up-is-good' },
266
+ notes: { zh: '链式 2017 美元年化季率水平值;同比请用 yoy 变换。' },
267
+ tags: ['growth', 'us'],
268
+ aliases: ['GDP', '经济增长', 'real gdp'],
269
+ },
270
+ {
271
+ id: 'us.gdp.yoy',
272
+ group: 'US',
273
+ label: { zh: '美国实际 GDP 同比', en: 'US Real GDP YoY' },
274
+ unit: '%',
275
+ freq: 'quarterly',
276
+ seasonal: 'SA',
277
+ importance: 5,
278
+ source: { adapter: 'fred', seriesRef: 'GDPC1' },
279
+ display: { transform: 'yoy', decimals: 1, polarity: 'up-is-good' },
280
+ tags: ['growth', 'us'],
281
+ aliases: ['GDP同比', 'gdp growth'],
282
+ },
283
+ {
284
+ id: 'us.consumer.sentiment',
285
+ group: 'US',
286
+ label: { zh: '密歇根消费者信心', en: 'US Consumer Sentiment (UMich)' },
287
+ unit: '指数',
288
+ freq: 'monthly',
289
+ seasonal: 'NSA',
290
+ importance: 3,
291
+ source: { adapter: 'fred', seriesRef: 'UMCSENT' },
292
+ display: { transform: 'raw', decimals: 1, polarity: 'up-is-good' },
293
+ tags: ['sentiment', 'us'],
294
+ aliases: ['消费者信心', 'umich', 'sentiment'],
295
+ },
296
+ {
297
+ id: 'us.retail.sales',
298
+ group: 'US',
299
+ label: { zh: '美国零售销售', en: 'US Retail Sales' },
300
+ unit: '百万美元',
301
+ freq: 'monthly',
302
+ seasonal: 'SA',
303
+ importance: 3,
304
+ source: { adapter: 'fred', seriesRef: 'RSAFS' },
305
+ display: { transform: 'raw', decimals: 0, polarity: 'up-is-good' },
306
+ tags: ['consumption', 'us'],
307
+ aliases: ['零售销售', 'retail sales'],
308
+ },
309
+ {
310
+ id: 'us.mortgage30',
311
+ group: 'US',
312
+ label: { zh: '美国 30 年期房贷利率', en: 'US 30-Year Mortgage Rate' },
313
+ unit: '%',
314
+ freq: 'weekly',
315
+ seasonal: 'NA',
316
+ importance: 3,
317
+ source: { adapter: 'fred', seriesRef: 'MORTGAGE30US' },
318
+ display: { transform: 'raw', decimals: 2, polarity: 'down-is-good' },
319
+ notes: { zh: 'Freddie Mac 周频调查均值,周四发布。' },
320
+ tags: ['rates', 'housing', 'us'],
321
+ aliases: ['房贷利率', 'mortgage', '30年房贷'],
322
+ },
323
+ {
324
+ id: 'us.dollar.index',
325
+ group: 'US',
326
+ label: { zh: '美元指数(广义)', en: 'US Dollar Index (Broad)' },
327
+ unit: '指数',
328
+ freq: 'daily',
329
+ seasonal: 'NA',
330
+ importance: 3,
331
+ source: { adapter: 'fred', seriesRef: 'DTWEXBGS' },
332
+ display: { transform: 'raw', decimals: 2, polarity: 'neutral' },
333
+ notes: { zh: '美联储广义贸易加权美元指数(2006-01 = 100),不是 ICE 的 DXY。' },
334
+ tags: ['fx', 'us'],
335
+ aliases: ['美元指数', 'dollar index', 'DXY'],
336
+ },
337
+ {
338
+ id: 'us.oil.wti',
339
+ group: 'US',
340
+ label: { zh: 'WTI 原油', en: 'WTI Crude Oil' },
341
+ unit: '美元/桶',
342
+ freq: 'daily',
343
+ seasonal: 'NA',
344
+ importance: 4,
345
+ source: { adapter: 'fred', seriesRef: 'DCOILWTICO' },
346
+ display: { transform: 'raw', decimals: 2, polarity: 'neutral' },
347
+ notes: { zh: 'Cushing WTI 现货价;上游偶有 "." 缺失,函数一律跳过。' },
348
+ tags: ['commodity', 'energy'],
349
+ aliases: ['原油', 'WTI', '油价', 'oil'],
350
+ },
351
+ {
352
+ id: 'us.idx.spx',
353
+ group: 'US',
354
+ label: { zh: '标普 500', en: 'S&P 500' },
355
+ unit: '点',
356
+ freq: 'daily',
357
+ seasonal: 'NA',
358
+ importance: 5,
359
+ source: { adapter: 'sina-us', seriesRef: '.INX' },
360
+ display: { transform: 'raw', decimals: 2, polarity: 'up-is-good' },
361
+ tags: ['equity', 'us'],
362
+ aliases: ['标普', 'S&P', 'sp500'],
363
+ },
364
+ {
365
+ id: 'us.idx.dji',
366
+ group: 'US',
367
+ label: { zh: '道琼斯工业指数', en: 'Dow Jones Industrial Average' },
368
+ unit: '点',
369
+ freq: 'daily',
370
+ seasonal: 'NA',
371
+ importance: 4,
372
+ source: { adapter: 'sina-us', seriesRef: '.DJI' },
373
+ display: { transform: 'raw', decimals: 2, polarity: 'up-is-good' },
374
+ tags: ['equity', 'us'],
375
+ aliases: ['道指', '道琼斯', 'dow'],
376
+ },
377
+ {
378
+ id: 'us.idx.ndx',
379
+ group: 'US',
380
+ label: { zh: '纳斯达克 100', en: 'Nasdaq 100' },
381
+ unit: '点',
382
+ freq: 'daily',
383
+ seasonal: 'NA',
384
+ importance: 4,
385
+ source: { adapter: 'sina-us', seriesRef: '.NDX' },
386
+ display: { transform: 'raw', decimals: 2, polarity: 'up-is-good' },
387
+ tags: ['equity', 'us'],
388
+ aliases: ['纳指', '纳斯达克', 'nasdaq'],
389
+ },
390
+ ]
391
+
392
+ /** 中国 — 东方财富行情 + 数据中心(docs/04 §2, §3)。 */
393
+ const CN = [
394
+ {
395
+ id: 'cn.cpi.yoy',
396
+ group: 'CN',
397
+ label: { zh: '中国 CPI 同比', en: 'China CPI YoY' },
398
+ unit: '%',
399
+ freq: 'monthly',
400
+ seasonal: 'NSA',
401
+ importance: 5,
402
+ source: { adapter: 'eastmoney-macro', seriesRef: 'RPT_ECONOMY_CPI', params: { column: 'NATIONAL_SAME' } },
403
+ display: { transform: 'raw', decimals: 1, polarity: 'neutral' },
404
+ notes: { zh: '国家统计局口径同比,取自 RPT_ECONOMY_CPI 的 NATIONAL_SAME 列(上游本身就是百分比)。' },
405
+ tags: ['inflation', 'cn'],
406
+ aliases: ['中国CPI', 'CPI同比', '通胀'],
407
+ },
408
+ {
409
+ id: 'cn.cpi.mom',
410
+ group: 'CN',
411
+ label: { zh: '中国 CPI 环比', en: 'China CPI MoM' },
412
+ unit: '%',
413
+ freq: 'monthly',
414
+ seasonal: 'NSA',
415
+ importance: 3,
416
+ source: { adapter: 'eastmoney-macro', seriesRef: 'RPT_ECONOMY_CPI', params: { column: 'NATIONAL_SEQUENTIAL' } },
417
+ display: { transform: 'raw', decimals: 1, polarity: 'neutral' },
418
+ notes: { zh: 'NATIONAL_SEQUENTIAL 是环比(%),不是累计同比。' },
419
+ tags: ['inflation', 'cn'],
420
+ aliases: ['CPI环比', '环比'],
421
+ },
422
+ {
423
+ id: 'cn.ppi.yoy',
424
+ group: 'CN',
425
+ label: { zh: '中国 PPI 同比', en: 'China PPI YoY' },
426
+ unit: '%',
427
+ freq: 'monthly',
428
+ seasonal: 'NSA',
429
+ importance: 4,
430
+ source: { adapter: 'eastmoney-macro', seriesRef: 'RPT_ECONOMY_PPI', params: { column: 'BASE_SAME' } },
431
+ display: { transform: 'raw', decimals: 1, polarity: 'neutral' },
432
+ notes: { zh: 'PPI 同比在 BASE_SAME 列(BASE 是指数列)。' },
433
+ tags: ['inflation', 'cn', 'industry'],
434
+ aliases: ['PPI', '生产者价格'],
435
+ },
436
+ {
437
+ id: 'cn.pmi.mfg',
438
+ group: 'CN',
439
+ label: { zh: '中国制造业 PMI', en: 'China Manufacturing PMI' },
440
+ unit: '指数',
441
+ freq: 'monthly',
442
+ seasonal: 'SA',
443
+ importance: 5,
444
+ source: { adapter: 'eastmoney-macro', seriesRef: 'RPT_ECONOMY_PMI', params: { column: 'MAKE_INDEX' } },
445
+ display: { transform: 'raw', decimals: 1, polarity: 'up-is-good' },
446
+ notes: { zh: '50 是荣枯线。MAKE_SAME 是「较上月变化(pp)」,不是同比。' },
447
+ tags: ['growth', 'cn', 'industry'],
448
+ aliases: ['制造业PMI', 'PMI', 'pmi'],
449
+ },
450
+ {
451
+ id: 'cn.pmi.nonmfg',
452
+ group: 'CN',
453
+ label: { zh: '中国非制造业 PMI', en: 'China Non-Manufacturing PMI' },
454
+ unit: '指数',
455
+ freq: 'monthly',
456
+ seasonal: 'SA',
457
+ importance: 3,
458
+ source: { adapter: 'eastmoney-macro', seriesRef: 'RPT_ECONOMY_PMI', params: { column: 'NMAKE_INDEX' } },
459
+ display: { transform: 'raw', decimals: 1, polarity: 'up-is-good' },
460
+ tags: ['growth', 'cn', 'services'],
461
+ aliases: ['非制造业PMI', '服务业PMI'],
462
+ },
463
+ {
464
+ id: 'cn.gdp.yoy',
465
+ group: 'CN',
466
+ label: { zh: '中国 GDP 同比', en: 'China GDP YoY' },
467
+ unit: '%',
468
+ freq: 'quarterly',
469
+ seasonal: 'NSA',
470
+ importance: 5,
471
+ source: { adapter: 'eastmoney-macro', seriesRef: 'RPT_ECONOMY_GDP', params: { column: 'SUM_SAME' } },
472
+ display: { transform: 'raw', decimals: 1, polarity: 'up-is-good' },
473
+ notes: { zh: 'SUM_SAME 是累计同比口径(国家统计局按累计发布)。' },
474
+ tags: ['growth', 'cn'],
475
+ aliases: ['中国GDP', 'GDP增速'],
476
+ },
477
+ {
478
+ id: 'cn.gdp.level',
479
+ group: 'CN',
480
+ label: { zh: '中国 GDP 现价累计', en: 'China GDP (Cumulative, Current Prices)' },
481
+ unit: '亿元',
482
+ freq: 'quarterly',
483
+ seasonal: 'NSA',
484
+ importance: 3,
485
+ source: { adapter: 'eastmoney-macro', seriesRef: 'RPT_ECONOMY_GDP', params: { column: 'DOMESTICL_PRODUCT_BASE' } },
486
+ display: { transform: 'raw', decimals: 0, polarity: 'up-is-good' },
487
+ notes: { zh: '上游列名拼写为 DOMESTICL_PRODUCT_BASE(缺一个 S),照抄不纠正。' },
488
+ tags: ['growth', 'cn'],
489
+ aliases: ['GDP总量', 'gdp level'],
490
+ },
491
+ {
492
+ id: 'cn.m2.yoy',
493
+ group: 'CN',
494
+ label: { zh: '中国 M2 同比', en: 'China M2 YoY' },
495
+ unit: '%',
496
+ freq: 'monthly',
497
+ seasonal: 'NSA',
498
+ importance: 5,
499
+ source: { adapter: 'eastmoney-macro', seriesRef: 'RPT_ECONOMY_CURRENCY_SUPPLY', params: { column: 'BASIC_CURRENCY_SAME' } },
500
+ display: { transform: 'raw', decimals: 1, polarity: 'neutral' },
501
+ notes: {
502
+ zh: '口径陷阱:在 RPT_ECONOMY_CURRENCY_SUPPLY 里 BASIC_CURRENCY 才是 M2(约 355 万亿),CURRENCY 是 M1(约 115 万亿)。列名与直觉相反。',
503
+ },
504
+ tags: ['money', 'cn'],
505
+ aliases: ['M2', '货币供应', 'm2 growth'],
506
+ },
507
+ {
508
+ id: 'cn.m1.yoy',
509
+ group: 'CN',
510
+ label: { zh: '中国 M1 同比', en: 'China M1 YoY' },
511
+ unit: '%',
512
+ freq: 'monthly',
513
+ seasonal: 'NSA',
514
+ importance: 4,
515
+ source: { adapter: 'eastmoney-macro', seriesRef: 'RPT_ECONOMY_CURRENCY_SUPPLY', params: { column: 'CURRENCY_SAME' } },
516
+ display: { transform: 'raw', decimals: 1, polarity: 'neutral' },
517
+ notes: { zh: 'CURRENCY_SAME 是 M1 同比;M1−M2 剪刀差常被用来观察资金活化程度。' },
518
+ tags: ['money', 'cn'],
519
+ aliases: ['M1', 'm1 growth'],
520
+ },
521
+ {
522
+ id: 'cn.m2.m1.spread',
523
+ group: 'CN',
524
+ label: { zh: '中国 M2−M1 剪刀差', en: 'China M2−M1 Growth Spread' },
525
+ unit: 'pp',
526
+ freq: 'monthly',
527
+ seasonal: 'NSA',
528
+ importance: 4,
529
+ derive: { op: 'spread', operands: ['cn.m2.yoy', 'cn.m1.yoy'] },
530
+ display: { transform: 'raw', decimals: 1, polarity: 'down-is-good' },
531
+ notes: { zh: '剪刀差扩大代表资金淤积在定期存款,活化程度下降。' },
532
+ tags: ['money', 'cn', 'signal'],
533
+ aliases: ['剪刀差', 'm2 m1'],
534
+ },
535
+ {
536
+ id: 'cn.idx.sse',
537
+ group: 'CN',
538
+ label: { zh: '上证指数', en: 'Shanghai Composite' },
539
+ unit: '点',
540
+ freq: 'daily',
541
+ seasonal: 'NA',
542
+ importance: 5,
543
+ source: { adapter: 'quote', seriesRef: 'sse' },
544
+ display: { transform: 'raw', decimals: 2, polarity: 'up-is-good' },
545
+ tags: ['equity', 'cn'],
546
+ aliases: ['上证', '大盘', 'shanghai composite'],
547
+ },
548
+ {
549
+ id: 'cn.idx.szse',
550
+ group: 'CN',
551
+ label: { zh: '深证成指', en: 'Shenzhen Component' },
552
+ unit: '点',
553
+ freq: 'daily',
554
+ seasonal: 'NA',
555
+ importance: 4,
556
+ source: { adapter: 'quote', seriesRef: 'szse' },
557
+ display: { transform: 'raw', decimals: 2, polarity: 'up-is-good' },
558
+ tags: ['equity', 'cn'],
559
+ aliases: ['深成指', '深证', 'shenzhen'],
560
+ },
561
+ {
562
+ id: 'cn.idx.csi300',
563
+ group: 'CN',
564
+ label: { zh: '沪深 300', en: 'CSI 300' },
565
+ unit: '点',
566
+ freq: 'daily',
567
+ seasonal: 'NA',
568
+ importance: 5,
569
+ source: { adapter: 'quote', seriesRef: 'csi300' },
570
+ display: { transform: 'raw', decimals: 2, polarity: 'up-is-good' },
571
+ notes: { zh: '覆盖沪深两市大盘蓝筹,是 A 股宽基基准。' },
572
+ tags: ['equity', 'cn'],
573
+ aliases: ['沪深300', 'csi300', 'hs300'],
574
+ },
575
+ {
576
+ id: 'cn.idx.chinext',
577
+ group: 'CN',
578
+ label: { zh: '创业板指', en: 'ChiNext Index' },
579
+ unit: '点',
580
+ freq: 'daily',
581
+ seasonal: 'NA',
582
+ importance: 3,
583
+ source: { adapter: 'quote', seriesRef: 'chinext' },
584
+ display: { transform: 'raw', decimals: 2, polarity: 'up-is-good' },
585
+ tags: ['equity', 'cn'],
586
+ aliases: ['创业板', 'chinext'],
587
+ },
588
+ {
589
+ id: 'cn.idx.dividend',
590
+ group: 'CN',
591
+ label: { zh: '上证红利指数', en: 'SSE Dividend Index' },
592
+ unit: '点',
593
+ freq: 'daily',
594
+ seasonal: 'NA',
595
+ importance: 2,
596
+ source: { adapter: 'quote', seriesRef: 'dividend' },
597
+ display: { transform: 'raw', decimals: 2, polarity: 'up-is-good' },
598
+ tags: ['equity', 'cn', 'dividend'],
599
+ aliases: ['红利指数', 'dividend index'],
600
+ },
601
+ {
602
+ id: 'cn.bond.govt.index',
603
+ group: 'CN',
604
+ label: { zh: '上证国债指数', en: 'SSE Government Bond Index' },
605
+ unit: '点',
606
+ freq: 'daily',
607
+ seasonal: 'NA',
608
+ importance: 4,
609
+ source: { adapter: 'quote', seriesRef: 'govtbond' },
610
+ display: { transform: 'raw', decimals: 2, polarity: 'up-is-good' },
611
+ notes: { zh: '这是债券价格指数,不是到期收益率;中国 10Y 收益率暂无可用公开源(见 docs/03 §3.6)。行情取自多源级联(腾讯 → 东方财富),任一源被限流不影响该卡片。' },
612
+ tags: ['bond', 'cn'],
613
+ aliases: ['国债指数', '国债', 'government bond'],
614
+ },
615
+ {
616
+ id: 'cn.bond.corp.index',
617
+ group: 'CN',
618
+ label: { zh: '上证企债指数', en: 'SSE Corporate Bond Index' },
619
+ unit: '点',
620
+ freq: 'daily',
621
+ seasonal: 'NA',
622
+ importance: 4,
623
+ source: { adapter: 'quote', seriesRef: 'corpbond' },
624
+ display: { transform: 'raw', decimals: 2, polarity: 'up-is-good' },
625
+ tags: ['bond', 'cn', 'credit'],
626
+ aliases: ['企债指数', '信用债', 'corporate bond'],
627
+ },
628
+ {
629
+ id: 'cn.bond.credit.spread',
630
+ group: 'CN',
631
+ label: { zh: '中国信用债−国债比价', en: 'China Corporate vs Government Bond Ratio' },
632
+ unit: '比值',
633
+ freq: 'daily',
634
+ seasonal: 'NA',
635
+ importance: 3,
636
+ derive: { op: 'ratio', operands: ['cn.bond.corp.index', 'cn.bond.govt.index'] },
637
+ display: { transform: 'raw', decimals: 4, polarity: 'up-is-good' },
638
+ notes: { zh: '两条指数按日期内连接后取比值;上升代表信用债相对走强(风险偏好改善)。' },
639
+ tags: ['bond', 'cn', 'signal'],
640
+ aliases: ['信用利差代理', 'credit spread proxy'],
641
+ },
642
+ {
643
+ id: 'cn.houseprice.new',
644
+ group: 'CN',
645
+ label: { zh: '中国 70 城新房价格同比', en: 'China 70-City New Home Price YoY' },
646
+ unit: '%',
647
+ freq: 'monthly',
648
+ seasonal: 'NSA',
649
+ importance: 5,
650
+ source: { adapter: 'eastmoney-macro', seriesRef: 'RPT_ECONOMY_HOUSE_PRICE', params: { column: 'FIRST_COMHOUSE_SAME', city: '北京' } },
651
+ display: { transform: 'raw', decimals: 1, polarity: 'up-is-good' },
652
+ notes: { zh: '国家统计局 70 城新建商品住宅销售价格同比(%),100 为基准。上游该报表按城市分行,取北京作一线代表;FIRST_COMHOUSE_SAME 本身就是同比百分比。' },
653
+ tags: ['housing', 'cn'],
654
+ aliases: ['房价', '新房价格', '70城房价'],
655
+ },
656
+ {
657
+ id: 'cn.houseprice.second',
658
+ group: 'CN',
659
+ label: { zh: '中国 70 城二手房价格同比', en: 'China 70-City Existing Home Price YoY' },
660
+ unit: '%',
661
+ freq: 'monthly',
662
+ seasonal: 'NSA',
663
+ importance: 4,
664
+ source: { adapter: 'eastmoney-macro', seriesRef: 'RPT_ECONOMY_HOUSE_PRICE', params: { column: 'SECOND_HOUSE_SAME', city: '北京' } },
665
+ display: { transform: 'raw', decimals: 1, polarity: 'up-is-good' },
666
+ notes: { zh: '二手住宅同比(%)。二手房比新房更早反映真实成交,二者背离时以二手房为领先参考。' },
667
+ tags: ['housing', 'cn'],
668
+ aliases: ['二手房', '二手房价'],
669
+ },
670
+ {
671
+ id: 'cn.population.birthrate',
672
+ group: 'CN',
673
+ label: { zh: '中国人口出生率', en: 'China Birth Rate' },
674
+ unit: '‰',
675
+ freq: 'annual',
676
+ seasonal: 'NSA',
677
+ importance: 4,
678
+ source: { adapter: 'worldbank', seriesRef: 'SP.DYN.CBRT.IN', params: { country: 'CN', date: '1990:3000' } },
679
+ display: { transform: 'raw', decimals: 2, polarity: 'up-is-good' },
680
+ notes: { zh: '世界银行粗出生率(每千人),年度频率,最新年份取决于上游发布节奏。' },
681
+ tags: ['population', 'cn'],
682
+ aliases: ['出生率', '人口', 'birth rate'],
683
+ },
684
+ {
685
+ id: 'cn.population.fertility',
686
+ group: 'CN',
687
+ label: { zh: '中国总和生育率', en: 'China Fertility Rate' },
688
+ unit: '孩/妇女',
689
+ freq: 'annual',
690
+ seasonal: 'NSA',
691
+ importance: 4,
692
+ source: { adapter: 'worldbank', seriesRef: 'SP.DYN.TFRT.IN', params: { country: 'CN', date: '1990:3000' } },
693
+ display: { transform: 'raw', decimals: 3, polarity: 'up-is-good' },
694
+ notes: { zh: '世界银行总和生育率(每名妇女生育数)。替代水平约 2.1,长期低于该值是人口结构压力的核心指标。' },
695
+ tags: ['population', 'cn'],
696
+ aliases: ['生育率', '总和生育率', 'fertility'],
697
+ },
698
+ {
699
+ id: 'cn.population.urban',
700
+ group: 'CN',
701
+ label: { zh: '中国城镇化率', en: 'China Urban Population Share' },
702
+ unit: '%',
703
+ freq: 'annual',
704
+ seasonal: 'NSA',
705
+ importance: 3,
706
+ source: { adapter: 'worldbank', seriesRef: 'SP.URB.TOTL.IN.ZS', params: { country: 'CN', date: '1990:3000' } },
707
+ display: { transform: 'raw', decimals: 2, polarity: 'neutral' },
708
+ notes: { zh: '城镇人口占比(%)。与楼市需求同源,其增速放缓通常领先于房价同比走弱。' },
709
+ tags: ['population', 'housing', 'cn'],
710
+ aliases: ['城镇化', '城市化', 'urban'],
711
+ },
712
+ {
713
+ id: 'cn.trade.exports',
714
+ group: 'CN',
715
+ label: { zh: '中国出口金额', en: 'China Exports' },
716
+ // The upstream publishes 万美元; changing the unit would require rescaling,
717
+ // so the unit string states what the source really returns.
718
+ unit: '万美元',
719
+ freq: 'monthly',
720
+ seasonal: 'NSA',
721
+ importance: 4,
722
+ source: { adapter: 'eastmoney-macro', seriesRef: 'RPT_ECONOMY_CUSTOMS', params: { column: 'EXIT_BASE' } },
723
+ display: { transform: 'raw', decimals: 0, polarity: 'up-is-good' },
724
+ notes: { zh: '海关总署月度出口金额,单位与上游一致(万美元)。上游另有 EXIT_BASE_SAME 给出同比(%),这里取绝对额以便看水平与趋势。' },
725
+ tags: ['trade', 'cn'],
726
+ aliases: ['出口', '出口金额', 'exports'],
727
+ },
728
+ {
729
+ id: 'cn.trade.imports',
730
+ group: 'CN',
731
+ label: { zh: '中国进口金额', en: 'China Imports' },
732
+ unit: '万美元',
733
+ freq: 'monthly',
734
+ seasonal: 'NSA',
735
+ importance: 4,
736
+ source: { adapter: 'eastmoney-macro', seriesRef: 'RPT_ECONOMY_CUSTOMS', params: { column: 'IMPORT_BASE' } },
737
+ display: { transform: 'raw', decimals: 0, polarity: 'up-is-good' },
738
+ notes: { zh: '海关总署月度进口金额,单位与上游一致(万美元)。进口走弱常先于出口反映内需变化。' },
739
+ tags: ['trade', 'cn'],
740
+ aliases: ['进口', '进口金额', 'imports'],
741
+ },
742
+ {
743
+ id: 'cn.trade.balance',
744
+ group: 'CN',
745
+ label: { zh: '中国贸易顺差', en: 'China Trade Balance' },
746
+ unit: '万美元',
747
+ freq: 'monthly',
748
+ seasonal: 'NSA',
749
+ importance: 4,
750
+ derive: { op: 'spread', operands: ['cn.trade.exports', 'cn.trade.imports'] },
751
+ display: { transform: 'raw', decimals: 0, polarity: 'neutral' },
752
+ notes: { zh: '出口减进口(万美元),按日期内连接后相减;两条序列同为月度且同日发布,差值近似月度贸易顺差。' },
753
+ tags: ['trade', 'cn', 'signal'],
754
+ aliases: ['贸易顺差', '顺差', 'trade balance', '进出口'],
755
+ },
756
+ ]
757
+
758
+ /** 全球与跨市场(World Bank / ECB / 美国财政部 / 海外指数)。 */
759
+ const GLOBAL = [
760
+ {
761
+ id: 'ecb.exr.usd',
762
+ group: 'GLOBAL',
763
+ label: { zh: '欧元/美元', en: 'EUR/USD' },
764
+ unit: '汇率',
765
+ freq: 'daily',
766
+ seasonal: 'NA',
767
+ importance: 4,
768
+ source: { adapter: 'ecb', seriesRef: 'EXR/D.USD.EUR.SP00.A', params: { lastNObservations: 1600 } },
769
+ display: { transform: 'raw', decimals: 4, polarity: 'neutral' },
770
+ notes: { zh: 'ECB 每日参考汇率(约 16:00 CET 定盘),不是实时报价。' },
771
+ tags: ['fx', 'eu'],
772
+ aliases: ['欧元', 'eurusd', '汇率'],
773
+ },
774
+ {
775
+ id: 'wb.gdp.us',
776
+ group: 'GLOBAL',
777
+ label: { zh: '美国 GDP(现价美元)', en: 'US GDP (current US$)' },
778
+ unit: '美元',
779
+ freq: 'annual',
780
+ seasonal: 'NA',
781
+ importance: 3,
782
+ source: { adapter: 'worldbank', seriesRef: 'NY.GDP.MKTP.CD', params: { country: 'US' } },
783
+ display: { transform: 'raw', decimals: 0, polarity: 'up-is-good' },
784
+ notes: { zh: 'World Bank 年度口径,年末记账;发布滞后 1–2 年,陈旧阈值 400 天。' },
785
+ tags: ['growth', 'global'],
786
+ aliases: ['美国GDP总量', 'world bank gdp'],
787
+ },
788
+ {
789
+ id: 'wb.gdp.cn',
790
+ group: 'GLOBAL',
791
+ label: { zh: '中国 GDP(现价美元)', en: 'China GDP (current US$)' },
792
+ unit: '美元',
793
+ freq: 'annual',
794
+ seasonal: 'NA',
795
+ importance: 3,
796
+ source: { adapter: 'worldbank', seriesRef: 'NY.GDP.MKTP.CD', params: { country: 'CN' } },
797
+ display: { transform: 'raw', decimals: 0, polarity: 'up-is-good' },
798
+ tags: ['growth', 'global'],
799
+ aliases: ['中国GDP总量'],
800
+ },
801
+ {
802
+ id: 'wb.cpi.cn',
803
+ group: 'GLOBAL',
804
+ label: { zh: '中国通胀(WB 年频)', en: 'China Inflation (World Bank)' },
805
+ unit: '%',
806
+ freq: 'annual',
807
+ seasonal: 'NA',
808
+ importance: 2,
809
+ source: { adapter: 'worldbank', seriesRef: 'FP.CPI.TOTL.ZG', params: { country: 'CN' } },
810
+ display: { transform: 'raw', decimals: 1, polarity: 'neutral' },
811
+ notes: { zh: '可与 cn.cpi.yoy 交叉校验:两条独立来源同向才算可信。' },
812
+ tags: ['inflation', 'global'],
813
+ aliases: ['WB通胀', 'world bank cpi'],
814
+ },
815
+ {
816
+ id: 'wb.unemployment.us',
817
+ group: 'GLOBAL',
818
+ label: { zh: '美国失业率(ILO 口径)', en: 'US Unemployment (ILO)' },
819
+ unit: '%',
820
+ freq: 'annual',
821
+ seasonal: 'NA',
822
+ importance: 2,
823
+ source: { adapter: 'worldbank', seriesRef: 'SL.UEM.TOTL.ZS', params: { country: 'US' } },
824
+ display: { transform: 'raw', decimals: 1, polarity: 'down-is-good' },
825
+ notes: { zh: 'ILO 建模估计,与 BLS 的 us.unrate 口径不同(后者更及时)。' },
826
+ tags: ['labor', 'global'],
827
+ aliases: ['ILO失业率'],
828
+ },
829
+ {
830
+ id: 'wb.lending.cn',
831
+ group: 'GLOBAL',
832
+ label: { zh: '中国贷款加权平均利率', en: 'China Lending Interest Rate (World Bank)' },
833
+ unit: '%',
834
+ freq: 'annual',
835
+ seasonal: 'NA',
836
+ importance: 3,
837
+ source: { adapter: 'worldbank', seriesRef: 'FR.INR.LEND', params: { country: 'CN' } },
838
+ display: { transform: 'raw', decimals: 2, polarity: 'down-is-good' },
839
+ notes: { zh: 'LPR 没有可用公开时序源(docs/03 §3.6);这是 World Bank 的贷款加权平均利率年频口径,作为替代观察项。' },
840
+ tags: ['rates', 'cn'],
841
+ aliases: ['LPR替代', '贷款利率', 'lending rate'],
842
+ },
843
+ {
844
+ id: 'ust.avg.rate.notes',
845
+ group: 'GLOBAL',
846
+ label: { zh: '美国国债平均利率(Notes)', en: 'US Treasury Average Rate (Notes)' },
847
+ unit: '%',
848
+ freq: 'monthly',
849
+ seasonal: 'NA',
850
+ importance: 3,
851
+ source: {
852
+ adapter: 'us-treasury',
853
+ seriesRef: 'avg_interest_rates',
854
+ params: { filter: 'security_desc:eq:Treasury Notes', valueField: 'avg_interest_rate_amt' },
855
+ },
856
+ display: { transform: 'raw', decimals: 3, polarity: 'neutral' },
857
+ notes: { zh: '存续国债的平均票息,反映财政付息成本;必须带 filter,否则会混入 Bills/Bonds/TIPS。' },
858
+ tags: ['rates', 'fiscal', 'global'],
859
+ aliases: ['国债平均利率', 'treasury average rate'],
860
+ },
861
+ ]
862
+
863
+ /** 用户自定义指标落在这个分组('group: 'CUSTOM'')。 */
864
+ const CUSTOM = [
865
+ {
866
+ id: 'custom.example.placeholder',
867
+ group: 'CUSTOM',
868
+ label: { zh: '自定义指标(示例占位)', en: 'Custom Indicator (placeholder)' },
869
+ unit: '%',
870
+ freq: 'monthly',
871
+ seasonal: 'NA',
872
+ importance: 1,
873
+ source: { adapter: 'fred', seriesRef: 'PAYEMS' },
874
+ display: { transform: 'raw', decimals: 2, polarity: 'neutral' },
875
+ notes: { zh: '仅用于演示 CUSTOM 分组;用户新增的指标由 WatchlistRepository 管理,不写进种子目录。' },
876
+ tags: ['custom'],
877
+ aliases: ['自定义', 'custom'],
878
+ },
879
+ ]
880
+
881
+ /** The full seed catalog. */
882
+ export const CATALOG = [...US, ...CN, ...GLOBAL, ...CUSTOM]
883
+
884
+ /**
885
+ * Indicators that were investigated and deliberately left out, with the reason
886
+ * (docs/10 hard rule 3: never guess an interface). 'cn.us.10y.spread' depends on
887
+ * a China 10-year yield, so it is unsupported until such a source exists.
888
+ *
889
+ * @type {Array<{ id: string, label: { zh: string, en: string }, group: string, reason: string, investigated: string[] }>}
890
+ */
891
+ export const UNSUPPORTED = [
892
+ {
893
+ id: 'cn.bond.10y.yield',
894
+ label: { zh: '中国 10Y 国债收益率', en: 'China 10-Year Government Bond Yield' },
895
+ group: 'CN',
896
+ reason: '没有找到可用的公开时序源,按纪律标为 unsupported 而不是猜接口。',
897
+ investigated: [
898
+ '东方财富 datacenter RPT_ECONOMY_INTEREST_RATE / RPT_BOND_CB_YIELD → code 9501「报表配置不存在」',
899
+ '东方财富行情 secid 0.100303(10Y 国债收益率)→ rc=100、data=null',
900
+ '中国债券信息网 yield.chinabond.com.cn/cbweb-mn/yield_main/getYieldData → HTTP 404',
901
+ '新浪债券行情 hq.sinajs.cn → HTTP 403(需要特定 Referer)',
902
+ '中金所 CFFEX 日行情 XML → 只有单交易日快照,且是国债期货价格而非收益率',
903
+ ],
904
+ },
905
+ {
906
+ id: 'cn.lpr.1y',
907
+ label: { zh: '中国 1 年期 LPR', en: 'China 1-Year LPR' },
908
+ group: 'CN',
909
+ reason: 'datacenter 无对应报表;LPR 目前只能从新闻/公告获得,无法构成时序。',
910
+ investigated: ['RPT_ECONOMY_LPR → code 9501', '替代口径:World Bank FR.INR.LEND(年频,已作为 wb.lending.cn 收录)'],
911
+ },
912
+ {
913
+ id: 'cn.tsf.level',
914
+ label: { zh: '中国社会融资规模', en: 'China Total Social Financing' },
915
+ group: 'CN',
916
+ reason: 'datacenter 未确认存在社融报表(RPT_ECONOMY_* 枚举中无 TS/社融),不猜 reportName。',
917
+ investigated: ['RPT_ECONOMY_TRADE / RPT_ECONOMY_SHIBOR / RPT_ECONOMY_INTEREST_RATE → code 9501', '未逐个枚举全部报表名'],
918
+ },
919
+ {
920
+ id: 'hk.idx.hsi',
921
+ label: { zh: '恒生指数', en: 'Hang Seng Index' },
922
+ group: 'GLOBAL',
923
+ reason: '本网络可达的三个行情端点都不提供恒指日线:新浪 A 股接口对该代码返回 null(实测),腾讯返回 501,东方财富行情域主动断连。',
924
+ investigated: [
925
+ '新浪 CN_MarketDataService.getKLineData:hkHSI / rt_hkHSI / hkHSI.HK 全部返回 x(null)',
926
+ '腾讯 fqkline:hkHSI 曾有数据,现返回 HTTP 501',
927
+ '东方财富 push2his:UND_ERR_SOCKET(该域对本网络断连)',
928
+ ],
929
+ },
930
+ {
931
+ id: 'jp.idx.n225',
932
+ label: { zh: '日经 225', en: 'Nikkei 225' },
933
+ group: 'GLOBAL',
934
+ reason: '本部署可达的行情源都不提供日经 225 的日线历史:腾讯接口对该代码返回 param error,东方财富行情域被网络阻断,FRED 被边缘 WAF 拒绝。',
935
+ investigated: [
936
+ '腾讯 web.ifzq.gtimg.cn kline:jpNI225 → param error',
937
+ '新浪美股日线 US_MinKService:.N225 → 连接失败',
938
+ '东方财富 push2his:UND_ERR_SOCKET(该域对本网络断连)',
939
+ 'FRED(NASDAQ100/NIKKEI 系列):HTTP 403 AkamaiGHost',
940
+ ],
941
+ },
942
+ {
943
+ id: 'kr.idx.kospi',
944
+ label: { zh: '韩国 KOSPI', en: 'KOSPI' },
945
+ group: 'GLOBAL',
946
+ reason: '同上:没有可达的日线历史源。',
947
+ investigated: ['腾讯 krKOSPI → param error', '新浪 .KS11 → 连接失败', '东方财富 100.KS11 → 域被阻断'],
948
+ },
949
+ {
950
+ id: 'de.idx.dax',
951
+ label: { zh: '德国 DAX 30', en: 'DAX 30' },
952
+ group: 'GLOBAL',
953
+ reason: '同上:没有可达的日线历史源。',
954
+ investigated: ['腾讯 deDAXI → param error', '新浪 .GDAXI → 连接失败', '东方财富 100.GDAXI → 域被阻断'],
955
+ },
956
+ {
957
+ id: 'uk.idx.ftse',
958
+ label: { zh: '英国富时 100', en: 'FTSE 100' },
959
+ group: 'GLOBAL',
960
+ reason: '腾讯返回了数据节点但 day 为空,新浪无该符号,东方财富域被阻断。',
961
+ investigated: ['腾讯 ukFTSE → day: [](空)', '新浪 .FTSE → 连接失败', '东方财富 100.FTSE → 域被阻断'],
962
+ },
963
+ {
964
+ id: 'fr.idx.cac',
965
+ label: { zh: '法国 CAC 40', en: 'CAC 40' },
966
+ group: 'GLOBAL',
967
+ reason: '同上:没有可达的日线历史源。',
968
+ investigated: ['腾讯 frCAC → param error', '新浪 .FCHI → 连接失败', '东方财富 100.FCHI → 域被阻断'],
969
+ },
970
+ {
971
+ id: 'eu.idx.stoxx50',
972
+ label: { zh: '欧洲斯托克 50', en: 'Euro Stoxx 50' },
973
+ group: 'GLOBAL',
974
+ reason: '同上:没有可达的日线历史源。',
975
+ investigated: ['腾讯 euSX5E → param error', '新浪 .STOXX50E → 连接失败', '东方财富 100.SX5E → 域被阻断'],
976
+ },
977
+ {
978
+ id: 'au.idx.asx200',
979
+ label: { zh: '澳大利亚标普 200', en: 'S&P/ASX 200' },
980
+ group: 'GLOBAL',
981
+ reason: '同上:没有可达的日线历史源。',
982
+ investigated: ['腾讯 auAS51/100.AS51 → param error', '新浪 .AXJO → 连接失败', '东方财富 100.AS51 → 域被阻断'],
983
+ },
984
+ {
985
+ id: 'cn.us.10y.spread',
986
+ label: { zh: '中美 10Y 利差', en: 'China–US 10-Year Yield Spread' },
987
+ group: 'GLOBAL',
988
+ reason: '依赖 cn.bond.10y.yield;美国一侧(us.dgs10)可用,但缺中国一侧,因此整条不可用。',
989
+ investigated: ['美国一侧 us.dgs10 已实测可用(FRED DGS10)'],
990
+ },
991
+ ]
992
+
993
+ /**
994
+ * Index the catalog by id.
995
+ *
996
+ * @param {IndicatorDef[]} [catalog] - catalog to index.
997
+ * @returns {Map<string, IndicatorDef>} id → definition.
998
+ */
999
+ export function indexById(catalog = CATALOG) {
1000
+ return new Map(catalog.map((indicator) => [indicator.id, indicator]))
1001
+ }
1002
+
1003
+ /**
1004
+ * Look one indicator up.
1005
+ *
1006
+ * @param {string} id - indicator id.
1007
+ * @returns {IndicatorDef|undefined} definition.
1008
+ */
1009
+ export function getIndicator(id) {
1010
+ return CATALOG.find((indicator) => indicator.id === id)
1011
+ }