@openfinclaw/findoo-datahub-plugin 2026.3.2 → 2026.3.10

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 (67) hide show
  1. package/DESIGN.md +492 -151
  2. package/_vendor/claude-skills-finance/SKILL.md +192 -0
  3. package/_vendor/claude-skills-finance/assets/dcf_analysis_template.md +184 -0
  4. package/_vendor/claude-skills-finance/assets/expected_output.json +161 -0
  5. package/_vendor/claude-skills-finance/assets/forecast_report_template.md +177 -0
  6. package/_vendor/claude-skills-finance/assets/sample_financial_data.json +219 -0
  7. package/_vendor/claude-skills-finance/assets/variance_report_template.md +122 -0
  8. package/_vendor/claude-skills-finance/references/financial-ratios-guide.md +396 -0
  9. package/_vendor/claude-skills-finance/references/forecasting-best-practices.md +294 -0
  10. package/_vendor/claude-skills-finance/references/valuation-methodology.md +255 -0
  11. package/_vendor/claude-skills-finance/scripts/budget_variance_analyzer.py +406 -0
  12. package/_vendor/claude-skills-finance/scripts/dcf_valuation.py +449 -0
  13. package/_vendor/claude-skills-finance/scripts/forecast_builder.py +494 -0
  14. package/_vendor/claude-skills-finance/scripts/ratio_calculator.py +432 -0
  15. package/index.ts +332 -14
  16. package/openclaw.plugin.json +2 -2
  17. package/package.json +1 -1
  18. package/references/cn-market-specifics.md +165 -0
  19. package/references/crypto-analysis.md +635 -0
  20. package/references/financial-ratios-cn.md +452 -0
  21. package/references/hk-market-specifics.md +166 -0
  22. package/references/macro-cycle-cn.md +409 -0
  23. package/references/valuation-cn.md +427 -0
  24. package/skills/README.md +294 -0
  25. package/skills/a-concept-cycle/skill.md +200 -0
  26. package/skills/a-convertible-arb/skill.md +294 -0
  27. package/skills/a-dividend-king/skill.md +187 -0
  28. package/skills/a-earnings-season/skill.md +221 -0
  29. package/skills/a-index-timer/skill.md +192 -0
  30. package/skills/a-ipo-new/skill.md +297 -0
  31. package/skills/a-northbound-decoder/skill.md +185 -0
  32. package/skills/a-quant-board/skill.md +286 -0
  33. package/skills/a-share/skill.md +347 -0
  34. package/skills/a-share-radar/skill.md +185 -0
  35. package/skills/cross-asset/skill.md +202 -0
  36. package/skills/crypto/skill.md +269 -0
  37. package/skills/crypto-altseason/skill.md +208 -0
  38. package/skills/crypto-btc-cycle/skill.md +231 -0
  39. package/skills/crypto-defi-yield/skill.md +181 -0
  40. package/skills/crypto-funding-arb/skill.md +158 -0
  41. package/skills/crypto-stablecoin-flow/skill.md +149 -0
  42. package/skills/data-query/skill.md +124 -30
  43. package/skills/derivatives/skill.md +188 -35
  44. package/skills/etf-fund/skill.md +216 -0
  45. package/skills/factor-screen/skill.md +186 -0
  46. package/skills/hk-china-internet/skill.md +190 -0
  47. package/skills/hk-dividend-harvest/skill.md +192 -0
  48. package/skills/hk-hsi-pulse/skill.md +154 -0
  49. package/skills/hk-southbound-alpha/skill.md +163 -0
  50. package/skills/hk-stock/skill.md +295 -0
  51. package/skills/macro/skill.md +244 -53
  52. package/skills/risk-monitor/skill.md +171 -0
  53. package/skills/us-dividend/skill.md +162 -0
  54. package/skills/us-earnings/skill.md +149 -0
  55. package/skills/us-equity/skill.md +235 -0
  56. package/skills/us-etf/skill.md +261 -0
  57. package/skills/us-sector-rotation/skill.md +223 -0
  58. package/src/config.ts +4 -5
  59. package/src/datahub-client.test.ts +4 -7
  60. package/src/datahub-client.ts +6 -1
  61. package/src/register-tools.ts +720 -0
  62. package/src/tool-helpers.ts +89 -0
  63. package/test/e2e/l3-gateway-bootstrap.live.test.ts +339 -0
  64. package/test/e2e/l4-skill-tool-chain.live.test.ts +465 -0
  65. package/skills/crypto-defi/skill.md +0 -69
  66. package/skills/equity/skill.md +0 -64
  67. package/skills/market-radar/skill.md +0 -47
