@363045841yyt/klinechart-core 0.7.3 → 0.7.5-alpha.2

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 (231) hide show
  1. package/README.md +201 -201
  2. package/README.zh-CN.md +201 -201
  3. package/dist/engine/renderers/webgl/candleSurface.js +47 -47
  4. package/dist/version.d.ts +1 -1
  5. package/dist/version.d.ts.map +1 -1
  6. package/dist/version.js +1 -2
  7. package/dist/version.js.map +1 -1
  8. package/package.json +129 -122
  9. package/src/__tests__/signal.test.ts +124 -124
  10. package/src/config/chartSettings.ts +66 -66
  11. package/src/controllers/__tests__/drawing.test.ts +214 -214
  12. package/src/controllers/__tests__/indicatorSelector.test.ts +481 -481
  13. package/src/controllers/__tests__/toolbar.test.ts +225 -225
  14. package/src/controllers/createChartController.ts +665 -665
  15. package/src/controllers/createDrawingController.ts +96 -96
  16. package/src/controllers/createIndicatorSelectorController.ts +307 -307
  17. package/src/controllers/createToolbarController.ts +146 -146
  18. package/src/controllers/index.ts +19 -19
  19. package/src/controllers/types.ts +284 -284
  20. package/src/engine/__tests__/chart.dpr.test.ts +401 -401
  21. package/src/engine/__tests__/paneRenderer.resize.test.ts +92 -92
  22. package/src/engine/chart-store.ts +121 -121
  23. package/src/engine/chart.d.ts +617 -617
  24. package/src/engine/chart.ts +2815 -2815
  25. package/src/engine/controller/__tests__/interaction.dpr.test.ts +259 -259
  26. package/src/engine/controller/interaction.ts +722 -722
  27. package/src/engine/controller/markerInteraction.ts +130 -130
  28. package/src/engine/controller/pinchTracker.ts +82 -82
  29. package/src/engine/controller/tooltipPosition.ts +48 -48
  30. package/src/engine/draw/__tests__/pixelAlign.spec.ts +176 -176
  31. package/src/engine/draw/pixelAlign.ts +259 -259
  32. package/src/engine/drawing/index.ts +655 -655
  33. package/src/engine/drawing/interaction.ts +842 -842
  34. package/src/engine/drawing/plugin.ts +343 -343
  35. package/src/engine/indicators/__tests__/__fixtures__/golden/atr.json +38 -38
  36. package/src/engine/indicators/__tests__/__fixtures__/golden/dema.json +14 -14
  37. package/src/engine/indicators/__tests__/__fixtures__/golden/hma.json +14 -14
  38. package/src/engine/indicators/__tests__/__fixtures__/golden/index.ts +55 -55
  39. package/src/engine/indicators/__tests__/__fixtures__/golden/kama.json +14 -14
  40. package/src/engine/indicators/__tests__/__fixtures__/golden/tema.json +14 -14
  41. package/src/engine/indicators/__tests__/__fixtures__/golden/wma.json +40 -40
  42. package/src/engine/indicators/__tests__/__fixtures__/synthetic.ts +65 -65
  43. package/src/engine/indicators/__tests__/_propertyAssertions.ts +76 -76
  44. package/src/engine/indicators/__tests__/atr.test.ts +153 -153
  45. package/src/engine/indicators/__tests__/calculators.test.ts +614 -614
  46. package/src/engine/indicators/__tests__/cmf-mfi.test.ts +100 -100
  47. package/src/engine/indicators/__tests__/dema.test.ts +73 -73
  48. package/src/engine/indicators/__tests__/donchian.test.ts +70 -70
  49. package/src/engine/indicators/__tests__/hma.test.ts +73 -73
  50. package/src/engine/indicators/__tests__/ichimoku.test.ts +105 -105
  51. package/src/engine/indicators/__tests__/kama.test.ts +80 -80
  52. package/src/engine/indicators/__tests__/keltner.test.ts +65 -65
  53. package/src/engine/indicators/__tests__/pivot-fib.test.ts +110 -110
  54. package/src/engine/indicators/__tests__/roc.test.ts +68 -68
  55. package/src/engine/indicators/__tests__/sar.test.ts +86 -86
  56. package/src/engine/indicators/__tests__/scheduler.test.ts +831 -831
  57. package/src/engine/indicators/__tests__/soa.test.ts +533 -533
  58. package/src/engine/indicators/__tests__/structure.test.ts +110 -110
  59. package/src/engine/indicators/__tests__/supertrend.test.ts +65 -65
  60. package/src/engine/indicators/__tests__/tema.test.ts +68 -68
  61. package/src/engine/indicators/__tests__/trix.test.ts +70 -70
  62. package/src/engine/indicators/__tests__/volatility.test.ts +117 -117
  63. package/src/engine/indicators/__tests__/volume.test.ts +115 -115
  64. package/src/engine/indicators/__tests__/volumeProfile.test.ts +74 -74
  65. package/src/engine/indicators/__tests__/vwap.test.ts +69 -69
  66. package/src/engine/indicators/__tests__/wma.test.ts +112 -112
  67. package/src/engine/indicators/__tests__/zones.test.ts +95 -95
  68. package/src/engine/indicators/atrState.ts +27 -27
  69. package/src/engine/indicators/bollState.ts +51 -51
  70. package/src/engine/indicators/calculators.ts +2593 -2593
  71. package/src/engine/indicators/cciState.ts +25 -25
  72. package/src/engine/indicators/chaikinVolState.ts +32 -32
  73. package/src/engine/indicators/cmfState.ts +27 -27
  74. package/src/engine/indicators/demaState.ts +27 -27
  75. package/src/engine/indicators/donchianState.ts +43 -43
  76. package/src/engine/indicators/eneState.ts +43 -43
  77. package/src/engine/indicators/expmaState.ts +43 -43
  78. package/src/engine/indicators/fastkState.ts +25 -25
  79. package/src/engine/indicators/fibState.ts +41 -41
  80. package/src/engine/indicators/hmaState.ts +27 -27
  81. package/src/engine/indicators/hvState.ts +28 -28
  82. package/src/engine/indicators/ichimokuState.ts +70 -70
  83. package/src/engine/indicators/indicator.worker.ts +169 -169
  84. package/src/engine/indicators/indicatorDefinitionRegistry.ts +62 -62
  85. package/src/engine/indicators/indicatorMetadata.ts +110 -110
  86. package/src/engine/indicators/indicatorRegistry.ts +106 -106
  87. package/src/engine/indicators/indicatorRuntime.ts +1548 -1548
  88. package/src/engine/indicators/kamaState.ts +34 -34
  89. package/src/engine/indicators/keltnerState.ts +49 -49
  90. package/src/engine/indicators/kstState.ts +42 -42
  91. package/src/engine/indicators/maState.ts +36 -36
  92. package/src/engine/indicators/macdState.ts +76 -76
  93. package/src/engine/indicators/mfiState.ts +27 -27
  94. package/src/engine/indicators/momState.ts +25 -25
  95. package/src/engine/indicators/obvState.ts +25 -25
  96. package/src/engine/indicators/parkinsonState.ts +28 -28
  97. package/src/engine/indicators/pivotState.ts +51 -51
  98. package/src/engine/indicators/pvtState.ts +25 -25
  99. package/src/engine/indicators/rocState.ts +27 -27
  100. package/src/engine/indicators/rsiState.ts +65 -65
  101. package/src/engine/indicators/sarState.ts +41 -41
  102. package/src/engine/indicators/scheduler.ts +1205 -1205
  103. package/src/engine/indicators/soa.ts +352 -352
  104. package/src/engine/indicators/stateComposer.ts +1262 -1262
  105. package/src/engine/indicators/stochState.ts +26 -26
  106. package/src/engine/indicators/structureState.ts +69 -69
  107. package/src/engine/indicators/supertrendState.ts +37 -37
  108. package/src/engine/indicators/temaState.ts +27 -27
  109. package/src/engine/indicators/trixState.ts +35 -35
  110. package/src/engine/indicators/vmaState.ts +27 -27
  111. package/src/engine/indicators/volumeProfileState.ts +63 -63
  112. package/src/engine/indicators/vwapState.ts +29 -29
  113. package/src/engine/indicators/wmaState.ts +27 -27
  114. package/src/engine/indicators/wmsrState.ts +25 -25
  115. package/src/engine/indicators/workerProtocol.ts +613 -613
  116. package/src/engine/indicators/zonesState.ts +47 -47
  117. package/src/engine/layout/pane.ts +161 -161
  118. package/src/engine/marker/registry.ts +265 -265
  119. package/src/engine/paneRenderer.ts +169 -169
  120. package/src/engine/renderers/Indicator/atr.ts +237 -237
  121. package/src/engine/renderers/Indicator/boll.ts +317 -317
  122. package/src/engine/renderers/Indicator/cci.ts +275 -275
  123. package/src/engine/renderers/Indicator/chaikinVol.ts +138 -138
  124. package/src/engine/renderers/Indicator/cmf.ts +137 -137
  125. package/src/engine/renderers/Indicator/dema.ts +136 -136
  126. package/src/engine/renderers/Indicator/donchian.ts +137 -137
  127. package/src/engine/renderers/Indicator/ene.ts +271 -271
  128. package/src/engine/renderers/Indicator/expma.ts +197 -197
  129. package/src/engine/renderers/Indicator/fastk.ts +316 -316
  130. package/src/engine/renderers/Indicator/fib.ts +141 -141
  131. package/src/engine/renderers/Indicator/hma.ts +136 -136
  132. package/src/engine/renderers/Indicator/hv.ts +124 -124
  133. package/src/engine/renderers/Indicator/ichimoku.ts +181 -181
  134. package/src/engine/renderers/Indicator/index.ts +241 -241
  135. package/src/engine/renderers/Indicator/indicatorData.ts +650 -650
  136. package/src/engine/renderers/Indicator/kama.ts +136 -136
  137. package/src/engine/renderers/Indicator/keltner.ts +137 -137
  138. package/src/engine/renderers/Indicator/kst.ts +302 -302
  139. package/src/engine/renderers/Indicator/ma.ts +200 -200
  140. package/src/engine/renderers/Indicator/macd.ts +477 -477
  141. package/src/engine/renderers/Indicator/macdLegend.ts +141 -141
  142. package/src/engine/renderers/Indicator/mainIndicatorLegend.ts +272 -272
  143. package/src/engine/renderers/Indicator/mfi.ts +142 -142
  144. package/src/engine/renderers/Indicator/mom.ts +311 -311
  145. package/src/engine/renderers/Indicator/obv.ts +123 -123
  146. package/src/engine/renderers/Indicator/parkinson.ts +124 -124
  147. package/src/engine/renderers/Indicator/pivot.ts +131 -131
  148. package/src/engine/renderers/Indicator/pvt.ts +123 -123
  149. package/src/engine/renderers/Indicator/roc.ts +143 -143
  150. package/src/engine/renderers/Indicator/rsi.ts +390 -390
  151. package/src/engine/renderers/Indicator/sar.ts +113 -113
  152. package/src/engine/renderers/Indicator/scale/atr_scale.ts +19 -19
  153. package/src/engine/renderers/Indicator/scale/cci_scale.ts +19 -19
  154. package/src/engine/renderers/Indicator/scale/fastk_scale.ts +19 -19
  155. package/src/engine/renderers/Indicator/scale/indicator_scale.ts +204 -204
  156. package/src/engine/renderers/Indicator/scale/kst_scale.ts +19 -19
  157. package/src/engine/renderers/Indicator/scale/macd_scale.ts +22 -22
  158. package/src/engine/renderers/Indicator/scale/mom_scale.ts +19 -19
  159. package/src/engine/renderers/Indicator/scale/rsi_scale.ts +19 -19
  160. package/src/engine/renderers/Indicator/scale/stoch_scale.ts +19 -19
  161. package/src/engine/renderers/Indicator/scale/volume_scale.ts +26 -26
  162. package/src/engine/renderers/Indicator/scale/wmsr_scale.ts +19 -19
  163. package/src/engine/renderers/Indicator/stoch.ts +359 -359
  164. package/src/engine/renderers/Indicator/structure.ts +126 -126
  165. package/src/engine/renderers/Indicator/subPaneConfig.ts +265 -265
  166. package/src/engine/renderers/Indicator/supertrend.ts +115 -115
  167. package/src/engine/renderers/Indicator/tema.ts +136 -136
  168. package/src/engine/renderers/Indicator/trix.ts +158 -158
  169. package/src/engine/renderers/Indicator/vma.ts +124 -124
  170. package/src/engine/renderers/Indicator/volumeProfile.ts +125 -125
  171. package/src/engine/renderers/Indicator/vwap.ts +123 -123
  172. package/src/engine/renderers/Indicator/wma.ts +136 -136
  173. package/src/engine/renderers/Indicator/wmsr.ts +328 -328
  174. package/src/engine/renderers/Indicator/zones.ts +104 -104
  175. package/src/engine/renderers/__tests__/boll.renderer.test.ts +314 -314
  176. package/src/engine/renderers/__tests__/ene.renderer.test.ts +305 -305
  177. package/src/engine/renderers/__tests__/expma.renderer.test.ts +279 -279
  178. package/src/engine/renderers/__tests__/ma.renderer.test.ts +426 -426
  179. package/src/engine/renderers/__tests__/mainIndicatorLegend.renderer.test.ts +502 -502
  180. package/src/engine/renderers/__tests__/yAxis.renderer.test.ts +173 -173
  181. package/src/engine/renderers/candle.ts +459 -459
  182. package/src/engine/renderers/crosshair.ts +69 -69
  183. package/src/engine/renderers/customMarkers.ts +162 -162
  184. package/src/engine/renderers/extremaMarkers.ts +246 -246
  185. package/src/engine/renderers/gridLines.ts +90 -90
  186. package/src/engine/renderers/lastPrice.ts +97 -97
  187. package/src/engine/renderers/paneTitle.ts +136 -136
  188. package/src/engine/renderers/subVolume.ts +236 -236
  189. package/src/engine/renderers/timeAxis.ts +121 -121
  190. package/src/engine/renderers/webgl/candleSurface.ts +955 -955
  191. package/src/engine/renderers/webgl/sharedWebGLSurface.ts +146 -146
  192. package/src/engine/renderers/yAxis.ts +105 -105
  193. package/src/engine/scale/__tests__/logFormula.spec.ts +148 -148
  194. package/src/engine/scale/logFormula.ts +130 -130
  195. package/src/engine/scale/price.ts +39 -39
  196. package/src/engine/scale/priceScale.ts +264 -264
  197. package/src/engine/subPaneManager.ts +427 -427
  198. package/src/engine/theme/colors.ts +642 -642
  199. package/src/engine/theme/fonts.ts +20 -20
  200. package/src/engine/utils/klineConfig.ts +49 -49
  201. package/src/engine/utils/tickCount.ts +11 -11
  202. package/src/engine/utils/tickPosition.ts +214 -214
  203. package/src/engine/utils/zoom.ts +83 -83
  204. package/src/engine/viewport/viewport.ts +67 -67
  205. package/src/index.ts +3 -3
  206. package/src/plugin/ConfigManager.ts +93 -93
  207. package/src/plugin/EventBus.ts +77 -77
  208. package/src/plugin/HookSystem.ts +106 -106
  209. package/src/plugin/PluginHost.ts +243 -243
  210. package/src/plugin/PluginRegistry.ts +92 -92
  211. package/src/plugin/StateStore.ts +73 -73
  212. package/src/plugin/index.ts +19 -19
  213. package/src/plugin/rendererPluginManager.ts +368 -368
  214. package/src/plugin/stateKeys.ts +8 -8
  215. package/src/plugin/types.ts +526 -526
  216. package/src/reactivity/index.ts +2 -2
  217. package/src/reactivity/signal.ts +119 -119
  218. package/src/semantic/controller.ts +251 -251
  219. package/src/semantic/drawShape.ts +260 -260
  220. package/src/semantic/index.ts +28 -28
  221. package/src/semantic/schema.json +256 -256
  222. package/src/semantic/types.ts +251 -251
  223. package/src/semantic/validator.ts +349 -349
  224. package/src/types/kLine.ts +13 -13
  225. package/src/types/price.ts +56 -56
  226. package/src/types/volumePrice.ts +33 -33
  227. package/src/utils/dateFormat.ts +208 -208
  228. package/src/utils/kLineDraw/axis.ts +562 -562
  229. package/src/utils/priceToY.ts +34 -34
  230. package/src/utils/volumePrice.ts +202 -202
  231. package/src/version.ts +1 -1
