@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,168 @@
1
+ /**
2
+ * L2 Order Book Heatmap — public types.
3
+ *
4
+ * Implements the data model described in `docs/ROADMAP.md` §3.2.
5
+ *
6
+ * Critique addressed (PR23): the live render path uses fixed-cadence
7
+ * snapshots (cheap to upload to a GPU storage buffer), while a parallel
8
+ * append-only delta archive preserves the full event stream so that
9
+ * sub-snapshot "flash orders" can be replayed exactly. Snapshot ring is
10
+ * the render source; delta archive is the source of truth.
11
+ *
12
+ * No file in this module imports from `src/` — this component is part of
13
+ * the additive `packages/core/` work.
14
+ */
15
+
16
+ import type { Signal } from '../../reactivity'
17
+
18
+ // ---------------------------------------------------------------------------
19
+ // Inbound stream
20
+ // ---------------------------------------------------------------------------
21
+
22
+ /**
23
+ * One exchange-pushed delta. `size === 0` means the price level is removed.
24
+ *
25
+ * Timestamp is the **exchange** wall-clock in milliseconds — we use it as
26
+ * the controller's clock so the system is deterministic for tests and
27
+ * correct under bursty traffic (no setInterval).
28
+ */
29
+ export interface OrderBookDelta {
30
+ side: 'bid' | 'ask'
31
+ price: number
32
+ size: number
33
+ timestamp: number
34
+ }
35
+
36
+ // ---------------------------------------------------------------------------
37
+ // Snapshot
38
+ // ---------------------------------------------------------------------------
39
+
40
+ /**
41
+ * Immutable view of the book at one instant. Prices in this object are
42
+ * always returned in their **dequantized** (real-world) form — clients
43
+ * never see the integer tick index.
44
+ *
45
+ * Bids are sorted descending (best bid first), asks ascending (best ask
46
+ * first). Each entry is `[price, size]`.
47
+ */
48
+ export interface BookSnapshot {
49
+ readonly bids: ReadonlyArray<readonly [number, number]>
50
+ readonly asks: ReadonlyArray<readonly [number, number]>
51
+ readonly timestamp: number
52
+ }
53
+
54
+ // ---------------------------------------------------------------------------
55
+ // State accumulator
56
+ // ---------------------------------------------------------------------------
57
+
58
+ export interface OrderBookStateOptions {
59
+ /** quantize all input prices to this tick (e.g. 0.01 = cents) */
60
+ tickSize: number
61
+ /** keep at most this many levels per side; oldest-by-distance dropped */
62
+ maxLevels?: number
63
+ }
64
+
65
+ export interface OrderBookState {
66
+ /** Apply one delta. `size === 0` removes the level. */
67
+ applyDelta(delta: OrderBookDelta): void
68
+ /** Take a fresh snapshot (prices dequantized). */
69
+ snapshot(): BookSnapshot
70
+ /** Empty both sides. */
71
+ clear(): void
72
+ /** Latest timestamp seen via {@link applyDelta}. */
73
+ lastTimestamp(): number
74
+ }
75
+
76
+ // ---------------------------------------------------------------------------
77
+ // Snapshot ring (live render path)
78
+ // ---------------------------------------------------------------------------
79
+
80
+ export interface SnapshotRing {
81
+ readonly capacity: number
82
+ push(snapshot: BookSnapshot): void
83
+ /** snapshots oldest → newest; never contains gaps */
84
+ toArray(): ReadonlyArray<BookSnapshot>
85
+ size(): number
86
+ clear(): void
87
+ }
88
+
89
+ // ---------------------------------------------------------------------------
90
+ // Delta archive (replay path)
91
+ // ---------------------------------------------------------------------------
92
+
93
+ export interface DeltaArchive {
94
+ append(delta: OrderBookDelta): void
95
+ /** inclusive range; deltas with `from <= ts <= to` */
96
+ range(fromTimestamp: number, toTimestamp: number): ReadonlyArray<OrderBookDelta>
97
+ size(): number
98
+ clear(): void
99
+ /** drop oldest deltas until total size ≤ maxSize */
100
+ trim(maxSize: number): void
101
+ }
102
+
103
+ export interface DeltaArchiveOptions {
104
+ /** when set, the archive self-trims after each {@link DeltaArchive.append} */
105
+ maxSize?: number
106
+ }
107
+
108
+ // ---------------------------------------------------------------------------
109
+ // Log color scale
110
+ // ---------------------------------------------------------------------------
111
+
112
+ export interface LogColorScale {
113
+ /** returns intensity in [0,1] for the given size */
114
+ intensity(size: number): number
115
+ /** swap the size range (does not retroactively rescale anything) */
116
+ setRange(sizeMin: number, sizeMax: number): void
117
+ /** current range (for callers that need to mirror it into GPU uniforms) */
118
+ range(): { sizeMin: number; sizeMax: number }
119
+ }
120
+
121
+ // ---------------------------------------------------------------------------
122
+ // Top-level controller
123
+ // ---------------------------------------------------------------------------
124
+
125
+ export interface HeatmapControllerConfig {
126
+ tickSize: number
127
+ snapshotIntervalMs: number
128
+ snapshotRingCapacity: number
129
+ deltaArchiveMaxSize: number
130
+ logColorRange: { sizeMin: number; sizeMax: number }
131
+ }
132
+
133
+ export interface HeatmapState {
134
+ readonly latestSnapshot: BookSnapshot | null
135
+ readonly snapshotCount: number
136
+ readonly deltaCount: number
137
+ }
138
+
139
+ export interface HeatmapController {
140
+ readonly state: Signal<HeatmapState>
141
+
142
+ /**
143
+ * Ingest one L2 delta — canonical method, aligned with the cross-controller
144
+ * `ingest()` convention (VolumeProfile, Footprint). Closes API audit
145
+ * BLOCKER-001 (5-verb intake proliferation).
146
+ */
147
+ ingest(delta: OrderBookDelta): void
148
+
149
+ /**
150
+ * @deprecated since 0.1.0-alpha.1 — use {@link HeatmapController.ingest}.
151
+ * Kept as a non-removing alias for at least 6 months for migration.
152
+ */
153
+ ingestDelta(delta: OrderBookDelta): void
154
+ /** Force a snapshot now using the controller's current state. */
155
+ forceSnapshot(): void
156
+ /**
157
+ * Reconstruct snapshots at a regular cadence by replaying the delta archive.
158
+ * `from` is the first snapshot timestamp, `to` is exclusive upper bound.
159
+ */
160
+ replay(
161
+ fromTimestamp: number,
162
+ toTimestamp: number,
163
+ snapshotIntervalMs: number,
164
+ ): ReadonlyArray<BookSnapshot>
165
+
166
+ setConfig(next: Partial<HeatmapControllerConfig>): void
167
+ dispose(): void
168
+ }
@@ -0,0 +1,133 @@
1
+ /**
2
+ * Tests for `binBarToBuckets` — bar → bucket volume distribution.
3
+ *
4
+ * Modes covered:
5
+ * - `typical-price`: drop entire bar volume into the bucket holding
6
+ * `(high+low+close)/3`; silently skip if the typical price falls outside
7
+ * `[binMin, binMin + binCount*binSize)`.
8
+ * - `proportional`: split the bar's volume across every bucket that
9
+ * overlaps `[low, high]`, weighted by per-bucket overlap.
10
+ *
11
+ * All assertions are anchored to the actual implementation in
12
+ * `binning.ts`; if the algorithm diverges from the brief, the test reflects
13
+ * the implementation (not the brief).
14
+ */
15
+
16
+ import { describe, it, expect } from 'vitest'
17
+
18
+ import { binBarToBuckets } from '../binning'
19
+ import type { VolumeProfileBar } from '../types'
20
+
21
+ function makeBuckets(n: number): Float64Array {
22
+ return new Float64Array(n)
23
+ }
24
+
25
+ describe('binBarToBuckets — typical-price mode', () => {
26
+ it('drops the entire bar volume into the bucket containing the typical price', () => {
27
+ // high=100, low=90, close=95 → typical = (100+90+95)/3 = 95
28
+ const bar: VolumeProfileBar = { high: 100, low: 90, close: 95, volume: 1000 }
29
+ // Bucket grid: binMin=90, binSize=1, binCount=10 → buckets cover [90, 100).
30
+ // Typical price 95 → idx = floor((95-90)/1) = 5 → buckets[5].
31
+ const buckets = makeBuckets(10)
32
+ binBarToBuckets(bar, buckets, 90, 1, 10, 'typical-price')
33
+ expect(buckets[5]).toBe(1000)
34
+ // No other buckets touched.
35
+ for (let i = 0; i < 10; i++) {
36
+ if (i !== 5) expect(buckets[i]).toBe(0)
37
+ }
38
+ })
39
+
40
+ it('silently drops a bar whose typical price is below binMin', () => {
41
+ // bar fully below the grid: high/low/close all < binMin → typical < binMin.
42
+ const bar: VolumeProfileBar = { high: 10, low: 5, close: 7, volume: 500 }
43
+ const buckets = makeBuckets(10)
44
+ // Grid covers [100, 110).
45
+ binBarToBuckets(bar, buckets, 100, 1, 10, 'typical-price')
46
+ // Nothing should have been written.
47
+ for (let i = 0; i < 10; i++) expect(buckets[i]).toBe(0)
48
+ })
49
+
50
+ it('silently drops a bar whose typical price is at/above binMin + binCount*binSize', () => {
51
+ // bar fully above the grid: typical >> binMin + binCount*binSize.
52
+ const bar: VolumeProfileBar = { high: 1000, low: 500, close: 700, volume: 999 }
53
+ const buckets = makeBuckets(10)
54
+ // Grid covers [0, 10).
55
+ binBarToBuckets(bar, buckets, 0, 1, 10, 'typical-price')
56
+ for (let i = 0; i < 10; i++) expect(buckets[i]).toBe(0)
57
+ })
58
+ })
59
+
60
+ describe('binBarToBuckets — proportional mode', () => {
61
+ it('splits a bar covering exactly 2 buckets 500/500 on equal overlap', () => {
62
+ // Grid: binMin=0, binSize=1, binCount=10 → buckets [0,1), [1,2), ...
63
+ // Bar spans [3.0, 5.0) — exactly buckets 3 and 4, each contributing
64
+ // half the range. volume=1000 → 500 / 500.
65
+ const bar: VolumeProfileBar = { high: 5, low: 3, close: 4, volume: 1000 }
66
+ const buckets = makeBuckets(10)
67
+ binBarToBuckets(bar, buckets, 0, 1, 10, 'proportional')
68
+ expect(buckets[3]).toBeCloseTo(500, 9)
69
+ expect(buckets[4]).toBeCloseTo(500, 9)
70
+ // Everything else zero.
71
+ for (let i = 0; i < 10; i++) {
72
+ if (i !== 3 && i !== 4) expect(buckets[i]).toBe(0)
73
+ }
74
+ })
75
+
76
+ it('puts all volume into a single bucket when the bar exactly spans one bucket', () => {
77
+ // Bar [4.0, 5.0) exactly equals bucket 4 → all volume there.
78
+ const bar: VolumeProfileBar = { high: 5, low: 4, close: 4.5, volume: 750 }
79
+ const buckets = makeBuckets(10)
80
+ binBarToBuckets(bar, buckets, 0, 1, 10, 'proportional')
81
+ // Implementation note: `hi = 5`, ceil((5-0)/1) - 1 = 4 → lastIdx = 4.
82
+ // firstIdx = floor((4-0)/1) = 4. So only bucket 4 gets volume.
83
+ expect(buckets[4]).toBeCloseTo(750, 9)
84
+ for (let i = 0; i < 10; i++) {
85
+ if (i !== 4) expect(buckets[i]).toBe(0)
86
+ }
87
+ })
88
+
89
+ it('splits across 3 buckets proportional to per-bucket overlap', () => {
90
+ // Bar [2.5, 5.5), grid binSize=1: overlaps with buckets 2, 3, 4, 5.
91
+ // bucket 2 [2, 3): overlap [2.5, 3.0) = 0.5
92
+ // bucket 3 [3, 4): overlap [3.0, 4.0) = 1.0
93
+ // bucket 4 [4, 5): overlap [4.0, 5.0) = 1.0
94
+ // bucket 5 [5, 6): overlap [5.0, 5.5) = 0.5
95
+ // Total overlap span = 3.0; barHigh - barLow = 3.0; volPerUnit = 900/3 = 300.
96
+ // Distribution: 150 / 300 / 300 / 150.
97
+ const bar: VolumeProfileBar = { high: 5.5, low: 2.5, close: 4, volume: 900 }
98
+ const buckets = makeBuckets(10)
99
+ binBarToBuckets(bar, buckets, 0, 1, 10, 'proportional')
100
+ expect(buckets[2]).toBeCloseTo(150, 9)
101
+ expect(buckets[3]).toBeCloseTo(300, 9)
102
+ expect(buckets[4]).toBeCloseTo(300, 9)
103
+ expect(buckets[5]).toBeCloseTo(150, 9)
104
+ // Sum equals the bar volume (conservation).
105
+ const sum = buckets.reduce((a, b) => a + b, 0)
106
+ expect(sum).toBeCloseTo(900, 9)
107
+ })
108
+
109
+ it('drops a bar fully outside the configured price range (both sides)', () => {
110
+ // Below the grid: binMin=100, binCount=10, binSize=1 → grid [100, 110).
111
+ const below: VolumeProfileBar = { high: 50, low: 40, close: 45, volume: 500 }
112
+ const b1 = makeBuckets(10)
113
+ binBarToBuckets(below, b1, 100, 1, 10, 'proportional')
114
+ expect(b1.reduce((a, b) => a + b, 0)).toBe(0)
115
+
116
+ // Above the grid.
117
+ const above: VolumeProfileBar = { high: 500, low: 400, close: 450, volume: 500 }
118
+ const b2 = makeBuckets(10)
119
+ binBarToBuckets(above, b2, 100, 1, 10, 'proportional')
120
+ expect(b2.reduce((a, b) => a + b, 0)).toBe(0)
121
+ })
122
+
123
+ it('treats a zero-range bar (high === low) like typical-price (lands in one bucket)', () => {
124
+ // Doji: high == low == close = 4.5 → falls in bucket 4.
125
+ const bar: VolumeProfileBar = { high: 4.5, low: 4.5, close: 4.5, volume: 800 }
126
+ const buckets = makeBuckets(10)
127
+ binBarToBuckets(bar, buckets, 0, 1, 10, 'proportional')
128
+ expect(buckets[4]).toBe(800)
129
+ for (let i = 0; i < 10; i++) {
130
+ if (i !== 4) expect(buckets[i]).toBe(0)
131
+ }
132
+ })
133
+ })
@@ -0,0 +1,44 @@
1
+ /**
2
+ * Tests for `findPOCIndex` — argmax over the bucket histogram with a
3
+ * deterministic lowest-index tie-breaker.
4
+ *
5
+ * Implementation behaviour (see `poc.ts` header for rationale):
6
+ * - Strictly-greater wins → earlier index is preserved on ties.
7
+ * - Empty array returns `-1`.
8
+ * - All zeros returns `0` (first bucket "wins" because no strictly-greater
9
+ * value is ever found).
10
+ */
11
+
12
+ import { describe, it, expect } from 'vitest'
13
+
14
+ import { findPOCIndex } from '../poc'
15
+
16
+ function f(arr: number[]): Float64Array {
17
+ return Float64Array.from(arr)
18
+ }
19
+
20
+ describe('findPOCIndex', () => {
21
+ it('returns the index of the largest bucket (plain argmax)', () => {
22
+ // Buckets [10, 50, 30, 20] → max=50 at index 1.
23
+ expect(findPOCIndex(f([10, 50, 30, 20]))).toBe(1)
24
+ })
25
+
26
+ it('resolves ties to the lowest index', () => {
27
+ // All equal → first index wins because comparator is strict `>`.
28
+ expect(findPOCIndex(f([40, 40, 40]))).toBe(0)
29
+ // Tie between index 2 and 5; the lower (2) wins.
30
+ expect(findPOCIndex(f([1, 2, 99, 3, 4, 99, 5]))).toBe(2)
31
+ })
32
+
33
+ it('returns 0 for an all-zero histogram (documented edge case)', () => {
34
+ // bestVol starts at buckets[0] = 0; no later value is strictly greater,
35
+ // so the index sticks at 0. The controller treats this state via the
36
+ // Value-Area total-volume zero branch, not by inspecting the POC.
37
+ expect(findPOCIndex(f([0, 0, 0, 0, 0]))).toBe(0)
38
+ })
39
+
40
+ it('returns -1 for an empty array', () => {
41
+ // Sanity for the explicit guard at the top of `findPOCIndex`.
42
+ expect(findPOCIndex(new Float64Array(0))).toBe(-1)
43
+ })
44
+ })
@@ -0,0 +1,177 @@
1
+ /**
2
+ * Tests for `computeValueArea` — greedy expansion around POC.
3
+ *
4
+ * Algorithm summary (see `valueArea.ts` header for full rationale):
5
+ * - Seed the VA with the POC bucket.
6
+ * - Each step compares `buckets[vahIdx+1]` vs `buckets[valIdx-1]` and
7
+ * annexes the larger side.
8
+ * - Ties → "expand toward POC" rule: pick the side whose CURRENT boundary
9
+ * is closer to POC. Equidistant ties → upper side wins.
10
+ * - Edge POC, boundary exhaustion, zero-volume, percent clamping all
11
+ * covered by dedicated tests below.
12
+ */
13
+
14
+ import { describe, it, expect } from 'vitest'
15
+
16
+ import { computeValueArea } from '../valueArea'
17
+ import { findPOCIndex } from '../poc'
18
+
19
+ function f(arr: number[]): Float64Array {
20
+ return Float64Array.from(arr)
21
+ }
22
+
23
+ describe('computeValueArea — symmetric / skewed distributions', () => {
24
+ it('centres the VA around the middle bucket on a symmetric distribution at target=0.70', () => {
25
+ // Buckets: [5,10,20,30,40,30,20,10,5], n=9, total=170, POC=4.
26
+ // Target = 119. Trace:
27
+ // start vaVol=40 (POC)
28
+ // step1 up=30, down=30 tie, equidist → goUp → vahIdx=5, vaVol=70
29
+ // step2 up=20, down=30 → down wins → valIdx=3, vaVol=100
30
+ // step3 up=20, down=20 tie, equidist (distUp=1,distDown=1) → goUp
31
+ // → vahIdx=6, vaVol=120
32
+ // 120 >= 119 → stop.
33
+ const buckets = f([5, 10, 20, 30, 40, 30, 20, 10, 5])
34
+ const poc = findPOCIndex(buckets) // 4
35
+ const res = computeValueArea(buckets, poc, 0.7)
36
+ expect(res.pocIndex).toBe(4)
37
+ expect(res.valIndex).toBe(3)
38
+ expect(res.vahIndex).toBe(6)
39
+ expect(res.totalVolume).toBe(170)
40
+ expect(res.vaVolume).toBe(120)
41
+ expect(res.vaPercent).toBeCloseTo(120 / 170, 9)
42
+ })
43
+
44
+ it('captures the heavy right tail on a right-skewed distribution; tie pulls back toward POC', () => {
45
+ // [1,1,1,2,3,5,10,40,20,10], n=10, total=92, POC=7 (value 40).
46
+ // Target = 64.4. Trace:
47
+ // vaVol=40 (valIdx=7, vahIdx=7)
48
+ // step1 up=buckets[8]=20, down=buckets[6]=10 → up wins → vahIdx=8, vaVol=60
49
+ // step2 up=buckets[9]=10, down=buckets[6]=10 → TIE.
50
+ // distUp = vahIdx - poc = 1; distDown = poc - valIdx = 0.
51
+ // distDown < distUp → extend the side closer to POC (down).
52
+ // → valIdx=6, vaVol=70
53
+ // 70 >= 64.4 → stop.
54
+ // VA = [6, 8]. The heavy right tail is captured in step 1 (the dominant
55
+ // upper neighbor); the subsequent tie rebalances toward POC per the
56
+ // CME-traditional "expand toward POC" tie-break — see valueArea.ts header.
57
+ const buckets = f([1, 1, 1, 2, 3, 5, 10, 40, 20, 10])
58
+ const poc = findPOCIndex(buckets) // 7
59
+ const res = computeValueArea(buckets, poc, 0.7)
60
+ expect(res.pocIndex).toBe(7)
61
+ expect(res.valIndex).toBe(6)
62
+ expect(res.vahIndex).toBe(8)
63
+ expect(res.vaVolume).toBe(70)
64
+ })
65
+ })
66
+
67
+ describe('computeValueArea — edge POC (only one expansion direction)', () => {
68
+ it('expands only upward when POC is at index 0', () => {
69
+ // POC at the bottom — `canDown` is always false; expansion is forced up.
70
+ // Buckets: [100, 50, 25, 10, 5], total=190, target=133.
71
+ // Start vaVol=100; canDown=false branch picks vahIdx=1 → vaVol=150 >= 133.
72
+ const buckets = f([100, 50, 25, 10, 5])
73
+ const res = computeValueArea(buckets, 0, 0.7)
74
+ expect(res.pocIndex).toBe(0)
75
+ expect(res.valIndex).toBe(0)
76
+ expect(res.vahIndex).toBe(1)
77
+ expect(res.vaVolume).toBe(150)
78
+ })
79
+
80
+ it('expands only downward when POC is at index N-1', () => {
81
+ // POC at the top — `canUp` is always false.
82
+ // Buckets: [5, 10, 25, 50, 100], total=190, target=133.
83
+ // Start vaVol=100; canUp=false branch picks valIdx=3 → vaVol=150 >= 133.
84
+ const buckets = f([5, 10, 25, 50, 100])
85
+ const res = computeValueArea(buckets, 4, 0.7)
86
+ expect(res.pocIndex).toBe(4)
87
+ expect(res.vahIndex).toBe(4) // N-1
88
+ expect(res.valIndex).toBe(3)
89
+ expect(res.vaVolume).toBe(150)
90
+ })
91
+ })
92
+
93
+ describe('computeValueArea — tie-breaker behaviour (CME-traditional)', () => {
94
+ it('on an upper==lower tie with asymmetric distances, extends the side whose current boundary is closer to POC', () => {
95
+ // Construct a state where after two forced upward steps a tie occurs
96
+ // with distDown < distUp:
97
+ //
98
+ // Buckets: [5,5,5,5,30,10,8,5,5], n=9, POC=4, total=78, target=0.7*78=54.6
99
+ //
100
+ // start vaVol=30 (valIdx=4, vahIdx=4)
101
+ // step1 up=10, down=5 → up wins → vahIdx=5, vaVol=40
102
+ // step2 up=buckets[6]=8, down=buckets[3]=5 → up wins → vahIdx=6, vaVol=48
103
+ // (now distUp=2, distDown=0)
104
+ // step3 up=buckets[7]=5, down=buckets[3]=5 → TIE.
105
+ // distUp=2, distDown=0 → distDown < distUp → goDown
106
+ // (closer-to-POC boundary extends away from POC)
107
+ // → valIdx=3, vaVol=53
108
+ // step4 up=buckets[7]=5, down=buckets[2]=5 → TIE.
109
+ // distUp=2, distDown=1 → distDown<distUp → goDown
110
+ // → valIdx=2, vaVol=58 >= 54.6 ✓
111
+ //
112
+ // Final: valIdx=2, vahIdx=6.
113
+ const buckets = f([5, 5, 5, 5, 30, 10, 8, 5, 5])
114
+ const res = computeValueArea(buckets, 4, 0.7)
115
+ expect(res.pocIndex).toBe(4)
116
+ // The tie was resolved by extending the boundary CLOSER to POC —
117
+ // i.e. the down side, which had distance 0 vs the up side's distance 2.
118
+ // This is the implementation's interpretation of "toward POC".
119
+ expect(res.valIndex).toBe(2)
120
+ expect(res.vahIndex).toBe(6)
121
+ expect(res.vaVolume).toBe(58)
122
+ })
123
+
124
+ it('on an equidistant tie, prefers the upper side (documented rule B)', () => {
125
+ // Buckets: [2,5,5,10,5,5,2], n=7, POC=3, total=34, target=23.8.
126
+ // start vaVol=10
127
+ // step1 up=5, down=5 tie, distUp=0, distDown=0 → goUp → vahIdx=4, vaVol=15
128
+ // step2 up=5, down=5 tie, distUp=1, distDown=1 → goUp → vahIdx=5, vaVol=20
129
+ // step3 up=2, down=5 → down wins → valIdx=2, vaVol=25 >= 23.8 ✓
130
+ const buckets = f([2, 5, 5, 10, 5, 5, 2])
131
+ const res = computeValueArea(buckets, 3, 0.7)
132
+ expect(res.pocIndex).toBe(3)
133
+ expect(res.vahIndex).toBe(5)
134
+ expect(res.valIndex).toBe(2)
135
+ expect(res.vaVolume).toBe(25)
136
+ })
137
+ })
138
+
139
+ describe('computeValueArea — percent clamping & target sweeps', () => {
140
+ it('sweeps the entire non-zero range at target=1.0', () => {
141
+ // Buckets: [5,10,5], n=3, POC=1, total=20, target=20.
142
+ // vaVol=10; up=5,down=5 tie equidist → goUp → vahIdx=2, vaVol=15
143
+ // canUp=false, canDown=true → goDown → valIdx=0, vaVol=20 ✓
144
+ const buckets = f([5, 10, 5])
145
+ const res = computeValueArea(buckets, 1, 1.0)
146
+ expect(res.valIndex).toBe(0)
147
+ expect(res.vahIndex).toBe(2)
148
+ expect(res.vaVolume).toBe(20)
149
+ expect(res.vaPercent).toBeCloseTo(1, 9)
150
+ })
151
+
152
+ it('produces a narrower VA at target=0.5 than at target=0.7 (monotonicity)', () => {
153
+ const buckets = f([5, 10, 20, 30, 40, 30, 20, 10, 5])
154
+ const poc = findPOCIndex(buckets) // 4
155
+ const half = computeValueArea(buckets, poc, 0.5)
156
+ const seventy = computeValueArea(buckets, poc, 0.7)
157
+ const halfWidth = half.vahIndex - half.valIndex
158
+ const seventyWidth = seventy.vahIndex - seventy.valIndex
159
+ expect(halfWidth).toBeLessThanOrEqual(seventyWidth)
160
+ // 50% target is 85; 40 + 30 + 30 = 100 reaches it well before 70%
161
+ // does so the difference must be strictly visible.
162
+ expect(halfWidth).toBeLessThan(seventyWidth)
163
+ expect(half.vaPercent).toBeLessThanOrEqual(seventy.vaPercent)
164
+ })
165
+
166
+ it('returns the degenerate result for an all-zero histogram', () => {
167
+ // Documented zero-volume behaviour: VA collapses to POC, percent 0.
168
+ const buckets = f([0, 0, 0, 0, 0])
169
+ const res = computeValueArea(buckets, 2, 0.7)
170
+ expect(res.vahIndex).toBe(2)
171
+ expect(res.valIndex).toBe(2)
172
+ expect(res.pocIndex).toBe(2)
173
+ expect(res.totalVolume).toBe(0)
174
+ expect(res.vaVolume).toBe(0)
175
+ expect(res.vaPercent).toBe(0)
176
+ })
177
+ })
@@ -0,0 +1,133 @@
1
+ /**
2
+ * Bar-to-bucket volume distribution.
3
+ *
4
+ * Two modes, both described in `docs/ROADMAP.md` §3.1:
5
+ *
6
+ * - `typical-price` (fast, default): the bar's entire volume is added to the
7
+ * bucket containing the typical price `(high + low + close) / 3`. O(1) per
8
+ * bar. Good enough for live profiles and the case where each bar is small
9
+ * relative to the bucket size.
10
+ *
11
+ * - `proportional` (accurate): the bar's volume is split across every bucket
12
+ * that overlaps `[low, high]`, weighted by that bucket's price-range
13
+ * overlap with the bar. O(spanned buckets) per bar. Use this when bars
14
+ * span many buckets (e.g. higher timeframes, wide ranges).
15
+ *
16
+ * Both modes mutate the `buckets` array in place — the function is called in
17
+ * a tight loop and we want zero allocations on the hot path. The controller
18
+ * is responsible for zeroing the buckets before the first call.
19
+ *
20
+ * Out-of-range handling:
21
+ * - In `typical-price` mode a bar whose typical price falls outside
22
+ * `[binMin, binMin + binCount*binSize)` is **dropped silently**. The
23
+ * controller is responsible for sizing the price range so this only
24
+ * happens for accidentally bad inputs (e.g. zero-volume bars in a
25
+ * degenerate range).
26
+ * - In `proportional` mode the overlap with `[binMin, binMax]` is the
27
+ * effective contribution; a bar fully outside contributes nothing, a bar
28
+ * partially overlapping contributes proportionally.
29
+ */
30
+
31
+ import type { BinningMode, VolumeProfileBar } from './types'
32
+
33
+ /**
34
+ * Distribute one bar's volume into `buckets`.
35
+ *
36
+ * Preconditions (not checked, hot path):
37
+ * - `buckets.length === binCount`
38
+ * - `binSize > 0`
39
+ * - `binCount >= 1`
40
+ *
41
+ * @param bar The OHLC bar (only `high`/`low`/`close`/`volume` are read).
42
+ * @param buckets Histogram array — written in place.
43
+ * @param binMin Low edge of bucket 0.
44
+ * @param binSize Price width of one bucket.
45
+ * @param binCount Number of buckets (must equal `buckets.length`).
46
+ * @param mode `typical-price` (fast) or `proportional` (accurate).
47
+ *
48
+ * @internal — building block used by the corresponding controller
49
+ * factory. Reachable today via the top-level `@klinechart-quant/core`
50
+ * barrel but **NOT part of the supported public API**. typedoc / api-
51
+ * extractor hide it from generated docs. Prefer the controller
52
+ * factory (e.g. `createVolumeProfileController`) for stable user code.
53
+ * Closes API audit BLOCKER-002 (export * leakage taxonomy).
54
+ */
55
+ export function binBarToBuckets(
56
+ bar: VolumeProfileBar,
57
+ buckets: Float64Array,
58
+ binMin: number,
59
+ binSize: number,
60
+ binCount: number,
61
+ mode: BinningMode,
62
+ ): void {
63
+ if (bar.volume === 0 || binCount === 0 || binSize <= 0) return
64
+
65
+ if (mode === 'typical-price') {
66
+ const tp = (bar.high + bar.low + bar.close) / 3
67
+ const idx = Math.floor((tp - binMin) / binSize)
68
+ if (idx < 0 || idx >= binCount) return
69
+ buckets[idx] = (buckets[idx] ?? 0) + bar.volume
70
+ return
71
+ }
72
+
73
+ // Proportional mode — split the bar's volume across [low, high] by
74
+ // per-bucket overlap with the bar's range.
75
+ //
76
+ // The bar's price extent is [low, high]; the buckets cover the price
77
+ // axis at [binMin + i*binSize, binMin + (i+1)*binSize). We compute the
78
+ // overlap of each touched bucket with [low, high] and weight by it.
79
+ //
80
+ // Degenerate-range bars (high === low, e.g. a doji at exactly one
81
+ // tick) fall back to the typical-price behaviour — putting the volume
82
+ // in the bucket containing `low` is the correct limit as
83
+ // `high - low -> 0`.
84
+ const binMax = binMin + binCount * binSize
85
+ const barLow = bar.low
86
+ const barHigh = bar.high
87
+
88
+ // Drop bars fully outside the configured price range — they can't
89
+ // contribute to any bucket.
90
+ if (barHigh < binMin || barLow >= binMax) return
91
+
92
+ if (barHigh === barLow) {
93
+ const idx = Math.floor((barLow - binMin) / binSize)
94
+ if (idx < 0 || idx >= binCount) return
95
+ buckets[idx] = (buckets[idx] ?? 0) + bar.volume
96
+ return
97
+ }
98
+
99
+ // Clamp the bar's range to the bucket grid so overlap math doesn't
100
+ // include the out-of-range portion.
101
+ const lo = barLow < binMin ? binMin : barLow
102
+ const hi = barHigh > binMax ? binMax : barHigh
103
+
104
+ const firstIdx = Math.floor((lo - binMin) / binSize)
105
+ // For `hi` we use ceiling-of-(hi - binMin)/binSize, minus 1, so the
106
+ // top boundary `hi === binMin + k*binSize` belongs to bucket k-1
107
+ // (consistent with the half-open bucket convention `[lo, hi)`).
108
+ let lastIdx = Math.ceil((hi - binMin) / binSize) - 1
109
+ if (lastIdx < firstIdx) lastIdx = firstIdx
110
+
111
+ // Effective span used as the denominator. We weight against the
112
+ // *clamped* span (the part actually inside the bucket grid) so a bar
113
+ // that hangs off the bottom doesn't get "phantom" volume into the
114
+ // visible buckets. Trade-off: this means a bar partially outside
115
+ // contributes only its inside-range fraction. This matches the
116
+ // intuition of "what fraction of the bar's range fell into the
117
+ // profile window".
118
+ const span = hi - lo
119
+ if (span <= 0) return
120
+
121
+ const volPerUnit = bar.volume / (barHigh - barLow)
122
+
123
+ for (let i = firstIdx; i <= lastIdx; i++) {
124
+ if (i < 0 || i >= binCount) continue
125
+ const bucketLow = binMin + i * binSize
126
+ const bucketHigh = bucketLow + binSize
127
+ const overlapLow = lo > bucketLow ? lo : bucketLow
128
+ const overlapHigh = hi < bucketHigh ? hi : bucketHigh
129
+ const overlap = overlapHigh - overlapLow
130
+ if (overlap <= 0) continue
131
+ buckets[i] = (buckets[i] ?? 0) + overlap * volPerUnit
132
+ }
133
+ }