@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
@@ -0,0 +1,444 @@
1
+ import { describe, expect, it, vi } from 'vitest'
2
+ import type { IndicatorMetadata } from '../indicatorMetadata'
3
+ import { composeRenderStates, composeVisibleSubIndicatorStates, computeMainIndicatorPriceRange } from '../stateComposer'
4
+ import type { IndicatorSeriesBundle } from '../workerProtocol'
5
+ import '../registerBuiltins'
6
+ import { getRegisteredIndicatorDefinition } from '../indicatorDefinitionRegistry'
7
+
8
+ function createBundle(): IndicatorSeriesBundle {
9
+ return {
10
+ ma: { series: {}, enabledPeriods: [] },
11
+ boll: { series: [], params: {} as never },
12
+ expma: { series: [], params: {} as never },
13
+ ene: { series: [], params: {} as never },
14
+ rsi: { series: {}, enabledPeriods: [], params: {} as never },
15
+ cci: { series: [], params: {} as never },
16
+ stoch: { series: [], params: {} as never },
17
+ mom: { series: [], params: {} as never },
18
+ wmsr: { series: [], params: {} as never },
19
+ kst: { series: [], params: {} as never },
20
+ fastk: { series: [], params: {} as never },
21
+ macd: { series: [], params: {} as never },
22
+ atr: { series: [], params: {} as never },
23
+ wma: { series: [], params: {} as never },
24
+ dema: { series: [], params: {} as never },
25
+ tema: { series: [], params: {} as never },
26
+ hma: { series: [], params: {} as never },
27
+ kama: { series: [], params: {} as never },
28
+ sar: { series: [], params: {} as never },
29
+ supertrend: { series: [], params: {} as never },
30
+ keltner: { series: [], params: {} as never },
31
+ donchian: { series: [], params: {} as never },
32
+ ichimoku: { series: [], params: {} as never },
33
+ roc: { series: [], params: {} as never },
34
+ trix: { series: [], signalSeries: [], params: {} as never },
35
+ hv: { series: [], params: {} as never },
36
+ parkinson: { series: [], params: {} as never },
37
+ chaikinVol: { series: [], params: {} as never },
38
+ vma: { series: [], params: {} as never },
39
+ obv: { series: [], params: {} as never },
40
+ pvt: { series: [], params: {} as never },
41
+ vwap: { series: [], params: {} as never },
42
+ cmf: { series: [], params: {} as never },
43
+ mfi: { series: [], params: {} as never },
44
+ pivot: { series: [], params: {} as never },
45
+ fib: { series: [], params: {} as never },
46
+ structure: { series: { swings: [], breakouts: [] }, params: {} as never },
47
+ zones: { series: [], params: {} as never },
48
+ volumeProfile: { series: { bins: [], vah: 0, val: 0, poc: 0 }, params: {} as never },
49
+ _changed: [],
50
+ }
51
+ }
52
+
53
+ function createDefinition(range: { min: number; max: number } | null): IndicatorMetadata {
54
+ return {
55
+ name: 'test',
56
+ displayName: 'Test',
57
+ category: 'main',
58
+ stateKey: 'indicator:test:main',
59
+ defaultPaneId: 'main',
60
+ rendererFactory: vi.fn() as never,
61
+ mainPane: {
62
+ rendererName: 'test',
63
+ computePriceRange: vi.fn(() => range),
64
+ },
65
+ }
66
+ }
67
+
68
+ function createComposerDefinition(id: string, state: unknown): IndicatorMetadata {
69
+ return {
70
+ name: id,
71
+ displayName: id.toUpperCase(),
72
+ category: 'main',
73
+ stateKey: `indicator:${id}:main`,
74
+ defaultPaneId: 'main',
75
+ rendererFactory: vi.fn() as never,
76
+ mainPane: {
77
+ rendererName: id,
78
+ composeRenderState: vi.fn(() => state),
79
+ },
80
+ }
81
+ }
82
+
83
+ function createVisibleStateDefinition(id: string, state: unknown): IndicatorMetadata {
84
+ return {
85
+ name: id,
86
+ displayName: id.toUpperCase(),
87
+ category: 'oscillator',
88
+ stateKey: `indicator:${id}:sub_${id}`,
89
+ defaultPaneId: `sub_${id}`,
90
+ rendererFactory: vi.fn() as never,
91
+ visibleState: {
92
+ compose: vi.fn(() => state),
93
+ },
94
+ }
95
+ }
96
+
97
+ function getComposerMetadata(id: string): IndicatorMetadata | undefined {
98
+ return getRegisteredIndicatorDefinition(id)
99
+ }
100
+
101
+ describe('stateComposer', () => {
102
+ it('computes main indicator price range through metadata', () => {
103
+ const definitions = new Map<string, IndicatorMetadata>([
104
+ ['ma', createDefinition({ min: 10, max: 20 })],
105
+ ['boll', createDefinition({ min: 5, max: 30 })],
106
+ ])
107
+
108
+ const range = computeMainIndicatorPriceRange(
109
+ createBundle(),
110
+ { start: 1, end: 3 },
111
+ new Set(['ma', 'boll']),
112
+ (indicatorId) => definitions.get(indicatorId),
113
+ )
114
+
115
+ expect(range).toEqual({ min: 5, max: 30 })
116
+ expect(definitions.get('ma')?.mainPane?.computePriceRange).toHaveBeenCalledWith(createBundle(), { start: 1, end: 3 })
117
+ })
118
+
119
+ it('ignores inactive or missing main price range metadata', () => {
120
+ const definitions = new Map<string, IndicatorMetadata>([
121
+ ['ma', createDefinition(null)],
122
+ ['boll', { ...createDefinition({ min: 1, max: 2 }), mainPane: { rendererName: 'boll' } }],
123
+ ])
124
+
125
+ expect(
126
+ computeMainIndicatorPriceRange(
127
+ createBundle(),
128
+ { start: 0, end: 1 },
129
+ new Set(['ma', 'boll', 'missing']),
130
+ (indicatorId) => definitions.get(indicatorId),
131
+ ),
132
+ ).toBeNull()
133
+ })
134
+
135
+ it('composes main render states through metadata', () => {
136
+ const bundle = createBundle()
137
+ const timestamp = 1234
138
+ const visibleRange = { start: 1, end: 3 }
139
+ const definitions = new Map<string, IndicatorMetadata>([
140
+ ['ma', createComposerDefinition('ma', { timestamp, series: { 5: [undefined, 10, 12] }, enabledPeriods: [5], visibleMin: 10, visibleMax: 12 })],
141
+ ['boll', createComposerDefinition('boll', { timestamp, series: [], params: {}, visibleMin: 20, visibleMax: 30 })],
142
+ ['expma', createComposerDefinition('expma', { timestamp, series: [], params: {}, visibleMin: 7, visibleMax: 9 })],
143
+ ['ene', createComposerDefinition('ene', { timestamp, series: [], params: {}, visibleMin: 8, visibleMax: 11 })],
144
+ ])
145
+
146
+ const states = composeRenderStates(bundle, visibleRange, timestamp, (indicatorId) => definitions.get(indicatorId))
147
+
148
+ expect(states.ma.visibleMin).toBe(10)
149
+ expect(states.boll.visibleMax).toBe(30)
150
+ expect(states.expma.visibleMin).toBe(7)
151
+ expect(states.ene.visibleMax).toBe(11)
152
+ expect(definitions.get('ma')?.mainPane?.composeRenderState).toHaveBeenCalledWith(bundle, visibleRange, timestamp)
153
+ })
154
+
155
+ it('throws when main render state composer metadata is missing', () => {
156
+ const definition = { ...createDefinition(null), mainPane: { rendererName: 'ma' } }
157
+
158
+ expect(() => composeRenderStates(createBundle(), { start: 0, end: 1 }, 1, (id) => id === 'ma' ? definition : undefined)).toThrow(
159
+ '[StateComposer] Missing mainPane.composeRenderState for ma',
160
+ )
161
+ })
162
+
163
+
164
+
165
+
166
+
167
+
168
+
169
+
170
+
171
+ it('applies symmetric abs padding for MOM via metadata composer', () => {
172
+ const bundle = createBundle()
173
+ bundle.mom.series = [undefined, -2, 4]
174
+ bundle.mom.params = { period: 10, showMOM: true } as never
175
+ const timestamp = 1000
176
+ const visibleRange = { start: 1, end: 3 }
177
+
178
+ const states = composeVisibleSubIndicatorStates(bundle, visibleRange, timestamp, { mom: true }, getComposerMetadata)
179
+
180
+ expect(states.mom.visibleMin).toBe(-2)
181
+ expect(states.mom.visibleMax).toBe(4)
182
+ expect(states.mom.valueMin).toBeCloseTo(-2.4)
183
+ expect(states.mom.valueMax).toBeCloseTo(4.4)
184
+ })
185
+
186
+ it('applies range padding for KST via metadata composer', () => {
187
+ const bundle = createBundle()
188
+ bundle.kst.series = [{ kst: -3, signal: 5 }]
189
+ bundle.kst.params = { roc1: 10, roc2: 15, roc3: 20, roc4: 30, signalPeriod: 9, showKST: true, showSignal: true } as never
190
+ const timestamp = 1000
191
+ const visibleRange = { start: 0, end: 1 }
192
+
193
+ const states = composeVisibleSubIndicatorStates(bundle, visibleRange, timestamp, { kst: true }, getComposerMetadata)
194
+
195
+ expect(states.kst.visibleMin).toBe(-3)
196
+ expect(states.kst.visibleMax).toBe(5)
197
+ expect(states.kst.valueMin).toBeCloseTo(-3.8)
198
+ expect(states.kst.valueMax).toBeCloseTo(5.8)
199
+ })
200
+
201
+ it('applies non-negative upper padding for ATR via metadata composer', () => {
202
+ const bundle = createBundle()
203
+ bundle.atr.series = [undefined, 1, 5]
204
+ bundle.atr.params = { period: 14, showATR: true } as never
205
+ const timestamp = 1000
206
+ const visibleRange = { start: 1, end: 3 }
207
+
208
+ const states = composeVisibleSubIndicatorStates(bundle, visibleRange, timestamp, { atr: true }, getComposerMetadata)
209
+
210
+ expect(states.atr.visibleMin).toBe(1)
211
+ expect(states.atr.visibleMax).toBe(5)
212
+ expect(states.atr.valueMin).toBe(0)
213
+ expect(states.atr.valueMax).toBeCloseTo(5.5)
214
+ })
215
+
216
+ it('combines series and signalSeries extremes for TRIX via metadata composer', () => {
217
+ const bundle = createBundle()
218
+ bundle.trix.series = [undefined, 1, 3]
219
+ bundle.trix.signalSeries = [100, -2, 2]
220
+ bundle.trix.params = { period: 15, signalPeriod: 9, showTRIX: true, showSignal: true } as never
221
+ const timestamp = 1000
222
+ const visibleRange = { start: 1, end: 3 }
223
+
224
+ const states = composeVisibleSubIndicatorStates(bundle, visibleRange, timestamp, { trix: true }, getComposerMetadata)
225
+
226
+ expect(states.trix.visibleMin).toBe(-2)
227
+ expect(states.trix.visibleMax).toBe(3)
228
+ expect(states.trix.valueMin).toBeCloseTo(-2.25)
229
+ expect(states.trix.valueMax).toBeCloseTo(3.25)
230
+ expect((states.trix as any).signalSeries).toBe(bundle.trix.signalSeries)
231
+ })
232
+
233
+ it('applies symmetric abs padding for MACD via metadata composer', () => {
234
+ const bundle = createBundle()
235
+ bundle.macd.series = [{ dif: -2, dea: 1, macd: 4 }]
236
+ bundle.macd.params = { fastPeriod: 12, slowPeriod: 26, signalPeriod: 9, showDIF: true, showDEA: true, showBAR: true } as never
237
+ const timestamp = 1000
238
+ const visibleRange = { start: 0, end: 1 }
239
+
240
+ const states = composeVisibleSubIndicatorStates(bundle, visibleRange, timestamp, { macd: true }, getComposerMetadata)
241
+
242
+ expect(states.macd.visibleMin).toBe(-2)
243
+ expect(states.macd.visibleMax).toBe(4)
244
+ expect(states.macd.valueMin).toBeCloseTo(-2.4)
245
+ expect(states.macd.valueMax).toBeCloseTo(4.4)
246
+ })
247
+
248
+ it('sets MACD latestValues via metadata composer', () => {
249
+ const bundle = createBundle()
250
+ bundle.macd.series = [{ dif: -2, dea: 1, macd: 4 }, { dif: -1, dea: 2, macd: 5 }]
251
+ bundle.macd.params = { fastPeriod: 12, slowPeriod: 26, signalPeriod: 9, showDIF: true, showDEA: true, showBAR: true } as never
252
+ const timestamp = 1000
253
+ const visibleRange = { start: 0, end: 2 }
254
+
255
+ const states = composeVisibleSubIndicatorStates(bundle, visibleRange, timestamp, { macd: true }, getComposerMetadata)
256
+
257
+ expect(states.macd.latestValues).toEqual({ dif: -1, dea: 2, macd: 5 })
258
+ })
259
+
260
+ it('preserves empty MACD state when MACD is inactive via metadata composer', () => {
261
+ const bundle = createBundle()
262
+ bundle.macd.series = [{ dif: -2, dea: 1, macd: 4 }]
263
+ bundle.macd.params = { fastPeriod: 12, slowPeriod: 26, signalPeriod: 9, showDIF: true, showDEA: true, showBAR: true } as never
264
+ const timestamp = 1000
265
+ const visibleRange = { start: 0, end: 1 }
266
+
267
+ const states = composeVisibleSubIndicatorStates(bundle, visibleRange, timestamp, { macd: false }, getComposerMetadata)
268
+
269
+ expect(states.macd.valueMin).toBe(-Infinity)
270
+ expect(states.macd.valueMax).toBe(Infinity)
271
+ expect(states.macd.series).toBe(bundle.macd.series)
272
+ expect(states.macd.params).toBe(bundle.macd.params)
273
+ expect(states.macd.timestamp).toBe(timestamp)
274
+ expect(states.macd.latestValues).toBeUndefined()
275
+ })
276
+
277
+
278
+
279
+ it('applies maFamilyBounds padding for value-point overlay via metadata composer (sar)', () => {
280
+ const bundle = createBundle()
281
+ bundle.sar.series = [{ value: 5, trend: 'up' as const }, { value: 15, trend: 'up' as const }]
282
+ bundle.sar.params = { period: 20, maxPeriod: 22, minPeriod: 2, af: 0.02, afMax: 0.2, showSAR: true } as never
283
+ const timestamp = 1000
284
+ const visibleRange = { start: 0, end: 2 }
285
+
286
+ const states = composeVisibleSubIndicatorStates(bundle, visibleRange, timestamp, { sar: true }, getComposerMetadata)
287
+
288
+ expect(states.sar.visibleMin).toBe(5)
289
+ expect(states.sar.visibleMax).toBe(15)
290
+ expect(states.sar.valueMin).toBeCloseTo(4.5)
291
+ expect(states.sar.valueMax).toBeCloseTo(15.5)
292
+ })
293
+
294
+ it('applies maFamilyBounds padding for band overlay via metadata composer (keltner)', () => {
295
+ const bundle = createBundle()
296
+ bundle.keltner.series = [{ upper: 20, middle: 15, lower: 10 }]
297
+ bundle.keltner.params = { period: 20, multiplier: 2, showKeltner: true, showMiddle: true } as never
298
+ const timestamp = 1000
299
+ const visibleRange = { start: 0, end: 1 }
300
+
301
+ const states = composeVisibleSubIndicatorStates(bundle, visibleRange, timestamp, { keltner: true }, getComposerMetadata)
302
+
303
+ expect(states.keltner.visibleMin).toBe(10)
304
+ expect(states.keltner.visibleMax).toBe(20)
305
+ expect(states.keltner.valueMin).toBeCloseTo(9.5)
306
+ expect(states.keltner.valueMax).toBeCloseTo(20.5)
307
+ })
308
+
309
+ it('applies exact extremes for pivot overlay via metadata composer', () => {
310
+ const bundle = createBundle()
311
+ bundle.pivot.series = [{ pp: 100, r1: 105, r2: 110, r3: 115, s1: 95, s2: 90, s3: 85 }]
312
+ bundle.pivot.params = { showPivot: true, showR1: true, showS1: true } as never
313
+ const timestamp = 1000
314
+ const visibleRange = { start: 0, end: 1 }
315
+
316
+ const states = composeVisibleSubIndicatorStates(bundle, visibleRange, timestamp, { pivot: true }, getComposerMetadata)
317
+
318
+ expect(states.pivot.visibleMin).toBe(85)
319
+ expect(states.pivot.visibleMax).toBe(115)
320
+ expect(states.pivot.valueMin).toBe(85)
321
+ expect(states.pivot.valueMax).toBe(115)
322
+ })
323
+
324
+ it('uses fixed unit range for structure overlay via metadata composer', () => {
325
+ const bundle = createBundle()
326
+ bundle.structure.series = { swings: [], breakouts: [] }
327
+ bundle.structure.params = { showStructure: true } as never
328
+ const timestamp = 1000
329
+ const visibleRange = { start: 0, end: 1 }
330
+
331
+ const states = composeVisibleSubIndicatorStates(bundle, visibleRange, timestamp, { structure: true }, getComposerMetadata)
332
+
333
+ expect(states.structure.valueMin).toBe(0)
334
+ expect(states.structure.valueMax).toBe(1)
335
+ expect(states.structure.visibleMin).toBe(0)
336
+ expect(states.structure.visibleMax).toBe(1)
337
+ })
338
+
339
+ it('derives volumeProfile range from bins and val/vah via metadata composer', () => {
340
+ const bundle = createBundle()
341
+ bundle.volumeProfile.series = {
342
+ bins: [{ priceLow: 95, priceHigh: 105, volume: 10, poc: false }],
343
+ vah: 103,
344
+ val: 97,
345
+ poc: 100,
346
+ }
347
+ bundle.volumeProfile.params = { showVolumeProfile: true } as never
348
+ const timestamp = 1000
349
+ const visibleRange = { start: 0, end: 1 }
350
+
351
+ const states = composeVisibleSubIndicatorStates(bundle, visibleRange, timestamp, { volumeProfile: true }, getComposerMetadata)
352
+
353
+ expect(states.volumeProfile.valueMin).toBe(95)
354
+ expect(states.volumeProfile.valueMax).toBe(105)
355
+ expect(states.volumeProfile.visibleMin).toBe(97)
356
+ expect(states.volumeProfile.visibleMax).toBe(103)
357
+ })
358
+
359
+ it('applies CCI clamp bounds via metadata composer', () => {
360
+ const bundle = createBundle()
361
+ bundle.cci.series = [-200, 100]
362
+ bundle.cci.params = { period: 14, showCCI: true } as never
363
+ const timestamp = 1000
364
+ const visibleRange = { start: 0, end: 2 }
365
+
366
+ const states = composeVisibleSubIndicatorStates(
367
+ bundle, visibleRange, timestamp, { cci: true },
368
+ getComposerMetadata,
369
+ )
370
+
371
+ expect(states.cci.visibleMin).toBe(-200)
372
+ expect(states.cci.visibleMax).toBe(100)
373
+ expect(states.cci.valueMin).toBe(-200)
374
+ expect(states.cci.valueMax).toBe(150)
375
+ })
376
+
377
+ it('applies CCI lower clamp when extremes are within bounds', () => {
378
+ const bundle = createBundle()
379
+ bundle.cci.series = [-50, 30]
380
+ bundle.cci.params = { period: 14, showCCI: true } as never
381
+ const timestamp = 1000
382
+ const visibleRange = { start: 0, end: 2 }
383
+
384
+ const states = composeVisibleSubIndicatorStates(
385
+ bundle, visibleRange, timestamp, { cci: true },
386
+ getComposerMetadata,
387
+ )
388
+
389
+ expect(states.cci.visibleMin).toBe(-50)
390
+ expect(states.cci.visibleMax).toBe(30)
391
+ expect(states.cci.valueMin).toBe(-150)
392
+ expect(states.cci.valueMax).toBe(150)
393
+ })
394
+
395
+ it('preserves empty CCI state when CCI is inactive', () => {
396
+ const bundle = createBundle()
397
+ bundle.cci.series = [-200, 100]
398
+ bundle.cci.params = { period: 14, showCCI: true } as never
399
+ const timestamp = 1000
400
+ const visibleRange = { start: 0, end: 2 }
401
+
402
+ const states = composeVisibleSubIndicatorStates(
403
+ bundle, visibleRange, timestamp, { cci: false },
404
+ getComposerMetadata,
405
+ )
406
+
407
+ expect(states.cci.valueMin).toBe(-150)
408
+ expect(states.cci.valueMax).toBe(150)
409
+ expect(states.cci.visibleMin).toBe(Infinity)
410
+ expect(states.cci.visibleMax).toBe(-Infinity)
411
+ expect(states.cci.series).toBe(bundle.cci.series)
412
+ expect(states.cci.params).toBe(bundle.cci.params)
413
+ expect(states.cci.timestamp).toBe(1000)
414
+ })
415
+
416
+ it('throws when registered indicator lacks visibleState.compose', () => {
417
+ const missingCompose = (id: string) =>
418
+ id === 'cci'
419
+ ? { name: 'cci', displayName: 'CCI', category: 'oscillator' as const, stateKey: '', defaultPaneId: '', rendererFactory: vi.fn() as never }
420
+ : undefined
421
+
422
+ expect(() =>
423
+ composeVisibleSubIndicatorStates(
424
+ createBundle(),
425
+ { start: 0, end: 1 },
426
+ 1000,
427
+ {},
428
+ missingCompose,
429
+ ),
430
+ ).toThrow('[StateComposer] Missing visibleState.compose for cci')
431
+ })
432
+
433
+ it('uses metadata path for all visible sub indicator states', () => {
434
+ const bundle = createBundle()
435
+ const timestamp = 1000
436
+ const visibleRange = { start: 0, end: 1 }
437
+ const states = composeVisibleSubIndicatorStates(
438
+ bundle, visibleRange, timestamp, {},
439
+ getComposerMetadata,
440
+ )
441
+ expect(states.cci.valueMin).toBe(-150)
442
+ expect(states.cci.valueMax).toBe(150)
443
+ })
444
+ })
@@ -1,15 +1,29 @@
1
- import type { IndicatorMetadata, IndicatorCategory, StateKey, RendererFactory } from './indicatorMetadata'
1
+ import type {
2
+ IndicatorMetadata,
3
+ IndicatorCategory,
4
+ StateKey,
5
+ RendererFactory,
6
+ ScaleRendererFactory,
7
+ IndicatorConfigUpdater,
8
+ } from './indicatorMetadata'
2
9
  import type { PluginHost } from '../../plugin'
