tickflow-assist 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +151 -0
- package/day_future.txt +8797 -0
- package/dist/analysis/orchestrators/composite-analysis.orchestrator.d.ts +35 -0
- package/dist/analysis/orchestrators/composite-analysis.orchestrator.js +232 -0
- package/dist/analysis/parsers/json-block.parser.d.ts +1 -0
- package/dist/analysis/parsers/json-block.parser.js +13 -0
- package/dist/analysis/parsers/key-levels.parser.d.ts +5 -0
- package/dist/analysis/parsers/key-levels.parser.js +61 -0
- package/dist/analysis/parsers/post-close-review.parser.d.ts +2 -0
- package/dist/analysis/parsers/post-close-review.parser.js +79 -0
- package/dist/analysis/parsers/watchlist-profile.parser.d.ts +6 -0
- package/dist/analysis/parsers/watchlist-profile.parser.js +93 -0
- package/dist/analysis/providers/financial-analysis.provider.d.ts +12 -0
- package/dist/analysis/providers/financial-analysis.provider.js +85 -0
- package/dist/analysis/providers/market-analysis.provider.d.ts +27 -0
- package/dist/analysis/providers/market-analysis.provider.js +187 -0
- package/dist/analysis/providers/news-analysis.provider.d.ts +9 -0
- package/dist/analysis/providers/news-analysis.provider.js +60 -0
- package/dist/analysis/tasks/analysis-step-task.d.ts +11 -0
- package/dist/analysis/tasks/analysis-step-task.js +1 -0
- package/dist/analysis/tasks/analysis-task.d.ts +13 -0
- package/dist/analysis/tasks/analysis-task.js +1 -0
- package/dist/analysis/tasks/composite-stock-analysis.task.d.ts +17 -0
- package/dist/analysis/tasks/composite-stock-analysis.task.js +47 -0
- package/dist/analysis/tasks/financial-fundamental-lite.task.d.ts +10 -0
- package/dist/analysis/tasks/financial-fundamental-lite.task.js +21 -0
- package/dist/analysis/tasks/financial-fundamental.task.d.ts +12 -0
- package/dist/analysis/tasks/financial-fundamental.task.js +64 -0
- package/dist/analysis/tasks/kline-technical-signal.task.d.ts +10 -0
- package/dist/analysis/tasks/kline-technical-signal.task.js +41 -0
- package/dist/analysis/tasks/kline-technical.task.d.ts +32 -0
- package/dist/analysis/tasks/kline-technical.task.js +61 -0
- package/dist/analysis/tasks/news-catalyst.task.d.ts +11 -0
- package/dist/analysis/tasks/news-catalyst.task.js +62 -0
- package/dist/analysis/tasks/post-close-review.task.d.ts +12 -0
- package/dist/analysis/tasks/post-close-review.task.js +35 -0
- package/dist/analysis/types/composite-analysis.d.ts +123 -0
- package/dist/analysis/types/composite-analysis.js +1 -0
- package/dist/background/daily-update.worker.d.ts +50 -0
- package/dist/background/daily-update.worker.js +546 -0
- package/dist/background/realtime-monitor.worker.d.ts +8 -0
- package/dist/background/realtime-monitor.worker.js +28 -0
- package/dist/bootstrap.d.ts +45 -0
- package/dist/bootstrap.js +214 -0
- package/dist/config/normalize.d.ts +4 -0
- package/dist/config/normalize.js +99 -0
- package/dist/config/schema.d.ts +23 -0
- package/dist/config/schema.js +18 -0
- package/dist/config/tickflow-access.d.ts +4 -0
- package/dist/config/tickflow-access.js +28 -0
- package/dist/constants/market-indexes.d.ts +5 -0
- package/dist/constants/market-indexes.js +4 -0
- package/dist/dev/run-daily-update-loop.d.ts +1 -0
- package/dist/dev/run-daily-update-loop.js +48 -0
- package/dist/dev/run-monitor-loop.d.ts +1 -0
- package/dist/dev/run-monitor-loop.js +60 -0
- package/dist/dev/run-tool.d.ts +1 -0
- package/dist/dev/run-tool.js +49 -0
- package/dist/dev/tickflow-assist-cli.d.ts +2 -0
- package/dist/dev/tickflow-assist-cli.js +525 -0
- package/dist/dev/validate-mx-search.d.ts +1 -0
- package/dist/dev/validate-mx-search.js +212 -0
- package/dist/plugin-commands.d.ts +3 -0
- package/dist/plugin-commands.js +229 -0
- package/dist/plugin.d.ts +8 -0
- package/dist/plugin.js +151 -0
- package/dist/prompts/analysis/common-system-prompt.d.ts +1 -0
- package/dist/prompts/analysis/common-system-prompt.js +44 -0
- package/dist/prompts/analysis/composite-analysis-user-prompt.d.ts +11 -0
- package/dist/prompts/analysis/composite-analysis-user-prompt.js +102 -0
- package/dist/prompts/analysis/financial-analysis-user-prompt.d.ts +7 -0
- package/dist/prompts/analysis/financial-analysis-user-prompt.js +106 -0
- package/dist/prompts/analysis/financial-lite-analysis-user-prompt.d.ts +7 -0
- package/dist/prompts/analysis/financial-lite-analysis-user-prompt.js +59 -0
- package/dist/prompts/analysis/index.d.ts +8 -0
- package/dist/prompts/analysis/index.js +8 -0
- package/dist/prompts/analysis/kline-analysis-user-prompt.d.ts +13 -0
- package/dist/prompts/analysis/kline-analysis-user-prompt.js +215 -0
- package/dist/prompts/analysis/news-analysis-user-prompt.d.ts +8 -0
- package/dist/prompts/analysis/news-analysis-user-prompt.js +57 -0
- package/dist/prompts/analysis/post-close-review-user-prompt.d.ts +3 -0
- package/dist/prompts/analysis/post-close-review-user-prompt.js +129 -0
- package/dist/prompts/analysis/watchlist-profile-extraction-prompt.d.ts +7 -0
- package/dist/prompts/analysis/watchlist-profile-extraction-prompt.js +52 -0
- package/dist/prompts/analysis-system-prompt.d.ts +1 -0
- package/dist/prompts/analysis-system-prompt.js +1 -0
- package/dist/prompts/analysis-user-prompt.d.ts +1 -0
- package/dist/prompts/analysis-user-prompt.js +1 -0
- package/dist/runtime/daily-update-process.d.ts +3 -0
- package/dist/runtime/daily-update-process.js +24 -0
- package/dist/runtime/monitor-process.d.ts +3 -0
- package/dist/runtime/monitor-process.js +24 -0
- package/dist/runtime/plugin-api.d.ts +22 -0
- package/dist/runtime/plugin-api.js +2 -0
- package/dist/runtime/process-config.d.ts +8 -0
- package/dist/runtime/process-config.js +35 -0
- package/dist/services/alert-service.d.ts +45 -0
- package/dist/services/alert-service.js +198 -0
- package/dist/services/analysis-service.d.ts +20 -0
- package/dist/services/analysis-service.js +73 -0
- package/dist/services/analysis-view-service.d.ts +23 -0
- package/dist/services/analysis-view-service.js +343 -0
- package/dist/services/financial-lite-service.d.ts +23 -0
- package/dist/services/financial-lite-service.js +201 -0
- package/dist/services/financial-service.d.ts +20 -0
- package/dist/services/financial-service.js +47 -0
- package/dist/services/indicator-service.d.ts +9 -0
- package/dist/services/indicator-service.js +67 -0
- package/dist/services/instrument-service.d.ts +6 -0
- package/dist/services/instrument-service.js +21 -0
- package/dist/services/key-level-service.d.ts +2 -0
- package/dist/services/key-level-service.js +2 -0
- package/dist/services/key-levels-backtest-service.d.ts +71 -0
- package/dist/services/key-levels-backtest-service.js +427 -0
- package/dist/services/kline-service.d.ts +19 -0
- package/dist/services/kline-service.js +91 -0
- package/dist/services/monitor-service.d.ts +44 -0
- package/dist/services/monitor-service.js +598 -0
- package/dist/services/mx-search-service.d.ts +22 -0
- package/dist/services/mx-search-service.js +286 -0
- package/dist/services/post-close-review-service.d.ts +31 -0
- package/dist/services/post-close-review-service.js +402 -0
- package/dist/services/quote-service.d.ts +7 -0
- package/dist/services/quote-service.js +9 -0
- package/dist/services/review-memory-service.d.ts +7 -0
- package/dist/services/review-memory-service.js +76 -0
- package/dist/services/tickflow-client.d.ts +43 -0
- package/dist/services/tickflow-client.js +126 -0
- package/dist/services/trading-calendar-service.d.ts +20 -0
- package/dist/services/trading-calendar-service.js +102 -0
- package/dist/services/update-service.d.ts +21 -0
- package/dist/services/update-service.js +130 -0
- package/dist/services/watchlist-profile-service.d.ts +20 -0
- package/dist/services/watchlist-profile-service.js +76 -0
- package/dist/services/watchlist-service.d.ts +43 -0
- package/dist/services/watchlist-service.js +204 -0
- package/dist/storage/db.d.ts +23 -0
- package/dist/storage/db.js +70 -0
- package/dist/storage/repositories/alert-log-repo.d.ts +15 -0
- package/dist/storage/repositories/alert-log-repo.js +54 -0
- package/dist/storage/repositories/analysis-log-repo.d.ts +8 -0
- package/dist/storage/repositories/analysis-log-repo.js +48 -0
- package/dist/storage/repositories/composite-analysis-repo.d.ts +9 -0
- package/dist/storage/repositories/composite-analysis-repo.js +116 -0
- package/dist/storage/repositories/financial-analysis-repo.d.ts +9 -0
- package/dist/storage/repositories/financial-analysis-repo.js +107 -0
- package/dist/storage/repositories/indicators-repo.d.ts +8 -0
- package/dist/storage/repositories/indicators-repo.js +98 -0
- package/dist/storage/repositories/intraday-klines-repo.d.ts +9 -0
- package/dist/storage/repositories/intraday-klines-repo.js +102 -0
- package/dist/storage/repositories/key-levels-history-repo.d.ts +9 -0
- package/dist/storage/repositories/key-levels-history-repo.js +91 -0
- package/dist/storage/repositories/key-levels-repo.d.ts +9 -0
- package/dist/storage/repositories/key-levels-repo.js +83 -0
- package/dist/storage/repositories/klines-repo.d.ts +8 -0
- package/dist/storage/repositories/klines-repo.js +60 -0
- package/dist/storage/repositories/news-analysis-repo.d.ts +9 -0
- package/dist/storage/repositories/news-analysis-repo.js +107 -0
- package/dist/storage/repositories/technical-analysis-repo.d.ts +9 -0
- package/dist/storage/repositories/technical-analysis-repo.js +80 -0
- package/dist/storage/repositories/watchlist-repo.d.ts +10 -0
- package/dist/storage/repositories/watchlist-repo.js +124 -0
- package/dist/storage/schemas.d.ts +13 -0
- package/dist/storage/schemas.js +177 -0
- package/dist/tools/add-stock.tool.d.ts +13 -0
- package/dist/tools/add-stock.tool.js +123 -0
- package/dist/tools/analyze.tool.d.ts +8 -0
- package/dist/tools/analyze.tool.js +24 -0
- package/dist/tools/backtest-key-levels.tool.d.ts +8 -0
- package/dist/tools/backtest-key-levels.tool.js +43 -0
- package/dist/tools/daily-update-status.tool.d.ts +6 -0
- package/dist/tools/daily-update-status.tool.js +9 -0
- package/dist/tools/fetch-financials.tool.d.ts +8 -0
- package/dist/tools/fetch-financials.tool.js +224 -0
- package/dist/tools/fetch-intraday-klines.tool.d.ts +11 -0
- package/dist/tools/fetch-intraday-klines.tool.js +58 -0
- package/dist/tools/fetch-klines.tool.d.ts +11 -0
- package/dist/tools/fetch-klines.tool.js +61 -0
- package/dist/tools/list-watchlist.tool.d.ts +6 -0
- package/dist/tools/list-watchlist.tool.js +22 -0
- package/dist/tools/monitor-status.tool.d.ts +6 -0
- package/dist/tools/monitor-status.tool.js +9 -0
- package/dist/tools/mx-search.tool.d.ts +8 -0
- package/dist/tools/mx-search.tool.js +77 -0
- package/dist/tools/mx-select-stock.tool.d.ts +8 -0
- package/dist/tools/mx-select-stock.tool.js +118 -0
- package/dist/tools/query-database.tool.d.ts +8 -0
- package/dist/tools/query-database.tool.js +283 -0
- package/dist/tools/refresh-watchlist-names.tool.d.ts +7 -0
- package/dist/tools/refresh-watchlist-names.tool.js +17 -0
- package/dist/tools/refresh-watchlist-profiles.tool.d.ts +9 -0
- package/dist/tools/refresh-watchlist-profiles.tool.js +67 -0
- package/dist/tools/remove-stock.tool.d.ts +9 -0
- package/dist/tools/remove-stock.tool.js +27 -0
- package/dist/tools/start-daily-update.tool.d.ts +10 -0
- package/dist/tools/start-daily-update.tool.js +23 -0
- package/dist/tools/start-monitor.tool.d.ts +9 -0
- package/dist/tools/start-monitor.tool.js +52 -0
- package/dist/tools/stop-daily-update.tool.d.ts +9 -0
- package/dist/tools/stop-daily-update.tool.js +20 -0
- package/dist/tools/stop-monitor.tool.d.ts +9 -0
- package/dist/tools/stop-monitor.tool.js +44 -0
- package/dist/tools/test-alert.tool.d.ts +7 -0
- package/dist/tools/test-alert.tool.js +21 -0
- package/dist/tools/update-all.tool.d.ts +9 -0
- package/dist/tools/update-all.tool.js +17 -0
- package/dist/tools/view-analysis.tool.d.ts +8 -0
- package/dist/tools/view-analysis.tool.js +95 -0
- package/dist/types/daily-update.d.ts +26 -0
- package/dist/types/daily-update.js +1 -0
- package/dist/types/domain.d.ts +140 -0
- package/dist/types/domain.js +1 -0
- package/dist/types/indicator.d.ts +43 -0
- package/dist/types/indicator.js +1 -0
- package/dist/types/monitor.d.ts +17 -0
- package/dist/types/monitor.js +1 -0
- package/dist/types/mx-search.d.ts +14 -0
- package/dist/types/mx-search.js +1 -0
- package/dist/types/mx-select-stock.d.ts +28 -0
- package/dist/types/mx-select-stock.js +1 -0
- package/dist/types/tickflow.d.ts +133 -0
- package/dist/types/tickflow.js +1 -0
- package/dist/utils/abortable-sleep.d.ts +1 -0
- package/dist/utils/abortable-sleep.js +20 -0
- package/dist/utils/china-time.d.ts +3 -0
- package/dist/utils/china-time.js +18 -0
- package/dist/utils/cost-price.d.ts +3 -0
- package/dist/utils/cost-price.js +18 -0
- package/dist/utils/format.d.ts +1 -0
- package/dist/utils/format.js +3 -0
- package/dist/utils/process.d.ts +5 -0
- package/dist/utils/process.js +1 -0
- package/dist/utils/symbol.d.ts +1 -0
- package/dist/utils/symbol.js +13 -0
- package/docs/installation.md +391 -0
- package/docs/usage.md +244 -0
- package/openclaw.plugin.json +116 -0
- package/package.json +57 -0
- package/python/indicator_runner.py +31 -0
- package/python/indicators.py +148 -0
- package/python/pyproject.toml +9 -0
- package/python/requirements.txt +3 -0
- package/python/uv.lock +366 -0
- package/skills/database-query/SKILL.md +58 -0
- package/skills/stock-analysis/SKILL.md +106 -0
- package/skills/usage-help/SKILL.md +102 -0
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { formatTickflowApiKeyLevel, supportsIntradayKlines, } from "../config/tickflow-access.js";
|
|
2
|
+
import { normalizeSymbol } from "../utils/symbol.js";
|
|
3
|
+
const FETCH_INTRADAY_RETENTION_DAYS = 10;
|
|
4
|
+
function parseInput(rawInput) {
|
|
5
|
+
if (typeof rawInput === "object" && rawInput !== null) {
|
|
6
|
+
const obj = rawInput;
|
|
7
|
+
const symbol = String(obj.symbol ?? "").trim();
|
|
8
|
+
const period = obj.period == null ? undefined : String(obj.period).trim();
|
|
9
|
+
const count = obj.count == null ? undefined : Number(obj.count);
|
|
10
|
+
if (!symbol) {
|
|
11
|
+
throw new Error("fetch-intraday-klines requires symbol");
|
|
12
|
+
}
|
|
13
|
+
return { symbol, period, count };
|
|
14
|
+
}
|
|
15
|
+
if (typeof rawInput === "string" && rawInput.trim()) {
|
|
16
|
+
const parts = rawInput.trim().split(/\s+/);
|
|
17
|
+
return {
|
|
18
|
+
symbol: parts[0] ?? "",
|
|
19
|
+
period: parts[1] || undefined,
|
|
20
|
+
count: parts[2] ? Number(parts[2]) : undefined,
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
throw new Error("invalid fetch-intraday-klines input");
|
|
24
|
+
}
|
|
25
|
+
export function fetchIntradayKlinesTool(tickflowApiKeyLevel, klineService, intradayKlinesRepository, tradingCalendarService) {
|
|
26
|
+
return {
|
|
27
|
+
name: "fetch_intraday_klines",
|
|
28
|
+
description: "Fetch intraday minute K-lines from TickFlow and write them to LanceDB.",
|
|
29
|
+
async run({ rawInput }) {
|
|
30
|
+
const input = parseInput(rawInput);
|
|
31
|
+
const symbol = normalizeSymbol(input.symbol);
|
|
32
|
+
const period = input.period ?? "1m";
|
|
33
|
+
if (!supportsIntradayKlines(tickflowApiKeyLevel)) {
|
|
34
|
+
return `⚠️ 当前 TickFlow API Key Level 为 ${formatTickflowApiKeyLevel(tickflowApiKeyLevel)},不支持分钟K线接口`;
|
|
35
|
+
}
|
|
36
|
+
const rows = await klineService.fetchIntradayKlines(symbol, {
|
|
37
|
+
period,
|
|
38
|
+
count: input.count,
|
|
39
|
+
});
|
|
40
|
+
if (rows.length === 0) {
|
|
41
|
+
return `⚠️ 未获取到 ${symbol} 的分钟K线数据(period=${period})`;
|
|
42
|
+
}
|
|
43
|
+
await intradayKlinesRepository.saveAll(symbol, period, rows);
|
|
44
|
+
const keepTradeDates = await tradingCalendarService.getRecentTradingDays(FETCH_INTRADAY_RETENTION_DAYS, new Date(rows[rows.length - 1].timestamp));
|
|
45
|
+
await intradayKlinesRepository.pruneToTradeDates(symbol, period, keepTradeDates);
|
|
46
|
+
const first = rows[0];
|
|
47
|
+
const last = rows[rows.length - 1];
|
|
48
|
+
return [
|
|
49
|
+
`📈 获取 ${symbol} 分钟K线数据完成`,
|
|
50
|
+
`周期: ${period}`,
|
|
51
|
+
`数量: ${rows.length} 根`,
|
|
52
|
+
`区间: ${first.trade_date} ${first.trade_time} ~ ${last.trade_date} ${last.trade_time}`,
|
|
53
|
+
`最新收盘: ${last.close.toFixed(2)}`,
|
|
54
|
+
"💾 分钟K线数据已写入数据库表 klines_intraday",
|
|
55
|
+
].join("\n");
|
|
56
|
+
},
|
|
57
|
+
};
|
|
58
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { KlineService } from "../services/kline-service.js";
|
|
2
|
+
import { KlinesRepository } from "../storage/repositories/klines-repo.js";
|
|
3
|
+
import { IndicatorService } from "../services/indicator-service.js";
|
|
4
|
+
import { IndicatorsRepository } from "../storage/repositories/indicators-repo.js";
|
|
5
|
+
export declare function fetchKlinesTool(klineService: KlineService, klinesRepository: KlinesRepository, indicatorService: IndicatorService, indicatorsRepository: IndicatorsRepository): {
|
|
6
|
+
name: string;
|
|
7
|
+
description: string;
|
|
8
|
+
run({ rawInput }: {
|
|
9
|
+
rawInput?: unknown;
|
|
10
|
+
}): Promise<string>;
|
|
11
|
+
};
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { normalizeSymbol } from "../utils/symbol.js";
|
|
2
|
+
function parseInput(rawInput) {
|
|
3
|
+
if (typeof rawInput === "object" && rawInput !== null) {
|
|
4
|
+
const obj = rawInput;
|
|
5
|
+
const symbol = String(obj.symbol ?? "").trim();
|
|
6
|
+
const count = obj.count == null ? undefined : Number(obj.count);
|
|
7
|
+
const adjust = obj.adjust == null ? undefined : String(obj.adjust);
|
|
8
|
+
if (!symbol) {
|
|
9
|
+
throw new Error("fetch-klines requires symbol");
|
|
10
|
+
}
|
|
11
|
+
return { symbol, count, adjust };
|
|
12
|
+
}
|
|
13
|
+
if (typeof rawInput === "string" && rawInput.trim()) {
|
|
14
|
+
const parts = rawInput.trim().split(/\s+/);
|
|
15
|
+
return {
|
|
16
|
+
symbol: parts[0],
|
|
17
|
+
count: parts[1] ? Number(parts[1]) : undefined,
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
throw new Error("invalid fetch-klines input");
|
|
21
|
+
}
|
|
22
|
+
export function fetchKlinesTool(klineService, klinesRepository, indicatorService, indicatorsRepository) {
|
|
23
|
+
return {
|
|
24
|
+
name: "fetch_klines",
|
|
25
|
+
description: "Fetch daily K-lines from TickFlow and return a normalized summary.",
|
|
26
|
+
async run({ rawInput }) {
|
|
27
|
+
const input = parseInput(rawInput);
|
|
28
|
+
const symbol = normalizeSymbol(input.symbol);
|
|
29
|
+
const rows = await klineService.fetchKlines(symbol, {
|
|
30
|
+
count: input.count ?? 90,
|
|
31
|
+
adjust: input.adjust ?? "forward",
|
|
32
|
+
});
|
|
33
|
+
if (rows.length === 0) {
|
|
34
|
+
return `⚠️ 未获取到 ${symbol} 的日K线数据`;
|
|
35
|
+
}
|
|
36
|
+
await klinesRepository.saveAll(symbol, rows);
|
|
37
|
+
const indicators = await indicatorService.calculate(rows);
|
|
38
|
+
await indicatorsRepository.saveAll(symbol, indicators);
|
|
39
|
+
const first = rows[0];
|
|
40
|
+
const last = rows[rows.length - 1];
|
|
41
|
+
const latestIndicator = indicators[indicators.length - 1];
|
|
42
|
+
return [
|
|
43
|
+
`📊 获取 ${symbol} 日K线数据完成`,
|
|
44
|
+
`数量: ${rows.length} 根`,
|
|
45
|
+
`区间: ${first.trade_date} ~ ${last.trade_date}`,
|
|
46
|
+
`最新收盘: ${last.close.toFixed(2)}`,
|
|
47
|
+
`💾 K线数据已写入数据库`,
|
|
48
|
+
`🔧 技术指标已计算并写入数据库`,
|
|
49
|
+
latestIndicator
|
|
50
|
+
? `最新指标: MA5 ${formatIndicator(latestIndicator.ma5)} | MA10 ${formatIndicator(latestIndicator.ma10)} | RSI6 ${formatIndicator(latestIndicator.rsi_6)}`
|
|
51
|
+
: `最新指标: 暂无`,
|
|
52
|
+
].join("\n");
|
|
53
|
+
},
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
function formatIndicator(value) {
|
|
57
|
+
if (value == null || Number.isNaN(value)) {
|
|
58
|
+
return "-";
|
|
59
|
+
}
|
|
60
|
+
return value.toFixed(2);
|
|
61
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { formatCostPrice } from "../utils/cost-price.js";
|
|
2
|
+
export function listWatchlistTool(watchlistService) {
|
|
3
|
+
return {
|
|
4
|
+
name: "list_watchlist",
|
|
5
|
+
description: "List current watchlist symbols with names, optional cost price, and industry/concept metadata.",
|
|
6
|
+
async run() {
|
|
7
|
+
const items = await watchlistService.list();
|
|
8
|
+
if (items.length === 0) {
|
|
9
|
+
return "📋 关注列表为空";
|
|
10
|
+
}
|
|
11
|
+
const lines = [`📋 当前关注列表 (${items.length} 只):`];
|
|
12
|
+
for (const item of items) {
|
|
13
|
+
const tags = [
|
|
14
|
+
item.sector ? `行业分类 ${item.sector}` : null,
|
|
15
|
+
item.themes.length > 0 ? `概念板块 ${item.themes.join("、")}` : null,
|
|
16
|
+
].filter(Boolean);
|
|
17
|
+
lines.push(`• ${item.name}(${item.symbol}) 成本: ${formatCostPrice(item.costPrice)}${tags.length > 0 ? ` | ${tags.join(" | ")}` : ""}`);
|
|
18
|
+
}
|
|
19
|
+
return lines.join("\n");
|
|
20
|
+
},
|
|
21
|
+
};
|
|
22
|
+
}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
const DEFAULT_LIMIT = 5;
|
|
2
|
+
const MAX_LIMIT = 10;
|
|
3
|
+
function parseInput(rawInput) {
|
|
4
|
+
if (typeof rawInput === "string" && rawInput.trim()) {
|
|
5
|
+
return {
|
|
6
|
+
query: rawInput.trim(),
|
|
7
|
+
limit: DEFAULT_LIMIT,
|
|
8
|
+
};
|
|
9
|
+
}
|
|
10
|
+
if (typeof rawInput === "object" && rawInput !== null) {
|
|
11
|
+
const obj = rawInput;
|
|
12
|
+
const query = String(obj.query ?? obj.keyword ?? obj.q ?? "").trim();
|
|
13
|
+
const limit = obj.limit == null ? DEFAULT_LIMIT : Number(obj.limit);
|
|
14
|
+
if (!query) {
|
|
15
|
+
throw new Error("mx_search requires query");
|
|
16
|
+
}
|
|
17
|
+
if (!Number.isFinite(limit) || limit <= 0) {
|
|
18
|
+
throw new Error("mx_search limit must be > 0");
|
|
19
|
+
}
|
|
20
|
+
return {
|
|
21
|
+
query,
|
|
22
|
+
limit: Math.min(Math.trunc(limit), MAX_LIMIT),
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
throw new Error("invalid mx_search input");
|
|
26
|
+
}
|
|
27
|
+
export function mxSearchTool(mxSearchService) {
|
|
28
|
+
return {
|
|
29
|
+
name: "mx_search",
|
|
30
|
+
description: "Search timely market information such as news, announcements, reports, policy, and event interpretation.",
|
|
31
|
+
async run({ rawInput }) {
|
|
32
|
+
const input = parseInput(rawInput);
|
|
33
|
+
const documents = await mxSearchService.search(input.query);
|
|
34
|
+
const selected = documents.slice(0, input.limit);
|
|
35
|
+
if (selected.length === 0) {
|
|
36
|
+
return [
|
|
37
|
+
`🔎 妙想搜索: ${input.query}`,
|
|
38
|
+
"结果数: 0",
|
|
39
|
+
"⚠️ 未检索到匹配资讯",
|
|
40
|
+
].join("\n");
|
|
41
|
+
}
|
|
42
|
+
const lines = [
|
|
43
|
+
`🔎 妙想搜索: ${input.query}`,
|
|
44
|
+
`结果数: ${documents.length}`,
|
|
45
|
+
`展示: ${selected.length}`,
|
|
46
|
+
"",
|
|
47
|
+
];
|
|
48
|
+
selected.forEach((item, index) => {
|
|
49
|
+
lines.push(`${index + 1}. ${item.title}`);
|
|
50
|
+
if (item.publishedAt) {
|
|
51
|
+
lines.push(`时间: ${item.publishedAt}`);
|
|
52
|
+
}
|
|
53
|
+
if (item.source) {
|
|
54
|
+
lines.push(`来源: ${item.source}`);
|
|
55
|
+
}
|
|
56
|
+
if (item.secuList.length > 0) {
|
|
57
|
+
lines.push(`关联标的: ${formatSecurities(item.secuList)}`);
|
|
58
|
+
}
|
|
59
|
+
lines.push("正文:");
|
|
60
|
+
lines.push(item.trunk || "无正文");
|
|
61
|
+
if (index < selected.length - 1) {
|
|
62
|
+
lines.push("");
|
|
63
|
+
}
|
|
64
|
+
});
|
|
65
|
+
return lines.join("\n");
|
|
66
|
+
},
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
function formatSecurities(securities) {
|
|
70
|
+
return securities
|
|
71
|
+
.map((item) => {
|
|
72
|
+
const main = [item.secuName, item.secuCode].filter(Boolean).join(" ");
|
|
73
|
+
return item.secuType ? `${main} (${item.secuType})` : main;
|
|
74
|
+
})
|
|
75
|
+
.filter(Boolean)
|
|
76
|
+
.join(";");
|
|
77
|
+
}
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
const DEFAULT_PAGE_NO = 1;
|
|
2
|
+
const DEFAULT_PAGE_SIZE = 20;
|
|
3
|
+
const MAX_PAGE_SIZE = 100;
|
|
4
|
+
function parseInput(rawInput) {
|
|
5
|
+
if (typeof rawInput === "string" && rawInput.trim()) {
|
|
6
|
+
return {
|
|
7
|
+
keyword: rawInput.trim(),
|
|
8
|
+
pageNo: DEFAULT_PAGE_NO,
|
|
9
|
+
pageSize: DEFAULT_PAGE_SIZE,
|
|
10
|
+
};
|
|
11
|
+
}
|
|
12
|
+
if (typeof rawInput === "object" && rawInput !== null) {
|
|
13
|
+
const obj = rawInput;
|
|
14
|
+
const keyword = String(obj.keyword ?? obj.query ?? obj.q ?? "").trim();
|
|
15
|
+
const pageNo = obj.pageNo == null ? DEFAULT_PAGE_NO : Number(obj.pageNo);
|
|
16
|
+
const pageSize = obj.pageSize == null ? DEFAULT_PAGE_SIZE : Number(obj.pageSize);
|
|
17
|
+
if (!keyword) {
|
|
18
|
+
throw new Error("mx_select_stock requires keyword");
|
|
19
|
+
}
|
|
20
|
+
if (!Number.isFinite(pageNo) || pageNo <= 0) {
|
|
21
|
+
throw new Error("mx_select_stock pageNo must be > 0");
|
|
22
|
+
}
|
|
23
|
+
if (!Number.isFinite(pageSize) || pageSize <= 0) {
|
|
24
|
+
throw new Error("mx_select_stock pageSize must be > 0");
|
|
25
|
+
}
|
|
26
|
+
return {
|
|
27
|
+
keyword,
|
|
28
|
+
pageNo: Math.trunc(pageNo),
|
|
29
|
+
pageSize: Math.min(Math.trunc(pageSize), MAX_PAGE_SIZE),
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
throw new Error("invalid mx_select_stock input");
|
|
33
|
+
}
|
|
34
|
+
export function mxSelectStockTool(mxApiService) {
|
|
35
|
+
return {
|
|
36
|
+
name: "mx_select_stock",
|
|
37
|
+
description: "Screen stocks by natural-language conditions using MX smart stock screening.",
|
|
38
|
+
async run({ rawInput }) {
|
|
39
|
+
const input = parseInput(rawInput);
|
|
40
|
+
const result = await mxApiService.selectStocks(input);
|
|
41
|
+
return renderMxSelectStockResult(input, result);
|
|
42
|
+
},
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
function renderMxSelectStockResult(input, result) {
|
|
46
|
+
const lines = [
|
|
47
|
+
`🧠 妙想选股: ${input.keyword}`,
|
|
48
|
+
`状态: ${result.status ?? "-"} | 业务码: ${result.code ?? "-"} | 消息: ${result.msg ?? result.message ?? "-"}`,
|
|
49
|
+
`结果类型: ${result.resultType ?? "-"} | 总数: ${result.total} | 总记录: ${result.totalRecordCount}`,
|
|
50
|
+
`页码: ${input.pageNo} | 页大小: ${input.pageSize} | 本页返回: ${result.dataList.length}`,
|
|
51
|
+
];
|
|
52
|
+
if (result.parserText) {
|
|
53
|
+
lines.push(`解析: ${result.parserText}`);
|
|
54
|
+
}
|
|
55
|
+
if (result.totalCondition) {
|
|
56
|
+
lines.push(`组合条件: ${result.totalCondition.describe}(${result.totalCondition.stockCount ?? "-"} 只)`);
|
|
57
|
+
}
|
|
58
|
+
if (result.responseConditionList.length > 0) {
|
|
59
|
+
lines.push("", "条件拆解:");
|
|
60
|
+
for (const condition of result.responseConditionList) {
|
|
61
|
+
lines.push(`- ${condition.describe}(${condition.stockCount ?? "-"} 只)`);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
lines.push("");
|
|
65
|
+
lines.push("字段说明:");
|
|
66
|
+
if (result.columns.length === 0) {
|
|
67
|
+
lines.push("- 无字段定义");
|
|
68
|
+
}
|
|
69
|
+
else {
|
|
70
|
+
for (const column of result.columns) {
|
|
71
|
+
lines.push(`- ${column.title} <- ${column.key}${formatColumnMeta(column)}`);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
lines.push("");
|
|
75
|
+
lines.push("CSV:");
|
|
76
|
+
lines.push(renderCsv(result.columns, result.dataList));
|
|
77
|
+
return lines.join("\n");
|
|
78
|
+
}
|
|
79
|
+
function formatColumnMeta(column) {
|
|
80
|
+
const parts = [];
|
|
81
|
+
if (column.unit) {
|
|
82
|
+
parts.push(`单位=${column.unit}`);
|
|
83
|
+
}
|
|
84
|
+
if (column.dataType) {
|
|
85
|
+
parts.push(`类型=${column.dataType}`);
|
|
86
|
+
}
|
|
87
|
+
if (column.dateMsg) {
|
|
88
|
+
parts.push(`日期=${column.dateMsg}`);
|
|
89
|
+
}
|
|
90
|
+
return parts.length > 0 ? ` (${parts.join(", ")})` : "";
|
|
91
|
+
}
|
|
92
|
+
function renderCsv(columns, rows) {
|
|
93
|
+
if (columns.length === 0) {
|
|
94
|
+
return "";
|
|
95
|
+
}
|
|
96
|
+
const headerLabels = columns.map((column) => escapeCsv(column.title));
|
|
97
|
+
const csvLines = [headerLabels.join(",")];
|
|
98
|
+
for (const row of rows) {
|
|
99
|
+
const values = columns.map((column) => escapeCsv(formatCell(row[column.key])));
|
|
100
|
+
csvLines.push(values.join(","));
|
|
101
|
+
}
|
|
102
|
+
return csvLines.join("\n");
|
|
103
|
+
}
|
|
104
|
+
function formatCell(value) {
|
|
105
|
+
if (value == null) {
|
|
106
|
+
return "";
|
|
107
|
+
}
|
|
108
|
+
if (typeof value === "object") {
|
|
109
|
+
return JSON.stringify(value);
|
|
110
|
+
}
|
|
111
|
+
return String(value);
|
|
112
|
+
}
|
|
113
|
+
function escapeCsv(value) {
|
|
114
|
+
if (/[",\n]/.test(value)) {
|
|
115
|
+
return `"${value.replace(/"/g, "\"\"")}"`;
|
|
116
|
+
}
|
|
117
|
+
return value;
|
|
118
|
+
}
|