@363045841yyt/klinechart-core 0.7.9 → 0.7.10

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 (234) hide show
  1. package/dist/engine/chart.d.ts.map +1 -1
  2. package/dist/engine/chart.js +39 -229
  3. package/dist/engine/chart.js.map +1 -1
  4. package/dist/engine/indicators/indicatorDefinitionRegistry.d.ts +10 -3
  5. package/dist/engine/indicators/indicatorDefinitionRegistry.d.ts.map +1 -1
  6. package/dist/engine/indicators/indicatorDefinitionRegistry.js +29 -2
  7. package/dist/engine/indicators/indicatorDefinitionRegistry.js.map +1 -1
  8. package/dist/engine/indicators/indicatorMetadata.d.ts +79 -2
  9. package/dist/engine/indicators/indicatorMetadata.d.ts.map +1 -1
  10. package/dist/engine/indicators/indicatorMetadata.js.map +1 -1
  11. package/dist/engine/indicators/indicatorRegistry.d.ts +5 -0
  12. package/dist/engine/indicators/indicatorRegistry.d.ts.map +1 -1
  13. package/dist/engine/indicators/indicatorRegistry.js +49 -5
  14. package/dist/engine/indicators/indicatorRegistry.js.map +1 -1
  15. package/dist/engine/indicators/registerBuiltins.d.ts +42 -0
  16. package/dist/engine/indicators/registerBuiltins.d.ts.map +1 -0
  17. package/dist/engine/indicators/registerBuiltins.js +46 -0
  18. package/dist/engine/indicators/registerBuiltins.js.map +1 -0
  19. package/dist/engine/indicators/scheduler.d.ts +2 -2
  20. package/dist/engine/indicators/scheduler.d.ts.map +1 -1
  21. package/dist/engine/indicators/scheduler.js +41 -11
  22. package/dist/engine/indicators/scheduler.js.map +1 -1
  23. package/dist/engine/indicators/stateComposer.d.ts +6 -4
  24. package/dist/engine/indicators/stateComposer.d.ts.map +1 -1
  25. package/dist/engine/indicators/stateComposer.js +80 -984
  26. package/dist/engine/indicators/stateComposer.js.map +1 -1
  27. package/dist/engine/indicators/visibleStateComposers.d.ts +145 -0
  28. package/dist/engine/indicators/visibleStateComposers.d.ts.map +1 -0
  29. package/dist/engine/indicators/visibleStateComposers.js +469 -0
  30. package/dist/engine/indicators/visibleStateComposers.js.map +1 -0
  31. package/dist/engine/renderers/Indicator/atr.d.ts.map +1 -1
  32. package/dist/engine/renderers/Indicator/atr.js +8 -0
  33. package/dist/engine/renderers/Indicator/atr.js.map +1 -1
  34. package/dist/engine/renderers/Indicator/boll.d.ts.map +1 -1
  35. package/dist/engine/renderers/Indicator/boll.js +47 -0
  36. package/dist/engine/renderers/Indicator/boll.js.map +1 -1
  37. package/dist/engine/renderers/Indicator/cci.d.ts.map +1 -1
  38. package/dist/engine/renderers/Indicator/cci.js +8 -1
  39. package/dist/engine/renderers/Indicator/cci.js.map +1 -1
  40. package/dist/engine/renderers/Indicator/chaikinVol.d.ts.map +1 -1
  41. package/dist/engine/renderers/Indicator/chaikinVol.js +7 -1
  42. package/dist/engine/renderers/Indicator/chaikinVol.js.map +1 -1
  43. package/dist/engine/renderers/Indicator/cmf.d.ts.map +1 -1
  44. package/dist/engine/renderers/Indicator/cmf.js +7 -1
  45. package/dist/engine/renderers/Indicator/cmf.js.map +1 -1
  46. package/dist/engine/renderers/Indicator/dema.d.ts.map +1 -1
  47. package/dist/engine/renderers/Indicator/dema.js +8 -1
  48. package/dist/engine/renderers/Indicator/dema.js.map +1 -1
  49. package/dist/engine/renderers/Indicator/donchian.d.ts.map +1 -1
  50. package/dist/engine/renderers/Indicator/donchian.js +8 -1
  51. package/dist/engine/renderers/Indicator/donchian.js.map +1 -1
  52. package/dist/engine/renderers/Indicator/ene.d.ts.map +1 -1
  53. package/dist/engine/renderers/Indicator/ene.js +45 -0
  54. package/dist/engine/renderers/Indicator/ene.js.map +1 -1
  55. package/dist/engine/renderers/Indicator/expma.d.ts.map +1 -1
  56. package/dist/engine/renderers/Indicator/expma.js +45 -0
  57. package/dist/engine/renderers/Indicator/expma.js.map +1 -1
  58. package/dist/engine/renderers/Indicator/fastk.d.ts.map +1 -1
  59. package/dist/engine/renderers/Indicator/fastk.js +8 -1
  60. package/dist/engine/renderers/Indicator/fastk.js.map +1 -1
  61. package/dist/engine/renderers/Indicator/fib.d.ts.map +1 -1
  62. package/dist/engine/renderers/Indicator/fib.js +8 -1
  63. package/dist/engine/renderers/Indicator/fib.js.map +1 -1
  64. package/dist/engine/renderers/Indicator/hma.d.ts.map +1 -1
  65. package/dist/engine/renderers/Indicator/hma.js +8 -1
  66. package/dist/engine/renderers/Indicator/hma.js.map +1 -1
  67. package/dist/engine/renderers/Indicator/hv.d.ts.map +1 -1
  68. package/dist/engine/renderers/Indicator/hv.js +7 -0
  69. package/dist/engine/renderers/Indicator/hv.js.map +1 -1
  70. package/dist/engine/renderers/Indicator/ichimoku.d.ts.map +1 -1
  71. package/dist/engine/renderers/Indicator/ichimoku.js +8 -1
  72. package/dist/engine/renderers/Indicator/ichimoku.js.map +1 -1
  73. package/dist/engine/renderers/Indicator/index.d.ts +7 -2
  74. package/dist/engine/renderers/Indicator/index.d.ts.map +1 -1
  75. package/dist/engine/renderers/Indicator/index.js +2 -114
  76. package/dist/engine/renderers/Indicator/index.js.map +1 -1
  77. package/dist/engine/renderers/Indicator/kama.d.ts.map +1 -1
  78. package/dist/engine/renderers/Indicator/kama.js +8 -1
  79. package/dist/engine/renderers/Indicator/kama.js.map +1 -1
  80. package/dist/engine/renderers/Indicator/keltner.d.ts.map +1 -1
  81. package/dist/engine/renderers/Indicator/keltner.js +8 -1
  82. package/dist/engine/renderers/Indicator/keltner.js.map +1 -1
  83. package/dist/engine/renderers/Indicator/kst.d.ts.map +1 -1
  84. package/dist/engine/renderers/Indicator/kst.js +8 -0
  85. package/dist/engine/renderers/Indicator/kst.js.map +1 -1
  86. package/dist/engine/renderers/Indicator/ma.d.ts.map +1 -1
  87. package/dist/engine/renderers/Indicator/ma.js +63 -0
  88. package/dist/engine/renderers/Indicator/ma.js.map +1 -1
  89. package/dist/engine/renderers/Indicator/macd.d.ts.map +1 -1
  90. package/dist/engine/renderers/Indicator/macd.js +8 -1
  91. package/dist/engine/renderers/Indicator/macd.js.map +1 -1
  92. package/dist/engine/renderers/Indicator/mfi.d.ts.map +1 -1
  93. package/dist/engine/renderers/Indicator/mfi.js +7 -1
  94. package/dist/engine/renderers/Indicator/mfi.js.map +1 -1
  95. package/dist/engine/renderers/Indicator/mom.d.ts.map +1 -1
  96. package/dist/engine/renderers/Indicator/mom.js +8 -0
  97. package/dist/engine/renderers/Indicator/mom.js.map +1 -1
  98. package/dist/engine/renderers/Indicator/obv.d.ts.map +1 -1
  99. package/dist/engine/renderers/Indicator/obv.js +7 -1
  100. package/dist/engine/renderers/Indicator/obv.js.map +1 -1
  101. package/dist/engine/renderers/Indicator/parkinson.d.ts.map +1 -1
  102. package/dist/engine/renderers/Indicator/parkinson.js +7 -0
  103. package/dist/engine/renderers/Indicator/parkinson.js.map +1 -1
  104. package/dist/engine/renderers/Indicator/pivot.d.ts.map +1 -1
  105. package/dist/engine/renderers/Indicator/pivot.js +8 -1
  106. package/dist/engine/renderers/Indicator/pivot.js.map +1 -1
  107. package/dist/engine/renderers/Indicator/pvt.d.ts.map +1 -1
  108. package/dist/engine/renderers/Indicator/pvt.js +7 -1
  109. package/dist/engine/renderers/Indicator/pvt.js.map +1 -1
  110. package/dist/engine/renderers/Indicator/roc.d.ts.map +1 -1
  111. package/dist/engine/renderers/Indicator/roc.js +7 -1
  112. package/dist/engine/renderers/Indicator/roc.js.map +1 -1
  113. package/dist/engine/renderers/Indicator/rsi.d.ts.map +1 -1
  114. package/dist/engine/renderers/Indicator/rsi.js +8 -1
  115. package/dist/engine/renderers/Indicator/rsi.js.map +1 -1
  116. package/dist/engine/renderers/Indicator/sar.d.ts.map +1 -1
  117. package/dist/engine/renderers/Indicator/sar.js +8 -1
  118. package/dist/engine/renderers/Indicator/sar.js.map +1 -1
  119. package/dist/engine/renderers/Indicator/stoch.d.ts.map +1 -1
  120. package/dist/engine/renderers/Indicator/stoch.js +8 -1
  121. package/dist/engine/renderers/Indicator/stoch.js.map +1 -1
  122. package/dist/engine/renderers/Indicator/structure.d.ts.map +1 -1
  123. package/dist/engine/renderers/Indicator/structure.js +8 -1
  124. package/dist/engine/renderers/Indicator/structure.js.map +1 -1
  125. package/dist/engine/renderers/Indicator/subPaneConfig.d.ts +1 -1
  126. package/dist/engine/renderers/Indicator/subPaneConfig.d.ts.map +1 -1
  127. package/dist/engine/renderers/Indicator/subPaneConfig.js.map +1 -1
  128. package/dist/engine/renderers/Indicator/supertrend.d.ts.map +1 -1
  129. package/dist/engine/renderers/Indicator/supertrend.js +8 -1
  130. package/dist/engine/renderers/Indicator/supertrend.js.map +1 -1
  131. package/dist/engine/renderers/Indicator/tema.d.ts.map +1 -1
  132. package/dist/engine/renderers/Indicator/tema.js +8 -1
  133. package/dist/engine/renderers/Indicator/tema.js.map +1 -1
  134. package/dist/engine/renderers/Indicator/trix.d.ts.map +1 -1
  135. package/dist/engine/renderers/Indicator/trix.js +7 -0
  136. package/dist/engine/renderers/Indicator/trix.js.map +1 -1
  137. package/dist/engine/renderers/Indicator/vma.d.ts.map +1 -1
  138. package/dist/engine/renderers/Indicator/vma.js +7 -0
  139. package/dist/engine/renderers/Indicator/vma.js.map +1 -1
  140. package/dist/engine/renderers/Indicator/volumeProfile.d.ts.map +1 -1
  141. package/dist/engine/renderers/Indicator/volumeProfile.js +7 -1
  142. package/dist/engine/renderers/Indicator/volumeProfile.js.map +1 -1
  143. package/dist/engine/renderers/Indicator/vwap.d.ts.map +1 -1
  144. package/dist/engine/renderers/Indicator/vwap.js +7 -1
  145. package/dist/engine/renderers/Indicator/vwap.js.map +1 -1
  146. package/dist/engine/renderers/Indicator/wma.d.ts.map +1 -1
  147. package/dist/engine/renderers/Indicator/wma.js +8 -1
  148. package/dist/engine/renderers/Indicator/wma.js.map +1 -1
  149. package/dist/engine/renderers/Indicator/wmsr.d.ts.map +1 -1
  150. package/dist/engine/renderers/Indicator/wmsr.js +8 -1
  151. package/dist/engine/renderers/Indicator/wmsr.js.map +1 -1
  152. package/dist/engine/renderers/Indicator/zones.d.ts.map +1 -1
  153. package/dist/engine/renderers/Indicator/zones.js +8 -1
  154. package/dist/engine/renderers/Indicator/zones.js.map +1 -1
  155. package/dist/engine/renderers/extremaMarkers.d.ts.map +1 -1
  156. package/dist/engine/renderers/extremaMarkers.js +0 -22
  157. package/dist/engine/renderers/extremaMarkers.js.map +1 -1
  158. package/dist/engine/renderers/subVolume.d.ts.map +1 -1
  159. package/dist/engine/renderers/subVolume.js +3 -0
  160. package/dist/engine/renderers/subVolume.js.map +1 -1
  161. package/dist/engine/subPaneManager.d.ts +1 -0
  162. package/dist/engine/subPaneManager.d.ts.map +1 -1
  163. package/dist/engine/subPaneManager.js +30 -237
  164. package/dist/engine/subPaneManager.js.map +1 -1
  165. package/dist/semantic/controller.d.ts +9 -4
  166. package/dist/semantic/controller.d.ts.map +1 -1
  167. package/dist/semantic/controller.js +57 -53
  168. package/dist/semantic/controller.js.map +1 -1
  169. package/dist/version.d.ts +1 -1
  170. package/dist/version.d.ts.map +1 -1
  171. package/dist/version.js +1 -1
  172. package/dist/version.js.map +1 -1
  173. package/package.json +1 -1
  174. package/src/engine/chart.ts +49 -229
  175. package/src/engine/indicators/__tests__/indicatorDefinitionRegistry.test.ts +59 -0
  176. package/src/engine/indicators/__tests__/indicatorRegistry.test.ts +62 -0
  177. package/src/engine/indicators/__tests__/registerBuiltins.test.ts +380 -0
  178. package/src/engine/indicators/__tests__/scheduler.test.ts +62 -32
  179. package/src/engine/indicators/__tests__/stateComposer.test.ts +444 -0
  180. package/src/engine/indicators/indicatorDefinitionRegistry.ts +49 -4
  181. package/src/engine/indicators/indicatorMetadata.ts +107 -2
  182. package/src/engine/indicators/indicatorRegistry.ts +54 -5
  183. package/src/engine/indicators/registerBuiltins.ts +47 -0
  184. package/src/engine/indicators/scheduler.ts +61 -13
  185. package/src/engine/indicators/stateComposer.ts +110 -1040
  186. package/src/engine/indicators/visibleStateComposers.ts +734 -0
  187. package/src/engine/renderers/Indicator/__tests__/createSubIndicatorRenderer.test.ts +61 -0
  188. package/src/engine/renderers/Indicator/atr.ts +9 -1
  189. package/src/engine/renderers/Indicator/boll.ts +53 -1
  190. package/src/engine/renderers/Indicator/cci.ts +9 -2
  191. package/src/engine/renderers/Indicator/chaikinVol.ts +8 -2
  192. package/src/engine/renderers/Indicator/cmf.ts +8 -2
  193. package/src/engine/renderers/Indicator/dema.ts +9 -2
  194. package/src/engine/renderers/Indicator/donchian.ts +9 -2
  195. package/src/engine/renderers/Indicator/ene.ts +51 -1
  196. package/src/engine/renderers/Indicator/expma.ts +51 -1
  197. package/src/engine/renderers/Indicator/fastk.ts +9 -2
  198. package/src/engine/renderers/Indicator/fib.ts +9 -2
  199. package/src/engine/renderers/Indicator/hma.ts +9 -2
  200. package/src/engine/renderers/Indicator/hv.ts +8 -1
  201. package/src/engine/renderers/Indicator/ichimoku.ts +9 -2
  202. package/src/engine/renderers/Indicator/index.ts +9 -121
  203. package/src/engine/renderers/Indicator/kama.ts +9 -2
  204. package/src/engine/renderers/Indicator/keltner.ts +9 -2
  205. package/src/engine/renderers/Indicator/kst.ts +9 -1
  206. package/src/engine/renderers/Indicator/ma.ts +69 -0
  207. package/src/engine/renderers/Indicator/macd.ts +9 -2
  208. package/src/engine/renderers/Indicator/mfi.ts +8 -2
  209. package/src/engine/renderers/Indicator/mom.ts +9 -1
  210. package/src/engine/renderers/Indicator/obv.ts +8 -2
  211. package/src/engine/renderers/Indicator/parkinson.ts +8 -1
  212. package/src/engine/renderers/Indicator/pivot.ts +9 -2
  213. package/src/engine/renderers/Indicator/pvt.ts +8 -2
  214. package/src/engine/renderers/Indicator/roc.ts +8 -2
  215. package/src/engine/renderers/Indicator/rsi.ts +9 -2
  216. package/src/engine/renderers/Indicator/sar.ts +9 -2
  217. package/src/engine/renderers/Indicator/stoch.ts +9 -2
  218. package/src/engine/renderers/Indicator/structure.ts +9 -2
  219. package/src/engine/renderers/Indicator/subPaneConfig.ts +1 -1
  220. package/src/engine/renderers/Indicator/supertrend.ts +9 -2
  221. package/src/engine/renderers/Indicator/tema.ts +9 -2
  222. package/src/engine/renderers/Indicator/trix.ts +8 -1
  223. package/src/engine/renderers/Indicator/vma.ts +8 -1
  224. package/src/engine/renderers/Indicator/volumeProfile.ts +8 -2
  225. package/src/engine/renderers/Indicator/vwap.ts +8 -2
  226. package/src/engine/renderers/Indicator/wma.ts +9 -2
  227. package/src/engine/renderers/Indicator/wmsr.ts +9 -2
  228. package/src/engine/renderers/Indicator/zones.ts +9 -2
  229. package/src/engine/renderers/extremaMarkers.ts +0 -24
  230. package/src/engine/renderers/subVolume.ts +3 -0
  231. package/src/engine/subPaneManager.ts +34 -274
  232. package/src/semantic/__tests__/controller.test.ts +84 -0
  233. package/src/semantic/controller.ts +69 -65
  234. package/src/version.ts +1 -1
