@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,312 @@
1
+ /**
2
+ * AlertController — framework-agnostic, signal-based.
3
+ *
4
+ * Same dispose-guard pattern as the other core controllers (volume-profile,
5
+ * indicator-selector). Adapters (React/Vue/Angular) subscribe to the
6
+ * `rules` and `events` signals via their native reactivity.
7
+ *
8
+ * Per-rule prev-snapshot:
9
+ * Cross-style predicates compare prev vs. curr. Rather than asking the
10
+ * caller to thread that state, the controller stashes the previous
11
+ * evaluation snapshot per rule id and feeds it back into the predicate.
12
+ * When a rule is added or re-enabled, its prev is reset — that prevents
13
+ * a spurious fire on first evaluation (a newly-added "price-cross 100"
14
+ * rule should NOT fire just because the current close happens to be 105).
15
+ *
16
+ * Cooldown:
17
+ * For non-oneShot rules we record `lastFiredAt` and suppress re-fires
18
+ * within `cooldownMs`. oneShot ignores cooldown — it just flips
19
+ * `enabled` to false on first fire.
20
+ *
21
+ * Crash safety:
22
+ * `kind: 'custom'` predicates run inside try/catch. A throwing predicate
23
+ * is caught, marked internally, and skipped for this pass; the rest of
24
+ * the rules continue to evaluate. Errors are swallowed at the boundary
25
+ * (no console.* per coding-style.md) — observability hooks are a future
26
+ * addition (`onError` listener on the controller).
27
+ */
28
+
29
+ import { createSignal, type Signal } from '../reactivity/signal'
30
+ import { evaluatePredicate } from './predicates'
31
+ import type {
32
+ AlertController,
33
+ AlertControllerOptions,
34
+ AlertEvent,
35
+ AlertRule,
36
+ MarketSnapshot,
37
+ } from './types'
38
+
39
+ const DEFAULT_MAX_EVENTS = 100
40
+
41
+ interface RuleRuntimeState {
42
+ /** Snapshot from the previous evaluation, for cross-style predicates. */
43
+ prev: MarketSnapshot | null
44
+ /** ms timestamp of last fire (for cooldown). undefined = never fired. */
45
+ lastFiredAt: number | undefined
46
+ }
47
+
48
+ export function createAlertController(
49
+ opts?: AlertControllerOptions,
50
+ ): AlertController {
51
+ const maxEvents = (() => {
52
+ const raw = opts?.maxEvents
53
+ if (raw === undefined) return DEFAULT_MAX_EVENTS
54
+ if (!Number.isFinite(raw) || raw < 1) return DEFAULT_MAX_EVENTS
55
+ return Math.floor(raw)
56
+ })()
57
+
58
+ // -----------------------------------------------------------------------
59
+ // Signals — frozen arrays so React/Vue see new identity on every change.
60
+ // -----------------------------------------------------------------------
61
+ const rules: Signal<ReadonlyArray<AlertRule>> = createSignal<
62
+ ReadonlyArray<AlertRule>
63
+ >([])
64
+ const events: Signal<ReadonlyArray<AlertEvent>> = createSignal<
65
+ ReadonlyArray<AlertEvent>
66
+ >([])
67
+
68
+ // -----------------------------------------------------------------------
69
+ // Private state
70
+ // -----------------------------------------------------------------------
71
+ const runtime = new Map<string, RuleRuntimeState>()
72
+ const listeners = new Set<(event: AlertEvent) => void>()
73
+
74
+ let disposed = false
75
+
76
+ function findIndex(id: string): number {
77
+ const arr = rules.peek()
78
+ for (let i = 0; i < arr.length; i++) {
79
+ if (arr[i]!.id === id) return i
80
+ }
81
+ return -1
82
+ }
83
+
84
+ function replaceAt(arr: ReadonlyArray<AlertRule>, i: number, next: AlertRule): ReadonlyArray<AlertRule> {
85
+ const copy = arr.slice()
86
+ copy[i] = next
87
+ return copy
88
+ }
89
+
90
+ // -----------------------------------------------------------------------
91
+ // addRule / removeRule / setRuleEnabled / updateRule
92
+ // -----------------------------------------------------------------------
93
+
94
+ function addRule(rule: AlertRule): boolean {
95
+ if (findIndex(rule.id) >= 0) return false
96
+ // Defensive shallow copy so external mutation of the caller's object
97
+ // does not affect controller state.
98
+ const stored: AlertRule = {
99
+ ...rule,
100
+ metadata:
101
+ rule.metadata !== undefined ? { ...rule.metadata } : undefined,
102
+ }
103
+ rules.set([...rules.peek(), stored])
104
+ runtime.set(rule.id, { prev: null, lastFiredAt: undefined })
105
+ return true
106
+ }
107
+
108
+ function removeRule(id: string): boolean {
109
+ const idx = findIndex(id)
110
+ if (idx < 0) return false
111
+ const copy = rules.peek().slice()
112
+ copy.splice(idx, 1)
113
+ rules.set(copy)
114
+ runtime.delete(id)
115
+ return true
116
+ }
117
+
118
+ function setRuleEnabled(id: string, enabled: boolean): boolean {
119
+ const idx = findIndex(id)
120
+ if (idx < 0) return false
121
+ const cur = rules.peek()[idx]!
122
+ if (cur.enabled === enabled) return true // no-op but reports success
123
+ const next: AlertRule = { ...cur, enabled }
124
+ rules.set(replaceAt(rules.peek(), idx, next))
125
+ // Re-enabling resets prev — a freshly enabled cross rule should not
126
+ // fire on the first eval just because the level is already broken.
127
+ if (enabled) {
128
+ runtime.set(id, { prev: null, lastFiredAt: undefined })
129
+ }
130
+ return true
131
+ }
132
+
133
+ function updateRule(
134
+ id: string,
135
+ patch: Partial<Omit<AlertRule, 'id'>>,
136
+ ): boolean {
137
+ const idx = findIndex(id)
138
+ if (idx < 0) return false
139
+ const cur = rules.peek()[idx]!
140
+ const next: AlertRule = {
141
+ ...cur,
142
+ ...patch,
143
+ id: cur.id, // id is invariant
144
+ metadata:
145
+ patch.metadata !== undefined
146
+ ? { ...patch.metadata }
147
+ : cur.metadata,
148
+ }
149
+ rules.set(replaceAt(rules.peek(), idx, next))
150
+ // Changing the predicate invalidates prev — different predicates may
151
+ // need different prev fields, and a stale prev could cause a spurious
152
+ // fire on next eval.
153
+ if (patch.predicate !== undefined) {
154
+ runtime.set(id, { prev: null, lastFiredAt: undefined })
155
+ }
156
+ return true
157
+ }
158
+
159
+ // -----------------------------------------------------------------------
160
+ // evaluate — the hot path. Safe to call every frame.
161
+ // -----------------------------------------------------------------------
162
+
163
+ function evaluate(
164
+ snapshot: MarketSnapshot,
165
+ now: number,
166
+ ): ReadonlyArray<AlertEvent> {
167
+ const fired: AlertEvent[] = []
168
+ const currentRules = rules.peek()
169
+
170
+ // We may need to flip oneShot rules off — collect indices and apply
171
+ // once at the end to avoid mutating `currentRules` mid-loop.
172
+ const toDisable: number[] = []
173
+
174
+ for (let i = 0; i < currentRules.length; i++) {
175
+ const rule = currentRules[i]!
176
+ if (!rule.enabled) continue
177
+
178
+ const rt = runtime.get(rule.id) ?? {
179
+ prev: null,
180
+ lastFiredAt: undefined,
181
+ }
182
+ // Cooldown gate (applies to non-oneShot rules; oneShot rules
183
+ // can only fire once anyway).
184
+ if (
185
+ !rule.oneShot &&
186
+ rule.cooldownMs !== undefined &&
187
+ rule.cooldownMs > 0 &&
188
+ rt.lastFiredAt !== undefined &&
189
+ now - rt.lastFiredAt < rule.cooldownMs
190
+ ) {
191
+ // Still update prev so the next eval after cooldown has the
192
+ // right reference point for cross detection.
193
+ rt.prev = snapshot
194
+ runtime.set(rule.id, rt)
195
+ continue
196
+ }
197
+
198
+ // Evaluate. Custom predicates can throw — wrap.
199
+ let hit = false
200
+ try {
201
+ hit = evaluatePredicate(rule.predicate, snapshot, rt.prev)
202
+ } catch {
203
+ // Swallow per crash-safety contract. Do NOT fire. Continue.
204
+ hit = false
205
+ }
206
+
207
+ if (hit) {
208
+ const event: AlertEvent = {
209
+ ruleId: rule.id,
210
+ ruleName: rule.name,
211
+ triggeredAt: now,
212
+ snapshotBar:
213
+ snapshot.bar !== null ? { ...snapshot.bar } : null,
214
+ metadata: rule.metadata,
215
+ }
216
+ fired.push(event)
217
+ rt.lastFiredAt = now
218
+ if (rule.oneShot) {
219
+ toDisable.push(i)
220
+ }
221
+ }
222
+
223
+ rt.prev = snapshot
224
+ runtime.set(rule.id, rt)
225
+ }
226
+
227
+ if (fired.length > 0) {
228
+ // Append fired events to the ring, capped at maxEvents.
229
+ const prevEvents = events.peek()
230
+ const merged = prevEvents.concat(fired)
231
+ const trimmed =
232
+ merged.length > maxEvents
233
+ ? merged.slice(merged.length - maxEvents)
234
+ : merged
235
+ events.set(trimmed)
236
+
237
+ // Notify per-event listeners. Copy first so a listener that
238
+ // unsubscribes during fire-out doesn't mutate the iteration.
239
+ const snapshotListeners = [...listeners]
240
+ for (const ev of fired) {
241
+ for (const l of snapshotListeners) {
242
+ try {
243
+ l(ev)
244
+ } catch {
245
+ // listener errors are isolated — never leak across.
246
+ }
247
+ }
248
+ }
249
+ }
250
+
251
+ if (toDisable.length > 0) {
252
+ const copy = rules.peek().slice()
253
+ for (const i of toDisable) {
254
+ const r = copy[i]
255
+ if (r !== undefined) copy[i] = { ...r, enabled: false }
256
+ }
257
+ rules.set(copy)
258
+ }
259
+
260
+ return fired
261
+ }
262
+
263
+ // -----------------------------------------------------------------------
264
+ // events / listener management
265
+ // -----------------------------------------------------------------------
266
+
267
+ function clearEvents(): void {
268
+ if (events.peek().length === 0) return
269
+ events.set([])
270
+ }
271
+
272
+ function onEvent(listener: (event: AlertEvent) => void): () => void {
273
+ listeners.add(listener)
274
+ return () => {
275
+ listeners.delete(listener)
276
+ }
277
+ }
278
+
279
+ // -----------------------------------------------------------------------
280
+ // dispose
281
+ // -----------------------------------------------------------------------
282
+
283
+ function dispose(): void {
284
+ if (disposed) return
285
+ disposed = true
286
+ listeners.clear()
287
+ runtime.clear()
288
+ }
289
+
290
+ function guard<T extends (...args: never[]) => unknown>(
291
+ fn: T,
292
+ fallback: ReturnType<T>,
293
+ ): T {
294
+ return ((...args: Parameters<T>): ReturnType<T> => {
295
+ if (disposed) return fallback
296
+ return fn(...args) as ReturnType<T>
297
+ }) as T
298
+ }
299
+
300
+ return {
301
+ rules,
302
+ events,
303
+ addRule: guard(addRule, false as boolean) as AlertController['addRule'],
304
+ removeRule: guard(removeRule, false as boolean) as AlertController['removeRule'],
305
+ setRuleEnabled: guard(setRuleEnabled, false as boolean) as AlertController['setRuleEnabled'],
306
+ updateRule: guard(updateRule, false as boolean) as AlertController['updateRule'],
307
+ evaluate: guard(evaluate, [] as ReadonlyArray<AlertEvent>) as AlertController['evaluate'],
308
+ clearEvents: guard(clearEvents, undefined as void) as AlertController['clearEvents'],
309
+ onEvent: guard(onEvent, (() => undefined) as () => void) as AlertController['onEvent'],
310
+ dispose,
311
+ }
312
+ }
@@ -0,0 +1,18 @@
1
+ export type {
2
+ AlertController,
3
+ AlertControllerOptions,
4
+ AlertEvent,
5
+ AlertPredicate,
6
+ AlertPredicateKind,
7
+ AlertRule,
8
+ CrossDirection,
9
+ IndicatorCrossPairDirection,
10
+ MarketSnapshot,
11
+ } from './types'
12
+ export { createAlertController } from './createAlertController'
13
+ export { evaluatePredicate } from './predicates'
14
+ export {
15
+ AlertRuleSchemaError,
16
+ deserializeRule,
17
+ serializeRule,
18
+ } from './ruleSchema'
@@ -0,0 +1,231 @@
1
+ /**
2
+ * Built-in predicate kit.
3
+ *
4
+ * Each predicate is a pure function over `(predicate, curr, prev)`:
5
+ * - `curr` is the snapshot at the current evaluation.
6
+ * - `prev` is the snapshot from the previous evaluation of the SAME rule
7
+ * (the controller threads it through). For cross-style predicates the
8
+ * prev value is what makes "just-crossed" detectable vs. "is above".
9
+ * - When `prev` is null (first evaluation), cross predicates must NOT fire —
10
+ * we cannot distinguish "already above" from "just crossed up" without a
11
+ * reference point.
12
+ *
13
+ * All predicates are O(1) — no scanning of history. The caller pre-computes
14
+ * any rolling state (e.g. `rollingVolume[N]`).
15
+ *
16
+ * Defensive: predicates return `false` for any required field that is null,
17
+ * undefined, or non-finite. We never throw — a bad snapshot must not crash
18
+ * an entire alert pass.
19
+ */
20
+
21
+ import type {
22
+ AlertPredicate,
23
+ CrossDirection,
24
+ IndicatorCrossPairDirection,
25
+ MarketSnapshot,
26
+ } from './types'
27
+
28
+ // ---------------------------------------------------------------------------
29
+ // Helpers
30
+ // ---------------------------------------------------------------------------
31
+
32
+ function isFiniteNumber(x: unknown): x is number {
33
+ return typeof x === 'number' && Number.isFinite(x)
34
+ }
35
+
36
+ /**
37
+ * Generic numeric cross check.
38
+ * - up : prev < threshold && curr >= threshold
39
+ * - down : prev > threshold && curr <= threshold
40
+ * - any : either
41
+ *
42
+ * Returns false if either side is non-finite. The `>=` / `<=` on the curr side
43
+ * is intentional — a value landing exactly on the threshold counts as a cross
44
+ * the instant it arrives (matches trader intuition: "alert me when price hits
45
+ * 100" should fire at 100, not require 100.01).
46
+ */
47
+ function crossed(
48
+ prevValue: number | null,
49
+ currValue: number,
50
+ threshold: number,
51
+ direction: CrossDirection,
52
+ ): boolean {
53
+ if (prevValue === null || !isFiniteNumber(prevValue)) return false
54
+ if (!isFiniteNumber(currValue) || !isFiniteNumber(threshold)) return false
55
+ const up = prevValue < threshold && currValue >= threshold
56
+ const down = prevValue > threshold && currValue <= threshold
57
+ if (direction === 'up') return up
58
+ if (direction === 'down') return down
59
+ return up || down
60
+ }
61
+
62
+ /**
63
+ * Cross of two series A vs B (indicator vs indicator). Direction:
64
+ * - a-above-b : A was <= B and is now > B (A crossed UP through B)
65
+ * - a-below-b : A was >= B and is now < B (A crossed DOWN through B)
66
+ * - any : either
67
+ *
68
+ * Note the asymmetric strictness vs. `crossed`: here we use strict inequality
69
+ * on the post side because equality of two floats is rare and ambiguous — we
70
+ * wait for the next tick of separation.
71
+ */
72
+ function crossedPair(
73
+ prevA: number | null,
74
+ prevB: number | null,
75
+ currA: number,
76
+ currB: number,
77
+ direction: IndicatorCrossPairDirection,
78
+ ): boolean {
79
+ if (prevA === null || prevB === null) return false
80
+ if (!isFiniteNumber(prevA) || !isFiniteNumber(prevB)) return false
81
+ if (!isFiniteNumber(currA) || !isFiniteNumber(currB)) return false
82
+ const aAboveB = prevA <= prevB && currA > currB
83
+ const aBelowB = prevA >= prevB && currA < currB
84
+ if (direction === 'a-above-b') return aAboveB
85
+ if (direction === 'a-below-b') return aBelowB
86
+ return aAboveB || aBelowB
87
+ }
88
+
89
+ // ---------------------------------------------------------------------------
90
+ // evaluatePredicate — the dispatch
91
+ // ---------------------------------------------------------------------------
92
+
93
+ /**
94
+ * Returns `true` iff the predicate fires for this (prev, curr) pair.
95
+ *
96
+ * The controller wraps `kind: 'custom'` in its own try/catch — but we still
97
+ * defensively guard against the function being missing here.
98
+ */
99
+ export function evaluatePredicate(
100
+ predicate: AlertPredicate,
101
+ curr: MarketSnapshot,
102
+ prev: MarketSnapshot | null,
103
+ ): boolean {
104
+ switch (predicate.kind) {
105
+ case 'price-cross': {
106
+ const cBar = curr.bar
107
+ const pBar = prev?.bar ?? null
108
+ if (cBar === null || !isFiniteNumber(cBar.close)) return false
109
+ const prevClose =
110
+ pBar !== null && isFiniteNumber(pBar.close) ? pBar.close : null
111
+ return crossed(prevClose, cBar.close, predicate.price, predicate.direction)
112
+ }
113
+
114
+ case 'price-in-range': {
115
+ const cBar = curr.bar
116
+ if (cBar === null || !isFiniteNumber(cBar.close)) return false
117
+ const { min, max } = predicate
118
+ if (!isFiniteNumber(min) || !isFiniteNumber(max)) return false
119
+ return cBar.close >= min && cBar.close <= max
120
+ }
121
+
122
+ case 'price-out-of-range': {
123
+ const cBar = curr.bar
124
+ if (cBar === null || !isFiniteNumber(cBar.close)) return false
125
+ const { min, max } = predicate
126
+ if (!isFiniteNumber(min) || !isFiniteNumber(max)) return false
127
+ return cBar.close < min || cBar.close > max
128
+ }
129
+
130
+ case 'indicator-cross': {
131
+ const id = predicate.indicatorId
132
+ const cVal = curr.indicators[id]
133
+ if (cVal === undefined || !isFiniteNumber(cVal)) return false
134
+ const pRaw = prev?.indicators[id]
135
+ const pVal = pRaw !== undefined && isFiniteNumber(pRaw) ? pRaw : null
136
+ return crossed(pVal, cVal, predicate.threshold, predicate.direction)
137
+ }
138
+
139
+ case 'indicator-cross-indicator': {
140
+ const { aId, bId, direction } = predicate
141
+ const cA = curr.indicators[aId]
142
+ const cB = curr.indicators[bId]
143
+ if (
144
+ cA === undefined ||
145
+ cB === undefined ||
146
+ !isFiniteNumber(cA) ||
147
+ !isFiniteNumber(cB)
148
+ ) {
149
+ return false
150
+ }
151
+ const pARaw = prev?.indicators[aId]
152
+ const pBRaw = prev?.indicators[bId]
153
+ const pA = pARaw !== undefined && isFiniteNumber(pARaw) ? pARaw : null
154
+ const pB = pBRaw !== undefined && isFiniteNumber(pBRaw) ? pBRaw : null
155
+ return crossedPair(pA, pB, cA, cB, direction)
156
+ }
157
+
158
+ case 'volume-spike': {
159
+ const cBar = curr.bar
160
+ if (cBar === null || !isFiniteNumber(cBar.volume)) return false
161
+ const avg = curr.rollingVolume[predicate.lookbackBars]
162
+ // Missing avg or zero avg → no useful baseline; do not fire.
163
+ if (avg === undefined || !isFiniteNumber(avg) || avg <= 0) return false
164
+ if (!isFiniteNumber(predicate.multipleOfAvg)) return false
165
+ return cBar.volume >= avg * predicate.multipleOfAvg
166
+ }
167
+
168
+ case 'volume-profile-poc-touch': {
169
+ const cBar = curr.bar
170
+ const vp = curr.volumeProfile
171
+ if (cBar === null || !isFiniteNumber(cBar.close)) return false
172
+ if (vp === undefined || !isFiniteNumber(vp.poc) || vp.poc === 0) return false
173
+ if (!isFiniteNumber(predicate.bandPercent)) return false
174
+ const distance = Math.abs(cBar.close - vp.poc) / Math.abs(vp.poc)
175
+ return distance <= predicate.bandPercent
176
+ }
177
+
178
+ case 'order-book-wall': {
179
+ const ob = curr.orderBook
180
+ if (ob === undefined) return false
181
+ const { sizeMultipleOfMedian: k } = predicate
182
+ if (!isFiniteNumber(k)) return false
183
+ const bidHit =
184
+ isFiniteNumber(ob.medianBidSize) &&
185
+ isFiniteNumber(ob.maxBidSize) &&
186
+ ob.medianBidSize > 0 &&
187
+ ob.maxBidSize >= ob.medianBidSize * k
188
+ const askHit =
189
+ isFiniteNumber(ob.medianAskSize) &&
190
+ isFiniteNumber(ob.maxAskSize) &&
191
+ ob.medianAskSize > 0 &&
192
+ ob.maxAskSize >= ob.medianAskSize * k
193
+ return bidHit || askHit
194
+ }
195
+
196
+ case 'footprint-imbalance': {
197
+ const fp = curr.footprint
198
+ if (fp === undefined) return false
199
+ if (
200
+ !isFiniteNumber(fp.latestBarMaxImbalanceRatio) ||
201
+ !isFiniteNumber(fp.latestBarImbalanceCount)
202
+ ) {
203
+ return false
204
+ }
205
+ return (
206
+ fp.latestBarMaxImbalanceRatio >= predicate.minImbalanceRatio &&
207
+ fp.latestBarImbalanceCount >= predicate.consecutivePriceLevels
208
+ )
209
+ }
210
+
211
+ case 'custom': {
212
+ if (typeof predicate.evaluate !== 'function') return false
213
+ // The controller also wraps this call in try/catch; the inner
214
+ // guard here protects callers that invoke predicates directly
215
+ // (e.g. tests or third-party tooling).
216
+ try {
217
+ return predicate.evaluate(curr) === true
218
+ } catch {
219
+ return false
220
+ }
221
+ }
222
+
223
+ default: {
224
+ // Exhaustiveness check — adding a new kind without a case here
225
+ // will surface as a TS error on this line.
226
+ const _exhaustive: never = predicate
227
+ void _exhaustive
228
+ return false
229
+ }
230
+ }
231
+ }
@@ -0,0 +1,51 @@
1
+ import type { MarketSnapshot } from './types'
2
+
3
+ export class RollingVolumeCalculator {
4
+ private buffer: number[]
5
+ private sum = 0
6
+ private cursor = 0
7
+ private filled = false
8
+
9
+ constructor(public readonly size: number) {
10
+ this.buffer = new Array(size)
11
+ }
12
+
13
+ push(volume: number): number {
14
+ if (this.filled) {
15
+ this.sum -= this.buffer[this.cursor]!
16
+ }
17
+ this.buffer[this.cursor] = volume
18
+ this.sum += volume
19
+ this.cursor = (this.cursor + 1) % this.size
20
+ if (!this.filled && this.cursor === 0) {
21
+ this.filled = true
22
+ }
23
+ return this.mean
24
+ }
25
+
26
+ get mean(): number {
27
+ const count = this.filled ? this.size : this.cursor
28
+ return count > 0 ? this.sum / count : 0
29
+ }
30
+ }
31
+
32
+ export type VolumeLookbacks = Map<number, RollingVolumeCalculator>
33
+
34
+ export function createVolumeLookbacks(sizes: number[]): VolumeLookbacks {
35
+ const map = new Map<number, RollingVolumeCalculator>()
36
+ for (const size of sizes) {
37
+ map.set(size, new RollingVolumeCalculator(size))
38
+ }
39
+ return map
40
+ }
41
+
42
+ export function pushToVolumeLookbacks(
43
+ lookbacks: VolumeLookbacks,
44
+ volume: number,
45
+ ): MarketSnapshot['rollingVolume'] {
46
+ const result: Record<number, number> = {}
47
+ for (const [size, calc] of lookbacks) {
48
+ result[size] = calc.push(volume)
49
+ }
50
+ return result
51
+ }