velo-plot 1.12.0 → 1.19.0

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 (153) hide show
  1. package/README.md +14 -0
  2. package/dist/{index.core-xiNcuFfJ.js → ChartCore-DQ691eXH.js} +1807 -1287
  3. package/dist/ChartCore-DQ691eXH.js.map +1 -0
  4. package/dist/assets/downsample.worker-C70QJ04y.js +2 -0
  5. package/dist/assets/downsample.worker-C70QJ04y.js.map +1 -0
  6. package/dist/assets/indicator.worker-bv0zC4EX.js +2 -0
  7. package/dist/assets/indicator.worker-bv0zC4EX.js.map +1 -0
  8. package/dist/core/OverlayRenderer.d.ts +2 -0
  9. package/dist/core/chart/ChartAlerts.d.ts +42 -0
  10. package/dist/core/chart/ChartCore.d.ts +20 -1
  11. package/dist/core/chart/ChartRenderLoop.d.ts +4 -2
  12. package/dist/core/chart/ChartRenderer.d.ts +3 -2
  13. package/dist/core/chart/candlestickMarkers.d.ts +23 -0
  14. package/dist/core/chart/exporter/SVGExporter.d.ts +7 -2
  15. package/dist/core/chart/heikinAshi.d.ts +10 -0
  16. package/dist/core/chart/series/types.d.ts +2 -2
  17. package/dist/core/chart/types.d.ts +9 -0
  18. package/dist/core/indicator/addIndicator.d.ts +36 -0
  19. package/dist/core/indicator/index.d.ts +2 -0
  20. package/dist/core/indicator/indicatorPresets.d.ts +37 -0
  21. package/dist/core/render/pixelSnap.d.ts +8 -0
  22. package/dist/core/series/Series.d.ts +3 -0
  23. package/dist/core/stacked/index.d.ts +3 -1
  24. package/dist/core/stacked/paneResize.d.ts +15 -18
  25. package/dist/core/stacked/stackExport.d.ts +18 -0
  26. package/dist/core/stacked/types.d.ts +42 -5
  27. package/dist/core/time/TimeScale.d.ts +31 -0
  28. package/dist/createStackedChart-BPooTQ9z.js +1164 -0
  29. package/dist/createStackedChart-BPooTQ9z.js.map +1 -0
  30. package/dist/gpu/adapter/gpuRenderer.d.ts +21 -0
  31. package/dist/gpu/backends/webgpu/WebGPUBackend.d.ts +2 -1
  32. package/dist/gpuRenderer-BpaMYz-k.js +1848 -0
  33. package/dist/gpuRenderer-BpaMYz-k.js.map +1 -0
  34. package/dist/index-CUGS98p4.js +277 -0
  35. package/dist/index-CUGS98p4.js.map +1 -0
  36. package/dist/index-D7dTq6VB.js +503 -0
  37. package/dist/index-D7dTq6VB.js.map +1 -0
  38. package/dist/{index-Ce2JgkH_.js → index-DoYxf1cV.js} +86 -43
  39. package/dist/{index-Ce2JgkH_.js.map → index-DoYxf1cV.js.map} +1 -1
  40. package/dist/index.core-BtGFYMOu.js +167 -0
  41. package/dist/index.core-BtGFYMOu.js.map +1 -0
  42. package/dist/index.d.ts +12 -4
  43. package/dist/indicators--eJGmVox.js +302 -0
  44. package/dist/indicators--eJGmVox.js.map +1 -0
  45. package/dist/math-Ddm2EZjj.js +85 -0
  46. package/dist/math-Ddm2EZjj.js.map +1 -0
  47. package/dist/plugins/analysis.js +543 -818
  48. package/dist/plugins/analysis.js.map +1 -1
  49. package/dist/plugins/anomaly-detection.d.ts +1 -0
  50. package/dist/plugins/anomaly-detection.js +221 -0
  51. package/dist/plugins/anomaly-detection.js.map +1 -0
  52. package/dist/plugins/broken-axis.d.ts +3 -0
  53. package/dist/plugins/broken-axis.js +262 -0
  54. package/dist/plugins/broken-axis.js.map +1 -0
  55. package/dist/plugins/caching.d.ts +3 -0
  56. package/dist/plugins/caching.js +187 -0
  57. package/dist/plugins/caching.js.map +1 -0
  58. package/dist/plugins/data-transform.d.ts +3 -0
  59. package/dist/plugins/data-transform.js +146 -0
  60. package/dist/plugins/data-transform.js.map +1 -0
  61. package/dist/plugins/debug.js +12 -11
  62. package/dist/plugins/debug.js.map +1 -1
  63. package/dist/plugins/drawing-tools/index.d.ts +16 -0
  64. package/dist/plugins/forecasting.d.ts +1 -0
  65. package/dist/plugins/forecasting.js +236 -0
  66. package/dist/plugins/forecasting.js.map +1 -0
  67. package/dist/plugins/gpu.js +202 -1895
  68. package/dist/plugins/gpu.js.map +1 -1
  69. package/dist/plugins/index.d.ts +2 -0
  70. package/dist/plugins/keyboard/index.d.ts +1 -7
  71. package/dist/plugins/keyboard.js +1 -1
  72. package/dist/plugins/latex.d.ts +1 -0
  73. package/dist/plugins/latex.js +454 -0
  74. package/dist/plugins/latex.js.map +1 -0
  75. package/dist/plugins/lazy-load/types.d.ts +7 -0
  76. package/dist/plugins/lazy-load.d.ts +3 -0
  77. package/dist/plugins/lazy-load.js +212 -0
  78. package/dist/plugins/lazy-load.js.map +1 -0
  79. package/dist/plugins/ml-integration.d.ts +3 -0
  80. package/dist/plugins/ml-integration.js +355 -0
  81. package/dist/plugins/ml-integration.js.map +1 -0
  82. package/dist/plugins/offscreen.d.ts +3 -0
  83. package/dist/plugins/offscreen.js +169 -0
  84. package/dist/plugins/offscreen.js.map +1 -0
  85. package/dist/plugins/pattern-recognition.d.ts +3 -0
  86. package/dist/plugins/pattern-recognition.js +690 -0
  87. package/dist/plugins/pattern-recognition.js.map +1 -0
  88. package/dist/plugins/radar.d.ts +3 -0
  89. package/dist/plugins/radar.js +103 -0
  90. package/dist/plugins/radar.js.map +1 -0
  91. package/dist/plugins/regression.d.ts +3 -0
  92. package/dist/plugins/regression.js +634 -0
  93. package/dist/plugins/regression.js.map +1 -0
  94. package/dist/plugins/replay/index.d.ts +19 -0
  95. package/dist/plugins/roi.d.ts +1 -0
  96. package/dist/plugins/roi.js +223 -0
  97. package/dist/plugins/roi.js.map +1 -0
  98. package/dist/plugins/snapshot/types.d.ts +1 -1
  99. package/dist/plugins/snapshot.d.ts +3 -0
  100. package/dist/plugins/snapshot.js +90 -0
  101. package/dist/plugins/snapshot.js.map +1 -0
  102. package/dist/plugins/sync/index.d.ts +2 -1
  103. package/dist/plugins/sync.js +13 -269
  104. package/dist/plugins/sync.js.map +1 -1
  105. package/dist/plugins/video-recorder.d.ts +3 -0
  106. package/dist/plugins/video-recorder.js +104 -0
  107. package/dist/plugins/video-recorder.js.map +1 -0
  108. package/dist/plugins/virtualization/types.d.ts +12 -0
  109. package/dist/plugins/virtualization.d.ts +3 -0
  110. package/dist/plugins/virtualization.js +6 -0
  111. package/dist/plugins/virtualization.js.map +1 -0
  112. package/dist/pool-15HMCNv8.js +88 -0
  113. package/dist/pool-15HMCNv8.js.map +1 -0
  114. package/dist/react.d.ts +1 -0
  115. package/dist/react.js +31 -0
  116. package/dist/react.js.map +1 -0
  117. package/dist/renderer/CandlestickRenderer.d.ts +1 -1
  118. package/dist/renderer/ChartSeriesRenderer.d.ts +6 -0
  119. package/dist/renderer/GpuChartRenderer.d.ts +23 -0
  120. package/dist/renderer/index.d.ts +3 -0
  121. package/dist/renderer/spike/WebGLGridSpike.d.ts +40 -0
  122. package/dist/testing/baselines/v1.15.0.json.d.ts +51 -0
  123. package/dist/testing/gridSpikeBenchmark.d.ts +49 -0
  124. package/dist/testing/index.d.ts +5 -0
  125. package/dist/testing/rendererBenchmark.d.ts +13 -0
  126. package/dist/testing/stage1BrowserBench.d.ts +42 -0
  127. package/dist/types.d.ts +21 -1
  128. package/dist/utils-BK5UUXxj.js +172 -0
  129. package/dist/utils-BK5UUXxj.js.map +1 -0
  130. package/dist/velo-plot.full.js +1382 -5932
  131. package/dist/velo-plot.full.js.map +1 -1
  132. package/dist/velo-plot.js +26 -25
  133. package/dist/velo-plot.js.map +1 -1
  134. package/dist/workers/downsample.d.ts +38 -0
  135. package/dist/workers/downsampleAsync.d.ts +6 -0
  136. package/dist/workers/indicator.worker.d.ts +32 -0
  137. package/dist/workers/indicatorsAsync.d.ts +26 -0
  138. package/dist/workers/pool.d.ts +36 -0
  139. package/package.json +19 -2
  140. package/dist/core/OverlayRenderer.test.d.ts +0 -1
  141. package/dist/core/chart/ChartScaling.test.d.ts +0 -1
  142. package/dist/core/chart/NavigationUtils.test.d.ts +0 -1
  143. package/dist/core/format/axisFormat.test.d.ts +0 -1
  144. package/dist/core/indicator/buildIndicatorSeries.test.d.ts +0 -1
  145. package/dist/core/series/SeriesBounds.test.d.ts +0 -1
  146. package/dist/core/stacked/createStackedChart.test.d.ts +0 -1
  147. package/dist/core/stacked/paneAxis.test.d.ts +0 -1
  148. package/dist/core/stacked/paneResize.test.d.ts +0 -1
  149. package/dist/core/sync/index.test.d.ts +0 -1
  150. package/dist/index.core-xiNcuFfJ.js.map +0 -1
  151. package/dist/plugins/tools/tooltip/format.test.d.ts +0 -1
  152. package/dist/utils-Dbro9-qM.js +0 -254
  153. package/dist/utils-Dbro9-qM.js.map +0 -1
