fi-pool-server 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +26 -0
- package/dist/db/index.d.ts +18 -0
- package/dist/db/index.d.ts.map +1 -0
- package/dist/db/index.js +58 -0
- package/dist/db/index.js.map +1 -0
- package/dist/db/migrate.d.ts +11 -0
- package/dist/db/migrate.d.ts.map +1 -0
- package/dist/db/migrate.js +42 -0
- package/dist/db/migrate.js.map +1 -0
- package/dist/db/schema.d.ts +1101 -0
- package/dist/db/schema.d.ts.map +1 -0
- package/dist/db/schema.js +149 -0
- package/dist/db/schema.js.map +1 -0
- package/dist/index.d.ts +50 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +69 -0
- package/dist/index.js.map +1 -0
- package/dist/services/analysis.d.ts +62 -0
- package/dist/services/analysis.d.ts.map +1 -0
- package/dist/services/analysis.js +74 -0
- package/dist/services/analysis.js.map +1 -0
- package/dist/services/daily-info.d.ts +150 -0
- package/dist/services/daily-info.d.ts.map +1 -0
- package/dist/services/daily-info.js +293 -0
- package/dist/services/daily-info.js.map +1 -0
- package/dist/services/embedding.d.ts +89 -0
- package/dist/services/embedding.d.ts.map +1 -0
- package/dist/services/embedding.js +227 -0
- package/dist/services/embedding.js.map +1 -0
- package/dist/services/llm.d.ts +64 -0
- package/dist/services/llm.d.ts.map +1 -0
- package/dist/services/llm.js +109 -0
- package/dist/services/llm.js.map +1 -0
- package/dist/services/pipeline.d.ts +161 -0
- package/dist/services/pipeline.d.ts.map +1 -0
- package/dist/services/pipeline.js +844 -0
- package/dist/services/pipeline.js.map +1 -0
- package/dist/services/pool.d.ts +142 -0
- package/dist/services/pool.d.ts.map +1 -0
- package/dist/services/pool.js +208 -0
- package/dist/services/pool.js.map +1 -0
- package/dist/services/sentiment.d.ts +31 -0
- package/dist/services/sentiment.d.ts.map +1 -0
- package/dist/services/sentiment.js +76 -0
- package/dist/services/sentiment.js.map +1 -0
- package/dist/services/session.d.ts +117 -0
- package/dist/services/session.d.ts.map +1 -0
- package/dist/services/session.js +176 -0
- package/dist/services/session.js.map +1 -0
- package/dist/services/stock.d.ts +82 -0
- package/dist/services/stock.d.ts.map +1 -0
- package/dist/services/stock.js +99 -0
- package/dist/services/stock.js.map +1 -0
- package/dist/services/word-count.d.ts +61 -0
- package/dist/services/word-count.d.ts.map +1 -0
- package/dist/services/word-count.js +120 -0
- package/dist/services/word-count.js.map +1 -0
- package/dist/tools/auxiliary.d.ts +93 -0
- package/dist/tools/auxiliary.d.ts.map +1 -0
- package/dist/tools/auxiliary.js +204 -0
- package/dist/tools/auxiliary.js.map +1 -0
- package/dist/tools/command.d.ts +193 -0
- package/dist/tools/command.d.ts.map +1 -0
- package/dist/tools/command.js +263 -0
- package/dist/tools/command.js.map +1 -0
- package/dist/tools/execute.d.ts +109 -0
- package/dist/tools/execute.d.ts.map +1 -0
- package/dist/tools/execute.js +112 -0
- package/dist/tools/execute.js.map +1 -0
- package/dist/tools/manager.d.ts +150 -0
- package/dist/tools/manager.d.ts.map +1 -0
- package/dist/tools/manager.js +200 -0
- package/dist/tools/manager.js.map +1 -0
- package/dist/tools/query.d.ts +163 -0
- package/dist/tools/query.d.ts.map +1 -0
- package/dist/tools/query.js +190 -0
- package/dist/tools/query.js.map +1 -0
- package/dist/utils/http-client.d.ts +87 -0
- package/dist/utils/http-client.d.ts.map +1 -0
- package/dist/utils/http-client.js +211 -0
- package/dist/utils/http-client.js.map +1 -0
- package/dist/utils/indicators.d.ts +194 -0
- package/dist/utils/indicators.d.ts.map +1 -0
- package/dist/utils/indicators.js +395 -0
- package/dist/utils/indicators.js.map +1 -0
- package/dist/utils/signals.d.ts +65 -0
- package/dist/utils/signals.d.ts.map +1 -0
- package/dist/utils/signals.js +171 -0
- package/dist/utils/signals.js.map +1 -0
- package/drizzle/0000_equal_marvel_apes.sql +124 -0
- package/drizzle/meta/0000_snapshot.json +858 -0
- package/drizzle/meta/_journal.json +13 -0
- package/package.json +58 -0
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 技术指标计算工具模块
|
|
3
|
+
*
|
|
4
|
+
* 提供 A 股常用的技术分析指标计算函数。
|
|
5
|
+
* 所有函数接收 OHLCV 日行情数组,返回与输入等长的计算结果数组。
|
|
6
|
+
* 数据不足时对应位置填充 null。
|
|
7
|
+
*
|
|
8
|
+
* @module indicators
|
|
9
|
+
*/
|
|
10
|
+
/**
|
|
11
|
+
* OHLCV 日行情数据点
|
|
12
|
+
*/
|
|
13
|
+
export interface OHLCV {
|
|
14
|
+
/** 日期,格式 'yyyy-MM-dd' */
|
|
15
|
+
date: string;
|
|
16
|
+
/** 开盘价 */
|
|
17
|
+
open: number;
|
|
18
|
+
/** 最高价 */
|
|
19
|
+
high: number;
|
|
20
|
+
/** 最低价 */
|
|
21
|
+
low: number;
|
|
22
|
+
/** 收盘价 */
|
|
23
|
+
close: number;
|
|
24
|
+
/** 成交量(股数) */
|
|
25
|
+
volume: number;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* 计算简单移动平均线(SMA)
|
|
29
|
+
*
|
|
30
|
+
* 公式:MA = (P₁ + P₂ + ... + Pₙ) / n
|
|
31
|
+
* 前 n-1 个位置为 null(数据不足)。
|
|
32
|
+
*
|
|
33
|
+
* @param data - OHLCV 数组
|
|
34
|
+
* @param period - 计算周期(如 5、10、20)
|
|
35
|
+
* @returns 长度与 data 相同的数组,每个元素为对应周期的 MA 值或 null
|
|
36
|
+
*
|
|
37
|
+
* @example
|
|
38
|
+
* ```typescript
|
|
39
|
+
* const ma5 = calcMA(dailyData, 5);
|
|
40
|
+
* // ma5[4] 为第 1-5 天的平均值
|
|
41
|
+
* ```
|
|
42
|
+
*/
|
|
43
|
+
export declare function calcMA(data: OHLCV[], period: number): (number | null)[];
|
|
44
|
+
/**
|
|
45
|
+
* 计算指数移动平均线(EMA)
|
|
46
|
+
*
|
|
47
|
+
* 公式:
|
|
48
|
+
* multiplier = 2 / (n + 1)
|
|
49
|
+
* EMA₁ = SMA(前 n 个 close)
|
|
50
|
+
* EMAₜ = (closeₜ - EMAₜ₋₁) × multiplier + EMAₜ₋₁
|
|
51
|
+
*
|
|
52
|
+
* 前 n-1 个位置为 null(数据不足)。
|
|
53
|
+
*
|
|
54
|
+
* @param data - OHLCV 数组
|
|
55
|
+
* @param period - 计算周期(如 12、26)
|
|
56
|
+
* @returns 长度与 data 相同的数组,每个元素为对应位置的 EMA 值或 null
|
|
57
|
+
*/
|
|
58
|
+
export declare function calcEMA(data: OHLCV[], period: number): (number | null)[];
|
|
59
|
+
/**
|
|
60
|
+
* 计算 MACD 指标(指数平滑异同移动平均线)
|
|
61
|
+
*
|
|
62
|
+
* 标准参数 (12, 26, 9):
|
|
63
|
+
* DIF = EMA₁₂(close) − EMA₂₆(close)
|
|
64
|
+
* DEA = EMA₉(DIF)
|
|
65
|
+
* Histogram = 2 × (DIF − DEA)
|
|
66
|
+
*
|
|
67
|
+
* @param data - OHLCV 数组
|
|
68
|
+
* @returns 包含 DIF、DEA、Histogram 三个等长数组的对象
|
|
69
|
+
*
|
|
70
|
+
* @example
|
|
71
|
+
* ```typescript
|
|
72
|
+
* const { dif, dea, histogram } = calcMACD(dailyData);
|
|
73
|
+
* // 最后一个值为最新信号
|
|
74
|
+
* ```
|
|
75
|
+
*/
|
|
76
|
+
export declare function calcMACD(data: OHLCV[]): {
|
|
77
|
+
dif: (number | null)[];
|
|
78
|
+
dea: (number | null)[];
|
|
79
|
+
histogram: (number | null)[];
|
|
80
|
+
};
|
|
81
|
+
/**
|
|
82
|
+
* 计算相对强弱指标(RSI)
|
|
83
|
+
*
|
|
84
|
+
* 使用 Wilder 平滑法(改良指数平均):
|
|
85
|
+
* 1. 计算每日价格变动 Δ = closeₜ − closeₜ₋₁
|
|
86
|
+
* 2. 初始平均涨幅 = 前 n 个 Δ 中正值的平均值
|
|
87
|
+
* 初始平均跌幅 = 前 n 个 Δ 中负值绝对值的平均值
|
|
88
|
+
* 3. 后续平滑:
|
|
89
|
+
* avgGainₜ = (avgGainₜ₋₁ × (n−1) + gainₜ) / n
|
|
90
|
+
* avgLossₜ = (avgLossₜ₋₁ × (n−1) + lossₜ) / n
|
|
91
|
+
* 4. RS = avgGain / avgLoss
|
|
92
|
+
* RSI = 100 − 100 / (1 + RS)
|
|
93
|
+
*
|
|
94
|
+
* 前 n 个位置为 null(需要 n+1 个价格才能计算第一个 RSI 值)。
|
|
95
|
+
*
|
|
96
|
+
* @param data - OHLCV 数组
|
|
97
|
+
* @param period - RSI 计算周期(通常为 14)
|
|
98
|
+
* @returns 长度与 data 相同的 RSI 值数组
|
|
99
|
+
*
|
|
100
|
+
* @example
|
|
101
|
+
* ```typescript
|
|
102
|
+
* const rsi14 = calcRSI(dailyData, 14);
|
|
103
|
+
* ```
|
|
104
|
+
*/
|
|
105
|
+
export declare function calcRSI(data: OHLCV[], period: number): (number | null)[];
|
|
106
|
+
/**
|
|
107
|
+
* 计算 KDJ 指标(随机指标)
|
|
108
|
+
*
|
|
109
|
+
* 标准参数 (9, 3, 3):
|
|
110
|
+
* 1. RSV = (close − LLV) / (HHV − LLV) × 100
|
|
111
|
+
* 其中 LLV 为最近 period 周期的最低价,HHV 为最近 period 周期的最高价
|
|
112
|
+
* 2. Kₜ = ⅔ × Kₜ₋₁ + ⅓ × RSVₜ (初始 K = 50)
|
|
113
|
+
* 3. Dₜ = ⅔ × Dₜ₋₁ + ⅓ × Kₜ (初始 D = 50)
|
|
114
|
+
* 4. Jₜ = 3 × Kₜ − 2 × Dₜ
|
|
115
|
+
*
|
|
116
|
+
* 前 period-1 个位置为 null(数据不足)。
|
|
117
|
+
*
|
|
118
|
+
* @param data - OHLCV 数组
|
|
119
|
+
* @param period - 周期(默认 9,即 RSV 的观察窗口)
|
|
120
|
+
* @returns 包含 K、D、J 三个等长数组的对象
|
|
121
|
+
*
|
|
122
|
+
* @example
|
|
123
|
+
* ```typescript
|
|
124
|
+
* const { k, d, j } = calcKDJ(dailyData);
|
|
125
|
+
* ```
|
|
126
|
+
*/
|
|
127
|
+
export declare function calcKDJ(data: OHLCV[], period?: number): {
|
|
128
|
+
k: (number | null)[];
|
|
129
|
+
d: (number | null)[];
|
|
130
|
+
j: (number | null)[];
|
|
131
|
+
};
|
|
132
|
+
/**
|
|
133
|
+
* 计算布林带(Bollinger Bands)
|
|
134
|
+
*
|
|
135
|
+
* 公式(标准参数 20, 2):
|
|
136
|
+
* MID = SMA(close, n)
|
|
137
|
+
* StdDev = √(Σ(close − MID)² / n)
|
|
138
|
+
* UPPER = MID + multiplier × StdDev
|
|
139
|
+
* LOWER = MID − multiplier × StdDev
|
|
140
|
+
*
|
|
141
|
+
* 前 n-1 个位置为 null(数据不足)。
|
|
142
|
+
*
|
|
143
|
+
* @param data - OHLCV 数组
|
|
144
|
+
* @param period - 计算周期(默认 20)
|
|
145
|
+
* @param multiplier - 标准差倍数(默认 2)
|
|
146
|
+
* @returns 包含 upper、mid、lower 三个等长数组的对象
|
|
147
|
+
*
|
|
148
|
+
* @example
|
|
149
|
+
* ```typescript
|
|
150
|
+
* const { upper, mid, lower } = calcBollinger(dailyData, 20, 2);
|
|
151
|
+
* ```
|
|
152
|
+
*/
|
|
153
|
+
export declare function calcBollinger(data: OHLCV[], period?: number, multiplier?: number): {
|
|
154
|
+
upper: (number | null)[];
|
|
155
|
+
mid: (number | null)[];
|
|
156
|
+
lower: (number | null)[];
|
|
157
|
+
};
|
|
158
|
+
/**
|
|
159
|
+
* 计算指定位置的振幅
|
|
160
|
+
*
|
|
161
|
+
* 振幅 = (high − low) / prevClose × 100
|
|
162
|
+
*
|
|
163
|
+
* 首日(index = 0)因无前一日收盘价,返回 0。
|
|
164
|
+
*
|
|
165
|
+
* @param data - OHLCV 数组
|
|
166
|
+
* @param index - 目标位置(从 0 开始)
|
|
167
|
+
* @returns 振幅百分比
|
|
168
|
+
*
|
|
169
|
+
* @example
|
|
170
|
+
* ```typescript
|
|
171
|
+
* const amp = calcAmplitude(dailyData, dailyData.length - 1);
|
|
172
|
+
* // 最新一天的振幅
|
|
173
|
+
* ```
|
|
174
|
+
*/
|
|
175
|
+
export declare function calcAmplitude(data: OHLCV[], index: number): number;
|
|
176
|
+
/**
|
|
177
|
+
* 计算指定位置的涨跌幅
|
|
178
|
+
*
|
|
179
|
+
* 涨跌幅 = (close − prevClose) / prevClose × 100
|
|
180
|
+
*
|
|
181
|
+
* 首日(index = 0)因无前一日收盘价,返回 0。
|
|
182
|
+
*
|
|
183
|
+
* @param data - OHLCV 数组
|
|
184
|
+
* @param index - 目标位置(从 0 开始)
|
|
185
|
+
* @returns 涨跌幅百分比
|
|
186
|
+
*
|
|
187
|
+
* @example
|
|
188
|
+
* ```typescript
|
|
189
|
+
* const pct = calcPriceChangePct(dailyData, dailyData.length - 1);
|
|
190
|
+
* // 最新一天的涨跌幅
|
|
191
|
+
* ```
|
|
192
|
+
*/
|
|
193
|
+
export declare function calcPriceChangePct(data: OHLCV[], index: number): number;
|
|
194
|
+
//# sourceMappingURL=indicators.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"indicators.d.ts","sourceRoot":"","sources":["../../src/utils/indicators.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAIH;;GAEG;AACH,MAAM,WAAW,KAAK;IACpB,yBAAyB;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,UAAU;IACV,IAAI,EAAE,MAAM,CAAC;IACb,UAAU;IACV,IAAI,EAAE,MAAM,CAAC;IACb,UAAU;IACV,GAAG,EAAE,MAAM,CAAC;IACZ,UAAU;IACV,KAAK,EAAE,MAAM,CAAC;IACd,cAAc;IACd,MAAM,EAAE,MAAM,CAAC;CAChB;AAID;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,MAAM,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,MAAM,EAAE,MAAM,GAAG,CAAC,MAAM,GAAG,IAAI,CAAC,EAAE,CAuBvE;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,OAAO,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,MAAM,EAAE,MAAM,GAAG,CAAC,MAAM,GAAG,IAAI,CAAC,EAAE,CAyBxE;AAgDD;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,QAAQ,CACtB,IAAI,EAAE,KAAK,EAAE,GACZ;IAAE,GAAG,EAAE,CAAC,MAAM,GAAG,IAAI,CAAC,EAAE,CAAC;IAAC,GAAG,EAAE,CAAC,MAAM,GAAG,IAAI,CAAC,EAAE,CAAC;IAAC,SAAS,EAAE,CAAC,MAAM,GAAG,IAAI,CAAC,EAAE,CAAA;CAAE,CA0BlF;AAID;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAgB,OAAO,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,MAAM,EAAE,MAAM,GAAG,CAAC,MAAM,GAAG,IAAI,CAAC,EAAE,CAgDxE;AAID;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,OAAO,CACrB,IAAI,EAAE,KAAK,EAAE,EACb,MAAM,GAAE,MAAU,GACjB;IAAE,CAAC,EAAE,CAAC,MAAM,GAAG,IAAI,CAAC,EAAE,CAAC;IAAC,CAAC,EAAE,CAAC,MAAM,GAAG,IAAI,CAAC,EAAE,CAAC;IAAC,CAAC,EAAE,CAAC,MAAM,GAAG,IAAI,CAAC,EAAE,CAAA;CAAE,CA8CtE;AAID;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,aAAa,CAC3B,IAAI,EAAE,KAAK,EAAE,EACb,MAAM,GAAE,MAAW,EACnB,UAAU,GAAE,MAAU,GACrB;IAAE,KAAK,EAAE,CAAC,MAAM,GAAG,IAAI,CAAC,EAAE,CAAC;IAAC,GAAG,EAAE,CAAC,MAAM,GAAG,IAAI,CAAC,EAAE,CAAC;IAAC,KAAK,EAAE,CAAC,MAAM,GAAG,IAAI,CAAC,EAAE,CAAA;CAAE,CAgChF;AAID;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAalE;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAavE"}
|
|
@@ -0,0 +1,395 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 技术指标计算工具模块
|
|
3
|
+
*
|
|
4
|
+
* 提供 A 股常用的技术分析指标计算函数。
|
|
5
|
+
* 所有函数接收 OHLCV 日行情数组,返回与输入等长的计算结果数组。
|
|
6
|
+
* 数据不足时对应位置填充 null。
|
|
7
|
+
*
|
|
8
|
+
* @module indicators
|
|
9
|
+
*/
|
|
10
|
+
// ─── 移动平均线 ───────────────────────────────────────────────
|
|
11
|
+
/**
|
|
12
|
+
* 计算简单移动平均线(SMA)
|
|
13
|
+
*
|
|
14
|
+
* 公式:MA = (P₁ + P₂ + ... + Pₙ) / n
|
|
15
|
+
* 前 n-1 个位置为 null(数据不足)。
|
|
16
|
+
*
|
|
17
|
+
* @param data - OHLCV 数组
|
|
18
|
+
* @param period - 计算周期(如 5、10、20)
|
|
19
|
+
* @returns 长度与 data 相同的数组,每个元素为对应周期的 MA 值或 null
|
|
20
|
+
*
|
|
21
|
+
* @example
|
|
22
|
+
* ```typescript
|
|
23
|
+
* const ma5 = calcMA(dailyData, 5);
|
|
24
|
+
* // ma5[4] 为第 1-5 天的平均值
|
|
25
|
+
* ```
|
|
26
|
+
*/
|
|
27
|
+
export function calcMA(data, period) {
|
|
28
|
+
const result = new Array(data.length).fill(null);
|
|
29
|
+
if (data.length < period || period <= 0) {
|
|
30
|
+
return result;
|
|
31
|
+
}
|
|
32
|
+
// 滑动窗口求和,避免每次重新遍历
|
|
33
|
+
let sum = 0;
|
|
34
|
+
// 填充第一个窗口
|
|
35
|
+
for (let i = 0; i < period; i++) {
|
|
36
|
+
sum += data[i].close;
|
|
37
|
+
}
|
|
38
|
+
result[period - 1] = sum / period;
|
|
39
|
+
// 滑动窗口
|
|
40
|
+
for (let i = period; i < data.length; i++) {
|
|
41
|
+
sum += data[i].close - data[i - period].close;
|
|
42
|
+
result[i] = sum / period;
|
|
43
|
+
}
|
|
44
|
+
return result;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* 计算指数移动平均线(EMA)
|
|
48
|
+
*
|
|
49
|
+
* 公式:
|
|
50
|
+
* multiplier = 2 / (n + 1)
|
|
51
|
+
* EMA₁ = SMA(前 n 个 close)
|
|
52
|
+
* EMAₜ = (closeₜ - EMAₜ₋₁) × multiplier + EMAₜ₋₁
|
|
53
|
+
*
|
|
54
|
+
* 前 n-1 个位置为 null(数据不足)。
|
|
55
|
+
*
|
|
56
|
+
* @param data - OHLCV 数组
|
|
57
|
+
* @param period - 计算周期(如 12、26)
|
|
58
|
+
* @returns 长度与 data 相同的数组,每个元素为对应位置的 EMA 值或 null
|
|
59
|
+
*/
|
|
60
|
+
export function calcEMA(data, period) {
|
|
61
|
+
const result = new Array(data.length).fill(null);
|
|
62
|
+
if (data.length < period || period <= 0) {
|
|
63
|
+
return result;
|
|
64
|
+
}
|
|
65
|
+
const multiplier = 2 / (period + 1);
|
|
66
|
+
// 初始 EMA = 第一个周期的 SMA
|
|
67
|
+
let sum = 0;
|
|
68
|
+
for (let i = 0; i < period; i++) {
|
|
69
|
+
sum += data[i].close;
|
|
70
|
+
}
|
|
71
|
+
let prevEma = sum / period;
|
|
72
|
+
result[period - 1] = prevEma;
|
|
73
|
+
// 递推计算后续 EMA
|
|
74
|
+
for (let i = period; i < data.length; i++) {
|
|
75
|
+
const ema = (data[i].close - prevEma) * multiplier + prevEma;
|
|
76
|
+
result[i] = ema;
|
|
77
|
+
prevEma = ema;
|
|
78
|
+
}
|
|
79
|
+
return result;
|
|
80
|
+
}
|
|
81
|
+
// ─── MACD ──────────────────────────────────────────────────────
|
|
82
|
+
/**
|
|
83
|
+
* 从可空数组中提取有效值及其索引,计算 EMA
|
|
84
|
+
*
|
|
85
|
+
* 内部辅助函数,用于对 DIF 序列计算 DEA。
|
|
86
|
+
*
|
|
87
|
+
* @param values - 可能包含 null 的数值数组
|
|
88
|
+
* @param period - EMA 周期
|
|
89
|
+
* @returns 长度与 values 相同的 EMA 计算结果数组
|
|
90
|
+
*/
|
|
91
|
+
function emaOnNullable(values, period) {
|
|
92
|
+
const result = new Array(values.length).fill(null);
|
|
93
|
+
// 收集所有非 null 值及其索引
|
|
94
|
+
const valid = [];
|
|
95
|
+
for (let i = 0; i < values.length; i++) {
|
|
96
|
+
if (values[i] !== null) {
|
|
97
|
+
valid.push({ value: values[i], index: i });
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
if (valid.length < period || period <= 0) {
|
|
101
|
+
return result;
|
|
102
|
+
}
|
|
103
|
+
const multiplier = 2 / (period + 1);
|
|
104
|
+
// 初始 EMA = 第一个周期的 SMA
|
|
105
|
+
let sum = 0;
|
|
106
|
+
for (let i = 0; i < period; i++) {
|
|
107
|
+
sum += valid[i].value;
|
|
108
|
+
}
|
|
109
|
+
let prevEma = sum / period;
|
|
110
|
+
result[valid[period - 1].index] = prevEma;
|
|
111
|
+
// 递推计算后续 EMA
|
|
112
|
+
for (let i = period; i < valid.length; i++) {
|
|
113
|
+
const ema = (valid[i].value - prevEma) * multiplier + prevEma;
|
|
114
|
+
result[valid[i].index] = ema;
|
|
115
|
+
prevEma = ema;
|
|
116
|
+
}
|
|
117
|
+
return result;
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* 计算 MACD 指标(指数平滑异同移动平均线)
|
|
121
|
+
*
|
|
122
|
+
* 标准参数 (12, 26, 9):
|
|
123
|
+
* DIF = EMA₁₂(close) − EMA₂₆(close)
|
|
124
|
+
* DEA = EMA₉(DIF)
|
|
125
|
+
* Histogram = 2 × (DIF − DEA)
|
|
126
|
+
*
|
|
127
|
+
* @param data - OHLCV 数组
|
|
128
|
+
* @returns 包含 DIF、DEA、Histogram 三个等长数组的对象
|
|
129
|
+
*
|
|
130
|
+
* @example
|
|
131
|
+
* ```typescript
|
|
132
|
+
* const { dif, dea, histogram } = calcMACD(dailyData);
|
|
133
|
+
* // 最后一个值为最新信号
|
|
134
|
+
* ```
|
|
135
|
+
*/
|
|
136
|
+
export function calcMACD(data) {
|
|
137
|
+
const ema12 = calcEMA(data, 12);
|
|
138
|
+
const ema26 = calcEMA(data, 26);
|
|
139
|
+
const length = data.length;
|
|
140
|
+
const dif = new Array(length).fill(null);
|
|
141
|
+
// DIF = EMA12 - EMA26(两者均非 null 时有效)
|
|
142
|
+
for (let i = 0; i < length; i++) {
|
|
143
|
+
if (ema12[i] !== null && ema26[i] !== null) {
|
|
144
|
+
dif[i] = ema12[i] - ema26[i];
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
// DEA = EMA9(DIF)
|
|
148
|
+
const dea = emaOnNullable(dif, 9);
|
|
149
|
+
// Histogram = 2 * (DIF - DEA)
|
|
150
|
+
const histogram = new Array(length).fill(null);
|
|
151
|
+
for (let i = 0; i < length; i++) {
|
|
152
|
+
if (dif[i] !== null && dea[i] !== null) {
|
|
153
|
+
histogram[i] = 2 * (dif[i] - dea[i]);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
return { dif, dea, histogram };
|
|
157
|
+
}
|
|
158
|
+
// ─── RSI ──────────────────────────────────────────────────────
|
|
159
|
+
/**
|
|
160
|
+
* 计算相对强弱指标(RSI)
|
|
161
|
+
*
|
|
162
|
+
* 使用 Wilder 平滑法(改良指数平均):
|
|
163
|
+
* 1. 计算每日价格变动 Δ = closeₜ − closeₜ₋₁
|
|
164
|
+
* 2. 初始平均涨幅 = 前 n 个 Δ 中正值的平均值
|
|
165
|
+
* 初始平均跌幅 = 前 n 个 Δ 中负值绝对值的平均值
|
|
166
|
+
* 3. 后续平滑:
|
|
167
|
+
* avgGainₜ = (avgGainₜ₋₁ × (n−1) + gainₜ) / n
|
|
168
|
+
* avgLossₜ = (avgLossₜ₋₁ × (n−1) + lossₜ) / n
|
|
169
|
+
* 4. RS = avgGain / avgLoss
|
|
170
|
+
* RSI = 100 − 100 / (1 + RS)
|
|
171
|
+
*
|
|
172
|
+
* 前 n 个位置为 null(需要 n+1 个价格才能计算第一个 RSI 值)。
|
|
173
|
+
*
|
|
174
|
+
* @param data - OHLCV 数组
|
|
175
|
+
* @param period - RSI 计算周期(通常为 14)
|
|
176
|
+
* @returns 长度与 data 相同的 RSI 值数组
|
|
177
|
+
*
|
|
178
|
+
* @example
|
|
179
|
+
* ```typescript
|
|
180
|
+
* const rsi14 = calcRSI(dailyData, 14);
|
|
181
|
+
* ```
|
|
182
|
+
*/
|
|
183
|
+
export function calcRSI(data, period) {
|
|
184
|
+
const result = new Array(data.length).fill(null);
|
|
185
|
+
if (data.length < period + 1 || period <= 0) {
|
|
186
|
+
return result;
|
|
187
|
+
}
|
|
188
|
+
// 计算每日价格变化
|
|
189
|
+
const changes = new Array(data.length - 1);
|
|
190
|
+
for (let i = 1; i < data.length; i++) {
|
|
191
|
+
changes[i - 1] = data[i].close - data[i - 1].close;
|
|
192
|
+
}
|
|
193
|
+
// 初始平均涨幅/跌幅(前 period 个变化值)
|
|
194
|
+
let avgGain = 0;
|
|
195
|
+
let avgLoss = 0;
|
|
196
|
+
for (let i = 0; i < period; i++) {
|
|
197
|
+
const change = changes[i];
|
|
198
|
+
if (change > 0) {
|
|
199
|
+
avgGain += change;
|
|
200
|
+
}
|
|
201
|
+
else {
|
|
202
|
+
avgLoss += Math.abs(change);
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
avgGain /= period;
|
|
206
|
+
avgLoss /= period;
|
|
207
|
+
// 第一个 RSI 值(位于 index = period)
|
|
208
|
+
result[period] = avgLoss === 0
|
|
209
|
+
? 100
|
|
210
|
+
: 100 - 100 / (1 + avgGain / avgLoss);
|
|
211
|
+
// 递推计算后续 RSI
|
|
212
|
+
for (let i = period + 1; i < data.length; i++) {
|
|
213
|
+
const change = changes[i - 1]; // changes[i-1] 对应 data[i]
|
|
214
|
+
const gain = change > 0 ? change : 0;
|
|
215
|
+
const loss = change < 0 ? Math.abs(change) : 0;
|
|
216
|
+
avgGain = (avgGain * (period - 1) + gain) / period;
|
|
217
|
+
avgLoss = (avgLoss * (period - 1) + loss) / period;
|
|
218
|
+
result[i] = avgLoss === 0
|
|
219
|
+
? 100
|
|
220
|
+
: 100 - 100 / (1 + avgGain / avgLoss);
|
|
221
|
+
}
|
|
222
|
+
return result;
|
|
223
|
+
}
|
|
224
|
+
// ─── KDJ ──────────────────────────────────────────────────────
|
|
225
|
+
/**
|
|
226
|
+
* 计算 KDJ 指标(随机指标)
|
|
227
|
+
*
|
|
228
|
+
* 标准参数 (9, 3, 3):
|
|
229
|
+
* 1. RSV = (close − LLV) / (HHV − LLV) × 100
|
|
230
|
+
* 其中 LLV 为最近 period 周期的最低价,HHV 为最近 period 周期的最高价
|
|
231
|
+
* 2. Kₜ = ⅔ × Kₜ₋₁ + ⅓ × RSVₜ (初始 K = 50)
|
|
232
|
+
* 3. Dₜ = ⅔ × Dₜ₋₁ + ⅓ × Kₜ (初始 D = 50)
|
|
233
|
+
* 4. Jₜ = 3 × Kₜ − 2 × Dₜ
|
|
234
|
+
*
|
|
235
|
+
* 前 period-1 个位置为 null(数据不足)。
|
|
236
|
+
*
|
|
237
|
+
* @param data - OHLCV 数组
|
|
238
|
+
* @param period - 周期(默认 9,即 RSV 的观察窗口)
|
|
239
|
+
* @returns 包含 K、D、J 三个等长数组的对象
|
|
240
|
+
*
|
|
241
|
+
* @example
|
|
242
|
+
* ```typescript
|
|
243
|
+
* const { k, d, j } = calcKDJ(dailyData);
|
|
244
|
+
* ```
|
|
245
|
+
*/
|
|
246
|
+
export function calcKDJ(data, period = 9) {
|
|
247
|
+
const length = data.length;
|
|
248
|
+
const k = new Array(length).fill(null);
|
|
249
|
+
const d = new Array(length).fill(null);
|
|
250
|
+
const j = new Array(length).fill(null);
|
|
251
|
+
if (data.length < period || period <= 0) {
|
|
252
|
+
return { k, d, j };
|
|
253
|
+
}
|
|
254
|
+
// K/D 初始值
|
|
255
|
+
let prevK = 50;
|
|
256
|
+
let prevD = 50;
|
|
257
|
+
for (let i = period - 1; i < length; i++) {
|
|
258
|
+
// 计算周期内最高价、最低价
|
|
259
|
+
let highestHigh = -Infinity;
|
|
260
|
+
let lowestLow = Infinity;
|
|
261
|
+
for (let jj = i - period + 1; jj <= i; jj++) {
|
|
262
|
+
if (data[jj].high > highestHigh)
|
|
263
|
+
highestHigh = data[jj].high;
|
|
264
|
+
if (data[jj].low < lowestLow)
|
|
265
|
+
lowestLow = data[jj].low;
|
|
266
|
+
}
|
|
267
|
+
// RSV 计算
|
|
268
|
+
const rsv = highestHigh === lowestLow
|
|
269
|
+
? 50
|
|
270
|
+
: ((data[i].close - lowestLow) / (highestHigh - lowestLow)) * 100;
|
|
271
|
+
// K、D、J 递推
|
|
272
|
+
if (i === period - 1) {
|
|
273
|
+
k[i] = prevK; // 初始 K = 50
|
|
274
|
+
d[i] = prevD; // 初始 D = 50
|
|
275
|
+
}
|
|
276
|
+
else {
|
|
277
|
+
const currK = (2 / 3) * prevK + (1 / 3) * rsv;
|
|
278
|
+
const currD = (2 / 3) * prevD + (1 / 3) * currK;
|
|
279
|
+
k[i] = currK;
|
|
280
|
+
d[i] = currD;
|
|
281
|
+
prevK = currK;
|
|
282
|
+
prevD = currD;
|
|
283
|
+
}
|
|
284
|
+
j[i] = 3 * k[i] - 2 * d[i];
|
|
285
|
+
}
|
|
286
|
+
return { k, d, j };
|
|
287
|
+
}
|
|
288
|
+
// ─── 布林带 ───────────────────────────────────────────────────
|
|
289
|
+
/**
|
|
290
|
+
* 计算布林带(Bollinger Bands)
|
|
291
|
+
*
|
|
292
|
+
* 公式(标准参数 20, 2):
|
|
293
|
+
* MID = SMA(close, n)
|
|
294
|
+
* StdDev = √(Σ(close − MID)² / n)
|
|
295
|
+
* UPPER = MID + multiplier × StdDev
|
|
296
|
+
* LOWER = MID − multiplier × StdDev
|
|
297
|
+
*
|
|
298
|
+
* 前 n-1 个位置为 null(数据不足)。
|
|
299
|
+
*
|
|
300
|
+
* @param data - OHLCV 数组
|
|
301
|
+
* @param period - 计算周期(默认 20)
|
|
302
|
+
* @param multiplier - 标准差倍数(默认 2)
|
|
303
|
+
* @returns 包含 upper、mid、lower 三个等长数组的对象
|
|
304
|
+
*
|
|
305
|
+
* @example
|
|
306
|
+
* ```typescript
|
|
307
|
+
* const { upper, mid, lower } = calcBollinger(dailyData, 20, 2);
|
|
308
|
+
* ```
|
|
309
|
+
*/
|
|
310
|
+
export function calcBollinger(data, period = 20, multiplier = 2) {
|
|
311
|
+
const length = data.length;
|
|
312
|
+
const upper = new Array(length).fill(null);
|
|
313
|
+
const mid = new Array(length).fill(null);
|
|
314
|
+
const lower = new Array(length).fill(null);
|
|
315
|
+
if (data.length < period || period <= 0) {
|
|
316
|
+
return { upper, mid, lower };
|
|
317
|
+
}
|
|
318
|
+
for (let i = period - 1; i < length; i++) {
|
|
319
|
+
// 计算 SMA
|
|
320
|
+
let sum = 0;
|
|
321
|
+
for (let j = i - period + 1; j <= i; j++) {
|
|
322
|
+
sum += data[j].close;
|
|
323
|
+
}
|
|
324
|
+
const sma = sum / period;
|
|
325
|
+
mid[i] = sma;
|
|
326
|
+
// 计算标准差(总体标准差)
|
|
327
|
+
let variance = 0;
|
|
328
|
+
for (let j = i - period + 1; j <= i; j++) {
|
|
329
|
+
const diff = data[j].close - sma;
|
|
330
|
+
variance += diff * diff;
|
|
331
|
+
}
|
|
332
|
+
const stdDev = Math.sqrt(variance / period);
|
|
333
|
+
upper[i] = sma + multiplier * stdDev;
|
|
334
|
+
lower[i] = sma - multiplier * stdDev;
|
|
335
|
+
}
|
|
336
|
+
return { upper, mid, lower };
|
|
337
|
+
}
|
|
338
|
+
// ─── 辅助指标 ─────────────────────────────────────────────────
|
|
339
|
+
/**
|
|
340
|
+
* 计算指定位置的振幅
|
|
341
|
+
*
|
|
342
|
+
* 振幅 = (high − low) / prevClose × 100
|
|
343
|
+
*
|
|
344
|
+
* 首日(index = 0)因无前一日收盘价,返回 0。
|
|
345
|
+
*
|
|
346
|
+
* @param data - OHLCV 数组
|
|
347
|
+
* @param index - 目标位置(从 0 开始)
|
|
348
|
+
* @returns 振幅百分比
|
|
349
|
+
*
|
|
350
|
+
* @example
|
|
351
|
+
* ```typescript
|
|
352
|
+
* const amp = calcAmplitude(dailyData, dailyData.length - 1);
|
|
353
|
+
* // 最新一天的振幅
|
|
354
|
+
* ```
|
|
355
|
+
*/
|
|
356
|
+
export function calcAmplitude(data, index) {
|
|
357
|
+
if (index <= 0 || index >= data.length) {
|
|
358
|
+
return 0;
|
|
359
|
+
}
|
|
360
|
+
const { high, low } = data[index];
|
|
361
|
+
const prevClose = data[index - 1].close;
|
|
362
|
+
if (prevClose === 0) {
|
|
363
|
+
return 0;
|
|
364
|
+
}
|
|
365
|
+
return ((high - low) / prevClose) * 100;
|
|
366
|
+
}
|
|
367
|
+
/**
|
|
368
|
+
* 计算指定位置的涨跌幅
|
|
369
|
+
*
|
|
370
|
+
* 涨跌幅 = (close − prevClose) / prevClose × 100
|
|
371
|
+
*
|
|
372
|
+
* 首日(index = 0)因无前一日收盘价,返回 0。
|
|
373
|
+
*
|
|
374
|
+
* @param data - OHLCV 数组
|
|
375
|
+
* @param index - 目标位置(从 0 开始)
|
|
376
|
+
* @returns 涨跌幅百分比
|
|
377
|
+
*
|
|
378
|
+
* @example
|
|
379
|
+
* ```typescript
|
|
380
|
+
* const pct = calcPriceChangePct(dailyData, dailyData.length - 1);
|
|
381
|
+
* // 最新一天的涨跌幅
|
|
382
|
+
* ```
|
|
383
|
+
*/
|
|
384
|
+
export function calcPriceChangePct(data, index) {
|
|
385
|
+
if (index <= 0 || index >= data.length) {
|
|
386
|
+
return 0;
|
|
387
|
+
}
|
|
388
|
+
const currentClose = data[index].close;
|
|
389
|
+
const prevClose = data[index - 1].close;
|
|
390
|
+
if (prevClose === 0) {
|
|
391
|
+
return 0;
|
|
392
|
+
}
|
|
393
|
+
return ((currentClose - prevClose) / prevClose) * 100;
|
|
394
|
+
}
|
|
395
|
+
//# sourceMappingURL=indicators.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"indicators.js","sourceRoot":"","sources":["../../src/utils/indicators.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 信号检测工具模块
|
|
3
|
+
*
|
|
4
|
+
* 基于技术指标识别买入/卖出信号。
|
|
5
|
+
* 用于在流水线中生成每日分析报告的 signals 字段。
|
|
6
|
+
*
|
|
7
|
+
* @module signals
|
|
8
|
+
*/
|
|
9
|
+
import { type OHLCV } from './indicators.js';
|
|
10
|
+
/**
|
|
11
|
+
* 信号检测结果
|
|
12
|
+
*
|
|
13
|
+
* 包含常见的技术信号标记和辅助数值,
|
|
14
|
+
* 最终会被序列化为 JSON 存入 daily_analysis_report.signals 字段。
|
|
15
|
+
*/
|
|
16
|
+
export interface Signals {
|
|
17
|
+
/** 金叉:MA5 上穿 MA10 */
|
|
18
|
+
goldenCross: boolean;
|
|
19
|
+
/** 死叉:MA5 下穿 MA10 */
|
|
20
|
+
deadCross: boolean;
|
|
21
|
+
/** 超买:RSI14 > 80 */
|
|
22
|
+
overbought: boolean;
|
|
23
|
+
/** 超卖:RSI14 < 20 */
|
|
24
|
+
oversold: boolean;
|
|
25
|
+
/** 放量:当日成交量 > 前 5 日均量 × 2 */
|
|
26
|
+
volumeSpike: boolean;
|
|
27
|
+
/** 量比:当日成交量 / 前 5 日均量 */
|
|
28
|
+
volumeRatio: number;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* 检测技术信号
|
|
32
|
+
*
|
|
33
|
+
* 综合判断金叉/死叉、超买/超卖、放量等信号。
|
|
34
|
+
*
|
|
35
|
+
* 金叉/死叉判断逻辑:
|
|
36
|
+
* 计算 MA5 和 MA10 完整序列,取最后一个有效值及其前一个值进行比较。
|
|
37
|
+
* 金叉条件:前值 MA5 ≤ MA10 且 现值 MA5 > MA10
|
|
38
|
+
* 死叉条件:前值 MA5 ≥ MA10 且 现值 MA5 < MA10
|
|
39
|
+
*
|
|
40
|
+
* 量比逻辑:
|
|
41
|
+
* 取最后 5 个交易日(不含当日)成交量的平均值作为基准,
|
|
42
|
+
* 量比 = 当日成交量 / 基准均量。
|
|
43
|
+
*
|
|
44
|
+
* @param data - 完整 OHLCV 数组(按日期升序排列)
|
|
45
|
+
* @param latestMA - 当前最新的 MA5 与 MA10 值(由调用方预计算传入)
|
|
46
|
+
* @param latestRSI14 - 当前最新的 RSI14 值(由调用方预计算传入)
|
|
47
|
+
* @returns 信号检测结果
|
|
48
|
+
*
|
|
49
|
+
* @example
|
|
50
|
+
* ```typescript
|
|
51
|
+
* const ma5 = calcMA(data, 5);
|
|
52
|
+
* const ma10 = calcMA(data, 10);
|
|
53
|
+
* const rsi14 = calcRSI(data, 14);
|
|
54
|
+
* const signals = detectSignals(
|
|
55
|
+
* data,
|
|
56
|
+
* { ma5: ma5[ma5.length - 1], ma10: ma10[ma10.length - 1] },
|
|
57
|
+
* rsi14[rsi14.length - 1]
|
|
58
|
+
* );
|
|
59
|
+
* ```
|
|
60
|
+
*/
|
|
61
|
+
export declare function detectSignals(data: OHLCV[], latestMA: {
|
|
62
|
+
ma5: number | null;
|
|
63
|
+
ma10: number | null;
|
|
64
|
+
}, latestRSI14: number | null): Signals;
|
|
65
|
+
//# sourceMappingURL=signals.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"signals.d.ts","sourceRoot":"","sources":["../../src/utils/signals.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAU,KAAK,KAAK,EAAE,MAAM,iBAAiB,CAAC;AAIrD;;;;;GAKG;AACH,MAAM,WAAW,OAAO;IACtB,qBAAqB;IACrB,WAAW,EAAE,OAAO,CAAC;IACrB,qBAAqB;IACrB,SAAS,EAAE,OAAO,CAAC;IACnB,oBAAoB;IACpB,UAAU,EAAE,OAAO,CAAC;IACpB,oBAAoB;IACpB,QAAQ,EAAE,OAAO,CAAC;IAClB,6BAA6B;IAC7B,WAAW,EAAE,OAAO,CAAC;IACrB,yBAAyB;IACzB,WAAW,EAAE,MAAM,CAAC;CACrB;AAgBD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AACH,wBAAgB,aAAa,CAC3B,IAAI,EAAE,KAAK,EAAE,EACb,QAAQ,EAAE;IAAE,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;IAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,EACrD,WAAW,EAAE,MAAM,GAAG,IAAI,GACzB,OAAO,CAaT"}
|