@363045841yyt/klinechart-core 0.7.12 → 0.8.1-alpha.1

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 (323) hide show
  1. package/dist/config/chartSettings.d.ts +0 -6
  2. package/dist/config/chartSettings.d.ts.map +1 -1
  3. package/dist/config/chartSettings.js +0 -1
  4. package/dist/config/chartSettings.js.map +1 -1
  5. package/dist/controllers/createChartController.d.ts.map +1 -1
  6. package/dist/controllers/createChartController.js +22 -0
  7. package/dist/controllers/createChartController.js.map +1 -1
  8. package/dist/controllers/createIndicatorSelectorController.d.ts.map +1 -1
  9. package/dist/controllers/createIndicatorSelectorController.js +4 -6
  10. package/dist/controllers/createIndicatorSelectorController.js.map +1 -1
  11. package/dist/controllers/index.d.ts +4 -4
  12. package/dist/controllers/index.d.ts.map +1 -1
  13. package/dist/controllers/index.js +3 -2
  14. package/dist/controllers/index.js.map +1 -1
  15. package/dist/controllers/types.d.ts +21 -0
  16. package/dist/controllers/types.d.ts.map +1 -1
  17. package/dist/data-fetchers/baostock.d.ts +3 -0
  18. package/dist/data-fetchers/baostock.d.ts.map +1 -0
  19. package/dist/data-fetchers/baostock.js +34 -0
  20. package/dist/data-fetchers/baostock.js.map +1 -0
  21. package/dist/data-fetchers/hundred-mock.d.ts +3 -0
  22. package/dist/data-fetchers/hundred-mock.d.ts.map +1 -0
  23. package/dist/data-fetchers/hundred-mock.js +30 -0
  24. package/dist/data-fetchers/hundred-mock.js.map +1 -0
  25. package/dist/data-fetchers/index.d.ts +5 -0
  26. package/dist/data-fetchers/index.d.ts.map +1 -0
  27. package/dist/data-fetchers/index.js +5 -0
  28. package/dist/data-fetchers/index.js.map +1 -0
  29. package/dist/data-fetchers/router.d.ts +3 -0
  30. package/dist/data-fetchers/router.d.ts.map +1 -0
  31. package/dist/data-fetchers/router.js +16 -0
  32. package/dist/data-fetchers/router.js.map +1 -0
  33. package/dist/data-fetchers/thousand-mock.d.ts +3 -0
  34. package/dist/data-fetchers/thousand-mock.d.ts.map +1 -0
  35. package/dist/data-fetchers/thousand-mock.js +29 -0
  36. package/dist/data-fetchers/thousand-mock.js.map +1 -0
  37. package/dist/engine/chart.d.ts +20 -2
  38. package/dist/engine/chart.d.ts.map +1 -1
  39. package/dist/engine/chart.js +81 -24
  40. package/dist/engine/chart.js.map +1 -1
  41. package/dist/engine/indicators/indicatorDefinitionRegistry.d.ts +3 -2
  42. package/dist/engine/indicators/indicatorDefinitionRegistry.d.ts.map +1 -1
  43. package/dist/engine/indicators/indicatorDefinitionRegistry.js +26 -1
  44. package/dist/engine/indicators/indicatorDefinitionRegistry.js.map +1 -1
  45. package/dist/engine/indicators/indicatorMetadata.d.ts +29 -2
  46. package/dist/engine/indicators/indicatorMetadata.d.ts.map +1 -1
  47. package/dist/engine/indicators/indicatorMetadata.js.map +1 -1
  48. package/dist/engine/indicators/indicatorRuntime.d.ts.map +1 -1
  49. package/dist/engine/indicators/indicatorRuntime.js +5 -4
  50. package/dist/engine/indicators/indicatorRuntime.js.map +1 -1
  51. package/dist/engine/indicators/scheduler.d.ts +16 -1
  52. package/dist/engine/indicators/scheduler.d.ts.map +1 -1
  53. package/dist/engine/indicators/scheduler.js +26 -7
  54. package/dist/engine/indicators/scheduler.js.map +1 -1
  55. package/dist/engine/renderers/Indicator/atr.d.ts +2 -1
  56. package/dist/engine/renderers/Indicator/atr.d.ts.map +1 -1
  57. package/dist/engine/renderers/Indicator/atr.js +5 -9
  58. package/dist/engine/renderers/Indicator/atr.js.map +1 -1
  59. package/dist/engine/renderers/Indicator/boll.d.ts +4 -1
  60. package/dist/engine/renderers/Indicator/boll.d.ts.map +1 -1
  61. package/dist/engine/renderers/Indicator/boll.js +22 -10
  62. package/dist/engine/renderers/Indicator/boll.js.map +1 -1
  63. package/dist/engine/renderers/Indicator/cci.d.ts +2 -1
  64. package/dist/engine/renderers/Indicator/cci.d.ts.map +1 -1
  65. package/dist/engine/renderers/Indicator/cci.js +6 -10
  66. package/dist/engine/renderers/Indicator/cci.js.map +1 -1
  67. package/dist/engine/renderers/Indicator/chaikinVol.d.ts +4 -1
  68. package/dist/engine/renderers/Indicator/chaikinVol.d.ts.map +1 -1
  69. package/dist/engine/renderers/Indicator/chaikinVol.js +16 -8
  70. package/dist/engine/renderers/Indicator/chaikinVol.js.map +1 -1
  71. package/dist/engine/renderers/Indicator/cmf.d.ts +4 -1
  72. package/dist/engine/renderers/Indicator/cmf.d.ts.map +1 -1
  73. package/dist/engine/renderers/Indicator/cmf.js +15 -8
  74. package/dist/engine/renderers/Indicator/cmf.js.map +1 -1
  75. package/dist/engine/renderers/Indicator/dema.d.ts +2 -0
  76. package/dist/engine/renderers/Indicator/dema.d.ts.map +1 -1
  77. package/dist/engine/renderers/Indicator/dema.js +18 -8
  78. package/dist/engine/renderers/Indicator/dema.js.map +1 -1
  79. package/dist/engine/renderers/Indicator/donchian.d.ts +4 -1
  80. package/dist/engine/renderers/Indicator/donchian.d.ts.map +1 -1
  81. package/dist/engine/renderers/Indicator/donchian.js +19 -8
  82. package/dist/engine/renderers/Indicator/donchian.js.map +1 -1
  83. package/dist/engine/renderers/Indicator/ene.d.ts +12 -1
  84. package/dist/engine/renderers/Indicator/ene.d.ts.map +1 -1
  85. package/dist/engine/renderers/Indicator/ene.js +22 -10
  86. package/dist/engine/renderers/Indicator/ene.js.map +1 -1
  87. package/dist/engine/renderers/Indicator/expma.d.ts +4 -1
  88. package/dist/engine/renderers/Indicator/expma.d.ts.map +1 -1
  89. package/dist/engine/renderers/Indicator/expma.js +21 -10
  90. package/dist/engine/renderers/Indicator/expma.js.map +1 -1
  91. package/dist/engine/renderers/Indicator/fastk.d.ts +2 -1
  92. package/dist/engine/renderers/Indicator/fastk.d.ts.map +1 -1
  93. package/dist/engine/renderers/Indicator/fastk.js +6 -10
  94. package/dist/engine/renderers/Indicator/fastk.js.map +1 -1
  95. package/dist/engine/renderers/Indicator/fib.d.ts +2 -0
  96. package/dist/engine/renderers/Indicator/fib.d.ts.map +1 -1
  97. package/dist/engine/renderers/Indicator/fib.js +25 -8
  98. package/dist/engine/renderers/Indicator/fib.js.map +1 -1
  99. package/dist/engine/renderers/Indicator/hma.d.ts +2 -0
  100. package/dist/engine/renderers/Indicator/hma.d.ts.map +1 -1
  101. package/dist/engine/renderers/Indicator/hma.js +18 -8
  102. package/dist/engine/renderers/Indicator/hma.js.map +1 -1
  103. package/dist/engine/renderers/Indicator/hv.d.ts +4 -1
  104. package/dist/engine/renderers/Indicator/hv.d.ts.map +1 -1
  105. package/dist/engine/renderers/Indicator/hv.js +17 -8
  106. package/dist/engine/renderers/Indicator/hv.js.map +1 -1
  107. package/dist/engine/renderers/Indicator/ichimoku.d.ts +4 -1
  108. package/dist/engine/renderers/Indicator/ichimoku.d.ts.map +1 -1
  109. package/dist/engine/renderers/Indicator/ichimoku.js +26 -8
  110. package/dist/engine/renderers/Indicator/ichimoku.js.map +1 -1
  111. package/dist/engine/renderers/Indicator/index.d.ts +27 -28
  112. package/dist/engine/renderers/Indicator/index.d.ts.map +1 -1
  113. package/dist/engine/renderers/Indicator/index.js +27 -28
  114. package/dist/engine/renderers/Indicator/index.js.map +1 -1
  115. package/dist/engine/renderers/Indicator/{indicatorData.d.ts → indicatorCatalog.d.ts} +1 -1
  116. package/dist/engine/renderers/Indicator/indicatorCatalog.d.ts.map +1 -0
  117. package/dist/engine/renderers/Indicator/{indicatorData.js → indicatorCatalog.js} +94 -406
  118. package/dist/engine/renderers/Indicator/indicatorCatalog.js.map +1 -0
  119. package/dist/engine/renderers/Indicator/kama.d.ts +2 -0
  120. package/dist/engine/renderers/Indicator/kama.d.ts.map +1 -1
  121. package/dist/engine/renderers/Indicator/kama.js +18 -8
  122. package/dist/engine/renderers/Indicator/kama.js.map +1 -1
  123. package/dist/engine/renderers/Indicator/keltner.d.ts +4 -1
  124. package/dist/engine/renderers/Indicator/keltner.d.ts.map +1 -1
  125. package/dist/engine/renderers/Indicator/keltner.js +19 -8
  126. package/dist/engine/renderers/Indicator/keltner.js.map +1 -1
  127. package/dist/engine/renderers/Indicator/kst.d.ts +2 -1
  128. package/dist/engine/renderers/Indicator/kst.d.ts.map +1 -1
  129. package/dist/engine/renderers/Indicator/kst.js +11 -10
  130. package/dist/engine/renderers/Indicator/kst.js.map +1 -1
  131. package/dist/engine/renderers/Indicator/ma.d.ts +4 -1
  132. package/dist/engine/renderers/Indicator/ma.d.ts.map +1 -1
  133. package/dist/engine/renderers/Indicator/ma.js +32 -9
  134. package/dist/engine/renderers/Indicator/ma.js.map +1 -1
  135. package/dist/engine/renderers/Indicator/macd.d.ts +1 -1
  136. package/dist/engine/renderers/Indicator/macd.d.ts.map +1 -1
  137. package/dist/engine/renderers/Indicator/macd.js +9 -10
  138. package/dist/engine/renderers/Indicator/macd.js.map +1 -1
  139. package/dist/engine/renderers/Indicator/mainIndicatorLegend.d.ts.map +1 -1
  140. package/dist/engine/renderers/Indicator/mainIndicatorLegend.js +38 -136
  141. package/dist/engine/renderers/Indicator/mainIndicatorLegend.js.map +1 -1
  142. package/dist/engine/renderers/Indicator/mfi.d.ts +4 -1
  143. package/dist/engine/renderers/Indicator/mfi.d.ts.map +1 -1
  144. package/dist/engine/renderers/Indicator/mfi.js +15 -8
  145. package/dist/engine/renderers/Indicator/mfi.js.map +1 -1
  146. package/dist/engine/renderers/Indicator/mom.d.ts +2 -1
  147. package/dist/engine/renderers/Indicator/mom.d.ts.map +1 -1
  148. package/dist/engine/renderers/Indicator/mom.js +6 -10
  149. package/dist/engine/renderers/Indicator/mom.js.map +1 -1
  150. package/dist/engine/renderers/Indicator/obv.d.ts +4 -1
  151. package/dist/engine/renderers/Indicator/obv.d.ts.map +1 -1
  152. package/dist/engine/renderers/Indicator/obv.js +14 -8
  153. package/dist/engine/renderers/Indicator/obv.js.map +1 -1
  154. package/dist/engine/renderers/Indicator/parkinson.d.ts +4 -1
  155. package/dist/engine/renderers/Indicator/parkinson.d.ts.map +1 -1
  156. package/dist/engine/renderers/Indicator/parkinson.js +17 -8
  157. package/dist/engine/renderers/Indicator/parkinson.js.map +1 -1
  158. package/dist/engine/renderers/Indicator/pivot.d.ts +2 -0
  159. package/dist/engine/renderers/Indicator/pivot.d.ts.map +1 -1
  160. package/dist/engine/renderers/Indicator/pivot.js +42 -8
  161. package/dist/engine/renderers/Indicator/pivot.js.map +1 -1
  162. package/dist/engine/renderers/Indicator/pvt.d.ts +4 -1
  163. package/dist/engine/renderers/Indicator/pvt.d.ts.map +1 -1
  164. package/dist/engine/renderers/Indicator/pvt.js +14 -8
  165. package/dist/engine/renderers/Indicator/pvt.js.map +1 -1
  166. package/dist/engine/renderers/Indicator/roc.d.ts +4 -1
  167. package/dist/engine/renderers/Indicator/roc.d.ts.map +1 -1
  168. package/dist/engine/renderers/Indicator/roc.js +15 -8
  169. package/dist/engine/renderers/Indicator/roc.js.map +1 -1
  170. package/dist/engine/renderers/Indicator/rsi.d.ts +2 -1
  171. package/dist/engine/renderers/Indicator/rsi.d.ts.map +1 -1
  172. package/dist/engine/renderers/Indicator/rsi.js +9 -10
  173. package/dist/engine/renderers/Indicator/rsi.js.map +1 -1
  174. package/dist/engine/renderers/Indicator/sar.d.ts +4 -1
  175. package/dist/engine/renderers/Indicator/sar.d.ts.map +1 -1
  176. package/dist/engine/renderers/Indicator/sar.js +17 -8
  177. package/dist/engine/renderers/Indicator/sar.js.map +1 -1
  178. package/dist/engine/renderers/Indicator/stoch.d.ts +2 -1
  179. package/dist/engine/renderers/Indicator/stoch.d.ts.map +1 -1
  180. package/dist/engine/renderers/Indicator/stoch.js +8 -10
  181. package/dist/engine/renderers/Indicator/stoch.js.map +1 -1
  182. package/dist/engine/renderers/Indicator/structure.d.ts +4 -1
  183. package/dist/engine/renderers/Indicator/structure.d.ts.map +1 -1
  184. package/dist/engine/renderers/Indicator/structure.js +21 -9
  185. package/dist/engine/renderers/Indicator/structure.js.map +1 -1
  186. package/dist/engine/renderers/Indicator/supertrend.d.ts +4 -1
  187. package/dist/engine/renderers/Indicator/supertrend.d.ts.map +1 -1
  188. package/dist/engine/renderers/Indicator/supertrend.js +18 -9
  189. package/dist/engine/renderers/Indicator/supertrend.js.map +1 -1
  190. package/dist/engine/renderers/Indicator/tema.d.ts +2 -0
  191. package/dist/engine/renderers/Indicator/tema.d.ts.map +1 -1
  192. package/dist/engine/renderers/Indicator/tema.js +18 -8
  193. package/dist/engine/renderers/Indicator/tema.js.map +1 -1
  194. package/dist/engine/renderers/Indicator/trix.d.ts +4 -1
  195. package/dist/engine/renderers/Indicator/trix.d.ts.map +1 -1
  196. package/dist/engine/renderers/Indicator/trix.js +29 -8
  197. package/dist/engine/renderers/Indicator/trix.js.map +1 -1
  198. package/dist/engine/renderers/Indicator/vma.d.ts +4 -1
  199. package/dist/engine/renderers/Indicator/vma.d.ts.map +1 -1
  200. package/dist/engine/renderers/Indicator/vma.js +15 -8
  201. package/dist/engine/renderers/Indicator/vma.js.map +1 -1
  202. package/dist/engine/renderers/Indicator/volumeProfile.d.ts +4 -1
  203. package/dist/engine/renderers/Indicator/volumeProfile.d.ts.map +1 -1
  204. package/dist/engine/renderers/Indicator/volumeProfile.js +27 -8
  205. package/dist/engine/renderers/Indicator/volumeProfile.js.map +1 -1
  206. package/dist/engine/renderers/Indicator/vwap.d.ts +4 -1
  207. package/dist/engine/renderers/Indicator/vwap.d.ts.map +1 -1
  208. package/dist/engine/renderers/Indicator/vwap.js +14 -8
  209. package/dist/engine/renderers/Indicator/vwap.js.map +1 -1
  210. package/dist/engine/renderers/Indicator/wma.d.ts +2 -0
  211. package/dist/engine/renderers/Indicator/wma.d.ts.map +1 -1
  212. package/dist/engine/renderers/Indicator/wma.js +18 -8
  213. package/dist/engine/renderers/Indicator/wma.js.map +1 -1
  214. package/dist/engine/renderers/Indicator/wmsr.d.ts +2 -1
  215. package/dist/engine/renderers/Indicator/wmsr.d.ts.map +1 -1
  216. package/dist/engine/renderers/Indicator/wmsr.js +6 -10
  217. package/dist/engine/renderers/Indicator/wmsr.js.map +1 -1
  218. package/dist/engine/renderers/Indicator/zones.d.ts +2 -0
  219. package/dist/engine/renderers/Indicator/zones.d.ts.map +1 -1
  220. package/dist/engine/renderers/Indicator/zones.js +23 -8
  221. package/dist/engine/renderers/Indicator/zones.js.map +1 -1
  222. package/dist/engine/renderers/paneTitle.d.ts +4 -10
  223. package/dist/engine/renderers/paneTitle.d.ts.map +1 -1
  224. package/dist/engine/renderers/paneTitle.js +30 -7
  225. package/dist/engine/renderers/paneTitle.js.map +1 -1
  226. package/dist/engine/renderers/subVolume.js +0 -3
  227. package/dist/engine/renderers/subVolume.js.map +1 -1
  228. package/dist/engine/subPaneManager.d.ts.map +1 -1
  229. package/dist/engine/subPaneManager.js +2 -1
  230. package/dist/engine/subPaneManager.js.map +1 -1
  231. package/dist/semantic/controller.d.ts +3 -14
  232. package/dist/semantic/controller.d.ts.map +1 -1
  233. package/dist/semantic/controller.js +9 -43
  234. package/dist/semantic/controller.js.map +1 -1
  235. package/dist/semantic/index.d.ts +3 -2
  236. package/dist/semantic/index.d.ts.map +1 -1
  237. package/dist/semantic/index.js +1 -1
  238. package/dist/semantic/index.js.map +1 -1
  239. package/dist/version.d.ts +1 -1
  240. package/dist/version.d.ts.map +1 -1
  241. package/dist/version.js +1 -1
  242. package/dist/version.js.map +1 -1
  243. package/package.json +7 -7
  244. package/src/config/chartSettings.ts +0 -1
  245. package/src/controllers/__tests__/indicatorSelector.test.ts +5 -4
  246. package/src/controllers/createChartController.ts +28 -1
  247. package/src/controllers/createIndicatorSelectorController.ts +4 -6
  248. package/src/controllers/index.ts +7 -6
  249. package/src/controllers/types.ts +30 -0
  250. package/src/data-fetchers/baostock.ts +34 -0
  251. package/src/data-fetchers/hundred-mock.ts +31 -0
  252. package/src/data-fetchers/index.ts +4 -0
  253. package/src/data-fetchers/router.ts +17 -0
  254. package/src/data-fetchers/thousand-mock.ts +30 -0
  255. package/src/engine/chart.ts +91 -23
  256. package/src/engine/indicators/__tests__/registerBuiltins.test.ts +4 -5
  257. package/src/engine/indicators/indicatorDefinitionRegistry.ts +35 -2
  258. package/src/engine/indicators/indicatorMetadata.ts +39 -2
  259. package/src/engine/indicators/indicatorRuntime.ts +5 -4
  260. package/src/engine/indicators/scheduler.ts +32 -8
  261. package/src/engine/renderers/Indicator/atr.ts +8 -11
  262. package/src/engine/renderers/Indicator/boll.ts +31 -10
  263. package/src/engine/renderers/Indicator/cci.ts +9 -14
  264. package/src/engine/renderers/Indicator/chaikinVol.ts +24 -8
  265. package/src/engine/renderers/Indicator/cmf.ts +23 -8
  266. package/src/engine/renderers/Indicator/dema.ts +27 -9
  267. package/src/engine/renderers/Indicator/donchian.ts +27 -9
  268. package/src/engine/renderers/Indicator/ene.ts +31 -10
  269. package/src/engine/renderers/Indicator/expma.ts +30 -10
  270. package/src/engine/renderers/Indicator/fastk.ts +9 -14
  271. package/src/engine/renderers/Indicator/fib.ts +28 -9
  272. package/src/engine/renderers/Indicator/hma.ts +27 -9
  273. package/src/engine/renderers/Indicator/hv.ts +26 -8
  274. package/src/engine/renderers/Indicator/ichimoku.ts +30 -9
  275. package/src/engine/renderers/Indicator/index.ts +27 -28
  276. package/src/engine/renderers/Indicator/indicatorCatalog.ts +346 -0
  277. package/src/engine/renderers/Indicator/kama.ts +27 -9
  278. package/src/engine/renderers/Indicator/keltner.ts +27 -9
  279. package/src/engine/renderers/Indicator/kst.ts +14 -18
  280. package/src/engine/renderers/Indicator/ma.ts +43 -9
  281. package/src/engine/renderers/Indicator/macd.ts +27 -32
  282. package/src/engine/renderers/Indicator/mainIndicatorLegend.ts +43 -162
  283. package/src/engine/renderers/Indicator/mfi.ts +23 -8
  284. package/src/engine/renderers/Indicator/mom.ts +9 -14
  285. package/src/engine/renderers/Indicator/obv.ts +22 -8
  286. package/src/engine/renderers/Indicator/parkinson.ts +26 -8
  287. package/src/engine/renderers/Indicator/pivot.ts +46 -9
  288. package/src/engine/renderers/Indicator/pvt.ts +22 -8
  289. package/src/engine/renderers/Indicator/roc.ts +24 -8
  290. package/src/engine/renderers/Indicator/rsi.ts +12 -16
  291. package/src/engine/renderers/Indicator/sar.ts +25 -9
  292. package/src/engine/renderers/Indicator/stoch.ts +11 -15
  293. package/src/engine/renderers/Indicator/structure.ts +31 -9
  294. package/src/engine/renderers/Indicator/supertrend.ts +26 -10
  295. package/src/engine/renderers/Indicator/tema.ts +27 -9
  296. package/src/engine/renderers/Indicator/trix.ts +38 -8
  297. package/src/engine/renderers/Indicator/vma.ts +23 -8
  298. package/src/engine/renderers/Indicator/volumeProfile.ts +39 -8
  299. package/src/engine/renderers/Indicator/vwap.ts +22 -8
  300. package/src/engine/renderers/Indicator/wma.ts +27 -9
  301. package/src/engine/renderers/Indicator/wmsr.ts +9 -14
  302. package/src/engine/renderers/Indicator/zones.ts +28 -9
  303. package/src/engine/renderers/__tests__/mainIndicatorLegend.renderer.test.ts +142 -79
  304. package/src/engine/renderers/paneTitle.ts +45 -19
  305. package/src/engine/renderers/subVolume.ts +0 -2
  306. package/src/engine/subPaneManager.ts +2 -1
  307. package/src/semantic/__tests__/controller.test.ts +19 -7
  308. package/src/semantic/controller.ts +9 -57
  309. package/src/semantic/index.ts +3 -2
  310. package/src/version.ts +1 -1
  311. package/dist/engine/renderers/Indicator/indicatorData.d.ts.map +0 -1
  312. package/dist/engine/renderers/Indicator/indicatorData.js.map +0 -1
  313. package/dist/engine/renderers/Indicator/macdLegend.d.ts +0 -13
  314. package/dist/engine/renderers/Indicator/macdLegend.d.ts.map +0 -1
  315. package/dist/engine/renderers/Indicator/macdLegend.js +0 -116
  316. package/dist/engine/renderers/Indicator/macdLegend.js.map +0 -1
  317. package/dist/engine/renderers/Indicator/subPaneConfig.d.ts +0 -16
  318. package/dist/engine/renderers/Indicator/subPaneConfig.d.ts.map +0 -1
  319. package/dist/engine/renderers/Indicator/subPaneConfig.js +0 -194
  320. package/dist/engine/renderers/Indicator/subPaneConfig.js.map +0 -1
  321. package/src/engine/renderers/Indicator/indicatorData.ts +0 -650
  322. package/src/engine/renderers/Indicator/macdLegend.ts +0 -141
  323. package/src/engine/renderers/Indicator/subPaneConfig.ts +0 -265