@@ -0,0 +1,2 @@
1
+ (function(){"use strict";function I(s,n,t){const e=s.length;if(t>=e||t<=2)return{x:new Float32Array(s),y:new Float32Array(n),indices:new Uint32Array(Array.from({length:e},(o,p)=>p))};const u=new Float32Array(t),l=new Float32Array(t),i=new Uint32Array(t);u[0]=s[0],l[0]=n[0],i[0]=0;const h=(e-2)/(t-2);let r=0,c=1;for(let o=0;o<t-2;o++){const p=Math.floor((o+1)*h)+1,y=Math.floor((o+2)*h)+1,w=Math.min(y,e-1),f=Math.min(Math.floor((o+3)*h)+1,e);let a=0,g=0,b=0;for(let d=w;d<f;d++)a+=s[d],g+=n[d],b++;b>0&&(a/=b,g/=b);let F=-1,m=p;const A=s[r],M=n[r];for(let d=p;d<y&&d<e;d++){const x=Math.abs((A-a)*(n[d]-M)-(A-s[d])*(g-M));x>F&&(F=x,m=d)}u[c]=s[m],l[c]=n[m],i[c]=m,r=m,c++}return u[t-1]=s[e-1],l[t-1]=n[e-1],i[t-1]=e-1,{x:u,y:l,indices:i}}function k(s,n,t){const e=s.length;if(t>=e/2)return{x:new Float32Array(s),y:new Float32Array(n),indices:new Uint32Array(Array.from({length:e},(r,c)=>c))};const u=e/t,l=[],i=[],h=[];for(let r=0;r<t;r++){const c=Math.floor(r*u),o=Math.floor((r+1)*u);let p=1/0,y=-1/0,w=c,f=c;for(let a=c;a<o&&a<e;a++)n[a]<p&&(p=n[a],w=a),n[a]>y&&(y=n[a],f=a);w<=f?(l.push(s[w],s[f]),i.push(n[w],n[f]),h.push(w,f)):(l.push(s[f],s[w]),i.push(n[f],n[w]),h.push(f,w))}return{x:new Float32Array(l),y:new Float32Array(i),indices:new Uint32Array(h)}}function S(s,n,t,e,u,l){const i=s.length;if(l>=i||l<=1||i===0)return{x:new Float32Array(s),open:new Float32Array(n),high:new Float32Array(t),low:new Float32Array(e),close:new Float32Array(u),indices:new Uint32Array(Array.from({length:i},(f,a)=>a))};const h=i/l,r=[],c=[],o=[],p=[],y=[],w=[];for(let f=0;f<l;f++){const a=Math.floor(f*h),g=Math.min(i,Math.floor((f+1)*h));if(a>=g)continue;let b=-1/0,F=1/0,m=a;for(let A=a;A<g;A++)t[A]>b&&(b=t[A]),e[A]<F&&(F=e[A]),m=A;c.push(n[a]),o.push(b),p.push(F),y.push(u[m]),r.push(s[m]),w.push(m)}return{x:new Float32Array(r),open:new Float32Array(c),high:new Float32Array(o),low:new Float32Array(p),close:new Float32Array(y),indices:new Uint32Array(w)}}self.onmessage=function(s){const n=s.data;try{if(n.type==="downsample"){const t=performance.now(),{x:e,y:u,targetPoints:l,algorithm:i="lttb",id:h}=n;let r;if(i==="minmax"){const p=Math.ceil(l/2);r=k(e,u,p)}else r=I(e,u,l);const c=performance.now()-t,o={type:"downsample-result",id:h,x:r.x,y:r.y,indices:r.indices,originalLength:e.length,duration:c};self.postMessage(o,[r.x.buffer,r.y.buffer,r.indices.buffer])}else if(n.type==="ohlc-downsample"){const t=performance.now(),{x:e,open:u,high:l,low:i,close:h,targetBars:r,id:c}=n,o=S(e,u,l,i,h,r),p=performance.now()-t,y={type:"ohlc-downsample-result",id:c,x:o.x,open:o.open,high:o.high,low:o.low,close:o.close,indices:o.indices,originalLength:e.length,duration:p};self.postMessage(y,[o.x.buffer,o.open.buffer,o.high.buffer,o.low.buffer,o.close.buffer,o.indices.buffer])}}catch(t){const e={type:"error",id:n.id,error:t instanceof Error?t.message:String(t)};self.postMessage(e)}}})();
2
+ //# sourceMappingURL=downsample.worker-C70QJ04y.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"downsample.worker-C70QJ04y.js","sources":["../src/workers/downsample.ts","../src/workers/downsample.worker.ts"],"sourcesContent":["/**\n * LTTB (Largest-Triangle-Three-Buckets) Downsampling Algorithm\n *\n * This algorithm downsamples time-series data while preserving visual features.\n * It's much better than naive sampling for preserving peaks and valleys.\n *\n * Reference: https://skemman.is/bitstream/1946/15343/3/SS_MSthesis.pdf\n */\n\nexport interface DownsampleResult {\n x: Float32Array;\n y: Float32Array;\n /** Original indices of selected points */\n indices: Uint32Array;\n}\n\n/**\n * Downsample data using LTTB algorithm\n *\n * @param x - X values (e.g., potential)\n * @param y - Y values (e.g., current)\n * @param targetPoints - Number of output points\n * @returns Downsampled data\n */\nexport function lttbDownsample(\n x: Float32Array | Float64Array,\n y: Float32Array | Float64Array,\n targetPoints: number\n): DownsampleResult {\n const length = x.length;\n\n // No need to downsample\n if (targetPoints >= length || targetPoints <= 2) {\n return {\n x: new Float32Array(x),\n y: new Float32Array(y),\n indices: new Uint32Array(Array.from({ length }, (_, i) => i)),\n };\n }\n\n const outX = new Float32Array(targetPoints);\n const outY = new Float32Array(targetPoints);\n const outIndices = new Uint32Array(targetPoints);\n\n // Always include first point\n outX[0] = x[0];\n outY[0] = y[0];\n outIndices[0] = 0;\n\n // Bucket size\n const bucketSize = (length - 2) / (targetPoints - 2);\n\n let a = 0; // Previous selected point index\n let outIdx = 1;\n\n for (let i = 0; i < targetPoints - 2; i++) {\n // Calculate bucket boundaries\n const bucketStart = Math.floor((i + 1) * bucketSize) + 1;\n const bucketEnd = Math.floor((i + 2) * bucketSize) + 1;\n\n // Calculate average point of next bucket\n const nextBucketStart = Math.min(bucketEnd, length - 1);\n const nextBucketEnd = Math.min(\n Math.floor((i + 3) * bucketSize) + 1,\n length\n );\n\n let avgX = 0;\n let avgY = 0;\n let avgCount = 0;\n\n for (let j = nextBucketStart; j < nextBucketEnd; j++) {\n avgX += x[j];\n avgY += y[j];\n avgCount++;\n }\n\n if (avgCount > 0) {\n avgX /= avgCount;\n avgY /= avgCount;\n }\n\n // Find point in current bucket with largest triangle area\n let maxArea = -1;\n let maxIndex = bucketStart;\n\n const aX = x[a];\n const aY = y[a];\n\n for (let j = bucketStart; j < bucketEnd && j < length; j++) {\n // Calculate triangle area (simplified: |x1(y2-y3) + x2(y3-y1) + x3(y1-y2)| / 2)\n const area = Math.abs(\n (aX - avgX) * (y[j] - aY) - (aX - x[j]) * (avgY - aY)\n );\n\n if (area > maxArea) {\n maxArea = area;\n maxIndex = j;\n }\n }\n\n // Store selected point\n outX[outIdx] = x[maxIndex];\n outY[outIdx] = y[maxIndex];\n outIndices[outIdx] = maxIndex;\n\n a = maxIndex;\n outIdx++;\n }\n\n // Always include last point\n outX[targetPoints - 1] = x[length - 1];\n outY[targetPoints - 1] = y[length - 1];\n outIndices[targetPoints - 1] = length - 1;\n\n return { x: outX, y: outY, indices: outIndices };\n}\n\n/**\n * Min-Max per bucket downsampling\n *\n * Simpler alternative to LTTB that preserves extremes in each bucket.\n * Uses 2 points per bucket (min and max), so output is ~2x target.\n */\nexport function minMaxDownsample(\n x: Float32Array | Float64Array,\n y: Float32Array | Float64Array,\n bucketCount: number\n): DownsampleResult {\n const length = x.length;\n\n if (bucketCount >= length / 2) {\n return {\n x: new Float32Array(x),\n y: new Float32Array(y),\n indices: new Uint32Array(Array.from({ length }, (_, i) => i)),\n };\n }\n\n const bucketSize = length / bucketCount;\n const outX: number[] = [];\n const outY: number[] = [];\n const outIndices: number[] = [];\n\n for (let b = 0; b < bucketCount; b++) {\n const start = Math.floor(b * bucketSize);\n const end = Math.floor((b + 1) * bucketSize);\n\n let minY = Infinity;\n let maxY = -Infinity;\n let minIdx = start;\n let maxIdx = start;\n\n for (let i = start; i < end && i < length; i++) {\n if (y[i] < minY) {\n minY = y[i];\n minIdx = i;\n }\n if (y[i] > maxY) {\n maxY = y[i];\n maxIdx = i;\n }\n }\n\n // Add points in order (min first if it comes before max)\n if (minIdx <= maxIdx) {\n outX.push(x[minIdx], x[maxIdx]);\n outY.push(y[minIdx], y[maxIdx]);\n outIndices.push(minIdx, maxIdx);\n } else {\n outX.push(x[maxIdx], x[minIdx]);\n outY.push(y[maxIdx], y[minIdx]);\n outIndices.push(maxIdx, minIdx);\n }\n }\n\n return {\n x: new Float32Array(outX),\n y: new Float32Array(outY),\n indices: new Uint32Array(outIndices),\n };\n}\n\n/**\n * Calculate optimal target points based on canvas width\n */\nexport function calculateTargetPoints(\n dataLength: number,\n canvasWidth: number,\n pointsPerPixel = 2\n): number {\n // Never draw more than pointsPerPixel per pixel\n const maxPoints = canvasWidth * pointsPerPixel;\n return Math.min(dataLength, maxPoints);\n}\n\nexport interface OhlcDownsampleResult {\n x: Float32Array;\n open: Float32Array;\n high: Float32Array;\n low: Float32Array;\n close: Float32Array;\n indices: Uint32Array;\n}\n\n/**\n * Aggregate OHLC bars into fewer buckets while preserving extremes.\n * Each bucket: open=first open, close=last close, high=max high, low=min low, x=last x.\n */\nexport function ohlcMinMaxDownsample(\n x: Float32Array | Float64Array,\n open: Float32Array | Float64Array,\n high: Float32Array | Float64Array,\n low: Float32Array | Float64Array,\n close: Float32Array | Float64Array,\n targetBars: number,\n): OhlcDownsampleResult {\n const length = x.length;\n if (targetBars >= length || targetBars <= 1 || length === 0) {\n return {\n x: new Float32Array(x),\n open: new Float32Array(open),\n high: new Float32Array(high),\n low: new Float32Array(low),\n close: new Float32Array(close),\n indices: new Uint32Array(Array.from({ length }, (_, i) => i)),\n };\n }\n\n const bucketSize = length / targetBars;\n const outX: number[] = [];\n const outOpen: number[] = [];\n const outHigh: number[] = [];\n const outLow: number[] = [];\n const outClose: number[] = [];\n const outIndices: number[] = [];\n\n for (let b = 0; b < targetBars; b++) {\n const start = Math.floor(b * bucketSize);\n const end = Math.min(length, Math.floor((b + 1) * bucketSize));\n if (start >= end) continue;\n\n let hi = -Infinity;\n let lo = Infinity;\n let lastIdx = start;\n\n for (let i = start; i < end; i++) {\n if (high[i] > hi) hi = high[i];\n if (low[i] < lo) lo = low[i];\n lastIdx = i;\n }\n\n outOpen.push(open[start]);\n outHigh.push(hi);\n outLow.push(lo);\n outClose.push(close[lastIdx]);\n outX.push(x[lastIdx]);\n outIndices.push(lastIdx);\n }\n\n return {\n x: new Float32Array(outX),\n open: new Float32Array(outOpen),\n high: new Float32Array(outHigh),\n low: new Float32Array(outLow),\n close: new Float32Array(outClose),\n indices: new Uint32Array(outIndices),\n };\n}\n\n/** Binary search lower bound: first index where x[i] >= value */\nexport function lowerBoundX(\n x: Float32Array | Float64Array,\n value: number,\n): number {\n let lo = 0;\n let hi = x.length;\n while (lo < hi) {\n const mid = (lo + hi) >>> 1;\n if (x[mid] < value) lo = mid + 1;\n else hi = mid;\n }\n return lo;\n}\n\n/** Binary search upper bound: first index where x[i] > value */\nexport function upperBoundX(\n x: Float32Array | Float64Array,\n value: number,\n): number {\n let lo = 0;\n let hi = x.length;\n while (lo < hi) {\n const mid = (lo + hi) >>> 1;\n if (x[mid] <= value) lo = mid + 1;\n else hi = mid;\n }\n return lo;\n}\n\nexport interface ViewportSlice {\n x: Float32Array;\n y?: Float32Array;\n open?: Float32Array;\n high?: Float32Array;\n low?: Float32Array;\n close?: Float32Array;\n start: number;\n end: number;\n}\n\n/**\n * Slice sorted x-series to visible range plus buffer (fraction of visible width).\n */\nexport function sliceSeriesToViewport(\n source: {\n x: Float32Array | Float64Array;\n y?: Float32Array | Float64Array;\n open?: Float32Array | Float64Array;\n high?: Float32Array | Float64Array;\n low?: Float32Array | Float64Array;\n close?: Float32Array | Float64Array;\n },\n xMin: number,\n xMax: number,\n bufferRatio = 0.5,\n): ViewportSlice {\n const length = source.x.length;\n if (length === 0) {\n return { x: new Float32Array(0), start: 0, end: 0 };\n }\n\n const range = Math.max(xMax - xMin, 1e-12);\n const paddedMin = xMin - range * bufferRatio;\n const paddedMax = xMax + range * bufferRatio;\n\n let start = lowerBoundX(source.x, paddedMin);\n let end = upperBoundX(source.x, paddedMax);\n start = Math.max(0, start);\n end = Math.min(length, Math.max(end, start + 1));\n\n const slice = <T extends Float32Array | Float64Array>(arr: T | undefined): Float32Array | undefined => {\n if (!arr) return undefined;\n return new Float32Array(arr.subarray(start, end));\n };\n\n return {\n x: new Float32Array(source.x.subarray(start, end)),\n y: slice(source.y),\n open: slice(source.open),\n high: slice(source.high),\n low: slice(source.low),\n close: slice(source.close),\n start,\n end,\n };\n}\n","/**\n * Downsampling Web Worker\n *\n * Performs CPU-intensive downsampling off the main thread.\n *\n * Usage:\n * ```typescript\n * const worker = new Worker(new URL('./downsample.worker.ts', import.meta.url));\n *\n * worker.postMessage({\n * type: 'downsample',\n * x: xArray,\n * y: yArray,\n * targetPoints: 1000,\n * algorithm: 'lttb'\n * });\n *\n * worker.onmessage = (e) => {\n * const { x, y, indices } = e.data;\n * chart.setDownsampledData(x, y);\n * };\n * ```\n */\n\nimport {\n lttbDownsample,\n minMaxDownsample,\n ohlcMinMaxDownsample,\n type DownsampleResult,\n} from './downsample';\n\n// ============================================\n// Message Types\n// ============================================\n\ninterface DownsampleRequestMessage {\n type: 'downsample';\n id?: string;\n x: Float32Array | Float64Array;\n y: Float32Array | Float64Array;\n targetPoints: number;\n algorithm?: 'lttb' | 'minmax';\n}\n\ninterface DownsampleResponseMessage {\n type: 'downsample-result';\n id?: string;\n x: Float32Array;\n y: Float32Array;\n indices: Uint32Array;\n originalLength: number;\n duration: number;\n}\n\ninterface ErrorMessage {\n type: 'error';\n id?: string;\n error: string;\n}\n\ninterface OhlcDownsampleRequestMessage {\n type: 'ohlc-downsample';\n id?: string;\n x: Float32Array | Float64Array;\n open: Float32Array | Float64Array;\n high: Float32Array | Float64Array;\n low: Float32Array | Float64Array;\n close: Float32Array | Float64Array;\n targetBars: number;\n}\n\ninterface OhlcDownsampleResponseMessage {\n type: 'ohlc-downsample-result';\n id?: string;\n x: Float32Array;\n open: Float32Array;\n high: Float32Array;\n low: Float32Array;\n close: Float32Array;\n indices: Uint32Array;\n originalLength: number;\n duration: number;\n}\n\ntype WorkerMessage = DownsampleRequestMessage | OhlcDownsampleRequestMessage;\n\n// ============================================\n// Worker Logic\n// ============================================\n\nself.onmessage = function (e: MessageEvent<WorkerMessage>) {\n const message = e.data;\n\n try {\n if (message.type === 'downsample') {\n const start = performance.now();\n\n const { x, y, targetPoints, algorithm = 'lttb', id } = message;\n\n let result: DownsampleResult;\n\n if (algorithm === 'minmax') {\n // Min-max uses bucket count, not target points\n const bucketCount = Math.ceil(targetPoints / 2);\n result = minMaxDownsample(x, y, bucketCount);\n } else {\n result = lttbDownsample(x, y, targetPoints);\n }\n\n const duration = performance.now() - start;\n\n const response: DownsampleResponseMessage = {\n type: 'downsample-result',\n id,\n x: result.x,\n y: result.y,\n indices: result.indices,\n originalLength: x.length,\n duration,\n };\n\n // Transfer ownership of buffers for zero-copy\n (self.postMessage as (message: unknown, transfer: Transferable[]) => void)(\n response,\n [result.x.buffer, result.y.buffer, result.indices.buffer]\n );\n } else if (message.type === 'ohlc-downsample') {\n const start = performance.now();\n const { x, open, high, low, close, targetBars, id } = message;\n\n const result = ohlcMinMaxDownsample(x, open, high, low, close, targetBars);\n const duration = performance.now() - start;\n\n const response: OhlcDownsampleResponseMessage = {\n type: 'ohlc-downsample-result',\n id,\n x: result.x,\n open: result.open,\n high: result.high,\n low: result.low,\n close: result.close,\n indices: result.indices,\n originalLength: x.length,\n duration,\n };\n\n (self.postMessage as (message: unknown, transfer: Transferable[]) => void)(\n response,\n [\n result.x.buffer,\n result.open.buffer,\n result.high.buffer,\n result.low.buffer,\n result.close.buffer,\n result.indices.buffer,\n ]\n );\n }\n } catch (error) {\n const errorResponse: ErrorMessage = {\n type: 'error',\n id: (message as DownsampleRequestMessage).id,\n error: error instanceof Error ? error.message : String(error),\n };\n self.postMessage(errorResponse);\n }\n};\n\n// Export types for TypeScript\nexport type { DownsampleRequestMessage, DownsampleResponseMessage, ErrorMessage };\n"],"names":["lttbDownsample","x","y","targetPoints","length","_","i","outX","outY","outIndices","bucketSize","a","outIdx","bucketStart","bucketEnd","nextBucketStart","nextBucketEnd","avgX","avgY","avgCount","j","maxArea","maxIndex","aX","aY","area","minMaxDownsample","bucketCount","b","start","end","minY","maxY","minIdx","maxIdx","ohlcMinMaxDownsample","open","high","low","close","targetBars","outOpen","outHigh","outLow","outClose","hi","lo","lastIdx","e","message","algorithm","id","result","duration","response","error","errorResponse"],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ (function(){"use strict";function g(o,t){const a=o instanceof Float32Array||o instanceof Float64Array?o:Float32Array.from(o),r=new Float32Array(a.length);if(t<1||t>a.length)return r.fill(NaN),r;for(let n=0;n<t-1;n++)r[n]=NaN;let e=0;for(let n=0;n<t;n++)e+=a[n];r[t-1]=e/t;for(let n=t;n<a.length;n++)e=e-a[n-t]+a[n],r[n]=e/t;return r}function u(o,t){const a=o instanceof Float32Array||o instanceof Float64Array?o:Float32Array.from(o),r=new Float32Array(a.length);if(t<1||t>a.length)return r.fill(NaN),r;const e=2/(t+1);for(let s=0;s<t-1;s++)r[s]=NaN;let n=0;for(let s=0;s<t;s++)n+=a[s];r[t-1]=n/t;for(let s=t;s<a.length;s++)r[s]=(a[s]-r[s-1])*e+r[s-1];return r}function h(o,t=14){const a=o instanceof Float32Array||o instanceof Float64Array?o:Float32Array.from(o),r=new Float32Array(a.length);if(t<1||a.length<t+1)return r.fill(NaN),r;for(let s=0;s<t;s++)r[s]=NaN;let e=0,n=0;for(let s=1;s<=t;s++){const l=a[s]-a[s-1];l>0?e+=l:n+=Math.abs(l)}if(e/=t,n/=t,n===0)r[t]=100;else{const s=e/n;r[t]=100-100/(1+s)}for(let s=t+1;s<a.length;s++){const l=a[s]-a[s-1];let f=0,c=0;if(l>0?f=l:c=Math.abs(l),e=(e*(t-1)+f)/t,n=(n*(t-1)+c)/t,n===0)r[s]=100;else{const i=e/n;r[s]=100-100/(1+i)}}return r}function y(o,t=12,a=26,r=9){const e=o instanceof Float32Array||o instanceof Float64Array?o:Float32Array.from(o),n=u(e,t),s=u(e,a),l=new Float32Array(e.length);for(let i=0;i<e.length;i++)l[i]=n[i]-s[i];const f=u(l,r),c=new Float32Array(e.length);for(let i=0;i<e.length;i++)c[i]=l[i]-f[i];return{values:l,signal:f,histogram:c}}function w(o,t=20,a=2){const r=o instanceof Float32Array||o instanceof Float64Array?o:Float32Array.from(o),e=g(r,t),n=new Float32Array(r.length),s=new Float32Array(r.length);for(let l=0;l<r.length;l++){if(l<t-1){n[l]=NaN,s[l]=NaN;continue}let f=0;for(let i=l-t+1;i<=l;i++){const m=r[i]-e[l];f+=m*m}const c=Math.sqrt(f/t);n[l]=e[l]+a*c,s[l]=e[l]-a*c}return{values:e,upper:n,lower:s}}self.onmessage=function(o){const t=o.data;try{const a=performance.now();let r;switch(t.indicator){case"rsi":{const e=h(t.data,t.period??14);r={id:t.id,type:"indicator-result",indicator:"rsi",values:e,duration:performance.now()-a},self.postMessage(r,[e.buffer]);return}case"sma":{const e=g(t.data,t.period??14);r={id:t.id,type:"indicator-result",indicator:"sma",values:e,duration:performance.now()-a},self.postMessage(r,[e.buffer]);return}case"ema":{const e=u(t.data,t.period??14);r={id:t.id,type:"indicator-result",indicator:"ema",values:e,duration:performance.now()-a},self.postMessage(r,[e.buffer]);return}case"macd":{const e=y(t.data,t.fastPeriod??12,t.slowPeriod??26,t.signalPeriod??9);r={id:t.id,type:"indicator-result",indicator:"macd",values:e.values,signal:e.signal,histogram:e.histogram,duration:performance.now()-a};const n=[e.values.buffer];e.signal&&n.push(e.signal.buffer),e.histogram&&n.push(e.histogram.buffer),self.postMessage(r,n);return}case"bollingerBands":{const e=w(t.data,t.period??20,t.stdDev??2);r={id:t.id,type:"indicator-result",indicator:"bollingerBands",values:e.values,upper:e.upper,lower:e.lower,duration:performance.now()-a};const n=[e.values.buffer];e.upper&&n.push(e.upper.buffer),e.lower&&n.push(e.lower.buffer),self.postMessage(r,n);return}default:{const e={id:t.id,type:"error",error:`Unknown indicator: ${t.indicator}`};self.postMessage(e)}}}catch(a){const r={id:t.id,type:"error",error:a instanceof Error?a.message:String(a)};self.postMessage(r)}}})();
2
+ //# sourceMappingURL=indicator.worker-bv0zC4EX.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"indicator.worker-bv0zC4EX.js","sources":["../src/plugins/analysis/indicators.ts","../src/workers/indicator.worker.ts"],"sourcesContent":["/**\n * Sci Plot - Financial/Technical Indicators Module\n * \n * Provides common financial and technical analysis indicators:\n * - Moving Averages (SMA, EMA, WMA)\n * - Momentum Indicators (RSI, MACD, Stochastic)\n * - Volatility (Bollinger Bands, ATR)\n * - Volume (VWAP, OBV)\n * - Trend (ADX, Aroon)\n * \n * @module indicators\n */\n\n// ============================================\n// Types\n// ============================================\n\nexport interface IndicatorResult {\n /** Indicator values (NaN for insufficient data) */\n values: Float32Array;\n /** Additional line (e.g., signal line for MACD) */\n signal?: Float32Array;\n /** Upper band (e.g., Bollinger upper) */\n upper?: Float32Array;\n /** Lower band (e.g., Bollinger lower) */\n lower?: Float32Array;\n /** Histogram (e.g., MACD histogram) */\n histogram?: Float32Array;\n}\n\nexport interface OHLCData {\n open: Float32Array | Float64Array;\n high: Float32Array | Float64Array;\n low: Float32Array | Float64Array;\n close: Float32Array | Float64Array;\n volume?: Float32Array | Float64Array;\n}\n\n// ============================================\n// Moving Averages\n// ============================================\n\n/**\n * Simple Moving Average (SMA)\n * @param data Input data array\n * @param period Number of periods\n */\nexport function sma(data: Float32Array | Float64Array | number[], period: number): Float32Array {\n const input = data instanceof Float32Array || data instanceof Float64Array ? data : Float32Array.from(data);\n const result = new Float32Array(input.length);\n \n if (period < 1 || period > input.length) {\n result.fill(NaN);\n return result;\n }\n\n // Fill initial values with NaN\n for (let i = 0; i < period - 1; i++) {\n result[i] = NaN;\n }\n\n // Calculate first SMA\n let sum = 0;\n for (let i = 0; i < period; i++) {\n sum += input[i];\n }\n result[period - 1] = sum / period;\n\n // Calculate remaining SMAs using sliding window\n for (let i = period; i < input.length; i++) {\n sum = sum - input[i - period] + input[i];\n result[i] = sum / period;\n }\n\n return result;\n}\n\n/**\n * Exponential Moving Average (EMA)\n * @param data Input data array\n * @param period Number of periods\n */\nexport function ema(data: Float32Array | Float64Array | number[], period: number): Float32Array {\n const input = data instanceof Float32Array || data instanceof Float64Array ? data : Float32Array.from(data);\n const result = new Float32Array(input.length);\n \n if (period < 1 || period > input.length) {\n result.fill(NaN);\n return result;\n }\n\n const multiplier = 2 / (period + 1);\n\n // Fill initial values with NaN\n for (let i = 0; i < period - 1; i++) {\n result[i] = NaN;\n }\n\n // First EMA is SMA\n let sum = 0;\n for (let i = 0; i < period; i++) {\n sum += input[i];\n }\n result[period - 1] = sum / period;\n\n // Calculate remaining EMAs\n for (let i = period; i < input.length; i++) {\n result[i] = (input[i] - result[i - 1]) * multiplier + result[i - 1];\n }\n\n return result;\n}\n\n/**\n * Weighted Moving Average (WMA)\n * @param data Input data array\n * @param period Number of periods\n */\nexport function wma(data: Float32Array | Float64Array | number[], period: number): Float32Array {\n const input = data instanceof Float32Array || data instanceof Float64Array ? data : Float32Array.from(data);\n const result = new Float32Array(input.length);\n \n if (period < 1 || period > input.length) {\n result.fill(NaN);\n return result;\n }\n\n const weightSum = (period * (period + 1)) / 2;\n\n // Fill initial values with NaN\n for (let i = 0; i < period - 1; i++) {\n result[i] = NaN;\n }\n\n // Calculate WMAs\n for (let i = period - 1; i < input.length; i++) {\n let weightedSum = 0;\n for (let j = 0; j < period; j++) {\n weightedSum += input[i - period + 1 + j] * (j + 1);\n }\n result[i] = weightedSum / weightSum;\n }\n\n return result;\n}\n\n/**\n * Double Exponential Moving Average (DEMA)\n * @param data Input data array\n * @param period Number of periods\n */\nexport function dema(data: Float32Array | Float64Array | number[], period: number): Float32Array {\n const ema1 = ema(data, period);\n const ema2 = ema(ema1, period);\n const result = new Float32Array(data.length);\n\n for (let i = 0; i < data.length; i++) {\n result[i] = 2 * ema1[i] - ema2[i];\n }\n\n return result;\n}\n\n/**\n * Triple Exponential Moving Average (TEMA)\n * @param data Input data array\n * @param period Number of periods\n */\nexport function tema(data: Float32Array | Float64Array | number[], period: number): Float32Array {\n const ema1 = ema(data, period);\n const ema2 = ema(ema1, period);\n const ema3 = ema(ema2, period);\n const result = new Float32Array(data.length);\n\n for (let i = 0; i < data.length; i++) {\n result[i] = 3 * ema1[i] - 3 * ema2[i] + ema3[i];\n }\n\n return result;\n}\n\n// ============================================\n// Momentum Indicators\n// ============================================\n\n/**\n * Relative Strength Index (RSI)\n * @param data Close prices\n * @param period RSI period (default: 14)\n */\nexport function rsi(data: Float32Array | Float64Array | number[], period: number = 14): Float32Array {\n const input = data instanceof Float32Array || data instanceof Float64Array ? data : Float32Array.from(data);\n const result = new Float32Array(input.length);\n \n if (period < 1 || input.length < period + 1) {\n result.fill(NaN);\n return result;\n }\n\n // Fill initial values with NaN\n for (let i = 0; i < period; i++) {\n result[i] = NaN;\n }\n\n // Calculate initial average gain/loss\n let avgGain = 0;\n let avgLoss = 0;\n\n for (let i = 1; i <= period; i++) {\n const change = input[i] - input[i - 1];\n if (change > 0) {\n avgGain += change;\n } else {\n avgLoss += Math.abs(change);\n }\n }\n\n avgGain /= period;\n avgLoss /= period;\n\n // First RSI value\n if (avgLoss === 0) {\n result[period] = 100;\n } else {\n const rs = avgGain / avgLoss;\n result[period] = 100 - (100 / (1 + rs));\n }\n\n // Calculate remaining RSI values using smoothed averages\n for (let i = period + 1; i < input.length; i++) {\n const change = input[i] - input[i - 1];\n let gain = 0;\n let loss = 0;\n\n if (change > 0) {\n gain = change;\n } else {\n loss = Math.abs(change);\n }\n\n avgGain = (avgGain * (period - 1) + gain) / period;\n avgLoss = (avgLoss * (period - 1) + loss) / period;\n\n if (avgLoss === 0) {\n result[i] = 100;\n } else {\n const rs = avgGain / avgLoss;\n result[i] = 100 - (100 / (1 + rs));\n }\n }\n\n return result;\n}\n\n/**\n * Moving Average Convergence Divergence (MACD)\n * @param data Close prices\n * @param fastPeriod Fast EMA period (default: 12)\n * @param slowPeriod Slow EMA period (default: 26)\n * @param signalPeriod Signal line period (default: 9)\n */\nexport function macd(\n data: Float32Array | Float64Array | number[],\n fastPeriod: number = 12,\n slowPeriod: number = 26,\n signalPeriod: number = 9\n): IndicatorResult {\n const input = data instanceof Float32Array || data instanceof Float64Array ? data : Float32Array.from(data);\n \n const fastEma = ema(input, fastPeriod);\n const slowEma = ema(input, slowPeriod);\n \n // MACD Line = Fast EMA - Slow EMA\n const macdLine = new Float32Array(input.length);\n for (let i = 0; i < input.length; i++) {\n macdLine[i] = fastEma[i] - slowEma[i];\n }\n \n // Signal Line = EMA of MACD Line\n const signal = ema(macdLine, signalPeriod);\n \n // Histogram = MACD Line - Signal Line\n const histogram = new Float32Array(input.length);\n for (let i = 0; i < input.length; i++) {\n histogram[i] = macdLine[i] - signal[i];\n }\n\n return {\n values: macdLine,\n signal,\n histogram,\n };\n}\n\n/**\n * Stochastic Oscillator\n * @param ohlc OHLC data\n * @param kPeriod %K period (default: 14)\n * @param dPeriod %D smoothing period (default: 3)\n */\nexport function stochastic(\n ohlc: OHLCData,\n kPeriod: number = 14,\n dPeriod: number = 3\n): IndicatorResult {\n const { high, low, close } = ohlc;\n const length = close.length;\n const kValues = new Float32Array(length);\n \n // Calculate %K\n for (let i = 0; i < length; i++) {\n if (i < kPeriod - 1) {\n kValues[i] = NaN;\n continue;\n }\n \n let highest = -Infinity;\n let lowest = Infinity;\n \n for (let j = i - kPeriod + 1; j <= i; j++) {\n if (high[j] > highest) highest = high[j];\n if (low[j] < lowest) lowest = low[j];\n }\n \n const range = highest - lowest;\n if (range === 0) {\n kValues[i] = 50; // Neutral when no range\n } else {\n kValues[i] = ((close[i] - lowest) / range) * 100;\n }\n }\n \n // %D is SMA of %K\n const dValues = sma(kValues, dPeriod);\n\n return {\n values: kValues, // %K\n signal: dValues, // %D\n };\n}\n\n/**\n * Rate of Change (ROC)\n * @param data Close prices\n * @param period ROC period (default: 10)\n */\nexport function roc(data: Float32Array | Float64Array | number[], period: number = 10): Float32Array {\n const input = data instanceof Float32Array || data instanceof Float64Array ? data : Float32Array.from(data);\n const result = new Float32Array(input.length);\n \n for (let i = 0; i < period; i++) {\n result[i] = NaN;\n }\n \n for (let i = period; i < input.length; i++) {\n const pastValue = input[i - period];\n if (pastValue === 0) {\n result[i] = NaN;\n } else {\n result[i] = ((input[i] - pastValue) / pastValue) * 100;\n }\n }\n\n return result;\n}\n\n/**\n * Momentum\n * @param data Close prices\n * @param period Momentum period (default: 10)\n */\nexport function momentum(data: Float32Array | Float64Array | number[], period: number = 10): Float32Array {\n const input = data instanceof Float32Array || data instanceof Float64Array ? data : Float32Array.from(data);\n const result = new Float32Array(input.length);\n \n for (let i = 0; i < period; i++) {\n result[i] = NaN;\n }\n \n for (let i = period; i < input.length; i++) {\n result[i] = input[i] - input[i - period];\n }\n\n return result;\n}\n\n// ============================================\n// Volatility Indicators\n// ============================================\n\n/**\n * Bollinger Bands\n * @param data Close prices\n * @param period SMA period (default: 20)\n * @param stdDev Standard deviation multiplier (default: 2)\n */\nexport function bollingerBands(\n data: Float32Array | Float64Array | number[],\n period: number = 20,\n stdDev: number = 2\n): IndicatorResult {\n const input = data instanceof Float32Array || data instanceof Float64Array ? data : Float32Array.from(data);\n const middle = sma(input, period);\n const upper = new Float32Array(input.length);\n const lower = new Float32Array(input.length);\n\n for (let i = 0; i < input.length; i++) {\n if (i < period - 1) {\n upper[i] = NaN;\n lower[i] = NaN;\n continue;\n }\n\n // Calculate standard deviation\n let sumSquares = 0;\n for (let j = i - period + 1; j <= i; j++) {\n const diff = input[j] - middle[i];\n sumSquares += diff * diff;\n }\n const std = Math.sqrt(sumSquares / period);\n\n upper[i] = middle[i] + stdDev * std;\n lower[i] = middle[i] - stdDev * std;\n }\n\n return {\n values: middle,\n upper,\n lower,\n };\n}\n\n/**\n * Average True Range (ATR)\n * @param ohlc OHLC data\n * @param period ATR period (default: 14)\n */\nexport function atr(ohlc: OHLCData, period: number = 14): Float32Array {\n const { high, low, close } = ohlc;\n const length = close.length;\n const tr = new Float32Array(length);\n \n // True Range calculation\n tr[0] = high[0] - low[0];\n \n for (let i = 1; i < length; i++) {\n const hl = high[i] - low[i];\n const hc = Math.abs(high[i] - close[i - 1]);\n const lc = Math.abs(low[i] - close[i - 1]);\n tr[i] = Math.max(hl, hc, lc);\n }\n\n // ATR is smoothed average of True Range\n return ema(tr, period);\n}\n\n/**\n * Standard Deviation\n * @param data Input data\n * @param period Period for calculation (default: 20)\n */\nexport function standardDeviation(data: Float32Array | Float64Array | number[], period: number = 20): Float32Array {\n const input = data instanceof Float32Array || data instanceof Float64Array ? data : Float32Array.from(data);\n const result = new Float32Array(input.length);\n const avg = sma(input, period);\n\n for (let i = 0; i < input.length; i++) {\n if (i < period - 1) {\n result[i] = NaN;\n continue;\n }\n\n let sumSquares = 0;\n for (let j = i - period + 1; j <= i; j++) {\n const diff = input[j] - avg[i];\n sumSquares += diff * diff;\n }\n result[i] = Math.sqrt(sumSquares / period);\n }\n\n return result;\n}\n\n// ============================================\n// Volume Indicators\n// ============================================\n\n/**\n * Volume Weighted Average Price (VWAP)\n * @param ohlc OHLC data with volume\n */\nexport function vwap(ohlc: OHLCData): Float32Array {\n const { high, low, close, volume } = ohlc;\n \n if (!volume) {\n throw new Error('VWAP requires volume data');\n }\n\n const length = close.length;\n const result = new Float32Array(length);\n \n let cumulativeTPV = 0; // Cumulative Typical Price * Volume\n let cumulativeVolume = 0;\n\n for (let i = 0; i < length; i++) {\n const typicalPrice = (high[i] + low[i] + close[i]) / 3;\n cumulativeTPV += typicalPrice * volume[i];\n cumulativeVolume += volume[i];\n \n if (cumulativeVolume === 0) {\n result[i] = typicalPrice;\n } else {\n result[i] = cumulativeTPV / cumulativeVolume;\n }\n }\n\n return result;\n}\n\n/**\n * On-Balance Volume (OBV)\n * @param close Close prices\n * @param volume Volume data\n */\nexport function obv(\n close: Float32Array | Float64Array | number[],\n volume: Float32Array | Float64Array | number[]\n): Float32Array {\n const closeInput = close instanceof Float32Array || close instanceof Float64Array ? close : Float32Array.from(close);\n const volumeInput = volume instanceof Float32Array || volume instanceof Float64Array ? volume : Float32Array.from(volume);\n \n const result = new Float32Array(closeInput.length);\n result[0] = volumeInput[0];\n\n for (let i = 1; i < closeInput.length; i++) {\n if (closeInput[i] > closeInput[i - 1]) {\n result[i] = result[i - 1] + volumeInput[i];\n } else if (closeInput[i] < closeInput[i - 1]) {\n result[i] = result[i - 1] - volumeInput[i];\n } else {\n result[i] = result[i - 1];\n }\n }\n\n return result;\n}\n\n// ============================================\n// Trend Indicators\n// ============================================\n\n/**\n * Average Directional Index (ADX)\n * @param ohlc OHLC data\n * @param period ADX period (default: 14)\n */\nexport function adx(ohlc: OHLCData, period: number = 14): IndicatorResult {\n const { high, low, close } = ohlc;\n const length = close.length;\n \n const plusDM = new Float32Array(length);\n const minusDM = new Float32Array(length);\n const tr = new Float32Array(length);\n \n // Calculate +DM, -DM, TR\n tr[0] = high[0] - low[0];\n plusDM[0] = 0;\n minusDM[0] = 0;\n\n for (let i = 1; i < length; i++) {\n const upMove = high[i] - high[i - 1];\n const downMove = low[i - 1] - low[i];\n \n plusDM[i] = upMove > downMove && upMove > 0 ? upMove : 0;\n minusDM[i] = downMove > upMove && downMove > 0 ? downMove : 0;\n \n const hl = high[i] - low[i];\n const hc = Math.abs(high[i] - close[i - 1]);\n const lc = Math.abs(low[i] - close[i - 1]);\n tr[i] = Math.max(hl, hc, lc);\n }\n\n // Smooth with EMA\n const smoothedTR = ema(tr, period);\n const smoothedPlusDM = ema(plusDM, period);\n const smoothedMinusDM = ema(minusDM, period);\n\n // Calculate +DI and -DI\n const plusDI = new Float32Array(length);\n const minusDI = new Float32Array(length);\n const dx = new Float32Array(length);\n\n for (let i = 0; i < length; i++) {\n if (smoothedTR[i] === 0 || isNaN(smoothedTR[i])) {\n plusDI[i] = NaN;\n minusDI[i] = NaN;\n dx[i] = NaN;\n } else {\n plusDI[i] = (smoothedPlusDM[i] / smoothedTR[i]) * 100;\n minusDI[i] = (smoothedMinusDM[i] / smoothedTR[i]) * 100;\n \n const diSum = plusDI[i] + minusDI[i];\n dx[i] = diSum === 0 ? 0 : (Math.abs(plusDI[i] - minusDI[i]) / diSum) * 100;\n }\n }\n\n // ADX is smoothed DX\n const adxValues = ema(dx, period);\n\n return {\n values: adxValues,\n upper: plusDI, // +DI\n lower: minusDI, // -DI\n };\n}\n\n/**\n * Aroon Indicator\n * @param ohlc OHLC data\n * @param period Aroon period (default: 25)\n */\nexport function aroon(ohlc: OHLCData, period: number = 25): IndicatorResult {\n const { high, low } = ohlc;\n const length = high.length;\n \n const aroonUp = new Float32Array(length);\n const aroonDown = new Float32Array(length);\n\n for (let i = 0; i < length; i++) {\n if (i < period) {\n aroonUp[i] = NaN;\n aroonDown[i] = NaN;\n continue;\n }\n\n let highestIdx = i;\n let lowestIdx = i;\n let highest = -Infinity;\n let lowest = Infinity;\n\n for (let j = i - period; j <= i; j++) {\n if (high[j] > highest) {\n highest = high[j];\n highestIdx = j;\n }\n if (low[j] < lowest) {\n lowest = low[j];\n lowestIdx = j;\n }\n }\n\n aroonUp[i] = ((period - (i - highestIdx)) / period) * 100;\n aroonDown[i] = ((period - (i - lowestIdx)) / period) * 100;\n }\n\n // Aroon Oscillator = Aroon Up - Aroon Down\n const oscillator = new Float32Array(length);\n for (let i = 0; i < length; i++) {\n oscillator[i] = aroonUp[i] - aroonDown[i];\n }\n\n return {\n values: oscillator,\n upper: aroonUp,\n lower: aroonDown,\n };\n}\n\n// ============================================\n// Utility Functions\n// ============================================\n\n/**\n * Calculate percentage change\n */\nexport function percentChange(data: Float32Array | Float64Array | number[], period: number = 1): Float32Array {\n const input = data instanceof Float32Array || data instanceof Float64Array ? data : Float32Array.from(data);\n const result = new Float32Array(input.length);\n \n for (let i = 0; i < period; i++) {\n result[i] = NaN;\n }\n \n for (let i = period; i < input.length; i++) {\n const prev = input[i - period];\n if (prev === 0) {\n result[i] = NaN;\n } else {\n result[i] = ((input[i] - prev) / prev) * 100;\n }\n }\n\n return result;\n}\n\n/**\n * Calculate cumulative sum\n */\nexport function cumsum(data: Float32Array | Float64Array | number[]): Float32Array {\n const input = data instanceof Float32Array || data instanceof Float64Array ? data : Float32Array.from(data);\n const result = new Float32Array(input.length);\n \n result[0] = input[0];\n for (let i = 1; i < input.length; i++) {\n result[i] = result[i - 1] + input[i];\n }\n\n return result;\n}\n\n/**\n * Normalize data to 0-100 range\n */\nexport function normalize(data: Float32Array | Float64Array | number[]): Float32Array {\n const input = data instanceof Float32Array || data instanceof Float64Array ? data : Float32Array.from(data);\n const result = new Float32Array(input.length);\n \n let min = Infinity;\n let max = -Infinity;\n \n for (let i = 0; i < input.length; i++) {\n if (!isNaN(input[i])) {\n if (input[i] < min) min = input[i];\n if (input[i] > max) max = input[i];\n }\n }\n\n const range = max - min;\n if (range === 0) {\n result.fill(50);\n } else {\n for (let i = 0; i < input.length; i++) {\n result[i] = ((input[i] - min) / range) * 100;\n }\n }\n\n return result;\n}\n","/**\n * Indicator calculations in a Web Worker.\n * @module workers/indicator.worker\n */\n\nimport { rsi, macd, bollingerBands, sma, ema } from \"../plugins/analysis/indicators\";\n\ninterface IndicatorTask {\n id: string;\n type: \"indicator\";\n indicator: \"rsi\" | \"macd\" | \"bollingerBands\" | \"sma\" | \"ema\";\n data: Float32Array | Float64Array;\n period?: number;\n fastPeriod?: number;\n slowPeriod?: number;\n signalPeriod?: number;\n stdDev?: number;\n}\n\ninterface IndicatorResultMessage {\n id: string;\n type: \"indicator-result\";\n indicator: string;\n values: Float32Array;\n signal?: Float32Array;\n upper?: Float32Array;\n lower?: Float32Array;\n histogram?: Float32Array;\n duration: number;\n}\n\ninterface ErrorMessage {\n id: string;\n type: \"error\";\n error: string;\n}\n\nself.onmessage = function (event: MessageEvent<IndicatorTask>) {\n const message = event.data;\n\n try {\n const start = performance.now();\n let response: IndicatorResultMessage;\n\n switch (message.indicator) {\n case \"rsi\": {\n const values = rsi(message.data, message.period ?? 14);\n response = {\n id: message.id,\n type: \"indicator-result\",\n indicator: \"rsi\",\n values,\n duration: performance.now() - start,\n };\n (self.postMessage as (msg: unknown, transfer: Transferable[]) => void)(response, [values.buffer]);\n return;\n }\n case \"sma\": {\n const values = sma(message.data, message.period ?? 14);\n response = {\n id: message.id,\n type: \"indicator-result\",\n indicator: \"sma\",\n values,\n duration: performance.now() - start,\n };\n (self.postMessage as (msg: unknown, transfer: Transferable[]) => void)(response, [values.buffer]);\n return;\n }\n case \"ema\": {\n const values = ema(message.data, message.period ?? 14);\n response = {\n id: message.id,\n type: \"indicator-result\",\n indicator: \"ema\",\n values,\n duration: performance.now() - start,\n };\n (self.postMessage as (msg: unknown, transfer: Transferable[]) => void)(response, [values.buffer]);\n return;\n }\n case \"macd\": {\n const result = macd(\n message.data,\n message.fastPeriod ?? 12,\n message.slowPeriod ?? 26,\n message.signalPeriod ?? 9,\n );\n response = {\n id: message.id,\n type: \"indicator-result\",\n indicator: \"macd\",\n values: result.values,\n signal: result.signal,\n histogram: result.histogram,\n duration: performance.now() - start,\n };\n const transfer: Transferable[] = [result.values.buffer];\n if (result.signal) transfer.push(result.signal.buffer);\n if (result.histogram) transfer.push(result.histogram.buffer);\n (self.postMessage as (msg: unknown, transfer: Transferable[]) => void)(response, transfer);\n return;\n }\n case \"bollingerBands\": {\n const result = bollingerBands(message.data, message.period ?? 20, message.stdDev ?? 2);\n response = {\n id: message.id,\n type: \"indicator-result\",\n indicator: \"bollingerBands\",\n values: result.values,\n upper: result.upper,\n lower: result.lower,\n duration: performance.now() - start,\n };\n const transfer: Transferable[] = [result.values.buffer];\n if (result.upper) transfer.push(result.upper.buffer);\n if (result.lower) transfer.push(result.lower.buffer);\n (self.postMessage as (msg: unknown, transfer: Transferable[]) => void)(response, transfer);\n return;\n }\n default: {\n const err: ErrorMessage = {\n id: message.id,\n type: \"error\",\n error: `Unknown indicator: ${(message as IndicatorTask).indicator}`,\n };\n self.postMessage(err);\n }\n }\n } catch (error) {\n const err: ErrorMessage = {\n id: message.id,\n type: \"error\",\n error: error instanceof Error ? error.message : String(error),\n };\n self.postMessage(err);\n }\n};\n\nexport type { IndicatorTask, IndicatorResultMessage, ErrorMessage };\n"],"names":["sma","data","period","input","result","i","sum","ema","multiplier","rsi","avgGain","avgLoss","change","rs","gain","loss","macd","fastPeriod","slowPeriod","signalPeriod","fastEma","slowEma","macdLine","signal","histogram","bollingerBands","stdDev","middle","upper","lower","sumSquares","j","diff","std","event","message","start","response","values","transfer","err","error"],"mappings":"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"}
@@ -85,4 +85,6 @@ export declare class OverlayRenderer {
85
85
  private generateMinorTicks;
86
86
  private formatXTick;
87
87
  private formatYTick;
88
+ /** Draw buy/sell markers on candlestick series (Stage 2.14). */
89
+ drawCandlestickMarkers(plotArea: PlotArea, series: Series, xScale: Scale, yScale: Scale): void;
88
90
  }