@@ -3,54 +3,7 @@ import type { SubIndicatorType } from './renderers/Indicator'
3
3
  import { createSignal, type Signal } from '../reactivity/signal'
4
4
  import { createSubIndicatorRenderer } from './renderers/Indicator'
5
5
  import { createPaneTitleRendererPlugin } from './renderers/paneTitle'
6
- import { createVolumeScaleRendererPlugin } from './renderers/Indicator/scale/volume_scale'
7
- import { createMacdScaleRendererPlugin } from './renderers/Indicator/scale/macd_scale'
8
- import { createRsiScaleRendererPlugin } from './renderers/Indicator/scale/rsi_scale'
9
- import { createCciScaleRendererPlugin } from './renderers/Indicator/scale/cci_scale'
10
- import { createStochScaleRendererPlugin } from './renderers/Indicator/scale/stoch_scale'
11
- import { createMomScaleRendererPlugin } from './renderers/Indicator/scale/mom_scale'
12
- import { createWmsrScaleRendererPlugin } from './renderers/Indicator/scale/wmsr_scale'
13
- import { createKstScaleRendererPlugin } from './renderers/Indicator/scale/kst_scale'
14
- import { createFastkScaleRendererPlugin } from './renderers/Indicator/scale/fastk_scale'
15
- import { createAtrScaleRendererPlugin } from './renderers/Indicator/scale/atr_scale'
16
6
  import { createIndicatorScaleRendererPlugin } from './renderers/Indicator/scale/indicator_scale'
