@hedgehog-finance/hedgehog-plugin 1.0.21 → 1.0.22
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/dist/index.d.ts +4 -3
- package/dist/index.js +49 -6
- package/dist/index.js.map +1 -1
- package/dist/setup-api.d.ts +2 -0
- package/dist/setup-api.js +8 -0
- package/dist/setup-api.js.map +1 -0
- package/dist/src/channel.js +25 -23
- package/dist/src/channel.js.map +1 -1
- package/dist/src/core/database.js +449 -39
- package/dist/src/core/database.js.map +1 -1
- package/dist/src/dailyMorningBriefingCron.d.ts +46 -0
- package/dist/src/dailyMorningBriefingCron.js +82 -0
- package/dist/src/dailyMorningBriefingCron.js.map +1 -0
- package/dist/src/features/chartOutput.d.ts +2 -0
- package/dist/src/features/chartOutput.js +35 -0
- package/dist/src/features/chartOutput.js.map +1 -0
- package/dist/src/features/dailyMorningBriefing/schema.d.ts +56 -0
- package/dist/src/features/dailyMorningBriefing/schema.js +22 -0
- package/dist/src/features/dailyMorningBriefing/schema.js.map +1 -0
- package/dist/src/features/dailyMorningBriefing/tools.d.ts +12 -0
- package/dist/src/features/dailyMorningBriefing/tools.js +204 -0
- package/dist/src/features/dailyMorningBriefing/tools.js.map +1 -0
- package/dist/src/features/deepReasoning/schema.d.ts +43 -0
- package/dist/src/features/deepReasoning/schema.js +17 -0
- package/dist/src/features/deepReasoning/schema.js.map +1 -0
- package/dist/src/features/deepReasoning/tools.d.ts +12 -0
- package/dist/src/features/deepReasoning/tools.js +163 -0
- package/dist/src/features/deepReasoning/tools.js.map +1 -0
- package/dist/src/features/index.d.ts +2 -1
- package/dist/src/features/index.js +9 -1
- package/dist/src/features/index.js.map +1 -1
- package/dist/src/features/informationVerification/schema.d.ts +43 -0
- package/dist/src/features/informationVerification/schema.js +17 -0
- package/dist/src/features/informationVerification/schema.js.map +1 -0
- package/dist/src/features/informationVerification/tools.d.ts +12 -0
- package/dist/src/features/informationVerification/tools.js +162 -0
- package/dist/src/features/informationVerification/tools.js.map +1 -0
- package/dist/src/features/notes/schema.d.ts +136 -39
- package/dist/src/features/notes/schema.js +13 -10
- package/dist/src/features/notes/schema.js.map +1 -1
- package/dist/src/features/notes/tools.d.ts +1 -0
- package/dist/src/features/notes/tools.js +47 -14
- package/dist/src/features/notes/tools.js.map +1 -1
- package/dist/src/features/pluginInfo/schema.d.ts +79 -0
- package/dist/src/features/pluginInfo/schema.js +14 -0
- package/dist/src/features/pluginInfo/schema.js.map +1 -0
- package/dist/src/features/pluginInfo/tools.d.ts +1 -0
- package/dist/src/features/pluginInfo/tools.js +157 -2
- package/dist/src/features/pluginInfo/tools.js.map +1 -1
- package/dist/src/features/profileLibrary/schema.d.ts +34 -6
- package/dist/src/features/profileLibrary/schema.js +1 -1
- package/dist/src/features/profileLibrary/schema.js.map +1 -1
- package/dist/src/features/stockAnalysis/schema.d.ts +224 -31
- package/dist/src/features/stockAnalysis/schema.js +76 -12
- package/dist/src/features/stockAnalysis/schema.js.map +1 -1
- package/dist/src/features/stockAnalysis/tools.d.ts +6 -4
- package/dist/src/features/stockAnalysis/tools.js +389 -44
- package/dist/src/features/stockAnalysis/tools.js.map +1 -1
- package/dist/src/features/stockBasic/schema.d.ts +149 -0
- package/dist/src/features/stockBasic/schema.js +26 -0
- package/dist/src/features/stockBasic/schema.js.map +1 -0
- package/dist/src/features/stockBasic/tools.d.ts +12 -0
- package/dist/src/features/stockBasic/tools.js +124 -0
- package/dist/src/features/stockBasic/tools.js.map +1 -0
- package/dist/src/features/watchlist/logic.d.ts +3 -3
- package/dist/src/features/watchlist/logic.js +47 -46
- package/dist/src/features/watchlist/logic.js.map +1 -1
- package/dist/src/features/watchlist/schema.d.ts +89 -54
- package/dist/src/features/watchlist/schema.js +7 -4
- package/dist/src/features/watchlist/schema.js.map +1 -1
- package/dist/src/features/watchlist/tools.d.ts +106 -59
- package/dist/src/features/watchlist/tools.js +182 -104
- package/dist/src/features/watchlist/tools.js.map +1 -1
- package/dist/src/openclawConfig.d.ts +6 -0
- package/dist/src/openclawConfig.js +74 -0
- package/dist/src/openclawConfig.js.map +1 -0
- package/dist/src/openclawConstants.d.ts +4 -0
- package/dist/src/openclawConstants.js +10 -0
- package/dist/src/openclawConstants.js.map +1 -0
- package/dist/src/runtime.js +20 -0
- package/dist/src/runtime.js.map +1 -1
- package/index.ts +52 -5
- package/openclaw.plugin.json +24 -0
- package/package.json +21 -6
- package/setup-api.ts +10 -0
- package/src/channel.ts +26 -25
- package/src/core/database.ts +447 -40
- package/src/dailyMorningBriefingCron.ts +129 -0
- package/src/features/chartOutput.ts +35 -0
- package/src/features/dailyMorningBriefing/schema.ts +38 -0
- package/src/features/dailyMorningBriefing/tools.ts +246 -0
- package/src/features/deepReasoning/schema.ts +22 -0
- package/src/features/deepReasoning/tools.ts +182 -0
- package/src/features/index.ts +11 -2
- package/src/features/informationVerification/schema.ts +22 -0
- package/src/features/informationVerification/tools.ts +181 -0
- package/src/features/notes/schema.ts +17 -12
- package/src/features/notes/tools.ts +54 -17
- package/src/features/pluginInfo/schema.ts +19 -0
- package/src/features/pluginInfo/tools.ts +173 -2
- package/src/features/profileLibrary/schema.ts +1 -1
- package/src/features/stockAnalysis/schema.ts +99 -17
- package/src/features/stockAnalysis/tools.ts +447 -49
- package/src/features/stockBasic/schema.ts +33 -0
- package/src/features/stockBasic/tools.ts +157 -0
- package/src/features/watchlist/logic.ts +56 -53
- package/src/features/watchlist/schema.ts +11 -6
- package/src/features/watchlist/tools.ts +191 -106
- package/src/openclawConfig.ts +101 -0
- package/src/openclawConstants.ts +11 -0
- package/src/runtime.ts +19 -0
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
export declare const StockBasicItemSchema: z.ZodObject<{
|
|
3
|
+
act_ent_type: z.ZodDefault<z.ZodOptional<z.ZodString>>;
|
|
4
|
+
act_name: z.ZodDefault<z.ZodOptional<z.ZodString>>;
|
|
5
|
+
area: z.ZodDefault<z.ZodOptional<z.ZodString>>;
|
|
6
|
+
cnspell: z.ZodDefault<z.ZodOptional<z.ZodString>>;
|
|
7
|
+
curr_type: z.ZodDefault<z.ZodOptional<z.ZodString>>;
|
|
8
|
+
enname: z.ZodDefault<z.ZodOptional<z.ZodString>>;
|
|
9
|
+
exchange: z.ZodString;
|
|
10
|
+
fullname: z.ZodDefault<z.ZodOptional<z.ZodString>>;
|
|
11
|
+
industry: z.ZodDefault<z.ZodOptional<z.ZodString>>;
|
|
12
|
+
is_hs: z.ZodDefault<z.ZodOptional<z.ZodString>>;
|
|
13
|
+
list_date: z.ZodDefault<z.ZodOptional<z.ZodString>>;
|
|
14
|
+
market: z.ZodDefault<z.ZodOptional<z.ZodString>>;
|
|
15
|
+
name: z.ZodString;
|
|
16
|
+
stock_code: z.ZodString;
|
|
17
|
+
symbol: z.ZodString;
|
|
18
|
+
}, "strip", z.ZodTypeAny, {
|
|
19
|
+
symbol: string;
|
|
20
|
+
name: string;
|
|
21
|
+
stock_code: string;
|
|
22
|
+
industry: string;
|
|
23
|
+
market: string;
|
|
24
|
+
exchange: string;
|
|
25
|
+
act_ent_type: string;
|
|
26
|
+
act_name: string;
|
|
27
|
+
area: string;
|
|
28
|
+
cnspell: string;
|
|
29
|
+
curr_type: string;
|
|
30
|
+
enname: string;
|
|
31
|
+
fullname: string;
|
|
32
|
+
is_hs: string;
|
|
33
|
+
list_date: string;
|
|
34
|
+
}, {
|
|
35
|
+
symbol: string;
|
|
36
|
+
name: string;
|
|
37
|
+
stock_code: string;
|
|
38
|
+
exchange: string;
|
|
39
|
+
industry?: string | undefined;
|
|
40
|
+
market?: string | undefined;
|
|
41
|
+
act_ent_type?: string | undefined;
|
|
42
|
+
act_name?: string | undefined;
|
|
43
|
+
area?: string | undefined;
|
|
44
|
+
cnspell?: string | undefined;
|
|
45
|
+
curr_type?: string | undefined;
|
|
46
|
+
enname?: string | undefined;
|
|
47
|
+
fullname?: string | undefined;
|
|
48
|
+
is_hs?: string | undefined;
|
|
49
|
+
list_date?: string | undefined;
|
|
50
|
+
}>;
|
|
51
|
+
export type StockBasicItem = z.infer<typeof StockBasicItemSchema>;
|
|
52
|
+
export declare const SyncStockBasicParamsSchema: z.ZodObject<{
|
|
53
|
+
stocks: z.ZodArray<z.ZodObject<{
|
|
54
|
+
act_ent_type: z.ZodDefault<z.ZodOptional<z.ZodString>>;
|
|
55
|
+
act_name: z.ZodDefault<z.ZodOptional<z.ZodString>>;
|
|
56
|
+
area: z.ZodDefault<z.ZodOptional<z.ZodString>>;
|
|
57
|
+
cnspell: z.ZodDefault<z.ZodOptional<z.ZodString>>;
|
|
58
|
+
curr_type: z.ZodDefault<z.ZodOptional<z.ZodString>>;
|
|
59
|
+
enname: z.ZodDefault<z.ZodOptional<z.ZodString>>;
|
|
60
|
+
exchange: z.ZodString;
|
|
61
|
+
fullname: z.ZodDefault<z.ZodOptional<z.ZodString>>;
|
|
62
|
+
industry: z.ZodDefault<z.ZodOptional<z.ZodString>>;
|
|
63
|
+
is_hs: z.ZodDefault<z.ZodOptional<z.ZodString>>;
|
|
64
|
+
list_date: z.ZodDefault<z.ZodOptional<z.ZodString>>;
|
|
65
|
+
market: z.ZodDefault<z.ZodOptional<z.ZodString>>;
|
|
66
|
+
name: z.ZodString;
|
|
67
|
+
stock_code: z.ZodString;
|
|
68
|
+
symbol: z.ZodString;
|
|
69
|
+
}, "strip", z.ZodTypeAny, {
|
|
70
|
+
symbol: string;
|
|
71
|
+
name: string;
|
|
72
|
+
stock_code: string;
|
|
73
|
+
industry: string;
|
|
74
|
+
market: string;
|
|
75
|
+
exchange: string;
|
|
76
|
+
act_ent_type: string;
|
|
77
|
+
act_name: string;
|
|
78
|
+
area: string;
|
|
79
|
+
cnspell: string;
|
|
80
|
+
curr_type: string;
|
|
81
|
+
enname: string;
|
|
82
|
+
fullname: string;
|
|
83
|
+
is_hs: string;
|
|
84
|
+
list_date: string;
|
|
85
|
+
}, {
|
|
86
|
+
symbol: string;
|
|
87
|
+
name: string;
|
|
88
|
+
stock_code: string;
|
|
89
|
+
exchange: string;
|
|
90
|
+
industry?: string | undefined;
|
|
91
|
+
market?: string | undefined;
|
|
92
|
+
act_ent_type?: string | undefined;
|
|
93
|
+
act_name?: string | undefined;
|
|
94
|
+
area?: string | undefined;
|
|
95
|
+
cnspell?: string | undefined;
|
|
96
|
+
curr_type?: string | undefined;
|
|
97
|
+
enname?: string | undefined;
|
|
98
|
+
fullname?: string | undefined;
|
|
99
|
+
is_hs?: string | undefined;
|
|
100
|
+
list_date?: string | undefined;
|
|
101
|
+
}>, "many">;
|
|
102
|
+
}, "strip", z.ZodTypeAny, {
|
|
103
|
+
stocks: {
|
|
104
|
+
symbol: string;
|
|
105
|
+
name: string;
|
|
106
|
+
stock_code: string;
|
|
107
|
+
industry: string;
|
|
108
|
+
market: string;
|
|
109
|
+
exchange: string;
|
|
110
|
+
act_ent_type: string;
|
|
111
|
+
act_name: string;
|
|
112
|
+
area: string;
|
|
113
|
+
cnspell: string;
|
|
114
|
+
curr_type: string;
|
|
115
|
+
enname: string;
|
|
116
|
+
fullname: string;
|
|
117
|
+
is_hs: string;
|
|
118
|
+
list_date: string;
|
|
119
|
+
}[];
|
|
120
|
+
}, {
|
|
121
|
+
stocks: {
|
|
122
|
+
symbol: string;
|
|
123
|
+
name: string;
|
|
124
|
+
stock_code: string;
|
|
125
|
+
exchange: string;
|
|
126
|
+
industry?: string | undefined;
|
|
127
|
+
market?: string | undefined;
|
|
128
|
+
act_ent_type?: string | undefined;
|
|
129
|
+
act_name?: string | undefined;
|
|
130
|
+
area?: string | undefined;
|
|
131
|
+
cnspell?: string | undefined;
|
|
132
|
+
curr_type?: string | undefined;
|
|
133
|
+
enname?: string | undefined;
|
|
134
|
+
fullname?: string | undefined;
|
|
135
|
+
is_hs?: string | undefined;
|
|
136
|
+
list_date?: string | undefined;
|
|
137
|
+
}[];
|
|
138
|
+
}>;
|
|
139
|
+
export type SyncStockBasicParams = z.infer<typeof SyncStockBasicParamsSchema>;
|
|
140
|
+
export declare const GetStockBasicListParamsSchema: z.ZodOptional<z.ZodNullable<z.ZodObject<{}, "strip", z.ZodTypeAny, {}, {}>>>;
|
|
141
|
+
export type GetStockBasicListParams = z.infer<typeof GetStockBasicListParamsSchema>;
|
|
142
|
+
export declare const GetStockBasicInfoParamsSchema: z.ZodObject<{
|
|
143
|
+
stock_code: z.ZodString;
|
|
144
|
+
}, "strip", z.ZodTypeAny, {
|
|
145
|
+
stock_code: string;
|
|
146
|
+
}, {
|
|
147
|
+
stock_code: string;
|
|
148
|
+
}>;
|
|
149
|
+
export type GetStockBasicInfoParams = z.infer<typeof GetStockBasicInfoParamsSchema>;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
export const StockBasicItemSchema = z.object({
|
|
3
|
+
act_ent_type: z.string().optional().default(""),
|
|
4
|
+
act_name: z.string().optional().default(""),
|
|
5
|
+
area: z.string().optional().default(""),
|
|
6
|
+
cnspell: z.string().optional().default(""),
|
|
7
|
+
curr_type: z.string().optional().default(""),
|
|
8
|
+
enname: z.string().optional().default(""),
|
|
9
|
+
exchange: z.string().trim().min(1),
|
|
10
|
+
fullname: z.string().optional().default(""),
|
|
11
|
+
industry: z.string().optional().default(""),
|
|
12
|
+
is_hs: z.string().optional().default(""),
|
|
13
|
+
list_date: z.string().optional().default(""),
|
|
14
|
+
market: z.string().optional().default(""),
|
|
15
|
+
name: z.string().trim().min(1),
|
|
16
|
+
stock_code: z.string().trim().min(1),
|
|
17
|
+
symbol: z.string().trim().min(1)
|
|
18
|
+
});
|
|
19
|
+
export const SyncStockBasicParamsSchema = z.object({
|
|
20
|
+
stocks: z.array(StockBasicItemSchema).min(1)
|
|
21
|
+
});
|
|
22
|
+
export const GetStockBasicListParamsSchema = z.object({}).nullish();
|
|
23
|
+
export const GetStockBasicInfoParamsSchema = z.object({
|
|
24
|
+
stock_code: z.string().trim().min(1).describe("股票代码")
|
|
25
|
+
});
|
|
26
|
+
//# sourceMappingURL=schema.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schema.js","sourceRoot":"","sources":["../../../../src/features/stockBasic/schema.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,MAAM,CAAC,MAAM,oBAAoB,GAAG,CAAC,CAAC,MAAM,CAAC;IAC5C,YAAY,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC;IAC/C,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC;IAC3C,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC;IACvC,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC;IAC1C,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC;IAC5C,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC;IACzC,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;IAClC,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC;IAC3C,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC;IAC3C,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC;IACxC,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC;IAC5C,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC;IACzC,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;IAC9B,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;IACpC,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;CAChC,CAAC,CAAC;AAGH,MAAM,CAAC,MAAM,0BAA0B,GAAG,CAAC,CAAC,MAAM,CAAC;IAClD,MAAM,EAAE,CAAC,CAAC,KAAK,CAAC,oBAAoB,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;CAC5C,CAAC,CAAC;AAGH,MAAM,CAAC,MAAM,6BAA6B,GAAG,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC;AAGpE,MAAM,CAAC,MAAM,6BAA6B,GAAG,CAAC,CAAC,MAAM,CAAC;IACrD,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC;CACrD,CAAC,CAAC"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
interface RuntimeTool {
|
|
2
|
+
name: string;
|
|
3
|
+
label?: string;
|
|
4
|
+
description: string;
|
|
5
|
+
parameters: unknown;
|
|
6
|
+
registerTool?: boolean;
|
|
7
|
+
execute(params: unknown, ctx?: {
|
|
8
|
+
userId: string;
|
|
9
|
+
}): Promise<string>;
|
|
10
|
+
}
|
|
11
|
+
export declare const stockBasicTools: Record<string, RuntimeTool>;
|
|
12
|
+
export {};
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import { getDB } from "../../core/database.js";
|
|
2
|
+
import { GetStockBasicListParamsSchema, GetStockBasicInfoParamsSchema, SyncStockBasicParamsSchema } from "./schema.js";
|
|
3
|
+
const GetStockBasicInfoAgentToolSchema = {
|
|
4
|
+
type: "object",
|
|
5
|
+
additionalProperties: false,
|
|
6
|
+
required: ["stock_code"],
|
|
7
|
+
properties: {
|
|
8
|
+
stock_code: { type: "string", description: "股票代码,例如:000001.SZ 或 600000.SH" }
|
|
9
|
+
}
|
|
10
|
+
};
|
|
11
|
+
function normalizeStockBasic(stock) {
|
|
12
|
+
return {
|
|
13
|
+
...stock,
|
|
14
|
+
stock_code: stock.stock_code.trim().toUpperCase().replace(/\.SS$/i, ".SH"),
|
|
15
|
+
symbol: stock.symbol.trim(),
|
|
16
|
+
exchange: stock.exchange.trim().toUpperCase(),
|
|
17
|
+
name: stock.name.trim(),
|
|
18
|
+
fullname: stock.fullname.trim(),
|
|
19
|
+
enname: stock.enname.trim(),
|
|
20
|
+
cnspell: stock.cnspell.trim().toUpperCase()
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
function escapeLike(value) {
|
|
24
|
+
return value.replace(/[\\%_]/g, "\\$&");
|
|
25
|
+
}
|
|
26
|
+
export const stockBasicTools = {
|
|
27
|
+
sync_stock_basic: {
|
|
28
|
+
name: "sync_stock_basic",
|
|
29
|
+
description: "批量同步证券基础资料主数据。系统以 stock_code 作为唯一标识执行新增或覆盖更新,适用于初始化或定期刷新股票代码、名称、交易所、行业、上市日期等基础字段。",
|
|
30
|
+
parameters: SyncStockBasicParamsSchema,
|
|
31
|
+
registerTool: false,
|
|
32
|
+
async execute(params) {
|
|
33
|
+
const args = SyncStockBasicParamsSchema.parse(params);
|
|
34
|
+
const db = getDB();
|
|
35
|
+
const stmt = db.prepare(`
|
|
36
|
+
INSERT INTO stock_basic (
|
|
37
|
+
stock_code,
|
|
38
|
+
symbol,
|
|
39
|
+
name,
|
|
40
|
+
fullname,
|
|
41
|
+
enname,
|
|
42
|
+
cnspell,
|
|
43
|
+
exchange,
|
|
44
|
+
market,
|
|
45
|
+
industry,
|
|
46
|
+
area,
|
|
47
|
+
curr_type,
|
|
48
|
+
list_date,
|
|
49
|
+
is_hs,
|
|
50
|
+
act_name,
|
|
51
|
+
act_ent_type
|
|
52
|
+
)
|
|
53
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
54
|
+
ON CONFLICT(stock_code) DO UPDATE SET
|
|
55
|
+
symbol = excluded.symbol,
|
|
56
|
+
name = excluded.name,
|
|
57
|
+
fullname = excluded.fullname,
|
|
58
|
+
enname = excluded.enname,
|
|
59
|
+
cnspell = excluded.cnspell,
|
|
60
|
+
exchange = excluded.exchange,
|
|
61
|
+
market = excluded.market,
|
|
62
|
+
industry = excluded.industry,
|
|
63
|
+
area = excluded.area,
|
|
64
|
+
curr_type = excluded.curr_type,
|
|
65
|
+
list_date = excluded.list_date,
|
|
66
|
+
is_hs = excluded.is_hs,
|
|
67
|
+
act_name = excluded.act_name,
|
|
68
|
+
act_ent_type = excluded.act_ent_type,
|
|
69
|
+
updatedAt = STRFTIME('%Y-%m-%dT%H:%M:%fZ', 'NOW')
|
|
70
|
+
`);
|
|
71
|
+
if (db.inTransaction)
|
|
72
|
+
db.exec("ROLLBACK");
|
|
73
|
+
db.exec("BEGIN TRANSACTION");
|
|
74
|
+
try {
|
|
75
|
+
for (const rawStock of args.stocks) {
|
|
76
|
+
const stock = normalizeStockBasic(rawStock);
|
|
77
|
+
stmt.run(stock.stock_code, stock.symbol, stock.name, stock.fullname, stock.enname, stock.cnspell, stock.exchange, stock.market, stock.industry, stock.area, stock.curr_type, stock.list_date, stock.is_hs, stock.act_name, stock.act_ent_type);
|
|
78
|
+
}
|
|
79
|
+
db.exec("COMMIT");
|
|
80
|
+
return JSON.stringify({ success: true, synced: args.stocks.length });
|
|
81
|
+
}
|
|
82
|
+
catch (e) {
|
|
83
|
+
if (db.inTransaction)
|
|
84
|
+
db.exec("ROLLBACK");
|
|
85
|
+
return JSON.stringify({ success: false, error: e.message });
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
},
|
|
89
|
+
get_stock_basic_list: {
|
|
90
|
+
name: "get_stock_basic_list",
|
|
91
|
+
description: "查询证券基础资料全量列表。返回股票代码、证券简称、公司全称、交易所、市场板块、行业及上市日期等基础字段,用于前端缓存、下拉选择或基础数据校验。",
|
|
92
|
+
parameters: GetStockBasicListParamsSchema,
|
|
93
|
+
registerTool: false,
|
|
94
|
+
async execute(params) {
|
|
95
|
+
GetStockBasicListParamsSchema.parse(params);
|
|
96
|
+
const db = getDB();
|
|
97
|
+
const rows = db.prepare(`
|
|
98
|
+
SELECT stock_code, symbol, name, fullname, enname, cnspell, exchange, market, industry, area, curr_type, list_date, is_hs, act_name, act_ent_type, createdAt, updatedAt
|
|
99
|
+
FROM stock_basic
|
|
100
|
+
ORDER BY exchange ASC, symbol ASC
|
|
101
|
+
`).all();
|
|
102
|
+
return JSON.stringify({ success: true, data: rows });
|
|
103
|
+
}
|
|
104
|
+
},
|
|
105
|
+
get_stock_basic_info: {
|
|
106
|
+
name: "get_stock_basic_info",
|
|
107
|
+
label: "查询股票基本信息",
|
|
108
|
+
description: "根据股票代码查询证券基础资料。",
|
|
109
|
+
parameters: GetStockBasicInfoAgentToolSchema,
|
|
110
|
+
registerTool: true,
|
|
111
|
+
async execute(params) {
|
|
112
|
+
const args = GetStockBasicInfoParamsSchema.parse(params);
|
|
113
|
+
const db = getDB();
|
|
114
|
+
const code = args.stock_code.trim().toUpperCase().replace(/\.SS$/i, ".SH");
|
|
115
|
+
const row = db.prepare(`
|
|
116
|
+
SELECT stock_code, name, enname, exchange, market, industry, is_hs
|
|
117
|
+
FROM stock_basic
|
|
118
|
+
WHERE stock_code = ?
|
|
119
|
+
`).get(code);
|
|
120
|
+
return JSON.stringify({ success: true, data: row || null });
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
};
|
|
124
|
+
//# sourceMappingURL=tools.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tools.js","sourceRoot":"","sources":["../../../../src/features/stockBasic/tools.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { PluginRuntime } from "openclaw/plugin-sdk";
|
|
2
2
|
import { StockClassification } from "../../types.js";
|
|
3
|
-
declare function normalizeStockCodeForCache(
|
|
3
|
+
declare function normalizeStockCodeForCache(stock_code: string, exchange?: string): string;
|
|
4
4
|
export declare const watchlistLogic: {
|
|
5
5
|
_normalizeStockCodeForCache: typeof normalizeStockCodeForCache;
|
|
6
|
-
getStockClassification(rt: PluginRuntime,
|
|
6
|
+
getStockClassification(rt: PluginRuntime, stock_name: string, stock_code: string, exchange: string, _userId: string): Promise<StockClassification | null>;
|
|
7
7
|
classifyStocksTogether(rt: PluginRuntime, stocks: any[], _userId: string): Promise<StockClassification[]>;
|
|
8
8
|
getBatchStockClassification(rt: PluginRuntime, stocks: any[], _userId: string, options?: {
|
|
9
9
|
requireComplete?: boolean;
|
|
@@ -13,7 +13,7 @@ export declare const watchlistLogic: {
|
|
|
13
13
|
industries: any[];
|
|
14
14
|
themes: any[];
|
|
15
15
|
};
|
|
16
|
-
_autoClassifyWithAI(rt: PluginRuntime,
|
|
16
|
+
_autoClassifyWithAI(rt: PluginRuntime, stock_name: string, stock_code: string, exchange: string): Promise<StockClassification | null>;
|
|
17
17
|
_callClassifierCompletion(rt: PluginRuntime, sessionId: string, prompt: string, timeoutMs: number): Promise<string>;
|
|
18
18
|
_callClassifierAi(rt: PluginRuntime, sessionId: string, prompt: string, timeoutMs: number): Promise<string>;
|
|
19
19
|
_ensureCategory(db: any, name: string, type: "industry" | "theme", userId: string): string;
|
|
@@ -19,8 +19,8 @@ const CLASSIFIER_SYSTEM_PROMPT = [
|
|
|
19
19
|
"禁止输出推理过程、解释、Markdown 或代码块;不要思考展开,只做快速匹配。",
|
|
20
20
|
"只允许根据用户消息中提供的行业/主题分类字典和股票列表输出纯 JSON 数组。"
|
|
21
21
|
].join("\n");
|
|
22
|
-
function normalizeStockCodeForCache(
|
|
23
|
-
const code = String(
|
|
22
|
+
function normalizeStockCodeForCache(stock_code, exchange) {
|
|
23
|
+
const code = String(stock_code || "")
|
|
24
24
|
.trim()
|
|
25
25
|
.toUpperCase();
|
|
26
26
|
if (/\.(SH|SS|SZ|HK|US)$/i.test(code)) {
|
|
@@ -37,18 +37,18 @@ function normalizeStockCodeForCache(stockCode, exchange) {
|
|
|
37
37
|
return code;
|
|
38
38
|
}
|
|
39
39
|
}
|
|
40
|
-
function legacyStockCodeWithoutSuffix(
|
|
41
|
-
return String(
|
|
40
|
+
function legacyStockCodeWithoutSuffix(stock_code) {
|
|
41
|
+
return String(stock_code || "")
|
|
42
42
|
.trim()
|
|
43
43
|
.toUpperCase()
|
|
44
44
|
.replace(/\.(SH|SS|SZ|HK|US)$/i, "");
|
|
45
45
|
}
|
|
46
|
-
function getCachedClassificationRow(db,
|
|
47
|
-
const cacheCode = normalizeStockCodeForCache(
|
|
48
|
-
const legacyCode = legacyStockCodeWithoutSuffix(
|
|
46
|
+
function getCachedClassificationRow(db, stock_code, exchange) {
|
|
47
|
+
const cacheCode = normalizeStockCodeForCache(stock_code, exchange);
|
|
48
|
+
const legacyCode = legacyStockCodeWithoutSuffix(stock_code);
|
|
49
49
|
const stmt = db.prepare(`
|
|
50
|
-
SELECT
|
|
51
|
-
WHERE
|
|
50
|
+
SELECT industry_classification, theme_classification FROM stock_classification_cache
|
|
51
|
+
WHERE stock_code = ? AND exchange = ?
|
|
52
52
|
`);
|
|
53
53
|
return (stmt.get(cacheCode, exchange) || (legacyCode !== cacheCode ? stmt.get(legacyCode, exchange) : undefined));
|
|
54
54
|
}
|
|
@@ -149,21 +149,21 @@ function extractJsonArray(text) {
|
|
|
149
149
|
}
|
|
150
150
|
export const watchlistLogic = {
|
|
151
151
|
_normalizeStockCodeForCache: normalizeStockCodeForCache,
|
|
152
|
-
async getStockClassification(rt,
|
|
152
|
+
async getStockClassification(rt, stock_name, stock_code, exchange, _userId) {
|
|
153
153
|
const db = getDB();
|
|
154
|
-
const cached = getCachedClassificationRow(db,
|
|
155
|
-
if (cached && cached.
|
|
154
|
+
const cached = getCachedClassificationRow(db, stock_code, exchange);
|
|
155
|
+
if (cached && cached.industry_classification) {
|
|
156
156
|
try {
|
|
157
157
|
return watchlistLogic._normalizeCachedClassification({
|
|
158
|
-
industry: JSON.parse(cached.
|
|
159
|
-
theme: JSON.parse(cached.
|
|
158
|
+
industry: JSON.parse(cached.industry_classification),
|
|
159
|
+
theme: JSON.parse(cached.theme_classification || '[]'),
|
|
160
160
|
weight: 50
|
|
161
161
|
});
|
|
162
162
|
}
|
|
163
163
|
catch (e) {
|
|
164
164
|
}
|
|
165
165
|
}
|
|
166
|
-
const classification = await watchlistLogic._autoClassifyWithAI(rt,
|
|
166
|
+
const classification = await watchlistLogic._autoClassifyWithAI(rt, stock_name, stock_code, exchange);
|
|
167
167
|
return classification;
|
|
168
168
|
},
|
|
169
169
|
async classifyStocksTogether(rt, stocks, _userId) {
|
|
@@ -171,12 +171,12 @@ export const watchlistLogic = {
|
|
|
171
171
|
const results = new Array(stocks.length).fill(null);
|
|
172
172
|
const pendingStocks = [];
|
|
173
173
|
stocks.forEach((stock, idx) => {
|
|
174
|
-
const cached = getCachedClassificationRow(db, stock.
|
|
175
|
-
if (cached && cached.
|
|
174
|
+
const cached = getCachedClassificationRow(db, stock.stock_code, stock.exchange);
|
|
175
|
+
if (cached && cached.industry_classification) {
|
|
176
176
|
try {
|
|
177
177
|
results[idx] = watchlistLogic._normalizeCachedClassification({
|
|
178
|
-
industry: JSON.parse(cached.
|
|
179
|
-
theme: JSON.parse(cached.
|
|
178
|
+
industry: JSON.parse(cached.industry_classification),
|
|
179
|
+
theme: JSON.parse(cached.theme_classification || '[]'),
|
|
180
180
|
weight: 50
|
|
181
181
|
});
|
|
182
182
|
return;
|
|
@@ -186,8 +186,8 @@ export const watchlistLogic = {
|
|
|
186
186
|
}
|
|
187
187
|
pendingStocks.push({
|
|
188
188
|
idx,
|
|
189
|
-
|
|
190
|
-
|
|
189
|
+
stock_name: stock.stock_name,
|
|
190
|
+
stock_code: stock.stock_code,
|
|
191
191
|
exchange: stock.exchange
|
|
192
192
|
});
|
|
193
193
|
});
|
|
@@ -198,7 +198,7 @@ export const watchlistLogic = {
|
|
|
198
198
|
if (cats.industries.length === 0) {
|
|
199
199
|
throw new Error("行业分类字典为空,无法分析行业/主题关系");
|
|
200
200
|
}
|
|
201
|
-
const stocksList = pendingStocks.map(s => `- ${s.
|
|
201
|
+
const stocksList = pendingStocks.map(s => `- ${s.stock_name} (${s.stock_code})`).join("\n");
|
|
202
202
|
const prompt = watchlistLogic._buildAiPrompt(cats.industries, cats.themes, stocksList, true);
|
|
203
203
|
const sessionId = `classify-batch-${randomUUID()}`;
|
|
204
204
|
const aiText = await watchlistLogic._callClassifierAi(rt, sessionId, prompt, resolveBatchClassificationTimeoutMs(pendingStocks.length));
|
|
@@ -209,7 +209,7 @@ export const watchlistLogic = {
|
|
|
209
209
|
catch (e) {
|
|
210
210
|
logger.warn({
|
|
211
211
|
err: e instanceof Error ? e.message : String(e),
|
|
212
|
-
pendingCodes: pendingStocks.map(stock => stock.
|
|
212
|
+
pendingCodes: pendingStocks.map(stock => stock.stock_code),
|
|
213
213
|
aiTextLength: aiText.length,
|
|
214
214
|
aiText
|
|
215
215
|
}, "[Watchlist] batch classification AI parse failed");
|
|
@@ -223,17 +223,17 @@ export const watchlistLogic = {
|
|
|
223
223
|
let parsedResults;
|
|
224
224
|
try {
|
|
225
225
|
parsedResults = pendingStocks.map((stock, i) => {
|
|
226
|
-
const raw = parsedByCode.get(String(stock.
|
|
226
|
+
const raw = parsedByCode.get(String(stock.stock_code)) || parsed[i];
|
|
227
227
|
return {
|
|
228
228
|
stock,
|
|
229
|
-
data: watchlistLogic._parseClassification(raw, cats, stock.
|
|
229
|
+
data: watchlistLogic._parseClassification(raw, cats, stock.stock_name || stock.stock_code)
|
|
230
230
|
};
|
|
231
231
|
});
|
|
232
232
|
}
|
|
233
233
|
catch (e) {
|
|
234
234
|
logger.warn({
|
|
235
235
|
err: e instanceof Error ? e.message : String(e),
|
|
236
|
-
pendingCodes: pendingStocks.map(stock => stock.
|
|
236
|
+
pendingCodes: pendingStocks.map(stock => stock.stock_code),
|
|
237
237
|
aiTextLength: aiText.length,
|
|
238
238
|
aiText
|
|
239
239
|
}, "[Watchlist] batch classification AI semantic parse failed");
|
|
@@ -244,7 +244,7 @@ export const watchlistLogic = {
|
|
|
244
244
|
}
|
|
245
245
|
const missing = stocks.find((_, i) => !results[i]);
|
|
246
246
|
if (missing) {
|
|
247
|
-
throw new Error(`行业/主题关系分析失败: ${missing.
|
|
247
|
+
throw new Error(`行业/主题关系分析失败: ${missing.stock_name || missing.stock_code}`);
|
|
248
248
|
}
|
|
249
249
|
return results;
|
|
250
250
|
},
|
|
@@ -255,21 +255,21 @@ export const watchlistLogic = {
|
|
|
255
255
|
stocks.forEach((s, i) => {
|
|
256
256
|
const cached = options.forceRefresh
|
|
257
257
|
? undefined
|
|
258
|
-
: getCachedClassificationRow(db, s.
|
|
259
|
-
if (cached && cached.
|
|
258
|
+
: getCachedClassificationRow(db, s.stock_code, s.exchange);
|
|
259
|
+
if (cached && cached.industry_classification) {
|
|
260
260
|
try {
|
|
261
261
|
results[i] = watchlistLogic._normalizeCachedClassification({
|
|
262
|
-
industry: JSON.parse(cached.
|
|
263
|
-
theme: JSON.parse(cached.
|
|
262
|
+
industry: JSON.parse(cached.industry_classification),
|
|
263
|
+
theme: JSON.parse(cached.theme_classification || '[]'),
|
|
264
264
|
weight: 50
|
|
265
265
|
});
|
|
266
266
|
}
|
|
267
267
|
catch (e) {
|
|
268
|
-
pendingStocks.push({ idx: i, name: s.
|
|
268
|
+
pendingStocks.push({ idx: i, name: s.stock_name, code: s.stock_code, exchange: s.exchange });
|
|
269
269
|
}
|
|
270
270
|
}
|
|
271
271
|
else {
|
|
272
|
-
pendingStocks.push({ idx: i, name: s.
|
|
272
|
+
pendingStocks.push({ idx: i, name: s.stock_name, code: s.stock_code, exchange: s.exchange });
|
|
273
273
|
}
|
|
274
274
|
});
|
|
275
275
|
if (pendingStocks.length > 0) {
|
|
@@ -309,36 +309,36 @@ export const watchlistLogic = {
|
|
|
309
309
|
if (options.requireComplete) {
|
|
310
310
|
const missing = stocks.find((_, i) => !results[i]);
|
|
311
311
|
if (missing) {
|
|
312
|
-
throw new Error(`行业/主题关系分析失败: ${missing.
|
|
312
|
+
throw new Error(`行业/主题关系分析失败: ${missing.stock_name || missing.stock_code}`);
|
|
313
313
|
}
|
|
314
314
|
}
|
|
315
315
|
return results;
|
|
316
316
|
},
|
|
317
317
|
_getKnownCategories(db) {
|
|
318
|
-
const industries = db.prepare("SELECT name FROM
|
|
319
|
-
const themes = db.prepare("SELECT name FROM
|
|
318
|
+
const industries = db.prepare("SELECT name FROM industry_theme_categories WHERE type = 'industry'").all();
|
|
319
|
+
const themes = db.prepare("SELECT name FROM industry_theme_categories WHERE type = 'theme'").all();
|
|
320
320
|
return {
|
|
321
321
|
industries: industries.map(i => i.name),
|
|
322
322
|
themes: themes.map(t => t.name)
|
|
323
323
|
};
|
|
324
324
|
},
|
|
325
|
-
async _autoClassifyWithAI(rt,
|
|
325
|
+
async _autoClassifyWithAI(rt, stock_name, stock_code, exchange) {
|
|
326
326
|
const db = getDB();
|
|
327
327
|
const cats = watchlistLogic._getKnownCategories(db);
|
|
328
328
|
if (cats.industries.length === 0) {
|
|
329
329
|
return null;
|
|
330
330
|
}
|
|
331
|
-
const prompt = watchlistLogic._buildAiPrompt(cats.industries, cats.themes, `${
|
|
332
|
-
const aiText = await watchlistLogic._callClassifierAi(rt, `classify-${
|
|
331
|
+
const prompt = watchlistLogic._buildAiPrompt(cats.industries, cats.themes, `${stock_name} (${stock_code})`, false);
|
|
332
|
+
const aiText = await watchlistLogic._callClassifierAi(rt, `classify-${stock_code}`, prompt, SINGLE_CLASSIFICATION_TIMEOUT_MS);
|
|
333
333
|
try {
|
|
334
334
|
const parsed = extractJsonArray(aiText);
|
|
335
335
|
const raw = parsed[0];
|
|
336
336
|
if (raw) {
|
|
337
|
-
return watchlistLogic._parseClassification(raw, cats,
|
|
337
|
+
return watchlistLogic._parseClassification(raw, cats, stock_name || stock_code);
|
|
338
338
|
}
|
|
339
339
|
}
|
|
340
340
|
catch (e) {
|
|
341
|
-
logger.warn({ err: e instanceof Error ? e.message : String(e),
|
|
341
|
+
logger.warn({ err: e instanceof Error ? e.message : String(e), stock_code, stock_name }, "[Watchlist] AI 分类解析异常");
|
|
342
342
|
}
|
|
343
343
|
return null;
|
|
344
344
|
},
|
|
@@ -355,11 +355,12 @@ export const watchlistLogic = {
|
|
|
355
355
|
}
|
|
356
356
|
}
|
|
357
357
|
};
|
|
358
|
-
const
|
|
358
|
+
const completionModelParams = {
|
|
359
359
|
cfg: embeddedCfg,
|
|
360
360
|
agentId: MAIN_AGENT_ID,
|
|
361
361
|
allowBundledStaticCatalogFallback: true
|
|
362
|
-
}
|
|
362
|
+
};
|
|
363
|
+
const prepared = await prepareSimpleCompletionModelForAgent(completionModelParams);
|
|
363
364
|
if ("error" in prepared) {
|
|
364
365
|
throw new Error(prepared.error);
|
|
365
366
|
}
|
|
@@ -409,13 +410,13 @@ export const watchlistLogic = {
|
|
|
409
410
|
}
|
|
410
411
|
},
|
|
411
412
|
_ensureCategory(db, name, type, userId) {
|
|
412
|
-
const existing = db.prepare("SELECT id FROM
|
|
413
|
+
const existing = db.prepare("SELECT id FROM industry_theme_categories WHERE userId = ? AND name = ? AND type = ?").get(userId, name, type);
|
|
413
414
|
if (existing)
|
|
414
415
|
return existing.id;
|
|
415
|
-
const maxOrderRow = db.prepare("SELECT MAX(sortOrder) as max FROM
|
|
416
|
+
const maxOrderRow = db.prepare("SELECT MAX(sortOrder) as max FROM industry_theme_categories WHERE userId = ?").get(userId);
|
|
416
417
|
const nextOrder = (maxOrderRow?.max || 0) + 10;
|
|
417
418
|
const id = randomUUID();
|
|
418
|
-
db.prepare(`INSERT INTO
|
|
419
|
+
db.prepare(`INSERT INTO industry_theme_categories (id, userId, name, type, sortOrder, weight) VALUES (?, ?, ?, ?, ?, 0)`).run(id, userId, name, type, nextOrder);
|
|
419
420
|
return id;
|
|
420
421
|
},
|
|
421
422
|
_buildSmartSortPrompt(stocks) {
|