@@ -0,0 +1,223 @@
1
+ ---
2
+ name: fin-us-sector-rotation
3
+ description: "US sector rotation — GICS 11-sector ETF scoreboard (XLK/XLF/XLE/XLV/XLU/XLI/XLB/XLP/XLY/XLRE/XLC), economic cycle positioning, sector vs SPY relative strength, valuation by sector. Use when: user asks about sector rotation, which industry to buy, economic cycle stage, or sector ETF comparison. NOT for: individual US stocks (use fin-us-equity), US ETF portfolio/DCA (use fin-us-etf), A-share sectors (use fin-a-share), macro rates only (use fin-macro), crypto sectors (use fin-crypto-altseason)."
4
+ metadata: { "openclaw": { "emoji": "🏭", "requires": { "extensions": ["findoo-datahub-plugin"] } } }
5
+ ---
6
+
7
+ # US Sector Rotation
8
+
9
+ Economic cycle positioning + GICS sector momentum = systematic allocation framework. This skill turns "which sector should I buy" from gut feeling into data-driven rotation decisions.
10
+
11
+ > **Scope boundary:** This skill covers US sector-level analysis and rotation strategy. For individual US stock analysis, use `/fin-us-equity`. For ETF portfolio construction and DCA, use `/fin-us-etf`. For macro rates and yield curve, use `/fin-macro`.
12
+
13
+ ## When to Use
14
+
15
+ - "现在该买哪个行业" / "Which sector should I buy now?"
16
+ - "科技股 vs 能源股" / "Tech vs Energy comparison"
17
+ - "经济周期在什么阶段" / "What stage of the economic cycle are we in?"
18
+ - "行业轮动到哪里了" / "Where is sector rotation heading?"
19
+ - "防御性板块是不是该配了" / "Should I add defensive sectors?"
20
+ - "XLK 和 XLV 哪个好" / "XLK vs XLV comparison"
21
+ - "哪个行业估值最低" / "Which sector has the lowest valuation?"
22
+
23
+ ## When NOT to Use
24
+
25
+ - 美股个股深度分析 (AAPL, NVDA) → use `/fin-us-equity`
26
+ - ETF 组合配置 / 定投模拟 / ETF 对比 → use `/fin-us-etf`
27
+ - 宏观利率 / 国债收益率 / GDP/CPI → use `/fin-macro`
28
+ - A 股行业 / 板块分析 → use `/fin-a-share`
29
+ - 加密货币赛道轮动 → use `/fin-crypto-altseason`
30
+ - 美股期权策略 → use `/fin-us-equity` (options section)
31
+
32
+ ## Tools & Parameters
33
+
34
+ ### fin_stock (Sector ETF price + fundamentals)
35
+
36
+ | Parameter | Type | Required | Format | Default | Example |
37
+ | --------- | ------ | -------- | --------- | ------- | ---------------- |
38
+ | symbol | string | Yes | US ticker | — | XLK |
39
+ | endpoint | string | Yes | see below | — | price/historical |
40
+ | provider | string | No | yfinance | auto | yfinance |
41
+ | limit | number | No | 1-5000 | 250 | 250 |
42
+
43
+ > **Important:** For US ETFs, always use `provider="yfinance"` with `price/historical`. Default tushare provider returns 500 for US symbols.
44
+
45
+ #### Endpoints
46
+
47
+ | endpoint | Description | Example |
48
+ | ------------------------------- | ----------------------- | --------------------------------------------------------------------------- |
49
+ | `price/historical` | Sector ETF OHLCV | `fin_stock(symbol="XLK", endpoint="price/historical", provider="yfinance")` |
50
+ | `fundamental/ratios` | Sector ETF basic ratios | `fin_stock(symbol="XLK", endpoint="fundamental/ratios")` |
51
+ | `fundamental/earnings_forecast` | Earnings consensus | `fin_stock(symbol="XLK", endpoint="fundamental/earnings_forecast")` |
52
+ | `profile` | ETF description | `fin_stock(symbol="XLK", endpoint="profile")` |
53
+
54
+ ### Auxiliary Tools
55
+
56
+ | tool | endpoint | use case |
57
+ | ----------------- | -------------- | -------------------------------------------- |
58
+ | `fin_macro` | `treasury_us` | Yield curve for economic cycle determination |
59
+ | `fin_ta` | `rsi/sma/macd` | Sector ETF technical momentum |
60
+ | `fin_data_regime` | — | SPY regime for macro overlay |
61
+ | `fin_data_ohlcv` | — | Sector ETF K-line data |
62
+ | `fin_index` | `daily_basic` | Index valuation (for cross-reference) |
63
+
64
+ ## Sector ETF Reference
65
+
66
+ ### SPDR Select Sector ETFs (11 GICS Sectors)
67
+
68
+ | Ticker | Sector | Expense | Cycle Phase | Rate Sensitivity |
69
+ | ------ | ------------------ | ------- | -------------------- | ---------------- |
70
+ | XLK | Technology | 0.09% | Early/Late Expansion | High (negative) |
71
+ | XLF | Financials | 0.09% | Early Recovery | High (positive) |
72
+ | XLE | Energy | 0.09% | Late Cycle/Inflation | Low |
73
+ | XLV | Healthcare | 0.09% | Defensive/Late Cycle | Low |
74
+ | XLU | Utilities | 0.09% | Recession/Defensive | High (negative) |
75
+ | XLI | Industrials | 0.09% | Early Recovery | Moderate |
76
+ | XLB | Materials | 0.09% | Mid Cycle/Inflation | Moderate |
77
+ | XLP | Consumer Staples | 0.09% | Recession/Defensive | Low |
78
+ | XLY | Consumer Discret. | 0.09% | Early Recovery | Moderate |
79
+ | XLRE | Real Estate | 0.09% | Rate Sensitive | Very High (neg) |
80
+ | XLC | Communication Svcs | 0.09% | Growth-oriented | High (negative) |
81
+
82
+ ### SPY as Benchmark
83
+
84
+ | Ticker | Description | Use |
85
+ | ------ | ----------- | ------------------------------------------- |
86
+ | SPY | S&P 500 | Benchmark for relative strength calculation |
87
+
88
+ ## Sector Rotation Analysis Pattern
89
+
90
+ ### 1. Sector Scoreboard
91
+
92
+ 1. **Pull price history for all 11 sectors + SPY** — `fin_stock(symbol="XLK", endpoint="price/historical", provider="yfinance", limit=250)` for each sector ETF + SPY
93
+ - Calculate for each: 1W return, 1M return, 3M return, YTD return
94
+ - Calculate relative return vs SPY for each period (sector return - SPY return)
95
+ - Rank by 3M relative return (primary momentum signal)
96
+ - ⚠️ If top sector 3M relative return > +10% AND RSI > 70 → overbought, potential mean reversion
97
+ - ⚠️ If bottom sector 3M relative return < -10% AND RSI < 30 → oversold, potential contrarian opportunity
98
+ - 💡 Sector leading for > 6 months with decelerating momentum = exhaustion risk
99
+
100
+ 2. **Momentum quality check** — `fin_ta(indicator="rsi", symbol="XLK", market="equity")` for top/bottom sectors
101
+ - RSI > 70 on sector ETF = overbought → trim bias
102
+ - RSI < 30 on sector ETF = oversold → accumulate bias
103
+ - 💡 Divergence between price (new high) and RSI (lower high) = weakening momentum
104
+
105
+ ### 2. Economic Cycle Positioning
106
+
107
+ 1. **Yield curve assessment** — `fin_macro(endpoint="treasury_us")` → 2Y and 10Y yields
108
+ - Calculate 2Y-10Y spread
109
+ - ⚠️ If spread < 0 (inverted) → late cycle / recession warning → rotate to defensives (XLU, XLP, XLV)
110
+ - ⚠️ If spread steepening from inversion → early recovery signal → rotate to cyclicals (XLF, XLY, XLI)
111
+ - 💡 Cross-validate with `fin_data_regime(symbol="SPY", market="equity")` for regime confirmation
112
+
113
+ 2. **Cycle phase determination** — Combine yield curve + SPY regime + sector leadership
114
+
115
+ | Cycle Phase | Yield Curve Signal | Sector Leaders | Sector Laggards |
116
+ | ---------------- | -------------------------- | ------------------- | --------------- |
117
+ | Early Recovery | Steepening from inversion | XLF, XLY, XLI, XLB | XLU, XLP |
118
+ | Mid Expansion | Normal slope, rates rising | XLK, XLC, XLI | XLU, XLRE |
119
+ | Late Expansion | Flattening, rates elevated | XLE, XLB, XLK | XLY, XLRE |
120
+ | Recession/Crisis | Inverting or steep-falling | XLU, XLP, XLV, cash | XLY, XLF, XLI |
121
+
122
+ - ⚠️ Cycle phases are not precise — use as directional bias, not timing tool
123
+ - 💡 If SPY regime = "bear" or "crisis" but yield curve suggests early recovery → possible inflection, watch for confirmation
124
+
125
+ ### 3. Sector Valuation Assessment
126
+
127
+ 1. **Relative valuation** — `fin_stock(symbol="XLK", endpoint="fundamental/ratios")` for each sector
128
+ - Compare P/E across sectors
129
+ - ⚠️ If sector P/E > 1.5x its 5-year median → expensive relative to history
130
+ - ⚠️ If sector P/E < 0.7x its 5-year median → cheap relative to history
131
+ - 💡 Low valuation + improving momentum = strongest rotation signal
132
+ - 💡 High valuation + weakening momentum = strongest sell signal
133
+
134
+ ### Historical Sector P/E Reference (approximate 5Y medians)
135
+
136
+ | Sector | Ticker | Approx 5Y Median P/E | Notes |
137
+ | ------ | ------ | -------------------- | --------------------------- |
138
+ | Tech | XLK | 28-32x | Driven by AAPL/MSFT/NVDA |
139
+ | Financ | XLF | 12-15x | Rate cycle dependent |
140
+ | Energy | XLE | 12-18x | Commodity price dependent |
141
+ | Health | XLV | 16-20x | Defensive premium |
142
+ | Util | XLU | 17-21x | Bond proxy, rate sensitive |
143
+ | Indust | XLI | 18-22x | GDP growth correlated |
144
+ | Mater | XLB | 15-19x | Commodity/inflation linked |
145
+ | Staple | XLP | 20-24x | Defensive premium |
146
+ | Discr | XLY | 22-28x | AMZN/TSLA weight distortion |
147
+ | RE | XLRE | 35-45x | REIT accounting (use P/FFO) |
148
+ | Comms | XLC | 18-24x | META/GOOG weight dominates |
149
+
150
+ ### 4. Rotation Decision Framework
151
+
152
+ ```
153
+ Combine signals into rotation recommendation:
154
+
155
+ 1. Momentum signal (Scoreboard 3M relative return ranking)
156
+ 2. Cycle signal (Economic cycle phase → favored sectors)
157
+ 3. Valuation signal (Current P/E vs historical median)
158
+
159
+ Strong BUY: Momentum top 3 + Cycle favored + Valuation below median
160
+ Strong SELL: Momentum bottom 3 + Cycle unfavored + Valuation above median
161
+ Hold/Neutral: Mixed signals across the three dimensions
162
+ ```
163
+
164
+ - ⚠️ Never recommend >20% portfolio in a single sector (concentration risk)
165
+ - ⚠️ Rotation is gradual tilt adjustment (5-10% weight shift), not binary all-in/all-out
166
+ - 💡 If all three signals align → highest conviction rotation call
167
+
168
+ ## Signal Quick-Reference
169
+
170
+ ### Sector Rotation Playbook by Macro Regime
171
+
172
+ | Macro Signal | Recommended Sectors | Avoid Sectors |
173
+ | ------------------------------ | ------------------- | ---------------- |
174
+ | Rate cuts beginning | XLK, XLRE, XLU, XLY | XLE, XLF (mixed) |
175
+ | Rate hikes beginning | XLF, XLE | XLRE, XLU, XLK |
176
+ | Inflation rising (CPI > 4%) | XLE, XLB, XLI | XLU, XLP, XLRE |
177
+ | Recession fears (VIX > 25) | XLU, XLP, XLV | XLY, XLI, XLF |
178
+ | AI/tech narrative dominant | XLK, XLC | XLE, XLB |
179
+ | Dollar weakening (DXY falling) | XLE, XLB, Emerging | XLK (mixed) |
180
+
181
+ ### Sector Correlation Clusters
182
+
183
+ Understanding which sectors move together helps diversification:
184
+
185
+ - **Cyclical cluster**: XLF + XLI + XLY + XLB (GDP-sensitive)
186
+ - **Defensive cluster**: XLU + XLP + XLV (recession-resistant)
187
+ - **Growth cluster**: XLK + XLC (duration-sensitive, rate-impacted)
188
+ - **Real assets cluster**: XLE + XLB + XLRE (inflation-linked)
189
+
190
+ ## Data Notes
191
+
192
+ - **yfinance ETF data**: ~15min delay, covers price and basic fundamentals. Always specify `provider="yfinance"` for US ETFs.
193
+ - **Sector ETF P/E**: `fundamental/ratios` may return limited data for ETFs. The historical P/E medians in the reference table are approximate and should be cited as "approximate historical reference."
194
+ - **Economic cycle determination**: Based on yield curve shape + SPY regime. This is a simplified framework — professional cycle dating (NBER) lags by months.
195
+ - **Missing from DataHub**: Sector-level aggregate earnings growth, ETF fund flows, precise P/E percentiles. Use the hardcoded reference table for historical context.
196
+ - **Rotation lag**: Sector rotation signals are medium-term (1-3 months). Do not use for day-trading or short-term tactical moves.
197
+
198
+ ## Response Guidelines
199
+
200
+ ### Number Formats
201
+
202
+ - Sector ETF price: $185.40 (2 decimal places)
203
+ - Returns: +8.5% / -2.3% (always with +/- sign, 1 decimal)
204
+ - Relative return vs SPY: +3.2% / -1.8% (clearly labeled "vs SPY")
205
+ - P/E ratio: 28.5x (1 decimal, with "x" suffix)
206
+ - Yield curve spread: +45bp / -12bp (basis points)
207
+ - Expense ratio: 0.09% (2 decimal places)
208
+
209
+ ### Must Include
210
+
211
+ - Data timestamp ("Data as of YYYY-MM-DD")
212
+ - Scoreboard table with all 11 sectors ranked
213
+ - Current economic cycle phase assessment with reasoning
214
+ - At least one ⚠️ risk signal (overbought/overvalued sector, or cycle transition warning)
215
+ - Relative returns vs SPY (not just absolute returns)
216
+
217
+ ### Display Format
218
+
219
+ - Sector overview → 11-sector scoreboard table (ticker, sector, 1W, 1M, 3M, YTD, vs SPY, RSI)
220
+ - Cycle positioning → phase label + yield curve data + favored/avoid sectors
221
+ - Sector comparison → side-by-side table (return, P/E, cycle alignment, momentum)
222
+ - Single sector analysis → structured: Performance, Valuation, Cycle Fit, Momentum, Verdict
223
+ - Always include actionable rotation recommendation with conviction level (high/medium/low)
package/src/config.ts CHANGED
@@ -3,7 +3,7 @@ import type { OpenClawPluginApi } from "openclaw/plugin-sdk";
3
3
  export type PluginConfig = {
4
4
  datahubApiUrl: string;
5
5
  datahubUsername: string;
6
- datahubPassword: string;
6
+ datahubApiKey: string | undefined;
7
7
  requestTimeoutMs: number;
8
8
  };
