@forgecharts/sdk 1.1.28 → 1.1.30

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 (237) hide show
  1. package/dist/index.js +8100 -48
  2. package/dist/index.js.map +1 -1
  3. package/dist/internal.js +8851 -31
  4. package/dist/internal.js.map +1 -1
  5. package/dist/react/index.js +11558 -27
  6. package/dist/react/index.js.map +1 -1
  7. package/dist/react/internal.js +12147 -43
  8. package/dist/react/internal.js.map +1 -1
  9. package/package.json +1 -1
  10. package/dist/__tests__/backwardCompatibility.test.js +0 -159
  11. package/dist/__tests__/backwardCompatibility.test.js.map +0 -1
  12. package/dist/__tests__/candleInvariant.test.js +0 -415
  13. package/dist/__tests__/candleInvariant.test.js.map +0 -1
  14. package/dist/__tests__/public-api-surface.js +0 -38
  15. package/dist/__tests__/public-api-surface.js.map +0 -1
  16. package/dist/__tests__/timeframeBoundary.test.js +0 -452
  17. package/dist/__tests__/timeframeBoundary.test.js.map +0 -1
  18. package/dist/api/DrawingManager.js +0 -190
  19. package/dist/api/DrawingManager.js.map +0 -1
  20. package/dist/api/EventBus.js +0 -44
  21. package/dist/api/EventBus.js.map +0 -1
  22. package/dist/api/IndicatorDAG.js +0 -316
  23. package/dist/api/IndicatorDAG.js.map +0 -1
  24. package/dist/api/IndicatorRegistry.js +0 -39
  25. package/dist/api/IndicatorRegistry.js.map +0 -1
  26. package/dist/api/LayoutManager.js +0 -51
  27. package/dist/api/LayoutManager.js.map +0 -1
  28. package/dist/api/PaneManager.js +0 -119
  29. package/dist/api/PaneManager.js.map +0 -1
  30. package/dist/api/ReferenceAPI.js +0 -153
  31. package/dist/api/ReferenceAPI.js.map +0 -1
  32. package/dist/api/TChart.js +0 -765
  33. package/dist/api/TChart.js.map +0 -1
  34. package/dist/api/createChart.js +0 -42
  35. package/dist/api/createChart.js.map +0 -1
  36. package/dist/api/drawing tools/fib gann menu/fibRetracement.js +0 -22
  37. package/dist/api/drawing tools/fib gann menu/fibRetracement.js.map +0 -1
  38. package/dist/api/drawing tools/lines menu/crossLine.js +0 -16
  39. package/dist/api/drawing tools/lines menu/crossLine.js.map +0 -1
  40. package/dist/api/drawing tools/lines menu/disjointChannel.js +0 -59
  41. package/dist/api/drawing tools/lines menu/disjointChannel.js.map +0 -1
  42. package/dist/api/drawing tools/lines menu/extendedLine.js +0 -17
  43. package/dist/api/drawing tools/lines menu/extendedLine.js.map +0 -1
  44. package/dist/api/drawing tools/lines menu/flatTopBottom.js +0 -41
  45. package/dist/api/drawing tools/lines menu/flatTopBottom.js.map +0 -1
  46. package/dist/api/drawing tools/lines menu/horizontal.js +0 -19
  47. package/dist/api/drawing tools/lines menu/horizontal.js.map +0 -1
  48. package/dist/api/drawing tools/lines menu/horizontalRay.js +0 -20
  49. package/dist/api/drawing tools/lines menu/horizontalRay.js.map +0 -1
  50. package/dist/api/drawing tools/lines menu/infoLine.js +0 -107
  51. package/dist/api/drawing tools/lines menu/infoLine.js.map +0 -1
  52. package/dist/api/drawing tools/lines menu/insidePitchfork.js +0 -31
  53. package/dist/api/drawing tools/lines menu/insidePitchfork.js.map +0 -1
  54. package/dist/api/drawing tools/lines menu/modifiedSchiffPitchfork.js +0 -15
  55. package/dist/api/drawing tools/lines menu/modifiedSchiffPitchfork.js.map +0 -1
  56. package/dist/api/drawing tools/lines menu/parallelChannel.js +0 -43
  57. package/dist/api/drawing tools/lines menu/parallelChannel.js.map +0 -1
  58. package/dist/api/drawing tools/lines menu/pitchfork.js +0 -12
  59. package/dist/api/drawing tools/lines menu/pitchfork.js.map +0 -1
  60. package/dist/api/drawing tools/lines menu/ray.js +0 -23
  61. package/dist/api/drawing tools/lines menu/ray.js.map +0 -1
  62. package/dist/api/drawing tools/lines menu/regressionTrend.js +0 -127
  63. package/dist/api/drawing tools/lines menu/regressionTrend.js.map +0 -1
  64. package/dist/api/drawing tools/lines menu/schiffPitchfork.js +0 -15
  65. package/dist/api/drawing tools/lines menu/schiffPitchfork.js.map +0 -1
  66. package/dist/api/drawing tools/lines menu/trendAngle.js +0 -51
  67. package/dist/api/drawing tools/lines menu/trendAngle.js.map +0 -1
  68. package/dist/api/drawing tools/lines menu/trendline.js +0 -11
  69. package/dist/api/drawing tools/lines menu/trendline.js.map +0 -1
  70. package/dist/api/drawing tools/lines menu/vertical.js +0 -11
  71. package/dist/api/drawing tools/lines menu/vertical.js.map +0 -1
  72. package/dist/api/drawing tools/pointers menu/crosshair.js +0 -16
  73. package/dist/api/drawing tools/pointers menu/crosshair.js.map +0 -1
  74. package/dist/api/drawing tools/pointers menu/cursor.js +0 -15
  75. package/dist/api/drawing tools/pointers menu/cursor.js.map +0 -1
  76. package/dist/api/drawing tools/pointers menu/demonstration.js +0 -30
  77. package/dist/api/drawing tools/pointers menu/demonstration.js.map +0 -1
  78. package/dist/api/drawing tools/pointers menu/dot.js +0 -23
  79. package/dist/api/drawing tools/pointers menu/dot.js.map +0 -1
  80. package/dist/api/drawing tools/shapes menu/rectangle.js +0 -19
  81. package/dist/api/drawing tools/shapes menu/rectangle.js.map +0 -1
  82. package/dist/api/drawing tools/shapes menu/text.js +0 -25
  83. package/dist/api/drawing tools/shapes menu/text.js.map +0 -1
  84. package/dist/api/drawingUtils.js +0 -83
  85. package/dist/api/drawingUtils.js.map +0 -1
  86. package/dist/core/CanvasLayer.js +0 -56
  87. package/dist/core/CanvasLayer.js.map +0 -1
  88. package/dist/core/Chart.js +0 -839
  89. package/dist/core/Chart.js.map +0 -1
  90. package/dist/core/CoordTransform.js +0 -224
  91. package/dist/core/CoordTransform.js.map +0 -1
  92. package/dist/core/Crosshair.js +0 -186
  93. package/dist/core/Crosshair.js.map +0 -1
  94. package/dist/core/IndicatorEngine.js +0 -181
  95. package/dist/core/IndicatorEngine.js.map +0 -1
  96. package/dist/core/InteractionManager.js +0 -698
  97. package/dist/core/InteractionManager.js.map +0 -1
  98. package/dist/core/PriceScale.js +0 -113
  99. package/dist/core/PriceScale.js.map +0 -1
  100. package/dist/core/Series.js +0 -114
  101. package/dist/core/Series.js.map +0 -1
  102. package/dist/core/TimeScale.js +0 -150
  103. package/dist/core/TimeScale.js.map +0 -1
  104. package/dist/datafeed/DatafeedConnector.js +0 -268
  105. package/dist/datafeed/DatafeedConnector.js.map +0 -1
  106. package/dist/engine/CandleEngine.js +0 -318
  107. package/dist/engine/CandleEngine.js.map +0 -1
  108. package/dist/engine/__tests__/CandleEngine.test.js +0 -300
  109. package/dist/engine/__tests__/CandleEngine.test.js.map +0 -1
  110. package/dist/engine/candleInvariants.js +0 -134
  111. package/dist/engine/candleInvariants.js.map +0 -1
  112. package/dist/engine/mergeUtils.js +0 -64
  113. package/dist/engine/mergeUtils.js.map +0 -1
  114. package/dist/engine/timeframeUtils.js +0 -100
  115. package/dist/engine/timeframeUtils.js.map +0 -1
  116. package/dist/licensing/ChartRuntimeResolver.js +0 -310
  117. package/dist/licensing/ChartRuntimeResolver.js.map +0 -1
  118. package/dist/licensing/LicenseManager.js +0 -114
  119. package/dist/licensing/LicenseManager.js.map +0 -1
  120. package/dist/licensing/__tests__/ChartRuntimeResolver.test.js +0 -177
  121. package/dist/licensing/__tests__/ChartRuntimeResolver.test.js.map +0 -1
  122. package/dist/licensing/__tests__/LicenseManager.test.js +0 -153
  123. package/dist/licensing/__tests__/LicenseManager.test.js.map +0 -1
  124. package/dist/licensing/licenseTypes.js +0 -2
  125. package/dist/licensing/licenseTypes.js.map +0 -1
  126. package/dist/pine/PineCompiler.js +0 -44
  127. package/dist/pine/PineCompiler.js.map +0 -1
  128. package/dist/pine/diagnostics.js +0 -11
  129. package/dist/pine/diagnostics.js.map +0 -1
  130. package/dist/pine/index.js +0 -5
  131. package/dist/pine/index.js.map +0 -1
  132. package/dist/pine/pine-ast.js +0 -19
  133. package/dist/pine/pine-ast.js.map +0 -1
  134. package/dist/pine/pine-lexer.js +0 -249
  135. package/dist/pine/pine-lexer.js.map +0 -1
  136. package/dist/pine/pine-parser.js +0 -416
  137. package/dist/pine/pine-parser.js.map +0 -1
  138. package/dist/pine/pine-transpiler.js +0 -260
  139. package/dist/pine/pine-transpiler.js.map +0 -1
  140. package/dist/pixi/LayerName.js +0 -35
  141. package/dist/pixi/LayerName.js.map +0 -1
  142. package/dist/pixi/PixiCandlestickRenderer.js +0 -107
  143. package/dist/pixi/PixiCandlestickRenderer.js.map +0 -1
  144. package/dist/pixi/PixiChart.js +0 -367
  145. package/dist/pixi/PixiChart.js.map +0 -1
  146. package/dist/pixi/PixiCrosshairRenderer.js +0 -110
  147. package/dist/pixi/PixiCrosshairRenderer.js.map +0 -1
  148. package/dist/pixi/PixiDrawingRenderer.js +0 -111
  149. package/dist/pixi/PixiDrawingRenderer.js.map +0 -1
  150. package/dist/pixi/PixiGridRenderer.js +0 -114
  151. package/dist/pixi/PixiGridRenderer.js.map +0 -1
  152. package/dist/pixi/PixiLayerManager.js +0 -92
  153. package/dist/pixi/PixiLayerManager.js.map +0 -1
  154. package/dist/react/canvas/ChartCanvas.js +0 -604
  155. package/dist/react/canvas/ChartCanvas.js.map +0 -1
  156. package/dist/react/canvas/ChartContextMenu.js +0 -5
  157. package/dist/react/canvas/ChartContextMenu.js.map +0 -1
  158. package/dist/react/canvas/ChartSettingsDialog.js +0 -28
  159. package/dist/react/canvas/ChartSettingsDialog.js.map +0 -1
  160. package/dist/react/canvas/IndicatorLabel.js +0 -196
  161. package/dist/react/canvas/IndicatorLabel.js.map +0 -1
  162. package/dist/react/canvas/IndicatorPane.js +0 -395
  163. package/dist/react/canvas/IndicatorPane.js.map +0 -1
  164. package/dist/react/canvas/PointerOverlay.js +0 -61
  165. package/dist/react/canvas/PointerOverlay.js.map +0 -1
  166. package/dist/react/canvas/toolbars/LeftToolbar.js +0 -407
  167. package/dist/react/canvas/toolbars/LeftToolbar.js.map +0 -1
  168. package/dist/react/hooks/useChartCapabilities.js +0 -66
  169. package/dist/react/hooks/useChartCapabilities.js.map +0 -1
  170. package/dist/react/shell/ManagedAppShell.js +0 -440
  171. package/dist/react/shell/ManagedAppShell.js.map +0 -1
  172. package/dist/react/trading/TradingBridge.js +0 -73
  173. package/dist/react/trading/TradingBridge.js.map +0 -1
  174. package/dist/react/workspace/ChartWorkspace.js +0 -42
  175. package/dist/react/workspace/ChartWorkspace.js.map +0 -1
  176. package/dist/react/workspace/FloatingPanel.js +0 -82
  177. package/dist/react/workspace/FloatingPanel.js.map +0 -1
  178. package/dist/react/workspace/IndicatorsDialog.js +0 -121
  179. package/dist/react/workspace/IndicatorsDialog.js.map +0 -1
  180. package/dist/react/workspace/LayoutMenu.js +0 -113
  181. package/dist/react/workspace/LayoutMenu.js.map +0 -1
  182. package/dist/react/workspace/SymbolSearchDialog.js +0 -245
  183. package/dist/react/workspace/SymbolSearchDialog.js.map +0 -1
  184. package/dist/react/workspace/TabBar.js +0 -29
  185. package/dist/react/workspace/TabBar.js.map +0 -1
  186. package/dist/react/workspace/toolbars/BottomToolbar.js +0 -236
  187. package/dist/react/workspace/toolbars/BottomToolbar.js.map +0 -1
  188. package/dist/react/workspace/toolbars/RightToolbar.js +0 -18
  189. package/dist/react/workspace/toolbars/RightToolbar.js.map +0 -1
  190. package/dist/react/workspace/toolbars/TopToolbar.js +0 -82
  191. package/dist/react/workspace/toolbars/TopToolbar.js.map +0 -1
  192. package/dist/renderers/CandlestickRenderer.js +0 -98
  193. package/dist/renderers/CandlestickRenderer.js.map +0 -1
  194. package/dist/renderers/HistogramRenderer.js +0 -50
  195. package/dist/renderers/HistogramRenderer.js.map +0 -1
  196. package/dist/renderers/LineRenderer.js +0 -64
  197. package/dist/renderers/LineRenderer.js.map +0 -1
  198. package/dist/theme/colors.js +0 -19
  199. package/dist/theme/colors.js.map +0 -1
  200. package/dist/tools/barDivergenceCheck.js +0 -200
  201. package/dist/tools/barDivergenceCheck.js.map +0 -1
  202. package/dist/trading/TradingOverlayStore.js +0 -139
  203. package/dist/trading/TradingOverlayStore.js.map +0 -1
  204. package/dist/trading/UnmanagedIngestion.js +0 -114
  205. package/dist/trading/UnmanagedIngestion.js.map +0 -1
  206. package/dist/trading/__tests__/ManagedTradingController.test.js +0 -271
  207. package/dist/trading/__tests__/ManagedTradingController.test.js.map +0 -1
  208. package/dist/trading/__tests__/TradingOverlayStore.test.js +0 -267
  209. package/dist/trading/__tests__/TradingOverlayStore.test.js.map +0 -1
  210. package/dist/trading/__tests__/UnmanagedIngestion.test.js +0 -170
  211. package/dist/trading/__tests__/UnmanagedIngestion.test.js.map +0 -1
  212. package/dist/trading/managed/ManagedTradingController.js +0 -247
  213. package/dist/trading/managed/ManagedTradingController.js.map +0 -1
  214. package/dist/trading/managed/managedCapabilities.js +0 -79
  215. package/dist/trading/managed/managedCapabilities.js.map +0 -1
  216. package/dist/trading/managed/managedTypes.js +0 -13
  217. package/dist/trading/managed/managedTypes.js.map +0 -1
  218. package/dist/trading/tradingTypes.js +0 -8
  219. package/dist/trading/tradingTypes.js.map +0 -1
  220. package/dist/tscript/TScriptIndicator.js +0 -47
  221. package/dist/tscript/TScriptIndicator.js.map +0 -1
  222. package/dist/tscript/ast.js +0 -22
  223. package/dist/tscript/ast.js.map +0 -1
  224. package/dist/tscript/lexer.js +0 -187
  225. package/dist/tscript/lexer.js.map +0 -1
  226. package/dist/tscript/parser.js +0 -318
  227. package/dist/tscript/parser.js.map +0 -1
  228. package/dist/tscript/runtime.js +0 -475
  229. package/dist/tscript/runtime.js.map +0 -1
  230. package/dist/tscript/series.js +0 -79
  231. package/dist/tscript/series.js.map +0 -1
  232. package/dist/types/IChart.js +0 -2
  233. package/dist/types/IChart.js.map +0 -1
  234. package/dist/types/IRenderer.js +0 -2
  235. package/dist/types/IRenderer.js.map +0 -1
  236. package/dist/types/ISeries.js +0 -2
  237. package/dist/types/ISeries.js.map +0 -1
