@363045841yyt/klinechart-core 0.8.11-alpha.0 → 0.8.12

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 (578) hide show
  1. package/dist/alerts/createAlertController.d.ts +30 -0
  2. package/dist/alerts/createAlertController.d.ts.map +1 -0
  3. package/dist/alerts/createAlertController.js +261 -0
  4. package/dist/alerts/createAlertController.js.map +1 -0
  5. package/dist/alerts/index.d.ts +5 -0
  6. package/dist/alerts/index.d.ts.map +1 -0
  7. package/dist/alerts/index.js +4 -0
  8. package/dist/alerts/index.js.map +1 -0
  9. package/dist/alerts/predicates.d.ts +28 -0
  10. package/dist/alerts/predicates.d.ts.map +1 -0
  11. package/dist/alerts/predicates.js +211 -0
  12. package/dist/alerts/predicates.js.map +1 -0
  13. package/dist/alerts/rollingVolume.d.ts +15 -0
  14. package/dist/alerts/rollingVolume.d.ts.map +1 -0
  15. package/dist/alerts/rollingVolume.js +42 -0
  16. package/dist/alerts/rollingVolume.js.map +1 -0
  17. package/dist/alerts/ruleSchema.d.ts +42 -0
  18. package/dist/alerts/ruleSchema.d.ts.map +1 -0
  19. package/dist/alerts/ruleSchema.js +240 -0
  20. package/dist/alerts/ruleSchema.js.map +1 -0
  21. package/dist/alerts/types.d.ts +169 -0
  22. package/dist/alerts/types.d.ts.map +1 -0
  23. package/dist/alerts/types.js +24 -0
  24. package/dist/alerts/types.js.map +1 -0
  25. package/dist/chartTypes/heikinAshi.d.ts +49 -0
  26. package/dist/chartTypes/heikinAshi.d.ts.map +1 -0
  27. package/dist/chartTypes/heikinAshi.js +94 -0
  28. package/dist/chartTypes/heikinAshi.js.map +1 -0
  29. package/dist/chartTypes/index.d.ts +6 -0
  30. package/dist/chartTypes/index.d.ts.map +1 -0
  31. package/dist/chartTypes/index.js +5 -0
  32. package/dist/chartTypes/index.js.map +1 -0
  33. package/dist/chartTypes/pointAndFigure.d.ts +83 -0
  34. package/dist/chartTypes/pointAndFigure.d.ts.map +1 -0
  35. package/dist/chartTypes/pointAndFigure.js +159 -0
  36. package/dist/chartTypes/pointAndFigure.js.map +1 -0
  37. package/dist/chartTypes/rangeBars.d.ts +61 -0
  38. package/dist/chartTypes/rangeBars.d.ts.map +1 -0
  39. package/dist/chartTypes/rangeBars.js +181 -0
  40. package/dist/chartTypes/rangeBars.js.map +1 -0
  41. package/dist/chartTypes/renko.d.ts +94 -0
  42. package/dist/chartTypes/renko.d.ts.map +1 -0
  43. package/dist/chartTypes/renko.js +207 -0
  44. package/dist/chartTypes/renko.js.map +1 -0
  45. package/dist/chartTypes/types.d.ts +97 -0
  46. package/dist/chartTypes/types.d.ts.map +1 -0
  47. package/dist/chartTypes/types.js +39 -0
  48. package/dist/chartTypes/types.js.map +1 -0
  49. package/dist/components/anchoredVwap/computeAnchoredVwap.d.ts +76 -0
  50. package/dist/components/anchoredVwap/computeAnchoredVwap.d.ts.map +1 -0
  51. package/dist/components/anchoredVwap/computeAnchoredVwap.js +155 -0
  52. package/dist/components/anchoredVwap/computeAnchoredVwap.js.map +1 -0
  53. package/dist/components/anchoredVwap/createAnchoredVwapController.d.ts +28 -0
  54. package/dist/components/anchoredVwap/createAnchoredVwapController.d.ts.map +1 -0
  55. package/dist/components/anchoredVwap/createAnchoredVwapController.js +282 -0
  56. package/dist/components/anchoredVwap/createAnchoredVwapController.js.map +1 -0
  57. package/dist/components/anchoredVwap/index.d.ts +11 -0
  58. package/dist/components/anchoredVwap/index.d.ts.map +1 -0
  59. package/dist/components/anchoredVwap/index.js +10 -0
  60. package/dist/components/anchoredVwap/index.js.map +1 -0
  61. package/dist/components/anchoredVwap/types.d.ts +171 -0
  62. package/dist/components/anchoredVwap/types.d.ts.map +1 -0
  63. package/dist/components/anchoredVwap/types.js +25 -0
  64. package/dist/components/anchoredVwap/types.js.map +1 -0
  65. package/dist/components/crosshairSync/createCrosshairSync.d.ts +94 -0
  66. package/dist/components/crosshairSync/createCrosshairSync.d.ts.map +1 -0
  67. package/dist/components/crosshairSync/createCrosshairSync.js +118 -0
  68. package/dist/components/crosshairSync/createCrosshairSync.js.map +1 -0
  69. package/dist/components/crosshairSync/index.d.ts +2 -0
  70. package/dist/components/crosshairSync/index.d.ts.map +1 -0
  71. package/dist/components/crosshairSync/index.js +2 -0
  72. package/dist/components/crosshairSync/index.js.map +1 -0
  73. package/dist/components/footprint/aggressor.d.ts +89 -0
  74. package/dist/components/footprint/aggressor.d.ts.map +1 -0
  75. package/dist/components/footprint/aggressor.js +106 -0
  76. package/dist/components/footprint/aggressor.js.map +1 -0
  77. package/dist/components/footprint/createFootprintController.d.ts +29 -0
  78. package/dist/components/footprint/createFootprintController.d.ts.map +1 -0
  79. package/dist/components/footprint/createFootprintController.js +264 -0
  80. package/dist/components/footprint/createFootprintController.js.map +1 -0
  81. package/dist/components/footprint/index.d.ts +7 -0
  82. package/dist/components/footprint/index.d.ts.map +1 -0
  83. package/dist/components/footprint/index.js +4 -0
  84. package/dist/components/footprint/index.js.map +1 -0
  85. package/dist/components/footprint/perBarStats.d.ts +63 -0
  86. package/dist/components/footprint/perBarStats.d.ts.map +1 -0
  87. package/dist/components/footprint/perBarStats.js +123 -0
  88. package/dist/components/footprint/perBarStats.js.map +1 -0
  89. package/dist/components/footprint/types.d.ts +197 -0
  90. package/dist/components/footprint/types.d.ts.map +1 -0
  91. package/dist/components/footprint/types.js +23 -0
  92. package/dist/components/footprint/types.js.map +1 -0
  93. package/dist/components/mtfOverlay/alignToBaseIndex.d.ts +45 -0
  94. package/dist/components/mtfOverlay/alignToBaseIndex.d.ts.map +1 -0
  95. package/dist/components/mtfOverlay/alignToBaseIndex.js +92 -0
  96. package/dist/components/mtfOverlay/alignToBaseIndex.js.map +1 -0
  97. package/dist/components/mtfOverlay/createMtfController.d.ts +7 -0
  98. package/dist/components/mtfOverlay/createMtfController.d.ts.map +1 -0
  99. package/dist/components/mtfOverlay/createMtfController.js +134 -0
  100. package/dist/components/mtfOverlay/createMtfController.js.map +1 -0
  101. package/dist/components/mtfOverlay/index.d.ts +19 -0
  102. package/dist/components/mtfOverlay/index.d.ts.map +1 -0
  103. package/dist/components/mtfOverlay/index.js +18 -0
  104. package/dist/components/mtfOverlay/index.js.map +1 -0
  105. package/dist/components/mtfOverlay/resampleBars.d.ts +37 -0
  106. package/dist/components/mtfOverlay/resampleBars.d.ts.map +1 -0
  107. package/dist/components/mtfOverlay/resampleBars.js +93 -0
  108. package/dist/components/mtfOverlay/resampleBars.js.map +1 -0
  109. package/dist/components/mtfOverlay/types.d.ts +132 -0
  110. package/dist/components/mtfOverlay/types.d.ts.map +1 -0
  111. package/dist/components/mtfOverlay/types.js +22 -0
  112. package/dist/components/mtfOverlay/types.js.map +1 -0
  113. package/dist/components/orderBookHeatmap/createHeatmapController.d.ts +21 -0
  114. package/dist/components/orderBookHeatmap/createHeatmapController.d.ts.map +1 -0
  115. package/dist/components/orderBookHeatmap/createHeatmapController.js +234 -0
  116. package/dist/components/orderBookHeatmap/createHeatmapController.js.map +1 -0
  117. package/dist/components/orderBookHeatmap/createOrderBookState.d.ts +18 -0
  118. package/dist/components/orderBookHeatmap/createOrderBookState.d.ts.map +1 -0
  119. package/dist/components/orderBookHeatmap/createOrderBookState.js +102 -0
  120. package/dist/components/orderBookHeatmap/createOrderBookState.js.map +1 -0
  121. package/dist/components/orderBookHeatmap/deltaArchive.d.ts +25 -0
  122. package/dist/components/orderBookHeatmap/deltaArchive.d.ts.map +1 -0
  123. package/dist/components/orderBookHeatmap/deltaArchive.js +106 -0
  124. package/dist/components/orderBookHeatmap/deltaArchive.js.map +1 -0
  125. package/dist/components/orderBookHeatmap/index.d.ts +13 -0
  126. package/dist/components/orderBookHeatmap/index.d.ts.map +1 -0
  127. package/dist/components/orderBookHeatmap/index.js +12 -0
  128. package/dist/components/orderBookHeatmap/index.js.map +1 -0
  129. package/dist/components/orderBookHeatmap/logColorScale.d.ts +20 -0
  130. package/dist/components/orderBookHeatmap/logColorScale.d.ts.map +1 -0
  131. package/dist/components/orderBookHeatmap/logColorScale.js +71 -0
  132. package/dist/components/orderBookHeatmap/logColorScale.js.map +1 -0
  133. package/dist/components/orderBookHeatmap/snapshotRing.d.ts +16 -0
  134. package/dist/components/orderBookHeatmap/snapshotRing.d.ts.map +1 -0
  135. package/dist/components/orderBookHeatmap/snapshotRing.js +61 -0
  136. package/dist/components/orderBookHeatmap/snapshotRing.js.map +1 -0
  137. package/dist/components/orderBookHeatmap/types.d.ts +128 -0
  138. package/dist/components/orderBookHeatmap/types.d.ts.map +1 -0
  139. package/dist/components/orderBookHeatmap/types.js +16 -0
  140. package/dist/components/orderBookHeatmap/types.js.map +1 -0
  141. package/dist/components/volumeProfile/binning.d.ts +54 -0
  142. package/dist/components/volumeProfile/binning.d.ts.map +1 -0
  143. package/dist/components/volumeProfile/binning.js +123 -0
  144. package/dist/components/volumeProfile/binning.js.map +1 -0
  145. package/dist/components/volumeProfile/createVolumeProfileController.d.ts +31 -0
  146. package/dist/components/volumeProfile/createVolumeProfileController.d.ts.map +1 -0
  147. package/dist/components/volumeProfile/createVolumeProfileController.js +179 -0
  148. package/dist/components/volumeProfile/createVolumeProfileController.js.map +1 -0
  149. package/dist/components/volumeProfile/index.d.ts +6 -0
  150. package/dist/components/volumeProfile/index.d.ts.map +1 -0
  151. package/dist/components/volumeProfile/index.js +5 -0
  152. package/dist/components/volumeProfile/index.js.map +1 -0
  153. package/dist/components/volumeProfile/poc.d.ts +35 -0
  154. package/dist/components/volumeProfile/poc.d.ts.map +1 -0
  155. package/dist/components/volumeProfile/poc.js +51 -0
  156. package/dist/components/volumeProfile/poc.js.map +1 -0
  157. package/dist/components/volumeProfile/types.d.ts +138 -0
  158. package/dist/components/volumeProfile/types.d.ts.map +1 -0
  159. package/dist/components/volumeProfile/types.js +19 -0
  160. package/dist/components/volumeProfile/types.js.map +1 -0
  161. package/dist/components/volumeProfile/valueArea.d.ts +58 -0
  162. package/dist/components/volumeProfile/valueArea.d.ts.map +1 -0
  163. package/dist/components/volumeProfile/valueArea.js +172 -0
  164. package/dist/components/volumeProfile/valueArea.js.map +1 -0
  165. package/dist/controllers/createChartController.d.ts.map +1 -1
  166. package/dist/controllers/createChartController.js +22 -11
  167. package/dist/controllers/createChartController.js.map +1 -1
  168. package/dist/controllers/types.d.ts +3 -1
  169. package/dist/controllers/types.d.ts.map +1 -1
  170. package/dist/data-fetchers/baostock.d.ts.map +1 -1
  171. package/dist/data-fetchers/baostock.js +2 -1
  172. package/dist/data-fetchers/baostock.js.map +1 -1
  173. package/dist/data-fetchers/dataBuffer.effects.d.ts.map +1 -1
  174. package/dist/data-fetchers/dataBuffer.effects.js +2 -1
  175. package/dist/data-fetchers/dataBuffer.effects.js.map +1 -1
  176. package/dist/data-fetchers/fetcherDefinitionRegistry.d.ts.map +1 -1
  177. package/dist/data-fetchers/fetcherDefinitionRegistry.js +2 -1
  178. package/dist/data-fetchers/fetcherDefinitionRegistry.js.map +1 -1
  179. package/dist/data-fetchers/gotdx.js +4 -3
  180. package/dist/data-fetchers/gotdx.js.map +1 -1
  181. package/dist/data-fetchers/router.d.ts.map +1 -1
  182. package/dist/data-fetchers/router.js +4 -3
  183. package/dist/data-fetchers/router.js.map +1 -1
  184. package/dist/data-fetchers/tradingview.js +3 -2
  185. package/dist/data-fetchers/tradingview.js.map +1 -1
  186. package/dist/engine/chart.d.ts +13 -0
  187. package/dist/engine/chart.d.ts.map +1 -1
  188. package/dist/engine/chart.js +109 -0
  189. package/dist/engine/chart.js.map +1 -1
  190. package/dist/engine/data/chartDataManager.d.ts +1 -0
  191. package/dist/engine/data/chartDataManager.d.ts.map +1 -1
  192. package/dist/engine/data/chartDataManager.js +27 -4
  193. package/dist/engine/data/chartDataManager.js.map +1 -1
  194. package/dist/engine/drawing/toolConfig.d.ts.map +1 -1
  195. package/dist/engine/drawing/toolConfig.js +2 -1
  196. package/dist/engine/drawing/toolConfig.js.map +1 -1
  197. package/dist/engine/indicators/chartIndicatorManager.d.ts.map +1 -1
  198. package/dist/engine/indicators/chartIndicatorManager.js +2 -1
  199. package/dist/engine/indicators/chartIndicatorManager.js.map +1 -1
  200. package/dist/engine/indicators/indicatorDefinitionRegistry.d.ts.map +1 -1
  201. package/dist/engine/indicators/indicatorDefinitionRegistry.js +2 -1
  202. package/dist/engine/indicators/indicatorDefinitionRegistry.js.map +1 -1
  203. package/dist/engine/indicators/indicatorMetadata.d.ts.map +1 -1
  204. package/dist/engine/indicators/indicatorMetadata.js +2 -1
  205. package/dist/engine/indicators/indicatorMetadata.js.map +1 -1
  206. package/dist/engine/indicators/indicatorRegistry.d.ts.map +1 -1
  207. package/dist/engine/indicators/indicatorRegistry.js +6 -5
  208. package/dist/engine/indicators/indicatorRegistry.js.map +1 -1
  209. package/dist/engine/indicators/registerBuiltins.d.ts.map +1 -1
  210. package/dist/engine/indicators/registerBuiltins.js +2 -1
  211. package/dist/engine/indicators/registerBuiltins.js.map +1 -1
  212. package/dist/engine/indicators/scheduler.d.ts +6 -0
  213. package/dist/engine/indicators/scheduler.d.ts.map +1 -1
  214. package/dist/engine/indicators/scheduler.js +12 -0
  215. package/dist/engine/indicators/scheduler.js.map +1 -1
  216. package/dist/engine/indicators/soa.d.ts.map +1 -1
  217. package/dist/engine/indicators/soa.js +2 -1
  218. package/dist/engine/indicators/soa.js.map +1 -1
  219. package/dist/engine/indicators/stateComposer.d.ts.map +1 -1
  220. package/dist/engine/indicators/stateComposer.js +2 -1
  221. package/dist/engine/indicators/stateComposer.js.map +1 -1
  222. package/dist/engine/subPaneManager.d.ts.map +1 -1
  223. package/dist/engine/subPaneManager.js +2 -1
  224. package/dist/engine/subPaneManager.js.map +1 -1
  225. package/dist/engine/utils/chartZoomController.d.ts +2 -0
  226. package/dist/engine/utils/chartZoomController.d.ts.map +1 -1
  227. package/dist/engine/utils/chartZoomController.js +5 -1
  228. package/dist/engine/utils/chartZoomController.js.map +1 -1
  229. package/dist/errors-help.d.ts +72 -0
  230. package/dist/errors-help.d.ts.map +1 -0
  231. package/dist/errors-help.js +149 -0
  232. package/dist/errors-help.js.map +1 -0
  233. package/dist/errors.d.ts +64 -0
  234. package/dist/errors.d.ts.map +1 -0
  235. package/dist/errors.js +61 -0
  236. package/dist/errors.js.map +1 -0
  237. package/dist/index.d.ts +18 -0
  238. package/dist/index.d.ts.map +1 -1
  239. package/dist/index.js +22 -0
  240. package/dist/index.js.map +1 -1
  241. package/dist/indicators/alma.d.ts +27 -0
  242. package/dist/indicators/alma.d.ts.map +1 -0
  243. package/dist/indicators/alma.js +36 -0
  244. package/dist/indicators/alma.js.map +1 -0
  245. package/dist/indicators/awesomeOscillator.d.ts +19 -0
  246. package/dist/indicators/awesomeOscillator.d.ts.map +1 -0
  247. package/dist/indicators/awesomeOscillator.js +36 -0
  248. package/dist/indicators/awesomeOscillator.js.map +1 -0
  249. package/dist/indicators/dpo.d.ts +17 -0
  250. package/dist/indicators/dpo.d.ts.map +1 -0
  251. package/dist/indicators/dpo.js +24 -0
  252. package/dist/indicators/dpo.js.map +1 -0
  253. package/dist/indicators/fisherTransform.d.ts +26 -0
  254. package/dist/indicators/fisherTransform.d.ts.map +1 -0
  255. package/dist/indicators/fisherTransform.js +44 -0
  256. package/dist/indicators/fisherTransform.js.map +1 -0
  257. package/dist/indicators/frama.d.ts +25 -0
  258. package/dist/indicators/frama.d.ts.map +1 -0
  259. package/dist/indicators/frama.js +61 -0
  260. package/dist/indicators/frama.js.map +1 -0
  261. package/dist/indicators/index.d.ts +24 -0
  262. package/dist/indicators/index.d.ts.map +1 -0
  263. package/dist/indicators/index.js +26 -0
  264. package/dist/indicators/index.js.map +1 -0
  265. package/dist/indicators/lsma.d.ts +21 -0
  266. package/dist/indicators/lsma.d.ts.map +1 -0
  267. package/dist/indicators/lsma.js +37 -0
  268. package/dist/indicators/lsma.js.map +1 -0
  269. package/dist/indicators/schaffTrendCycle.d.ts +24 -0
  270. package/dist/indicators/schaffTrendCycle.d.ts.map +1 -0
  271. package/dist/indicators/schaffTrendCycle.js +70 -0
  272. package/dist/indicators/schaffTrendCycle.js.map +1 -0
  273. package/dist/indicators/stochRSI.d.ts +24 -0
  274. package/dist/indicators/stochRSI.d.ts.map +1 -0
  275. package/dist/indicators/stochRSI.js +86 -0
  276. package/dist/indicators/stochRSI.js.map +1 -0
  277. package/dist/indicators/t3.d.ts +31 -0
  278. package/dist/indicators/t3.d.ts.map +1 -0
  279. package/dist/indicators/t3.js +63 -0
  280. package/dist/indicators/t3.js.map +1 -0
  281. package/dist/indicators/ultimateOscillator.d.ts +26 -0
  282. package/dist/indicators/ultimateOscillator.d.ts.map +1 -0
  283. package/dist/indicators/ultimateOscillator.js +59 -0
  284. package/dist/indicators/ultimateOscillator.js.map +1 -0
  285. package/dist/indicators/vidya.d.ts +24 -0
  286. package/dist/indicators/vidya.d.ts.map +1 -0
  287. package/dist/indicators/vidya.js +54 -0
  288. package/dist/indicators/vidya.js.map +1 -0
  289. package/dist/indicators/zlema.d.ts +16 -0
  290. package/dist/indicators/zlema.d.ts.map +1 -0
  291. package/dist/indicators/zlema.js +26 -0
  292. package/dist/indicators/zlema.js.map +1 -0
  293. package/dist/input/gesture.d.ts +125 -0
  294. package/dist/input/gesture.d.ts.map +1 -0
  295. package/dist/input/gesture.js +249 -0
  296. package/dist/input/gesture.js.map +1 -0
  297. package/dist/input/index.d.ts +9 -0
  298. package/dist/input/index.d.ts.map +1 -0
  299. package/dist/input/index.js +9 -0
  300. package/dist/input/index.js.map +1 -0
  301. package/dist/input/keyboard.d.ts +140 -0
  302. package/dist/input/keyboard.d.ts.map +1 -0
  303. package/dist/input/keyboard.js +260 -0
  304. package/dist/input/keyboard.js.map +1 -0
  305. package/dist/mcp/chartBridge.d.ts +2 -2
  306. package/dist/mcp/chartBridge.d.ts.map +1 -1
  307. package/dist/mcp/chartBridge.js +27 -21
  308. package/dist/mcp/chartBridge.js.map +1 -1
  309. package/dist/plugin/PluginHost.d.ts +0 -3
  310. package/dist/plugin/PluginHost.d.ts.map +1 -1
  311. package/dist/plugin/PluginHost.js +7 -3
  312. package/dist/plugin/PluginHost.js.map +1 -1
  313. package/dist/plugin/PluginRegistry.d.ts +0 -3
  314. package/dist/plugin/PluginRegistry.d.ts.map +1 -1
  315. package/dist/plugin/PluginRegistry.js +5 -1
  316. package/dist/plugin/PluginRegistry.js.map +1 -1
  317. package/dist/render/Renderer.d.ts +116 -0
  318. package/dist/render/Renderer.d.ts.map +1 -0
  319. package/dist/render/Renderer.js +31 -0
  320. package/dist/render/Renderer.js.map +1 -0
  321. package/dist/render/SurfaceBackend.d.ts +83 -0
  322. package/dist/render/SurfaceBackend.d.ts.map +1 -0
  323. package/dist/render/SurfaceBackend.js +27 -0
  324. package/dist/render/SurfaceBackend.js.map +1 -0
  325. package/dist/render/index.d.ts +12 -0
  326. package/dist/render/index.d.ts.map +1 -0
  327. package/dist/render/index.js +11 -0
  328. package/dist/render/index.js.map +1 -0
  329. package/dist/renderer-tier/detectRendererTier.d.ts +57 -0
  330. package/dist/renderer-tier/detectRendererTier.d.ts.map +1 -0
  331. package/dist/renderer-tier/detectRendererTier.js +143 -0
  332. package/dist/renderer-tier/detectRendererTier.js.map +1 -0
  333. package/dist/renderer-tier/index.d.ts +12 -0
  334. package/dist/renderer-tier/index.d.ts.map +1 -0
  335. package/dist/renderer-tier/index.js +12 -0
  336. package/dist/renderer-tier/index.js.map +1 -0
  337. package/dist/renderer-tier/selectBackend.d.ts +106 -0
  338. package/dist/renderer-tier/selectBackend.d.ts.map +1 -0
  339. package/dist/renderer-tier/selectBackend.js +113 -0
  340. package/dist/renderer-tier/selectBackend.js.map +1 -0
  341. package/dist/renderer-tier/types.d.ts +50 -0
  342. package/dist/renderer-tier/types.d.ts.map +1 -0
  343. package/dist/renderer-tier/types.js +24 -0
  344. package/dist/renderer-tier/types.js.map +1 -0
  345. package/dist/replay/createReplayController.d.ts +3 -0
  346. package/dist/replay/createReplayController.d.ts.map +1 -0
  347. package/dist/replay/createReplayController.js +251 -0
  348. package/dist/replay/createReplayController.js.map +1 -0
  349. package/dist/replay/index.d.ts +5 -0
  350. package/dist/replay/index.d.ts.map +1 -0
  351. package/dist/replay/index.js +3 -0
  352. package/dist/replay/index.js.map +1 -0
  353. package/dist/replay/timeline.d.ts +50 -0
  354. package/dist/replay/timeline.d.ts.map +1 -0
  355. package/dist/replay/timeline.js +104 -0
  356. package/dist/replay/timeline.js.map +1 -0
  357. package/dist/replay/types.d.ts +94 -0
  358. package/dist/replay/types.d.ts.map +1 -0
  359. package/dist/replay/types.js +21 -0
  360. package/dist/replay/types.js.map +1 -0
  361. package/dist/scale/anchoredZoom.d.ts +64 -0
  362. package/dist/scale/anchoredZoom.d.ts.map +1 -0
  363. package/dist/scale/anchoredZoom.js +67 -0
  364. package/dist/scale/anchoredZoom.js.map +1 -0
  365. package/dist/scale/createPriceScale.d.ts +49 -0
  366. package/dist/scale/createPriceScale.d.ts.map +1 -0
  367. package/dist/scale/createPriceScale.js +175 -0
  368. package/dist/scale/createPriceScale.js.map +1 -0
  369. package/dist/scale/createTimeScale.d.ts +27 -0
  370. package/dist/scale/createTimeScale.d.ts.map +1 -0
  371. package/dist/scale/createTimeScale.js +139 -0
  372. package/dist/scale/createTimeScale.js.map +1 -0
  373. package/dist/scale/index.d.ts +6 -0
  374. package/dist/scale/index.d.ts.map +1 -0
  375. package/dist/scale/index.js +5 -0
  376. package/dist/scale/index.js.map +1 -0
  377. package/dist/scale/originShift.d.ts +69 -0
  378. package/dist/scale/originShift.d.ts.map +1 -0
  379. package/dist/scale/originShift.js +41 -0
  380. package/dist/scale/originShift.js.map +1 -0
  381. package/dist/scale/types.d.ts +90 -0
  382. package/dist/scale/types.d.ts.map +1 -0
  383. package/dist/scale/types.js +17 -0
  384. package/dist/scale/types.js.map +1 -0
  385. package/dist/scene/createScene.d.ts +22 -0
  386. package/dist/scene/createScene.d.ts.map +1 -0
  387. package/dist/scene/createScene.js +114 -0
  388. package/dist/scene/createScene.js.map +1 -0
  389. package/dist/scene/index.d.ts +13 -0
  390. package/dist/scene/index.d.ts.map +1 -0
  391. package/dist/scene/index.js +11 -0
  392. package/dist/scene/index.js.map +1 -0
  393. package/dist/scene/layerRegistry.d.ts +83 -0
  394. package/dist/scene/layerRegistry.d.ts.map +1 -0
  395. package/dist/scene/layerRegistry.js +43 -0
  396. package/dist/scene/layerRegistry.js.map +1 -0
  397. package/dist/scene/types.d.ts +128 -0
  398. package/dist/scene/types.d.ts.map +1 -0
  399. package/dist/scene/types.js +21 -0
  400. package/dist/scene/types.js.map +1 -0
  401. package/dist/scheduler/createFrameBudget.d.ts +91 -0
  402. package/dist/scheduler/createFrameBudget.d.ts.map +1 -0
  403. package/dist/scheduler/createFrameBudget.js +232 -0
  404. package/dist/scheduler/createFrameBudget.js.map +1 -0
  405. package/dist/scheduler/index.d.ts +2 -0
  406. package/dist/scheduler/index.d.ts.map +1 -0
  407. package/dist/scheduler/index.js +2 -0
  408. package/dist/scheduler/index.js.map +1 -0
  409. package/dist/tokens/themeToCssVars.d.ts.map +1 -1
  410. package/dist/tokens/themeToCssVars.js +2 -28
  411. package/dist/tokens/themeToCssVars.js.map +1 -1
  412. package/dist/version.d.ts +1 -1
  413. package/dist/version.d.ts.map +1 -1
  414. package/dist/version.js +1 -1
  415. package/dist/version.js.map +1 -1
  416. package/package.json +1 -1
  417. package/src/__bench__/indicators.bench.ts +215 -0
  418. package/src/__bench__/orderBookHeatmap.bench.ts +68 -0
  419. package/src/__bench__/scale.bench.ts +80 -0
  420. package/src/__bench__/signal.bench.ts +41 -0
  421. package/src/__bench__/volumeProfile.bench.ts +66 -0
  422. package/src/__tests__/errors-help.test.ts +184 -0
  423. package/src/__tests__/errors.test.ts +187 -0
  424. package/src/alerts/__tests__/controller.test.ts +231 -0
  425. package/src/alerts/__tests__/predicates.test.ts +374 -0
  426. package/src/alerts/__tests__/ruleSchema.test.ts +180 -0
  427. package/src/alerts/createAlertController.ts +312 -0
  428. package/src/alerts/index.ts +18 -0
  429. package/src/alerts/predicates.ts +231 -0
  430. package/src/alerts/rollingVolume.ts +51 -0
  431. package/src/alerts/ruleSchema.ts +278 -0
  432. package/src/alerts/types.ts +177 -0
  433. package/src/chartTypes/__tests__/heikinAshi.test.ts +122 -0
  434. package/src/chartTypes/__tests__/pointAndFigure.test.ts +167 -0
  435. package/src/chartTypes/__tests__/rangeBars.test.ts +146 -0
  436. package/src/chartTypes/__tests__/renko.test.ts +160 -0
  437. package/src/chartTypes/heikinAshi.ts +116 -0
  438. package/src/chartTypes/index.ts +5 -0
  439. package/src/chartTypes/pointAndFigure.ts +278 -0
  440. package/src/chartTypes/rangeBars.ts +303 -0
  441. package/src/chartTypes/renko.ts +311 -0
  442. package/src/chartTypes/types.ts +99 -0
  443. package/src/components/anchoredVwap/__tests__/computeAnchoredVwap.test.ts +331 -0
  444. package/src/components/anchoredVwap/__tests__/controller.test.ts +430 -0
  445. package/src/components/anchoredVwap/computeAnchoredVwap.ts +174 -0
  446. package/src/components/anchoredVwap/createAnchoredVwapController.ts +358 -0
  447. package/src/components/anchoredVwap/index.ts +17 -0
  448. package/src/components/anchoredVwap/types.ts +187 -0
  449. package/src/components/crosshairSync/__tests__/crosshairSync.test.ts +261 -0
  450. package/src/components/crosshairSync/createCrosshairSync.ts +187 -0
  451. package/src/components/crosshairSync/index.ts +5 -0
  452. package/src/components/footprint/__tests__/aggressor.test.ts +127 -0
  453. package/src/components/footprint/__tests__/controller.test.ts +130 -0
  454. package/src/components/footprint/__tests__/perBarStats.test.ts +114 -0
  455. package/src/components/footprint/aggressor.ts +165 -0
  456. package/src/components/footprint/createFootprintController.ts +338 -0
  457. package/src/components/footprint/index.ts +21 -0
  458. package/src/components/footprint/perBarStats.ts +137 -0
  459. package/src/components/footprint/types.ts +232 -0
  460. package/src/components/mtfOverlay/__tests__/alignToBaseIndex.test.ts +103 -0
  461. package/src/components/mtfOverlay/__tests__/controller.test.ts +172 -0
  462. package/src/components/mtfOverlay/__tests__/resampleBars.test.ts +106 -0
  463. package/src/components/mtfOverlay/alignToBaseIndex.ts +108 -0
  464. package/src/components/mtfOverlay/createMtfController.ts +180 -0
  465. package/src/components/mtfOverlay/index.ts +26 -0
  466. package/src/components/mtfOverlay/resampleBars.ts +134 -0
  467. package/src/components/mtfOverlay/types.ts +148 -0
  468. package/src/components/orderBookHeatmap/__tests__/controller.test.ts +237 -0
  469. package/src/components/orderBookHeatmap/__tests__/deltaArchive.test.ts +88 -0
  470. package/src/components/orderBookHeatmap/__tests__/logColorScale.test.ts +69 -0
  471. package/src/components/orderBookHeatmap/__tests__/orderBookState.test.ts +113 -0
  472. package/src/components/orderBookHeatmap/__tests__/snapshotRing.test.ts +53 -0
  473. package/src/components/orderBookHeatmap/computeShader.wgsl.md +130 -0
  474. package/src/components/orderBookHeatmap/createHeatmapController.ts +273 -0
  475. package/src/components/orderBookHeatmap/createOrderBookState.ts +116 -0
  476. package/src/components/orderBookHeatmap/deltaArchive.ts +113 -0
  477. package/src/components/orderBookHeatmap/index.ts +25 -0
  478. package/src/components/orderBookHeatmap/logColorScale.ts +77 -0
  479. package/src/components/orderBookHeatmap/snapshotRing.ts +65 -0
  480. package/src/components/orderBookHeatmap/types.ts +168 -0
  481. package/src/components/volumeProfile/__tests__/binning.test.ts +133 -0
  482. package/src/components/volumeProfile/__tests__/poc.test.ts +44 -0
  483. package/src/components/volumeProfile/__tests__/valueArea.test.ts +177 -0
  484. package/src/components/volumeProfile/binning.ts +133 -0
  485. package/src/components/volumeProfile/createVolumeProfileController.ts +213 -0
  486. package/src/components/volumeProfile/index.ts +12 -0
  487. package/src/components/volumeProfile/poc.ts +53 -0
  488. package/src/components/volumeProfile/types.ts +148 -0
  489. package/src/components/volumeProfile/valueArea.ts +187 -0
  490. package/src/controllers/createChartController.ts +23 -10
  491. package/src/controllers/types.ts +5 -1
  492. package/src/data-fetchers/baostock.ts +2 -1
  493. package/src/data-fetchers/dataBuffer.effects.ts +3 -1
  494. package/src/data-fetchers/fetcherDefinitionRegistry.ts +2 -1
  495. package/src/data-fetchers/gotdx.ts +4 -3
  496. package/src/data-fetchers/router.ts +6 -3
  497. package/src/data-fetchers/tradingview.ts +3 -2
  498. package/src/engine/chart.ts +126 -3
  499. package/src/engine/data/chartDataManager.ts +26 -4
  500. package/src/engine/drawing/toolConfig.ts +2 -1
  501. package/src/engine/indicators/chartIndicatorManager.ts +2 -1
  502. package/src/engine/indicators/indicatorDefinitionRegistry.ts +2 -1
  503. package/src/engine/indicators/indicatorMetadata.ts +2 -1
  504. package/src/engine/indicators/indicatorRegistry.ts +6 -5
  505. package/src/engine/indicators/registerBuiltins.ts +2 -1
  506. package/src/engine/indicators/scheduler.ts +15 -0
  507. package/src/engine/indicators/soa.ts +2 -1
  508. package/src/engine/indicators/stateComposer.ts +2 -1
  509. package/src/engine/subPaneManager.ts +2 -1
  510. package/src/engine/utils/chartZoomController.ts +7 -1
  511. package/src/errors-help.ts +218 -0
  512. package/src/errors.ts +128 -0
  513. package/src/index.ts +37 -0
  514. package/src/indicators/__tests__/maFamily.test.ts +159 -0
  515. package/src/indicators/__tests__/oscillators.test.ts +150 -0
  516. package/src/indicators/alma.ts +61 -0
  517. package/src/indicators/awesomeOscillator.ts +54 -0
  518. package/src/indicators/dpo.ts +37 -0
  519. package/src/indicators/fisherTransform.ts +63 -0
  520. package/src/indicators/frama.ts +87 -0
  521. package/src/indicators/index.ts +39 -0
  522. package/src/indicators/lsma.ts +58 -0
  523. package/src/indicators/schaffTrendCycle.ts +92 -0
  524. package/src/indicators/stochRSI.ts +108 -0
  525. package/src/indicators/t3.ts +96 -0
  526. package/src/indicators/ultimateOscillator.ts +83 -0
  527. package/src/indicators/vidya.ts +80 -0
  528. package/src/indicators/zlema.ts +41 -0
  529. package/src/input/__tests__/gesture.test.ts +271 -0
  530. package/src/input/__tests__/keyboard.test.ts +317 -0
  531. package/src/input/gesture.ts +357 -0
  532. package/src/input/index.ts +26 -0
  533. package/src/input/keyboard.ts +373 -0
  534. package/src/mcp/chartBridge.ts +98 -72
  535. package/src/plugin/PluginHost.ts +4 -3
  536. package/src/plugin/PluginRegistry.ts +2 -1
  537. package/src/render/Renderer.ts +127 -0
  538. package/src/render/SurfaceBackend.ts +94 -0
  539. package/src/render/__tests__/contract.test.ts +176 -0
  540. package/src/render/index.ts +27 -0
  541. package/src/renderer-tier/__tests__/detectRendererTier.test.ts +180 -0
  542. package/src/renderer-tier/__tests__/selectBackend.test.ts +253 -0
  543. package/src/renderer-tier/detectRendererTier.ts +168 -0
  544. package/src/renderer-tier/index.ts +30 -0
  545. package/src/renderer-tier/selectBackend.ts +201 -0
  546. package/src/renderer-tier/types.ts +59 -0
  547. package/src/replay/__tests__/controller.test.ts +309 -0
  548. package/src/replay/__tests__/timeline.test.ts +99 -0
  549. package/src/replay/createReplayController.ts +302 -0
  550. package/src/replay/index.ts +15 -0
  551. package/src/replay/timeline.ts +106 -0
  552. package/src/replay/types.ts +107 -0
  553. package/src/scale/__tests__/anchoredZoom.test.ts +125 -0
  554. package/src/scale/__tests__/originShift.test.ts +97 -0
  555. package/src/scale/__tests__/priceScale.test.ts +219 -0
  556. package/src/scale/__tests__/timeScale.test.ts +119 -0
  557. package/src/scale/anchoredZoom.ts +104 -0
  558. package/src/scale/createPriceScale.ts +226 -0
  559. package/src/scale/createTimeScale.ts +150 -0
  560. package/src/scale/index.ts +9 -0
  561. package/src/scale/originShift.ts +111 -0
  562. package/src/scale/types.ts +100 -0
  563. package/src/scene/__tests__/layerRegistry.test.ts +207 -0
  564. package/src/scene/__tests__/scene.test.ts +411 -0
  565. package/src/scene/createScene.ts +117 -0
  566. package/src/scene/index.ts +29 -0
  567. package/src/scene/layerRegistry.ts +117 -0
  568. package/src/scene/types.ts +143 -0
  569. package/src/scheduler/__tests__/createFrameBudget.test.ts +315 -0
  570. package/src/scheduler/createFrameBudget.ts +316 -0
  571. package/src/scheduler/index.ts +7 -0
  572. package/src/tokens/themeToCssVars.ts +3 -1
  573. package/src/version.ts +1 -1
  574. package/dist/data-fetchers/gotdx/gotdx.d.ts +0 -7
  575. package/dist/data-fetchers/gotdx/gotdx.d.ts.map +0 -1
  576. package/dist/data-fetchers/gotdx/gotdx.js +0 -7
  577. package/dist/data-fetchers/gotdx/gotdx.js.map +0 -1
  578. package/src/data-fetchers/gotdx/gotdx.ts +0 -6