17
- import type {
18
- RSISchedulerConfig,
19
- CCISchedulerConfig,
20
- STOCHSchedulerConfig,
21
- MOMSchedulerConfig,
22
- WMSRSchedulerConfig,
23
- KSTSchedulerConfig,
24
- FASTKSchedulerConfig,
25
- ATRSchedulerConfig,
26
- WMASchedulerConfig,
27
- DEMASchedulerConfig,
28
- TEMASchedulerConfig,
29
- HMASchedulerConfig,
30
- KAMASchedulerConfig,
31
- SARSchedulerConfig,
32
- SuperTrendSchedulerConfig,
33
- KeltnerSchedulerConfig,
34
- DonchianSchedulerConfig,
35
- IchimokuSchedulerConfig,
36
- ROCSchedulerConfig,
37
- TRIXSchedulerConfig,
38
- HVSchedulerConfig,
39
- ParkinsonSchedulerConfig,
40
- ChaikinVolSchedulerConfig,
41
- VMASchedulerConfig,
42
- OBVSchedulerConfig,
43
- PVTSchedulerConfig,
44
- VWAPSchedulerConfig,
45
- CMFSchedulerConfig,
46
- MFISchedulerConfig,
47
- PivotSchedulerConfig,
48
- FibSchedulerConfig,
49
- StructureSchedulerConfig,
50
- ZonesSchedulerConfig,
51
- VolumeProfileSchedulerConfig,
52
- } from './indicators/scheduler'
53
- import type { MACDSchedulerConfig } from './indicators/macdState'
54
7
 
