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.
Files changed (93) hide show
  1. package/README.md +26 -0
  2. package/dist/db/index.d.ts +18 -0
  3. package/dist/db/index.d.ts.map +1 -0
  4. package/dist/db/index.js +58 -0
  5. package/dist/db/index.js.map +1 -0
  6. package/dist/db/migrate.d.ts +11 -0
  7. package/dist/db/migrate.d.ts.map +1 -0
  8. package/dist/db/migrate.js +42 -0
  9. package/dist/db/migrate.js.map +1 -0
  10. package/dist/db/schema.d.ts +1101 -0
  11. package/dist/db/schema.d.ts.map +1 -0
  12. package/dist/db/schema.js +149 -0
  13. package/dist/db/schema.js.map +1 -0
  14. package/dist/index.d.ts +50 -0
  15. package/dist/index.d.ts.map +1 -0
  16. package/dist/index.js +69 -0
  17. package/dist/index.js.map +1 -0
  18. package/dist/services/analysis.d.ts +62 -0
  19. package/dist/services/analysis.d.ts.map +1 -0
  20. package/dist/services/analysis.js +74 -0
  21. package/dist/services/analysis.js.map +1 -0
  22. package/dist/services/daily-info.d.ts +150 -0
  23. package/dist/services/daily-info.d.ts.map +1 -0
  24. package/dist/services/daily-info.js +293 -0
  25. package/dist/services/daily-info.js.map +1 -0
  26. package/dist/services/embedding.d.ts +89 -0
  27. package/dist/services/embedding.d.ts.map +1 -0
  28. package/dist/services/embedding.js +227 -0
  29. package/dist/services/embedding.js.map +1 -0
  30. package/dist/services/llm.d.ts +64 -0
  31. package/dist/services/llm.d.ts.map +1 -0
  32. package/dist/services/llm.js +109 -0
  33. package/dist/services/llm.js.map +1 -0
  34. package/dist/services/pipeline.d.ts +161 -0
  35. package/dist/services/pipeline.d.ts.map +1 -0
  36. package/dist/services/pipeline.js +844 -0
  37. package/dist/services/pipeline.js.map +1 -0
  38. package/dist/services/pool.d.ts +142 -0
  39. package/dist/services/pool.d.ts.map +1 -0
  40. package/dist/services/pool.js +208 -0
  41. package/dist/services/pool.js.map +1 -0
  42. package/dist/services/sentiment.d.ts +31 -0
  43. package/dist/services/sentiment.d.ts.map +1 -0
  44. package/dist/services/sentiment.js +76 -0
  45. package/dist/services/sentiment.js.map +1 -0
  46. package/dist/services/session.d.ts +117 -0
  47. package/dist/services/session.d.ts.map +1 -0
  48. package/dist/services/session.js +176 -0
  49. package/dist/services/session.js.map +1 -0
  50. package/dist/services/stock.d.ts +82 -0
  51. package/dist/services/stock.d.ts.map +1 -0
  52. package/dist/services/stock.js +99 -0
  53. package/dist/services/stock.js.map +1 -0
  54. package/dist/services/word-count.d.ts +61 -0
  55. package/dist/services/word-count.d.ts.map +1 -0
  56. package/dist/services/word-count.js +120 -0
  57. package/dist/services/word-count.js.map +1 -0
  58. package/dist/tools/auxiliary.d.ts +93 -0
  59. package/dist/tools/auxiliary.d.ts.map +1 -0
  60. package/dist/tools/auxiliary.js +204 -0
  61. package/dist/tools/auxiliary.js.map +1 -0
  62. package/dist/tools/command.d.ts +193 -0
  63. package/dist/tools/command.d.ts.map +1 -0
  64. package/dist/tools/command.js +263 -0
  65. package/dist/tools/command.js.map +1 -0
  66. package/dist/tools/execute.d.ts +109 -0
  67. package/dist/tools/execute.d.ts.map +1 -0
  68. package/dist/tools/execute.js +112 -0
  69. package/dist/tools/execute.js.map +1 -0
  70. package/dist/tools/manager.d.ts +150 -0
  71. package/dist/tools/manager.d.ts.map +1 -0
  72. package/dist/tools/manager.js +200 -0
  73. package/dist/tools/manager.js.map +1 -0
  74. package/dist/tools/query.d.ts +163 -0
  75. package/dist/tools/query.d.ts.map +1 -0
  76. package/dist/tools/query.js +190 -0
  77. package/dist/tools/query.js.map +1 -0
  78. package/dist/utils/http-client.d.ts +87 -0
  79. package/dist/utils/http-client.d.ts.map +1 -0
  80. package/dist/utils/http-client.js +211 -0
  81. package/dist/utils/http-client.js.map +1 -0
  82. package/dist/utils/indicators.d.ts +194 -0
  83. package/dist/utils/indicators.d.ts.map +1 -0
  84. package/dist/utils/indicators.js +395 -0
  85. package/dist/utils/indicators.js.map +1 -0
  86. package/dist/utils/signals.d.ts +65 -0
  87. package/dist/utils/signals.d.ts.map +1 -0
  88. package/dist/utils/signals.js +171 -0
  89. package/dist/utils/signals.js.map +1 -0
  90. package/drizzle/0000_equal_marvel_apes.sql +124 -0
  91. package/drizzle/meta/0000_snapshot.json +858 -0
  92. package/drizzle/meta/_journal.json +13 -0
  93. 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"}