@363045841yyt/klinechart-core 0.7.3 → 0.7.5

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 (247) hide show
  1. package/README.md +201 -201
  2. package/README.zh-CN.md +201 -201
  3. package/dist/controllers/index.d.ts +1 -0
  4. package/dist/controllers/index.d.ts.map +1 -1
  5. package/dist/controllers/index.js +1 -0
  6. package/dist/controllers/index.js.map +1 -1
  7. package/dist/engine/chart.d.ts +11 -19
  8. package/dist/engine/chart.d.ts.map +1 -1
  9. package/dist/engine/chart.js +92 -109
  10. package/dist/engine/chart.js.map +1 -1
  11. package/dist/engine/renderers/Indicator/indicatorData.d.ts +1 -0
  12. package/dist/engine/renderers/Indicator/indicatorData.d.ts.map +1 -1
  13. package/dist/engine/renderers/Indicator/indicatorData.js +1 -1
  14. package/dist/engine/renderers/Indicator/indicatorData.js.map +1 -1
  15. package/dist/engine/renderers/webgl/candleSurface.js +47 -47
  16. package/dist/engine/subPaneManager.d.ts +4 -0
  17. package/dist/engine/subPaneManager.d.ts.map +1 -1
  18. package/dist/engine/subPaneManager.js +13 -0
  19. package/dist/engine/subPaneManager.js.map +1 -1
  20. package/dist/version.d.ts +1 -1
  21. package/dist/version.d.ts.map +1 -1
  22. package/dist/version.js +1 -2
  23. package/dist/version.js.map +1 -1
  24. package/package.json +129 -122
  25. package/src/__tests__/signal.test.ts +124 -124
  26. package/src/config/chartSettings.ts +66 -66
  27. package/src/controllers/__tests__/drawing.test.ts +214 -214
  28. package/src/controllers/__tests__/indicatorSelector.test.ts +481 -481
  29. package/src/controllers/__tests__/toolbar.test.ts +225 -225
  30. package/src/controllers/createChartController.ts +665 -665
  31. package/src/controllers/createDrawingController.ts +96 -96
  32. package/src/controllers/createIndicatorSelectorController.ts +307 -307
  33. package/src/controllers/createToolbarController.ts +146 -146
  34. package/src/controllers/index.ts +20 -19
  35. package/src/controllers/types.ts +284 -284
  36. package/src/engine/__tests__/chart.dpr.test.ts +401 -401
  37. package/src/engine/__tests__/paneRenderer.resize.test.ts +92 -92
  38. package/src/engine/chart-store.ts +121 -121
  39. package/src/engine/chart.d.ts +617 -617
  40. package/src/engine/chart.ts +2803 -2815
  41. package/src/engine/controller/__tests__/interaction.dpr.test.ts +259 -259
  42. package/src/engine/controller/interaction.ts +722 -722
  43. package/src/engine/controller/markerInteraction.ts +130 -130
  44. package/src/engine/controller/pinchTracker.ts +82 -82
  45. package/src/engine/controller/tooltipPosition.ts +48 -48
  46. package/src/engine/draw/__tests__/pixelAlign.spec.ts +176 -176
  47. package/src/engine/draw/pixelAlign.ts +259 -259
  48. package/src/engine/drawing/index.ts +655 -655
  49. package/src/engine/drawing/interaction.ts +842 -842
  50. package/src/engine/drawing/plugin.ts +343 -343
  51. package/src/engine/indicators/__tests__/__fixtures__/golden/atr.json +38 -38
  52. package/src/engine/indicators/__tests__/__fixtures__/golden/dema.json +14 -14
  53. package/src/engine/indicators/__tests__/__fixtures__/golden/hma.json +14 -14
  54. package/src/engine/indicators/__tests__/__fixtures__/golden/index.ts +55 -55
  55. package/src/engine/indicators/__tests__/__fixtures__/golden/kama.json +14 -14
  56. package/src/engine/indicators/__tests__/__fixtures__/golden/tema.json +14 -14
  57. package/src/engine/indicators/__tests__/__fixtures__/golden/wma.json +40 -40
  58. package/src/engine/indicators/__tests__/__fixtures__/synthetic.ts +65 -65
  59. package/src/engine/indicators/__tests__/_propertyAssertions.ts +76 -76
  60. package/src/engine/indicators/__tests__/atr.test.ts +153 -153
  61. package/src/engine/indicators/__tests__/calculators.test.ts +614 -614
  62. package/src/engine/indicators/__tests__/cmf-mfi.test.ts +100 -100
  63. package/src/engine/indicators/__tests__/dema.test.ts +73 -73
  64. package/src/engine/indicators/__tests__/donchian.test.ts +70 -70
  65. package/src/engine/indicators/__tests__/hma.test.ts +73 -73
  66. package/src/engine/indicators/__tests__/ichimoku.test.ts +105 -105
  67. package/src/engine/indicators/__tests__/kama.test.ts +80 -80
  68. package/src/engine/indicators/__tests__/keltner.test.ts +65 -65
  69. package/src/engine/indicators/__tests__/pivot-fib.test.ts +110 -110
  70. package/src/engine/indicators/__tests__/roc.test.ts +68 -68
  71. package/src/engine/indicators/__tests__/sar.test.ts +86 -86
  72. package/src/engine/indicators/__tests__/scheduler.test.ts +831 -831
  73. package/src/engine/indicators/__tests__/soa.test.ts +533 -533
  74. package/src/engine/indicators/__tests__/structure.test.ts +110 -110
  75. package/src/engine/indicators/__tests__/supertrend.test.ts +65 -65
  76. package/src/engine/indicators/__tests__/tema.test.ts +68 -68
  77. package/src/engine/indicators/__tests__/trix.test.ts +70 -70
  78. package/src/engine/indicators/__tests__/volatility.test.ts +117 -117
  79. package/src/engine/indicators/__tests__/volume.test.ts +115 -115
  80. package/src/engine/indicators/__tests__/volumeProfile.test.ts +74 -74
  81. package/src/engine/indicators/__tests__/vwap.test.ts +69 -69
  82. package/src/engine/indicators/__tests__/wma.test.ts +112 -112
  83. package/src/engine/indicators/__tests__/zones.test.ts +95 -95
  84. package/src/engine/indicators/atrState.ts +27 -27
  85. package/src/engine/indicators/bollState.ts +51 -51
  86. package/src/engine/indicators/calculators.ts +2593 -2593
  87. package/src/engine/indicators/cciState.ts +25 -25
  88. package/src/engine/indicators/chaikinVolState.ts +32 -32
  89. package/src/engine/indicators/cmfState.ts +27 -27
  90. package/src/engine/indicators/demaState.ts +27 -27
  91. package/src/engine/indicators/donchianState.ts +43 -43
  92. package/src/engine/indicators/eneState.ts +43 -43
  93. package/src/engine/indicators/expmaState.ts +43 -43
  94. package/src/engine/indicators/fastkState.ts +25 -25
  95. package/src/engine/indicators/fibState.ts +41 -41
  96. package/src/engine/indicators/hmaState.ts +27 -27
  97. package/src/engine/indicators/hvState.ts +28 -28
  98. package/src/engine/indicators/ichimokuState.ts +70 -70
  99. package/src/engine/indicators/indicator.worker.ts +169 -169
  100. package/src/engine/indicators/indicatorDefinitionRegistry.ts +62 -62
  101. package/src/engine/indicators/indicatorMetadata.ts +110 -110
  102. package/src/engine/indicators/indicatorRegistry.ts +106 -106
  103. package/src/engine/indicators/indicatorRuntime.ts +1548 -1548
  104. package/src/engine/indicators/kamaState.ts +34 -34
  105. package/src/engine/indicators/keltnerState.ts +49 -49
  106. package/src/engine/indicators/kstState.ts +42 -42
  107. package/src/engine/indicators/maState.ts +36 -36
  108. package/src/engine/indicators/macdState.ts +76 -76
  109. package/src/engine/indicators/mfiState.ts +27 -27
  110. package/src/engine/indicators/momState.ts +25 -25
  111. package/src/engine/indicators/obvState.ts +25 -25
  112. package/src/engine/indicators/parkinsonState.ts +28 -28
  113. package/src/engine/indicators/pivotState.ts +51 -51
  114. package/src/engine/indicators/pvtState.ts +25 -25
  115. package/src/engine/indicators/rocState.ts +27 -27
  116. package/src/engine/indicators/rsiState.ts +65 -65
  117. package/src/engine/indicators/sarState.ts +41 -41
  118. package/src/engine/indicators/scheduler.ts +1205 -1205
  119. package/src/engine/indicators/soa.ts +352 -352
  120. package/src/engine/indicators/stateComposer.ts +1262 -1262
  121. package/src/engine/indicators/stochState.ts +26 -26
  122. package/src/engine/indicators/structureState.ts +69 -69
  123. package/src/engine/indicators/supertrendState.ts +37 -37
  124. package/src/engine/indicators/temaState.ts +27 -27
  125. package/src/engine/indicators/trixState.ts +35 -35
  126. package/src/engine/indicators/vmaState.ts +27 -27
  127. package/src/engine/indicators/volumeProfileState.ts +63 -63
  128. package/src/engine/indicators/vwapState.ts +29 -29
  129. package/src/engine/indicators/wmaState.ts +27 -27
  130. package/src/engine/indicators/wmsrState.ts +25 -25
  131. package/src/engine/indicators/workerProtocol.ts +613 -613
  132. package/src/engine/indicators/zonesState.ts +47 -47
  133. package/src/engine/layout/pane.ts +161 -161
  134. package/src/engine/marker/registry.ts +265 -265
  135. package/src/engine/paneRenderer.ts +169 -169
  136. package/src/engine/renderers/Indicator/atr.ts +237 -237
  137. package/src/engine/renderers/Indicator/boll.ts +317 -317
  138. package/src/engine/renderers/Indicator/cci.ts +275 -275
  139. package/src/engine/renderers/Indicator/chaikinVol.ts +138 -138
  140. package/src/engine/renderers/Indicator/cmf.ts +137 -137
  141. package/src/engine/renderers/Indicator/dema.ts +136 -136
  142. package/src/engine/renderers/Indicator/donchian.ts +137 -137
  143. package/src/engine/renderers/Indicator/ene.ts +271 -271
  144. package/src/engine/renderers/Indicator/expma.ts +197 -197
  145. package/src/engine/renderers/Indicator/fastk.ts +316 -316
  146. package/src/engine/renderers/Indicator/fib.ts +141 -141
  147. package/src/engine/renderers/Indicator/hma.ts +136 -136
  148. package/src/engine/renderers/Indicator/hv.ts +124 -124
  149. package/src/engine/renderers/Indicator/ichimoku.ts +181 -181
  150. package/src/engine/renderers/Indicator/index.ts +241 -241
  151. package/src/engine/renderers/Indicator/indicatorData.ts +650 -650
  152. package/src/engine/renderers/Indicator/kama.ts +136 -136
  153. package/src/engine/renderers/Indicator/keltner.ts +137 -137
  154. package/src/engine/renderers/Indicator/kst.ts +302 -302
  155. package/src/engine/renderers/Indicator/ma.ts +200 -200
  156. package/src/engine/renderers/Indicator/macd.ts +477 -477
  157. package/src/engine/renderers/Indicator/macdLegend.ts +141 -141
  158. package/src/engine/renderers/Indicator/mainIndicatorLegend.ts +272 -272
  159. package/src/engine/renderers/Indicator/mfi.ts +142 -142
  160. package/src/engine/renderers/Indicator/mom.ts +311 -311
  161. package/src/engine/renderers/Indicator/obv.ts +123 -123
  162. package/src/engine/renderers/Indicator/parkinson.ts +124 -124
  163. package/src/engine/renderers/Indicator/pivot.ts +131 -131
  164. package/src/engine/renderers/Indicator/pvt.ts +123 -123
  165. package/src/engine/renderers/Indicator/roc.ts +143 -143
  166. package/src/engine/renderers/Indicator/rsi.ts +390 -390
  167. package/src/engine/renderers/Indicator/sar.ts +113 -113
  168. package/src/engine/renderers/Indicator/scale/atr_scale.ts +19 -19
  169. package/src/engine/renderers/Indicator/scale/cci_scale.ts +19 -19
  170. package/src/engine/renderers/Indicator/scale/fastk_scale.ts +19 -19
  171. package/src/engine/renderers/Indicator/scale/indicator_scale.ts +204 -204
  172. package/src/engine/renderers/Indicator/scale/kst_scale.ts +19 -19
  173. package/src/engine/renderers/Indicator/scale/macd_scale.ts +22 -22
  174. package/src/engine/renderers/Indicator/scale/mom_scale.ts +19 -19
  175. package/src/engine/renderers/Indicator/scale/rsi_scale.ts +19 -19
  176. package/src/engine/renderers/Indicator/scale/stoch_scale.ts +19 -19
  177. package/src/engine/renderers/Indicator/scale/volume_scale.ts +26 -26
  178. package/src/engine/renderers/Indicator/scale/wmsr_scale.ts +19 -19
  179. package/src/engine/renderers/Indicator/stoch.ts +359 -359
  180. package/src/engine/renderers/Indicator/structure.ts +126 -126
  181. package/src/engine/renderers/Indicator/subPaneConfig.ts +265 -265
  182. package/src/engine/renderers/Indicator/supertrend.ts +115 -115
  183. package/src/engine/renderers/Indicator/tema.ts +136 -136
  184. package/src/engine/renderers/Indicator/trix.ts +158 -158
  185. package/src/engine/renderers/Indicator/vma.ts +124 -124
  186. package/src/engine/renderers/Indicator/volumeProfile.ts +125 -125
  187. package/src/engine/renderers/Indicator/vwap.ts +123 -123
  188. package/src/engine/renderers/Indicator/wma.ts +136 -136
  189. package/src/engine/renderers/Indicator/wmsr.ts +328 -328
  190. package/src/engine/renderers/Indicator/zones.ts +104 -104
  191. package/src/engine/renderers/__tests__/boll.renderer.test.ts +314 -314
  192. package/src/engine/renderers/__tests__/ene.renderer.test.ts +305 -305
  193. package/src/engine/renderers/__tests__/expma.renderer.test.ts +279 -279
  194. package/src/engine/renderers/__tests__/ma.renderer.test.ts +426 -426
  195. package/src/engine/renderers/__tests__/mainIndicatorLegend.renderer.test.ts +502 -502
  196. package/src/engine/renderers/__tests__/yAxis.renderer.test.ts +173 -173
  197. package/src/engine/renderers/candle.ts +459 -459
  198. package/src/engine/renderers/crosshair.ts +69 -69
  199. package/src/engine/renderers/customMarkers.ts +162 -162
  200. package/src/engine/renderers/extremaMarkers.ts +246 -246
  201. package/src/engine/renderers/gridLines.ts +90 -90
  202. package/src/engine/renderers/lastPrice.ts +97 -97
  203. package/src/engine/renderers/paneTitle.ts +136 -136
  204. package/src/engine/renderers/subVolume.ts +236 -236
  205. package/src/engine/renderers/timeAxis.ts +121 -121
  206. package/src/engine/renderers/webgl/candleSurface.ts +955 -955
  207. package/src/engine/renderers/webgl/sharedWebGLSurface.ts +146 -146
  208. package/src/engine/renderers/yAxis.ts +105 -105
  209. package/src/engine/scale/__tests__/logFormula.spec.ts +148 -148
  210. package/src/engine/scale/logFormula.ts +130 -130
  211. package/src/engine/scale/price.ts +39 -39
  212. package/src/engine/scale/priceScale.ts +264 -264
  213. package/src/engine/subPaneManager.ts +442 -427
  214. package/src/engine/theme/colors.ts +642 -642
  215. package/src/engine/theme/fonts.ts +20 -20
  216. package/src/engine/utils/klineConfig.ts +49 -49
  217. package/src/engine/utils/tickCount.ts +11 -11
  218. package/src/engine/utils/tickPosition.ts +214 -214
  219. package/src/engine/utils/zoom.ts +83 -83
  220. package/src/engine/viewport/viewport.ts +67 -67
  221. package/src/index.ts +3 -3
  222. package/src/plugin/ConfigManager.ts +93 -93
  223. package/src/plugin/EventBus.ts +77 -77
  224. package/src/plugin/HookSystem.ts +106 -106
  225. package/src/plugin/PluginHost.ts +243 -243
  226. package/src/plugin/PluginRegistry.ts +92 -92
  227. package/src/plugin/StateStore.ts +73 -73
  228. package/src/plugin/index.ts +19 -19
  229. package/src/plugin/rendererPluginManager.ts +368 -368
  230. package/src/plugin/stateKeys.ts +8 -8
  231. package/src/plugin/types.ts +526 -526
  232. package/src/reactivity/index.ts +2 -2
  233. package/src/reactivity/signal.ts +119 -119
  234. package/src/semantic/controller.ts +251 -251
  235. package/src/semantic/drawShape.ts +260 -260
  236. package/src/semantic/index.ts +28 -28
  237. package/src/semantic/schema.json +256 -256
  238. package/src/semantic/types.ts +251 -251
  239. package/src/semantic/validator.ts +349 -349
  240. package/src/types/kLine.ts +13 -13
  241. package/src/types/price.ts +56 -56
  242. package/src/types/volumePrice.ts +33 -33
  243. package/src/utils/dateFormat.ts +208 -208
  244. package/src/utils/kLineDraw/axis.ts +562 -562
  245. package/src/utils/priceToY.ts +34 -34
  246. package/src/utils/volumePrice.ts +202 -202
  247. 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
+ }