@@ -0,0 +1,42 @@
1
+ import { EventEmitter } from '../EventEmitter';
2
+ import { ChartEventMap } from '../../types';
3
+
4
+ export type AlertDirection = "above" | "below" | "cross";
5
+ export interface PriceAlertOptions {
6
+ id?: string;
7
+ price: number;
8
+ direction: AlertDirection;
9
+ seriesId?: string;
10
+ /** Fire once then remove (default true) */
11
+ once?: boolean;
12
+ }
13
+ export interface AlertEvent {
14
+ id: string;
15
+ price: number;
16
+ direction: AlertDirection;
17
+ seriesId?: string;
18
+ triggeredAt: number;
19
+ triggerPrice: number;
20
+ }
21
+ export interface AlertableSeries {
22
+ getId(): string;
23
+ getData(): {
24
+ x: Float32Array | Float64Array;
25
+ y?: Float32Array | Float64Array;
26
+ close?: Float32Array | Float64Array;
27
+ };
28
+ }
29
+ export declare class ChartAlertManager {
30
+ private events;
31
+ private getSeries;
32
+ private alerts;
33
+ private idCounter;
34
+ constructor(events: EventEmitter<ChartEventMap>, getSeries: (id?: string) => AlertableSeries | undefined);
35
+ addAlert(options: PriceAlertOptions): string;
36
+ removeAlert(id: string): boolean;
37
+ clearAlerts(): void;
38
+ getAlerts(): PriceAlertOptions[];
39
+ /** Call after data updates / render tick. */
40
+ evaluate(): void;
41
+ destroy(): void;
42
+ }
@@ -9,6 +9,8 @@ import { ResponsiveConfig, ResponsiveState } from '../responsive';
9
9
  import { ChartState, SerializeOptions, DeserializeOptions } from '../../serialization';
