@363045841yyt/klinechart-core 0.8.11-alpha.1 → 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,232 @@
1
+ /**
2
+ * Footprint Chart — public type contract.
3
+ *
4
+ * A Footprint chart expands each candle internally to show, at every price
5
+ * level, how much aggressive buying (lifting the ASK) and aggressive selling
6
+ * (hitting the BID) traded. It is the core tool of "order flow" reading:
7
+ * traders use it to answer "did this bar rise because there were real buyers,
8
+ * or only because sellers withdrew?".
9
+ *
10
+ * This module owns the **data model + classification math only**. Rendering
11
+ * belongs to the `@klinechart-quant/core` Renderer/Scene layer; the planned
12
+ * GPU compute path is sketched in `computeShader.wgsl.md`.
13
+ *
14
+ * See `docs/ROADMAP.md` §3.3 (Footprint) for the algorithm rationale and §0
15
+ * for how this controller fits the seven-module core layering.
16
+ *
17
+ * Cross-references:
18
+ * - `aggressor.ts` — buy/sell classification (explicit, tick rule, Lee-Ready)
19
+ * - `perBarStats.ts` — delta, cumulative delta, diagonal imbalance
20
+ * - `createFootprintController.ts` — streaming controller (Signal<bars>)
21
+ */
22
+
23
+ import type { Signal } from '../../reactivity'
24
+
25
+ // ---------------------------------------------------------------------------
26
+ // Aggressor classification — shared with `aggressor.ts`
27
+ // ---------------------------------------------------------------------------
28
+
29
+ /**
30
+ * Which side of the resting book a trade hit.
31
+ *
32
+ * - 'buy' — aggressor lifted the ASK (resting seller was passive)
33
+ * - 'sell' — aggressor hit the BID (resting buyer was passive)
34
+ *
35
+ * Note: this is the **aggressor**'s side, NOT the "buyer"'s side. Binance's
36
+ * `isBuyerMaker=true` means the buyer was the maker (passive) and so the
37
+ * aggressor is the seller — see `classifyExplicit` in `aggressor.ts`.
38
+ */
39
+ export type AggressorSide = 'buy' | 'sell'
40
+
41
+ /**
42
+ * A classification's confidence flag.
43
+ *
44
+ * - `inferred: false` — derived from an explicit exchange flag (zero error)
45
+ * - `inferred: true` — derived from a heuristic (tick rule or Lee-Ready);
46
+ * the consumer should mark this as approximate so it
47
+ * can be visually distinguished and excluded from
48
+ * strict order-flow analytics
49
+ *
50
+ * Every classifier in `aggressor.ts` must set this honestly. We rely on it
51
+ * downstream when surfacing "(estimated)" warnings on bars whose flow was
52
+ * inferred — this is the explicit boundary mandated by ROADMAP §3.3.
53
+ */
54
+ export interface AggressorWithConfidence {
55
+ side: AggressorSide
56
+ inferred: boolean
57
+ }
58
+
59
+ // ---------------------------------------------------------------------------
60
+ // Trade inputs
61
+ // ---------------------------------------------------------------------------
62
+
63
+ /**
64
+ * A single trade print. The minimum shape needed for footprint aggregation.
65
+ *
66
+ * `timestamp` is epoch ms (chosen because `Math.floor(ts / barIntervalMs)`
67
+ * cleanly produces a bar index). `size` is in base units (BTC, AAPL shares,
68
+ * not USD value).
69
+ */
70
+ export interface Trade {
71
+ timestamp: number
72
+ price: number
73
+ size: number
74
+ }
75
+
76
+ /**
77
+ * A trade carrying the exchange's aggressor flag. Binance-style:
78
+ * `isBuyerMaker=true` ⇒ the buyer was the passive maker, so the SELLER was
79
+ * the aggressor. Optional — if the exchange does not include it the
80
+ * controller falls back to the configured heuristic classifier.
81
+ */
82
+ export interface TradeWithFlag extends Trade {
83
+ isBuyerMaker?: boolean
84
+ }
85
+
86
+ // ---------------------------------------------------------------------------
87
+ // Bar shape
88
+ // ---------------------------------------------------------------------------
89
+
90
+ /**
91
+ * One price level inside a footprint bar.
92
+ *
93
+ * Cells are sorted by `price` ascending. `askVol` and `bidVol` are gross
94
+ * (not net) — the delta is computed separately.
95
+ */
96
+ export interface FootprintBarCell {
97
+ /** representative price of the bin (quantised to tickSize). */
98
+ price: number
99
+ /** volume of trades classified as `buy` (aggressor lifted the ASK). */
100
+ askVol: number
101
+ /** volume of trades classified as `sell` (aggressor hit the BID). */
102
+ bidVol: number
103
+ }
104
+
105
+ /**
106
+ * Direction of a diagonal imbalance — see `perBarStats.ts` for the math.
107
+ */
108
+ export type ImbalanceDirection = 'buy-imbalance' | 'sell-imbalance'
109
+
110
+ /**
111
+ * One imbalance flag inside a bar.
112
+ *
113
+ * `priceIndex` is the index into `FootprintBar.cells` of the dominant side
114
+ * (not the cell it was compared against). `ratio` is `dominant / weaker`
115
+ * (always ≥ the configured threshold; capped at `Number.POSITIVE_INFINITY`
116
+ * when the weaker side is zero — see `computeDiagonalImbalances`).
117
+ */
118
+ export interface FootprintImbalance {
119
+ priceIndex: number
120
+ direction: ImbalanceDirection
121
+ ratio: number
122
+ }
123
+
124
+ /**
125
+ * The materialised view of one bar (the unit a renderer consumes).
126
+ *
127
+ * All fields are derived from the controller's internal streaming aggregate;
128
+ * `cells` and `imbalances` are recomputed lazily on `bars` signal read.
129
+ */
130
+ export interface FootprintBar {
131
+ /** stable index = `Math.floor(timestamp / barIntervalMs)`. */
132
+ barIndex: number
133
+ /** inclusive start of the bar window (epoch ms). */
134
+ startTime: number
135
+ /** exclusive end of the bar window (epoch ms). */
136
+ endTime: number
137
+ /** per-price-level cells, ascending by `price`. */
138
+ cells: ReadonlyArray<FootprintBarCell>
139
+ /** Σ(askVol − bidVol) across cells. Positive ⇒ buyers led. */
140
+ delta: number
141
+ /** Σ(askVol + bidVol). */
142
+ totalVolume: number
143
+ /** diagonal imbalance flags; usually 0–5 per bar. */
144
+ imbalances: ReadonlyArray<FootprintImbalance>
145
+ }
146
+
147
+ // ---------------------------------------------------------------------------
148
+ // Configuration
149
+ // ---------------------------------------------------------------------------
150
+
151
+ /**
152
+ * Controller config. All fields required at the controller surface — the
153
+ * factory fills missing fields with sensible defaults so callers can pass
154
+ * a partial.
155
+ */
156
+ export interface FootprintConfig {
157
+ /** quantise trade prices to this tick size (e.g. 0.01 for BTCUSDT). */
158
+ tickSize: number
159
+ /** ms per bar (e.g. 60_000 for 1m). */
160
+ barIntervalMs: number
161
+ /**
162
+ * Diagonal imbalance threshold. Default 3 — i.e. a cell must have at
163
+ * least 3× the volume of its diagonal counterpart to flag.
164
+ */
165
+ imbalanceRatio: number
166
+ /**
167
+ * Classifier to fall back to when a trade has no explicit
168
+ * `isBuyerMaker` flag.
169
+ *
170
+ * - 'tick-rule' — price-change rule; default. Doesn't need bid/ask.
171
+ * - 'lee-ready' — uses bid/ask; controller's `ingestTrade` must
172
+ * receive `bid` and `ask` for this path.
173
+ */
174
+ fallbackClassifier: 'tick-rule' | 'lee-ready'
175
+ }
176
+
177
+ // ---------------------------------------------------------------------------
178
+ // Controller interface
179
+ // ---------------------------------------------------------------------------
180
+
181
+ /**
182
+ * Framework-agnostic controller — mirrors `IndicatorSelectorController`'s
183
+ * shape (signals for state, plain functions for mutations, idempotent
184
+ * `dispose`).
185
+ */
186
+ export interface FootprintController {
187
+ /** Current config; re-emits when `setConfig` is called. */
188
+ readonly config: Signal<FootprintConfig>
189
+ /** Materialised bars, ascending by `barIndex`. Empty before first trade. */
190
+ readonly bars: Signal<ReadonlyArray<FootprintBar>>
191
+ /**
192
+ * Cumulative delta series, parallel to `bars`. `cumulativeDelta[i]`
193
+ * corresponds to `bars[i]`.
194
+ */
195
+ readonly cumulativeDelta: Signal<ReadonlyArray<number>>
196
+
197
+ /**
198
+ * Ingest one trade — canonical method, aligned with the cross-controller
199
+ * `ingest()` convention (VolumeProfile, OrderBookHeatmap). `bid`/`ask` are
200
+ * optional and only consulted when the trade lacks an explicit
201
+ * `isBuyerMaker` flag AND the configured fallback is `lee-ready`.
202
+ *
203
+ * Closes API-audit BLOCKER-001 (5-verb intake proliferation) by
204
+ * harmonising on `ingest` as the stream-accumulator verb across
205
+ * `VolumeProfile`, `OrderBookHeatmap`, and `Footprint`.
206
+ */
207
+ ingest(trade: TradeWithFlag, bid?: number, ask?: number): void
208
+
209
+ /**
210
+ * @deprecated since 0.1.0-alpha.1 — use {@link FootprintController.ingest}.
211
+ * Kept as a non-removing alias for at least 6 months for migration. Will
212
+ * be removed in 0.2.0.
213
+ */
214
+ ingestTrade(trade: TradeWithFlag, bid?: number, ask?: number): void
215
+
216
+ /**
217
+ * Patch the config. Changing `barIntervalMs` or `tickSize` invalidates
218
+ * the buckets so the state is cleared. Changing only `imbalanceRatio`
219
+ * just re-materialises on the next read.
220
+ */
221
+ setConfig(next: Partial<FootprintConfig>): void
222
+
223
+ /** Clear all bars and cumulative delta. Does not change config. */
224
+ reset(): void
225
+
226
+ /**
227
+ * Stop emitting. Subsequent calls to ingest/setConfig/reset are silent
228
+ * no-ops; previously-attached subscribers receive no further
229
+ * notifications. Idempotent.
230
+ */
231
+ dispose(): void
232
+ }
@@ -0,0 +1,103 @@
1
+ /**
2
+ * alignToBaseIndex tests — forward fill + strict no-lookahead.
3
+ *
4
+ * The lookahead test is the load-bearing one: a naive implementation that
5
+ * uses `floor(t / targetIntervalMs) * targetIntervalMs` to pick the bar
6
+ * would expose future state. This file pins that out.
7
+ */
8
+
9
+ import { describe, it, expect } from 'vitest'
10
+ import { alignToBaseIndex } from '../alignToBaseIndex'
11
+
12
+ const HOUR = 60 * 60_000
13
+ const MIN_5 = 5 * 60_000
14
+
15
+ const ts = (ms: number): { timestamp: number } => ({ timestamp: ms })
16
+
17
+ describe('alignToBaseIndex — basic behavior', () => {
18
+ it('empty base bars → []', () => {
19
+ expect(alignToBaseIndex([], [ts(0)], [42], HOUR)).toEqual([])
20
+ })
21
+
22
+ it('empty higher-tf series → all nulls', () => {
23
+ const base = [ts(0), ts(MIN_5), ts(2 * MIN_5)]
24
+ expect(alignToBaseIndex(base, [], [], HOUR)).toEqual([null, null, null])
25
+ })
26
+
27
+ it('throws if higherTfBars and higherTfValues length differ', () => {
28
+ expect(() => alignToBaseIndex([ts(0)], [ts(0)], [1, 2], HOUR)).toThrow(/length/)
29
+ })
30
+
31
+ it('throws on non-positive targetIntervalMs', () => {
32
+ expect(() => alignToBaseIndex([ts(0)], [ts(0)], [1], 0)).toThrow(/positive/)
33
+ })
34
+ })
35
+
36
+ describe('alignToBaseIndex — no-lookahead (critical)', () => {
37
+ it('base bar at hbar.timestamp reads that hbar value', () => {
38
+ const hbars = [ts(HOUR)] // hbar opens at 09:00 in arbitrary epoch terms
39
+ const values = [100]
40
+ const base = [ts(HOUR)]
41
+ expect(alignToBaseIndex(base, hbars, values, HOUR)).toEqual([100])
42
+ })
43
+
44
+ it('base bar 1ms BEFORE hbar.timestamp gets null (no lookahead)', () => {
45
+ const hbars = [ts(HOUR)]
46
+ const values = [100]
47
+ const base = [ts(HOUR - 1)]
48
+ expect(alignToBaseIndex(base, hbars, values, HOUR)).toEqual([null])
49
+ })
50
+
51
+ it('base bar deep inside hbar interval reads that hbar value', () => {
52
+ const hbars = [ts(HOUR)]
53
+ const values = [100]
54
+ const base = [ts(HOUR + 30 * 60_000)] // 30 min into the hour
55
+ expect(alignToBaseIndex(base, hbars, values, HOUR)).toEqual([100])
56
+ })
57
+
58
+ it('base bar at hbar.timestamp + targetIntervalMs (next bucket open) reads NEXT hbar', () => {
59
+ const hbars = [ts(HOUR), ts(2 * HOUR)]
60
+ const values = [100, 200]
61
+ const base = [ts(2 * HOUR)]
62
+ expect(alignToBaseIndex(base, hbars, values, HOUR)).toEqual([200])
63
+ })
64
+ })
65
+
66
+ describe('alignToBaseIndex — forward fill across many base bars', () => {
67
+ it('a 1h hbar covers all 12 of the 5m base bars inside it', () => {
68
+ const hbars = [ts(HOUR)]
69
+ const values = ['hot']
70
+ const base: { timestamp: number }[] = []
71
+ for (let i = 0; i < 12; i++) base.push(ts(HOUR + i * MIN_5))
72
+ const out = alignToBaseIndex(base, hbars, values, HOUR)
73
+ expect(out).toEqual(new Array(12).fill('hot'))
74
+ })
75
+
76
+ it('multiple hbars switch correctly at boundaries', () => {
77
+ const hbars = [ts(HOUR), ts(2 * HOUR), ts(3 * HOUR)]
78
+ const values = ['a', 'b', 'c']
79
+ const base = [
80
+ ts(HOUR),
81
+ ts(HOUR + 30 * 60_000),
82
+ ts(2 * HOUR),
83
+ ts(2 * HOUR + 30 * 60_000),
84
+ ts(3 * HOUR),
85
+ ]
86
+ expect(alignToBaseIndex(base, hbars, values, HOUR)).toEqual(['a', 'a', 'b', 'b', 'c'])
87
+ })
88
+
89
+ it('gap in hbars — base bars in the gap forward-fill the prior hbar', () => {
90
+ // hbar1 at 09:00, hbar2 at 11:00. base bar at 10:30 → forward-fill 'a'.
91
+ const hbars = [ts(HOUR), ts(3 * HOUR)]
92
+ const values = ['a', 'b']
93
+ const base = [ts(2 * HOUR + 30 * 60_000)]
94
+ expect(alignToBaseIndex(base, hbars, values, HOUR)).toEqual(['a'])
95
+ })
96
+
97
+ it('leading base bars before first hbar are all null', () => {
98
+ const hbars = [ts(HOUR)]
99
+ const values = ['x']
100
+ const base = [ts(0), ts(MIN_5), ts(HOUR)]
101
+ expect(alignToBaseIndex(base, hbars, values, HOUR)).toEqual([null, null, 'x'])
102
+ })
103
+ })
@@ -0,0 +1,172 @@
1
+ /**
2
+ * MTF controller tests — series CRUD, recompute on mutation, EMA on a 1h
3
+ * overlay against 5m bars.
4
+ */
5
+
6
+ import { describe, it, expect, vi } from 'vitest'
7
+ import { createMtfController } from '../createMtfController'
8
+ import type { BaseBar, ResampledBar } from '../types'
9
+
10
+ const MIN = 60_000
11
+ const FIVE_MIN = 5 * MIN
12
+ const HOUR = 60 * MIN
13
+
14
+ function bar(tsMs: number, c: number, v = 10): BaseBar {
15
+ return { timestamp: tsMs, open: c, high: c, low: c, close: c, volume: v }
16
+ }
17
+
18
+ /** A trivial "last close" compute fn for asserting against. */
19
+ const lastClose = (rs: ReadonlyArray<ResampledBar>): number[] => rs.map((r) => r.close)
20
+
21
+ describe('createMtfController — CRUD + recompute', () => {
22
+ it('addSeries returns id and series signal fires', () => {
23
+ const ctl = createMtfController({
24
+ initialBars: [bar(0, 100), bar(FIVE_MIN, 101)],
25
+ baseIntervalMs: FIVE_MIN,
26
+ })
27
+ const listener = vi.fn()
28
+ ctl.series.subscribe(listener)
29
+ const id = ctl.addSeries({
30
+ id: 'lastClose-1h',
31
+ label: 'last close 1h',
32
+ targetIntervalMs: HOUR,
33
+ compute: lastClose,
34
+ })
35
+ expect(id).toBe('lastClose-1h')
36
+ expect(listener).toHaveBeenCalled()
37
+ expect(ctl.series()).toHaveLength(1)
38
+ })
39
+
40
+ it('addSeries with duplicate id throws', () => {
41
+ const ctl = createMtfController({
42
+ initialBars: [bar(0, 100)],
43
+ baseIntervalMs: FIVE_MIN,
44
+ })
45
+ ctl.addSeries({ id: 'a', label: 'a', targetIntervalMs: HOUR, compute: lastClose })
46
+ expect(() =>
47
+ ctl.addSeries({ id: 'a', label: 'a2', targetIntervalMs: HOUR, compute: lastClose }),
48
+ ).toThrow(/already in use/)
49
+ })
50
+
51
+ it('addSeries with targetIntervalMs not a multiple of baseIntervalMs throws', () => {
52
+ const ctl = createMtfController({
53
+ initialBars: [bar(0, 100)],
54
+ baseIntervalMs: FIVE_MIN,
55
+ })
56
+ expect(() =>
57
+ ctl.addSeries({ id: 'a', label: 'a', targetIntervalMs: 7 * MIN, compute: lastClose }),
58
+ ).toThrow(/multiple/)
59
+ })
60
+
61
+ it('removeSeries returns true if found, false otherwise', () => {
62
+ const ctl = createMtfController({
63
+ initialBars: [bar(0, 100)],
64
+ baseIntervalMs: FIVE_MIN,
65
+ })
66
+ ctl.addSeries({ id: 'a', label: 'a', targetIntervalMs: HOUR, compute: lastClose })
67
+ expect(ctl.removeSeries('a')).toBe(true)
68
+ expect(ctl.removeSeries('a')).toBe(false)
69
+ expect(ctl.series()).toHaveLength(0)
70
+ })
71
+
72
+ it('updateSeries patches compute fn and re-runs it', () => {
73
+ const ctl = createMtfController({
74
+ initialBars: [bar(0, 100), bar(FIVE_MIN, 200)],
75
+ baseIntervalMs: FIVE_MIN,
76
+ })
77
+ ctl.addSeries({ id: 'a', label: 'a', targetIntervalMs: FIVE_MIN, compute: lastClose })
78
+ const beforeValues = ctl.series()[0]!.alignedValues
79
+ expect(beforeValues).toEqual([100, 200])
80
+ ctl.updateSeries('a', { compute: (rs) => rs.map(() => 42) })
81
+ expect(ctl.series()[0]!.alignedValues).toEqual([42, 42])
82
+ })
83
+ })
84
+
85
+ describe('createMtfController — alignment correctness', () => {
86
+ it('lifts a 1h compute onto 5m base bars (12 base bars share one hbar value)', () => {
87
+ const base: BaseBar[] = []
88
+ for (let i = 0; i < 12; i++) base.push(bar(i * FIVE_MIN, 100 + i))
89
+ const ctl = createMtfController({
90
+ initialBars: base,
91
+ baseIntervalMs: FIVE_MIN,
92
+ })
93
+ ctl.addSeries({
94
+ id: 'a',
95
+ label: 'last close 1h',
96
+ targetIntervalMs: HOUR,
97
+ compute: lastClose,
98
+ })
99
+ // All 12 base bars should see the same value — the close of the
100
+ // single 1h resampled bar covering 0..59 min, which is base[11].close = 111
101
+ const aligned = ctl.series()[0]!.alignedValues
102
+ expect(aligned).toEqual(new Array(12).fill(111))
103
+ })
104
+
105
+ it('appendBaseBar extends aligned series by exactly one entry', () => {
106
+ const base: BaseBar[] = [bar(0, 100)]
107
+ const ctl = createMtfController({ initialBars: base, baseIntervalMs: FIVE_MIN })
108
+ ctl.addSeries({
109
+ id: 'a',
110
+ label: 'a',
111
+ targetIntervalMs: FIVE_MIN,
112
+ compute: lastClose,
113
+ })
114
+ expect(ctl.series()[0]!.alignedValues).toEqual([100])
115
+ ctl.appendBaseBar(bar(FIVE_MIN, 200))
116
+ expect(ctl.series()[0]!.alignedValues).toEqual([100, 200])
117
+ })
118
+
119
+ it('two series at different higher TFs co-exist independently', () => {
120
+ const base: BaseBar[] = []
121
+ for (let i = 0; i < 12; i++) base.push(bar(i * FIVE_MIN, 100 + i))
122
+ const ctl = createMtfController({ initialBars: base, baseIntervalMs: FIVE_MIN })
123
+ ctl.addSeries({ id: '5m', label: '5m', targetIntervalMs: FIVE_MIN, compute: lastClose })
124
+ ctl.addSeries({ id: '1h', label: '1h', targetIntervalMs: HOUR, compute: lastClose })
125
+
126
+ const series = ctl.series()
127
+ expect(series).toHaveLength(2)
128
+ const fiveM = series.find((s) => s.definition.id === '5m')!
129
+ const oneH = series.find((s) => s.definition.id === '1h')!
130
+ // 5m series: each base bar reads its own close
131
+ expect(fiveM.alignedValues).toEqual(base.map((b) => b.close))
132
+ // 1h series: all 12 read the close of the single 1h bar = 111
133
+ expect(oneH.alignedValues).toEqual(new Array(12).fill(111))
134
+ })
135
+ })
136
+
137
+ describe('createMtfController — config + lifecycle', () => {
138
+ it('setBaseBars rebuilds all series', () => {
139
+ const ctl = createMtfController({
140
+ initialBars: [bar(0, 100)],
141
+ baseIntervalMs: FIVE_MIN,
142
+ })
143
+ ctl.addSeries({ id: 'a', label: 'a', targetIntervalMs: FIVE_MIN, compute: lastClose })
144
+ expect(ctl.series()[0]!.alignedValues).toEqual([100])
145
+ ctl.setBaseBars([bar(0, 1), bar(FIVE_MIN, 2)], FIVE_MIN)
146
+ expect(ctl.series()[0]!.alignedValues).toEqual([1, 2])
147
+ })
148
+
149
+ it('setBaseBars throws if an existing series target no longer cleanly divides', () => {
150
+ const ctl = createMtfController({
151
+ initialBars: [bar(0, 100)],
152
+ baseIntervalMs: FIVE_MIN,
153
+ })
154
+ ctl.addSeries({ id: 'a', label: 'a', targetIntervalMs: HOUR, compute: lastClose })
155
+ // Changing base to 7-minute bars makes 1h (3_600_000) no longer divisible by 7m (420_000)
156
+ expect(() => ctl.setBaseBars([bar(0, 1)], 7 * MIN)).toThrow(/cleanly divide/)
157
+ })
158
+
159
+ it('dispose silences subsequent mutators', () => {
160
+ const ctl = createMtfController({
161
+ initialBars: [bar(0, 100)],
162
+ baseIntervalMs: FIVE_MIN,
163
+ })
164
+ const listener = vi.fn()
165
+ ctl.series.subscribe(listener)
166
+ ctl.dispose()
167
+ const beforeCalls = listener.mock.calls.length
168
+ ctl.addSeries({ id: 'a', label: 'a', targetIntervalMs: FIVE_MIN, compute: lastClose })
169
+ ctl.appendBaseBar(bar(FIVE_MIN, 200))
170
+ expect(listener.mock.calls.length).toBe(beforeCalls)
171
+ })
172
+ })
@@ -0,0 +1,106 @@
1
+ /**
2
+ * resampleBars tests — bucketing math, partial bars, gap handling.
3
+ */
4
+
5
+ import { describe, it, expect } from 'vitest'
6
+ import { resampleBars } from '../resampleBars'
7
+ import type { BaseBar } from '../types'
8
+
9
+ const min = 60_000
10
+ const hour = 60 * min
11
+
12
+ function bar(tsMs: number, o: number, h: number, l: number, c: number, v = 100): BaseBar {
13
+ return { timestamp: tsMs, open: o, high: h, low: l, close: c, volume: v }
14
+ }
15
+
16
+ describe('resampleBars — input validation', () => {
17
+ it('throws when targetIntervalMs is not a multiple of baseIntervalMs', () => {
18
+ // 1.5 min is not an integer multiple of 1 min
19
+ expect(() => resampleBars([], min, min + 30_000)).toThrow(/integer multiple/)
20
+ })
21
+
22
+ it('throws on non-positive intervals', () => {
23
+ expect(() => resampleBars([], 0, hour)).toThrow(/positive/)
24
+ expect(() => resampleBars([], min, -hour)).toThrow(/positive/)
25
+ })
26
+
27
+ it('returns [] for empty input', () => {
28
+ expect(resampleBars([], min, hour)).toEqual([])
29
+ })
30
+
31
+ it('targetIntervalMs === baseIntervalMs returns 1-to-1 wrapped bars', () => {
32
+ const bars = [bar(0, 1, 2, 0.5, 1.5), bar(min, 1.5, 3, 1, 2)]
33
+ const out = resampleBars(bars, min, min)
34
+ expect(out).toHaveLength(2)
35
+ expect(out[0]!.sourceStart).toBe(0)
36
+ expect(out[0]!.sourceEnd).toBe(0)
37
+ expect(out[0]!.open).toBe(1)
38
+ expect(out[1]!.sourceStart).toBe(1)
39
+ })
40
+ })
41
+
42
+ describe('resampleBars — aggregation rules', () => {
43
+ it('60 1m bars → 1 1h bar with correct OHLCV', () => {
44
+ const bars: BaseBar[] = []
45
+ for (let i = 0; i < 60; i++) {
46
+ bars.push(bar(i * min, 100 + i, 101 + i, 99 + i, 100 + i + 0.5, 10))
47
+ }
48
+ const out = resampleBars(bars, min, hour)
49
+ expect(out).toHaveLength(1)
50
+ expect(out[0]!.open).toBe(100)
51
+ expect(out[0]!.close).toBe(159.5)
52
+ expect(out[0]!.high).toBe(160) // 101 + 59
53
+ expect(out[0]!.low).toBe(99)
54
+ expect(out[0]!.volume).toBe(600)
55
+ expect(out[0]!.sourceStart).toBe(0)
56
+ expect(out[0]!.sourceEnd).toBe(59)
57
+ })
58
+
59
+ it('60 1m bars → 12 5m bars', () => {
60
+ const bars: BaseBar[] = []
61
+ for (let i = 0; i < 60; i++) {
62
+ bars.push(bar(i * min, 100, 101, 99, 100, 10))
63
+ }
64
+ const out = resampleBars(bars, min, 5 * min)
65
+ expect(out).toHaveLength(12)
66
+ for (const b of out) {
67
+ expect(b.volume).toBe(50)
68
+ expect(b.sourceEnd - b.sourceStart + 1).toBe(5)
69
+ }
70
+ })
71
+
72
+ it('partial final bucket is emitted (forming-bar visibility)', () => {
73
+ // 65 1m bars → 1 full 1h + 1 partial 1h (5 minutes)
74
+ const bars: BaseBar[] = []
75
+ for (let i = 0; i < 65; i++) {
76
+ bars.push(bar(i * min, 100, 101, 99, 100, 10))
77
+ }
78
+ const out = resampleBars(bars, min, hour)
79
+ expect(out).toHaveLength(2)
80
+ expect(out[1]!.sourceStart).toBe(60)
81
+ expect(out[1]!.sourceEnd).toBe(64)
82
+ expect(out[1]!.volume).toBe(50)
83
+ })
84
+
85
+ it('single base bar produces a single (partial) output bar', () => {
86
+ const out = resampleBars([bar(0, 1, 2, 0.5, 1.5)], min, hour)
87
+ expect(out).toHaveLength(1)
88
+ expect(out[0]!.sourceStart).toBe(0)
89
+ expect(out[0]!.sourceEnd).toBe(0)
90
+ })
91
+
92
+ it('input gap does not create a synthetic bucket; the missing minute is just absent', () => {
93
+ // 09:30, 09:31, [skip 09:32], 09:33, 09:34 → all fold into the same 5m bucket starting 09:30
94
+ const bars = [
95
+ bar(0, 100, 100, 100, 100, 10),
96
+ bar(min, 100, 100, 100, 100, 10),
97
+ bar(3 * min, 100, 100, 100, 100, 10),
98
+ bar(4 * min, 100, 100, 100, 100, 10),
99
+ ]
100
+ const out = resampleBars(bars, min, 5 * min)
101
+ expect(out).toHaveLength(1)
102
+ expect(out[0]!.volume).toBe(40) // 4 bars × 10
103
+ expect(out[0]!.sourceStart).toBe(0)
104
+ expect(out[0]!.sourceEnd).toBe(3)
105
+ })
106
+ })