@@ -1,1548 +1,1548 @@
1
- /**
2
- * Indicator 纯计算运行时
3
- * 不依赖 PluginHost/StateStore,只负责计算和缓存
4
- * 可被主线程(inline fallback)或 Worker 使用
5
- */
6
-
7
- import type { KLineData } from '../../types/price'
8
- import {
9
- calcMAData,
10
- calcBOLLData,
11
- calcEXPMAData,
12
- calcENEData,
13
- calcRSIData,
14
- calcCCIData,
15
- calcSTOCHData,
16
- calcMOMData,
17
- calcWMSRData,
18
- calcKSTData,
19
- calcFASTKData,
20
- calcMACDData,
21
- calcATRData,
22
- calcWMAData,
23
- calcDEMAData,
24
- calcTEMAData,
25
- calcHMAData,
26
- calcKAMAData,
27
- calcSARData,
28
- calcSuperTrendData,
29
- calcKeltnerData,
30
- calcDonchianData,
31
- calcIchimokuData,
32
- calcROCData,
33
- calcTRIXData,
34
- calcHVData,
35
- calcParkinsonData,
36
- calcChaikinVolData,
37
- calcVMAData,
38
- calcOBVData,
39
- calcPVTData,
40
- calcVWAPData,
41
- calcCMFData,
42
- calcMFIData,
43
- calcPivotData,
44
- calcFibData,
45
- calcStructureData,
46
- calcZonesData,
47
- calcVolumeProfileData,
48
- DEFAULT_MA_PERIODS,
49
- DEFAULT_ATR_PERIOD,
50
- DEFAULT_VMA_PERIOD,
51
- DEFAULT_STRUCTURE_LEFT,
52
- DEFAULT_STRUCTURE_RIGHT,
53
- DEFAULT_ZONES_OB_LOOKBACK,
54
- DEFAULT_VP_BINS,
55
- DEFAULT_VP_LOOKBACK,
56
- DEFAULT_VP_VALUE_AREA,
57
- DEFAULT_VWAP_SESSION_GAP_MS,
58
- DEFAULT_CMF_PERIOD,
59
- DEFAULT_MFI_PERIOD,
60
- DEFAULT_FIB_PERIOD,
61
- DEFAULT_WMA_PERIOD,
62
- DEFAULT_DEMA_PERIOD,
63
- DEFAULT_TEMA_PERIOD,
64
- DEFAULT_HMA_PERIOD,
65
- DEFAULT_KAMA_PERIOD,
66
- DEFAULT_KAMA_FAST_PERIOD,
67
- DEFAULT_KAMA_SLOW_PERIOD,
68
- DEFAULT_SAR_STEP,
69
- DEFAULT_SAR_MAX_STEP,
70
- DEFAULT_SUPERTREND_ATR_PERIOD,
71
- DEFAULT_SUPERTREND_MULTIPLIER,
72
- DEFAULT_KELTNER_EMA_PERIOD,
73
- DEFAULT_KELTNER_ATR_PERIOD,
74
- DEFAULT_KELTNER_MULTIPLIER,
75
- DEFAULT_DONCHIAN_PERIOD,
76
- DEFAULT_ICHIMOKU_TENKAN,
77
- DEFAULT_ICHIMOKU_KIJUN,
78
- DEFAULT_ICHIMOKU_SPAN_B,
79
- DEFAULT_ICHIMOKU_DISPLACEMENT,
80
- DEFAULT_ROC_PERIOD,
81
- DEFAULT_TRIX_PERIOD,
82
- DEFAULT_TRIX_SIGNAL_PERIOD,
83
- DEFAULT_HV_PERIOD,
84
- DEFAULT_HV_ANNUALIZATION,
85
- DEFAULT_PARKINSON_PERIOD,
86
- DEFAULT_PARKINSON_ANNUALIZATION,
87
- DEFAULT_CHAIKIN_VOL_EMA_PERIOD,
88
- DEFAULT_CHAIKIN_VOL_ROC_PERIOD,
89
- type MAFlags,
90
- type BOLLPoint,
91
- type EXPMAPoint,
92
- type ENEPoint,
93
- type STOCHPoint,
94
- type KSTPoint,
95
- type MACDPoint,
96
- type SARPoint,
97
- type SuperTrendPoint,
98
- type KeltnerPoint,
99
- type DonchianPoint,
100
- type IchimokuPoint,
101
- type PivotPoint,
102
- type FibPoint,
103
- type StructureSnapshot,
104
- type Zone,
105
- type VolumeProfileResult,
106
- } from './calculators'
107
- import type {
108
- BOLLSchedulerConfig,
109
- EXPMASchedulerConfig,
110
- ENESchedulerConfig,
111
- RSISchedulerConfig,
112
- CCISchedulerConfig,
113
- STOCHSchedulerConfig,
114
- MOMSchedulerConfig,
115
- WMSRSchedulerConfig,
116
- KSTSchedulerConfig,
117
- FASTKSchedulerConfig,
118
- MACDSchedulerConfig,
119
- ATRSchedulerConfig,
120
- WMASchedulerConfig,
121
- DEMASchedulerConfig,
122
- TEMASchedulerConfig,
123
- HMASchedulerConfig,
124
- KAMASchedulerConfig,
125
- SARSchedulerConfig,
126
- SuperTrendSchedulerConfig,
127
- KeltnerSchedulerConfig,
128
- DonchianSchedulerConfig,
129
- IchimokuSchedulerConfig,
130
- ROCSchedulerConfig,
131
- TRIXSchedulerConfig,
132
- HVSchedulerConfig,
133
- ParkinsonSchedulerConfig,
134
- ChaikinVolSchedulerConfig,
135
- VMASchedulerConfig,
136
- OBVSchedulerConfig,
137
- PVTSchedulerConfig,
138
- VWAPSchedulerConfig,
139
- CMFSchedulerConfig,
140
- MFISchedulerConfig,
141
- PivotSchedulerConfig,
142
- FibSchedulerConfig,
143
- StructureSchedulerConfig,
144
- ZonesSchedulerConfig,
145
- VolumeProfileSchedulerConfig,
146
- IndicatorConfigSnapshot,
147
- IndicatorSeriesBundle,
148
- } from './workerProtocol'
149
-
150
- /**
151
- * 可见范围
152
- */
153
- interface VisibleRange {
154
- start: number
155
- end: number
156
- }
157
-
158
- /**
159
- * 计算运行时
160
- * 管理数据、配置、缓存和脏标记
161
- */
162
- export class IndicatorRuntime {
163
- // 数据
164
- private currentData: KLineData[] = []
165
- private dataVersion = 0
166
-
167
- // 配置
168
- private config: IndicatorConfigSnapshot = this.getDefaultConfig()
169
- private configVersion = 0
170
-
171
- // 缓存的 series
172
- private cachedSeries: Record<number, (number | undefined)[]> = {}
173
- private cachedBollSeries: BOLLPoint[] = []
174
- private cachedExpmaSeries: EXPMAPoint[] = []
175
- private cachedEneSeries: ENEPoint[] = []
176
- private cachedRsiSeries: Record<number, (number | undefined)[]> = {}
177
- private cachedCciSeries: (number | undefined)[] = []
178
- private cachedStochSeries: STOCHPoint[] = []
179
- private cachedMomSeries: (number | undefined)[] = []
180
- private cachedWmsrSeries: (number | undefined)[] = []
181
- private cachedKstSeries: KSTPoint[] = []
182
- private cachedFastkSeries: (number | undefined)[] = []
183
- private cachedMacdSeries: MACDPoint[] = []
184
- private cachedAtrSeries: (number | undefined)[] = []
185
- private cachedWmaSeries: (number | undefined)[] = []
186
- private cachedDemaSeries: (number | undefined)[] = []
187
- private cachedTemaSeries: (number | undefined)[] = []
188
- private cachedHmaSeries: (number | undefined)[] = []
189
- private cachedKamaSeries: (number | undefined)[] = []
190
- private cachedSarSeries: (SARPoint | undefined)[] = []
191
- private cachedSupertrendSeries: (SuperTrendPoint | undefined)[] = []
192
- private cachedKeltnerSeries: (KeltnerPoint | undefined)[] = []
193
- private cachedDonchianSeries: (DonchianPoint | undefined)[] = []
194
- private cachedIchimokuSeries: (IchimokuPoint | undefined)[] = []
195
- private cachedRocSeries: (number | undefined)[] = []
196
- private cachedTrixSeries: (number | undefined)[] = []
197
- private cachedTrixSignalSeries: (number | undefined)[] = []
198
- private cachedHvSeries: (number | undefined)[] = []
199
- private cachedParkinsonSeries: (number | undefined)[] = []
200
- private cachedChaikinVolSeries: (number | undefined)[] = []
201
- private cachedVmaSeries: (number | undefined)[] = []
202
- private cachedObvSeries: (number | undefined)[] = []
203
- private cachedPvtSeries: (number | undefined)[] = []
204
- private cachedVwapSeries: (number | undefined)[] = []
205
- private cachedCmfSeries: (number | undefined)[] = []
206
- private cachedMfiSeries: (number | undefined)[] = []
207
- private cachedPivotSeries: (PivotPoint | undefined)[] = []
208
- private cachedFibSeries: (FibPoint | undefined)[] = []
209
- private cachedStructureSeries: StructureSnapshot = { swings: [], events: [], trend: 'range' }
210
- private cachedZonesSeries: Zone[] = []
211
- private cachedVolumeProfileSeries: VolumeProfileResult = { bins: [], poc: 0, vah: 0, val: 0, totalVolume: 0 }
212
-
213
- // 脏标记
214
- private dirtyData = true
215
- private dirtyMAConfig = true
216
- private dirtyBollConfig = true
217
- private dirtyExpmaConfig = true
218
- private dirtyEneConfig = true
219
- private dirtyRsiConfig = true
220
- private dirtyCciConfig = true
221
- private dirtyStochConfig = true
222
- private dirtyMomConfig = true
223
- private dirtyWmsrConfig = true
224
- private dirtyKstConfig = true
225
- private dirtyFastkConfig = true
226
- private dirtyMacdConfig = true
227
- private dirtyAtrConfig = true
228
- private dirtyWmaConfig = true
229
- private dirtyDemaConfig = true
230
- private dirtyTemaConfig = true
231
- private dirtyHmaConfig = true
232
- private dirtyKamaConfig = true
233
- private dirtySarConfig = true
234
- private dirtySupertrendConfig = true
235
- private dirtyKeltnerConfig = true
236
- private dirtyDonchianConfig = true
237
- private dirtyIchimokuConfig = true
238
- private dirtyRocConfig = true
239
- private dirtyTrixConfig = true
240
- private dirtyHvConfig = true
241
- private dirtyParkinsonConfig = true
242
- private dirtyChaikinVolConfig = true
243
- private dirtyVmaConfig = true
244
- private dirtyObvConfig = true
245
- private dirtyPvtConfig = true
246
- private dirtyVwapConfig = true
247
- private dirtyCmfConfig = true
248
- private dirtyMfiConfig = true
249
- private dirtyPivotConfig = true
250
- private dirtyFibConfig = true
251
- private dirtyStructureConfig = true
252
- private dirtyZonesConfig = true
253
- private dirtyVolumeProfileConfig = true
254
-
255
- private getDefaultConfig(): IndicatorConfigSnapshot {
256
- return {
257
- ma: { ma5: true, ma10: true, ma20: true, ma30: true, ma60: true },
258
- boll: {
259
- period: 20,
260
- multiplier: 2,
261
- showUpper: true,
262
- showMiddle: true,
263
- showLower: true,
264
- showBand: true,
265
- },
266
- expma: { fastPeriod: 12, slowPeriod: 50 },
267
- ene: { period: 10, deviation: 11 },
268
- rsi: {
269
- period1: 6,
270
- period2: 12,
271
- period3: 24,
272
- showRSI1: true,
273
- showRSI2: true,
274
- showRSI3: true,
275
- },
276
- cci: { period: 14, showCCI: true },
277
- stoch: { n: 9, m: 3, showK: true, showD: true },
278
- mom: { period: 10, showMOM: true },
279
- wmsr: { period: 14, showWMSR: true },
280
- kst: {
281
- roc1: 10,
282
- roc2: 15,
283
- roc3: 20,
284
- roc4: 30,
285
- signalPeriod: 9,
286
- showKST: true,
287
- showSignal: true,
288
- },
289
- fastk: { period: 9, showFASTK: true },
290
- macd: {
291
- fastPeriod: 12,
292
- slowPeriod: 26,
293
- signalPeriod: 9,
294
- showDIF: true,
295
- showDEA: true,
296
- showBAR: true,
297
- },
298
- atr: { period: DEFAULT_ATR_PERIOD, showATR: true },
299
- wma: { period: DEFAULT_WMA_PERIOD, showWMA: true },
300
- dema: { period: DEFAULT_DEMA_PERIOD, showDEMA: true },
301
- tema: { period: DEFAULT_TEMA_PERIOD, showTEMA: true },
302
- hma: { period: DEFAULT_HMA_PERIOD, showHMA: true },
303
- kama: {
304
- period: DEFAULT_KAMA_PERIOD,
305
- fastPeriod: DEFAULT_KAMA_FAST_PERIOD,
306
- slowPeriod: DEFAULT_KAMA_SLOW_PERIOD,
307
- showKAMA: true,
308
- },
309
- sar: { step: DEFAULT_SAR_STEP, maxStep: DEFAULT_SAR_MAX_STEP, showSAR: true },
310
- supertrend: {
311
- atrPeriod: DEFAULT_SUPERTREND_ATR_PERIOD,
312
- multiplier: DEFAULT_SUPERTREND_MULTIPLIER,
313
- showSuperTrend: true,
314
- },
315
- keltner: {
316
- emaPeriod: DEFAULT_KELTNER_EMA_PERIOD,
317
- atrPeriod: DEFAULT_KELTNER_ATR_PERIOD,
318
- multiplier: DEFAULT_KELTNER_MULTIPLIER,
319
- showUpper: true,
320
- showMiddle: true,
321
- showLower: true,
322
- },
323
- donchian: {
324
- period: DEFAULT_DONCHIAN_PERIOD,
325
- showUpper: true,
326
- showMiddle: true,
327
- showLower: true,
328
- },
329
- ichimoku: {
330
- tenkanPeriod: DEFAULT_ICHIMOKU_TENKAN,
331
- kijunPeriod: DEFAULT_ICHIMOKU_KIJUN,
332
- spanBPeriod: DEFAULT_ICHIMOKU_SPAN_B,
333
- displacement: DEFAULT_ICHIMOKU_DISPLACEMENT,
334
- showTenkan: true,
335
- showKijun: true,
336
- showSpanA: true,
337
- showSpanB: true,
338
- showCloud: true,
339
- showChikou: true,
340
- },
341
- roc: { period: DEFAULT_ROC_PERIOD, showROC: true },
342
- trix: {
343
- period: DEFAULT_TRIX_PERIOD,
344
- signalPeriod: DEFAULT_TRIX_SIGNAL_PERIOD,
345
- showTRIX: true,
346
- showSignal: true,
347
- },
348
- hv: {
349
- period: DEFAULT_HV_PERIOD,
350
- annualizationFactor: DEFAULT_HV_ANNUALIZATION,
351
- showHV: true,
352
- },
353
- parkinson: {
354
- period: DEFAULT_PARKINSON_PERIOD,
355
- annualizationFactor: DEFAULT_PARKINSON_ANNUALIZATION,
356
- showParkinson: true,
357
- },
358
- chaikinVol: {
359
- emaPeriod: DEFAULT_CHAIKIN_VOL_EMA_PERIOD,
360
- rocPeriod: DEFAULT_CHAIKIN_VOL_ROC_PERIOD,
361
- showChaikinVol: true,
362
- },
363
- vma: { period: DEFAULT_VMA_PERIOD, showVMA: true },
364
- obv: { showOBV: true },
365
- pvt: { showPVT: true },
366
- vwap: { sessionResetGapMs: DEFAULT_VWAP_SESSION_GAP_MS, showVWAP: true },
367
- cmf: { period: DEFAULT_CMF_PERIOD, showCMF: true },
368
- mfi: { period: DEFAULT_MFI_PERIOD, showMFI: true },
369
- pivot: { showPP: true, showR1: true, showR2: true, showR3: false, showS1: true, showS2: true, showS3: false },
370
- fib: { period: DEFAULT_FIB_PERIOD, showLevels: true },
371
- structure: {
372
- leftWindow: DEFAULT_STRUCTURE_LEFT,
373
- rightWindow: DEFAULT_STRUCTURE_RIGHT,
374
- breakoutSource: 'close',
375
- showSwingLabels: true,
376
- showBOS: true,
377
- showCHOCH: true,
378
- showProvisional: false,
379
- },
380
- zones: {
381
- showFVG: true,
382
- showOB: true,
383
- showFilledZones: false,
384
- obLookback: DEFAULT_ZONES_OB_LOOKBACK,
385
- },
386
- volumeProfile: {
387
- bins: DEFAULT_VP_BINS,
388
- lookback: DEFAULT_VP_LOOKBACK,
389
- valueAreaPercent: DEFAULT_VP_VALUE_AREA,
390
- showPOC: true,
391
- showValueArea: true,
392
- },
393
- rsiPaneId: 'sub_RSI',
394
- cciPaneId: 'sub_CCI',
395
- stochPaneId: 'sub_STOCH',
396
- momPaneId: 'sub_MOM',
397
- wmsrPaneId: 'sub_WMSR',
398
- kstPaneId: 'sub_KST',
399
- fastkPaneId: 'sub_FASTK',
400
- macdPaneId: 'sub_MACD',
401
- atrPaneId: 'sub_ATR',
402
- wmaPaneId: 'sub_WMA',
403
- demaPaneId: 'sub_DEMA',
404
- temaPaneId: 'sub_TEMA',
405
- hmaPaneId: 'sub_HMA',
406
- kamaPaneId: 'sub_KAMA',
407
- sarPaneId: 'sub_SAR',
408
- supertrendPaneId: 'sub_SuperTrend',
409
- keltnerPaneId: 'sub_Keltner',
410
- donchianPaneId: 'sub_Donchian',
411
- ichimokuPaneId: 'sub_Ichimoku',
412
- rocPaneId: 'sub_ROC',
413
- trixPaneId: 'sub_TRIX',
414
- hvPaneId: 'sub_HV',
415
- parkinsonPaneId: 'sub_Parkinson',
416
- chaikinVolPaneId: 'sub_ChaikinVol',
417
- vmaPaneId: 'sub_VMA',
418
- obvPaneId: 'sub_OBV',
419
- pvtPaneId: 'sub_PVT',
420
- vwapPaneId: 'sub_VWAP',
421
- cmfPaneId: 'sub_CMF',
422
- mfiPaneId: 'sub_MFI',
423
- pivotPaneId: 'sub_Pivot',
424
- fibPaneId: 'sub_Fib',
425
- structurePaneId: 'sub_Structure',
426
- zonesPaneId: 'sub_Zones',
427
- volumeProfilePaneId: 'sub_VolumeProfile',
428
- }
429
- }
430
-
431
- /**
432
- * 更新数据
433
- */
434
- setData(data: KLineData[], version: number): void {
435
- if (this.dataVersion === version && !this.dirtyData) return
436
- this.currentData = data
437
- this.dataVersion = version
438
- this.dirtyData = true
439
- }
440
-
441
- /**
442
- * 更新配置
443
- */
444
- private shallowEqual(a: Record<string, unknown>, b: Record<string, unknown>): boolean {
445
- const keysA = Object.keys(a)
446
- const keysB = Object.keys(b)
447
- if (keysA.length !== keysB.length) return false
448
- for (const key of keysA) {
449
- if (a[key] !== b[key]) return false
450
- }
451
- return true
452
- }
453
-
454
- /**
455
- * 更新配置(仅值变更时才设置脏标记)
456
- */
457
- setConfig(config: Partial<IndicatorConfigSnapshot>, version: number): void {
458
- // 合并配置(仅值变更时才标记脏)
459
- if (config.ma !== undefined && !this.shallowEqual(config.ma as unknown as Record<string, unknown>, this.config.ma as unknown as Record<string, unknown>)) {
460
- this.config.ma = { ...this.config.ma, ...config.ma }
461
- this.dirtyMAConfig = true
462
- }
463
- if (config.boll !== undefined && !this.shallowEqual(config.boll as unknown as Record<string, unknown>, this.config.boll as unknown as Record<string, unknown>)) {
464
- this.config.boll = { ...this.config.boll, ...config.boll }
465
- this.dirtyBollConfig = true
466
- }
467
- if (config.expma !== undefined && !this.shallowEqual(config.expma as unknown as Record<string, unknown>, this.config.expma as unknown as Record<string, unknown>)) {
468
- this.config.expma = { ...this.config.expma, ...config.expma }
469
- this.dirtyExpmaConfig = true
470
- }
471
- if (config.ene !== undefined && !this.shallowEqual(config.ene as unknown as Record<string, unknown>, this.config.ene as unknown as Record<string, unknown>)) {
472
- this.config.ene = { ...this.config.ene, ...config.ene }
473
- this.dirtyEneConfig = true
474
- }
475
- if (config.rsi !== undefined && !this.shallowEqual(config.rsi as unknown as Record<string, unknown>, this.config.rsi as unknown as Record<string, unknown>)) {
476
- this.config.rsi = { ...this.config.rsi, ...config.rsi }
477
- this.dirtyRsiConfig = true
478
- }
479
- if (config.cci !== undefined && !this.shallowEqual(config.cci as unknown as Record<string, unknown>, this.config.cci as unknown as Record<string, unknown>)) {
480
- this.config.cci = { ...this.config.cci, ...config.cci }
481
- this.dirtyCciConfig = true
482
- }
483
- if (config.stoch !== undefined && !this.shallowEqual(config.stoch as unknown as Record<string, unknown>, this.config.stoch as unknown as Record<string, unknown>)) {
484
- this.config.stoch = { ...this.config.stoch, ...config.stoch }
485
- this.dirtyStochConfig = true
486
- }
487
- if (config.mom !== undefined && !this.shallowEqual(config.mom as unknown as Record<string, unknown>, this.config.mom as unknown as Record<string, unknown>)) {
488
- this.config.mom = { ...this.config.mom, ...config.mom }
489
- this.dirtyMomConfig = true
490
- }
491
- if (config.wmsr !== undefined && !this.shallowEqual(config.wmsr as unknown as Record<string, unknown>, this.config.wmsr as unknown as Record<string, unknown>)) {
492
- this.config.wmsr = { ...this.config.wmsr, ...config.wmsr }
493
- this.dirtyWmsrConfig = true
494
- }
495
- if (config.kst !== undefined && !this.shallowEqual(config.kst as unknown as Record<string, unknown>, this.config.kst as unknown as Record<string, unknown>)) {
496
- this.config.kst = { ...this.config.kst, ...config.kst }
497
- this.dirtyKstConfig = true
498
- }
499
- if (config.fastk !== undefined && !this.shallowEqual(config.fastk as unknown as Record<string, unknown>, this.config.fastk as unknown as Record<string, unknown>)) {
500
- this.config.fastk = { ...this.config.fastk, ...config.fastk }
501
- this.dirtyFastkConfig = true
502
- }
503
- if (config.macd !== undefined && !this.shallowEqual(config.macd as unknown as Record<string, unknown>, this.config.macd as unknown as Record<string, unknown>)) {
504
- this.config.macd = { ...this.config.macd, ...config.macd }
505
- this.dirtyMacdConfig = true
506
- }
507
- if (config.atr !== undefined && !this.shallowEqual(config.atr as unknown as Record<string, unknown>, this.config.atr as unknown as Record<string, unknown>)) {
508
- this.config.atr = { ...this.config.atr, ...config.atr }
509
- this.dirtyAtrConfig = true
510
- }
511
- if (config.wma !== undefined && !this.shallowEqual(config.wma as unknown as Record<string, unknown>, this.config.wma as unknown as Record<string, unknown>)) {
512
- this.config.wma = { ...this.config.wma, ...config.wma }
513
- this.dirtyWmaConfig = true
514
- }
515
- if (config.dema !== undefined && !this.shallowEqual(config.dema as unknown as Record<string, unknown>, this.config.dema as unknown as Record<string, unknown>)) {
516
- this.config.dema = { ...this.config.dema, ...config.dema }
517
- this.dirtyDemaConfig = true
518
- }
519
- if (config.tema !== undefined && !this.shallowEqual(config.tema as unknown as Record<string, unknown>, this.config.tema as unknown as Record<string, unknown>)) {
520
- this.config.tema = { ...this.config.tema, ...config.tema }
521
- this.dirtyTemaConfig = true
522
- }
523
- if (config.hma !== undefined && !this.shallowEqual(config.hma as unknown as Record<string, unknown>, this.config.hma as unknown as Record<string, unknown>)) {
524
- this.config.hma = { ...this.config.hma, ...config.hma }
525
- this.dirtyHmaConfig = true
526
- }
527
- if (config.kama !== undefined && !this.shallowEqual(config.kama as unknown as Record<string, unknown>, this.config.kama as unknown as Record<string, unknown>)) {
528
- this.config.kama = { ...this.config.kama, ...config.kama }
529
- this.dirtyKamaConfig = true
530
- }
531
- if (config.sar !== undefined && !this.shallowEqual(config.sar as unknown as Record<string, unknown>, this.config.sar as unknown as Record<string, unknown>)) {
532
- this.config.sar = { ...this.config.sar, ...config.sar }
533
- this.dirtySarConfig = true
534
- }
535
- if (config.supertrend !== undefined && !this.shallowEqual(config.supertrend as unknown as Record<string, unknown>, this.config.supertrend as unknown as Record<string, unknown>)) {
536
- this.config.supertrend = { ...this.config.supertrend, ...config.supertrend }
537
- this.dirtySupertrendConfig = true
538
- }
539
- if (config.keltner !== undefined && !this.shallowEqual(config.keltner as unknown as Record<string, unknown>, this.config.keltner as unknown as Record<string, unknown>)) {
540
- this.config.keltner = { ...this.config.keltner, ...config.keltner }
541
- this.dirtyKeltnerConfig = true
542
- }
543
- if (config.donchian !== undefined && !this.shallowEqual(config.donchian as unknown as Record<string, unknown>, this.config.donchian as unknown as Record<string, unknown>)) {
544
- this.config.donchian = { ...this.config.donchian, ...config.donchian }
545
- this.dirtyDonchianConfig = true
546
- }
547
- if (config.ichimoku !== undefined && !this.shallowEqual(config.ichimoku as unknown as Record<string, unknown>, this.config.ichimoku as unknown as Record<string, unknown>)) {
548
- this.config.ichimoku = { ...this.config.ichimoku, ...config.ichimoku }
549
- this.dirtyIchimokuConfig = true
550
- }
551
- if (config.roc !== undefined && !this.shallowEqual(config.roc as unknown as Record<string, unknown>, this.config.roc as unknown as Record<string, unknown>)) {
552
- this.config.roc = { ...this.config.roc, ...config.roc }
553
- this.dirtyRocConfig = true
554
- }
555
- if (config.trix !== undefined && !this.shallowEqual(config.trix as unknown as Record<string, unknown>, this.config.trix as unknown as Record<string, unknown>)) {
556
- this.config.trix = { ...this.config.trix, ...config.trix }
557
- this.dirtyTrixConfig = true
558
- }
559
- if (config.hv !== undefined && !this.shallowEqual(config.hv as unknown as Record<string, unknown>, this.config.hv as unknown as Record<string, unknown>)) {
560
- this.config.hv = { ...this.config.hv, ...config.hv }
561
- this.dirtyHvConfig = true
562
- }
563
- if (config.parkinson !== undefined && !this.shallowEqual(config.parkinson as unknown as Record<string, unknown>, this.config.parkinson as unknown as Record<string, unknown>)) {
564
- this.config.parkinson = { ...this.config.parkinson, ...config.parkinson }
565
- this.dirtyParkinsonConfig = true
566
- }
567
- if (config.chaikinVol !== undefined && !this.shallowEqual(config.chaikinVol as unknown as Record<string, unknown>, this.config.chaikinVol as unknown as Record<string, unknown>)) {
568
- this.config.chaikinVol = { ...this.config.chaikinVol, ...config.chaikinVol }
569
- this.dirtyChaikinVolConfig = true
570
- }
571
- if (config.vma !== undefined && !this.shallowEqual(config.vma as unknown as Record<string, unknown>, this.config.vma as unknown as Record<string, unknown>)) {
572
- this.config.vma = { ...this.config.vma, ...config.vma }
573
- this.dirtyVmaConfig = true
574
- }
575
- if (config.obv !== undefined && !this.shallowEqual(config.obv as unknown as Record<string, unknown>, this.config.obv as unknown as Record<string, unknown>)) {
576
- this.config.obv = { ...this.config.obv, ...config.obv }
577
- this.dirtyObvConfig = true
578
- }
579
- if (config.pvt !== undefined && !this.shallowEqual(config.pvt as unknown as Record<string, unknown>, this.config.pvt as unknown as Record<string, unknown>)) {
580
- this.config.pvt = { ...this.config.pvt, ...config.pvt }
581
- this.dirtyPvtConfig = true
582
- }
583
- if (config.vwap !== undefined && !this.shallowEqual(config.vwap as unknown as Record<string, unknown>, this.config.vwap as unknown as Record<string, unknown>)) {
584
- this.config.vwap = { ...this.config.vwap, ...config.vwap }
585
- this.dirtyVwapConfig = true
586
- }
587
- if (config.cmf !== undefined && !this.shallowEqual(config.cmf as unknown as Record<string, unknown>, this.config.cmf as unknown as Record<string, unknown>)) {
588
- this.config.cmf = { ...this.config.cmf, ...config.cmf }
589
- this.dirtyCmfConfig = true
590
- }
591
- if (config.mfi !== undefined && !this.shallowEqual(config.mfi as unknown as Record<string, unknown>, this.config.mfi as unknown as Record<string, unknown>)) {
592
- this.config.mfi = { ...this.config.mfi, ...config.mfi }
593
- this.dirtyMfiConfig = true
594
- }
595
- if (config.pivot !== undefined && !this.shallowEqual(config.pivot as unknown as Record<string, unknown>, this.config.pivot as unknown as Record<string, unknown>)) {
596
- this.config.pivot = { ...this.config.pivot, ...config.pivot }
597
- this.dirtyPivotConfig = true
598
- }
599
- if (config.fib !== undefined && !this.shallowEqual(config.fib as unknown as Record<string, unknown>, this.config.fib as unknown as Record<string, unknown>)) {
600
- this.config.fib = { ...this.config.fib, ...config.fib }
601
- this.dirtyFibConfig = true
602
- }
603
- if (config.structure !== undefined && !this.shallowEqual(config.structure as unknown as Record<string, unknown>, this.config.structure as unknown as Record<string, unknown>)) {
604
- this.config.structure = { ...this.config.structure, ...config.structure }
605
- this.dirtyStructureConfig = true
606
- }
607
- if (config.zones !== undefined && !this.shallowEqual(config.zones as unknown as Record<string, unknown>, this.config.zones as unknown as Record<string, unknown>)) {
608
- this.config.zones = { ...this.config.zones, ...config.zones }
609
- this.dirtyZonesConfig = true
610
- }
611
- if (config.volumeProfile !== undefined && !this.shallowEqual(config.volumeProfile as unknown as Record<string, unknown>, this.config.volumeProfile as unknown as Record<string, unknown>)) {
612
- this.config.volumeProfile = { ...this.config.volumeProfile, ...config.volumeProfile }
613
- this.dirtyVolumeProfileConfig = true
614
- }
615
- // pane IDs
616
- if (config.rsiPaneId !== undefined) this.config.rsiPaneId = config.rsiPaneId
617
- if (config.cciPaneId !== undefined) this.config.cciPaneId = config.cciPaneId
618
- if (config.stochPaneId !== undefined) this.config.stochPaneId = config.stochPaneId
619
- if (config.momPaneId !== undefined) this.config.momPaneId = config.momPaneId
620
- if (config.wmsrPaneId !== undefined) this.config.wmsrPaneId = config.wmsrPaneId
621
- if (config.kstPaneId !== undefined) this.config.kstPaneId = config.kstPaneId
622
- if (config.fastkPaneId !== undefined) this.config.fastkPaneId = config.fastkPaneId
623
- if (config.macdPaneId !== undefined) this.config.macdPaneId = config.macdPaneId
624
- if (config.atrPaneId !== undefined) this.config.atrPaneId = config.atrPaneId
625
- if (config.wmaPaneId !== undefined) this.config.wmaPaneId = config.wmaPaneId
626
- if (config.demaPaneId !== undefined) this.config.demaPaneId = config.demaPaneId
627
- if (config.temaPaneId !== undefined) this.config.temaPaneId = config.temaPaneId
628
- if (config.hmaPaneId !== undefined) this.config.hmaPaneId = config.hmaPaneId
629
- if (config.kamaPaneId !== undefined) this.config.kamaPaneId = config.kamaPaneId
630
- if (config.sarPaneId !== undefined) this.config.sarPaneId = config.sarPaneId
631
- if (config.supertrendPaneId !== undefined) this.config.supertrendPaneId = config.supertrendPaneId
632
- if (config.keltnerPaneId !== undefined) this.config.keltnerPaneId = config.keltnerPaneId
633
- if (config.donchianPaneId !== undefined) this.config.donchianPaneId = config.donchianPaneId
634
- if (config.ichimokuPaneId !== undefined) this.config.ichimokuPaneId = config.ichimokuPaneId
635
- if (config.rocPaneId !== undefined) this.config.rocPaneId = config.rocPaneId
636
- if (config.trixPaneId !== undefined) this.config.trixPaneId = config.trixPaneId
637
- if (config.hvPaneId !== undefined) this.config.hvPaneId = config.hvPaneId
638
- if (config.parkinsonPaneId !== undefined) this.config.parkinsonPaneId = config.parkinsonPaneId
639
- if (config.chaikinVolPaneId !== undefined) this.config.chaikinVolPaneId = config.chaikinVolPaneId
640
- if (config.vmaPaneId !== undefined) this.config.vmaPaneId = config.vmaPaneId
641
- if (config.obvPaneId !== undefined) this.config.obvPaneId = config.obvPaneId
642
- if (config.pvtPaneId !== undefined) this.config.pvtPaneId = config.pvtPaneId
643
- if (config.vwapPaneId !== undefined) this.config.vwapPaneId = config.vwapPaneId
644
- if (config.cmfPaneId !== undefined) this.config.cmfPaneId = config.cmfPaneId
645
- if (config.mfiPaneId !== undefined) this.config.mfiPaneId = config.mfiPaneId
646
- if (config.pivotPaneId !== undefined) this.config.pivotPaneId = config.pivotPaneId
647
- if (config.fibPaneId !== undefined) this.config.fibPaneId = config.fibPaneId
648
- if (config.structurePaneId !== undefined) this.config.structurePaneId = config.structurePaneId
649
- if (config.zonesPaneId !== undefined) this.config.zonesPaneId = config.zonesPaneId
650
- if (config.volumeProfilePaneId !== undefined) this.config.volumeProfilePaneId = config.volumeProfilePaneId
651
-
652
- this.configVersion = version
653
- }
654
-
655
- /**
656
- * 强制所有指标标记为脏(用于 recompute)
657
- */
658
- forceDirty(): void {
659
- this.dirtyData = true
660
- this.dirtyMAConfig = true
661
- this.dirtyBollConfig = true
662
- this.dirtyExpmaConfig = true
663
- this.dirtyEneConfig = true
664
- this.dirtyRsiConfig = true
665
- this.dirtyCciConfig = true
666
- this.dirtyStochConfig = true
667
- this.dirtyMomConfig = true
668
- this.dirtyWmsrConfig = true
669
- this.dirtyKstConfig = true
670
- this.dirtyFastkConfig = true
671
- this.dirtyMacdConfig = true
672
- this.dirtyAtrConfig = true
673
- this.dirtyWmaConfig = true
674
- this.dirtyDemaConfig = true
675
- this.dirtyTemaConfig = true
676
- this.dirtyHmaConfig = true
677
- this.dirtyKamaConfig = true
678
- this.dirtySarConfig = true
679
- this.dirtySupertrendConfig = true
680
- this.dirtyKeltnerConfig = true
681
- this.dirtyDonchianConfig = true
682
- this.dirtyIchimokuConfig = true
683
- this.dirtyRocConfig = true
684
- this.dirtyTrixConfig = true
685
- this.dirtyHvConfig = true
686
- this.dirtyParkinsonConfig = true
687
- this.dirtyChaikinVolConfig = true
688
- this.dirtyVmaConfig = true
689
- this.dirtyObvConfig = true
690
- this.dirtyPvtConfig = true
691
- this.dirtyVwapConfig = true
692
- this.dirtyCmfConfig = true
693
- this.dirtyMfiConfig = true
694
- this.dirtyPivotConfig = true
695
- this.dirtyFibConfig = true
696
- this.dirtyStructureConfig = true
697
- this.dirtyZonesConfig = true
698
- this.dirtyVolumeProfileConfig = true
699
- }
700
-
701
- /**
702
- * 获取当前数据版本
703
- */
704
- getDataVersion(): number {
705
- return this.dataVersion
706
- }
707
-
708
- /**
709
- * 获取当前配置版本
710
- */
711
- getConfigVersion(): number {
712
- return this.configVersion
713
- }
714
-
715
- /**
716
- * 计算所有指标的 series(如果脏了)
717
- * 返回结果包,供主线程组装成 render states
718
- */
719
- computeSeries(): IndicatorSeriesBundle {
720
- const data = this.currentData
721
- const changed: string[] = []
722
-
723
- // MA
724
- if (this.dirtyData || this.dirtyMAConfig) {
725
- this.cachedSeries = {}
726
- for (const period of DEFAULT_MA_PERIODS) {
727
- const flagKey = `ma${period}` as keyof MAFlags
728
- if (this.config.ma[flagKey]) {
729
- this.cachedSeries[period] = calcMAData(data, period)
730
- }
731
- }
732
- changed.push('ma')
733
- }
734
-
735
- // BOLL
736
- if (this.dirtyData || this.dirtyBollConfig) {
737
- this.cachedBollSeries = calcBOLLData(
738
- data,
739
- this.config.boll.period,
740
- this.config.boll.multiplier
741
- )
742
- changed.push('boll')
743
- }
744
-
745
- // EXPMA
746
- if (this.dirtyData || this.dirtyExpmaConfig) {
747
- this.cachedExpmaSeries = calcEXPMAData(
748
- data,
749
- this.config.expma.fastPeriod,
750
- this.config.expma.slowPeriod
751
- )
752
- changed.push('expma')
753
- }
754
-
755
- // ENE
756
- if (this.dirtyData || this.dirtyEneConfig) {
757
- this.cachedEneSeries = calcENEData(
758
- data,
759
- this.config.ene.period,
760
- this.config.ene.deviation
761
- )
762
- changed.push('ene')
763
- }
764
-
765
- // RSI
766
- if (this.dirtyData || this.dirtyRsiConfig) {
767
- this.cachedRsiSeries = {}
768
- const periods = [this.config.rsi.period1, this.config.rsi.period2, this.config.rsi.period3]
769
- const shows = [this.config.rsi.showRSI1, this.config.rsi.showRSI2, this.config.rsi.showRSI3]
770
- for (let i = 0; i < periods.length; i++) {
771
- if (shows[i]) {
772
- this.cachedRsiSeries[periods[i]] = calcRSIData(data, periods[i])
773
- }
774
- }
775
- changed.push('rsi')
776
- }
777
-
778
- // CCI
779
- if (this.dirtyData || this.dirtyCciConfig) {
780
- if (this.config.cci.showCCI) {
781
- this.cachedCciSeries = calcCCIData(data, this.config.cci.period)
782
- } else {
783
- this.cachedCciSeries = []
784
- }
785
- changed.push('cci')
786
- }
787
-
788
- // STOCH
789
- if (this.dirtyData || this.dirtyStochConfig) {
790
- if (this.config.stoch.showK || this.config.stoch.showD) {
791
- this.cachedStochSeries = calcSTOCHData(data, this.config.stoch.n, this.config.stoch.m)
792
- } else {
793
- this.cachedStochSeries = []
794
- }
795
- changed.push('stoch')
796
- }
797
-
798
- // MOM
799
- if (this.dirtyData || this.dirtyMomConfig) {
800
- if (this.config.mom.showMOM) {
801
- this.cachedMomSeries = calcMOMData(data, this.config.mom.period)
802
- } else {
803
- this.cachedMomSeries = []
804
- }
805
- changed.push('mom')
806
- }
807
-
808
- // WMSR
809
- if (this.dirtyData || this.dirtyWmsrConfig) {
810
- if (this.config.wmsr.showWMSR) {
811
- this.cachedWmsrSeries = calcWMSRData(data, this.config.wmsr.period)
812
- } else {
813
- this.cachedWmsrSeries = []
814
- }
815
- changed.push('wmsr')
816
- }
817
-
818
- // KST
819
- if (this.dirtyData || this.dirtyKstConfig) {
820
- if (this.config.kst.showKST || this.config.kst.showSignal) {
821
- this.cachedKstSeries = calcKSTData(
822
- data,
823
- this.config.kst.roc1,
824
- this.config.kst.roc2,
825
- this.config.kst.roc3,
826
- this.config.kst.roc4,
827
- this.config.kst.signalPeriod
828
- )
829
- } else {
830
- this.cachedKstSeries = []
831
- }
832
- changed.push('kst')
833
- }
834
-
835
- // FASTK
836
- if (this.dirtyData || this.dirtyFastkConfig) {
837
- if (this.config.fastk.showFASTK) {
838
- this.cachedFastkSeries = calcFASTKData(data, this.config.fastk.period)
839
- } else {
840
- this.cachedFastkSeries = []
841
- }
842
- changed.push('fastk')
843
- }
844
-
845
- // MACD
846
- if (this.dirtyData || this.dirtyMacdConfig) {
847
- if (this.config.macd.showDIF || this.config.macd.showDEA || this.config.macd.showBAR) {
848
- this.cachedMacdSeries = calcMACDData(
849
- data,
850
- this.config.macd.fastPeriod,
851
- this.config.macd.slowPeriod,
852
- this.config.macd.signalPeriod
853
- )
854
- } else {
855
- this.cachedMacdSeries = []
856
- }
857
- changed.push('macd')
858
- }
859
-
860
- // ATR
861
- if (this.dirtyData || this.dirtyAtrConfig) {
862
- if (this.config.atr.showATR) {
863
- this.cachedAtrSeries = calcATRData(data, this.config.atr.period)
864
- } else {
865
- this.cachedAtrSeries = []
866
- }
867
- changed.push('atr')
868
- }
869
-
870
- // WMA
871
- if (this.dirtyData || this.dirtyWmaConfig) {
872
- if (this.config.wma.showWMA) {
873
- this.cachedWmaSeries = calcWMAData(data, this.config.wma.period)
874
- } else {
875
- this.cachedWmaSeries = []
876
- }
877
- changed.push('wma')
878
- }
879
-
880
- // DEMA
881
- if (this.dirtyData || this.dirtyDemaConfig) {
882
- if (this.config.dema.showDEMA) {
883
- this.cachedDemaSeries = calcDEMAData(data, this.config.dema.period)
884
- } else {
885
- this.cachedDemaSeries = []
886
- }
887
- changed.push('dema')
888
- }
889
-
890
- // TEMA
891
- if (this.dirtyData || this.dirtyTemaConfig) {
892
- if (this.config.tema.showTEMA) {
893
- this.cachedTemaSeries = calcTEMAData(data, this.config.tema.period)
894
- } else {
895
- this.cachedTemaSeries = []
896
- }
897
- changed.push('tema')
898
- }
899
-
900
- // HMA
901
- if (this.dirtyData || this.dirtyHmaConfig) {
902
- if (this.config.hma.showHMA) {
903
- this.cachedHmaSeries = calcHMAData(data, this.config.hma.period)
904
- } else {
905
- this.cachedHmaSeries = []
906
- }
907
- changed.push('hma')
908
- }
909
-
910
- // KAMA
911
- if (this.dirtyData || this.dirtyKamaConfig) {
912
- if (this.config.kama.showKAMA) {
913
- this.cachedKamaSeries = calcKAMAData(
914
- data,
915
- this.config.kama.period,
916
- this.config.kama.fastPeriod,
917
- this.config.kama.slowPeriod,
918
- )
919
- } else {
920
- this.cachedKamaSeries = []
921
- }
922
- changed.push('kama')
923
- }
924
-
925
- // SAR
926
- if (this.dirtyData || this.dirtySarConfig) {
927
- if (this.config.sar.showSAR) {
928
- this.cachedSarSeries = calcSARData(
929
- data,
930
- this.config.sar.step,
931
- this.config.sar.maxStep,
932
- )
933
- } else {
934
- this.cachedSarSeries = []
935
- }
936
- changed.push('sar')
937
- }
938
-
939
- // SuperTrend
940
- if (this.dirtyData || this.dirtySupertrendConfig) {
941
- if (this.config.supertrend.showSuperTrend) {
942
- this.cachedSupertrendSeries = calcSuperTrendData(
943
- data,
944
- this.config.supertrend.atrPeriod,
945
- this.config.supertrend.multiplier,
946
- )
947
- } else {
948
- this.cachedSupertrendSeries = []
949
- }
950
- changed.push('supertrend')
951
- }
952
-
953
- // Keltner
954
- if (this.dirtyData || this.dirtyKeltnerConfig) {
955
- if (this.config.keltner.showUpper || this.config.keltner.showMiddle || this.config.keltner.showLower) {
956
- this.cachedKeltnerSeries = calcKeltnerData(
957
- data,
958
- this.config.keltner.emaPeriod,
959
- this.config.keltner.atrPeriod,
960
- this.config.keltner.multiplier,
961
- )
962
- } else {
963
- this.cachedKeltnerSeries = []
964
- }
965
- changed.push('keltner')
966
- }
967
-
968
- // Donchian
969
- if (this.dirtyData || this.dirtyDonchianConfig) {
970
- if (this.config.donchian.showUpper || this.config.donchian.showMiddle || this.config.donchian.showLower) {
971
- this.cachedDonchianSeries = calcDonchianData(data, this.config.donchian.period)
972
- } else {
973
- this.cachedDonchianSeries = []
974
- }
975
- changed.push('donchian')
976
- }
977
-
978
- // Ichimoku
979
- if (this.dirtyData || this.dirtyIchimokuConfig) {
980
- const ic = this.config.ichimoku
981
- if (ic.showTenkan || ic.showKijun || ic.showSpanA || ic.showSpanB || ic.showCloud || ic.showChikou) {
982
- this.cachedIchimokuSeries = calcIchimokuData(
983
- data,
984
- ic.tenkanPeriod,
985
- ic.kijunPeriod,
986
- ic.spanBPeriod,
987
- ic.displacement,
988
- )
989
- } else {
990
- this.cachedIchimokuSeries = []
991
- }
992
- changed.push('ichimoku')
993
- }
994
-
995
- // ROC
996
- if (this.dirtyData || this.dirtyRocConfig) {
997
- if (this.config.roc.showROC) {
998
- this.cachedRocSeries = calcROCData(data, this.config.roc.period)
999
- } else {
1000
- this.cachedRocSeries = []
1001
- }
1002
- changed.push('roc')
1003
- }
1004
-
1005
- // TRIX
1006
- if (this.dirtyData || this.dirtyTrixConfig) {
1007
- if (this.config.trix.showTRIX || this.config.trix.showSignal) {
1008
- const result = calcTRIXData(data, this.config.trix.period, this.config.trix.signalPeriod)
1009
- this.cachedTrixSeries = result.series
1010
- this.cachedTrixSignalSeries = result.signalSeries
1011
- } else {
1012
- this.cachedTrixSeries = []
1013
- this.cachedTrixSignalSeries = []
1014
- }
1015
- changed.push('trix')
1016
- }
1017
-
1018
- // HV
1019
- if (this.dirtyData || this.dirtyHvConfig) {
1020
- if (this.config.hv.showHV) {
1021
- this.cachedHvSeries = calcHVData(data, this.config.hv.period, this.config.hv.annualizationFactor)
1022
- } else {
1023
- this.cachedHvSeries = []
1024
- }
1025
- changed.push('hv')
1026
- }
1027
-
1028
- // Parkinson
1029
- if (this.dirtyData || this.dirtyParkinsonConfig) {
1030
- if (this.config.parkinson.showParkinson) {
1031
- this.cachedParkinsonSeries = calcParkinsonData(
1032
- data,
1033
- this.config.parkinson.period,
1034
- this.config.parkinson.annualizationFactor,
1035
- )
1036
- } else {
1037
- this.cachedParkinsonSeries = []
1038
- }
1039
- changed.push('parkinson')
1040
- }
1041
-
1042
- // Chaikin Volatility
1043
- if (this.dirtyData || this.dirtyChaikinVolConfig) {
1044
- if (this.config.chaikinVol.showChaikinVol) {
1045
- this.cachedChaikinVolSeries = calcChaikinVolData(
1046
- data,
1047
- this.config.chaikinVol.emaPeriod,
1048
- this.config.chaikinVol.rocPeriod,
1049
- )
1050
- } else {
1051
- this.cachedChaikinVolSeries = []
1052
- }
1053
- changed.push('chaikinVol')
1054
- }
1055
-
1056
- // VMA
1057
- if (this.dirtyData || this.dirtyVmaConfig) {
1058
- if (this.config.vma.showVMA) {
1059
- this.cachedVmaSeries = calcVMAData(data, this.config.vma.period)
1060
- } else {
1061
- this.cachedVmaSeries = []
1062
- }
1063
- changed.push('vma')
1064
- }
1065
-
1066
- // OBV
1067
- if (this.dirtyData || this.dirtyObvConfig) {
1068
- if (this.config.obv.showOBV) {
1069
- this.cachedObvSeries = calcOBVData(data)
1070
- } else {
1071
- this.cachedObvSeries = []
1072
- }
1073
- changed.push('obv')
1074
- }
1075
-
1076
- // PVT
1077
- if (this.dirtyData || this.dirtyPvtConfig) {
1078
- if (this.config.pvt.showPVT) {
1079
- this.cachedPvtSeries = calcPVTData(data)
1080
- } else {
1081
- this.cachedPvtSeries = []
1082
- }
1083
- changed.push('pvt')
1084
- }
1085
-
1086
- // VWAP
1087
- if (this.dirtyData || this.dirtyVwapConfig) {
1088
- if (this.config.vwap.showVWAP) {
1089
- this.cachedVwapSeries = calcVWAPData(data, this.config.vwap.sessionResetGapMs)
1090
- } else {
1091
- this.cachedVwapSeries = []
1092
- }
1093
- changed.push('vwap')
1094
- }
1095
-
1096
- // CMF
1097
- if (this.dirtyData || this.dirtyCmfConfig) {
1098
- if (this.config.cmf.showCMF) {
1099
- this.cachedCmfSeries = calcCMFData(data, this.config.cmf.period)
1100
- } else {
1101
- this.cachedCmfSeries = []
1102
- }
1103
- changed.push('cmf')
1104
- }
1105
-
1106
- // MFI
1107
- if (this.dirtyData || this.dirtyMfiConfig) {
1108
- if (this.config.mfi.showMFI) {
1109
- this.cachedMfiSeries = calcMFIData(data, this.config.mfi.period)
1110
- } else {
1111
- this.cachedMfiSeries = []
1112
- }
1113
- changed.push('mfi')
1114
- }
1115
-
1116
- // Pivot
1117
- if (this.dirtyData || this.dirtyPivotConfig) {
1118
- const p = this.config.pivot
1119
- if (p.showPP || p.showR1 || p.showR2 || p.showR3 || p.showS1 || p.showS2 || p.showS3) {
1120
- this.cachedPivotSeries = calcPivotData(data)
1121
- } else {
1122
- this.cachedPivotSeries = []
1123
- }
1124
- changed.push('pivot')
1125
- }
1126
-
1127
- // Fibonacci
1128
- if (this.dirtyData || this.dirtyFibConfig) {
1129
- if (this.config.fib.showLevels) {
1130
- this.cachedFibSeries = calcFibData(data, this.config.fib.period)
1131
- } else {
1132
- this.cachedFibSeries = []
1133
- }
1134
- changed.push('fib')
1135
- }
1136
-
1137
- // SMC Structure
1138
- if (this.dirtyData || this.dirtyStructureConfig) {
1139
- const s = this.config.structure
1140
- if (s.showSwingLabels || s.showBOS || s.showCHOCH) {
1141
- this.cachedStructureSeries = calcStructureData(data, s.leftWindow, s.rightWindow, s.breakoutSource)
1142
- } else {
1143
- this.cachedStructureSeries = { swings: [], events: [], trend: 'range' }
1144
- }
1145
- changed.push('structure')
1146
- }
1147
-
1148
- // SMC Zones
1149
- if (this.dirtyData || this.dirtyZonesConfig) {
1150
- const z = this.config.zones
1151
- if (z.showFVG || z.showOB) {
1152
- this.cachedZonesSeries = calcZonesData(
1153
- data,
1154
- z.obLookback,
1155
- this.config.structure.leftWindow,
1156
- this.config.structure.rightWindow,
1157
- this.config.structure.breakoutSource,
1158
- )
1159
- } else {
1160
- this.cachedZonesSeries = []
1161
- }
1162
- changed.push('zones')
1163
- }
1164
-
1165
- // Volume Profile
1166
- if (this.dirtyData || this.dirtyVolumeProfileConfig) {
1167
- const vp = this.config.volumeProfile
1168
- if (vp.showPOC || vp.showValueArea) {
1169
- this.cachedVolumeProfileSeries = calcVolumeProfileData(data, vp.bins, vp.lookback, vp.valueAreaPercent)
1170
- } else {
1171
- this.cachedVolumeProfileSeries = { bins: [], poc: 0, vah: 0, val: 0, totalVolume: 0 }
1172
- }
1173
- changed.push('volumeProfile')
1174
- }
1175
-
1176
- // 重置脏标记
1177
- this.dirtyData = false
1178
- this.dirtyMAConfig = false
1179
- this.dirtyBollConfig = false
1180
- this.dirtyExpmaConfig = false
1181
- this.dirtyEneConfig = false
1182
- this.dirtyRsiConfig = false
1183
- this.dirtyCciConfig = false
1184
- this.dirtyStochConfig = false
1185
- this.dirtyMomConfig = false
1186
- this.dirtyWmsrConfig = false
1187
- this.dirtyKstConfig = false
1188
- this.dirtyFastkConfig = false
1189
- this.dirtyMacdConfig = false
1190
- this.dirtyAtrConfig = false
1191
- this.dirtyWmaConfig = false
1192
- this.dirtyDemaConfig = false
1193
- this.dirtyTemaConfig = false
1194
- this.dirtyHmaConfig = false
1195
- this.dirtyKamaConfig = false
1196
- this.dirtySarConfig = false
1197
- this.dirtySupertrendConfig = false
1198
- this.dirtyKeltnerConfig = false
1199
- this.dirtyDonchianConfig = false
1200
- this.dirtyIchimokuConfig = false
1201
- this.dirtyRocConfig = false
1202
- this.dirtyTrixConfig = false
1203
- this.dirtyHvConfig = false
1204
- this.dirtyParkinsonConfig = false
1205
- this.dirtyChaikinVolConfig = false
1206
- this.dirtyVmaConfig = false
1207
- this.dirtyObvConfig = false
1208
- this.dirtyPvtConfig = false
1209
- this.dirtyVwapConfig = false
1210
- this.dirtyCmfConfig = false
1211
- this.dirtyMfiConfig = false
1212
- this.dirtyPivotConfig = false
1213
- this.dirtyFibConfig = false
1214
- this.dirtyStructureConfig = false
1215
- this.dirtyZonesConfig = false
1216
- this.dirtyVolumeProfileConfig = false
1217
-
1218
- // 组装结果
1219
- return {
1220
- ma: {
1221
- series: this.cachedSeries,
1222
- enabledPeriods: Object.keys(this.cachedSeries).map(Number),
1223
- },
1224
- boll: {
1225
- series: this.cachedBollSeries,
1226
- params: { ...this.config.boll },
1227
- },
1228
- expma: {
1229
- series: this.cachedExpmaSeries,
1230
- params: { ...this.config.expma },
1231
- },
1232
- ene: {
1233
- series: this.cachedEneSeries,
1234
- params: { ...this.config.ene },
1235
- },
1236
- rsi: {
1237
- series: this.cachedRsiSeries,
1238
- enabledPeriods: Object.keys(this.cachedRsiSeries).map(Number),
1239
- params: { ...this.config.rsi },
1240
- },
1241
- cci: {
1242
- series: this.cachedCciSeries,
1243
- params: { ...this.config.cci },
1244
- },
1245
- stoch: {
1246
- series: this.cachedStochSeries,
1247
- params: { ...this.config.stoch },
1248
- },
1249
- mom: {
1250
- series: this.cachedMomSeries,
1251
- params: { ...this.config.mom },
1252
- },
1253
- wmsr: {
1254
- series: this.cachedWmsrSeries,
1255
- params: { ...this.config.wmsr },
1256
- },
1257
- kst: {
1258
- series: this.cachedKstSeries,
1259
- params: { ...this.config.kst },
1260
- },
1261
- fastk: {
1262
- series: this.cachedFastkSeries,
1263
- params: { ...this.config.fastk },
1264
- },
1265
- macd: {
1266
- series: this.cachedMacdSeries,
1267
- params: { ...this.config.macd },
1268
- },
1269
- atr: {
1270
- series: this.cachedAtrSeries,
1271
- params: { ...this.config.atr },
1272
- },
1273
- wma: {
1274
- series: this.cachedWmaSeries,
1275
- params: { ...this.config.wma },
1276
- },
1277
- dema: {
1278
- series: this.cachedDemaSeries,
1279
- params: { ...this.config.dema },
1280
- },
1281
- tema: {
1282
- series: this.cachedTemaSeries,
1283
- params: { ...this.config.tema },
1284
- },
1285
- hma: {
1286
- series: this.cachedHmaSeries,
1287
- params: { ...this.config.hma },
1288
- },
1289
- kama: {
1290
- series: this.cachedKamaSeries,
1291
- params: { ...this.config.kama },
1292
- },
1293
- sar: {
1294
- series: this.cachedSarSeries,
1295
- params: { ...this.config.sar },
1296
- },
1297
- supertrend: {
1298
- series: this.cachedSupertrendSeries,
1299
- params: { ...this.config.supertrend },
1300
- },
1301
- keltner: {
1302
- series: this.cachedKeltnerSeries,
1303
- params: { ...this.config.keltner },
1304
- },
1305
- donchian: {
1306
- series: this.cachedDonchianSeries,
1307
- params: { ...this.config.donchian },
1308
- },
1309
- ichimoku: {
1310
- series: this.cachedIchimokuSeries,
1311
- params: { ...this.config.ichimoku },
1312
- },
1313
- roc: {
1314
- series: this.cachedRocSeries,
1315
- params: { ...this.config.roc },
1316
- },
1317
- trix: {
1318
- series: this.cachedTrixSeries,
1319
- signalSeries: this.cachedTrixSignalSeries,
1320
- params: { ...this.config.trix },
1321
- },
1322
- hv: {
1323
- series: this.cachedHvSeries,
1324
- params: { ...this.config.hv },
1325
- },
1326
- parkinson: {
1327
- series: this.cachedParkinsonSeries,
1328
- params: { ...this.config.parkinson },
1329
- },
1330
- chaikinVol: {
1331
- series: this.cachedChaikinVolSeries,
1332
- params: { ...this.config.chaikinVol },
1333
- },
1334
- vma: {
1335
- series: this.cachedVmaSeries,
1336
- params: { ...this.config.vma },
1337
- },
1338
- obv: {
1339
- series: this.cachedObvSeries,
1340
- params: { ...this.config.obv },
1341
- },
1342
- pvt: {
1343
- series: this.cachedPvtSeries,
1344
- params: { ...this.config.pvt },
1345
- },
1346
- vwap: {
1347
- series: this.cachedVwapSeries,
1348
- params: { ...this.config.vwap },
1349
- },
1350
- cmf: {
1351
- series: this.cachedCmfSeries,
1352
- params: { ...this.config.cmf },
1353
- },
1354
- mfi: {
1355
- series: this.cachedMfiSeries,
1356
- params: { ...this.config.mfi },
1357
- },
1358
- pivot: {
1359
- series: this.cachedPivotSeries,
1360
- params: { ...this.config.pivot },
1361
- },
1362
- fib: {
1363
- series: this.cachedFibSeries,
1364
- params: { ...this.config.fib },
1365
- },
1366
- structure: {
1367
- series: this.cachedStructureSeries,
1368
- params: { ...this.config.structure },
1369
- },
1370
- zones: {
1371
- series: this.cachedZonesSeries,
1372
- params: { ...this.config.zones },
1373
- },
1374
- volumeProfile: {
1375
- series: this.cachedVolumeProfileSeries,
1376
- params: { ...this.config.volumeProfile },
1377
- },
1378
- _changed: changed,
1379
- }
1380
- }
1381
-
1382
- /**
1383
- * 获取缓存的 series(用于 visibleRange 变更时扫描极值)
1384
- */
1385
- getCachedSeries(): IndicatorSeriesBundle {
1386
- return {
1387
- _changed: [],
1388
- ma: {
1389
- series: this.cachedSeries,
1390
- enabledPeriods: Object.keys(this.cachedSeries).map(Number),
1391
- },
1392
- boll: {
1393
- series: this.cachedBollSeries,
1394
- params: { ...this.config.boll },
1395
- },
1396
- expma: {
1397
- series: this.cachedExpmaSeries,
1398
- params: { ...this.config.expma },
1399
- },
1400
- ene: {
1401
- series: this.cachedEneSeries,
1402
- params: { ...this.config.ene },
1403
- },
1404
- rsi: {
1405
- series: this.cachedRsiSeries,
1406
- enabledPeriods: Object.keys(this.cachedRsiSeries).map(Number),
1407
- params: { ...this.config.rsi },
1408
- },
1409
- cci: {
1410
- series: this.cachedCciSeries,
1411
- params: { ...this.config.cci },
1412
- },
1413
- stoch: {
1414
- series: this.cachedStochSeries,
1415
- params: { ...this.config.stoch },
1416
- },
1417
- mom: {
1418
- series: this.cachedMomSeries,
1419
- params: { ...this.config.mom },
1420
- },
1421
- wmsr: {
1422
- series: this.cachedWmsrSeries,
1423
- params: { ...this.config.wmsr },
1424
- },
1425
- kst: {
1426
- series: this.cachedKstSeries,
1427
- params: { ...this.config.kst },
1428
- },
1429
- fastk: {
1430
- series: this.cachedFastkSeries,
1431
- params: { ...this.config.fastk },
1432
- },
1433
- macd: {
1434
- series: this.cachedMacdSeries,
1435
- params: { ...this.config.macd },
1436
- },
1437
- atr: {
1438
- series: this.cachedAtrSeries,
1439
- params: { ...this.config.atr },
1440
- },
1441
- wma: {
1442
- series: this.cachedWmaSeries,
1443
- params: { ...this.config.wma },
1444
- },
1445
- dema: {
1446
- series: this.cachedDemaSeries,
1447
- params: { ...this.config.dema },
1448
- },
1449
- tema: {
1450
- series: this.cachedTemaSeries,
1451
- params: { ...this.config.tema },
1452
- },
1453
- hma: {
1454
- series: this.cachedHmaSeries,
1455
- params: { ...this.config.hma },
1456
- },
1457
- kama: {
1458
- series: this.cachedKamaSeries,
1459
- params: { ...this.config.kama },
1460
- },
1461
- sar: {
1462
- series: this.cachedSarSeries,
1463
- params: { ...this.config.sar },
1464
- },
1465
- supertrend: {
1466
- series: this.cachedSupertrendSeries,
1467
- params: { ...this.config.supertrend },
1468
- },
1469
- keltner: {
1470
- series: this.cachedKeltnerSeries,
1471
- params: { ...this.config.keltner },
1472
- },
1473
- donchian: {
1474
- series: this.cachedDonchianSeries,
1475
- params: { ...this.config.donchian },
1476
- },
1477
- ichimoku: {
1478
- series: this.cachedIchimokuSeries,
1479
- params: { ...this.config.ichimoku },
1480
- },
1481
- roc: {
1482
- series: this.cachedRocSeries,
1483
- params: { ...this.config.roc },
1484
- },
1485
- trix: {
1486
- series: this.cachedTrixSeries,
1487
- signalSeries: this.cachedTrixSignalSeries,
1488
- params: { ...this.config.trix },
1489
- },
1490
- hv: {
1491
- series: this.cachedHvSeries,
1492
- params: { ...this.config.hv },
1493
- },
1494
- parkinson: {
1495
- series: this.cachedParkinsonSeries,
1496
- params: { ...this.config.parkinson },
1497
- },
1498
- chaikinVol: {
1499
- series: this.cachedChaikinVolSeries,
1500
- params: { ...this.config.chaikinVol },
1501
- },
1502
- vma: {
1503
- series: this.cachedVmaSeries,
1504
- params: { ...this.config.vma },
1505
- },
1506
- obv: {
1507
- series: this.cachedObvSeries,
1508
- params: { ...this.config.obv },
1509
- },
1510
- pvt: {
1511
- series: this.cachedPvtSeries,
1512
- params: { ...this.config.pvt },
1513
- },
1514
- vwap: {
1515
- series: this.cachedVwapSeries,
1516
- params: { ...this.config.vwap },
1517
- },
1518
- cmf: {
1519
- series: this.cachedCmfSeries,
1520
- params: { ...this.config.cmf },
1521
- },
1522
- mfi: {
1523
- series: this.cachedMfiSeries,
1524
- params: { ...this.config.mfi },
1525
- },
1526
- pivot: {
1527
- series: this.cachedPivotSeries,
1528
- params: { ...this.config.pivot },
1529
- },
1530
- fib: {
1531
- series: this.cachedFibSeries,
1532
- params: { ...this.config.fib },
1533
- },
1534
- structure: {
1535
- series: this.cachedStructureSeries,
1536
- params: { ...this.config.structure },
1537
- },
1538
- zones: {
1539
- series: this.cachedZonesSeries,
1540
- params: { ...this.config.zones },
1541
- },
1542
- volumeProfile: {
1543
- series: this.cachedVolumeProfileSeries,
1544
- params: { ...this.config.volumeProfile },
1545
- },
1546
- }
1547
- }
1548
- }
1
+ /**
2
+ * Indicator 纯计算运行时
3
+ * 不依赖 PluginHost/StateStore,只负责计算和缓存
4
+ * 可被主线程(inline fallback)或 Worker 使用
5
+ */
6
+
7
+ import type { KLineData } from '../../types/price'
8
+ import {
9
+ calcMAData,
10
+ calcBOLLData,
11
+ calcEXPMAData,
12
+ calcENEData,
13
+ calcRSIData,
14
+ calcCCIData,
15
+ calcSTOCHData,
16
+ calcMOMData,
17
+ calcWMSRData,
18
+ calcKSTData,
19
+ calcFASTKData,
20
+ calcMACDData,
21
+ calcATRData,
22
+ calcWMAData,
23
+ calcDEMAData,
24
+ calcTEMAData,
25
+ calcHMAData,
26
+ calcKAMAData,
27
+ calcSARData,
28
+ calcSuperTrendData,
29
+ calcKeltnerData,
30
+ calcDonchianData,
31
+ calcIchimokuData,
32
+ calcROCData,
33
+ calcTRIXData,
34
+ calcHVData,
35
+ calcParkinsonData,
36
+ calcChaikinVolData,
37
+ calcVMAData,
38
+ calcOBVData,
39
+ calcPVTData,
40
+ calcVWAPData,
41
+ calcCMFData,
42
+ calcMFIData,
43
+ calcPivotData,
44
+ calcFibData,
45
+ calcStructureData,
46
+ calcZonesData,
47
+ calcVolumeProfileData,
48
+ DEFAULT_MA_PERIODS,
49
+ DEFAULT_ATR_PERIOD,
50
+ DEFAULT_VMA_PERIOD,
51
+ DEFAULT_STRUCTURE_LEFT,
52
+ DEFAULT_STRUCTURE_RIGHT,
53
+ DEFAULT_ZONES_OB_LOOKBACK,
54
+ DEFAULT_VP_BINS,
55
+ DEFAULT_VP_LOOKBACK,
56
+ DEFAULT_VP_VALUE_AREA,
57
+ DEFAULT_VWAP_SESSION_GAP_MS,
58
+ DEFAULT_CMF_PERIOD,
59
+ DEFAULT_MFI_PERIOD,
60
+ DEFAULT_FIB_PERIOD,
61
+ DEFAULT_WMA_PERIOD,
62
+ DEFAULT_DEMA_PERIOD,
63
+ DEFAULT_TEMA_PERIOD,
64
+ DEFAULT_HMA_PERIOD,
65
+ DEFAULT_KAMA_PERIOD,
66
+ DEFAULT_KAMA_FAST_PERIOD,
67
+ DEFAULT_KAMA_SLOW_PERIOD,
68
+ DEFAULT_SAR_STEP,
69
+ DEFAULT_SAR_MAX_STEP,
70
+ DEFAULT_SUPERTREND_ATR_PERIOD,
71
+ DEFAULT_SUPERTREND_MULTIPLIER,
72
+ DEFAULT_KELTNER_EMA_PERIOD,
73
+ DEFAULT_KELTNER_ATR_PERIOD,
74
+ DEFAULT_KELTNER_MULTIPLIER,
75
+ DEFAULT_DONCHIAN_PERIOD,
76
+ DEFAULT_ICHIMOKU_TENKAN,
77
+ DEFAULT_ICHIMOKU_KIJUN,
78
+ DEFAULT_ICHIMOKU_SPAN_B,
79
+ DEFAULT_ICHIMOKU_DISPLACEMENT,
80
+ DEFAULT_ROC_PERIOD,
81
+ DEFAULT_TRIX_PERIOD,
82
+ DEFAULT_TRIX_SIGNAL_PERIOD,
83
+ DEFAULT_HV_PERIOD,
84
+ DEFAULT_HV_ANNUALIZATION,
85
+ DEFAULT_PARKINSON_PERIOD,
86
+ DEFAULT_PARKINSON_ANNUALIZATION,
87
+ DEFAULT_CHAIKIN_VOL_EMA_PERIOD,
88
+ DEFAULT_CHAIKIN_VOL_ROC_PERIOD,
89
+ type MAFlags,
90
+ type BOLLPoint,
91
+ type EXPMAPoint,
92
+ type ENEPoint,
93
+ type STOCHPoint,
94
+ type KSTPoint,
95
+ type MACDPoint,
96
+ type SARPoint,
97
+ type SuperTrendPoint,
98
+ type KeltnerPoint,
99
+ type DonchianPoint,
100
+ type IchimokuPoint,
101
+ type PivotPoint,
102
+ type FibPoint,
103
+ type StructureSnapshot,
104
+ type Zone,
105
+ type VolumeProfileResult,
106
+ } from './calculators'
107
+ import type {
108
+ BOLLSchedulerConfig,
109
+ EXPMASchedulerConfig,
110
+ ENESchedulerConfig,
111
+ RSISchedulerConfig,
112
+ CCISchedulerConfig,
113
+ STOCHSchedulerConfig,
114
+ MOMSchedulerConfig,
115
+ WMSRSchedulerConfig,
116
+ KSTSchedulerConfig,
117
+ FASTKSchedulerConfig,
118
+ MACDSchedulerConfig,
119
+ ATRSchedulerConfig,
120
+ WMASchedulerConfig,
121
+ DEMASchedulerConfig,
122
+ TEMASchedulerConfig,
123
+ HMASchedulerConfig,
124
+ KAMASchedulerConfig,
125
+ SARSchedulerConfig,
126
+ SuperTrendSchedulerConfig,
127
+ KeltnerSchedulerConfig,
128
+ DonchianSchedulerConfig,
129
+ IchimokuSchedulerConfig,
130
+ ROCSchedulerConfig,
131
+ TRIXSchedulerConfig,
132
+ HVSchedulerConfig,
133
+ ParkinsonSchedulerConfig,
134
+ ChaikinVolSchedulerConfig,
135
+ VMASchedulerConfig,
136
+ OBVSchedulerConfig,
137
+ PVTSchedulerConfig,
138
+ VWAPSchedulerConfig,
139
+ CMFSchedulerConfig,
140
+ MFISchedulerConfig,
141
+ PivotSchedulerConfig,
142
+ FibSchedulerConfig,
143
+ StructureSchedulerConfig,
144
+ ZonesSchedulerConfig,
145
+ VolumeProfileSchedulerConfig,
146
+ IndicatorConfigSnapshot,
147
+ IndicatorSeriesBundle,
148
+ } from './workerProtocol'
149
+
150
+ /**
151
+ * 可见范围
152
+ */
153
+ interface VisibleRange {
154
+ start: number
155
+ end: number
156
+ }
157
+
158
+ /**
159
+ * 计算运行时
160
+ * 管理数据、配置、缓存和脏标记
161
+ */
162
+ export class IndicatorRuntime {
163
+ // 数据
164
+ private currentData: KLineData[] = []
165
+ private dataVersion = 0
166
+
167
+ // 配置
168
+ private config: IndicatorConfigSnapshot = this.getDefaultConfig()
169
+ private configVersion = 0
170
+
171
+ // 缓存的 series
172
+ private cachedSeries: Record<number, (number | undefined)[]> = {}
173
+ private cachedBollSeries: BOLLPoint[] = []
174
+ private cachedExpmaSeries: EXPMAPoint[] = []
175
+ private cachedEneSeries: ENEPoint[] = []
176
+ private cachedRsiSeries: Record<number, (number | undefined)[]> = {}
177
+ private cachedCciSeries: (number | undefined)[] = []
178
+ private cachedStochSeries: STOCHPoint[] = []
179
+ private cachedMomSeries: (number | undefined)[] = []
180
+ private cachedWmsrSeries: (number | undefined)[] = []
181
+ private cachedKstSeries: KSTPoint[] = []
182
+ private cachedFastkSeries: (number | undefined)[] = []
183
+ private cachedMacdSeries: MACDPoint[] = []
184
+ private cachedAtrSeries: (number | undefined)[] = []
185
+ private cachedWmaSeries: (number | undefined)[] = []
186
+ private cachedDemaSeries: (number | undefined)[] = []
187
+ private cachedTemaSeries: (number | undefined)[] = []
188
+ private cachedHmaSeries: (number | undefined)[] = []
189
+ private cachedKamaSeries: (number | undefined)[] = []
190
+ private cachedSarSeries: (SARPoint | undefined)[] = []
191
+ private cachedSupertrendSeries: (SuperTrendPoint | undefined)[] = []
192
+ private cachedKeltnerSeries: (KeltnerPoint | undefined)[] = []
193
+ private cachedDonchianSeries: (DonchianPoint | undefined)[] = []
194
+ private cachedIchimokuSeries: (IchimokuPoint | undefined)[] = []
195
+ private cachedRocSeries: (number | undefined)[] = []
196
+ private cachedTrixSeries: (number | undefined)[] = []
197
+ private cachedTrixSignalSeries: (number | undefined)[] = []
198
+ private cachedHvSeries: (number | undefined)[] = []
199
+ private cachedParkinsonSeries: (number | undefined)[] = []
200
+ private cachedChaikinVolSeries: (number | undefined)[] = []
201
+ private cachedVmaSeries: (number | undefined)[] = []
202
+ private cachedObvSeries: (number | undefined)[] = []
203
+ private cachedPvtSeries: (number | undefined)[] = []
204
+ private cachedVwapSeries: (number | undefined)[] = []
205
+ private cachedCmfSeries: (number | undefined)[] = []
206
+ private cachedMfiSeries: (number | undefined)[] = []
207
+ private cachedPivotSeries: (PivotPoint | undefined)[] = []
208
+ private cachedFibSeries: (FibPoint | undefined)[] = []
209
+ private cachedStructureSeries: StructureSnapshot = { swings: [], events: [], trend: 'range' }
210
+ private cachedZonesSeries: Zone[] = []
211
+ private cachedVolumeProfileSeries: VolumeProfileResult = { bins: [], poc: 0, vah: 0, val: 0, totalVolume: 0 }
212
+
213
+ // 脏标记
214
+ private dirtyData = true
215
+ private dirtyMAConfig = true
216
+ private dirtyBollConfig = true
217
+ private dirtyExpmaConfig = true
218
+ private dirtyEneConfig = true
219
+ private dirtyRsiConfig = true
220
+ private dirtyCciConfig = true
221
+ private dirtyStochConfig = true
222
+ private dirtyMomConfig = true
223
+ private dirtyWmsrConfig = true
224
+ private dirtyKstConfig = true
225
+ private dirtyFastkConfig = true
226
+ private dirtyMacdConfig = true
227
+ private dirtyAtrConfig = true
228
+ private dirtyWmaConfig = true
229
+ private dirtyDemaConfig = true
230
+ private dirtyTemaConfig = true
231
+ private dirtyHmaConfig = true
232
+ private dirtyKamaConfig = true
233
+ private dirtySarConfig = true
234
+ private dirtySupertrendConfig = true
235
+ private dirtyKeltnerConfig = true
236
+ private dirtyDonchianConfig = true
237
+ private dirtyIchimokuConfig = true
238
+ private dirtyRocConfig = true
239
+ private dirtyTrixConfig = true
240
+ private dirtyHvConfig = true
241
+ private dirtyParkinsonConfig = true
242
+ private dirtyChaikinVolConfig = true
243
+ private dirtyVmaConfig = true
244
+ private dirtyObvConfig = true
245
+ private dirtyPvtConfig = true
246
+ private dirtyVwapConfig = true
247
+ private dirtyCmfConfig = true
248
+ private dirtyMfiConfig = true
249
+ private dirtyPivotConfig = true
250
+ private dirtyFibConfig = true
251
+ private dirtyStructureConfig = true
252
+ private dirtyZonesConfig = true
253
+ private dirtyVolumeProfileConfig = true
254
+
255
+ private getDefaultConfig(): IndicatorConfigSnapshot {
256
+ return {
257
+ ma: { ma5: true, ma10: true, ma20: true, ma30: true, ma60: true },
258
+ boll: {
259
+ period: 20,
260
+ multiplier: 2,
261
+ showUpper: true,
262
+ showMiddle: true,
263
+ showLower: true,
264
+ showBand: true,
265
+ },
266
+ expma: { fastPeriod: 12, slowPeriod: 50 },
267
+ ene: { period: 10, deviation: 11 },
268
+ rsi: {
269
+ period1: 6,
270
+ period2: 12,
271
+ period3: 24,
272
+ showRSI1: true,
273
+ showRSI2: true,
274
+ showRSI3: true,
275
+ },
276
+ cci: { period: 14, showCCI: true },
277
+ stoch: { n: 9, m: 3, showK: true, showD: true },
278
+ mom: { period: 10, showMOM: true },
279
+ wmsr: { period: 14, showWMSR: true },
280
+ kst: {
281
+ roc1: 10,
282
+ roc2: 15,
283
+ roc3: 20,
284
+ roc4: 30,
285
+ signalPeriod: 9,
286
+ showKST: true,
287
+ showSignal: true,
288
+ },
289
+ fastk: { period: 9, showFASTK: true },
290
+ macd: {
291
+ fastPeriod: 12,
292
+ slowPeriod: 26,
293
+ signalPeriod: 9,
294
+ showDIF: true,
295
+ showDEA: true,
296
+ showBAR: true,
297
+ },
298
+ atr: { period: DEFAULT_ATR_PERIOD, showATR: true },
299
+ wma: { period: DEFAULT_WMA_PERIOD, showWMA: true },
300
+ dema: { period: DEFAULT_DEMA_PERIOD, showDEMA: true },
301
+ tema: { period: DEFAULT_TEMA_PERIOD, showTEMA: true },
302
+ hma: { period: DEFAULT_HMA_PERIOD, showHMA: true },
303
+ kama: {
304
+ period: DEFAULT_KAMA_PERIOD,
305
+ fastPeriod: DEFAULT_KAMA_FAST_PERIOD,
306
+ slowPeriod: DEFAULT_KAMA_SLOW_PERIOD,
307
+ showKAMA: true,
308
+ },
309
+ sar: { step: DEFAULT_SAR_STEP, maxStep: DEFAULT_SAR_MAX_STEP, showSAR: true },
310
+ supertrend: {
311
+ atrPeriod: DEFAULT_SUPERTREND_ATR_PERIOD,
312
+ multiplier: DEFAULT_SUPERTREND_MULTIPLIER,
313
+ showSuperTrend: true,
314
+ },
315
+ keltner: {
316
+ emaPeriod: DEFAULT_KELTNER_EMA_PERIOD,
317
+ atrPeriod: DEFAULT_KELTNER_ATR_PERIOD,
318
+ multiplier: DEFAULT_KELTNER_MULTIPLIER,
319
+ showUpper: true,
320
+ showMiddle: true,
321
+ showLower: true,
322
+ },
323
+ donchian: {
324
+ period: DEFAULT_DONCHIAN_PERIOD,
325
+ showUpper: true,
326
+ showMiddle: true,
327
+ showLower: true,
328
+ },
329
+ ichimoku: {
330
+ tenkanPeriod: DEFAULT_ICHIMOKU_TENKAN,
331
+ kijunPeriod: DEFAULT_ICHIMOKU_KIJUN,
332
+ spanBPeriod: DEFAULT_ICHIMOKU_SPAN_B,
333
+ displacement: DEFAULT_ICHIMOKU_DISPLACEMENT,
334
+ showTenkan: true,
335
+ showKijun: true,
336
+ showSpanA: true,
337
+ showSpanB: true,
338
+ showCloud: true,
339
+ showChikou: true,
340
+ },
341
+ roc: { period: DEFAULT_ROC_PERIOD, showROC: true },
342
+ trix: {
343
+ period: DEFAULT_TRIX_PERIOD,
344
+ signalPeriod: DEFAULT_TRIX_SIGNAL_PERIOD,
345
+ showTRIX: true,
346
+ showSignal: true,
347
+ },
348
+ hv: {
349
+ period: DEFAULT_HV_PERIOD,
350
+ annualizationFactor: DEFAULT_HV_ANNUALIZATION,
351
+ showHV: true,
352
+ },
353
+ parkinson: {
354
+ period: DEFAULT_PARKINSON_PERIOD,
355
+ annualizationFactor: DEFAULT_PARKINSON_ANNUALIZATION,
356
+ showParkinson: true,
357
+ },
358
+ chaikinVol: {
359
+ emaPeriod: DEFAULT_CHAIKIN_VOL_EMA_PERIOD,
360
+ rocPeriod: DEFAULT_CHAIKIN_VOL_ROC_PERIOD,
361
+ showChaikinVol: true,
362
+ },
363
+ vma: { period: DEFAULT_VMA_PERIOD, showVMA: true },
364
+ obv: { showOBV: true },
365
+ pvt: { showPVT: true },
366
+ vwap: { sessionResetGapMs: DEFAULT_VWAP_SESSION_GAP_MS, showVWAP: true },
367
+ cmf: { period: DEFAULT_CMF_PERIOD, showCMF: true },
368
+ mfi: { period: DEFAULT_MFI_PERIOD, showMFI: true },
369
+ pivot: { showPP: true, showR1: true, showR2: true, showR3: false, showS1: true, showS2: true, showS3: false },
370
+ fib: { period: DEFAULT_FIB_PERIOD, showLevels: true },
371
+ structure: {
372
+ leftWindow: DEFAULT_STRUCTURE_LEFT,
373
+ rightWindow: DEFAULT_STRUCTURE_RIGHT,
374
+ breakoutSource: 'close',
375
+ showSwingLabels: true,
376
+ showBOS: true,
377
+ showCHOCH: true,
378
+ showProvisional: false,
379
+ },
380
+ zones: {
381
+ showFVG: true,
382
+ showOB: true,
383
+ showFilledZones: false,
384
+ obLookback: DEFAULT_ZONES_OB_LOOKBACK,
385
+ },
386
+ volumeProfile: {
387
+ bins: DEFAULT_VP_BINS,
388
+ lookback: DEFAULT_VP_LOOKBACK,
389
+ valueAreaPercent: DEFAULT_VP_VALUE_AREA,
390
+ showPOC: true,
391
+ showValueArea: true,
392
+ },
393
+ rsiPaneId: 'sub_RSI',
394
+ cciPaneId: 'sub_CCI',
395
+ stochPaneId: 'sub_STOCH',
396
+ momPaneId: 'sub_MOM',
397
+ wmsrPaneId: 'sub_WMSR',
398
+ kstPaneId: 'sub_KST',
399
+ fastkPaneId: 'sub_FASTK',
400
+ macdPaneId: 'sub_MACD',
401
+ atrPaneId: 'sub_ATR',
402
+ wmaPaneId: 'sub_WMA',
403
+ demaPaneId: 'sub_DEMA',
404
+ temaPaneId: 'sub_TEMA',
405
+ hmaPaneId: 'sub_HMA',
406
+ kamaPaneId: 'sub_KAMA',
407
+ sarPaneId: 'sub_SAR',
408
+ supertrendPaneId: 'sub_SuperTrend',
409
+ keltnerPaneId: 'sub_Keltner',
410
+ donchianPaneId: 'sub_Donchian',
411
+ ichimokuPaneId: 'sub_Ichimoku',
412
+ rocPaneId: 'sub_ROC',
413
+ trixPaneId: 'sub_TRIX',
414
+ hvPaneId: 'sub_HV',
415
+ parkinsonPaneId: 'sub_Parkinson',
416
+ chaikinVolPaneId: 'sub_ChaikinVol',
417
+ vmaPaneId: 'sub_VMA',
418
+ obvPaneId: 'sub_OBV',
419
+ pvtPaneId: 'sub_PVT',
420
+ vwapPaneId: 'sub_VWAP',
421
+ cmfPaneId: 'sub_CMF',
422
+ mfiPaneId: 'sub_MFI',
423
+ pivotPaneId: 'sub_Pivot',
424
+ fibPaneId: 'sub_Fib',
425
+ structurePaneId: 'sub_Structure',
426
+ zonesPaneId: 'sub_Zones',
427
+ volumeProfilePaneId: 'sub_VolumeProfile',
428
+ }
429
+ }
430
+
431
+ /**
432
+ * 更新数据
433
+ */
434
+ setData(data: KLineData[], version: number): void {
435
+ if (this.dataVersion === version && !this.dirtyData) return
436
+ this.currentData = data
437
+ this.dataVersion = version
438
+ this.dirtyData = true
439
+ }
440
+
441
+ /**
442
+ * 更新配置
443
+ */
444
+ private shallowEqual(a: Record<string, unknown>, b: Record<string, unknown>): boolean {
445
+ const keysA = Object.keys(a)
446
+ const keysB = Object.keys(b)
447
+ if (keysA.length !== keysB.length) return false
448
+ for (const key of keysA) {
449
+ if (a[key] !== b[key]) return false
450
+ }
451
+ return true
452
+ }
453
+
454
+ /**
455
+ * 更新配置(仅值变更时才设置脏标记)
456
+ */
457
+ setConfig(config: Partial<IndicatorConfigSnapshot>, version: number): void {
458
+ // 合并配置(仅值变更时才标记脏)
459
+ if (config.ma !== undefined && !this.shallowEqual(config.ma as unknown as Record<string, unknown>, this.config.ma as unknown as Record<string, unknown>)) {
460
+ this.config.ma = { ...this.config.ma, ...config.ma }
461
+ this.dirtyMAConfig = true
462
+ }
463
+ if (config.boll !== undefined && !this.shallowEqual(config.boll as unknown as Record<string, unknown>, this.config.boll as unknown as Record<string, unknown>)) {
464
+ this.config.boll = { ...this.config.boll, ...config.boll }
465
+ this.dirtyBollConfig = true
466
+ }
467
+ if (config.expma !== undefined && !this.shallowEqual(config.expma as unknown as Record<string, unknown>, this.config.expma as unknown as Record<string, unknown>)) {
468
+ this.config.expma = { ...this.config.expma, ...config.expma }
469
+ this.dirtyExpmaConfig = true
470
+ }
471
+ if (config.ene !== undefined && !this.shallowEqual(config.ene as unknown as Record<string, unknown>, this.config.ene as unknown as Record<string, unknown>)) {
472
+ this.config.ene = { ...this.config.ene, ...config.ene }
473
+ this.dirtyEneConfig = true
474
+ }
475
+ if (config.rsi !== undefined && !this.shallowEqual(config.rsi as unknown as Record<string, unknown>, this.config.rsi as unknown as Record<string, unknown>)) {
476
+ this.config.rsi = { ...this.config.rsi, ...config.rsi }
477
+ this.dirtyRsiConfig = true
478
+ }
479
+ if (config.cci !== undefined && !this.shallowEqual(config.cci as unknown as Record<string, unknown>, this.config.cci as unknown as Record<string, unknown>)) {
480
+ this.config.cci = { ...this.config.cci, ...config.cci }
481
+ this.dirtyCciConfig = true
482
+ }
483
+ if (config.stoch !== undefined && !this.shallowEqual(config.stoch as unknown as Record<string, unknown>, this.config.stoch as unknown as Record<string, unknown>)) {
484
+ this.config.stoch = { ...this.config.stoch, ...config.stoch }
485
+ this.dirtyStochConfig = true
486
+ }
487
+ if (config.mom !== undefined && !this.shallowEqual(config.mom as unknown as Record<string, unknown>, this.config.mom as unknown as Record<string, unknown>)) {
488
+ this.config.mom = { ...this.config.mom, ...config.mom }
489
+ this.dirtyMomConfig = true
490
+ }
491
+ if (config.wmsr !== undefined && !this.shallowEqual(config.wmsr as unknown as Record<string, unknown>, this.config.wmsr as unknown as Record<string, unknown>)) {
492
+ this.config.wmsr = { ...this.config.wmsr, ...config.wmsr }
493
+ this.dirtyWmsrConfig = true
494
+ }
495
+ if (config.kst !== undefined && !this.shallowEqual(config.kst as unknown as Record<string, unknown>, this.config.kst as unknown as Record<string, unknown>)) {
496
+ this.config.kst = { ...this.config.kst, ...config.kst }
497
+ this.dirtyKstConfig = true
498
+ }
499
+ if (config.fastk !== undefined && !this.shallowEqual(config.fastk as unknown as Record<string, unknown>, this.config.fastk as unknown as Record<string, unknown>)) {
500
+ this.config.fastk = { ...this.config.fastk, ...config.fastk }
501
+ this.dirtyFastkConfig = true
502
+ }
503
+ if (config.macd !== undefined && !this.shallowEqual(config.macd as unknown as Record<string, unknown>, this.config.macd as unknown as Record<string, unknown>)) {
504
+ this.config.macd = { ...this.config.macd, ...config.macd }
505
+ this.dirtyMacdConfig = true
506
+ }
507
+ if (config.atr !== undefined && !this.shallowEqual(config.atr as unknown as Record<string, unknown>, this.config.atr as unknown as Record<string, unknown>)) {
508
+ this.config.atr = { ...this.config.atr, ...config.atr }
509
+ this.dirtyAtrConfig = true
510
+ }
511
+ if (config.wma !== undefined && !this.shallowEqual(config.wma as unknown as Record<string, unknown>, this.config.wma as unknown as Record<string, unknown>)) {
512
+ this.config.wma = { ...this.config.wma, ...config.wma }
513
+ this.dirtyWmaConfig = true
514
+ }
515
+ if (config.dema !== undefined && !this.shallowEqual(config.dema as unknown as Record<string, unknown>, this.config.dema as unknown as Record<string, unknown>)) {
516
+ this.config.dema = { ...this.config.dema, ...config.dema }
517
+ this.dirtyDemaConfig = true
518
+ }
519
+ if (config.tema !== undefined && !this.shallowEqual(config.tema as unknown as Record<string, unknown>, this.config.tema as unknown as Record<string, unknown>)) {
520
+ this.config.tema = { ...this.config.tema, ...config.tema }
521
+ this.dirtyTemaConfig = true
522
+ }
523
+ if (config.hma !== undefined && !this.shallowEqual(config.hma as unknown as Record<string, unknown>, this.config.hma as unknown as Record<string, unknown>)) {
524
+ this.config.hma = { ...this.config.hma, ...config.hma }
525
+ this.dirtyHmaConfig = true
526
+ }
527
+ if (config.kama !== undefined && !this.shallowEqual(config.kama as unknown as Record<string, unknown>, this.config.kama as unknown as Record<string, unknown>)) {
528
+ this.config.kama = { ...this.config.kama, ...config.kama }
529
+ this.dirtyKamaConfig = true
530
+ }
531
+ if (config.sar !== undefined && !this.shallowEqual(config.sar as unknown as Record<string, unknown>, this.config.sar as unknown as Record<string, unknown>)) {
532
+ this.config.sar = { ...this.config.sar, ...config.sar }
533
+ this.dirtySarConfig = true
534
+ }
535
+ if (config.supertrend !== undefined && !this.shallowEqual(config.supertrend as unknown as Record<string, unknown>, this.config.supertrend as unknown as Record<string, unknown>)) {
536
+ this.config.supertrend = { ...this.config.supertrend, ...config.supertrend }
537
+ this.dirtySupertrendConfig = true
538
+ }
539
+ if (config.keltner !== undefined && !this.shallowEqual(config.keltner as unknown as Record<string, unknown>, this.config.keltner as unknown as Record<string, unknown>)) {
540
+ this.config.keltner = { ...this.config.keltner, ...config.keltner }
541
+ this.dirtyKeltnerConfig = true
542
+ }
543
+ if (config.donchian !== undefined && !this.shallowEqual(config.donchian as unknown as Record<string, unknown>, this.config.donchian as unknown as Record<string, unknown>)) {
544
+ this.config.donchian = { ...this.config.donchian, ...config.donchian }
545
+ this.dirtyDonchianConfig = true
546
+ }
547
+ if (config.ichimoku !== undefined && !this.shallowEqual(config.ichimoku as unknown as Record<string, unknown>, this.config.ichimoku as unknown as Record<string, unknown>)) {
548
+ this.config.ichimoku = { ...this.config.ichimoku, ...config.ichimoku }
549
+ this.dirtyIchimokuConfig = true
550
+ }
551
+ if (config.roc !== undefined && !this.shallowEqual(config.roc as unknown as Record<string, unknown>, this.config.roc as unknown as Record<string, unknown>)) {
552
+ this.config.roc = { ...this.config.roc, ...config.roc }
553
+ this.dirtyRocConfig = true
554
+ }
555
+ if (config.trix !== undefined && !this.shallowEqual(config.trix as unknown as Record<string, unknown>, this.config.trix as unknown as Record<string, unknown>)) {
556
+ this.config.trix = { ...this.config.trix, ...config.trix }
557
+ this.dirtyTrixConfig = true
558
+ }
559
+ if (config.hv !== undefined && !this.shallowEqual(config.hv as unknown as Record<string, unknown>, this.config.hv as unknown as Record<string, unknown>)) {
560
+ this.config.hv = { ...this.config.hv, ...config.hv }
561
+ this.dirtyHvConfig = true
562
+ }
563
+ if (config.parkinson !== undefined && !this.shallowEqual(config.parkinson as unknown as Record<string, unknown>, this.config.parkinson as unknown as Record<string, unknown>)) {
564
+ this.config.parkinson = { ...this.config.parkinson, ...config.parkinson }
565
+ this.dirtyParkinsonConfig = true
566
+ }
567
+ if (config.chaikinVol !== undefined && !this.shallowEqual(config.chaikinVol as unknown as Record<string, unknown>, this.config.chaikinVol as unknown as Record<string, unknown>)) {
568
+ this.config.chaikinVol = { ...this.config.chaikinVol, ...config.chaikinVol }
569
+ this.dirtyChaikinVolConfig = true
570
+ }
571
+ if (config.vma !== undefined && !this.shallowEqual(config.vma as unknown as Record<string, unknown>, this.config.vma as unknown as Record<string, unknown>)) {
572
+ this.config.vma = { ...this.config.vma, ...config.vma }
573
+ this.dirtyVmaConfig = true
574
+ }
575
+ if (config.obv !== undefined && !this.shallowEqual(config.obv as unknown as Record<string, unknown>, this.config.obv as unknown as Record<string, unknown>)) {
576
+ this.config.obv = { ...this.config.obv, ...config.obv }
577
+ this.dirtyObvConfig = true
578
+ }
579
+ if (config.pvt !== undefined && !this.shallowEqual(config.pvt as unknown as Record<string, unknown>, this.config.pvt as unknown as Record<string, unknown>)) {
580
+ this.config.pvt = { ...this.config.pvt, ...config.pvt }
581
+ this.dirtyPvtConfig = true
582
+ }
583
+ if (config.vwap !== undefined && !this.shallowEqual(config.vwap as unknown as Record<string, unknown>, this.config.vwap as unknown as Record<string, unknown>)) {
584
+ this.config.vwap = { ...this.config.vwap, ...config.vwap }
585
+ this.dirtyVwapConfig = true
586
+ }
587
+ if (config.cmf !== undefined && !this.shallowEqual(config.cmf as unknown as Record<string, unknown>, this.config.cmf as unknown as Record<string, unknown>)) {
588
+ this.config.cmf = { ...this.config.cmf, ...config.cmf }
589
+ this.dirtyCmfConfig = true
590
+ }
591
+ if (config.mfi !== undefined && !this.shallowEqual(config.mfi as unknown as Record<string, unknown>, this.config.mfi as unknown as Record<string, unknown>)) {
592
+ this.config.mfi = { ...this.config.mfi, ...config.mfi }
593
+ this.dirtyMfiConfig = true
594
+ }
595
+ if (config.pivot !== undefined && !this.shallowEqual(config.pivot as unknown as Record<string, unknown>, this.config.pivot as unknown as Record<string, unknown>)) {
596
+ this.config.pivot = { ...this.config.pivot, ...config.pivot }
597
+ this.dirtyPivotConfig = true
598
+ }
599
+ if (config.fib !== undefined && !this.shallowEqual(config.fib as unknown as Record<string, unknown>, this.config.fib as unknown as Record<string, unknown>)) {
600
+ this.config.fib = { ...this.config.fib, ...config.fib }
601
+ this.dirtyFibConfig = true
602
+ }
603
+ if (config.structure !== undefined && !this.shallowEqual(config.structure as unknown as Record<string, unknown>, this.config.structure as unknown as Record<string, unknown>)) {
604
+ this.config.structure = { ...this.config.structure, ...config.structure }
605
+ this.dirtyStructureConfig = true
606
+ }
607
+ if (config.zones !== undefined && !this.shallowEqual(config.zones as unknown as Record<string, unknown>, this.config.zones as unknown as Record<string, unknown>)) {
608
+ this.config.zones = { ...this.config.zones, ...config.zones }
609
+ this.dirtyZonesConfig = true
610
+ }
611
+ if (config.volumeProfile !== undefined && !this.shallowEqual(config.volumeProfile as unknown as Record<string, unknown>, this.config.volumeProfile as unknown as Record<string, unknown>)) {
612
+ this.config.volumeProfile = { ...this.config.volumeProfile, ...config.volumeProfile }
613
+ this.dirtyVolumeProfileConfig = true
614
+ }
615
+ // pane IDs
616
+ if (config.rsiPaneId !== undefined) this.config.rsiPaneId = config.rsiPaneId
617
+ if (config.cciPaneId !== undefined) this.config.cciPaneId = config.cciPaneId
618
+ if (config.stochPaneId !== undefined) this.config.stochPaneId = config.stochPaneId
619
+ if (config.momPaneId !== undefined) this.config.momPaneId = config.momPaneId
620
+ if (config.wmsrPaneId !== undefined) this.config.wmsrPaneId = config.wmsrPaneId
621
+ if (config.kstPaneId !== undefined) this.config.kstPaneId = config.kstPaneId
622
+ if (config.fastkPaneId !== undefined) this.config.fastkPaneId = config.fastkPaneId
623
+ if (config.macdPaneId !== undefined) this.config.macdPaneId = config.macdPaneId
624
+ if (config.atrPaneId !== undefined) this.config.atrPaneId = config.atrPaneId
625
+ if (config.wmaPaneId !== undefined) this.config.wmaPaneId = config.wmaPaneId
626
+ if (config.demaPaneId !== undefined) this.config.demaPaneId = config.demaPaneId
627
+ if (config.temaPaneId !== undefined) this.config.temaPaneId = config.temaPaneId
628
+ if (config.hmaPaneId !== undefined) this.config.hmaPaneId = config.hmaPaneId
629
+ if (config.kamaPaneId !== undefined) this.config.kamaPaneId = config.kamaPaneId
630
+ if (config.sarPaneId !== undefined) this.config.sarPaneId = config.sarPaneId
631
+ if (config.supertrendPaneId !== undefined) this.config.supertrendPaneId = config.supertrendPaneId
632
+ if (config.keltnerPaneId !== undefined) this.config.keltnerPaneId = config.keltnerPaneId
633
+ if (config.donchianPaneId !== undefined) this.config.donchianPaneId = config.donchianPaneId
634
+ if (config.ichimokuPaneId !== undefined) this.config.ichimokuPaneId = config.ichimokuPaneId
635
+ if (config.rocPaneId !== undefined) this.config.rocPaneId = config.rocPaneId
636
+ if (config.trixPaneId !== undefined) this.config.trixPaneId = config.trixPaneId
637
+ if (config.hvPaneId !== undefined) this.config.hvPaneId = config.hvPaneId
638
+ if (config.parkinsonPaneId !== undefined) this.config.parkinsonPaneId = config.parkinsonPaneId
639
+ if (config.chaikinVolPaneId !== undefined) this.config.chaikinVolPaneId = config.chaikinVolPaneId
640
+ if (config.vmaPaneId !== undefined) this.config.vmaPaneId = config.vmaPaneId
641
+ if (config.obvPaneId !== undefined) this.config.obvPaneId = config.obvPaneId
642
+ if (config.pvtPaneId !== undefined) this.config.pvtPaneId = config.pvtPaneId
643
+ if (config.vwapPaneId !== undefined) this.config.vwapPaneId = config.vwapPaneId
644
+ if (config.cmfPaneId !== undefined) this.config.cmfPaneId = config.cmfPaneId
645
+ if (config.mfiPaneId !== undefined) this.config.mfiPaneId = config.mfiPaneId
646
+ if (config.pivotPaneId !== undefined) this.config.pivotPaneId = config.pivotPaneId
647
+ if (config.fibPaneId !== undefined) this.config.fibPaneId = config.fibPaneId
648
+ if (config.structurePaneId !== undefined) this.config.structurePaneId = config.structurePaneId
649
+ if (config.zonesPaneId !== undefined) this.config.zonesPaneId = config.zonesPaneId
650
+ if (config.volumeProfilePaneId !== undefined) this.config.volumeProfilePaneId = config.volumeProfilePaneId
651
+
652
+ this.configVersion = version
653
+ }
654
+
655
+ /**
656
+ * 强制所有指标标记为脏(用于 recompute)
657
+ */
658
+ forceDirty(): void {
659
+ this.dirtyData = true
660
+ this.dirtyMAConfig = true
661
+ this.dirtyBollConfig = true
662
+ this.dirtyExpmaConfig = true
663
+ this.dirtyEneConfig = true
664
+ this.dirtyRsiConfig = true
665
+ this.dirtyCciConfig = true
666
+ this.dirtyStochConfig = true
667
+ this.dirtyMomConfig = true
668
+ this.dirtyWmsrConfig = true
669
+ this.dirtyKstConfig = true
670
+ this.dirtyFastkConfig = true
671
+ this.dirtyMacdConfig = true
672
+ this.dirtyAtrConfig = true
673
+ this.dirtyWmaConfig = true
674
+ this.dirtyDemaConfig = true
675
+ this.dirtyTemaConfig = true
676
+ this.dirtyHmaConfig = true
677
+ this.dirtyKamaConfig = true
678
+ this.dirtySarConfig = true
679
+ this.dirtySupertrendConfig = true
680
+ this.dirtyKeltnerConfig = true
681
+ this.dirtyDonchianConfig = true
682
+ this.dirtyIchimokuConfig = true
683
+ this.dirtyRocConfig = true
684
+ this.dirtyTrixConfig = true
685
+ this.dirtyHvConfig = true
686
+ this.dirtyParkinsonConfig = true
687
+ this.dirtyChaikinVolConfig = true
688
+ this.dirtyVmaConfig = true
689
+ this.dirtyObvConfig = true
690
+ this.dirtyPvtConfig = true
691
+ this.dirtyVwapConfig = true
692
+ this.dirtyCmfConfig = true
693
+ this.dirtyMfiConfig = true
694
+ this.dirtyPivotConfig = true
695
+ this.dirtyFibConfig = true
696
+ this.dirtyStructureConfig = true
697
+ this.dirtyZonesConfig = true
698
+ this.dirtyVolumeProfileConfig = true
699
+ }
700
+
701
+ /**
702
+ * 获取当前数据版本
703
+ */
704
+ getDataVersion(): number {
705
+ return this.dataVersion
706
+ }
707
+
708
+ /**
709
+ * 获取当前配置版本
710
+ */
711
+ getConfigVersion(): number {
712
+ return this.configVersion
713
+ }
714
+
715
+ /**
716
+ * 计算所有指标的 series(如果脏了)
717
+ * 返回结果包,供主线程组装成 render states
718
+ */
719
+ computeSeries(): IndicatorSeriesBundle {
720
+ const data = this.currentData
721
+ const changed: string[] = []
722
+
723
+ // MA
724
+ if (this.dirtyData || this.dirtyMAConfig) {
725
+ this.cachedSeries = {}
726
+ for (const period of DEFAULT_MA_PERIODS) {
727
+ const flagKey = `ma${period}` as keyof MAFlags
728
+ if (this.config.ma[flagKey]) {
729
+ this.cachedSeries[period] = calcMAData(data, period)
730
+ }
731
+ }
732
+ changed.push('ma')
733
+ }
734
+
735
+ // BOLL
736
+ if (this.dirtyData || this.dirtyBollConfig) {
737
+ this.cachedBollSeries = calcBOLLData(
738
+ data,
739
+ this.config.boll.period,
740
+ this.config.boll.multiplier
741
+ )
742
+ changed.push('boll')
743
+ }
744
+
745
+ // EXPMA
746
+ if (this.dirtyData || this.dirtyExpmaConfig) {
747
+ this.cachedExpmaSeries = calcEXPMAData(
748
+ data,
749
+ this.config.expma.fastPeriod,
750
+ this.config.expma.slowPeriod
751
+ )
752
+ changed.push('expma')
753
+ }
754
+
755
+ // ENE
756
+ if (this.dirtyData || this.dirtyEneConfig) {
757
+ this.cachedEneSeries = calcENEData(
758
+ data,
759
+ this.config.ene.period,
760
+ this.config.ene.deviation
761
+ )
762
+ changed.push('ene')
763
+ }
764
+
765
+ // RSI
766
+ if (this.dirtyData || this.dirtyRsiConfig) {
767
+ this.cachedRsiSeries = {}
768
+ const periods = [this.config.rsi.period1, this.config.rsi.period2, this.config.rsi.period3]
769
+ const shows = [this.config.rsi.showRSI1, this.config.rsi.showRSI2, this.config.rsi.showRSI3]
770
+ for (let i = 0; i < periods.length; i++) {
771
+ if (shows[i]) {
772
+ this.cachedRsiSeries[periods[i]] = calcRSIData(data, periods[i])
773
+ }
774
+ }
775
+ changed.push('rsi')
776
+ }
777
+
778
+ // CCI
779
+ if (this.dirtyData || this.dirtyCciConfig) {
780
+ if (this.config.cci.showCCI) {
781
+ this.cachedCciSeries = calcCCIData(data, this.config.cci.period)
782
+ } else {
783
+ this.cachedCciSeries = []
784
+ }
785
+ changed.push('cci')
786
+ }
787
+
788
+ // STOCH
789
+ if (this.dirtyData || this.dirtyStochConfig) {
790
+ if (this.config.stoch.showK || this.config.stoch.showD) {
791
+ this.cachedStochSeries = calcSTOCHData(data, this.config.stoch.n, this.config.stoch.m)
792
+ } else {
793
+ this.cachedStochSeries = []
794
+ }
795
+ changed.push('stoch')
796
+ }
797
+
798
+ // MOM
799
+ if (this.dirtyData || this.dirtyMomConfig) {
800
+ if (this.config.mom.showMOM) {
801
+ this.cachedMomSeries = calcMOMData(data, this.config.mom.period)
802
+ } else {
803
+ this.cachedMomSeries = []
804
+ }
805
+ changed.push('mom')
806
+ }
807
+
808
+ // WMSR
809
+ if (this.dirtyData || this.dirtyWmsrConfig) {
810
+ if (this.config.wmsr.showWMSR) {
811
+ this.cachedWmsrSeries = calcWMSRData(data, this.config.wmsr.period)
812
+ } else {
813
+ this.cachedWmsrSeries = []
814
+ }
815
+ changed.push('wmsr')
816
+ }
817
+
818
+ // KST
819
+ if (this.dirtyData || this.dirtyKstConfig) {
820
+ if (this.config.kst.showKST || this.config.kst.showSignal) {
821
+ this.cachedKstSeries = calcKSTData(
822
+ data,
823
+ this.config.kst.roc1,
824
+ this.config.kst.roc2,
825
+ this.config.kst.roc3,
826
+ this.config.kst.roc4,
827
+ this.config.kst.signalPeriod
828
+ )
829
+ } else {
830
+ this.cachedKstSeries = []
831
+ }
832
+ changed.push('kst')
833
+ }
834
+
835
+ // FASTK
836
+ if (this.dirtyData || this.dirtyFastkConfig) {
837
+ if (this.config.fastk.showFASTK) {
838
+ this.cachedFastkSeries = calcFASTKData(data, this.config.fastk.period)
839
+ } else {
840
+ this.cachedFastkSeries = []
841
+ }
842
+ changed.push('fastk')
843
+ }
844
+
845
+ // MACD
846
+ if (this.dirtyData || this.dirtyMacdConfig) {
847
+ if (this.config.macd.showDIF || this.config.macd.showDEA || this.config.macd.showBAR) {
848
+ this.cachedMacdSeries = calcMACDData(
849
+ data,
850
+ this.config.macd.fastPeriod,
851
+ this.config.macd.slowPeriod,
852
+ this.config.macd.signalPeriod
853
+ )
854
+ } else {
855
+ this.cachedMacdSeries = []
856
+ }
857
+ changed.push('macd')
858
+ }
859
+
860
+ // ATR
861
+ if (this.dirtyData || this.dirtyAtrConfig) {
862
+ if (this.config.atr.showATR) {
863
+ this.cachedAtrSeries = calcATRData(data, this.config.atr.period)
864
+ } else {
865
+ this.cachedAtrSeries = []
866
+ }
867
+ changed.push('atr')
868
+ }
869
+
870
+ // WMA
871
+ if (this.dirtyData || this.dirtyWmaConfig) {
872
+ if (this.config.wma.showWMA) {
873
+ this.cachedWmaSeries = calcWMAData(data, this.config.wma.period)
874
+ } else {
875
+ this.cachedWmaSeries = []
876
+ }
877
+ changed.push('wma')
878
+ }
879
+
880
+ // DEMA
881
+ if (this.dirtyData || this.dirtyDemaConfig) {
882
+ if (this.config.dema.showDEMA) {
883
+ this.cachedDemaSeries = calcDEMAData(data, this.config.dema.period)
884
+ } else {
885
+ this.cachedDemaSeries = []
886
+ }
887
+ changed.push('dema')
888
+ }
889
+
890
+ // TEMA
891
+ if (this.dirtyData || this.dirtyTemaConfig) {
892
+ if (this.config.tema.showTEMA) {
893
+ this.cachedTemaSeries = calcTEMAData(data, this.config.tema.period)
894
+ } else {
895
+ this.cachedTemaSeries = []
896
+ }
897
+ changed.push('tema')
898
+ }
899
+
900
+ // HMA
901
+ if (this.dirtyData || this.dirtyHmaConfig) {
902
+ if (this.config.hma.showHMA) {
903
+ this.cachedHmaSeries = calcHMAData(data, this.config.hma.period)
904
+ } else {
905
+ this.cachedHmaSeries = []
906
+ }
907
+ changed.push('hma')
908
+ }
909
+
910
+ // KAMA
911
+ if (this.dirtyData || this.dirtyKamaConfig) {
912
+ if (this.config.kama.showKAMA) {
913
+ this.cachedKamaSeries = calcKAMAData(
914
+ data,
915
+ this.config.kama.period,
916
+ this.config.kama.fastPeriod,
917
+ this.config.kama.slowPeriod,
918
+ )
919
+ } else {
920
+ this.cachedKamaSeries = []
921
+ }
922
+ changed.push('kama')
923
+ }
924
+
925
+ // SAR
926
+ if (this.dirtyData || this.dirtySarConfig) {
927
+ if (this.config.sar.showSAR) {
928
+ this.cachedSarSeries = calcSARData(
929
+ data,
930
+ this.config.sar.step,
931
+ this.config.sar.maxStep,
932
+ )
933
+ } else {
934
+ this.cachedSarSeries = []
935
+ }
936
+ changed.push('sar')
937
+ }
938
+
939
+ // SuperTrend
940
+ if (this.dirtyData || this.dirtySupertrendConfig) {
941
+ if (this.config.supertrend.showSuperTrend) {
942
+ this.cachedSupertrendSeries = calcSuperTrendData(
943
+ data,
944
+ this.config.supertrend.atrPeriod,
945
+ this.config.supertrend.multiplier,
946
+ )
947
+ } else {
948
+ this.cachedSupertrendSeries = []
949
+ }
950
+ changed.push('supertrend')
951
+ }
952
+
953
+ // Keltner
954
+ if (this.dirtyData || this.dirtyKeltnerConfig) {
955
+ if (this.config.keltner.showUpper || this.config.keltner.showMiddle || this.config.keltner.showLower) {
956
+ this.cachedKeltnerSeries = calcKeltnerData(
957
+ data,
958
+ this.config.keltner.emaPeriod,
959
+ this.config.keltner.atrPeriod,
960
+ this.config.keltner.multiplier,
961
+ )
962
+ } else {
963
+ this.cachedKeltnerSeries = []
964
+ }
965
+ changed.push('keltner')
966
+ }
967
+
968
+ // Donchian
969
+ if (this.dirtyData || this.dirtyDonchianConfig) {
970
+ if (this.config.donchian.showUpper || this.config.donchian.showMiddle || this.config.donchian.showLower) {
971
+ this.cachedDonchianSeries = calcDonchianData(data, this.config.donchian.period)
972
+ } else {
973
+ this.cachedDonchianSeries = []
974
+ }
975
+ changed.push('donchian')
976
+ }
977
+
978
+ // Ichimoku
979
+ if (this.dirtyData || this.dirtyIchimokuConfig) {
980
+ const ic = this.config.ichimoku
981
+ if (ic.showTenkan || ic.showKijun || ic.showSpanA || ic.showSpanB || ic.showCloud || ic.showChikou) {
982
+ this.cachedIchimokuSeries = calcIchimokuData(
983
+ data,
984
+ ic.tenkanPeriod,
985
+ ic.kijunPeriod,
986
+ ic.spanBPeriod,
987
+ ic.displacement,
988
+ )
989
+ } else {
990
+ this.cachedIchimokuSeries = []
991
+ }
992
+ changed.push('ichimoku')
993
+ }
994
+
995
+ // ROC
996
+ if (this.dirtyData || this.dirtyRocConfig) {
997
+ if (this.config.roc.showROC) {
998
+ this.cachedRocSeries = calcROCData(data, this.config.roc.period)
999
+ } else {
1000
+ this.cachedRocSeries = []
1001
+ }
1002
+ changed.push('roc')
1003
+ }
1004
+
1005
+ // TRIX
1006
+ if (this.dirtyData || this.dirtyTrixConfig) {
1007
+ if (this.config.trix.showTRIX || this.config.trix.showSignal) {
1008
+ const result = calcTRIXData(data, this.config.trix.period, this.config.trix.signalPeriod)
1009
+ this.cachedTrixSeries = result.series
1010
+ this.cachedTrixSignalSeries = result.signalSeries
1011
+ } else {
1012
+ this.cachedTrixSeries = []
1013
+ this.cachedTrixSignalSeries = []
1014
+ }
1015
+ changed.push('trix')
1016
+ }
1017
+
1018
+ // HV
1019
+ if (this.dirtyData || this.dirtyHvConfig) {
1020
+ if (this.config.hv.showHV) {
1021
+ this.cachedHvSeries = calcHVData(data, this.config.hv.period, this.config.hv.annualizationFactor)
1022
+ } else {
1023
+ this.cachedHvSeries = []
1024
+ }
1025
+ changed.push('hv')
1026
+ }
1027
+
1028
+ // Parkinson
1029
+ if (this.dirtyData || this.dirtyParkinsonConfig) {
1030
+ if (this.config.parkinson.showParkinson) {
1031
+ this.cachedParkinsonSeries = calcParkinsonData(
1032
+ data,
1033
+ this.config.parkinson.period,
1034
+ this.config.parkinson.annualizationFactor,
1035
+ )
1036
+ } else {
1037
+ this.cachedParkinsonSeries = []
1038
+ }
1039
+ changed.push('parkinson')
1040
+ }
1041
+
1042
+ // Chaikin Volatility
1043
+ if (this.dirtyData || this.dirtyChaikinVolConfig) {
1044
+ if (this.config.chaikinVol.showChaikinVol) {
1045
+ this.cachedChaikinVolSeries = calcChaikinVolData(
1046
+ data,
1047
+ this.config.chaikinVol.emaPeriod,
1048
+ this.config.chaikinVol.rocPeriod,
1049
+ )
1050
+ } else {
1051
+ this.cachedChaikinVolSeries = []
1052
+ }
1053
+ changed.push('chaikinVol')
1054
+ }
1055
+
1056
+ // VMA
1057
+ if (this.dirtyData || this.dirtyVmaConfig) {
1058
+ if (this.config.vma.showVMA) {
1059
+ this.cachedVmaSeries = calcVMAData(data, this.config.vma.period)
1060
+ } else {
1061
+ this.cachedVmaSeries = []
1062
+ }
1063
+ changed.push('vma')
1064
+ }
1065
+
1066
+ // OBV
1067
+ if (this.dirtyData || this.dirtyObvConfig) {
1068
+ if (this.config.obv.showOBV) {
1069
+ this.cachedObvSeries = calcOBVData(data)
1070
+ } else {
1071
+ this.cachedObvSeries = []
1072
+ }
1073
+ changed.push('obv')
1074
+ }
1075
+
1076
+ // PVT
1077
+ if (this.dirtyData || this.dirtyPvtConfig) {
1078
+ if (this.config.pvt.showPVT) {
1079
+ this.cachedPvtSeries = calcPVTData(data)
1080
+ } else {
1081
+ this.cachedPvtSeries = []
1082
+ }
1083
+ changed.push('pvt')
1084
+ }
1085
+
1086
+ // VWAP
1087
+ if (this.dirtyData || this.dirtyVwapConfig) {
1088
+ if (this.config.vwap.showVWAP) {
1089
+ this.cachedVwapSeries = calcVWAPData(data, this.config.vwap.sessionResetGapMs)
1090
+ } else {
1091
+ this.cachedVwapSeries = []
1092
+ }
1093
+ changed.push('vwap')
1094
+ }
1095
+
1096
+ // CMF
1097
+ if (this.dirtyData || this.dirtyCmfConfig) {
1098
+ if (this.config.cmf.showCMF) {
1099
+ this.cachedCmfSeries = calcCMFData(data, this.config.cmf.period)
1100
+ } else {
1101
+ this.cachedCmfSeries = []
1102
+ }
1103
+ changed.push('cmf')
1104
+ }
1105
+
1106
+ // MFI
1107
+ if (this.dirtyData || this.dirtyMfiConfig) {
1108
+ if (this.config.mfi.showMFI) {
1109
+ this.cachedMfiSeries = calcMFIData(data, this.config.mfi.period)
1110
+ } else {
1111
+ this.cachedMfiSeries = []
1112
+ }
1113
+ changed.push('mfi')
1114
+ }
1115
+
1116
+ // Pivot
1117
+ if (this.dirtyData || this.dirtyPivotConfig) {
1118
+ const p = this.config.pivot
1119
+ if (p.showPP || p.showR1 || p.showR2 || p.showR3 || p.showS1 || p.showS2 || p.showS3) {
1120
+ this.cachedPivotSeries = calcPivotData(data)
1121
+ } else {
1122
+ this.cachedPivotSeries = []
1123
+ }
1124
+ changed.push('pivot')
1125
+ }
1126
+
1127
+ // Fibonacci
1128
+ if (this.dirtyData || this.dirtyFibConfig) {
1129
+ if (this.config.fib.showLevels) {
1130
+ this.cachedFibSeries = calcFibData(data, this.config.fib.period)
1131
+ } else {
1132
+ this.cachedFibSeries = []
1133
+ }
1134
+ changed.push('fib')
1135
+ }
1136
+
1137
+ // SMC Structure
1138
+ if (this.dirtyData || this.dirtyStructureConfig) {
1139
+ const s = this.config.structure
1140
+ if (s.showSwingLabels || s.showBOS || s.showCHOCH) {
1141
+ this.cachedStructureSeries = calcStructureData(data, s.leftWindow, s.rightWindow, s.breakoutSource)
1142
+ } else {
1143
+ this.cachedStructureSeries = { swings: [], events: [], trend: 'range' }
1144
+ }
1145
+ changed.push('structure')
1146
+ }
1147
+
1148
+ // SMC Zones
1149
+ if (this.dirtyData || this.dirtyZonesConfig) {
1150
+ const z = this.config.zones
1151
+ if (z.showFVG || z.showOB) {
1152
+ this.cachedZonesSeries = calcZonesData(
1153
+ data,
1154
+ z.obLookback,
1155
+ this.config.structure.leftWindow,
1156
+ this.config.structure.rightWindow,
1157
+ this.config.structure.breakoutSource,
1158
+ )
1159
+ } else {
1160
+ this.cachedZonesSeries = []
1161
+ }
1162
+ changed.push('zones')
1163
+ }
1164
+
1165
+ // Volume Profile
1166
+ if (this.dirtyData || this.dirtyVolumeProfileConfig) {
1167
+ const vp = this.config.volumeProfile
1168
+ if (vp.showPOC || vp.showValueArea) {
1169
+ this.cachedVolumeProfileSeries = calcVolumeProfileData(data, vp.bins, vp.lookback, vp.valueAreaPercent)
1170
+ } else {
1171
+ this.cachedVolumeProfileSeries = { bins: [], poc: 0, vah: 0, val: 0, totalVolume: 0 }
1172
+ }
1173
+ changed.push('volumeProfile')
1174
+ }
1175
+
1176
+ // 重置脏标记
1177
+ this.dirtyData = false
1178
+ this.dirtyMAConfig = false
1179
+ this.dirtyBollConfig = false
1180
+ this.dirtyExpmaConfig = false
1181
+ this.dirtyEneConfig = false
1182
+ this.dirtyRsiConfig = false
1183
+ this.dirtyCciConfig = false
1184
+ this.dirtyStochConfig = false
1185
+ this.dirtyMomConfig = false
1186
+ this.dirtyWmsrConfig = false
1187
+ this.dirtyKstConfig = false
1188
+ this.dirtyFastkConfig = false
1189
+ this.dirtyMacdConfig = false
1190
+ this.dirtyAtrConfig = false
1191
+ this.dirtyWmaConfig = false
1192
+ this.dirtyDemaConfig = false
1193
+ this.dirtyTemaConfig = false
1194
+ this.dirtyHmaConfig = false
1195
+ this.dirtyKamaConfig = false
1196
+ this.dirtySarConfig = false
1197
+ this.dirtySupertrendConfig = false
1198
+ this.dirtyKeltnerConfig = false
1199
+ this.dirtyDonchianConfig = false
1200
+ this.dirtyIchimokuConfig = false
1201
+ this.dirtyRocConfig = false
1202
+ this.dirtyTrixConfig = false
1203
+ this.dirtyHvConfig = false
1204
+ this.dirtyParkinsonConfig = false
1205
+ this.dirtyChaikinVolConfig = false
1206
+ this.dirtyVmaConfig = false
1207
+ this.dirtyObvConfig = false
1208
+ this.dirtyPvtConfig = false
1209
+ this.dirtyVwapConfig = false
1210
+ this.dirtyCmfConfig = false
1211
+ this.dirtyMfiConfig = false
1212
+ this.dirtyPivotConfig = false
1213
+ this.dirtyFibConfig = false
1214
+ this.dirtyStructureConfig = false
1215
+ this.dirtyZonesConfig = false
1216
+ this.dirtyVolumeProfileConfig = false
1217
+
1218
+ // 组装结果
1219
+ return {
1220
+ ma: {
1221
+ series: this.cachedSeries,
1222
+ enabledPeriods: Object.keys(this.cachedSeries).map(Number),
1223
+ },
1224
+ boll: {
1225
+ series: this.cachedBollSeries,
1226
+ params: { ...this.config.boll },
1227
+ },
1228
+ expma: {
1229
+ series: this.cachedExpmaSeries,
1230
+ params: { ...this.config.expma },
1231
+ },
1232
+ ene: {
1233
+ series: this.cachedEneSeries,
1234
+ params: { ...this.config.ene },
1235
+ },
1236
+ rsi: {
1237
+ series: this.cachedRsiSeries,
1238
+ enabledPeriods: Object.keys(this.cachedRsiSeries).map(Number),
1239
+ params: { ...this.config.rsi },
1240
+ },
1241
+ cci: {
1242
+ series: this.cachedCciSeries,
1243
+ params: { ...this.config.cci },
1244
+ },
1245
+ stoch: {
1246
+ series: this.cachedStochSeries,
1247
+ params: { ...this.config.stoch },
1248
+ },
1249
+ mom: {
1250
+ series: this.cachedMomSeries,
1251
+ params: { ...this.config.mom },
1252
+ },
1253
+ wmsr: {
1254
+ series: this.cachedWmsrSeries,
1255
+ params: { ...this.config.wmsr },
1256
+ },
1257
+ kst: {
1258
+ series: this.cachedKstSeries,
1259
+ params: { ...this.config.kst },
1260
+ },
1261
+ fastk: {
1262
+ series: this.cachedFastkSeries,
1263
+ params: { ...this.config.fastk },
1264
+ },
1265
+ macd: {
1266
+ series: this.cachedMacdSeries,
1267
+ params: { ...this.config.macd },
1268
+ },
1269
+ atr: {
1270
+ series: this.cachedAtrSeries,
1271
+ params: { ...this.config.atr },
1272
+ },
1273
+ wma: {
1274
+ series: this.cachedWmaSeries,
1275
+ params: { ...this.config.wma },
1276
+ },
1277
+ dema: {
1278
+ series: this.cachedDemaSeries,
1279
+ params: { ...this.config.dema },
1280
+ },
1281
+ tema: {
1282
+ series: this.cachedTemaSeries,
1283
+ params: { ...this.config.tema },
1284
+ },
1285
+ hma: {
1286
+ series: this.cachedHmaSeries,
1287
+ params: { ...this.config.hma },
1288
+ },
1289
+ kama: {
1290
+ series: this.cachedKamaSeries,
1291
+ params: { ...this.config.kama },
1292
+ },
1293
+ sar: {
1294
+ series: this.cachedSarSeries,
1295
+ params: { ...this.config.sar },
1296
+ },
1297
+ supertrend: {
1298
+ series: this.cachedSupertrendSeries,
1299
+ params: { ...this.config.supertrend },
1300
+ },
1301
+ keltner: {
1302
+ series: this.cachedKeltnerSeries,
1303
+ params: { ...this.config.keltner },
1304
+ },
1305
+ donchian: {
1306
+ series: this.cachedDonchianSeries,
1307
+ params: { ...this.config.donchian },
1308
+ },
1309
+ ichimoku: {
1310
+ series: this.cachedIchimokuSeries,
1311
+ params: { ...this.config.ichimoku },
1312
+ },
1313
+ roc: {
1314
+ series: this.cachedRocSeries,
1315
+ params: { ...this.config.roc },
1316
+ },
1317
+ trix: {
1318
+ series: this.cachedTrixSeries,
1319
+ signalSeries: this.cachedTrixSignalSeries,
1320
+ params: { ...this.config.trix },
1321
+ },
1322
+ hv: {
1323
+ series: this.cachedHvSeries,
1324
+ params: { ...this.config.hv },
1325
+ },
1326
+ parkinson: {
1327
+ series: this.cachedParkinsonSeries,
1328
+ params: { ...this.config.parkinson },
1329
+ },
1330
+ chaikinVol: {
1331
+ series: this.cachedChaikinVolSeries,
1332
+ params: { ...this.config.chaikinVol },
1333
+ },
1334
+ vma: {
1335
+ series: this.cachedVmaSeries,
1336
+ params: { ...this.config.vma },
1337
+ },
1338
+ obv: {
1339
+ series: this.cachedObvSeries,
1340
+ params: { ...this.config.obv },
1341
+ },
1342
+ pvt: {
1343
+ series: this.cachedPvtSeries,
1344
+ params: { ...this.config.pvt },
1345
+ },
1346
+ vwap: {
1347
+ series: this.cachedVwapSeries,
1348
+ params: { ...this.config.vwap },
1349
+ },
1350
+ cmf: {
1351
+ series: this.cachedCmfSeries,
1352
+ params: { ...this.config.cmf },
1353
+ },
1354
+ mfi: {
1355
+ series: this.cachedMfiSeries,
1356
+ params: { ...this.config.mfi },
1357
+ },
1358
+ pivot: {
1359
+ series: this.cachedPivotSeries,
1360
+ params: { ...this.config.pivot },
1361
+ },
1362
+ fib: {
1363
+ series: this.cachedFibSeries,
1364
+ params: { ...this.config.fib },
1365
+ },
1366
+ structure: {
1367
+ series: this.cachedStructureSeries,
1368
+ params: { ...this.config.structure },
1369
+ },
1370
+ zones: {
1371
+ series: this.cachedZonesSeries,
1372
+ params: { ...this.config.zones },
1373
+ },
1374
+ volumeProfile: {
1375
+ series: this.cachedVolumeProfileSeries,
1376
+ params: { ...this.config.volumeProfile },
1377
+ },
1378
+ _changed: changed,
1379
+ }
1380
+ }
1381
+
1382
+ /**
1383
+ * 获取缓存的 series(用于 visibleRange 变更时扫描极值)
1384
+ */
1385
+ getCachedSeries(): IndicatorSeriesBundle {
1386
+ return {
1387
+ _changed: [],
1388
+ ma: {
1389
+ series: this.cachedSeries,
1390
+ enabledPeriods: Object.keys(this.cachedSeries).map(Number),
1391
+ },
1392
+ boll: {
1393
+ series: this.cachedBollSeries,
1394
+ params: { ...this.config.boll },
1395
+ },
1396
+ expma: {
1397
+ series: this.cachedExpmaSeries,
1398
+ params: { ...this.config.expma },
1399
+ },
1400
+ ene: {
1401
+ series: this.cachedEneSeries,
1402
+ params: { ...this.config.ene },
1403
+ },
1404
+ rsi: {
1405
+ series: this.cachedRsiSeries,
1406
+ enabledPeriods: Object.keys(this.cachedRsiSeries).map(Number),
1407
+ params: { ...this.config.rsi },
1408
+ },
1409
+ cci: {
1410
+ series: this.cachedCciSeries,
1411
+ params: { ...this.config.cci },
1412
+ },
1413
+ stoch: {
1414
+ series: this.cachedStochSeries,
1415
+ params: { ...this.config.stoch },
1416
+ },
1417
+ mom: {
1418
+ series: this.cachedMomSeries,
1419
+ params: { ...this.config.mom },
1420
+ },
1421
+ wmsr: {
1422
+ series: this.cachedWmsrSeries,
1423
+ params: { ...this.config.wmsr },
1424
+ },
1425
+ kst: {
1426
+ series: this.cachedKstSeries,
1427
+ params: { ...this.config.kst },
1428
+ },
1429
+ fastk: {
1430
+ series: this.cachedFastkSeries,
1431
+ params: { ...this.config.fastk },
1432
+ },
1433
+ macd: {
1434
+ series: this.cachedMacdSeries,
1435
+ params: { ...this.config.macd },
1436
+ },
1437
+ atr: {
1438
+ series: this.cachedAtrSeries,
1439
+ params: { ...this.config.atr },
1440
+ },
1441
+ wma: {
1442
+ series: this.cachedWmaSeries,
1443
+ params: { ...this.config.wma },
1444
+ },
1445
+ dema: {
1446
+ series: this.cachedDemaSeries,
1447
+ params: { ...this.config.dema },
1448
+ },
1449
+ tema: {
1450
+ series: this.cachedTemaSeries,
1451
+ params: { ...this.config.tema },
1452
+ },
1453
+ hma: {
1454
+ series: this.cachedHmaSeries,
1455
+ params: { ...this.config.hma },
1456
+ },
1457
+ kama: {
1458
+ series: this.cachedKamaSeries,
1459
+ params: { ...this.config.kama },
1460
+ },
1461
+ sar: {
1462
+ series: this.cachedSarSeries,
1463
+ params: { ...this.config.sar },
1464
+ },
1465
+ supertrend: {
1466
+ series: this.cachedSupertrendSeries,
1467
+ params: { ...this.config.supertrend },
1468
+ },
1469
+ keltner: {
1470
+ series: this.cachedKeltnerSeries,
1471
+ params: { ...this.config.keltner },
1472
+ },
1473
+ donchian: {
1474
+ series: this.cachedDonchianSeries,
1475
+ params: { ...this.config.donchian },
1476
+ },
1477
+ ichimoku: {
1478
+ series: this.cachedIchimokuSeries,
1479
+ params: { ...this.config.ichimoku },
1480
+ },
1481
+ roc: {
1482
+ series: this.cachedRocSeries,
1483
+ params: { ...this.config.roc },
1484
+ },
1485
+ trix: {
1486
+ series: this.cachedTrixSeries,
1487
+ signalSeries: this.cachedTrixSignalSeries,
1488
+ params: { ...this.config.trix },
1489
+ },
1490
+ hv: {
1491
+ series: this.cachedHvSeries,
1492
+ params: { ...this.config.hv },
1493
+ },
1494
+ parkinson: {
1495
+ series: this.cachedParkinsonSeries,
1496
+ params: { ...this.config.parkinson },
1497
+ },
1498
+ chaikinVol: {
1499
+ series: this.cachedChaikinVolSeries,
1500
+ params: { ...this.config.chaikinVol },
1501
+ },
1502
+ vma: {
1503
+ series: this.cachedVmaSeries,
1504
+ params: { ...this.config.vma },
1505
+ },
1506
+ obv: {
1507
+ series: this.cachedObvSeries,
1508
+ params: { ...this.config.obv },
1509
+ },
1510
+ pvt: {
1511
+ series: this.cachedPvtSeries,
1512
+ params: { ...this.config.pvt },
1513
+ },
1514
+ vwap: {
1515
+ series: this.cachedVwapSeries,
1516
+ params: { ...this.config.vwap },
1517
+ },
1518
+ cmf: {
1519
+ series: this.cachedCmfSeries,
1520
+ params: { ...this.config.cmf },
1521
+ },
1522
+ mfi: {
1523
+ series: this.cachedMfiSeries,
1524
+ params: { ...this.config.mfi },
1525
+ },
1526
+ pivot: {
1527
+ series: this.cachedPivotSeries,
1528
+ params: { ...this.config.pivot },
1529
+ },
1530
+ fib: {
1531
+ series: this.cachedFibSeries,
1532
+ params: { ...this.config.fib },
1533
+ },
1534
+ structure: {
1535
+ series: this.cachedStructureSeries,
1536
+ params: { ...this.config.structure },
1537
+ },
1538
+ zones: {
1539
+ series: this.cachedZonesSeries,
1540
+ params: { ...this.config.zones },
1541
+ },
1542
+ volumeProfile: {
1543
+ series: this.cachedVolumeProfileSeries,
1544
+ params: { ...this.config.volumeProfile },
1545
+ },
1546
+ }
1547
+ }
1548
+ }