9
9
 
@@ -15,10 +15,9 @@ function readEnv(keys: string[]): string | undefined {
15
15
  return undefined;
16
16
  }
17
17
 
18
- // Public DataHub defaultsworks out of the box
18
+ // Built-in DataHub URLAPI key must be configured by the user
19
19
  const DEFAULT_DATAHUB_URL = "http://43.134.61.136:8088";
20
20
  const DEFAULT_DATAHUB_USERNAME = "admin";
21
- const DEFAULT_DATAHUB_PASSWORD = "98ffa5c5-1ec6-4735-8e0c-715a5eca1a8d";
22
21
 
23
22
  export function resolveConfig(api: OpenClawPluginApi): PluginConfig {
24
23
  const raw = api.pluginConfig as Record<string, unknown> | undefined;
@@ -37,7 +36,7 @@ export function resolveConfig(api: OpenClawPluginApi): PluginConfig {
37
36
  (typeof raw?.datahubPassword === "string" ? raw.datahubPassword : undefined) ??
38
37
  (typeof raw?.datahubApiKey === "string" ? raw.datahubApiKey : undefined) ??
39
38
  readEnv(["DATAHUB_PASSWORD", "OPENFINCLAW_DATAHUB_PASSWORD", "DATAHUB_API_KEY"]) ??
40
- DEFAULT_DATAHUB_PASSWORD;
39
+ undefined;
41
40
 
42
41
  const timeoutRaw = raw?.requestTimeoutMs ?? readEnv(["OPENFINCLAW_DATAHUB_TIMEOUT_MS"]);
43
42
  const timeout = Number(timeoutRaw);
@@ -45,7 +44,7 @@ export function resolveConfig(api: OpenClawPluginApi): PluginConfig {
45
44
  return {
46
45
  datahubApiUrl: datahubApiUrl.replace(/\/+$/, ""),
47
46
  datahubUsername,
48
- datahubPassword,
47
+ datahubApiKey: datahubPassword,
49
48
  requestTimeoutMs: Number.isFinite(timeout) && timeout >= 1000 ? Math.floor(timeout) : 30_000,
50
49
  };
51
50
  }
@@ -226,19 +226,16 @@ describe("DataHubClient construction", () => {
226
226
 
227
227
  const DATAHUB_URL = process.env.DATAHUB_API_URL ?? "http://43.134.61.136:8088";
228
228
  const DATAHUB_USERNAME = process.env.DATAHUB_USERNAME ?? "admin";
229
- const DATAHUB_PASSWORD =
230
- process.env.DATAHUB_PASSWORD ??
231
- process.env.DATAHUB_API_KEY ??
232
- "98ffa5c5-1ec6-4735-8e0c-715a5eca1a8d";
233
- // Live tests run by default (public DataHub has baked-in credentials)
234
- // Set DATAHUB_SKIP_LIVE=1 to skip
229
+ const DEV_KEY = "98ffa5c5-1ec6-4735-8e0c-715a5eca1a8d";
230
+ const DATAHUB_API_KEY = process.env.DATAHUB_PASSWORD ?? process.env.DATAHUB_API_KEY ?? DEV_KEY;
231
+ // Live tests use built-in dev key by default. Set DATAHUB_SKIP_LIVE=1 to skip.
235
232
  const SKIP_LIVE = process.env.DATAHUB_SKIP_LIVE === "1";
236
233
 
237
234
  describe.skipIf(SKIP_LIVE)("Live DataHub E2E", () => {
238
235
  let client: DataHubClient;
239
236
 
240
237
  beforeAll(() => {
241
- client = new DataHubClient(DATAHUB_URL, DATAHUB_USERNAME, DATAHUB_PASSWORD, 30_000);
238
+ client = new DataHubClient(DATAHUB_URL, DATAHUB_USERNAME, DATAHUB_API_KEY, 30_000);
242
239
  });
243
240
 
244
241
  // --- Coverage / Meta ---
@@ -102,6 +102,11 @@ export class DataHubClient {
102
102
  return this.query(`coverage/${endpoint}`);
103
103
  }
104
104
 
105
+ /** /api/v1/ta/* — Technical Analysis indicators (sma, ema, rsi, macd, bbands) */
106
+ ta(indicator: string, params?: Record<string, string>): Promise<unknown[]> {
107
+ return this.query(`ta/${indicator}`, params);
108
+ }
109
+
105
110
  /* ============================================================
106
111
  * Typed convenience methods (OHLCV + Ticker)
107
112
  * ============================================================ */
@@ -203,5 +208,5 @@ function detectEquityProvider(symbol: string): string {
203
208
  ) {
204
209
  return "tushare";
205
210
  }
206
- return "yfinance";
211
+ return "massive";
207
212
  }