55
8
  export interface SubPaneEntry {
56
9
  paneId: string
@@ -78,9 +31,11 @@ export class SubPaneManager {
78
31
  return true
79
32
  }
80
33
 
81
- const rendererName = `${indicatorId.toLowerCase()}_${paneId}`
82
34
  const scaleRendererName = `${indicatorId.toLowerCase()}_scale_${paneId}`
83
35
  const paneTitleRendererName = `paneTitle_${paneId}`
36
+ const renderer = this.createIndicatorRenderer(chart, paneId, indicatorId, params)
37
+ if (!renderer) return false
38
+ const rendererName = renderer.name
84
39
 
85
40
  const paneExists = chart.hasPane(paneId)
86
41
  if (!paneExists) {
@@ -89,7 +44,6 @@ export class SubPaneManager {
89
44
 
90
45
  const existingRenderer = chart.getRenderer(rendererName)
91
46
  if (!existingRenderer) {
92
- const renderer = createSubIndicatorRenderer({ indicatorId, paneId })
93
47
  chart.useRenderer(renderer, params as Record<string, number | boolean | string>)
94
48
  }
95
49
 
@@ -136,11 +90,12 @@ export class SubPaneManager {
136
90
  chart.removeRenderer(entry.scaleRendererName)
137
91
  chart.removeRenderer(entry.paneTitleRendererName)
138
92
 
139
- const newRendererName = `${newIndicatorId.toLowerCase()}_${paneId}`
140
93
  const newScaleRendererName = `${newIndicatorId.toLowerCase()}_scale_${paneId}`
141
94
  const newPaneTitleRendererName = `paneTitle_${paneId}`
95
+ const renderer = this.createIndicatorRenderer(chart, paneId, newIndicatorId, newParams)
96
+ if (!renderer) return
97
+ const newRendererName = renderer.name
142
98
 
143
- const renderer = createSubIndicatorRenderer({ indicatorId: newIndicatorId, paneId })
144
99
  chart.useRenderer(renderer, newParams as Record<string, number | boolean | string>)
145
100
 
146
101
  this.mountScaleRenderer(chart, paneId, newIndicatorId, newScaleRendererName)
@@ -177,6 +132,19 @@ export class SubPaneManager {
177
132
  return this.entries.get(paneId)
178
133
  }
179
134
 
135
+ private createIndicatorRenderer(
136
+ chart: Chart,
137
+ paneId: string,
138
+ indicatorId: SubIndicatorType,
139
+ params: Record<string, unknown>,
140
+ ): import('../plugin').RendererPlugin {
141
+ const definition = chart.getIndicatorScheduler().getIndicatorMetadata(indicatorId)
142
+ if (!definition) {
143
+ throw new Error(`[SubPaneManager] Unknown indicator: ${indicatorId}`)
144
+ }
145
+ return createSubIndicatorRenderer({ indicatorId, paneId, definition, params })
146
+ }
147
+
180
148
  getAll(): SubPaneEntry[] {
181
149
  return Array.from(this.entries.values())
182
150
  }
@@ -203,116 +171,8 @@ export class SubPaneManager {
203
171
  params: Record<string, unknown>,
204
172
  ): void {
205
173
  const scheduler = chart.getIndicatorScheduler()
206
- switch (indicatorId) {
207
- case 'MACD':
208
- scheduler.updateMACDConfig(params as Partial<MACDSchedulerConfig>, paneId)
209
- break
210
- case 'RSI':
211
- scheduler.updateRSIConfig(params as Partial<RSISchedulerConfig>, paneId)
212
- break
213
- case 'CCI':
214
- scheduler.updateCCIConfig(params as Partial<CCISchedulerConfig>, paneId)
215
- break
216
- case 'STOCH':
217
- scheduler.updateSTOCHConfig(params as Partial<STOCHSchedulerConfig>, paneId)
218
- break
219
- case 'MOM':
220
- scheduler.updateMOMConfig(params as Partial<MOMSchedulerConfig>, paneId)
221
- break
222
- case 'WMSR':
223
- scheduler.updateWMSRConfig(params as Partial<WMSRSchedulerConfig>, paneId)
224
- break
225
- case 'KST':
226
- scheduler.updateKSTConfig(params as Partial<KSTSchedulerConfig>, paneId)
227
- break
228
- case 'FASTK':
229
- scheduler.updateFASTKConfig(params as Partial<FASTKSchedulerConfig>, paneId)
230
- break
231
- case 'ATR':
232
- console.log(`[ATR-SubPane] syncSchedulerConfig: paneId=${paneId} params=${JSON.stringify(params)}`)
233
- scheduler.updateATRConfig(params as Partial<ATRSchedulerConfig>, paneId)
234
- break
235
- case 'WMA':
236
- scheduler.updateWMAConfig(params as Partial<WMASchedulerConfig>, paneId)
237
- break
238
- case 'DEMA':
239
- scheduler.updateDEMAConfig(params as Partial<DEMASchedulerConfig>, paneId)
240
- break
241
- case 'TEMA':
242
- scheduler.updateTEMAConfig(params as Partial<TEMASchedulerConfig>, paneId)
243
- break
244
- case 'HMA':
245
- scheduler.updateHMAConfig(params as Partial<HMASchedulerConfig>, paneId)
246
- break
247
- case 'KAMA':
248
- scheduler.updateKAMAConfig(params as Partial<KAMASchedulerConfig>, paneId)
249
- break
250
- case 'SAR':
251
- scheduler.updateSARConfig(params as Partial<SARSchedulerConfig>, paneId)
252
- break
253
- case 'SUPERTREND':
254
- scheduler.updateSuperTrendConfig(params as Partial<SuperTrendSchedulerConfig>, paneId)
255
- break
256
- case 'KELTNER':
257
- scheduler.updateKeltnerConfig(params as Partial<KeltnerSchedulerConfig>, paneId)
258
- break
259
- case 'DONCHIAN':
260
- scheduler.updateDonchianConfig(params as Partial<DonchianSchedulerConfig>, paneId)
261
- break
262
- case 'ICHIMOKU':
263
- scheduler.updateIchimokuConfig(params as Partial<IchimokuSchedulerConfig>, paneId)
264
- break
265
- case 'ROC':
266
- scheduler.updateROCConfig(params as Partial<ROCSchedulerConfig>, paneId)
267
- break
268
- case 'TRIX':
269
- scheduler.updateTRIXConfig(params as Partial<TRIXSchedulerConfig>, paneId)
270
- break
271
- case 'HV':
272
- scheduler.updateHVConfig(params as Partial<HVSchedulerConfig>, paneId)
273
- break
274
- case 'PARKINSON':
275
- scheduler.updateParkinsonConfig(params as Partial<ParkinsonSchedulerConfig>, paneId)
276
- break
277
- case 'CHAIKIN_VOL':
278
- scheduler.updateChaikinVolConfig(params as Partial<ChaikinVolSchedulerConfig>, paneId)
279
- break
280
- case 'VMA':
281
- scheduler.updateVMAConfig(params as Partial<VMASchedulerConfig>, paneId)
282
- break
283
- case 'OBV':
284
- scheduler.updateOBVConfig(params as Partial<OBVSchedulerConfig>, paneId)
285
- break
286
- case 'PVT':
287
- scheduler.updatePVTConfig(params as Partial<PVTSchedulerConfig>, paneId)
288
- break
289
- case 'VWAP':
290
- scheduler.updateVWAPConfig(params as Partial<VWAPSchedulerConfig>, paneId)
291
- break
292
- case 'CMF':
293
- scheduler.updateCMFConfig(params as Partial<CMFSchedulerConfig>, paneId)
294
- break
295
- case 'MFI':
296
- scheduler.updateMFIConfig(params as Partial<MFISchedulerConfig>, paneId)
297
- break
298
- case 'PIVOT':
299
- scheduler.updatePivotConfig(params as Partial<PivotSchedulerConfig>, paneId)
300
- break
301
- case 'FIB':
302
- scheduler.updateFibConfig(params as Partial<FibSchedulerConfig>, paneId)
303
- break
304
- case 'STRUCTURE':
305
- scheduler.updateStructureConfig(params as Partial<StructureSchedulerConfig>, paneId)
306
- break
307
- case 'ZONES':
308
- scheduler.updateZonesConfig(params as Partial<ZonesSchedulerConfig>, paneId)
309
- break
310
- case 'VOLUME_PROFILE':
311
- scheduler.updateVolumeProfileConfig(params as Partial<VolumeProfileSchedulerConfig>, paneId)
312
- break
313
- case 'VOLUME':
314
- break
315
- }
174
+ const definition = scheduler.getIndicatorMetadata(indicatorId)
175
+ definition?.updateConfig?.(scheduler, params, paneId)
316
176
  }
317
177
 
318
178
  private mountScaleRenderer(chart: Chart, paneId: string, indicatorId: SubIndicatorType, scaleRendererName: string): void {
@@ -333,121 +193,21 @@ export class SubPaneManager {
333
193
 
334
194
  const opts = { axisWidth, paneId, yPaddingPx, getCrosshair }
335
195
 
336
- let renderer: import('../plugin').RendererPluginWithHost
337
- switch (indicatorId) {
338
- case 'VOLUME':
339
- renderer = createVolumeScaleRendererPlugin(opts)
340
- break
341
- case 'MACD':
342
- renderer = createMacdScaleRendererPlugin(opts)
343
- break
344
- case 'RSI':
345
- renderer = createRsiScaleRendererPlugin(opts)
346
- break
347
- case 'CCI':
348
- renderer = createCciScaleRendererPlugin(opts)
349
- break
350
- case 'STOCH':
351
- renderer = createStochScaleRendererPlugin(opts)
352
- break
353
- case 'MOM':
354
- renderer = createMomScaleRendererPlugin(opts)
355
- break
356
- case 'WMSR':
357
- renderer = createWmsrScaleRendererPlugin(opts)
358
- break
359
- case 'KST':
360
- renderer = createKstScaleRendererPlugin(opts)
361
- break
362
- case 'FASTK':
363
- renderer = createFastkScaleRendererPlugin(opts)
364
- break
365
- case 'ATR':
366
- renderer = createAtrScaleRendererPlugin(opts)
367
- break
368
- case 'WMA':
369
- renderer = createIndicatorScaleRendererPlugin({ ...opts, indicatorKey: 'wma', label: 'WMA', decimals: 2 })
370
- break
371
- case 'DEMA':
372
- renderer = createIndicatorScaleRendererPlugin({ ...opts, indicatorKey: 'dema', label: 'DEMA', decimals: 2 })
373
- break
374
- case 'TEMA':
375
- renderer = createIndicatorScaleRendererPlugin({ ...opts, indicatorKey: 'tema', label: 'TEMA', decimals: 2 })
376
- break
377
- case 'HMA':
378
- renderer = createIndicatorScaleRendererPlugin({ ...opts, indicatorKey: 'hma', label: 'HMA', decimals: 2 })
379
- break
380
- case 'KAMA':
381
- renderer = createIndicatorScaleRendererPlugin({ ...opts, indicatorKey: 'kama', label: 'KAMA', decimals: 2 })
382
- break
383
- case 'SAR':
384
- renderer = createIndicatorScaleRendererPlugin({ ...opts, indicatorKey: 'sar', label: 'SAR', decimals: 4 })
385
- break
386
- case 'SUPERTREND':
387
- renderer = createIndicatorScaleRendererPlugin({ ...opts, indicatorKey: 'supertrend', label: 'SuperTrend', decimals: 2 })
388
- break
389
- case 'KELTNER':
390
- renderer = createIndicatorScaleRendererPlugin({ ...opts, indicatorKey: 'keltner', label: 'Keltner', decimals: 2 })
391
- break
392
- case 'DONCHIAN':
393
- renderer = createIndicatorScaleRendererPlugin({ ...opts, indicatorKey: 'donchian', label: 'Donchian', decimals: 2 })
394
- break
395
- case 'ICHIMOKU':
396
- renderer = createIndicatorScaleRendererPlugin({ ...opts, indicatorKey: 'ichimoku', label: 'Ichimoku', decimals: 2 })
397
- break
398
- case 'ROC':
399
- renderer = createIndicatorScaleRendererPlugin({ ...opts, indicatorKey: 'roc', label: 'ROC', decimals: 2 })
400
- break
401
- case 'TRIX':
402
- renderer = createIndicatorScaleRendererPlugin({ ...opts, indicatorKey: 'trix', label: 'TRIX', decimals: 6 })
403
- break
404
- case 'HV':
405
- renderer = createIndicatorScaleRendererPlugin({ ...opts, indicatorKey: 'hv', label: 'HV', decimals: 2 })
406
- break
407
- case 'PARKINSON':
408
- renderer = createIndicatorScaleRendererPlugin({ ...opts, indicatorKey: 'parkinson', label: 'Parkinson', decimals: 2 })
409
- break
410
- case 'CHAIKIN_VOL':
411
- renderer = createIndicatorScaleRendererPlugin({ ...opts, indicatorKey: 'chaikinVol', label: 'ChaikinVol', decimals: 2 })
412
- break
413
- case 'VMA':
414
- renderer = createIndicatorScaleRendererPlugin({ ...opts, indicatorKey: 'vma', label: 'VMA', decimals: 0 })
415
- break
416
- case 'OBV':
417
- renderer = createIndicatorScaleRendererPlugin({ ...opts, indicatorKey: 'obv', label: 'OBV', decimals: 0 })
418
- break
419
- case 'PVT':
420
- renderer = createIndicatorScaleRendererPlugin({ ...opts, indicatorKey: 'pvt', label: 'PVT', decimals: 0 })
421
- break
422
- case 'VWAP':
423
- renderer = createIndicatorScaleRendererPlugin({ ...opts, indicatorKey: 'vwap', label: 'VWAP', decimals: 2 })
424
- break
425
- case 'CMF':
426
- renderer = createIndicatorScaleRendererPlugin({ ...opts, indicatorKey: 'cmf', label: 'CMF', decimals: 4 })
427
- break
428
- case 'MFI':
429
- renderer = createIndicatorScaleRendererPlugin({ ...opts, indicatorKey: 'mfi', label: 'MFI', decimals: 2 })
430
- break
431
- case 'PIVOT':
432
- renderer = createIndicatorScaleRendererPlugin({ ...opts, indicatorKey: 'pivot', label: 'Pivot', decimals: 2 })
433
- break
434
- case 'FIB':
435
- renderer = createIndicatorScaleRendererPlugin({ ...opts, indicatorKey: 'fib', label: 'Fib', decimals: 4 })
436
- break
437
- case 'STRUCTURE':
438
- renderer = createIndicatorScaleRendererPlugin({ ...opts, indicatorKey: 'structure', label: 'Structure', decimals: 2 })
439
- break
440
- case 'ZONES':
441
- renderer = createIndicatorScaleRendererPlugin({ ...opts, indicatorKey: 'zones', label: 'Zones', decimals: 2 })
442
- break
443
- case 'VOLUME_PROFILE':
444
- renderer = createIndicatorScaleRendererPlugin({ ...opts, indicatorKey: 'volumeProfile', label: 'VP', decimals: 0 })
445
- break
446
- default:
447
- return
196
+ const definition = chart.getIndicatorScheduler().getIndicatorMetadata(indicatorId)
197
+ if (definition?.scaleRendererFactory) {
198
+ chart.useRenderer(definition.scaleRendererFactory({ ...opts, indicatorId }))
199
+ return
448
200
  }
449
201
 
450
- chart.useRenderer(renderer)
202
+ if (definition?.scale) {
203
+ chart.useRenderer(createIndicatorScaleRendererPlugin({
204
+ ...opts,
205
+ indicatorKey: definition.scale.indicatorKey ?? definition.name,
206
+ label: definition.scale.label ?? definition.displayName,
207
+ decimals: definition.scale.decimals,
208
+ }))
209
+ return
210
+ }
451
211
  }
452
212
 
453
213
  private mountPaneTitleRenderer(chart: Chart, paneId: string, indicatorId: SubIndicatorType, params: Record<string, unknown>): void {
@@ -0,0 +1,84 @@
1
+ import { afterEach, describe, expect, it, vi } from 'vitest'
2
+ import { SemanticChartController, __setDataFetcher, type SemanticChartAdapter } from '../controller'
3
+ import type { SemanticChartConfig } from '../types'
4
+
5
+ function createConfig(indicators: SemanticChartConfig['indicators']): SemanticChartConfig {
6
+ return {
7
+ version: '1.0.0',
8
+ data: {
9
+ source: 'baostock',
10
+ symbol: '600000',
11
+ exchange: 'SH',
12
+ startDate: '2025-01-01',
13
+ endDate: '2025-01-02',
14
+ period: 'daily',
15
+ adjust: 'qfq',
16
+ },
17
+ indicators,
18
+ }
19
+ }
20
+
21
+ function createChartAdapter(): SemanticChartAdapter {
22
+ return {
23
+ updateData: vi.fn(),
24
+ updateRendererConfig: vi.fn(),
25
+ addIndicator: vi.fn((definitionId: string) => definitionId),
26
+ removeIndicator: vi.fn(() => true),
27
+ enableMainIndicator: vi.fn(() => true),
28
+ disableMainIndicator: vi.fn(() => true),
29
+ clearSubPanes: vi.fn(),
30
+ createSubPane: vi.fn(() => true),
31
+ clearCustomMarkers: vi.fn(),
32
+ updateCustomMarkers: vi.fn(),
33
+ }
34
+ }
35
+
36
+ describe('SemanticChartController', () => {
37
+ afterEach(() => {
38
+ __setDataFetcher(null)
39
+ })
40
+
41
+ it('routes semantic sub indicators through registered definitions', async () => {
42
+ __setDataFetcher(vi.fn(async () => []))
43
+ const chart = createChartAdapter()
44
+ const controller = new SemanticChartController(chart)
45
+
46
+ const result = await controller.applyConfig(
47
+ createConfig({
48
+ sub: [
49
+ { type: 'VOLUME', enabled: true },
50
+ { type: 'RSI', enabled: true, params: { period1: 7 } },
51
+ { type: 'MACD', enabled: false, params: { fast: 8 } },
52
+ ],
53
+ }),
54
+ )
55
+
56
+ expect(result).toEqual({ success: true })
57
+ expect(chart.clearSubPanes).toHaveBeenCalledTimes(1)
58
+ expect(chart.createSubPane).toHaveBeenCalledTimes(2)
59
+ expect(chart.createSubPane).toHaveBeenCalledWith('VOLUME_0', 'VOLUME', undefined)
60
+ expect(chart.createSubPane).toHaveBeenCalledWith('RSI_0', 'RSI', { period1: 7 })
61
+ })
62
+
63
+ it('routes semantic main indicators through chart main indicator API', async () => {
64
+ __setDataFetcher(vi.fn(async () => []))
65
+ const chart = createChartAdapter()
66
+ const controller = new SemanticChartController(chart)
67
+
68
+ const result = await controller.applyConfig(
69
+ createConfig({
70
+ main: [
71
+ { type: 'BOLL', enabled: true, params: { period: 21, multiplier: 2.5 } },
72
+ { type: 'MA', enabled: false, params: { periods: [5, 20] } },
73
+ ],
74
+ }),
75
+ )
76
+
77
+ expect(result).toEqual({ success: true })
78
+ expect(chart.addIndicator).toHaveBeenCalledWith('BOLL', 'main', { period: 21, multiplier: 2.5 })
79
+ expect(chart.removeIndicator).toHaveBeenCalledWith('MA')
80
+ expect(chart.enableMainIndicator).not.toHaveBeenCalled()
81
+ expect(chart.disableMainIndicator).not.toHaveBeenCalled()
82
+ expect(chart.updateRendererConfig).not.toHaveBeenCalledWith('boll', expect.anything())
83
+ })
84
+ })
@@ -1,6 +1,9 @@
1
1
  import { EventBus } from '../plugin/EventBus'
2
2
  import type { CustomMarkerEntity } from '../engine/marker/registry'
3
3
  import { SemanticConfigValidator } from './validator'
4
+ import { getBuiltinIndicatorDefinitions } from '../engine/indicators/registerBuiltins'
5
+ import { getRegisteredIndicatorDefinition } from '../engine/indicators/indicatorDefinitionRegistry'
6
+ import type { IndicatorMetadata } from '../engine/indicators/indicatorMetadata'
4
7
  import type {
5
8
  SemanticChartConfig,
6
9
  ApplyResult,
@@ -27,6 +30,21 @@ export type DataFetcher = (
27
30
 
28
31
  let _dataFetcher: DataFetcher | null = null
29
32
 
33
+ function normalizeIndicatorId(id: string): string {
34
+ return id.trim().toLowerCase().replace(/[^a-z0-9]/g, '')
35
+ }
36
+
37
+ function getSemanticIndicatorDefinition(type: string): IndicatorMetadata | undefined {
38
+ const registered = getRegisteredIndicatorDefinition(type)
39
+ if (registered) return registered
40
+
41
+ const normalizedType = normalizeIndicatorId(type)
42
+ return getBuiltinIndicatorDefinitions().find((definition) => {
43
+ const candidates = [definition.name, definition.displayName, ...(definition.aliases ?? [])]
44
+ return candidates.some((candidate) => normalizeIndicatorId(candidate) === normalizedType)
45
+ })
46
+ }
47
+
30
48
  export function __setDataFetcher(fetcher: DataFetcher | null): void {
31
49
  _dataFetcher = fetcher
32
50
  }
@@ -44,6 +62,10 @@ async function getDataFetcher(): Promise<DataFetcher> {
44
62
  export interface SemanticChartAdapter {
45
63
  updateData(data: ReadonlyArray<KLineData>): void
46
64
  updateRendererConfig(name: string, config: Record<string, unknown>): void
65
+ addIndicator?(definitionId: string, role: 'main' | 'sub', params?: Record<string, unknown>): string | null
66
+ removeIndicator?(instanceId: string): boolean
67
+ enableMainIndicator?(indicatorId: string, params?: Record<string, number | boolean | string>): boolean
68
+ disableMainIndicator?(indicatorId: string): boolean
47
69
  clearSubPanes(): void
48
70
  createSubPane(paneId: string, indicatorId: CoreSubIndicatorType, params?: Record<string, unknown>): boolean
49
71
  clearCustomMarkers(): void
@@ -94,7 +116,35 @@ export class SemanticChartController {
94
116
  this.events.off(event, handler)
95
117
  }
96
118
 
119
+ /**
120
+ * 仅注册指标配置,不获取/更新数据。
121
+ * 用于 performanceTest10kKlines 等场景:数据由外部提供,语义控制器只管指标。
122
+ */
123
+ applyIndicatorsOnly(config: SemanticChartConfig): ApplyResult {
124
+ try {
125
+ if (config.indicators) {
126
+ this.applyIndicators(config.indicators.main, config.indicators.sub)
127
+ }
128
+ if (config.markers) {
129
+ this.applyMarkers(config.markers.customMarkers, config.data.period)
130
+ }
131
+ this.events.emit('config:ready', undefined)
132
+ return { success: true }
133
+ } catch (error) {
134
+ this.events.emit('config:error', error)
135
+ return {
136
+ success: false,
137
+ errors: [error instanceof Error ? error.message : String(error)],
138
+ }
139
+ }
140
+ }
141
+
97
142
  private async doApplyConfig(config: SemanticChartConfig): Promise<void> {
143
+ // 先注册指标(同步),确保 scheduler 首次 applyResults 时指标已在 registry
144
+ if (config.indicators) {
145
+ this.applyIndicators(config.indicators.main, config.indicators.sub)
146
+ }
147
+
98
148
  const fetcher = await getDataFetcher()
99
149
  const data = await fetcher(config.data.source, {
100
150
  symbol: config.data.symbol,
@@ -105,10 +155,6 @@ export class SemanticChartController {
105
155
  })
106
156
  this.chart.updateData(data)
107
157
 
108
- if (config.indicators) {
109
- this.applyIndicators(config.indicators.main, config.indicators.sub)
110
- }
111
-
112
158
  if (config.markers) {
113
159
  this.applyMarkers(config.markers.customMarkers, config.data.period)
114
160
  }
@@ -121,21 +167,24 @@ export class SemanticChartController {
121
167
  private applyIndicators(main?: MainIndicatorConfig[], sub?: SubIndicatorConfig[]): void {
122
168
  if (main) {
123
169
  for (const indicator of main) {
124
- if (!indicator.enabled) continue
125
- switch (indicator.type) {
126
- case 'MA':
127
- this.applyMAIndicator(indicator)
128
- break
129
- case 'BOLL':
130
- this.applyBOLLIndicator(indicator)
131
- break
132
- case 'EXPMA':
133
- this.applyEXPMAIndicator(indicator)
134
- break
135
- case 'ENE':
136
- this.applyENEIndicator(indicator)
137
- break
170
+ if (!indicator.enabled) {
171
+ if (!this.chart.removeIndicator?.(indicator.type)) {
172
+ this.chart.disableMainIndicator?.(indicator.type)
173
+ }
174
+ continue
175
+ }
176
+ const added = this.chart.addIndicator?.(indicator.type, 'main', indicator.params as Record<string, unknown>)
177
+ if (added) {
178
+ continue
179
+ }
180
+ const enabled = this.chart.enableMainIndicator?.(
181
+ indicator.type,
182
+ indicator.params as Record<string, number | boolean | string>,
183
+ )
184
+ if (enabled) {
185
+ continue
138
186
  }
187
+ getSemanticIndicatorDefinition(indicator.type)?.semantic?.apply?.(this.chart, indicator)
139
188
  }
140
189
  }
141
190
 
@@ -148,57 +197,12 @@ export class SemanticChartController {
148
197
  }
149
198
  }
150
199
 
151
- private applyMAIndicator(indicator: { type: 'MA'; enabled: boolean; params?: { periods: number[] } }): void {
152
- const periods = indicator.params?.periods || [5, 10, 20, 30, 60]
153
- const maFlags: { ma5?: boolean; ma10?: boolean; ma20?: boolean; ma30?: boolean; ma60?: boolean } = {}
154
- for (const p of periods) {
155
- if (p === 5) maFlags.ma5 = true
156
- else if (p === 10) maFlags.ma10 = true
157
- else if (p === 20) maFlags.ma20 = true
158
- else if (p === 30) maFlags.ma30 = true
159
- else if (p === 60) maFlags.ma60 = true
160
- }
161
- this.chart.updateRendererConfig('ma', maFlags)
162
- }
163
-
164
- private applyBOLLIndicator(indicator: {
165
- type: 'BOLL'
166
- enabled: boolean
167
- params?: { period?: number; multiplier?: number }
168
- }): void {
169
- this.chart.updateRendererConfig('boll', {
170
- period: indicator.params?.period || 20,
171
- multiplier: indicator.params?.multiplier || 2,
172
- })
173
- }
174
-
175
- private applyEXPMAIndicator(indicator: {
176
- type: 'EXPMA'
177
- enabled: boolean
178
- params?: { fastPeriod?: number; slowPeriod?: number }
179
- }): void {
180
- this.chart.updateRendererConfig('expma', {
181
- fastPeriod: indicator.params?.fastPeriod || 12,
182
- slowPeriod: indicator.params?.slowPeriod || 50,
183
- })
184
- }
185
-
186
- private applyENEIndicator(indicator: {
187
- type: 'ENE'
188
- enabled: boolean
189
- params?: { period?: number; deviation?: number }
190
- }): void {
191
- this.chart.updateRendererConfig('ene', {
192
- period: indicator.params?.period || 10,
193
- deviation: indicator.params?.deviation || 11,
194
- })
195
- }
196
-
197
200
  private applySubIndicator(indicator: SubIndicatorConfig): void {
198
201
  if (!indicator.enabled) return
199
202
  const { type, params } = indicator
200
203
  const paneId = `${type}_0`
201
- const success = this.chart.createSubPane(paneId, type as CoreSubIndicatorType, params)
204
+ const indicatorId = type
205
+ const success = this.chart.createSubPane(paneId, indicatorId as CoreSubIndicatorType, params)
202
206
  if (!success) {
203
207
  console.warn(`[Semantic] Failed to create sub pane for ${type}`)
204
208
  }
package/src/version.ts CHANGED
@@ -1 +1 @@
1
- export const VERSION = "0.7.9"
1
+ export const VERSION = "0.7.10"