@@ -1,300 +0,0 @@
1
- import { describe, it, expect, vi } from 'vitest';
2
- import { CandleEngine } from '../CandleEngine';
3
- import { timeframeToMs, getBucketStart } from '../timeframeUtils';
4
- import { getMissingBarCount, mergeBars } from '../mergeUtils';
5
- // ─── Helpers ─────────────────────────────────────────────────────────────────
6
- /** Build a minimal raw bar with time in seconds. */
7
- function rawBar(timeSec, open, high, low, close, volume = 1, isClosed = false) {
8
- return { time: timeSec, open, high, low, close, volume, isClosed };
9
- }
10
- /** Build a raw bar with time in milliseconds. */
11
- function rawBarMs(timeSec, open, high, low, close) {
12
- return { time: timeSec * 1000, open, high, low, close, volume: 1 };
13
- }
14
- // 1-minute boundary: 2024-07-03T10:00:00Z = 1719997200 seconds
15
- const T0 = 1_719_997_200;
16
- const T1 = T0 + 60;
17
- const T2 = T0 + 120;
18
- const T3 = T0 + 180;
19
- const T4 = T0 + 240;
20
- // ─── 1. Same-candle update ────────────────────────────────────────────────────
21
- describe('same-candle update (3 ticks, same bucket)', () => {
22
- it('produces exactly one candle with correct O/H/L/C', () => {
23
- const engine = new CandleEngine();
24
- engine.initialize([], '1m');
25
- engine.applyLiveUpdate(rawBar(T0, 100, 105, 98, 103));
26
- engine.applyLiveUpdate(rawBar(T0, 100, 108, 96, 107)); // high rises, low drops
27
- engine.applyLiveUpdate(rawBar(T0, 100, 107, 97, 106)); // high recedes — not applied
28
- expect(engine.getBars().length).toBe(1);
29
- const bar = engine.getLastBar();
30
- expect(bar.open).toBe(100); // open preserved from first tick
31
- expect(bar.high).toBe(108); // max of all ticks
32
- expect(bar.low).toBe(96); // min of all ticks
33
- expect(bar.close).toBe(106); // close from latest tick
34
- });
35
- it('returns UpdateResult type "update" for same-candle ticks', () => {
36
- const engine = new CandleEngine();
37
- engine.initialize([], '1m');
38
- const r1 = engine.applyLiveUpdate(rawBar(T0, 100, 100, 100, 100));
39
- const r2 = engine.applyLiveUpdate(rawBar(T0, 100, 110, 90, 105));
40
- expect(r1.type).toBe('append'); // first tick is an append
41
- expect(r2.type).toBe('update');
42
- });
43
- it('high can never decrease within a candle', () => {
44
- const engine = new CandleEngine();
45
- engine.initialize([], '1m');
46
- engine.applyLiveUpdate(rawBar(T0, 50, 120, 40, 100));
47
- engine.applyLiveUpdate(rawBar(T0, 50, 80, 60, 90)); // high=80 < 120
48
- expect(engine.getLastBar().high).toBe(120);
49
- });
50
- it('low can never increase within a candle', () => {
51
- const engine = new CandleEngine();
52
- engine.initialize([], '1m');
53
- engine.applyLiveUpdate(rawBar(T0, 50, 120, 40, 100));
54
- engine.applyLiveUpdate(rawBar(T0, 50, 110, 75, 105)); // low=75 > 40
55
- expect(engine.getLastBar().low).toBe(40);
56
- });
57
- });
58
- // ─── 2. New-candle append ─────────────────────────────────────────────────────
59
- describe('new-candle append (time advances)', () => {
60
- it('appends a second candle and marks first as closed', () => {
61
- const engine = new CandleEngine();
62
- engine.initialize([], '1m');
63
- engine.applyLiveUpdate(rawBar(T0, 100, 105, 98, 103));
64
- const result = engine.applyLiveUpdate(rawBar(T1, 103, 110, 101, 108));
65
- expect(result.type).toBe('append');
66
- expect(engine.getBars().length).toBe(2);
67
- expect(engine.getBars()[0].isClosed).toBe(true);
68
- expect(engine.getBars()[1].isClosed).toBe(false);
69
- });
70
- it('appended candle uses the new tick\'s open price', () => {
71
- const engine = new CandleEngine();
72
- engine.initialize([], '1m');
73
- engine.applyLiveUpdate(rawBar(T0, 100, 105, 98, 103));
74
- engine.applyLiveUpdate(rawBar(T1, 200, 210, 195, 205));
75
- expect(engine.getBars()[1].open).toBe(200);
76
- });
77
- });
78
- // ─── 3. Out-of-order discard ──────────────────────────────────────────────────
79
- describe('out-of-order ticks', () => {
80
- it('discards ticks older than the current live candle', () => {
81
- const engine = new CandleEngine();
82
- engine.initialize([], '1m');
83
- engine.applyLiveUpdate(rawBar(T1, 103, 110, 100, 107)); // at T1
84
- const result = engine.applyLiveUpdate(rawBar(T0, 100, 120, 95, 115)); // T0 < T1
85
- expect(result.type).toBe('ignore');
86
- expect(engine.getBars().length).toBe(1);
87
- expect(engine.getLastBar().time).toBe(T1);
88
- });
89
- it('does not change any OHLCV values after discarding', () => {
90
- const engine = new CandleEngine();
91
- engine.initialize([], '1m');
92
- engine.applyLiveUpdate(rawBar(T1, 103, 110, 100, 107));
93
- const snapBefore = { ...engine.getLastBar() };
94
- engine.applyLiveUpdate(rawBar(T0, 999, 999, 1, 999));
95
- expect(engine.getLastBar().open).toBe(snapBefore.open);
96
- expect(engine.getLastBar().high).toBe(snapBefore.high);
97
- expect(engine.getLastBar().low).toBe(snapBefore.low);
98
- expect(engine.getLastBar().close).toBe(snapBefore.close);
99
- });
100
- });
101
- // ─── 4. Gap detection ─────────────────────────────────────────────────────────
102
- describe('gap detection', () => {
103
- it('fires onGapDetected when a bucket is skipped', () => {
104
- const gaps = [];
105
- const engine = new CandleEngine({ onGapDetected: (g) => gaps.push(g) });
106
- engine.initialize([], '1m');
107
- engine.applyLiveUpdate(rawBar(T0, 100, 105, 98, 103));
108
- // Jump 3 minutes — T1 and T2 are missing
109
- engine.applyLiveUpdate(rawBar(T3, 110, 115, 108, 113));
110
- expect(gaps.length).toBe(1);
111
- expect(gaps[0].missingCount).toBe(2);
112
- expect(gaps[0].fromTimeMs).toBe(T0 * 1000);
113
- expect(gaps[0].toTimeMs).toBe(T3 * 1000);
114
- });
115
- it('returns UpdateResult type "gap" when a gap occurs', () => {
116
- const engine = new CandleEngine();
117
- engine.initialize([], '1m');
118
- engine.applyLiveUpdate(rawBar(T0, 100, 105, 98, 103));
119
- const result = engine.applyLiveUpdate(rawBar(T4, 103, 108, 101, 106));
120
- expect(result.type).toBe('gap');
121
- if (result.type === 'gap') {
122
- expect(result.missingCount).toBe(3);
123
- }
124
- });
125
- it('does not fire onGapDetected for consecutive candles', () => {
126
- const gapFn = vi.fn();
127
- const engine = new CandleEngine({ onGapDetected: gapFn });
128
- engine.initialize([], '1m');
129
- engine.applyLiveUpdate(rawBar(T0, 100, 105, 98, 103));
130
- engine.applyLiveUpdate(rawBar(T1, 103, 108, 101, 106));
131
- expect(gapFn).not.toHaveBeenCalled();
132
- });
133
- });
134
- // ─── 5. Reconnect reconciliation ─────────────────────────────────────────────
135
- describe('handleReconnect', () => {
136
- it('deduplicates bars correctly when there is overlap', () => {
137
- const engine = new CandleEngine();
138
- engine.initialize([
139
- rawBar(T0, 100, 105, 98, 103, 10, true),
140
- rawBar(T1, 103, 108, 101, 106, 12, true),
141
- rawBar(T2, 106, 110, 104, 109, 8, false), // live
142
- ], '1m');
143
- // Reconnect brings T1 and T2 with corrected values
144
- engine.handleReconnect([
145
- rawBar(T1, 103, 112, 99, 111, 15, true), // corrected T1
146
- rawBar(T2, 106, 111, 103, 110, 9, false), // corrected T2 (live)
147
- ]);
148
- expect(engine.getBars().length).toBe(3);
149
- expect(engine.getBars()[1].high).toBe(112); // T1 updated
150
- expect(engine.getBars()[2].high).toBe(111); // T2 updated
151
- });
152
- it('fires onResync after handleReconnect', () => {
153
- const resyncFn = vi.fn();
154
- const engine = new CandleEngine({ onResync: resyncFn });
155
- engine.initialize([rawBar(T0, 100, 105, 98, 103)], '1m');
156
- engine.handleReconnect([rawBar(T0, 100, 107, 96, 104)]);
157
- expect(resyncFn).toHaveBeenCalledOnce();
158
- });
159
- });
160
- // ─── 6. ms → s timestamp conversion ─────────────────────────────────────────
161
- describe('millisecond vs second timestamp normalisation', () => {
162
- it('converts ms timestamps to seconds correctly', () => {
163
- const engine = new CandleEngine();
164
- engine.initialize([], '1m');
165
- // T0 in ms
166
- engine.applyLiveUpdate(rawBarMs(T0, 100, 105, 98, 103));
167
- const bar = engine.getLastBar();
168
- expect(bar.time).toBe(T0); // chart field = seconds
169
- expect(bar.timeMs).toBe(T0 * 1000); // engine field = ms
170
- });
171
- it('handles both ms and s inputs in the same session without corruption', () => {
172
- const engine = new CandleEngine();
173
- engine.initialize([], '1m');
174
- engine.applyLiveUpdate(rawBarMs(T0, 100, 105, 98, 103)); // ms
175
- engine.applyLiveUpdate(rawBar(T0, 100, 110, 95, 108)); // seconds, same bucket
176
- expect(engine.getBars().length).toBe(1); // same bucket → still one candle
177
- expect(engine.getLastBar().high).toBe(110);
178
- });
179
- it('floors ms timestamp to candle boundary', () => {
180
- const engine = new CandleEngine();
181
- engine.initialize([], '1m');
182
- // T0 + 30s (mid-candle) in ms → should still map to T0 bucket
183
- engine.applyLiveUpdate({ time: (T0 + 30) * 1000, open: 100, high: 105, low: 98, close: 103 });
184
- expect(engine.getLastBar().time).toBe(T0);
185
- });
186
- });
187
- // ─── 7. Custom timeframe aggregation (timeframeUtils) ────────────────────────
188
- describe('timeframeUtils helpers', () => {
189
- it('timeframeToMs returns correct durations', () => {
190
- expect(timeframeToMs('1m')).toBe(60_000);
191
- expect(timeframeToMs('5m')).toBe(300_000);
192
- expect(timeframeToMs('1h')).toBe(3_600_000);
193
- expect(timeframeToMs('4h')).toBe(14_400_000);
194
- expect(timeframeToMs('1d')).toBe(86_400_000);
195
- // 1w and 1M are calendar timeframes — no fixed ms duration.
196
- // timeframeUtils returns the 60_000 compat fallback so CandleEngine
197
- // always receives a finite number (calendar alignment is handled separately).
198
- expect(timeframeToMs('1w')).toBe(60_000);
199
- });
200
- it('timeframeToMs falls back to 60_000 for unknown labels', () => {
201
- // '3h' and '8h' are orphaned (excluded from canonical registry) → 60_000 fallback.
202
- // '2m' is now registered (120_000) — use genuinely unknown keys here.
203
- expect(timeframeToMs('3h')).toBe(60_000);
204
- expect(timeframeToMs('')).toBe(60_000);
205
- });
206
- it('getBucketStart floors to candle boundary', () => {
207
- expect(getBucketStart(62_000, 60_000)).toBe(60_000); // 1m01s → 1m00s
208
- expect(getBucketStart(3_720_000, 3_600_000)).toBe(3_600_000); // 1h02m → 1h00m
209
- expect(getBucketStart(0, 60_000)).toBe(0);
210
- });
211
- it('5m candle engine buckets a mid-bar tick to the 5m open', () => {
212
- const engine = new CandleEngine();
213
- engine.initialize([], '5m');
214
- const T5m = getBucketStart(T0 * 1000, timeframeToMs('5m')); // floor T0 to 5m
215
- const mid = T5m / 1000 + 120; // 2 minutes into the 5m bucket
216
- engine.applyLiveUpdate({ time: mid, open: 50, high: 55, low: 48, close: 52 });
217
- expect(engine.getLastBar().timeMs).toBe(T5m);
218
- });
219
- });
220
- // ─── 8. mergeUtils helpers ────────────────────────────────────────────────────
221
- describe('mergeUtils helpers', () => {
222
- const makeBar = (timeSec, close, isClosed) => ({
223
- timeMs: timeSec * 1000,
224
- time: timeSec,
225
- open: 100, high: 110, low: 90, close,
226
- volume: 1, isClosed,
227
- });
228
- it('getMissingBarCount returns 0 for consecutive bars', () => {
229
- expect(getMissingBarCount(T0 * 1000, T1 * 1000, 60_000)).toBe(0);
230
- });
231
- it('getMissingBarCount returns correct count for gap', () => {
232
- expect(getMissingBarCount(T0 * 1000, T3 * 1000, 60_000)).toBe(2); // T1 and T2
233
- expect(getMissingBarCount(T0 * 1000, T4 * 1000, 60_000)).toBe(3); // T1, T2, T3
234
- });
235
- it('mergeBars deduplicates by timeMs with incoming winning', () => {
236
- const existing = [makeBar(T0, 103, true), makeBar(T1, 106, true)];
237
- const incoming = [makeBar(T1, 999, true), makeBar(T2, 110, false)]; // T1 override
238
- const merged = mergeBars(existing, incoming);
239
- expect(merged.length).toBe(3);
240
- expect(merged[1].close).toBe(999); // incoming wins for closed bar
241
- expect(merged[2].time).toBe(T2);
242
- });
243
- it('mergeBars preserves existing live candle when incoming is also live and same time', () => {
244
- const existing = [makeBar(T0, 103, false)]; // live, close=103
245
- const incoming = [makeBar(T0, 107, false)]; // fresher live tick, close=107
246
- const merged = mergeBars(existing, incoming);
247
- // Live bar: incoming wins because it is the freshest tick
248
- expect(merged[0].close).toBe(107);
249
- });
250
- it('mergeBars sorts output by timeMs', () => {
251
- const bars = [makeBar(T2, 100, true), makeBar(T0, 100, true), makeBar(T1, 100, true)];
252
- const sorted = mergeBars(bars, []);
253
- expect(sorted.map(b => b.time)).toEqual([T0, T1, T2]);
254
- });
255
- });
256
- // ─── 9. backfillGap ───────────────────────────────────────────────────────────
257
- describe('backfillGap', () => {
258
- it('fills missing buckets and fires onResync', () => {
259
- const resyncFn = vi.fn();
260
- const engine = new CandleEngine({ onResync: resyncFn });
261
- engine.initialize([
262
- rawBar(T0, 100, 105, 98, 103),
263
- rawBar(T3, 110, 115, 108, 113), // gap: T1, T2 missing
264
- ], '1m');
265
- engine.backfillGap([
266
- rawBar(T1, 103, 108, 101, 106),
267
- rawBar(T2, 106, 110, 104, 109),
268
- ]);
269
- expect(engine.getBars().length).toBe(4);
270
- expect(resyncFn).toHaveBeenCalledOnce();
271
- const times = engine.getBars().map(b => b.time);
272
- expect(times).toEqual([T0, T1, T2, T3]);
273
- });
274
- });
275
- // ─── 10. CandleEngine lifecycle ──────────────────────────────────────────────
276
- describe('lifecycle', () => {
277
- it('reset() clears all bars', () => {
278
- const engine = new CandleEngine();
279
- engine.initialize([rawBar(T0, 100, 105, 98, 103)], '1m');
280
- engine.reset();
281
- expect(engine.getBars().length).toBe(0);
282
- expect(engine.getLastBar()).toBeNull();
283
- });
284
- it('handles initialize() with empty history', () => {
285
- const engine = new CandleEngine();
286
- engine.initialize([], '1m');
287
- expect(engine.getBars().length).toBe(0);
288
- expect(engine.getLastBar()).toBeNull();
289
- });
290
- it('handles duplicate historical bars (keeps last per timeMs)', () => {
291
- const engine = new CandleEngine();
292
- engine.initialize([
293
- rawBar(T0, 100, 105, 98, 103),
294
- rawBar(T0, 100, 110, 96, 108), // same time, last should win
295
- ], '1m');
296
- expect(engine.getBars().length).toBe(1);
297
- expect(engine.getLastBar().high).toBe(110);
298
- });
299
- });
300
- //# sourceMappingURL=CandleEngine.test.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"CandleEngine.test.js","sourceRoot":"","sources":["../../../src/engine/__tests__/CandleEngine.test.ts"],"names":[],"mappings":"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"}
@@ -1,134 +0,0 @@
1
- /**
2
- * Candle Invariant Guards
3
- *
4
- * Defensive assertions for the CandleEngine update pipeline.
5
- * All guards are no-ops in production (`NODE_ENV === 'production'`).
6
- *
7
- * Design principles:
8
- * - Each guard checks exactly ONE invariant and logs a descriptive warning.
9
- * - Guards never throw by default — they warn so streaming data is never blocked.
10
- * - Call sites pass a `context` string that identifies where the check ran.
11
- * - A test harness can replace `_reporter` to assert on violations.
12
- *
13
- * Usage:
14
- * import { assertOhlcRelationships, assertNotFinalized } from './candleInvariants';
15
- */
16
- import { getCalendarBucketStart } from './timeframeUtils';
17
- // ─── Reporter (swappable in tests) ───────────────────────────────────────────
18
- /** Called for every invariant violation. Replaced in unit tests. */
19
- export let _reporter = (msg) => console.warn(msg);
20
- /** Replace the violation reporter (for unit-test assertions). */
21
- export function _setReporter(fn) {
22
- _reporter = fn;
23
- }
24
- /** Re-install the default console.warn reporter. */
25
- export function _resetReporter() {
26
- _reporter = (msg) => console.warn(msg);
27
- }
28
- // ─── Dev guard ───────────────────────────────────────────────────────────────
29
- function isDevMode() {
30
- // Access process via globalThis to avoid relying on @types/node in browser builds
31
- const nodeEnv = globalThis
32
- .process?.env?.['NODE_ENV'];
33
- return nodeEnv !== 'production';
34
- }
35
- function violation(context, message) {
36
- _reporter(`[CANDLE_INVARIANT] ${context}: ${message}`);
37
- }
38
- // ─── Guards ───────────────────────────────────────────────────────────────────
39
- /**
40
- * Verify that `high >= open, close, low` and `low <= open, close`.
41
- *
42
- * Floats from external feeds can occasionally violate these due to rounding.
43
- * This guard surfaces them immediately rather than silently corrupting the chart.
44
- */
45
- export function assertOhlcRelationships(bar, context) {
46
- if (!isDevMode())
47
- return;
48
- const { open, high, low, close, timeMs } = bar;
49
- if (high < open)
50
- violation(context, `high(${high}) < open(${open}) at timeMs=${timeMs}`);
51
- if (high < close)
52
- violation(context, `high(${high}) < close(${close}) at timeMs=${timeMs}`);
53
- if (high < low)
54
- violation(context, `high(${high}) < low(${low}) at timeMs=${timeMs}`);
55
- if (low > open)
56
- violation(context, `low(${low}) > open(${open}) at timeMs=${timeMs}`);
57
- if (low > close)
58
- violation(context, `low(${low}) > close(${close}) at timeMs=${timeMs}`);
59
- }
60
- /**
61
- * Verify that `bar.timeMs` is exactly equal to the candle-open boundary for the
62
- * given timeframe. If it is not, `normalizeOhlcv` or `getCalendarBucketStart`
63
- * has a bug.
64
- */
65
- export function assertBucketAlignment(bar, tf, context) {
66
- if (!isDevMode())
67
- return;
68
- const expected = getCalendarBucketStart(bar.timeMs, tf);
69
- if (bar.timeMs !== expected) {
70
- violation(context, `timeMs(${bar.timeMs}) ≠ bucketStart(${expected}) for tf=${tf} ` +
71
- `(delta=${bar.timeMs - expected} ms)`);
72
- }
73
- }
74
- /**
75
- * Verify that we are NOT about to mutate a candle that has already been finalised
76
- * (`isClosed === true`). Mutating a closed candle corrupts the historical record.
77
- *
78
- * Triggers on: same-bucket update landing on a bar already marked closed.
79
- */
80
- export function assertNotFinalized(bar, context) {
81
- if (!isDevMode())
82
- return;
83
- if (bar.isClosed) {
84
- violation(context, `attempted to mutate a finalized (isClosed=true) candle at timeMs=${bar.timeMs}`);
85
- }
86
- }
87
- /**
88
- * Verify that a same-bucket update did NOT silently overwrite the candle's `open`.
89
- *
90
- * The first tick's open is authoritative; subsequent updates for the same bucket
91
- * must preserve it. Call this AFTER the in-place mutation with the captured
92
- * `prevOpen` value.
93
- */
94
- export function assertOpenImmutability(prevOpen, bar, context) {
95
- if (!isDevMode())
96
- return;
97
- if (bar.open !== prevOpen) {
98
- violation(context, `open changed from ${prevOpen} → ${bar.open} on same-bucket update ` +
99
- `at timeMs=${bar.timeMs} — first-tick open is authoritative`);
100
- }
101
- }
102
- /**
103
- * Verify that a same-bucket update does NOT append a new bar instead of
104
- * updating the existing one.
105
- *
106
- * Call after an in-place update with the pre- and post-update bar counts.
107
- */
108
- export function assertNoDuplicateAppend(prevCount, nextCount, context) {
109
- if (!isDevMode())
110
- return;
111
- if (nextCount > prevCount) {
112
- violation(context, `same-bucket update incremented bar count from ${prevCount} → ${nextCount} ` +
113
- `(should have updated in-place, not appended)`);
114
- }
115
- }
116
- /**
117
- * Verify that a new-bucket append does NOT reduce the bar count or silently
118
- * overwrite a finalized candle (would require bar count to stay the same while
119
- * the last bar's timeMs changes, which the engine never does).
120
- *
121
- * Call after appending a new bar with the previous last bar for comparison.
122
- */
123
- export function assertFinalizedUnchanged(prevLastBar, currentBars, context) {
124
- if (!isDevMode())
125
- return;
126
- const prevIndex = currentBars.findIndex(b => b.timeMs === prevLastBar.timeMs);
127
- if (prevIndex === -1)
128
- return; // bar may have been legitimately removed by merge
129
- const preserved = currentBars[prevIndex];
130
- if (!preserved.isClosed) {
131
- violation(context, `bar at timeMs=${prevLastBar.timeMs} should be isClosed=true after new-bucket append`);
132
- }
133
- }
134
- //# sourceMappingURL=candleInvariants.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"candleInvariants.js","sourceRoot":"","sources":["../../src/engine/candleInvariants.ts"],"names":[],"mappings":"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"}
@@ -1,64 +0,0 @@
1
- /**
2
- * Merge / reconciliation helpers for the candle engine.
3
- *
4
- * These utilities operate on plain data objects and have no side-effects,
5
- * making them easy to test and reuse.
6
- */
7
- /**
8
- * Count the number of missing candle buckets between two consecutive bar times.
9
- *
10
- * Returns 0 when bars are adjacent (no gap), ≥1 when candles are missing.
11
- *
12
- * @example
13
- * getMissingBarCount(60_000, 120_000, 60_000) // → 0 (consecutive 1m bars)
14
- * getMissingBarCount(60_000, 240_000, 60_000) // → 2 (10:01 and 10:02 missing)
15
- * getMissingBarCount(60_000, 3_660_000, 60_000) // → 59 (whole hour gap)
16
- */
17
- export function getMissingBarCount(lastTimeMs, nextTimeMs, intervalMs) {
18
- return Math.max(0, Math.floor((nextTimeMs - lastTimeMs) / intervalMs) - 1);
19
- }
20
- /**
21
- * Merge two candle arrays into a single deduplicated, time-sorted array.
22
- *
23
- * Conflict resolution when both arrays contain a bar with the same `timeMs`:
24
- * - Closed bars from `incoming` always override `existing` candles —
25
- * REST-fetched data is treated as authoritative for finished candles.
26
- * - The live (open) candle: `incoming` also wins — it is the freshest tick.
27
- *
28
- * This covers both gap backfill (REST data fills missing closed bars) and
29
- * reconnect reconciliation (recent REST window corrects stale candles).
30
- *
31
- * @param existing Current engine bar array (read-only — not mutated).
32
- * @param incoming New bars to merge in (read-only — not mutated).
33
- * @returns A new sorted array with duplicates removed.
34
- */
35
- export function mergeBars(existing, incoming) {
36
- const map = new Map();
37
- // Load existing bars first
38
- for (const bar of existing) {
39
- map.set(bar.timeMs, bar);
40
- }
41
- // Incoming bars override based on conflict resolution rules
42
- for (const bar of incoming) {
43
- const prev = map.get(bar.timeMs);
44
- // Incoming wins when:
45
- // a) no previous bar at this time (simple insert)
46
- // b) previous bar is closed — REST data is authoritative for closed candles
47
- // c) incoming bar is open (live) — always prefer the latest live tick
48
- if (!prev || prev.isClosed || !bar.isClosed) {
49
- map.set(bar.timeMs, bar);
50
- }
51
- }
52
- return Array.from(map.values()).sort((a, b) => a.timeMs - b.timeMs);
53
- }
54
- /**
55
- * Deduplicate a single sorted array by `timeMs`, keeping the last occurrence
56
- * of any duplicate (latest data wins).
57
- */
58
- export function deduplicateBars(bars) {
59
- const map = new Map();
60
- for (const bar of bars)
61
- map.set(bar.timeMs, bar);
62
- return Array.from(map.values()).sort((a, b) => a.timeMs - b.timeMs);
63
- }
64
- //# sourceMappingURL=mergeUtils.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"mergeUtils.js","sourceRoot":"","sources":["../../src/engine/mergeUtils.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAoBH;;;;;;;;;GASG;AACH,MAAM,UAAU,kBAAkB,CAChC,UAAkB,EAClB,UAAkB,EAClB,UAAkB;IAElB,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,UAAU,GAAG,UAAU,CAAC,GAAG,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC;AAC7E,CAAC;AAED;;;;;;;;;;;;;;GAcG;AACH,MAAM,UAAU,SAAS,CACvB,QAA8B,EAC9B,QAA8B;IAE9B,MAAM,GAAG,GAAG,IAAI,GAAG,EAAqB,CAAC;IAEzC,2BAA2B;IAC3B,KAAK,MAAM,GAAG,IAAI,QAAQ,EAAE,CAAC;QAC3B,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAC3B,CAAC;IAED,4DAA4D;IAC5D,KAAK,MAAM,GAAG,IAAI,QAAQ,EAAE,CAAC;QAC3B,MAAM,IAAI,GAAG,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;QACjC,sBAAsB;QACtB,oDAAoD;QACpD,8EAA8E;QAC9E,wEAAwE;QACxE,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,QAAQ,IAAI,CAAC,GAAG,CAAC,QAAQ,EAAE,CAAC;YAC5C,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;QAC3B,CAAC;IACH,CAAC;IAED,OAAO,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,MAAM,CAAC,CAAC;AACtE,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,eAAe,CAAC,IAAiB;IAC/C,MAAM,GAAG,GAAG,IAAI,GAAG,EAAqB,CAAC;IACzC,KAAK,MAAM,GAAG,IAAI,IAAI;QAAE,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IACjD,OAAO,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,MAAM,CAAC,CAAC;AACtE,CAAC"}
@@ -1,100 +0,0 @@
1
- /**
2
- * Timeframe utilities — thin compatibility wrappers over `@forgecharts/shared/time`.
3
- *
4
- * All bucket-alignment logic now lives in the canonical shared module.
5
- * These exports keep the existing `CandleEngine` and `DatafeedConnector` import
6
- * surface stable while delegating every calculation to the single source of truth.
7
- *
8
- * Migration note:
9
- * New code should import directly from `@forgecharts/shared/time`:
10
- * import { getBucketStart, getWeekBucketStart, getMonthBucketStart } from '@forgecharts/shared/time';
11
- *
12
- * Legacy imports from this file continue to work unchanged.
13
- */
14
- import { getBucketStart as sharedGetBucketStart, timeframeToMs as sharedTimeframeToMs, } from '@forgecharts/shared/time';
15
- // ─── timeframeToMs ────────────────────────────────────────────────────────────
16
- /**
17
- * Convert a timeframe label to its duration in milliseconds.
18
- *
19
- * Returns `60_000` (1 minute) for calendar timeframes (`1w`, `1M`) and unknown
20
- * labels — preserving the previous behaviour that `CandleEngine` depended on.
21
- * New code should use `sharedTimeframeToMs` (which returns `null` for those
22
- * cases) and handle `null` explicitly.
23
- *
24
- * @example
25
- * timeframeToMs('1m') // → 60_000
26
- * timeframeToMs('4h') // → 14_400_000
27
- * timeframeToMs('1w') // → 60_000 (calendar — no fixed duration; fallback)
28
- */
29
- export function timeframeToMs(timeframe) {
30
- return sharedTimeframeToMs(timeframe) ?? 60_000;
31
- }
32
- // ─── getBucketStart (interval-based) ─────────────────────────────────────────
33
- /**
34
- * Floor a millisecond timestamp to the start of its fixed-interval bucket.
35
- *
36
- * This overload takes an explicit `intervalMs` and is used internally by
37
- * `aggregateToBucket` for sub-daily custom timeframe synthesis.
38
- *
39
- * For timeframe-label–based alignment (including 1w / 1M calendar logic)
40
- * use `getCalendarBucketStart` or import `getBucketStart` from `@forgecharts/shared`.
41
- *
42
- * @example
43
- * getBucketStart(62_000, 60_000) // → 60_000
44
- * getBucketStart(3_720_000, 3_600_000) // → 3_600_000
45
- */
46
- export function getBucketStart(timeMs, intervalMs) {
47
- return Math.floor(timeMs / intervalMs) * intervalMs;
48
- }
49
- // ─── getCalendarBucketStart ───────────────────────────────────────────────────
50
- /**
51
- * Floor a millisecond timestamp to the candle-open boundary for the given
52
- * timeframe label, with correct calendar alignment:
53
- *
54
- * `1w` — Monday-aligned week (ISO 8601, UTC) via `getWeekBucketStart`
55
- * `1M` — first of calendar month, UTC via `getMonthBucketStart`
56
- * all others — plain epoch-floor via `getBucketStart`
57
- *
58
- * Delegates entirely to the canonical shared module.
59
- */
60
- export function getCalendarBucketStart(timeMs, tf) {
61
- return sharedGetBucketStart(timeMs, tf);
62
- }
63
- // ─── aggregateToBucket ────────────────────────────────────────────────────────
64
- /**
65
- * Build a custom timeframe by aggregating base-timeframe candles into larger buckets.
66
- * Returns the aggregated candles for all buckets covered by `subBars`.
67
- *
68
- * This is the building block for synthesising e.g. 3m from 1m feeds.
69
- *
70
- * @param subBars Candles from the base timeframe, sorted ascending by timeMs.
71
- * @param targetMs Target timeframe duration in ms (e.g. 180_000 for 3m).
72
- *
73
- * @throws {Error} If `targetMs` corresponds to a calendar-irregular timeframe
74
- * (`1w` / `1M`). Use `getCalendarBucketStart` for those directly.
75
- */
76
- export function aggregateToBucket(subBars, targetMs) {
77
- // 1w is 7 days exactly; 1M has no fixed duration and can never equal a targetMs.
78
- // Guard prevents accidentally using fixed-interval bucketing for weekly candles
79
- // where DST can make weeks slightly unequal (though UTC avoids this).
80
- const WEEK_MS = 7 * 24 * 60 * 60 * 1000; // 604_800_000
81
- if (targetMs === WEEK_MS) {
82
- throw new Error('aggregateToBucket: use getCalendarBucketStart for 1w/1M aggregation');
83
- }
84
- const buckets = new Map();
85
- for (const bar of subBars) {
86
- const bucket = getBucketStart(bar.timeMs, targetMs);
87
- const existing = buckets.get(bucket);
88
- if (!existing) {
89
- buckets.set(bucket, { timeMs: bucket, open: bar.open, high: bar.high, low: bar.low, close: bar.close, volume: bar.volume });
90
- }
91
- else {
92
- existing.high = Math.max(existing.high, bar.high);
93
- existing.low = Math.min(existing.low, bar.low);
94
- existing.close = bar.close;
95
- existing.volume += bar.volume;
96
- }
97
- }
98
- return Array.from(buckets.values()).sort((a, b) => a.timeMs - b.timeMs);
99
- }
100
- //# sourceMappingURL=timeframeUtils.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"timeframeUtils.js","sourceRoot":"","sources":["../../src/engine/timeframeUtils.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,EACL,cAAc,IAAM,oBAAoB,EACxC,aAAa,IAAO,mBAAmB,GACxC,MAAM,0BAA0B,CAAC;AAElC,iFAAiF;AAEjF;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,aAAa,CAAC,SAAiB;IAC7C,OAAO,mBAAmB,CAAC,SAAS,CAAC,IAAI,MAAM,CAAC;AAClD,CAAC;AAED,gFAAgF;AAEhF;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,cAAc,CAAC,MAAc,EAAE,UAAkB;IAC/D,OAAO,IAAI,CAAC,KAAK,CAAC,MAAM,GAAG,UAAU,CAAC,GAAG,UAAU,CAAC;AACtD,CAAC;AAED,iFAAiF;AAEjF;;;;;;;;;GASG;AACH,MAAM,UAAU,sBAAsB,CAAC,MAAc,EAAE,EAAU;IAC/D,OAAO,oBAAoB,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;AAC1C,CAAC;AAED,iFAAiF;AAEjF;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,iBAAiB,CAC/B,OAEE,EACF,QAAgB;IAEhB,iFAAiF;IACjF,gFAAgF;IAChF,sEAAsE;IACtE,MAAM,OAAO,GAAG,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC,cAAc;IACvD,IAAI,QAAQ,KAAK,OAAO,EAAE,CAAC;QACzB,MAAM,IAAI,KAAK,CAAC,qEAAqE,CAAC,CAAC;IACzF,CAAC;IAED,MAAM,OAAO,GAAG,IAAI,GAAG,EAAsG,CAAC;IAE9H,KAAK,MAAM,GAAG,IAAI,OAAO,EAAE,CAAC;QAC1B,MAAM,MAAM,GAAG,cAAc,CAAC,GAAG,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;QACpD,MAAM,QAAQ,GAAG,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;QACrC,IAAI,CAAC,QAAQ,EAAE,CAAC;YACd,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,GAAG,CAAC,IAAI,EAAE,IAAI,EAAE,GAAG,CAAC,IAAI,EAAE,GAAG,EAAE,GAAG,CAAC,GAAG,EAAE,KAAK,EAAE,GAAG,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,CAAC,CAAC;QAC9H,CAAC;aAAM,CAAC;YACN,QAAQ,CAAC,IAAI,GAAK,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,EAAE,GAAG,CAAC,IAAI,CAAC,CAAC;YACpD,QAAQ,CAAC,GAAG,GAAM,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,GAAG,EAAG,GAAG,CAAC,GAAG,CAAC,CAAC;YACnD,QAAQ,CAAC,KAAK,GAAI,GAAG,CAAC,KAAK,CAAC;YAC5B,QAAQ,CAAC,MAAM,IAAI,GAAG,CAAC,MAAM,CAAC;QAChC,CAAC;IACH,CAAC;IAED,OAAO,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,MAAM,CAAC,CAAC;AAC1E,CAAC"}