3
10
 
4
- export interface IndicatorDefinitionConfig {
11
+ export type IndicatorDefinitionConfig<T = unknown> = {
5
12
  name: string
13
+ aliases?: readonly string[]
6
14
  displayName: string
7
15
  category: IndicatorCategory
8
16
  stateKey: StateKey
9
17
  defaultPaneId: string
10
18
  paneIdField?: keyof import('./workerProtocol').IndicatorConfigSnapshot
11
19
  allowMainPane?: boolean
20
+ scaleRendererFactory?: ScaleRendererFactory
21
+ scale?: IndicatorMetadata['scale']
22
+ updateConfig?: IndicatorConfigUpdater
12
23
  applyResult?: (host: PluginHost, state: unknown, paneId: string) => void
24
+ mainPane?: IndicatorMetadata['mainPane']
25
+ visibleState?: IndicatorMetadata['visibleState']
26
+ semantic?: IndicatorMetadata<T>['semantic']
13
27
  }
14
28
 
15
29
  type IndicatorDefinitionClass = {
@@ -18,6 +32,26 @@ type IndicatorDefinitionClass = {
18
32
  }
19
33
 
20
34
  const indicatorDefinitions = new Map<string, IndicatorMetadata>()
35
+ const indicatorDefinitionAliases = new Map<string, string>()
36
+
37
+ function normalizeIndicatorId(id: string): string {
38
+ return id.trim().toLowerCase().replace(/[^a-z0-9]/g, '')
39
+ }
40
+
41
+ function indexAlias(alias: string, name: string): void {
42
+ const normalized = normalizeIndicatorId(alias)
43
+ if (normalized) {
44
+ indicatorDefinitionAliases.set(normalized, name)
45
+ }
46
+ }
47
+
48
+ function removeAliasesFor(name: string): void {
49
+ for (const [alias, target] of indicatorDefinitionAliases) {
50
+ if (target === name) {
51
+ indicatorDefinitionAliases.delete(alias)
52
+ }
53
+ }
54
+ }
21
55
 
22
56
  /**
23
57
  * 标准类装饰器:在模块加载时收集指标定义
@@ -36,13 +70,21 @@ export function Indicator(config: IndicatorDefinitionConfig) {
36
70
  throw new Error(`[Indicator] '${config.name}' definition must expose static rendererFactory`)
37
71
  }
38
72
 
39
- indicatorDefinitions.set(config.name, {
73
+ const normalizedName = normalizeIndicatorId(config.name)
74
+ removeAliasesFor(normalizedName)
75
+
76
+ indicatorDefinitions.set(normalizedName, {
40
77
  ...config,
41
78
  rendererFactory,
42
79
  paneIdField: config.paneIdField,
43
80
  allowMainPane: config.allowMainPane,
44
81
  applyResult: config.applyResult,
45
82
  })
83
+ indexAlias(config.name, normalizedName)
84
+ indexAlias(config.displayName, normalizedName)
85
+ for (const alias of config.aliases ?? []) {
86
+ indexAlias(alias, normalizedName)
87
+ }
46
88
  })
47
89
 
48
90
  return value
@@ -54,9 +96,12 @@ export function getRegisteredIndicatorDefinitions(): readonly IndicatorMetadata[
54
96
  }
55
97
 
56
98
  export function getRegisteredIndicatorDefinition(name: string): IndicatorMetadata | undefined {
57
- return indicatorDefinitions.get(name)
99
+ const normalizedName = normalizeIndicatorId(name)
100
+ const canonicalName = indicatorDefinitionAliases.get(normalizedName) ?? normalizedName
101
+ return indicatorDefinitions.get(canonicalName)
58
102
  }
59
103
 
60
104
  export function clearRegisteredIndicatorDefinitionsForTest(): void {
61
105
  indicatorDefinitions.clear()
106
+ indicatorDefinitionAliases.clear()
62
107
  }
@@ -6,7 +6,23 @@
6
6
  */
7
7
 
8
8
  import type { PluginHost, RendererPluginWithHost } from '../../plugin'
9
- import type { IndicatorConfigSnapshot } from './workerProtocol'
9
+ import type { IndicatorConfigSnapshot, IndicatorSeriesBundle } from './workerProtocol'
10
+
11
+ export type IndicatorId = string
12
+
13
+ export interface IndicatorRendererOptions {
14
+ paneId: string
15
+ indicatorId: IndicatorId
16
+ params?: Record<string, unknown>
17
+ }
18
+
19
+ export interface IndicatorScaleRendererOptions {
20
+ paneId: string
21
+ indicatorId: IndicatorId
22
+ axisWidth: number
23
+ yPaddingPx: number
24
+ getCrosshair: () => { y: number; price: number; activePaneId: string | null } | null
25
+ }
10
26
 
11
27
  /**
12
28
  * 指标分类:主图/副图
@@ -23,7 +39,51 @@ export type StateKey = string | ((paneId: string) => string)
23
39
  /**
24
40
  * 渲染器工厂函数
25
41
  */
26
- export type RendererFactory = () => RendererPluginWithHost
42
+ export type RendererFactory = (options?: IndicatorRendererOptions) => RendererPluginWithHost
43
+
44
+ export type ScaleRendererFactory = (options: IndicatorScaleRendererOptions) => RendererPluginWithHost
45
+
46
+ export type IndicatorConfigUpdater = (
47
+ scheduler: unknown,
48
+ params: Record<string, unknown>,
49
+ paneId: string,
50
+ ) => void
51
+
52
+ export interface IndicatorSemanticChartAdapter {
53
+ updateRendererConfig(name: string, config: Record<string, unknown>): void
54
+ }
55
+
56
+ export interface IndicatorVisibleRange {
57
+ start: number
58
+ end: number
59
+ }
60
+
61
+ export interface IndicatorPriceRange {
62
+ min: number
63
+ max: number
64
+ }
65
+
66
+ export type IndicatorPriceRangeComputer = (
67
+ bundle: IndicatorSeriesBundle,
68
+ visibleRange: IndicatorVisibleRange,
69
+ ) => IndicatorPriceRange | null
70
+
71
+ export type IndicatorRenderStateComposer = (
72
+ bundle: IndicatorSeriesBundle,
73
+ visibleRange: IndicatorVisibleRange,
74
+ timestamp: number,
75
+ ) => unknown
76
+
77
+ export interface IndicatorVisibleStateComposeContext {
78
+ bundle: IndicatorSeriesBundle
79
+ visibleRange: IndicatorVisibleRange
80
+ timestamp: number
81
+ active: boolean
82
+ }
83
+
84
+ export type IndicatorVisibleStateComposer = (
85
+ context: IndicatorVisibleStateComposeContext,
86
+ ) => unknown
27
87
 
28
88
  /**
29
89
  * 指标元数据接口
@@ -35,6 +95,11 @@ export interface IndicatorMetadata<T = unknown> {
35
95
  */
36
96
  name: string
37
97
 
98
+ /**
99
+ * 可选别名,用于兼容 UI/API 中的大写 ID 或历史名称。
100
+ */
101
+ aliases?: readonly string[]
102
+
38
103
  /**
39
104
  * 显示名称(用于日志和调试)
40
105
  */
@@ -64,6 +129,20 @@ export interface IndicatorMetadata<T = unknown> {
64
129
  */
65
130
  rendererFactory: RendererFactory
66
131
 
132
+ /**
133
+ * 专用坐标轴渲染器工厂。未提供时可回退到 scale 通用配置。
134
+ */
135
+ scaleRendererFactory?: ScaleRendererFactory
136
+
137
+ /**
138
+ * 通用指标坐标轴配置。
139
+ */
140
+ scale?: {
141
+ indicatorKey?: string
142
+ label?: string
143
+ decimals?: number
144
+ }
145
+
67
146
  /**
68
147
  * 默认 pane ID
69
148
  * - 主图指标:'main'
@@ -77,6 +156,11 @@ export interface IndicatorMetadata<T = unknown> {
77
156
  */
78
157
  isEnabled?: (config: IndicatorConfigSnapshot) => boolean
79
158
 
159
+ /**
160
+ * 指标配置更新入口。内置和用户自定义指标都应通过 metadata 分发。
161
+ */
162
+ updateConfig?: IndicatorConfigUpdater
163
+
80
164
  /**
81
165
  * 将指标计算结果写入 StateStore
82
166
  * @param host - PluginHost
@@ -91,6 +175,27 @@ export interface IndicatorMetadata<T = unknown> {
91
175
  * - false/undefined:仅限副图显示
92
176
  */
93
177
  allowMainPane?: boolean
178
+
179
+ /**
180
+ * 主图指标启停相关配置。
181
+ */
182
+ mainPane?: {
183
+ rendererName: string
184
+ toActiveConfig?: (params: Record<string, unknown>, active: boolean) => Record<string, unknown> | null
185
+ computePriceRange?: IndicatorPriceRangeComputer
186
+ composeRenderState?: IndicatorRenderStateComposer
187
+ }
188
+
189
+ visibleState?: {
190
+ compose: IndicatorVisibleStateComposer
191
+ }
192
+
193
+ /**
194
+ * 语义配置应用入口。
195
+ */
196
+ semantic?: {
197
+ apply?: (chart: IndicatorSemanticChartAdapter, indicator: T) => void
198
+ }
94
199
  }
95
200
 
96
201
  /**