@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.
- package/DESIGN.md +492 -151
- package/_vendor/claude-skills-finance/SKILL.md +192 -0
- package/_vendor/claude-skills-finance/assets/dcf_analysis_template.md +184 -0
- package/_vendor/claude-skills-finance/assets/expected_output.json +161 -0
- package/_vendor/claude-skills-finance/assets/forecast_report_template.md +177 -0
- package/_vendor/claude-skills-finance/assets/sample_financial_data.json +219 -0
- package/_vendor/claude-skills-finance/assets/variance_report_template.md +122 -0
- package/_vendor/claude-skills-finance/references/financial-ratios-guide.md +396 -0
- package/_vendor/claude-skills-finance/references/forecasting-best-practices.md +294 -0
- package/_vendor/claude-skills-finance/references/valuation-methodology.md +255 -0
- package/_vendor/claude-skills-finance/scripts/budget_variance_analyzer.py +406 -0
- package/_vendor/claude-skills-finance/scripts/dcf_valuation.py +449 -0
- package/_vendor/claude-skills-finance/scripts/forecast_builder.py +494 -0
- package/_vendor/claude-skills-finance/scripts/ratio_calculator.py +432 -0
- package/index.ts +332 -14
- package/openclaw.plugin.json +2 -2
- package/package.json +1 -1
- package/references/cn-market-specifics.md +165 -0
- package/references/crypto-analysis.md +635 -0
- package/references/financial-ratios-cn.md +452 -0
- package/references/hk-market-specifics.md +166 -0
- package/references/macro-cycle-cn.md +409 -0
- package/references/valuation-cn.md +427 -0
- package/skills/README.md +294 -0
- package/skills/a-concept-cycle/skill.md +200 -0
- package/skills/a-convertible-arb/skill.md +294 -0
- package/skills/a-dividend-king/skill.md +187 -0
- package/skills/a-earnings-season/skill.md +221 -0
- package/skills/a-index-timer/skill.md +192 -0
- package/skills/a-ipo-new/skill.md +297 -0
- package/skills/a-northbound-decoder/skill.md +185 -0
- package/skills/a-quant-board/skill.md +286 -0
- package/skills/a-share/skill.md +347 -0
- package/skills/a-share-radar/skill.md +185 -0
- package/skills/cross-asset/skill.md +202 -0
- package/skills/crypto/skill.md +269 -0
- package/skills/crypto-altseason/skill.md +208 -0
- package/skills/crypto-btc-cycle/skill.md +231 -0
- package/skills/crypto-defi-yield/skill.md +181 -0
- package/skills/crypto-funding-arb/skill.md +158 -0
- package/skills/crypto-stablecoin-flow/skill.md +149 -0
- package/skills/data-query/skill.md +124 -30
- package/skills/derivatives/skill.md +188 -35
- package/skills/etf-fund/skill.md +216 -0
- package/skills/factor-screen/skill.md +186 -0
- package/skills/hk-china-internet/skill.md +190 -0
- package/skills/hk-dividend-harvest/skill.md +192 -0
- package/skills/hk-hsi-pulse/skill.md +154 -0
- package/skills/hk-southbound-alpha/skill.md +163 -0
- package/skills/hk-stock/skill.md +295 -0
- package/skills/macro/skill.md +244 -53
- package/skills/risk-monitor/skill.md +171 -0
- package/skills/us-dividend/skill.md +162 -0
- package/skills/us-earnings/skill.md +149 -0
- package/skills/us-equity/skill.md +235 -0
- package/skills/us-etf/skill.md +261 -0
- package/skills/us-sector-rotation/skill.md +223 -0
- package/src/config.ts +4 -5
- package/src/datahub-client.test.ts +4 -7
- package/src/datahub-client.ts +6 -1
- package/src/register-tools.ts +720 -0
- package/src/tool-helpers.ts +89 -0
- package/test/e2e/l3-gateway-bootstrap.live.test.ts +339 -0
- package/test/e2e/l4-skill-tool-chain.live.test.ts +465 -0
- package/skills/crypto-defi/skill.md +0 -69
- package/skills/equity/skill.md +0 -64
- package/skills/market-radar/skill.md +0 -47
package/index.ts
CHANGED
|
@@ -20,10 +20,13 @@ function buildParams(params: Record<string, unknown>): Record<string, string> {
|
|
|
20
20
|
if (params.start_date) out.start_date = String(params.start_date);
|
|
21
21
|
if (params.end_date) out.end_date = String(params.end_date);
|
|
22
22
|
if (params.trade_date) out.trade_date = String(params.trade_date);
|
|
23
|
+
if (params.date) out.date = String(params.date);
|
|
23
24
|
if (params.limit) out.limit = String(params.limit);
|
|
24
25
|
if (params.provider) out.provider = String(params.provider);
|
|
25
26
|
if (params.country) out.country = String(params.country);
|
|
26
27
|
if (params.indicator) out.indicator = String(params.indicator);
|
|
28
|
+
if (params.manager) out.manager = String(params.manager);
|
|
29
|
+
if (params.hs_type) out.hs_type = String(params.hs_type);
|
|
27
30
|
return out;
|
|
28
31
|
}
|
|
29
32
|
|
|
@@ -37,14 +40,21 @@ const findooDatahubPlugin = {
|
|
|
37
40
|
"172 endpoints covering equity (A/HK/US), crypto, macro, derivatives, index, ETF.",
|
|
38
41
|
kind: "financial" as const,
|
|
39
42
|
|
|
40
|
-
|
|
43
|
+
register(api: OpenClawPluginApi) {
|
|
41
44
|
const config = resolveConfig(api);
|
|
42
45
|
|
|
43
46
|
// --- DataHub client ---
|
|
47
|
+
if (!config.datahubApiKey) {
|
|
48
|
+
api.log?.(
|
|
49
|
+
"warn",
|
|
50
|
+
"findoo-datahub-plugin: no API key configured. Set DATAHUB_API_KEY env var or plugins.findoo-datahub-plugin.datahubApiKey in config. Using built-in dev key.",
|
|
51
|
+
);
|
|
52
|
+
}
|
|
53
|
+
|
|
44
54
|
const client = new DataHubClient(
|
|
45
55
|
config.datahubApiUrl,
|
|
46
56
|
config.datahubUsername,
|
|
47
|
-
config.
|
|
57
|
+
config.datahubApiKey ?? "98ffa5c5-1ec6-4735-8e0c-715a5eca1a8d",
|
|
48
58
|
config.requestTimeoutMs,
|
|
49
59
|
);
|
|
50
60
|
|
|
@@ -118,7 +128,7 @@ const findooDatahubPlugin = {
|
|
|
118
128
|
} as Parameters<typeof api.registerService>[0]);
|
|
119
129
|
|
|
120
130
|
// ============================================================
|
|
121
|
-
// AI Tools (
|
|
131
|
+
// AI Tools (13 total)
|
|
122
132
|
// ============================================================
|
|
123
133
|
|
|
124
134
|
// === Tool 1: fin_stock — Equity data ===
|
|
@@ -127,7 +137,7 @@ const findooDatahubPlugin = {
|
|
|
127
137
|
name: "fin_stock",
|
|
128
138
|
label: "Stock Data (A/HK/US)",
|
|
129
139
|
description:
|
|
130
|
-
"Fetch A-share, HK, or US equity data — quotes, historical prices, income
|
|
140
|
+
"Fetch A-share, HK, or US equity data — quotes, historical prices, financials (income/balance/cash/ratios/metrics + VIP variants), ownership (top10/shareholder_trade/repurchase/pledge), money flow, concept lists, calendar (earnings/ipo), discovery (gainers/losers), HK subset (hk/*), US subset (us/*). Notes: estimates/consensus is yfinance-only (US/HK, rate-limited, NOT for A-share — use fundamental/earnings_forecast instead). fundamental/stock_factor returns pre-computed MACD/KDJ/RSI/BOLL/CCI. market/stock_limit requires symbol param (no batch scan by date).",
|
|
131
141
|
parameters: Type.Object({
|
|
132
142
|
symbol: Type.String({
|
|
133
143
|
description: "Stock code. A-shares: 600519.SH; HK: 00700.HK; US: AAPL",
|
|
@@ -136,17 +146,81 @@ const findooDatahubPlugin = {
|
|
|
136
146
|
type: "string",
|
|
137
147
|
enum: [
|
|
138
148
|
"price/historical",
|
|
149
|
+
"price/quote",
|
|
150
|
+
"profile",
|
|
151
|
+
"search",
|
|
152
|
+
"screener",
|
|
153
|
+
// fundamentals — A-share
|
|
139
154
|
"fundamental/income",
|
|
140
155
|
"fundamental/balance",
|
|
141
156
|
"fundamental/cash",
|
|
142
157
|
"fundamental/ratios",
|
|
143
158
|
"fundamental/metrics",
|
|
144
159
|
"fundamental/dividends",
|
|
160
|
+
"fundamental/adj_factor",
|
|
161
|
+
"fundamental/earnings_forecast",
|
|
162
|
+
"fundamental/financial_audit",
|
|
163
|
+
"fundamental/financial_express",
|
|
164
|
+
"fundamental/forecast_vip",
|
|
165
|
+
"fundamental/revenue_per_segment",
|
|
166
|
+
"fundamental/management",
|
|
167
|
+
// ownership & structure
|
|
145
168
|
"ownership/top10_holders",
|
|
169
|
+
"ownership/top10_float_holders",
|
|
170
|
+
"ownership/major_holders",
|
|
171
|
+
"ownership/shareholder_trade",
|
|
172
|
+
"ownership/repurchase",
|
|
173
|
+
"ownership/share_float",
|
|
174
|
+
"ownership/holder_number",
|
|
175
|
+
"ownership/share_statistics",
|
|
176
|
+
"pledge/stat",
|
|
177
|
+
"pledge/detail",
|
|
178
|
+
// money flow & market
|
|
146
179
|
"moneyflow/individual",
|
|
147
180
|
"market/top_list",
|
|
181
|
+
// discovery & calendar
|
|
148
182
|
"discovery/gainers",
|
|
149
183
|
"discovery/losers",
|
|
184
|
+
"discovery/active",
|
|
185
|
+
"discovery/undervalued_growth",
|
|
186
|
+
"discovery/undervalued_large_caps",
|
|
187
|
+
"discovery/growth_tech",
|
|
188
|
+
"discovery/aggressive_small_caps",
|
|
189
|
+
"discovery/name_change",
|
|
190
|
+
"calendar/earnings",
|
|
191
|
+
"calendar/ipo",
|
|
192
|
+
"compare/peers",
|
|
193
|
+
"shorts/short_volume",
|
|
194
|
+
"concept/concept_detail",
|
|
195
|
+
"concept/concept_list",
|
|
196
|
+
// estimates (yfinance only — US/HK stocks, not A-share; may hit rate limits)
|
|
197
|
+
"estimates/consensus",
|
|
198
|
+
// additional fundamentals (VIP / tushare-only)
|
|
199
|
+
"fundamental/backup_daily",
|
|
200
|
+
"fundamental/balance_vip",
|
|
201
|
+
"fundamental/cashflow_vip",
|
|
202
|
+
"fundamental/dividend_detail",
|
|
203
|
+
"fundamental/historical_splits",
|
|
204
|
+
"fundamental/income_vip",
|
|
205
|
+
"fundamental/revenue_segment_vip",
|
|
206
|
+
"fundamental/stock_factor",
|
|
207
|
+
// HK
|
|
208
|
+
"hk/income",
|
|
209
|
+
"hk/balancesheet",
|
|
210
|
+
"hk/cashflow",
|
|
211
|
+
"hk/fina_indicator",
|
|
212
|
+
"hk/basic",
|
|
213
|
+
"hk/hold",
|
|
214
|
+
"hk/adj_factor",
|
|
215
|
+
"hk/trade_cal",
|
|
216
|
+
// US
|
|
217
|
+
"us/income",
|
|
218
|
+
"us/balancesheet",
|
|
219
|
+
"us/cashflow",
|
|
220
|
+
"us/fina_indicator",
|
|
221
|
+
"us/basic",
|
|
222
|
+
"us/adj_factor",
|
|
223
|
+
"us/trade_cal",
|
|
150
224
|
],
|
|
151
225
|
description: "DataHub equity endpoint path",
|
|
152
226
|
}),
|
|
@@ -182,7 +256,7 @@ const findooDatahubPlugin = {
|
|
|
182
256
|
name: "fin_index",
|
|
183
257
|
label: "Index / ETF / Fund",
|
|
184
258
|
description:
|
|
185
|
-
"Query index constituents, valuations,
|
|
259
|
+
"Query index data — constituents, daily valuations (PE/PB via daily_basic), thematic/concept indices (ths_index/ths_daily/ths_member), classification, global indices. Use constituents (not members) for index composition.",
|
|
186
260
|
parameters: Type.Object({
|
|
187
261
|
symbol: Type.Optional(
|
|
188
262
|
Type.String({ description: "Index/ETF/fund code. Index: 000300.SH; ETF: 510050.SH" }),
|
|
@@ -193,6 +267,10 @@ const findooDatahubPlugin = {
|
|
|
193
267
|
"price/historical",
|
|
194
268
|
"constituents",
|
|
195
269
|
"daily_basic",
|
|
270
|
+
"available",
|
|
271
|
+
"info",
|
|
272
|
+
"classify",
|
|
273
|
+
"global_index",
|
|
196
274
|
"thematic/ths_index",
|
|
197
275
|
"thematic/ths_daily",
|
|
198
276
|
"thematic/ths_member",
|
|
@@ -228,7 +306,7 @@ const findooDatahubPlugin = {
|
|
|
228
306
|
name: "fin_macro",
|
|
229
307
|
label: "Macro / Rates / FX",
|
|
230
308
|
description:
|
|
231
|
-
"China macro (GDP/CPI/PPI/PMI/M2), interest rates (Shibor/LPR/Libor/Hibor), treasury yields, FX, WorldBank data.",
|
|
309
|
+
"China macro (GDP/CPI/PPI/PMI/M2/social financing), interest rates (Shibor/LPR/Libor/Hibor), CN/US treasury yields, FX rates (currency/*), WorldBank data (worldbank/*), economic calendar, fixedincome rate aliases (fixedincome/rate/*). Notes: LIBOR terminated 2023 (data stops 2020-06). fixedincome/rate/* are aliases for shibor/libor/hibor. worldbank/country provides country classification for EM vs DM analysis.",
|
|
232
310
|
parameters: Type.Object({
|
|
233
311
|
endpoint: Type.Unsafe<string>({
|
|
234
312
|
type: "string",
|
|
@@ -241,18 +319,29 @@ const findooDatahubPlugin = {
|
|
|
241
319
|
"social_financing",
|
|
242
320
|
"shibor",
|
|
243
321
|
"shibor_lpr",
|
|
322
|
+
"shibor_quote",
|
|
244
323
|
"libor",
|
|
245
324
|
"hibor",
|
|
246
325
|
"treasury_cn",
|
|
247
326
|
"treasury_us",
|
|
248
327
|
"index_global",
|
|
328
|
+
"wz_index",
|
|
249
329
|
"calendar",
|
|
330
|
+
"currency/price/historical",
|
|
331
|
+
"currency/search",
|
|
332
|
+
"currency/snapshots",
|
|
333
|
+
"worldbank/country",
|
|
250
334
|
"worldbank/gdp",
|
|
251
335
|
"worldbank/population",
|
|
252
336
|
"worldbank/inflation",
|
|
253
337
|
"worldbank/indicator",
|
|
338
|
+
// fixedincome (dedicated DataHub paths, same data as shibor/libor/hibor)
|
|
339
|
+
"fixedincome/rate/shibor",
|
|
340
|
+
"fixedincome/rate/shibor_lpr",
|
|
341
|
+
"fixedincome/rate/libor",
|
|
342
|
+
"fixedincome/rate/hibor",
|
|
254
343
|
],
|
|
255
|
-
description: "DataHub economy endpoint path",
|
|
344
|
+
description: "DataHub economy/currency endpoint path",
|
|
256
345
|
}),
|
|
257
346
|
symbol: Type.Optional(Type.String({ description: "Currency pair or indicator code" })),
|
|
258
347
|
country: Type.Optional(Type.String({ description: "Country code for WorldBank" })),
|
|
@@ -264,10 +353,22 @@ const findooDatahubPlugin = {
|
|
|
264
353
|
try {
|
|
265
354
|
const endpoint = String(params.endpoint ?? "cpi");
|
|
266
355
|
const qp = buildParams(params);
|
|
267
|
-
|
|
356
|
+
// Route currency/* and fixedincome/* endpoints to their categories
|
|
357
|
+
let results: unknown[];
|
|
358
|
+
let category: string;
|
|
359
|
+
if (endpoint.startsWith("currency/")) {
|
|
360
|
+
results = await client.currency(endpoint.replace("currency/", ""), qp);
|
|
361
|
+
category = "currency";
|
|
362
|
+
} else if (endpoint.startsWith("fixedincome/")) {
|
|
363
|
+
results = await client.query(endpoint, qp);
|
|
364
|
+
category = "fixedincome";
|
|
365
|
+
} else {
|
|
366
|
+
results = await client.economy(endpoint, qp);
|
|
367
|
+
category = "economy";
|
|
368
|
+
}
|
|
268
369
|
return json({
|
|
269
370
|
success: true,
|
|
270
|
-
endpoint:
|
|
371
|
+
endpoint: `${category}/${endpoint.startsWith("currency/") ? endpoint.replace("currency/", "") : endpoint}`,
|
|
271
372
|
count: results.length,
|
|
272
373
|
results,
|
|
273
374
|
});
|
|
@@ -285,7 +386,7 @@ const findooDatahubPlugin = {
|
|
|
285
386
|
name: "fin_derivatives",
|
|
286
387
|
label: "Futures / Options / CB",
|
|
287
388
|
description:
|
|
288
|
-
"Futures (daily, holdings, settlement, warehouse, mapping), options (basic, daily, chains), convertible bonds.",
|
|
389
|
+
"Futures (daily OHLCV, holdings/OI, settlement, warehouse receipts, contract mapping, term structure curve), options (basic info, daily, chains with Greeks/IV), convertible bonds (basic, daily). Use futures/curve for contango/backwardation analysis.",
|
|
289
390
|
parameters: Type.Object({
|
|
290
391
|
symbol: Type.Optional(
|
|
291
392
|
Type.String({ description: "Contract code, e.g. IF2501.CFX, 113xxx.SH (CB)" }),
|
|
@@ -299,6 +400,7 @@ const findooDatahubPlugin = {
|
|
|
299
400
|
"futures/settle",
|
|
300
401
|
"futures/warehouse",
|
|
301
402
|
"futures/mapping",
|
|
403
|
+
"futures/curve",
|
|
302
404
|
"options/basic",
|
|
303
405
|
"options/daily",
|
|
304
406
|
"options/chains",
|
|
@@ -337,7 +439,7 @@ const findooDatahubPlugin = {
|
|
|
337
439
|
name: "fin_crypto",
|
|
338
440
|
label: "Crypto & DeFi",
|
|
339
441
|
description:
|
|
340
|
-
"Crypto market data (
|
|
442
|
+
"Crypto market data (ticker/orderbook/trades/funding_rate) via CEX, DeFi (protocols/TVL/yields/stablecoins/fees/dex_volumes/bridges/chains) via DefiLlama, market metrics (coin/market/info/categories/trending/global_stats) via CoinGecko. price/historical for crypto OHLCV, search for symbol lookup.",
|
|
341
443
|
parameters: Type.Object({
|
|
342
444
|
endpoint: Type.Unsafe<string>({
|
|
343
445
|
type: "string",
|
|
@@ -361,19 +463,42 @@ const findooDatahubPlugin = {
|
|
|
361
463
|
"defi/stablecoins",
|
|
362
464
|
"defi/fees",
|
|
363
465
|
"defi/dex_volumes",
|
|
466
|
+
"defi/bridges",
|
|
364
467
|
"defi/coin_prices",
|
|
468
|
+
"price/historical",
|
|
469
|
+
"search",
|
|
365
470
|
],
|
|
366
471
|
description: "DataHub crypto endpoint path",
|
|
367
472
|
}),
|
|
368
473
|
symbol: Type.Optional(
|
|
369
474
|
Type.String({ description: "Coin ID, trading pair, or protocol slug" }),
|
|
370
475
|
),
|
|
476
|
+
start_date: Type.Optional(
|
|
477
|
+
Type.String({ description: "Start date for coin/historical (YYYY-MM-DD)" }),
|
|
478
|
+
),
|
|
479
|
+
end_date: Type.Optional(
|
|
480
|
+
Type.String({ description: "End date for coin/historical (YYYY-MM-DD)" }),
|
|
481
|
+
),
|
|
371
482
|
limit: Type.Optional(Type.Number()),
|
|
372
483
|
}),
|
|
373
484
|
async execute(_toolCallId: string, params: Record<string, unknown>) {
|
|
374
485
|
try {
|
|
375
486
|
const endpoint = String(params.endpoint ?? "coin/market");
|
|
376
487
|
const qp = buildParams(params);
|
|
488
|
+
// Endpoint-specific param mapping for crypto APIs
|
|
489
|
+
if (qp.symbol) {
|
|
490
|
+
const coinIdEndpoints = ["coin/historical", "coin/info"];
|
|
491
|
+
if (coinIdEndpoints.includes(endpoint)) {
|
|
492
|
+
qp.coin_id = qp.symbol;
|
|
493
|
+
delete qp.symbol;
|
|
494
|
+
} else if (endpoint === "defi/protocol_tvl") {
|
|
495
|
+
qp.protocol = qp.symbol;
|
|
496
|
+
delete qp.symbol;
|
|
497
|
+
} else if (endpoint === "defi/coin_prices") {
|
|
498
|
+
qp.coins = qp.symbol;
|
|
499
|
+
delete qp.symbol;
|
|
500
|
+
}
|
|
501
|
+
}
|
|
377
502
|
const results = await client.crypto(endpoint, qp);
|
|
378
503
|
return json({
|
|
379
504
|
success: true,
|
|
@@ -395,7 +520,7 @@ const findooDatahubPlugin = {
|
|
|
395
520
|
name: "fin_market",
|
|
396
521
|
label: "Market Radar",
|
|
397
522
|
description:
|
|
398
|
-
"
|
|
523
|
+
"A-share market monitoring — dragon-tiger list (top_list/top_inst), limit-up/down stats (limit_list), block trades, sector money flow (moneyflow/industry), margin (summary/detail/trading), Stock Connect northbound (hsgt_flow/hsgt_top10) and southbound (ggt_daily/ggt_monthly), market snapshots, discovery (gainers/losers/active/new_share). Notes: flow/hsgt_top10 requires 'date' param (NOT trade_date). flow/hs_const requires 'hs_type' param (SH or SZ). market/stock_limit requires 'symbol' (no date-only scan). market_snapshots returns full market snapshot (12000+ records, no params needed).",
|
|
399
524
|
parameters: Type.Object({
|
|
400
525
|
endpoint: Type.Unsafe<string>({
|
|
401
526
|
type: "string",
|
|
@@ -410,8 +535,14 @@ const findooDatahubPlugin = {
|
|
|
410
535
|
"moneyflow/block_trade",
|
|
411
536
|
"margin/summary",
|
|
412
537
|
"margin/detail",
|
|
538
|
+
"margin/trading",
|
|
413
539
|
"flow/hsgt_flow",
|
|
414
540
|
"flow/hsgt_top10",
|
|
541
|
+
"flow/ggt_daily",
|
|
542
|
+
"flow/ggt_monthly",
|
|
543
|
+
"flow/hs_const",
|
|
544
|
+
"market/stock_limit",
|
|
545
|
+
"market_snapshots",
|
|
415
546
|
"discovery/gainers",
|
|
416
547
|
"discovery/losers",
|
|
417
548
|
"discovery/active",
|
|
@@ -420,7 +551,19 @@ const findooDatahubPlugin = {
|
|
|
420
551
|
description: "DataHub equity endpoint for market data",
|
|
421
552
|
}),
|
|
422
553
|
trade_date: Type.Optional(Type.String({ description: "Trade date, e.g. 2025-02-28" })),
|
|
554
|
+
date: Type.Optional(
|
|
555
|
+
Type.String({
|
|
556
|
+
description:
|
|
557
|
+
"Date param for hsgt_top10 (uses 'date' not 'trade_date'), e.g. 2025-02-28",
|
|
558
|
+
}),
|
|
559
|
+
),
|
|
423
560
|
symbol: Type.Optional(Type.String({ description: "Symbol for specific queries" })),
|
|
561
|
+
hs_type: Type.Optional(
|
|
562
|
+
Type.String({
|
|
563
|
+
description:
|
|
564
|
+
"Stock Connect type for hs_const: SH (northbound) or SZ (northbound Shenzhen)",
|
|
565
|
+
}),
|
|
566
|
+
),
|
|
424
567
|
start_date: Type.Optional(Type.String()),
|
|
425
568
|
end_date: Type.Optional(Type.String()),
|
|
426
569
|
limit: Type.Optional(Type.Number()),
|
|
@@ -429,6 +572,17 @@ const findooDatahubPlugin = {
|
|
|
429
572
|
try {
|
|
430
573
|
const endpoint = String(params.endpoint ?? "market/top_list");
|
|
431
574
|
const qp = buildParams(params);
|
|
575
|
+
// Auto-alias: trade_date→date for endpoints that use 'date' param
|
|
576
|
+
const dateEndpoints = [
|
|
577
|
+
"market/top_list",
|
|
578
|
+
"market/top_inst",
|
|
579
|
+
"market/limit_list",
|
|
580
|
+
"flow/hsgt_top10",
|
|
581
|
+
];
|
|
582
|
+
if (qp.trade_date && !qp.date && dateEndpoints.includes(endpoint)) {
|
|
583
|
+
qp.date = qp.trade_date;
|
|
584
|
+
delete qp.trade_date;
|
|
585
|
+
}
|
|
432
586
|
const results = await client.equity(endpoint, qp);
|
|
433
587
|
return json({
|
|
434
588
|
success: true,
|
|
@@ -450,7 +604,7 @@ const findooDatahubPlugin = {
|
|
|
450
604
|
name: "fin_query",
|
|
451
605
|
label: "Raw DataHub Query",
|
|
452
606
|
description:
|
|
453
|
-
"Direct passthrough to any of
|
|
607
|
+
"Direct passthrough to any of 168 DataHub endpoints by path. Use when other tools don't cover the specific data. Accepts arbitrary query params. Example paths: equity/fundamental/income, crypto/defi/protocols, economy/cpi, fixedincome/rate/shibor.",
|
|
454
608
|
parameters: Type.Object({
|
|
455
609
|
path: Type.String({
|
|
456
610
|
description:
|
|
@@ -575,7 +729,171 @@ const findooDatahubPlugin = {
|
|
|
575
729
|
{ names: ["fin_data_regime"] },
|
|
576
730
|
);
|
|
577
731
|
|
|
578
|
-
// === Tool 10:
|
|
732
|
+
// === Tool 10: fin_ta — Technical Analysis Indicators ===
|
|
733
|
+
api.registerTool(
|
|
734
|
+
{
|
|
735
|
+
name: "fin_ta",
|
|
736
|
+
label: "Technical Analysis",
|
|
737
|
+
description:
|
|
738
|
+
"Calculate technical indicators (SMA, EMA, RSI, MACD, Bollinger Bands) for any symbol. DataHub fetches OHLCV and computes server-side.",
|
|
739
|
+
parameters: Type.Object({
|
|
740
|
+
symbol: Type.String({
|
|
741
|
+
description:
|
|
742
|
+
"Stock/crypto symbol. A: 600519.SH; HK: 00700.HK; US: AAPL; Crypto: BTC-USDT",
|
|
743
|
+
}),
|
|
744
|
+
indicator: Type.Unsafe<string>({
|
|
745
|
+
type: "string",
|
|
746
|
+
enum: ["sma", "ema", "rsi", "macd", "bbands"],
|
|
747
|
+
description: "Technical indicator to calculate",
|
|
748
|
+
}),
|
|
749
|
+
period: Type.Optional(
|
|
750
|
+
Type.Number({
|
|
751
|
+
description: "Indicator period (default: 20 for SMA/EMA/BBANDS, 14 for RSI)",
|
|
752
|
+
}),
|
|
753
|
+
),
|
|
754
|
+
limit: Type.Optional(
|
|
755
|
+
Type.Number({ description: "Number of OHLCV bars to fetch (default: 200)" }),
|
|
756
|
+
),
|
|
757
|
+
fast: Type.Optional(Type.Number({ description: "MACD fast period (default: 12)" })),
|
|
758
|
+
slow: Type.Optional(Type.Number({ description: "MACD slow period (default: 26)" })),
|
|
759
|
+
signal: Type.Optional(Type.Number({ description: "MACD signal period (default: 9)" })),
|
|
760
|
+
std: Type.Optional(
|
|
761
|
+
Type.Number({ description: "Bollinger Bands std dev (default: 2.0)" }),
|
|
762
|
+
),
|
|
763
|
+
provider: Type.Optional(
|
|
764
|
+
Type.String({ description: "Data provider override (auto-detected if omitted)" }),
|
|
765
|
+
),
|
|
766
|
+
}),
|
|
767
|
+
async execute(_toolCallId: string, params: Record<string, unknown>) {
|
|
768
|
+
try {
|
|
769
|
+
const indicator = String(params.indicator ?? "sma");
|
|
770
|
+
const qp: Record<string, string> = {};
|
|
771
|
+
if (params.symbol) qp.symbol = String(params.symbol);
|
|
772
|
+
if (params.period) qp.period = String(params.period);
|
|
773
|
+
if (params.limit) qp.limit = String(params.limit);
|
|
774
|
+
if (params.fast) qp.fast = String(params.fast);
|
|
775
|
+
if (params.slow) qp.slow = String(params.slow);
|
|
776
|
+
if (params.signal) qp.signal = String(params.signal);
|
|
777
|
+
if (params.std) qp.std = String(params.std);
|
|
778
|
+
if (params.provider) qp.provider = String(params.provider);
|
|
779
|
+
const results = await client.ta(indicator, qp);
|
|
780
|
+
return json({
|
|
781
|
+
success: true,
|
|
782
|
+
endpoint: `ta/${indicator}`,
|
|
783
|
+
count: results.length,
|
|
784
|
+
results,
|
|
785
|
+
});
|
|
786
|
+
} catch (err) {
|
|
787
|
+
return json({ error: err instanceof Error ? err.message : String(err) });
|
|
788
|
+
}
|
|
789
|
+
},
|
|
790
|
+
},
|
|
791
|
+
{ names: ["fin_ta"] },
|
|
792
|
+
);
|
|
793
|
+
|
|
794
|
+
// === Tool 11: fin_etf — ETF & Fund Data ===
|
|
795
|
+
api.registerTool(
|
|
796
|
+
{
|
|
797
|
+
name: "fin_etf",
|
|
798
|
+
label: "ETF & Fund",
|
|
799
|
+
description:
|
|
800
|
+
"ETF and fund data — NAV history, fund info (type/size/fees), historical prices, portfolio holdings (top 10, quarterly), manager track record, dividends, share changes (subscription/redemption trends), adjusted NAV (dividend-reinvested), search. Use fund/manager with a known fund code to find manager info; manager param available for search.",
|
|
801
|
+
parameters: Type.Object({
|
|
802
|
+
symbol: Type.Optional(
|
|
803
|
+
Type.String({
|
|
804
|
+
description: "ETF/Fund code. ETF: 510050.SH; Fund: 110011",
|
|
805
|
+
}),
|
|
806
|
+
),
|
|
807
|
+
manager: Type.Optional(
|
|
808
|
+
Type.String({
|
|
809
|
+
description: "Fund manager name for search endpoint (e.g. 张坤)",
|
|
810
|
+
}),
|
|
811
|
+
),
|
|
812
|
+
endpoint: Type.Unsafe<string>({
|
|
813
|
+
type: "string",
|
|
814
|
+
enum: [
|
|
815
|
+
"nav",
|
|
816
|
+
"info",
|
|
817
|
+
"historical",
|
|
818
|
+
"fund/portfolio",
|
|
819
|
+
"fund/manager",
|
|
820
|
+
"fund/dividends",
|
|
821
|
+
"fund/share",
|
|
822
|
+
"fund/adj_nav",
|
|
823
|
+
"search",
|
|
824
|
+
],
|
|
825
|
+
description: "DataHub ETF/fund endpoint path",
|
|
826
|
+
}),
|
|
827
|
+
start_date: Type.Optional(Type.String({ description: "Start date, e.g. 2025-01-01" })),
|
|
828
|
+
end_date: Type.Optional(Type.String({ description: "End date, e.g. 2025-12-31" })),
|
|
829
|
+
limit: Type.Optional(Type.Number({ description: "Max records to return" })),
|
|
830
|
+
}),
|
|
831
|
+
async execute(_toolCallId: string, params: Record<string, unknown>) {
|
|
832
|
+
try {
|
|
833
|
+
const endpoint = String(params.endpoint ?? "info");
|
|
834
|
+
const qp = buildParams(params);
|
|
835
|
+
const results = await client.etf(endpoint, qp);
|
|
836
|
+
return json({
|
|
837
|
+
success: true,
|
|
838
|
+
endpoint: `etf/${endpoint}`,
|
|
839
|
+
count: results.length,
|
|
840
|
+
results,
|
|
841
|
+
});
|
|
842
|
+
} catch (err) {
|
|
843
|
+
return json({ error: err instanceof Error ? err.message : String(err) });
|
|
844
|
+
}
|
|
845
|
+
},
|
|
846
|
+
},
|
|
847
|
+
{ names: ["fin_etf"] },
|
|
848
|
+
);
|
|
849
|
+
|
|
850
|
+
// === Tool 12: fin_currency — FX & News ===
|
|
851
|
+
api.registerTool(
|
|
852
|
+
{
|
|
853
|
+
name: "fin_currency",
|
|
854
|
+
label: "FX & News",
|
|
855
|
+
description:
|
|
856
|
+
"Foreign exchange rates (price/historical, search, snapshots) and company news (news/company). Major pairs: USDCNH, EURUSD, USDJPY. Use search to find available currency pair symbols.",
|
|
857
|
+
parameters: Type.Object({
|
|
858
|
+
endpoint: Type.Unsafe<string>({
|
|
859
|
+
type: "string",
|
|
860
|
+
enum: ["price/historical", "search", "snapshots", "news/company"],
|
|
861
|
+
description: "DataHub currency/news endpoint path",
|
|
862
|
+
}),
|
|
863
|
+
symbol: Type.Optional(
|
|
864
|
+
Type.String({
|
|
865
|
+
description: "Currency pair (USDCNH, EURUSD) or stock symbol for news (AAPL)",
|
|
866
|
+
}),
|
|
867
|
+
),
|
|
868
|
+
start_date: Type.Optional(Type.String({ description: "Start date, e.g. 2025-01-01" })),
|
|
869
|
+
end_date: Type.Optional(Type.String({ description: "End date, e.g. 2025-12-31" })),
|
|
870
|
+
limit: Type.Optional(Type.Number({ description: "Max records to return" })),
|
|
871
|
+
}),
|
|
872
|
+
async execute(_toolCallId: string, params: Record<string, unknown>) {
|
|
873
|
+
try {
|
|
874
|
+
const endpoint = String(params.endpoint ?? "price/historical");
|
|
875
|
+
const qp = buildParams(params);
|
|
876
|
+
// Route news/* to the generic query path
|
|
877
|
+
const results =
|
|
878
|
+
endpoint === "news/company"
|
|
879
|
+
? await client.query(`news/company`, qp)
|
|
880
|
+
: await client.currency(endpoint, qp);
|
|
881
|
+
const category = endpoint === "news/company" ? "news" : "currency";
|
|
882
|
+
return json({
|
|
883
|
+
success: true,
|
|
884
|
+
endpoint: `${category}/${endpoint === "news/company" ? "company" : endpoint}`,
|
|
885
|
+
count: results.length,
|
|
886
|
+
results,
|
|
887
|
+
});
|
|
888
|
+
} catch (err) {
|
|
889
|
+
return json({ error: err instanceof Error ? err.message : String(err) });
|
|
890
|
+
}
|
|
891
|
+
},
|
|
892
|
+
},
|
|
893
|
+
{ names: ["fin_currency"] },
|
|
894
|
+
);
|
|
895
|
+
|
|
896
|
+
// === Tool 13: fin_data_markets — Supported Markets ===
|
|
579
897
|
api.registerTool(
|
|
580
898
|
{
|
|
581
899
|
name: "fin_data_markets",
|
package/openclaw.plugin.json
CHANGED
|
@@ -18,9 +18,9 @@
|
|
|
18
18
|
"default": "admin",
|
|
19
19
|
"description": "DataHub HTTP Basic Auth username"
|
|
20
20
|
},
|
|
21
|
-
"
|
|
21
|
+
"datahubApiKey": {
|
|
22
22
|
"type": "string",
|
|
23
|
-
"description": "DataHub
|
|
23
|
+
"description": "DataHub API key (required). Set via config or DATAHUB_API_KEY env var.",
|
|
24
24
|
"sensitive": true
|
|
25
25
|
},
|
|
26
26
|
"requestTimeoutMs": {
|
package/package.json
CHANGED