@@ -7,6 +7,8 @@ import { resolveStateKey } from '../../indicators/indicatorMetadata'
7
7
  import { createSparseVisibleStateComposer } from '../../indicators/visibleStateComposers'
8
8
  import type { IndicatorScheduler, VWAPSchedulerConfig } from '../../indicators/scheduler'
9
9
  import { calcVWAPData } from '../../indicators/calculators'
10
+ import type { TitleInfo } from '../../indicators/indicatorMetadata'
11
+ import type { KLineData } from '../../../types/price'
10
12
 
11
13
  const VWAP_COLOR = '#ec4899'
12
14
 
@@ -109,22 +111,34 @@ export function createVWAPRendererPlugin(options: { paneId?: string } = {}): Ren
109
111
  }
110
112
  }
111
113
 
114
+ export function getVWAPTitleInfo(
115
+ _data: KLineData[],
116
+ index: number | null,
117
+ _params: Record<string, number | boolean | string>,
118
+ host: PluginHost,
119
+ paneId: string,
120
+ ): TitleInfo | null {
121
+ if (index === null) return null
122
+ const state = host.getSharedState<VWAPRenderState>(createVWAPStateKey(paneId))
123
+ const value = state?.series[index]
124
+ if (value === undefined) return null
125
+
126
+ return {
127
+ name: 'VWAP',
128
+ params: [],
129
+ values: [{ label: 'VWAP', value, color: VWAP_COLOR }],
130
+ }
131
+ }
132
+
112
133
  @Indicator({
113
134
  name: 'vwap',
114
135
  displayName: 'VWAP',
115
136
  category: 'volume',
116
- stateKey: createVWAPStateKey,
117
137
  defaultPaneId: 'sub_VWAP',
118
138
  visibleState: { compose: createSparseVisibleStateComposer('vwap', EMPTY_VWAP_STATE) },
119
139
  scale: { indicatorKey: 'vwap', label: 'VWAP', decimals: 2 },
120
- updateConfig: (scheduler, params, paneId) => {
121
- (scheduler as IndicatorScheduler).updateIndicatorConfig('vwap', params, paneId)
122
- },
123
- applyResult: (host, state, paneId) => {
124
- host.setSharedState(createVWAPStateKey(paneId), state as any, 'indicator_scheduler')
125
- },
140
+ getTitleInfo: getVWAPTitleInfo,
126
141
  runtime: {
127
- configKey: 'vwap',
128
142
  defaultConfig: { sessionResetGapMs: 0, showVWAP: true },
129
143
  computeKey: 'calcVWAPData',
130
144
  compute: (data, c) => calcVWAPData(data, c.sessionResetGapMs),
@@ -1,9 +1,10 @@
1
1
  import type { RendererPluginWithHost, RenderContext, PluginHost } from '../../../plugin'
2
+ import type { KLineData } from '../../../types/price'
2
3
  import { RENDERER_PRIORITY } from '../../../plugin'
3
4
  import type { WMARenderState } from '../../indicators/wmaState'
4
5
  import { createWMAStateKey, EMPTY_WMA_STATE } from '../../indicators/wmaState'
5
6
  import { Indicator } from '../../indicators/indicatorDefinitionRegistry'
6
- import { resolveStateKey } from '../../indicators/indicatorMetadata'
7
+ import { resolveStateKey, type TitleInfo, type TitleValueItem, type GetTitleInfoFn } from '../../indicators/indicatorMetadata'
7
8
  import { createSparseVisibleStateComposer } from '../../indicators/visibleStateComposers'
8
9
  import type { IndicatorScheduler, WMASchedulerConfig } from '../../indicators/scheduler'
9
10
  import { calcWMAData } from '../../indicators/calculators'
@@ -121,23 +122,40 @@ export function createWMARendererPlugin(options: WMARendererOptions = {}): Rende
121
122
  }
122
123
  }
123
124
 
125
+ export const getWMATitleInfo: GetTitleInfoFn = (
126
+ _data: KLineData[],
127
+ index: number | null,
128
+ _params: Record<string, number | boolean | string>,
129
+ pluginHost: PluginHost,
130
+ paneId: string,
131
+ ): TitleInfo | null => {
132
+ if (index === null) return null
133
+
134
+ const stateKey = createWMAStateKey(paneId)
135
+ const state = pluginHost?.getSharedState<WMARenderState>(stateKey)
136
+ if (!state || state.visibleMin > state.visibleMax) return null
137
+
138
+ const value = state.series[index]
139
+ if (value === undefined) return null
140
+
141
+ return {
142
+ name: 'WMA',
143
+ params: [state.params.period],
144
+ values: [{ label: 'WMA', value, color: '#10b981' }],
145
+ }
146
+ }
147
+
124
148
  @Indicator({
125
149
  name: 'wma',
126
150
  displayName: 'WMA',
151
+ getTitleInfo: getWMATitleInfo,
127
152
  category: 'main',
128
- stateKey: createWMAStateKey,
129
153
  defaultPaneId: 'main',
130
154
  allowMainPane: true,
131
155
  mainPane: { rendererName: 'wma_main', toActiveConfig: (params, active) => ({ ...params, showWMA: active }) },
132
156
  visibleState: { compose: createSparseVisibleStateComposer('wma', EMPTY_WMA_STATE) },
133
157
  scale: { indicatorKey: 'wma', label: 'WMA', decimals: 2 },
134
- updateConfig: (scheduler, params, paneId) => {
135
- (scheduler as IndicatorScheduler).updateIndicatorConfig('wma', params, paneId)
136
- },
137
- applyResult: (host, state, paneId) => {
138
- host.setSharedState(createWMAStateKey(paneId), state as any, 'indicator_scheduler')
139
- },
140
- runtime: { configKey:'wma', defaultConfig:{period:10,showWMA:true}, computeKey:'calcWMAData', compute:(data,c)=>calcWMAData(data,c.period) },
158
+ runtime: { defaultConfig:{period:10,showWMA:true}, computeKey:'calcWMAData', compute:(data,c)=>calcWMAData(data,c.period) },
141
159
  })
142
160
  class WMADefinition {
143
161
  static rendererFactory = createWMARendererPlugin
@@ -10,6 +10,7 @@ import { resolveStateKey } from '../../indicators/indicatorMetadata'
10
10
  import type { IndicatorScheduler, WMSRSchedulerConfig } from '../../indicators/scheduler'
11
11
  import { createWmsrScaleRendererPlugin } from './scale/wmsr_scale'
12
12
  import { calcWMSRData } from '../../indicators/calculators'
13
+ import type { KLineData } from '../../../types/price'
13
14
 
14
15
  type LinePoint = { x: number; y: number }
15
16
 
@@ -293,14 +294,15 @@ function drawWMSRLineWithCanvas2D(
293
294
  * 获取 WMSR 标题信息(供 paneTitle 使用)
294
295
  */
295
296
  export function getWMSRTitleInfo(
296
- index: number,
297
- period: number,
297
+ _data: KLineData[],
298
+ index: number | null,
299
+ params: Record<string, number | boolean | string>,
298
300
  pluginHost: PluginHost,
299
- paneId: string = 'sub_WMSR',
300
- theme: 'light' | 'dark' = 'light',
301
- isAsiaMarket?: boolean
301
+ paneId: string,
302
302
  ): { name: string; params: number[]; values: Array<{ label: string; value: number; color: string }> } | null {
303
- const colors = resolveThemeColors(theme, isAsiaMarket)
303
+ if (index === null) return null
304
+ const period = (params.period as number) ?? 14
305
+ const colors = resolveThemeColors('light')
304
306
  const state = pluginHost.getSharedState<WMSRRenderState>(createWMSRStateKey(paneId))
305
307
  if (!state) return null
306
308
 
@@ -320,18 +322,11 @@ export function getWMSRTitleInfo(
320
322
  name: 'wmsr',
321
323
  displayName: 'WMSR',
322
324
  category: 'oscillator',
323
- stateKey: createWMSRStateKey,
324
325
  defaultPaneId: 'sub_WMSR',
325
326
  visibleState: { compose: createFixedRangeSparseVisibleStateComposer('wmsr', EMPTY_WMSR_STATE) },
326
327
  scaleRendererFactory: createWmsrScaleRendererPlugin,
327
- updateConfig: (scheduler, params, paneId) => {
328
- (scheduler as IndicatorScheduler).updateIndicatorConfig('wmsr', params, paneId)
329
- },
330
- applyResult: (host, state, paneId) => {
331
- host.setSharedState(createWMSRStateKey(paneId), state as any, 'indicator_scheduler')
332
- },
328
+ getTitleInfo: getWMSRTitleInfo,
333
329
  runtime: {
334
- configKey: 'wmsr',
335
330
  defaultConfig: { period: 14, showWMSR: true },
336
331
  computeKey: 'calcWMSRData',
337
332
  compute: (data, c) => calcWMSRData(data, c.period),
@@ -5,7 +5,7 @@ import type { ZonesRenderState } from '../../indicators/zonesState'
5
5
  import { createZonesStateKey, EMPTY_ZONES_STATE } from '../../indicators/zonesState'
6
6
  import { Indicator } from '../../indicators/indicatorDefinitionRegistry'
7
7
  import { createFixedUnitVisibleStateComposer } from '../../indicators/visibleStateComposers'
8
- import { resolveStateKey } from '../../indicators/indicatorMetadata'
8
+ import { resolveStateKey, type TitleInfo, type TitleValueItem, type GetTitleInfoFn } from '../../indicators/indicatorMetadata'
9
9
  import type { IndicatorScheduler, ZonesSchedulerConfig } from '../../indicators/scheduler'
10
10
  import { calcZonesData } from '../../indicators/calculators'
11
11
 
@@ -90,23 +90,42 @@ export function createZonesRendererPlugin(options: { paneId?: string } = {}): Re
90
90
  }
91
91
  }
92
92
 
93
+ export const getZonesTitleInfo: GetTitleInfoFn = (_data, index, _params, host, paneId) => {
94
+ if (index === null) return null
95
+
96
+ const stateKey = createZonesStateKey(paneId)
97
+ const state = host?.getSharedState<ZonesRenderState>(stateKey)
98
+ if (!state) return null
99
+
100
+ const activeZones = state.series.filter(
101
+ z => z.startIndex <= index && (z.endIndex === undefined || z.endIndex >= index)
102
+ )
103
+ if (activeZones.length === 0) return null
104
+
105
+ const values: TitleValueItem[] = activeZones.slice(0, 5).map(z => ({
106
+ label: z.kind,
107
+ value: z.high,
108
+ color: z.kind.includes('Bull') ? '#22c55e' : '#ef4444',
109
+ }))
110
+
111
+ return {
112
+ name: 'Zones',
113
+ params: [activeZones.length],
114
+ values,
115
+ }
116
+ }
117
+
93
118
  @Indicator({
94
119
  name: 'zones',
95
120
  displayName: 'Zones',
121
+ getTitleInfo: getZonesTitleInfo,
96
122
  category: 'main',
97
- stateKey: createZonesStateKey,
98
123
  defaultPaneId: 'main',
99
124
  allowMainPane: true,
100
125
  mainPane: { rendererName: 'zones_main', toActiveConfig: (params, active) => ({ ...params, showFVG: active, showOB: active, showFilledZones: active }) },
101
126
  scale: { indicatorKey: 'zones', label: 'Zones', decimals: 2 },
102
127
  visibleState: { compose: createFixedUnitVisibleStateComposer('zones', EMPTY_ZONES_STATE) },
103
- updateConfig: (scheduler, params, paneId) => {
104
- (scheduler as IndicatorScheduler).updateIndicatorConfig('zones', params, paneId)
105
- },
106
- applyResult: (host, state, paneId) => {
107
- host.setSharedState(createZonesStateKey(paneId), state as any, 'indicator_scheduler')
108
- },
109
- runtime: { configKey:'zones', defaultConfig:{showFVG:true,showOB:true,showFilledZones:true,obLookback:20}, computeKey:'calcZonesData', compute:(data,c)=>calcZonesData(data,c.obLookback,5,2,'close') },
128
+ runtime: { defaultConfig:{showFVG:true,showOB:true,showFilledZones:true,obLookback:20}, computeKey:'calcZonesData', compute:(data,c)=>calcZonesData(data,c.obLookback,5,2,'close') },
110
129
  })
111
130
  class ZonesDefinition {
112
131
  static rendererFactory = createZonesRendererPlugin
@@ -8,11 +8,13 @@ import { ENE_STATE_KEY } from '@/core/indicators/eneState'
8
8
  import type { PluginHost, RenderContext, RendererPluginWithHost } from '@/plugin'
9
9
  import type { KLineData } from '@/types/price'
10
10
  import type { Pane } from '@/core/layout/pane'
11
+ import type { GetTitleInfoFn, TitleInfo, TitleValueItem } from '@/engine/indicators/indicatorMetadata'
12
+ import type { IndicatorScheduler } from '@/engine/indicators/indicatorScheduler'
11
13
 
12
14
  // Type helper for tests - we know these methods exist on the implementation
13
15
  interface TestableLegendRenderer extends RendererPluginWithHost {
14
16
  draw: (context: RenderContext) => void
15
- getConfig: () => { yPaddingPx: number; indicators: Record<string, { enabled: boolean; params: Record<string, unknown> }> }
17
+ getConfig: () => { yPaddingPx: number }
16
18
  setConfig: (config: Record<string, unknown>) => void
17
19
  }
18
20
 
@@ -33,10 +35,73 @@ function createMockCanvasContext(): CanvasRenderingContext2D {
33
35
  } as unknown as CanvasRenderingContext2D
34
36
  }
35
37
 
38
+ /**
39
+ * Create a mock scheduler that returns indicator metadata with getTitleInfo.
40
+ * Keys are case-insensitive (matching real IndicatorScheduler behavior).
41
+ */
42
+ function createMockScheduler(
43
+ metadataMap: Record<string, { getTitleInfo: GetTitleInfoFn }>,
44
+ activeMainIndicators?: string[]
45
+ ): IndicatorScheduler {
46
+ const activeSet = new Set((activeMainIndicators ?? ['ma']).map((i: string) => i.toLowerCase()))
47
+ return {
48
+ getIndicatorMetadata: vi.fn((id: string) => metadataMap[id.toLowerCase()] ?? null),
49
+ getMainIndicators: vi.fn(() => Object.entries(metadataMap).map(([id, meta]) => ({
50
+ name: id,
51
+ getTitleInfo: meta.getTitleInfo,
52
+ category: 'main',
53
+ }))),
54
+ isMainIndicatorActive: vi.fn((id: string) => activeSet.has(id.toLowerCase())),
55
+ getMainIndicatorParams: vi.fn(() => ({})),
56
+ } as unknown as IndicatorScheduler
57
+ }
58
+
59
+ /**
60
+ * Create a mock getTitleInfo for MA that reads from shared state
61
+ */
62
+ function createMAGetTitleInfo(): GetTitleInfoFn {
63
+ return (data, index, params, host, paneId): TitleInfo => {
64
+ const state = host.getSharedState<MARenderState>(MA_STATE_KEY)
65
+ if (!state) return null
66
+
67
+ const ci = index ?? (state.series[5]?.length ?? 100) - 1
68
+ const values: TitleValueItem[] = []
69
+ for (const period of state.enabledPeriods) {
70
+ const v = state.series[period]?.[ci]
71
+ if (v !== undefined) {
72
+ values.push({
73
+ label: `MA${period}`,
74
+ value: v,
75
+ color: '#888888',
76
+ })
77
+ }
78
+ }
79
+ return { name: 'MA', values: values.length > 0 ? values : undefined }
80
+ }
81
+ }
82
+
83
+ /**
84
+ * Create simple mock getTitleInfo for BOLL/EXPMA/ENE
85
+ */
86
+ function createSimpleGetTitleInfo(name: string): GetTitleInfoFn {
87
+ return (): TitleInfo => ({
88
+ name,
89
+ params: [20, 2],
90
+ values: [
91
+ { label: 'MID', value: 100.00, color: '#FF0000' },
92
+ { label: 'UP', value: 120.00, color: '#00FF00' },
93
+ { label: 'DN', value: 80.00, color: '#0000FF' },
94
+ ],
95
+ })
96
+ }
97
+
36
98
  /**
37
99
  * 创建 mock PluginHost
38
100
  */
39
- function createMockPluginHost(state?: MARenderState): PluginHost {
101
+ function createMockPluginHost(
102
+ state?: MARenderState,
103
+ scheduler?: IndicatorScheduler
104
+ ): PluginHost {
40
105
  return {
41
106
  setSharedState: vi.fn(),
42
107
  getSharedState: vi.fn(<T>(key: string): T | undefined => {
@@ -59,6 +124,10 @@ function createMockPluginHost(state?: MARenderState): PluginHost {
59
124
  off: vi.fn(),
60
125
  once: vi.fn(),
61
126
  emit: vi.fn(),
127
+ getService: vi.fn((name: string) => {
128
+ if (name === 'indicatorScheduler') return scheduler
129
+ return undefined
130
+ }),
62
131
  } as unknown as PluginHost
63
132
  }
64
133
 
@@ -149,14 +218,9 @@ describe('createMainIndicatorLegendRendererPlugin', () => {
149
218
  expect(typeof plugin.onInstall).toBe('function')
150
219
  })
151
220
 
152
- it('should declare all indicator namespace keys', () => {
221
+ it('should not declare any namespace keys (individual renderers own their state)', () => {
153
222
  const plugin = createMainIndicatorLegendRendererPlugin({ yPaddingPx: 20 })
154
- expect(plugin.getDeclaredNamespaces()).toEqual([
155
- MA_STATE_KEY,
156
- BOLL_STATE_KEY,
157
- EXPMA_STATE_KEY,
158
- ENE_STATE_KEY,
159
- ])
223
+ expect(plugin.getDeclaredNamespaces()).toEqual([])
160
224
  })
161
225
  })
162
226
 
@@ -168,17 +232,13 @@ describe('MainIndicatorLegend draw', () => {
168
232
  ctx = createMockCanvasContext()
169
233
  })
170
234
 
171
- it('should not draw MA when MA is disabled', () => {
235
+ it('should not draw MA when MA is not active', () => {
172
236
  const state = createTestMARenderState()
173
- const mockHost = createMockPluginHost(state)
237
+ const scheduler = createMockScheduler({ ma: { getTitleInfo: createMAGetTitleInfo() } }, [])
238
+ const mockHost = createMockPluginHost(state, scheduler)
174
239
  plugin = createMainIndicatorLegendRendererPlugin({ yPaddingPx: 20 }) as TestableLegendRenderer
175
240
  plugin.onInstall(mockHost)
176
241
 
177
- // Disable MA
178
- plugin.setConfig({
179
- indicators: { MA: { enabled: false, params: {} } },
180
- })
181
-
182
242
  const context = createMockRenderContext(ctx)
183
243
  plugin.draw(context)
184
244
 
@@ -190,7 +250,8 @@ describe('MainIndicatorLegend draw', () => {
190
250
 
191
251
  it('should draw MA values from StateStore', () => {
192
252
  const state = createTestMARenderState()
193
- const mockHost = createMockPluginHost(state)
253
+ const scheduler = createMockScheduler({ ma: { getTitleInfo: createMAGetTitleInfo() } }, ['ma'])
254
+ const mockHost = createMockPluginHost(state, scheduler)
194
255
  plugin = createMainIndicatorLegendRendererPlugin({ yPaddingPx: 20 }) as TestableLegendRenderer
195
256
  plugin.onInstall(mockHost)
196
257
 
@@ -215,7 +276,8 @@ describe('MainIndicatorLegend draw', () => {
215
276
  },
216
277
  enabledPeriods: [5],
217
278
  })
218
- const mockHost = createMockPluginHost(state)
279
+ const scheduler = createMockScheduler({ ma: { getTitleInfo: createMAGetTitleInfo() } }, ['ma'])
280
+ const mockHost = createMockPluginHost(state, scheduler)
219
281
  plugin = createMainIndicatorLegendRendererPlugin({ yPaddingPx: 20 }) as TestableLegendRenderer
220
282
  plugin.onInstall(mockHost)
221
283
 
@@ -227,7 +289,7 @@ describe('MainIndicatorLegend draw', () => {
227
289
 
228
290
  // Should show value 150 at index 50 (100 + 50)
229
291
  const maValueCalls = fillTextCalls.filter(call =>
230
- String(call[0]).includes('150.00')
292
+ String(call[0]).includes('150.000')
231
293
  )
232
294
  expect(maValueCalls.length).toBeGreaterThan(0)
233
295
  })
@@ -239,7 +301,8 @@ describe('MainIndicatorLegend draw', () => {
239
301
  },
240
302
  enabledPeriods: [5],
241
303
  })
242
- const mockHost = createMockPluginHost(state)
304
+ const scheduler = createMockScheduler({ ma: { getTitleInfo: createMAGetTitleInfo() } }, ['ma'])
305
+ const mockHost = createMockPluginHost(state, scheduler)
243
306
  plugin = createMainIndicatorLegendRendererPlugin({ yPaddingPx: 20 }) as TestableLegendRenderer
244
307
  plugin.onInstall(mockHost)
245
308
 
@@ -261,7 +324,7 @@ describe('MainIndicatorLegend draw', () => {
261
324
 
262
325
  // Should show last value (109) at index 9
263
326
  const maValueCalls = fillTextCalls.filter(call =>
264
- String(call[0]).includes('109.00')
327
+ String(call[0]).includes('109.000')
265
328
  )
266
329
  expect(maValueCalls.length).toBeGreaterThan(0)
267
330
  })
@@ -283,27 +346,29 @@ describe('MainIndicatorLegend draw', () => {
283
346
  visibleMax: -Infinity,
284
347
  enabledPeriods: [],
285
348
  })
286
- const mockHost = createMockPluginHost(state)
349
+ const scheduler = createMockScheduler({ ma: { getTitleInfo: createMAGetTitleInfo() } }, ['ma'])
350
+ const mockHost = createMockPluginHost(state, scheduler)
287
351
  plugin = createMainIndicatorLegendRendererPlugin({ yPaddingPx: 20 }) as TestableLegendRenderer
288
352
  plugin.onInstall(mockHost)
289
353
 
290
354
  const context = createMockRenderContext(ctx)
291
355
  plugin.draw(context)
292
356
 
293
- // Should not draw any MA values
357
+ // Should not draw any MA period values (name 'MA' may still appear but no period texts)
294
358
  const fillTextCalls = vi.mocked(ctx.fillText).mock.calls
295
359
  const ma5Calls = fillTextCalls.filter(call => String(call[0]).includes('MA5'))
296
360
  expect(ma5Calls).toHaveLength(0)
297
361
  })
298
362
 
299
- it('should display values with 2 decimal places', () => {
363
+ it('should display values with 3 decimal places', () => {
300
364
  const state = createTestMARenderState({
301
365
  series: {
302
366
  5: Array.from({ length: 100 }, () => 123.4567),
303
367
  },
304
368
  enabledPeriods: [5],
305
369
  })
306
- const mockHost = createMockPluginHost(state)
370
+ const scheduler = createMockScheduler({ ma: { getTitleInfo: createMAGetTitleInfo() } }, ['ma'])
371
+ const mockHost = createMockPluginHost(state, scheduler)
307
372
  plugin = createMainIndicatorLegendRendererPlugin({ yPaddingPx: 20 }) as TestableLegendRenderer
308
373
  plugin.onInstall(mockHost)
309
374
 
@@ -314,29 +379,31 @@ describe('MainIndicatorLegend draw', () => {
314
379
 
315
380
  // Should show formatted value
316
381
  const formattedValueCalls = fillTextCalls.filter(call =>
317
- String(call[0]).includes('123.46')
382
+ String(call[0]).includes('123.457')
318
383
  )
319
384
  expect(formattedValueCalls.length).toBeGreaterThan(0)
320
385
  })
321
386
 
322
387
  it('should use correct colors for each MA period', () => {
323
388
  const state = createTestMARenderState()
324
- const mockHost = createMockPluginHost(state)
389
+ const scheduler = createMockScheduler({ ma: { getTitleInfo: createMAGetTitleInfo() } }, ['ma'])
390
+ const mockHost = createMockPluginHost(state, scheduler)
325
391
  plugin = createMainIndicatorLegendRendererPlugin({ yPaddingPx: 20 }) as TestableLegendRenderer
326
392
  plugin.onInstall(mockHost)
327
393
 
328
394
  const context = createMockRenderContext(ctx)
329
395
  plugin.draw(context)
330
396
 
331
- const fillStyleSetter = vi.mocked(ctx).fillStyle as unknown as ReturnType<typeof vi.fn>
332
-
333
- // Should have set fillStyle for each period's color
334
- expect(fillStyleSetter).not.toBeUndefined()
397
+ // Should have drawn MA period values with proper colors
398
+ const fillTextCalls = vi.mocked(ctx.fillText).mock.calls
399
+ const ma5Calls = fillTextCalls.filter(call => String(call[0]).includes('MA5'))
400
+ expect(ma5Calls.length).toBeGreaterThan(0)
335
401
  })
336
402
 
337
403
  it('should save and restore context', () => {
338
404
  const state = createTestMARenderState()
339
- const mockHost = createMockPluginHost(state)
405
+ const scheduler = createMockScheduler({ ma: { getTitleInfo: createMAGetTitleInfo() } }, ['ma'])
406
+ const mockHost = createMockPluginHost(state, scheduler)
340
407
  plugin = createMainIndicatorLegendRendererPlugin({ yPaddingPx: 20 }) as TestableLegendRenderer
341
408
  plugin.onInstall(mockHost)
342
409
 
@@ -357,10 +424,15 @@ describe('MainIndicatorLegend MA data source', () => {
357
424
  enabledPeriods: [5],
358
425
  })
359
426
  const mockGetSharedState = vi.fn().mockReturnValue(state)
427
+ const scheduler = createMockScheduler({ ma: { getTitleInfo: createMAGetTitleInfo() } }, ['ma'])
360
428
  const mockHost = {
361
429
  setSharedState: vi.fn(),
362
430
  getSharedState: mockGetSharedState,
363
431
  clearByOwner: vi.fn(),
432
+ getService: vi.fn((name: string) => {
433
+ if (name === 'indicatorScheduler') return scheduler
434
+ return undefined
435
+ }),
364
436
  } as unknown as PluginHost
365
437
 
366
438
  const plugin = createMainIndicatorLegendRendererPlugin({ yPaddingPx: 20 })
@@ -373,7 +445,7 @@ describe('MainIndicatorLegend MA data source', () => {
373
445
  })
374
446
  plugin.draw(context)
375
447
 
376
- // Verify it read from StateStore
448
+ // Verify it read from StateStore (via getTitleInfo calling getSharedState)
377
449
  expect(mockGetSharedState).toHaveBeenCalledWith(MA_STATE_KEY)
378
450
 
379
451
  const fillTextCalls = vi.mocked(ctx.fillText).mock.calls
@@ -387,14 +459,12 @@ describe('MainIndicatorLegend MA data source', () => {
387
459
  })
388
460
 
389
461
  describe('MainIndicatorLegend config management', () => {
390
- it('getConfig should return current config', () => {
462
+ it('getConfig should return current yPaddingPx', () => {
391
463
  const plugin = createMainIndicatorLegendRendererPlugin({ yPaddingPx: 20 })
392
464
 
393
465
  const config = plugin.getConfig()
394
466
 
395
467
  expect(config.yPaddingPx).toBe(20)
396
- expect(config.indicators.MA.enabled).toBe(true)
397
- expect(config.indicators.BOLL.enabled).toBe(false)
398
468
  })
399
469
 
400
470
  it('setConfig should update yPaddingPx', () => {
@@ -405,37 +475,18 @@ describe('MainIndicatorLegend config management', () => {
405
475
  const config = plugin.getConfig()
406
476
  expect(config.yPaddingPx).toBe(30)
407
477
  })
408
-
409
- it('setConfig should merge indicator config', () => {
410
- const plugin = createMainIndicatorLegendRendererPlugin({ yPaddingPx: 20 })
411
-
412
- plugin.setConfig({
413
- indicators: {
414
- MA: { enabled: false, params: {} },
415
- BOLL: { enabled: true, params: { period: 26 } },
416
- },
417
- })
418
-
419
- const config = plugin.getConfig()
420
- expect(config.indicators.MA.enabled).toBe(false)
421
- expect(config.indicators.BOLL.enabled).toBe(true)
422
- expect(config.indicators.BOLL.params.period).toBe(26)
423
- })
424
478
  })
425
479
 
426
480
  describe('MainIndicatorLegend with other indicators', () => {
427
- it('should draw BOLL when enabled', () => {
428
- const mockHost = createMockPluginHost(undefined)
481
+ it('should draw BOLL when active', () => {
482
+ const scheduler = createMockScheduler(
483
+ { boll: { getTitleInfo: createSimpleGetTitleInfo('BOLL') } },
484
+ ['boll']
485
+ )
486
+ const mockHost = createMockPluginHost(undefined, scheduler)
429
487
  const plugin = createMainIndicatorLegendRendererPlugin({ yPaddingPx: 20 })
430
488
  plugin.onInstall(mockHost)
431
489
 
432
- plugin.setConfig({
433
- indicators: {
434
- MA: { enabled: false, params: {} },
435
- BOLL: { enabled: true, params: { period: 20, multiplier: 2 } },
436
- },
437
- })
438
-
439
490
  const ctx = createMockCanvasContext()
440
491
  const context = createMockRenderContext(ctx)
441
492
  plugin.draw(context)
@@ -449,18 +500,15 @@ describe('MainIndicatorLegend with other indicators', () => {
449
500
  expect(bollLabelCalls.length).toBeGreaterThan(0)
450
501
  })
451
502
 
452
- it('should draw EXPMA when enabled', () => {
453
- const mockHost = createMockPluginHost(undefined)
503
+ it('should draw EXPMA when active', () => {
504
+ const scheduler = createMockScheduler(
505
+ { expma: { getTitleInfo: createSimpleGetTitleInfo('EXPMA') } },
506
+ ['expma']
507
+ )
508
+ const mockHost = createMockPluginHost(undefined, scheduler)
454
509
  const plugin = createMainIndicatorLegendRendererPlugin({ yPaddingPx: 20 })
455
510
  plugin.onInstall(mockHost)
456
511
 
457
- plugin.setConfig({
458
- indicators: {
459
- MA: { enabled: false, params: {} },
460
- EXPMA: { enabled: true, params: { fastPeriod: 12, slowPeriod: 50 } },
461
- },
462
- })
463
-
464
512
  const ctx = createMockCanvasContext()
465
513
  const context = createMockRenderContext(ctx)
466
514
  plugin.draw(context)
@@ -474,18 +522,15 @@ describe('MainIndicatorLegend with other indicators', () => {
474
522
  expect(expmaLabelCalls.length).toBeGreaterThan(0)
475
523
  })
476
524
 
477
- it('should draw ENE when enabled', () => {
478
- const mockHost = createMockPluginHost(undefined)
525
+ it('should draw ENE when active', () => {
526
+ const scheduler = createMockScheduler(
527
+ { ene: { getTitleInfo: createSimpleGetTitleInfo('ENE') } },
528
+ ['ene']
529
+ )
530
+ const mockHost = createMockPluginHost(undefined, scheduler)
479
531
  const plugin = createMainIndicatorLegendRendererPlugin({ yPaddingPx: 20 })
480
532
  plugin.onInstall(mockHost)
481
533
 
482
- plugin.setConfig({
483
- indicators: {
484
- MA: { enabled: false, params: {} },
485
- ENE: { enabled: true, params: { period: 10, deviation: 11 } },
486
- },
487
- })
488
-
489
534
  const ctx = createMockCanvasContext()
490
535
  const context = createMockRenderContext(ctx)
491
536
  plugin.draw(context)
@@ -498,4 +543,22 @@ describe('MainIndicatorLegend with other indicators', () => {
498
543
  )
499
544
  expect(eneLabelCalls.length).toBeGreaterThan(0)
500
545
  })
546
+
547
+ it('should draw any registered main indicator when active (WMA example)', () => {
548
+ const scheduler = createMockScheduler(
549
+ { wma: { getTitleInfo: createSimpleGetTitleInfo('WMA') } },
550
+ ['wma']
551
+ )
552
+ const mockHost = createMockPluginHost(undefined, scheduler)
553
+ const plugin = createMainIndicatorLegendRendererPlugin({ yPaddingPx: 20 })
554
+ plugin.onInstall(mockHost)
555
+
556
+ const ctx = createMockCanvasContext()
557
+ const context = createMockRenderContext(ctx)
558
+ plugin.draw(context)
559
+
560
+ const fillTextCalls = vi.mocked(ctx.fillText).mock.calls
561
+ const wmaLabelCalls = fillTextCalls.filter(call => String(call[0]).includes('WMA'))
562
+ expect(wmaLabelCalls.length).toBeGreaterThan(0)
563
+ })
501
564
  })