10
10
  import { Chart, ExportOptions } from './types';
11
11
  import { ChartAnimationConfig } from '../animation';
12
+ import { AddIndicatorOptions, AddIndicatorResult, IndicatorPresetName } from '../indicator/addIndicator';
13
+ import { PriceAlertOptions } from './ChartAlerts';
12
14
 
13
15
  export declare class ChartImpl implements Chart {
14
16
  private container;
@@ -25,6 +27,8 @@ export declare class ChartImpl implements Chart {
25
27
  private backgroundColor;
26
28
  private plotAreaBackground;
27
29
  private renderer;
30
+ private activeRendererType;
31
+ private rendererInitPromise;
28
32
  private overlay;
29
33
  private interaction;
30
34
  private xScale;
@@ -64,6 +68,7 @@ export declare class ChartImpl implements Chart {
64
68
  private axisManager;
65
69
  private stateManager;
66
70
  private renderLoop;
71
+ private resizeObserver;
67
72
  setXScale(scale: Scale): void;
68
73
  setYScale(yAxisId: string, scale: Scale): void;
69
74
  get analysis(): any;
@@ -90,12 +95,13 @@ export declare class ChartImpl implements Chart {
90
95
  get animations(): ChartAnimationConfig;
91
96
  private selectionManager;
92
97
  private responsiveManager;
98
+ private alertManager;
93
99
  constructor(options: ChartOptions);
94
100
  /**
95
101
  * Start the chart initialization (called by queue system)
96
102
  * This performs the actual render startup that was deferred from constructor
97
103
  */
98
- startInit(): void;
104
+ startInit(): Promise<void>;
99
105
  /**
100
106
  * Mark this chart's initialization as complete in the queue
101
107
  */
@@ -126,6 +132,7 @@ export declare class ChartImpl implements Chart {
126
132
  };
127
133
  private getInteractedBounds;
128
134
  exportImage(type?: "png" | "jpeg"): string;
135
+ exportSVG(): string;
129
136
  private getSeriesContext;
130
137
  addSeries(options: SeriesOptions | HeatmapOptions): void;
131
138
  addBar(options: Omit<SeriesOptions, "type">): void;
@@ -139,6 +146,15 @@ export declare class ChartImpl implements Chart {
139
146
  * Add a line of best fit to a series
140
147
  */
141
148
  addFitLine(seriesId: string, type: any, options?: any): string;
149
+ /**
150
+ * Calculate and render a trading indicator preset (RSI, MACD, Bollinger, EMA, SMA).
151
+ * For stacked layouts use buildIndicatorPaneFromPreset() when creating panes.
152
+ */
153
+ addIndicator(preset: IndicatorPresetName, options?: AddIndicatorOptions): Promise<AddIndicatorResult>;
154
+ addAlert(options: PriceAlertOptions): string;
155
+ removeAlert(id: string): boolean;
156
+ clearAlerts(): void;
157
+ setDrawingMode(mode: import('../../plugins/drawing-tools').DrawingMode): void;
142
158
  getSeries(id: string): Series | undefined;
143
159
  getAllSeries(): Series[];
144
160
  private getNavContext;
@@ -211,6 +227,9 @@ export declare class ChartImpl implements Chart {
211
227
  * Get current device pixel ratio
212
228
  */
213
229
  getDPR(): number;
230
+ /** Runtime chart renderer backend in use. */
231
+ getActiveRenderer(): "webgl" | "webgpu";
232
+ private initGpuRenderer;
214
233
  /**
215
234
  * Set device pixel ratio and re-render
216
235
  */
@@ -1,4 +1,4 @@
1
- import { NativeWebGLRenderer } from '../../renderer/NativeWebGLRenderer';
1
+ import { ChartSeriesRenderer } from '../../renderer/ChartSeriesRenderer';
2
2
  import { OverlayRenderer } from '../OverlayRenderer';
3
3
  import { Series } from '../Series';
4
4
  import { Scale } from '../../scales';
@@ -19,7 +19,7 @@ export interface RenderLoopContext {
19
19
  yAxisOptionsMap: Map<string, AxisOptions>;
20
20
  xAxisOptions: AxisOptions;
21
21
  primaryYAxisId: string;
22
- renderer: NativeWebGLRenderer;
22
+ renderer?: ChartSeriesRenderer;
23
23
  overlay: OverlayRenderer;
24
24
  backgroundColor: [number, number, number, number];
25
25
  plotAreaBackground: [number, number, number, number];
@@ -59,6 +59,8 @@ export declare class ChartRenderLoop {
59
59
  * Mark that initialization has started
60
60
  */
61
61
  startInit(): void;
62
+ /** Wire renderer after async WebGPU init (context holds a snapshot, not a live ref). */
63
+ setRenderer(renderer: ChartSeriesRenderer): void;
62
64
  /**
63
65
  * Check if init has started
64
66
  */
@@ -1,7 +1,8 @@
1
1
  import { Bounds, CursorOptions, AxisOptions, PlotArea, ChartEventMap } from '../../types';
2
2
  import { Series } from '../Series';
3
3
  import { Scale } from '../../scales';
4
- import { NativeWebGLRenderer, NativeSeriesRenderData as SeriesRenderData } from '../../renderer/NativeWebGLRenderer';
4
+ import { ChartSeriesRenderer } from '../../renderer/ChartSeriesRenderer';
5
+ import { NativeSeriesRenderData as SeriesRenderData } from '../../renderer/NativeWebGLRenderer';
5
6
  import { OverlayRenderer } from '../OverlayRenderer';
6
7
  import { EventEmitter } from '../EventEmitter';
7
8
  import { SelectionManager } from '../selection';
@@ -18,7 +19,7 @@ export interface RenderContext {
18
19
  yAxisOptionsMap: Map<string, AxisOptions>;
19
20
  xAxisOptions: AxisOptions;
20
21
  primaryYAxisId: string;
21
- renderer: NativeWebGLRenderer;
22
+ renderer: ChartSeriesRenderer;
22
23
  overlay: OverlayRenderer;
23
24
  backgroundColor: [number, number, number, number];
24
25
  cursorOptions: CursorOptions | null;
@@ -0,0 +1,23 @@
1
+ /**
2
+ * Trade markers on candlestick series (Stage 2.14).
3
+ */
4
+ export type CandlestickMarkerPosition = "aboveBar" | "belowBar" | "inBar";
5
+ export type CandlestickMarkerShape = "arrowUp" | "arrowDown" | "circle";
6
+ export interface CandlestickMarker {
7
+ /** X value (epoch ms or data X) */
8
+ time: number;
9
+ position?: CandlestickMarkerPosition;
10
+ shape?: CandlestickMarkerShape;
11
+ text?: string;
12
+ color?: string;
13
+ }
14
+ export interface CandlestickMarkerDrawItem {
15
+ px: number;
16
+ py: number;
17
+ shape: CandlestickMarkerShape;
18
+ color: string;
19
+ text?: string;
20
+ }
21
+ /** Find nearest bar index for marker time. */
22
+ export declare function findBarIndex(x: Float32Array | Float64Array, time: number): number;
23
+ export declare function resolveMarkerY(position: CandlestickMarkerPosition, high: number, low: number, close: number): number;
@@ -1,6 +1,11 @@
1
1
  import { Series } from '../../Series';
2
- import { Bounds, PlotArea } from '../../../types';
2
+ import { AxisOptions, Bounds, PlotArea } from '../../../types';
3
3
  import { Scale } from '../../../scales';
4
4
  import { ChartTheme } from '../../../theme';
5
5
 
6
- export declare function exportToSVG(series: Series[], _viewBounds: Bounds, plotArea: PlotArea, xAxis: Scale, yAxes: Map<string, Scale>, theme: ChartTheme, width: number, height: number): string;
6
+ export interface SVGExportOptions {
7
+ xAxis?: AxisOptions;
8
+ yAxis?: AxisOptions;
9
+ primaryYAxisId?: string;
10
+ }
11
+ export declare function exportToSVG(series: Series[], _viewBounds: Bounds, plotArea: PlotArea, xAxis: Scale, yAxes: Map<string, Scale>, theme: ChartTheme, width: number, height: number, axisOptions?: SVGExportOptions): string;
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Heikin-Ashi OHLC transform (Stage 2.20).
3
+ */
4
+ export interface OhlcArrays {
5
+ open: Float32Array | Float64Array;
6
+ high: Float32Array | Float64Array;
7
+ low: Float32Array | Float64Array;
8
+ close: Float32Array | Float64Array;
9
+ }
10
+ export declare function computeHeikinAshi(ohlc: OhlcArrays): OhlcArrays;
@@ -1,11 +1,11 @@
1
1
  import { Series } from '../../Series';
2
- import { NativeWebGLRenderer } from '../../../renderer';
2
+ import { ChartSeriesRenderer } from '../../../renderer/ChartSeriesRenderer';
3
3
  import { Bounds } from '../../../types';
4
4
  import { Annotation } from '../../annotations';
5
5
 
6
6
  export interface SeriesManagerContext {
7
7
  series: Map<string, Series>;
8
- renderer: NativeWebGLRenderer;
8
+ renderer: ChartSeriesRenderer;
9
9
  viewBounds: Bounds;
10
10
  autoScale: () => void;
11
11
  requestRender: () => void;
@@ -18,6 +18,11 @@ export interface Chart {
18
18
  setAutoScroll(enabled: boolean): void;
19
19
  setMaxPoints(id: string, maxPoints: number): void;
20
20
  addFitLine(seriesId: string, type: any, options?: any): string;
21
+ addIndicator(preset: import('../indicator/addIndicator').IndicatorPresetName, options?: import('../indicator/addIndicator').AddIndicatorOptions): Promise<import('../indicator/addIndicator').AddIndicatorResult>;
22
+ addAlert(options: import('./ChartAlerts').PriceAlertOptions): string;
23
+ removeAlert(id: string): boolean;
24
+ clearAlerts(): void;
25
+ setDrawingMode(mode: import('../../plugins/drawing-tools').DrawingMode): void;
21
26
  zoom(options: ZoomOptions & {
22
27
  animate?: boolean;
23
28
  }): void;
@@ -37,6 +42,8 @@ export interface Chart {
37
42
  syncDragLayout?(width?: number, height?: number): void;
38
43
  /** Get current device pixel ratio used for rendering */
39
44
  getDPR(): number;
45
+ /** Actual renderer backend in use */
46
+ getActiveRenderer(): "webgl" | "webgpu";
40
47
  /** Set device pixel ratio and trigger re-render */
41
48
  setDPR(dpr: number): void;
42
49
  render(): void;
@@ -44,6 +51,8 @@ export interface Chart {
44
51
  off<K extends keyof ChartEventMap>(event: K, handler: (data: ChartEventMap[K]) => void): void;
45
52
  destroy(): void;
46
53
  exportImage(type?: "png" | "jpeg"): string;
54
+ /** Vector export of series, axes, grid, and tick labels */
55
+ exportSVG(): string;
47
56
  autoScale(animate?: boolean): void;
48
57
  setTheme(theme: string | object): void;
49
58
  /** Access to data analysis utilities */
@@ -0,0 +1,36 @@
1
+ import { Chart } from '../chart/types';
2
+ import { StackedPaneConfig } from '../stacked/types';
3
+ import { BuildIndicatorPaneOptions } from './buildIndicatorPane';
4
+ import { ComputedIndicatorPreset, IndicatorPresetName, IndicatorPresetOptions } from './indicatorPresets';
5
+
6
+ export interface AddIndicatorOptions extends IndicatorPresetOptions {
7
+ /** Series to derive prices from (default: first line/candlestick/bar) */
8
+ sourceSeriesId?: string;
9
+ /** Y axis for overlay lines (default: same as source series) */
10
+ yAxisId?: string;
11
+ /** For stacked charts — build a new pane config instead of mutating chart */
12
+ pane?: "inline" | "new";
13
+ /** Pane flex ratio when pane: 'new' (default 0.25) */
14
+ paneHeight?: number | string;
15
+ showXAxis?: boolean;
16
+ }
17
+ export interface AddIndicatorResult {
18
+ id: string;
19
+ preset: IndicatorPresetName;
20
+ placement: "overlay" | "oscillator";
21
+ seriesIds: string[];
22
+ }
23
+ type ChartIndicatorHost = Pick<Chart, "getSeries" | "getAllSeries" | "addSeries" | "removeSeries">;
24
+ /**
25
+ * Calculate indicator preset from a source series (no render).
26
+ */
27
+ export declare function computeIndicatorFromSeries(chart: ChartIndicatorHost, preset: IndicatorPresetName, options?: AddIndicatorOptions): Promise<ComputedIndicatorPreset>;
28
+ /**
29
+ * Add a trading indicator to an existing chart (overlay or inline oscillator layers).
30
+ */
31
+ export declare function addIndicatorToChart(chart: ChartIndicatorHost, preset: IndicatorPresetName, options?: AddIndicatorOptions): Promise<AddIndicatorResult>;
32
+ /**
33
+ * Build a stacked pane config for an indicator (use when creating or extending stacks).
34
+ */
35
+ export declare function buildIndicatorPaneFromPreset(preset: IndicatorPresetName, x: Float32Array | Float64Array, prices: Float32Array | Float64Array, options: IndicatorPresetOptions & Pick<BuildIndicatorPaneOptions, "id" | "height" | "label" | "yRange" | "tickCount" | "showXAxis" | "seriesId" | "style">): Promise<StackedPaneConfig>;
36
+ export type { IndicatorPresetName, IndicatorPresetOptions, ComputedIndicatorPreset };
@@ -1,3 +1,5 @@
1
1
  export type { IndicatorData, IndicatorFillLayer, IndicatorHistogramLayer, IndicatorLineColorZones, IndicatorLineLayer, IndicatorMarker, IndicatorMarkerKind, IndicatorReferenceLine, IndicatorSeriesOptions, IndicatorStyle, } from './types';
2
2
  export { buildIndicatorSeries, createIndicatorSeries, detectIndicatorMarkers, } from './buildIndicatorSeries';
3
3
  export { buildIndicatorPane, type BuildIndicatorPaneOptions } from './buildIndicatorPane';
4
+ export { addIndicatorToChart, buildIndicatorPaneFromPreset, computeIndicatorFromSeries, type AddIndicatorOptions, type AddIndicatorResult, type IndicatorPresetName, type IndicatorPresetOptions, } from './addIndicator';
5
+ export { computeIndicatorPreset, extractPriceSeries, resolveSourceSeries, isOverlayPreset, type ComputedIndicatorPreset, } from './indicatorPresets';
@@ -0,0 +1,37 @@
1
+ import { IndicatorData } from './types';
2
+ import { Series } from '../Series';
3
+
4
+ export type IndicatorPresetName = "rsi" | "macd" | "bollinger" | "bollingerBands" | "ema" | "sma";
5
+ export interface IndicatorPresetOptions {
6
+ period?: number;
7
+ fastPeriod?: number;
8
+ slowPeriod?: number;
9
+ signalPeriod?: number;
10
+ stdDev?: number;
11
+ /** Root id for generated series (default: preset name) */
12
+ id?: string;
13
+ label?: string;
14
+ }
15
+ export interface ComputedIndicatorPreset {
16
+ id: string;
17
+ preset: IndicatorPresetName;
18
+ /** overlay = price chart bands/lines; oscillator = separate pane layers */
19
+ placement: "overlay" | "oscillator";
20
+ yRange?: [number, number];
21
+ data: IndicatorData;
22
+ }
23
+ /** Extract X and close/price array from a source series. */
24
+ export declare function extractPriceSeries(source: Series): {
25
+ x: Float32Array | Float64Array;
26
+ prices: Float32Array | Float64Array;
27
+ };
28
+ /** Resolve source series from chart API surface. */
29
+ export declare function resolveSourceSeries(chart: {
30
+ getSeries(id: string): Series | undefined;
31
+ getAllSeries(): Series[];
32
+ }, sourceSeriesId?: string): Series;
33
+ /**
34
+ * Compute composite indicator layers for a preset (async worker path when available).
35
+ */
36
+ export declare function computeIndicatorPreset(preset: IndicatorPresetName, x: Float32Array | Float64Array, prices: Float32Array | Float64Array, options?: IndicatorPresetOptions): Promise<ComputedIndicatorPreset>;
37
+ export declare function isOverlayPreset(preset: IndicatorPresetName): boolean;
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Canvas pixel-alignment helpers for crisp 1px lines and sharper text.
3
+ * Coordinates are in CSS/logical space (before or after setTransform(dpr)).
4
+ */
5
+ /** Snap a coordinate to the center of a physical pixel (crisp 1px strokes). */
6
+ export declare function snapLineCoord(value: number): number;
7
+ /** Snap label positions to whole pixels (reduces sub-pixel blur on fillText). */
8
+ export declare function snapLabelCoord(value: number): number;
@@ -11,6 +11,7 @@ export declare class Series {
11
11
  private stackId?;
12
12
  private cycle?;
13
13
  private maxPoints?;
14
+ private markers;
14
15
  bullishCount: number;
15
16
  bearishCount: number;
16
17
  waterfallCounts?: {
@@ -42,6 +43,8 @@ export declare class Series {
42
43
  getVisible: () => boolean;
43
44
  isVisible: () => boolean;
44
45
  getStyle: () => SeriesStyle;
46
+ getMarkers: () => import('../..').CandlestickMarker[];
47
+ setMarkers: (markers: import('../chart/candlestickMarkers').CandlestickMarker[]) => void;
45
48
  getHeatmapData: () => HeatmapData | undefined;
46
49
  getHeatmapStyle: () => HeatmapStyle | undefined;
47
50
  getPolarData: () => PolarData | undefined;
@@ -1,4 +1,6 @@
1
1
  export { createStackedChart } from './createStackedChart';
2
- export type { StackedChart, StackedChartOptions, StackedPaneConfig, StackedSyncOptions } from './types';
2
+ export type { StackedChart, StackedChartOptions, StackedPaneConfig, StackedSyncOptions, StackDirection, StackSnapshotOptions, } from './types';
3
3
  export { STACKED_MAX_PANES, STACKED_DEFAULT_MIN_PANE_RATIO, } from './types';
4
+ export { exportStackImage } from './stackExport';
5
+ export type { StackExportOptions } from './stackExport';
4
6
  export { normalizePaneHeights, resolveMinPaneHeightPx, } from './paneResize';
@@ -1,32 +1,29 @@
1
- /**
2
- * VS Code–style drag dividers between stacked chart panes.
3
- */
1
+ import { StackDirection } from './types';
2
+
4
3
  export interface PaneResizeOptions {
5
- /** Min pane height as fraction of available height (default 1/6) */
4
+ /** Stack layout direction */
5
+ direction?: StackDirection;
6
+ /** Min pane size as fraction of available stack dimension (default 1/6) */
6
7
  minPaneRatio?: number;
7
- /** Absolute min pane height in px — used when larger than ratio-based min */
8
+ /** Absolute min pane size in px */
8
9
  minPanePx?: number;
9
- /** Divider hit area height (default 6) */
10
+ /** Divider hit area size (default 6) */
10
11
  dividerSize?: number;
11
- /** Called while dragging with normalized flex ratios keyed by pane id */
12
12
  onResize?: (ratiosById: Record<string, number>) => void;
13
- /** Called when divider drag starts — return initial pane heights for this drag session */
14
- onDragStart?: (topIdx: number, bottomIdx: number) => number[];
15
- /** Called each pointer move (batched to rAF by consumer) with updated heights */
16
- onDragMove?: (heightsPx: number[], topIdx: number, bottomIdx: number) => void;
17
- /** Called when divider drag ends — perform chart resize here */
18
- onDragEnd?: (finalHeightsPx: number[]) => void;
13
+ onDragStart?: (leadingIdx: number, trailingIdx: number) => number[];
14
+ onDragMove?: (sizesPx: number[], leadingIdx: number, trailingIdx: number) => void;
15
+ onDragEnd?: (finalSizesPx: number[]) => void;
19
16
  }
20
17
  export interface PaneResizeController {
21
18
  dividers: HTMLDivElement[];
22
19
  destroy: () => void;
23
20
  }
24
- /** Resolve per-pane minimum height in px for the current available stack height. */
21
+ declare function paneFlexStyle(ratio: number | string, direction: StackDirection): string;
25
22
  export declare function resolveMinPaneHeightPx(availHeight: number, paneCount: number, minPaneRatio?: number, minPanePx?: number): number;
26
- /**
27
- * Scale pane heights to exactly fill available space (fixes sub-pixel gaps during drag).
28
- */
23
+ export declare function resolveMinPaneWidthPx(availWidth: number, paneCount: number, minPaneRatio?: number, minPanePx?: number): number;
29
24
  export declare function normalizePaneHeights(heightsPx: number[], targetTotal: number): number[];
25
+ export declare const normalizePaneWidths: typeof normalizePaneHeights;
30
26
  export declare function attachPaneResize(container: HTMLDivElement, paneWrappers: HTMLDivElement[], paneIds: string[], ratios: number[], options?: PaneResizeOptions): PaneResizeController;
31
- export declare function applyPaneFlexRatios(paneWrappers: HTMLDivElement[], ratios: number[]): void;
27
+ export declare function applyPaneFlexRatios(paneWrappers: HTMLDivElement[], ratios: number[], direction?: StackDirection): void;
32
28
  export declare function initialPaneRatio(height: number | string): number;
29
+ export { paneFlexStyle };
@@ -0,0 +1,18 @@
1
+ import { Chart } from '../chart/types';
2
+
3
+ export type StackExportFormat = "png" | "jpeg" | "webp";
4
+ export type StackExportResolution = "standard" | "2k" | "4k" | "8k" | number;
5
+ export interface StackExportOptions {
6
+ format?: StackExportFormat;
7
+ quality?: number;
8
+ resolution?: StackExportResolution;
9
+ includeBackground?: boolean;
10
+ includeDividers?: boolean;
11
+ transparent?: boolean;
12
+ }
13
+ /** @internal Exported for unit tests */
14
+ export declare function stackResolutionScale(res: StackExportResolution): number;
15
+ /**
16
+ * Compose every pane chart into one raster image matching the on-screen stack layout.
17
+ */
18
+ export declare function exportStackImage(container: HTMLDivElement, paneWrappers: HTMLDivElement[], paneCharts: Chart[], dividers: HTMLDivElement[], backgroundColor: string, options?: StackExportOptions): Promise<string>;