@@ -0,0 +1,278 @@
1
+ /**
2
+ * Serialisable alert rule schema.
3
+ *
4
+ * Why a schema separate from `AlertRule`:
5
+ * - `AlertRule` can contain `kind: 'custom'`, whose `evaluate` is an
6
+ * in-memory function. Functions cannot be JSON-encoded, and we
7
+ * deliberately refuse to do anything clever (e.g. `Function(string)`)
8
+ * to bring them back — that would let a malicious shared rule execute
9
+ * arbitrary code on a victim's browser the moment they imported it.
10
+ * - All other predicate kinds are plain data and round-trip cleanly.
11
+ *
12
+ * SECURITY:
13
+ * `deserializeRule` is strictly data-driven. It NEVER calls `eval`,
14
+ * `Function(...)`, dynamic `import`, or `vm` — even if a malicious payload
15
+ * claims `kind: 'custom'` with a `source` string, we throw. The output is
16
+ * always a structurally-validated `AlertRule` whose predicate is one of
17
+ * the known data-only kinds.
18
+ *
19
+ * The schema is *minimal* on purpose — we do field-by-field validation
20
+ * inline rather than pulling Zod into the core bundle. Core has a strict
21
+ * size budget (30 KB gzip per package.json size-limit) and these rules are
22
+ * small.
23
+ */
24
+
25
+ import type {
26
+ AlertPredicate,
27
+ AlertPredicateKind,
28
+ AlertRule,
29
+ CrossDirection,
30
+ IndicatorCrossPairDirection,
31
+ } from './types'
32
+
33
+ // ---------------------------------------------------------------------------
34
+ // Error type — callers can catch and report cleanly.
35
+ // ---------------------------------------------------------------------------
36
+
37
+ export class AlertRuleSchemaError extends Error {
38
+ constructor(message: string) {
39
+ super(message)
40
+ this.name = 'AlertRuleSchemaError'
41
+ }
42
+ }
43
+
44
+ // ---------------------------------------------------------------------------
45
+ // serializeRule
46
+ // ---------------------------------------------------------------------------
47
+
48
+ /**
49
+ * Serialise a rule to a JSON string. Throws `AlertRuleSchemaError` if the
50
+ * rule contains a `custom` predicate — these are never serialisable, by
51
+ * security design.
52
+ */
53
+ export function serializeRule(rule: AlertRule): string {
54
+ if (rule.predicate.kind === 'custom') {
55
+ throw new AlertRuleSchemaError(
56
+ "Cannot serialise rule with 'custom' predicate: custom predicates carry " +
57
+ 'an in-memory function. Serialising them would force deserialise to ' +
58
+ 'evaluate user-supplied code, which is a remote-code-execution vector. ' +
59
+ 'Use a built-in predicate kind for shareable rules.',
60
+ )
61
+ }
62
+ // Everything else is plain data — JSON.stringify handles it directly.
63
+ // We omit `undefined` fields naturally via JSON.
64
+ const payload = {
65
+ id: rule.id,
66
+ name: rule.name,
67
+ predicate: rule.predicate,
68
+ enabled: rule.enabled,
69
+ oneShot: rule.oneShot,
70
+ ...(rule.cooldownMs !== undefined ? { cooldownMs: rule.cooldownMs } : {}),
71
+ ...(rule.metadata !== undefined ? { metadata: rule.metadata } : {}),
72
+ // Schema version pin — bumps if we make a breaking change.
73
+ schemaVersion: 1,
74
+ }
75
+ return JSON.stringify(payload)
76
+ }
77
+
78
+ // ---------------------------------------------------------------------------
79
+ // deserializeRule
80
+ // ---------------------------------------------------------------------------
81
+
82
+ const SERIALISABLE_KINDS: ReadonlySet<AlertPredicateKind> = new Set([
83
+ 'price-cross',
84
+ 'price-in-range',
85
+ 'price-out-of-range',
86
+ 'indicator-cross',
87
+ 'indicator-cross-indicator',
88
+ 'volume-spike',
89
+ 'volume-profile-poc-touch',
90
+ 'order-book-wall',
91
+ 'footprint-imbalance',
92
+ ] as const)
93
+
94
+ const CROSS_DIRECTIONS: ReadonlySet<CrossDirection> = new Set(['up', 'down', 'any'])
95
+ const PAIR_DIRECTIONS: ReadonlySet<IndicatorCrossPairDirection> = new Set([
96
+ 'a-above-b',
97
+ 'a-below-b',
98
+ 'any',
99
+ ])
100
+
101
+ function isObj(x: unknown): x is Record<string, unknown> {
102
+ return typeof x === 'object' && x !== null && !Array.isArray(x)
103
+ }
104
+
105
+ function reqString(obj: Record<string, unknown>, key: string): string {
106
+ const v = obj[key]
107
+ if (typeof v !== 'string' || v.length === 0) {
108
+ throw new AlertRuleSchemaError(`Field '${key}' must be a non-empty string`)
109
+ }
110
+ return v
111
+ }
112
+
113
+ function reqBool(obj: Record<string, unknown>, key: string): boolean {
114
+ const v = obj[key]
115
+ if (typeof v !== 'boolean') {
116
+ throw new AlertRuleSchemaError(`Field '${key}' must be a boolean`)
117
+ }
118
+ return v
119
+ }
120
+
121
+ function reqFiniteNumber(obj: Record<string, unknown>, key: string): number {
122
+ const v = obj[key]
123
+ if (typeof v !== 'number' || !Number.isFinite(v)) {
124
+ throw new AlertRuleSchemaError(`Field '${key}' must be a finite number`)
125
+ }
126
+ return v
127
+ }
128
+
129
+ function optFiniteNumber(
130
+ obj: Record<string, unknown>,
131
+ key: string,
132
+ ): number | undefined {
133
+ const v = obj[key]
134
+ if (v === undefined) return undefined
135
+ if (typeof v !== 'number' || !Number.isFinite(v)) {
136
+ throw new AlertRuleSchemaError(`Field '${key}' must be a finite number when set`)
137
+ }
138
+ return v
139
+ }
140
+
141
+ function reqEnum<T extends string>(
142
+ obj: Record<string, unknown>,
143
+ key: string,
144
+ allowed: ReadonlySet<T>,
145
+ ): T {
146
+ const v = obj[key]
147
+ if (typeof v !== 'string' || !allowed.has(v as T)) {
148
+ throw new AlertRuleSchemaError(
149
+ `Field '${key}' must be one of: ${[...allowed].join(', ')}`,
150
+ )
151
+ }
152
+ return v as T
153
+ }
154
+
155
+ function parsePredicate(raw: unknown): AlertPredicate {
156
+ if (!isObj(raw)) throw new AlertRuleSchemaError('predicate must be an object')
157
+ const kind = raw.kind
158
+ if (typeof kind !== 'string') {
159
+ throw new AlertRuleSchemaError("predicate.kind must be a string")
160
+ }
161
+ if (kind === 'custom') {
162
+ throw new AlertRuleSchemaError(
163
+ "Refusing to deserialise 'custom' predicate. Custom predicates are " +
164
+ 'never serialised — accepting one here would mean evaluating user-' +
165
+ 'supplied code (RCE). Custom predicates must be added in-process by ' +
166
+ 'the application.',
167
+ )
168
+ }
169
+ if (!SERIALISABLE_KINDS.has(kind as AlertPredicateKind)) {
170
+ throw new AlertRuleSchemaError(`Unknown predicate.kind: ${kind}`)
171
+ }
172
+
173
+ switch (kind as Exclude<AlertPredicateKind, 'custom'>) {
174
+ case 'price-cross':
175
+ return {
176
+ kind: 'price-cross',
177
+ price: reqFiniteNumber(raw, 'price'),
178
+ direction: reqEnum(raw, 'direction', CROSS_DIRECTIONS),
179
+ }
180
+ case 'price-in-range':
181
+ return {
182
+ kind: 'price-in-range',
183
+ min: reqFiniteNumber(raw, 'min'),
184
+ max: reqFiniteNumber(raw, 'max'),
185
+ }
186
+ case 'price-out-of-range':
187
+ return {
188
+ kind: 'price-out-of-range',
189
+ min: reqFiniteNumber(raw, 'min'),
190
+ max: reqFiniteNumber(raw, 'max'),
191
+ }
192
+ case 'indicator-cross':
193
+ return {
194
+ kind: 'indicator-cross',
195
+ indicatorId: reqString(raw, 'indicatorId'),
196
+ threshold: reqFiniteNumber(raw, 'threshold'),
197
+ direction: reqEnum(raw, 'direction', CROSS_DIRECTIONS),
198
+ }
199
+ case 'indicator-cross-indicator':
200
+ return {
201
+ kind: 'indicator-cross-indicator',
202
+ aId: reqString(raw, 'aId'),
203
+ bId: reqString(raw, 'bId'),
204
+ direction: reqEnum(raw, 'direction', PAIR_DIRECTIONS),
205
+ }
206
+ case 'volume-spike':
207
+ return {
208
+ kind: 'volume-spike',
209
+ multipleOfAvg: reqFiniteNumber(raw, 'multipleOfAvg'),
210
+ lookbackBars: reqFiniteNumber(raw, 'lookbackBars'),
211
+ }
212
+ case 'volume-profile-poc-touch':
213
+ return {
214
+ kind: 'volume-profile-poc-touch',
215
+ bandPercent: reqFiniteNumber(raw, 'bandPercent'),
216
+ }
217
+ case 'order-book-wall':
218
+ return {
219
+ kind: 'order-book-wall',
220
+ sizeMultipleOfMedian: reqFiniteNumber(raw, 'sizeMultipleOfMedian'),
221
+ }
222
+ case 'footprint-imbalance':
223
+ return {
224
+ kind: 'footprint-imbalance',
225
+ minImbalanceRatio: reqFiniteNumber(raw, 'minImbalanceRatio'),
226
+ consecutivePriceLevels: reqFiniteNumber(raw, 'consecutivePriceLevels'),
227
+ }
228
+ }
229
+ }
230
+
231
+ /**
232
+ * Parse a JSON string back into an `AlertRule`. Throws `AlertRuleSchemaError`
233
+ * for malformed JSON, unknown predicate kinds, or any field that fails type
234
+ * validation.
235
+ *
236
+ * Tolerates missing optional fields (`cooldownMs`, `metadata`).
237
+ */
238
+ export function deserializeRule(json: string): AlertRule {
239
+ let raw: unknown
240
+ try {
241
+ raw = JSON.parse(json)
242
+ } catch (err) {
243
+ throw new AlertRuleSchemaError(
244
+ `Malformed JSON: ${err instanceof Error ? err.message : String(err)}`,
245
+ )
246
+ }
247
+ if (!isObj(raw)) {
248
+ throw new AlertRuleSchemaError('Top-level payload must be an object')
249
+ }
250
+
251
+ const id = reqString(raw, 'id')
252
+ const name = reqString(raw, 'name')
253
+ const enabled = reqBool(raw, 'enabled')
254
+ const oneShot = reqBool(raw, 'oneShot')
255
+ const cooldownMs = optFiniteNumber(raw, 'cooldownMs')
256
+ const predicate = parsePredicate(raw.predicate)
257
+
258
+ // Metadata is a free-form object; we only check that it is an object if
259
+ // present, and we freeze it lazily by spreading the keys we got.
260
+ let metadata: Readonly<Record<string, unknown>> | undefined
261
+ if (raw.metadata !== undefined) {
262
+ if (!isObj(raw.metadata)) {
263
+ throw new AlertRuleSchemaError('metadata must be an object when set')
264
+ }
265
+ metadata = { ...raw.metadata }
266
+ }
267
+
268
+ const rule: AlertRule = {
269
+ id,
270
+ name,
271
+ predicate,
272
+ enabled,
273
+ oneShot,
274
+ ...(cooldownMs !== undefined ? { cooldownMs } : {}),
275
+ ...(metadata !== undefined ? { metadata } : {}),
276
+ }
277
+ return rule
278
+ }
@@ -0,0 +1,177 @@
1
+ /**
2
+ * Alert rule engine — public types.
3
+ *
4
+ * Why we build our own (vs. relying on TradingView's alert engine):
5
+ * - TV alerts are closed, server-side, capped (60 free + paid tiers).
6
+ * - TV alerts are limited to TV's built-in indicator outputs.
7
+ * - We need to alert on differentiating signals TV simply cannot see —
8
+ * Volume Profile POC touch, Order Book wall appearance, Footprint
9
+ * imbalance hit. These predicates are first-class here.
10
+ *
11
+ * Engine shape:
12
+ * - Predicate-based (discriminated union, schema-driven).
13
+ * - Rules are pure data and serialisable (see `ruleSchema.ts`) so they
14
+ * survive page reloads and can be shared between users/agents/servers.
15
+ * - The controller is a tiny state machine over rules + recent events;
16
+ * evaluation is O(rules) per call, O(1) per rule, safe to run in a
17
+ * per-frame loop.
18
+ *
19
+ * The `custom` predicate is an escape hatch for callers that need ad-hoc
20
+ * logic without forking the schema. It carries an in-memory function that
21
+ * is intentionally NOT serialisable — see `ruleSchema.ts` for the reasoning.
22
+ */
23
+
24
+ import type { Signal } from '../reactivity/signal'
25
+
26
+ // ---------------------------------------------------------------------------
27
+ // MarketSnapshot — the read-only input fed into every predicate.
28
+ // ---------------------------------------------------------------------------
29
+
30
+ /**
31
+ * A snapshot of "the chart right now" that all predicates evaluate against.
32
+ *
33
+ * Callers are expected to populate as much as they have. A predicate that
34
+ * needs a sub-field absent from the snapshot must return `false` (no spurious
35
+ * fires from missing data).
36
+ */
37
+ export interface MarketSnapshot {
38
+ /** Latest closed bar; `null` for an empty stream. */
39
+ bar: {
40
+ timestamp: number
41
+ open: number
42
+ high: number
43
+ low: number
44
+ close: number
45
+ volume: number
46
+ } | null
47
+ /** Latest scalar value per indicator id (keyed by your indicator instance id). */
48
+ indicators: Readonly<Record<string, number>>
49
+ /**
50
+ * Average volume across the last N bars, keyed by N. Required for the
51
+ * `volume-spike` predicate to be O(1) — the caller maintains the rolling
52
+ * mean elsewhere.
53
+ */
54
+ rollingVolume: Readonly<Record<number, number>>
55
+ /** Optional advanced components (filled only when those components are mounted). */
56
+ volumeProfile?: { poc: number; vah: number; val: number }
57
+ orderBook?: {
58
+ medianBidSize: number
59
+ medianAskSize: number
60
+ maxBidSize: number
61
+ maxAskSize: number
62
+ }
63
+ footprint?: {
64
+ latestBarMaxImbalanceRatio: number
65
+ latestBarImbalanceCount: number
66
+ }
67
+ }
68
+
69
+ // ---------------------------------------------------------------------------
70
+ // AlertPredicate — discriminated union of supported predicate kinds.
71
+ // ---------------------------------------------------------------------------
72
+
73
+ export type CrossDirection = 'up' | 'down' | 'any'
74
+ export type IndicatorCrossPairDirection = 'a-above-b' | 'a-below-b' | 'any'
75
+
76
+ /**
77
+ * Predicate kinds. Add new kinds by extending the union — the controller's
78
+ * switch in `predicates.ts` will give a TS exhaustiveness error if you forget
79
+ * to handle it.
80
+ */
81
+ export type AlertPredicate =
82
+ | { kind: 'price-cross'; price: number; direction: CrossDirection }
83
+ | { kind: 'price-in-range'; min: number; max: number }
84
+ | { kind: 'price-out-of-range'; min: number; max: number }
85
+ | {
86
+ kind: 'indicator-cross'
87
+ indicatorId: string
88
+ threshold: number
89
+ direction: CrossDirection
90
+ }
91
+ | {
92
+ kind: 'indicator-cross-indicator'
93
+ aId: string
94
+ bId: string
95
+ direction: IndicatorCrossPairDirection
96
+ }
97
+ | { kind: 'volume-spike'; multipleOfAvg: number; lookbackBars: number }
98
+ | { kind: 'volume-profile-poc-touch'; bandPercent: number }
99
+ | { kind: 'order-book-wall'; sizeMultipleOfMedian: number }
100
+ | {
101
+ kind: 'footprint-imbalance'
102
+ minImbalanceRatio: number
103
+ consecutivePriceLevels: number
104
+ }
105
+ /**
106
+ * Escape hatch. The `evaluate` function runs INSIDE a try/catch in the
107
+ * controller — a throwing custom predicate must not crash the alert pass.
108
+ * Custom predicates CANNOT be serialised; see `ruleSchema.ts`.
109
+ */
110
+ | { kind: 'custom'; evaluate: (snapshot: MarketSnapshot) => boolean }
111
+
112
+ export type AlertPredicateKind = AlertPredicate['kind']
113
+
114
+ // ---------------------------------------------------------------------------
115
+ // AlertRule + AlertEvent
116
+ // ---------------------------------------------------------------------------
117
+
118
+ export interface AlertRule {
119
+ id: string
120
+ name: string
121
+ predicate: AlertPredicate
122
+ enabled: boolean
123
+ /** Fire once and then auto-disable. */
124
+ oneShot: boolean
125
+ /**
126
+ * For non-oneShot rules, suppress re-fires within this window (ms after
127
+ * the last fire). Undefined / 0 = no cooldown.
128
+ */
129
+ cooldownMs?: number
130
+ /** Free-form metadata propagated onto fired events. */
131
+ metadata?: Readonly<Record<string, unknown>>
132
+ }
133
+
134
+ export interface AlertEvent {
135
+ ruleId: string
136
+ ruleName: string
137
+ /** ms since epoch, passed in by the caller as `now`. */
138
+ triggeredAt: number
139
+ /** Snapshot of the bar that triggered the rule (copied, not referenced). */
140
+ snapshotBar: MarketSnapshot['bar']
141
+ metadata?: Readonly<Record<string, unknown>>
142
+ }
143
+
144
+ // ---------------------------------------------------------------------------
145
+ // AlertController — the public, framework-agnostic facade.
146
+ // ---------------------------------------------------------------------------
147
+
148
+ export interface AlertController {
149
+ /** Current rules, in insertion order. Reactive. */
150
+ readonly rules: Signal<ReadonlyArray<AlertRule>>
151
+ /** Bounded ring of recent events, newest last. Reactive. */
152
+ readonly events: Signal<ReadonlyArray<AlertEvent>>
153
+
154
+ /** Add a rule; returns false if a rule with the same id already exists. */
155
+ addRule(rule: AlertRule): boolean
156
+ removeRule(id: string): boolean
157
+ setRuleEnabled(id: string, enabled: boolean): boolean
158
+ /** Patch any field except `id`. Returns false if the id is unknown. */
159
+ updateRule(id: string, patch: Partial<Omit<AlertRule, 'id'>>): boolean
160
+
161
+ /**
162
+ * Evaluate every enabled rule against the snapshot. Returns the events
163
+ * fired on this call (also appended to the `events` signal).
164
+ */
165
+ evaluate(snapshot: MarketSnapshot, now: number): ReadonlyArray<AlertEvent>
166
+
167
+ clearEvents(): void
168
+ /** Per-fire listener; returns an unsubscribe. */
169
+ onEvent(listener: (event: AlertEvent) => void): () => void
170
+
171
+ dispose(): void
172
+ }
173
+
174
+ export interface AlertControllerOptions {
175
+ /** Maximum size of the `events` ring buffer. Default 100. */
176
+ maxEvents?: number
177
+ }
@@ -0,0 +1,122 @@
1
+ import { describe, it, expect } from 'vitest'
2
+ import { createHeikinAshi } from '../heikinAshi'
3
+ import type { OHLCV } from '../types'
4
+
5
+ const bar = (i: number, o: number, h: number, l: number, c: number, v = 100): OHLCV => ({
6
+ timestamp: 1_700_000_000_000 + i * 60_000,
7
+ open: o,
8
+ high: h,
9
+ low: l,
10
+ close: c,
11
+ volume: v,
12
+ })
13
+
14
+ describe('heikinAshi', () => {
15
+ it('seeds HA_open[0] = (open + close) / 2', () => {
16
+ const ha = createHeikinAshi()
17
+ const [out] = ha.transform([bar(0, 100, 110, 90, 108)], {})
18
+ expect(out).toBeDefined()
19
+ expect(out!.open).toBeCloseTo((100 + 108) / 2, 10)
20
+ expect(out!.close).toBeCloseTo((100 + 110 + 90 + 108) / 4, 10)
21
+ })
22
+
23
+ it('subsequent bars use HA_open = (prevHAOpen + prevHAClose) / 2', () => {
24
+ const ha = createHeikinAshi()
25
+ const out = ha.transform([bar(0, 100, 110, 90, 108), bar(1, 108, 120, 105, 118)], {})
26
+ const prev = out[0]!
27
+ const cur = out[1]!
28
+ expect(cur.open).toBeCloseTo((prev.open + prev.close) / 2, 10)
29
+ expect(cur.close).toBeCloseTo((108 + 120 + 105 + 118) / 4, 10)
30
+ })
31
+
32
+ it('HA_high >= max(HA_open, HA_close) and HA_high >= input high', () => {
33
+ const ha = createHeikinAshi()
34
+ const out = ha.transform(
35
+ [bar(0, 100, 110, 90, 108), bar(1, 108, 120, 105, 118), bar(2, 118, 125, 116, 120)],
36
+ {},
37
+ )
38
+ for (const b of out) {
39
+ expect(b.high).toBeGreaterThanOrEqual(Math.max(b.open, b.close))
40
+ expect(b.low).toBeLessThanOrEqual(Math.min(b.open, b.close))
41
+ }
42
+ })
43
+
44
+ it('strong uptrend in input produces consecutive bullish HA bars (close >= open)', () => {
45
+ const ha = createHeikinAshi()
46
+ const series: OHLCV[] = []
47
+ for (let i = 0; i < 10; i++) {
48
+ const base = 100 + i * 5
49
+ // Strong up bars: open near low, close at high.
50
+ series.push(bar(i, base, base + 6, base - 1, base + 5))
51
+ }
52
+ const out = ha.transform(series, {})
53
+ // The first bar may be ambiguous; expect the trend to dominate the tail.
54
+ const bullishTail = out.slice(2).every((b) => b.close >= b.open)
55
+ expect(bullishTail).toBe(true)
56
+ })
57
+
58
+ it('incremental mode produces identical output to batch mode over a random series', () => {
59
+ const series: OHLCV[] = []
60
+ let price = 100
61
+ // Deterministic pseudo-random walk for repeatability.
62
+ let seed = 12345
63
+ const rand = () => {
64
+ seed = (seed * 1103515245 + 12345) & 0x7fffffff
65
+ return seed / 0x7fffffff
66
+ }
67
+ for (let i = 0; i < 30; i++) {
68
+ const open = price
69
+ const drift = (rand() - 0.5) * 4
70
+ const close = open + drift
71
+ const high = Math.max(open, close) + rand() * 2
72
+ const low = Math.min(open, close) - rand() * 2
73
+ series.push(bar(i, open, high, low, close, Math.floor(rand() * 1000)))
74
+ price = close
75
+ }
76
+ const haBatch = createHeikinAshi()
77
+ const batched = haBatch.transform(series, {})
78
+
79
+ const haInc = createHeikinAshi()
80
+ const incremental = series.flatMap((b) => Array.from(haInc.appendBar!(b)))
81
+ expect(incremental.length).toBe(batched.length)
82
+ for (let i = 0; i < batched.length; i++) {
83
+ const a = batched[i]!
84
+ const b = incremental[i]!
85
+ expect(a.open).toBeCloseTo(b.open, 10)
86
+ expect(a.high).toBeCloseTo(b.high, 10)
87
+ expect(a.low).toBeCloseTo(b.low, 10)
88
+ expect(a.close).toBeCloseTo(b.close, 10)
89
+ expect(a.timestamp).toBe(b.timestamp)
90
+ expect(a.volume).toBe(b.volume)
91
+ expect(a.sourceBarIndexStart).toBe(b.sourceBarIndexStart)
92
+ }
93
+ })
94
+
95
+ it('reset() clears state so the next appendBar uses the seed formula', () => {
96
+ const ha = createHeikinAshi()
97
+ ha.appendBar!(bar(0, 100, 110, 90, 108))
98
+ ha.appendBar!(bar(1, 108, 115, 105, 112))
99
+ ha.reset!()
100
+ const [first] = ha.appendBar!(bar(2, 200, 210, 190, 205))
101
+ expect(first!.open).toBeCloseTo((200 + 205) / 2, 10)
102
+ expect(first!.sourceBarIndexStart).toBe(0)
103
+ })
104
+
105
+ it('handles single-bar input cleanly', () => {
106
+ const ha = createHeikinAshi()
107
+ const out = ha.transform([bar(0, 50, 55, 45, 52)], {})
108
+ expect(out).toHaveLength(1)
109
+ expect(out[0]!.open).toBeCloseTo((50 + 52) / 2, 10)
110
+ expect(out[0]!.high).toBeGreaterThanOrEqual(55)
111
+ expect(out[0]!.volume).toBe(100)
112
+ })
113
+
114
+ it('preserves source bar indices 1:1', () => {
115
+ const ha = createHeikinAshi()
116
+ const out = ha.transform([bar(0, 100, 110, 90, 108), bar(1, 108, 120, 105, 118)], {})
117
+ expect(out[0]!.sourceBarIndexStart).toBe(0)
118
+ expect(out[0]!.sourceBarIndexEnd).toBe(0)
119
+ expect(out[1]!.sourceBarIndexStart).toBe(1)
120
+ expect(out[1]!.sourceBarIndexEnd).toBe(1)
121
+ })
122
+ })