@continuumdao/continuum-node-sdk 1.3.36 → 1.3.38

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 (208) hide show
  1. package/dist/agent-host-catalog.json +9 -0
  2. package/dist/core/chart/analysis/analysis-agent-view.d.ts.map +1 -1
  3. package/dist/core/chart/analysis/analysis-agent-view.js +33 -4
  4. package/dist/core/chart/analysis/analysis-agent-view.js.map +1 -1
  5. package/dist/core/chart/analysis/analysis-catalog.d.ts.map +1 -1
  6. package/dist/core/chart/analysis/analysis-catalog.js +47 -1
  7. package/dist/core/chart/analysis/analysis-catalog.js.map +1 -1
  8. package/dist/core/chart/analysis/analyze-tools.d.ts +167 -11
  9. package/dist/core/chart/analysis/analyze-tools.d.ts.map +1 -1
  10. package/dist/core/chart/analysis/analyze-tools.js +47 -55
  11. package/dist/core/chart/analysis/analyze-tools.js.map +1 -1
  12. package/dist/core/chart/analysis/chart-patterns-tools.d.ts +4 -4
  13. package/dist/core/chart/analysis/divergence/detect.d.ts +21 -0
  14. package/dist/core/chart/analysis/divergence/detect.d.ts.map +1 -0
  15. package/dist/core/chart/analysis/divergence/detect.js +223 -0
  16. package/dist/core/chart/analysis/divergence/detect.js.map +1 -0
  17. package/dist/core/chart/analysis/divergence/index.d.ts +4 -0
  18. package/dist/core/chart/analysis/divergence/index.d.ts.map +1 -0
  19. package/dist/core/chart/analysis/divergence/index.js +4 -0
  20. package/dist/core/chart/analysis/divergence/index.js.map +1 -0
  21. package/dist/core/chart/analysis/divergence/peaks.d.ts +11 -0
  22. package/dist/core/chart/analysis/divergence/peaks.d.ts.map +1 -0
  23. package/dist/core/chart/analysis/divergence/peaks.js +108 -0
  24. package/dist/core/chart/analysis/divergence/peaks.js.map +1 -0
  25. package/dist/core/chart/analysis/divergence/types.d.ts +30 -0
  26. package/dist/core/chart/analysis/divergence/types.d.ts.map +1 -0
  27. package/dist/core/chart/analysis/divergence/types.js +2 -0
  28. package/dist/core/chart/analysis/divergence/types.js.map +1 -0
  29. package/dist/core/chart/analysis/divergence-analyze-tools.d.ts +239 -0
  30. package/dist/core/chart/analysis/divergence-analyze-tools.d.ts.map +1 -0
  31. package/dist/core/chart/analysis/divergence-analyze-tools.js +283 -0
  32. package/dist/core/chart/analysis/divergence-analyze-tools.js.map +1 -0
  33. package/dist/core/chart/analysis/divergence-drawings-tools.d.ts +457 -0
  34. package/dist/core/chart/analysis/divergence-drawings-tools.d.ts.map +1 -0
  35. package/dist/core/chart/analysis/divergence-drawings-tools.js +380 -0
  36. package/dist/core/chart/analysis/divergence-drawings-tools.js.map +1 -0
  37. package/dist/core/chart/analysis/divergence-highlight.d.ts +19 -0
  38. package/dist/core/chart/analysis/divergence-highlight.d.ts.map +1 -0
  39. package/dist/core/chart/analysis/divergence-highlight.js +39 -0
  40. package/dist/core/chart/analysis/divergence-highlight.js.map +1 -0
  41. package/dist/core/chart/analysis/donchian-analyze-tools.d.ts +113 -0
  42. package/dist/core/chart/analysis/donchian-analyze-tools.d.ts.map +1 -0
  43. package/dist/core/chart/analysis/donchian-analyze-tools.js +218 -0
  44. package/dist/core/chart/analysis/donchian-analyze-tools.js.map +1 -0
  45. package/dist/core/chart/analysis/donchian-highlight.d.ts +31 -0
  46. package/dist/core/chart/analysis/donchian-highlight.d.ts.map +1 -0
  47. package/dist/core/chart/analysis/donchian-highlight.js +41 -0
  48. package/dist/core/chart/analysis/donchian-highlight.js.map +1 -0
  49. package/dist/core/chart/analysis/elliott-waves-analyze-tools.d.ts +35 -2
  50. package/dist/core/chart/analysis/elliott-waves-analyze-tools.d.ts.map +1 -1
  51. package/dist/core/chart/analysis/ichimoku-analyze-tools.d.ts +124 -0
  52. package/dist/core/chart/analysis/ichimoku-analyze-tools.d.ts.map +1 -0
  53. package/dist/core/chart/analysis/ichimoku-analyze-tools.js +243 -0
  54. package/dist/core/chart/analysis/ichimoku-analyze-tools.js.map +1 -0
  55. package/dist/core/chart/analysis/ichimoku-highlight.d.ts +36 -0
  56. package/dist/core/chart/analysis/ichimoku-highlight.d.ts.map +1 -0
  57. package/dist/core/chart/analysis/ichimoku-highlight.js +40 -0
  58. package/dist/core/chart/analysis/ichimoku-highlight.js.map +1 -0
  59. package/dist/core/chart/analysis/key-fib-drawings-tools.d.ts +2 -6
  60. package/dist/core/chart/analysis/key-fib-drawings-tools.d.ts.map +1 -1
  61. package/dist/core/chart/analysis/key-fib-drawings-tools.js +5 -17
  62. package/dist/core/chart/analysis/key-fib-drawings-tools.js.map +1 -1
  63. package/dist/core/chart/analysis/key-level-drawings-shared.d.ts +3 -12
  64. package/dist/core/chart/analysis/key-level-drawings-shared.d.ts.map +1 -1
  65. package/dist/core/chart/analysis/key-level-drawings-shared.js +6 -36
  66. package/dist/core/chart/analysis/key-level-drawings-shared.js.map +1 -1
  67. package/dist/core/chart/analysis/key-level-menu-summary.d.ts +15 -22
  68. package/dist/core/chart/analysis/key-level-menu-summary.d.ts.map +1 -1
  69. package/dist/core/chart/analysis/key-level-menu-summary.js +63 -124
  70. package/dist/core/chart/analysis/key-level-menu-summary.js.map +1 -1
  71. package/dist/core/chart/analysis/key-levels-dataset.d.ts +1 -0
  72. package/dist/core/chart/analysis/key-levels-dataset.d.ts.map +1 -1
  73. package/dist/core/chart/analysis/key-levels-dataset.js +4 -7
  74. package/dist/core/chart/analysis/key-levels-dataset.js.map +1 -1
  75. package/dist/core/chart/analysis/supertrend-analyze-tools.d.ts +112 -0
  76. package/dist/core/chart/analysis/supertrend-analyze-tools.d.ts.map +1 -0
  77. package/dist/core/chart/analysis/supertrend-analyze-tools.js +214 -0
  78. package/dist/core/chart/analysis/supertrend-analyze-tools.js.map +1 -0
  79. package/dist/core/chart/analysis/supertrend-highlight.d.ts +25 -0
  80. package/dist/core/chart/analysis/supertrend-highlight.d.ts.map +1 -0
  81. package/dist/core/chart/analysis/supertrend-highlight.js +37 -0
  82. package/dist/core/chart/analysis/supertrend-highlight.js.map +1 -0
  83. package/dist/core/chart/analysis/trade-setups/build-trade-uniswap.d.ts.map +1 -1
  84. package/dist/core/chart/analysis/trade-setups/build-trade-uniswap.js +21 -0
  85. package/dist/core/chart/analysis/trade-setups/build-trade-uniswap.js.map +1 -1
  86. package/dist/core/chart/analysis/trade-setups/build-trade.d.ts.map +1 -1
  87. package/dist/core/chart/analysis/trade-setups/build-trade.js +23 -5
  88. package/dist/core/chart/analysis/trade-setups/build-trade.js.map +1 -1
  89. package/dist/core/chart/analysis/trade-setups/divergence-trade-setup.d.ts +78 -0
  90. package/dist/core/chart/analysis/trade-setups/divergence-trade-setup.d.ts.map +1 -0
  91. package/dist/core/chart/analysis/trade-setups/divergence-trade-setup.js +184 -0
  92. package/dist/core/chart/analysis/trade-setups/divergence-trade-setup.js.map +1 -0
  93. package/dist/core/chart/analysis/trade-setups/donchian-trade-setup.d.ts +133 -0
  94. package/dist/core/chart/analysis/trade-setups/donchian-trade-setup.d.ts.map +1 -0
  95. package/dist/core/chart/analysis/trade-setups/donchian-trade-setup.js +419 -0
  96. package/dist/core/chart/analysis/trade-setups/donchian-trade-setup.js.map +1 -0
  97. package/dist/core/chart/analysis/trade-setups/ichimoku-trade-setup.d.ts +154 -0
  98. package/dist/core/chart/analysis/trade-setups/ichimoku-trade-setup.d.ts.map +1 -0
  99. package/dist/core/chart/analysis/trade-setups/ichimoku-trade-setup.js +396 -0
  100. package/dist/core/chart/analysis/trade-setups/ichimoku-trade-setup.js.map +1 -0
  101. package/dist/core/chart/analysis/trade-setups/index.d.ts +5 -0
  102. package/dist/core/chart/analysis/trade-setups/index.d.ts.map +1 -1
  103. package/dist/core/chart/analysis/trade-setups/index.js +5 -0
  104. package/dist/core/chart/analysis/trade-setups/index.js.map +1 -1
  105. package/dist/core/chart/analysis/trade-setups/key-level-fib-retrace-trade-setup.d.ts +7 -41
  106. package/dist/core/chart/analysis/trade-setups/key-level-fib-retrace-trade-setup.d.ts.map +1 -1
  107. package/dist/core/chart/analysis/trade-setups/key-level-fib-retrace-trade-setup.js +33 -235
  108. package/dist/core/chart/analysis/trade-setups/key-level-fib-retrace-trade-setup.js.map +1 -1
  109. package/dist/core/chart/analysis/trade-setups/key-levels-trade-setup.d.ts +2 -8
  110. package/dist/core/chart/analysis/trade-setups/key-levels-trade-setup.d.ts.map +1 -1
  111. package/dist/core/chart/analysis/trade-setups/key-levels-trade-setup.js +0 -27
  112. package/dist/core/chart/analysis/trade-setups/key-levels-trade-setup.js.map +1 -1
  113. package/dist/core/chart/analysis/trade-setups/shared.d.ts +1 -1
  114. package/dist/core/chart/analysis/trade-setups/shared.d.ts.map +1 -1
  115. package/dist/core/chart/analysis/trade-setups/shared.js +10 -0
  116. package/dist/core/chart/analysis/trade-setups/shared.js.map +1 -1
  117. package/dist/core/chart/analysis/trade-setups/supertrend-trade-setup.d.ts +119 -0
  118. package/dist/core/chart/analysis/trade-setups/supertrend-trade-setup.d.ts.map +1 -0
  119. package/dist/core/chart/analysis/trade-setups/supertrend-trade-setup.js +301 -0
  120. package/dist/core/chart/analysis/trade-setups/supertrend-trade-setup.js.map +1 -0
  121. package/dist/core/chart/analysis/trade-setups/trade-desk-universal-input.d.ts +34 -0
  122. package/dist/core/chart/analysis/trade-setups/trade-desk-universal-input.d.ts.map +1 -1
  123. package/dist/core/chart/analysis/trade-setups/trade-desk-universal-input.js +43 -0
  124. package/dist/core/chart/analysis/trade-setups/trade-desk-universal-input.js.map +1 -1
  125. package/dist/core/chart/analysis/trade-setups/trade-idea-list.d.ts +15 -0
  126. package/dist/core/chart/analysis/trade-setups/trade-idea-list.d.ts.map +1 -1
  127. package/dist/core/chart/analysis/trade-setups/trade-idea-list.js +89 -0
  128. package/dist/core/chart/analysis/trade-setups/trade-idea-list.js.map +1 -1
  129. package/dist/core/chart/analysis/trade-setups/trade-idea.d.ts +32 -0
  130. package/dist/core/chart/analysis/trade-setups/trade-idea.d.ts.map +1 -1
  131. package/dist/core/chart/analysis/trade-setups/trade-idea.js +32 -0
  132. package/dist/core/chart/analysis/trade-setups/trade-idea.js.map +1 -1
  133. package/dist/core/chart/analysis/trade-setups/trade-purpose-format.d.ts +2 -2
  134. package/dist/core/chart/analysis/trade-setups/trade-purpose-format.d.ts.map +1 -1
  135. package/dist/core/chart/analysis/trade-setups/trade-purpose-format.js +2 -6
  136. package/dist/core/chart/analysis/trade-setups/trade-purpose-format.js.map +1 -1
  137. package/dist/core/chart/analysis/trade-setups/trade-setup-selection.d.ts +42 -8
  138. package/dist/core/chart/analysis/trade-setups/trade-setup-selection.d.ts.map +1 -1
  139. package/dist/core/chart/analysis/trade-setups/trade-setup-selection.js +72 -17
  140. package/dist/core/chart/analysis/trade-setups/trade-setup-selection.js.map +1 -1
  141. package/dist/core/chart/analysis/trade-setups/z-score-trade-setup.d.ts +89 -0
  142. package/dist/core/chart/analysis/trade-setups/z-score-trade-setup.d.ts.map +1 -0
  143. package/dist/core/chart/analysis/trade-setups/z-score-trade-setup.js +195 -0
  144. package/dist/core/chart/analysis/trade-setups/z-score-trade-setup.js.map +1 -0
  145. package/dist/core/chart/analysis/z-score-analyze-tools.d.ts +111 -0
  146. package/dist/core/chart/analysis/z-score-analyze-tools.d.ts.map +1 -0
  147. package/dist/core/chart/analysis/z-score-analyze-tools.js +240 -0
  148. package/dist/core/chart/analysis/z-score-analyze-tools.js.map +1 -0
  149. package/dist/core/chart/analysis/z-score-highlight.d.ts +29 -0
  150. package/dist/core/chart/analysis/z-score-highlight.d.ts.map +1 -0
  151. package/dist/core/chart/analysis/z-score-highlight.js +39 -0
  152. package/dist/core/chart/analysis/z-score-highlight.js.map +1 -0
  153. package/dist/core/chart/customization-catalog.d.ts.map +1 -1
  154. package/dist/core/chart/customization-catalog.js +36 -0
  155. package/dist/core/chart/customization-catalog.js.map +1 -1
  156. package/dist/core/chart/display-downsample.d.ts.map +1 -1
  157. package/dist/core/chart/display-downsample.js +4 -14
  158. package/dist/core/chart/display-downsample.js.map +1 -1
  159. package/dist/core/chart/overlay-schemas.d.ts +496 -0
  160. package/dist/core/chart/overlay-schemas.d.ts.map +1 -1
  161. package/dist/core/chart/overlay-schemas.js +137 -0
  162. package/dist/core/chart/overlay-schemas.js.map +1 -1
  163. package/dist/core/chart/overlays.d.ts +2 -0
  164. package/dist/core/chart/overlays.d.ts.map +1 -1
  165. package/dist/core/chart/overlays.js +620 -2
  166. package/dist/core/chart/overlays.js.map +1 -1
  167. package/dist/core/chart/prepare-from-rows.d.ts +143 -0
  168. package/dist/core/chart/prepare-from-rows.d.ts.map +1 -1
  169. package/dist/core/chart/schemas.d.ts +491 -0
  170. package/dist/core/chart/schemas.d.ts.map +1 -1
  171. package/dist/core/coinmarketcap/schemas.d.ts +7 -7
  172. package/dist/index.d.ts +0 -1
  173. package/dist/index.d.ts.map +1 -1
  174. package/dist/index.js +2 -1
  175. package/dist/index.js.map +1 -1
  176. package/dist/mcp/agent-host-catalog.d.ts +1 -1
  177. package/dist/mcp/agent-host-catalog.d.ts.map +1 -1
  178. package/dist/mcp/agent-host-catalog.js +1 -0
  179. package/dist/mcp/agent-host-catalog.js.map +1 -1
  180. package/dist/mcp/chart.d.ts.map +1 -1
  181. package/dist/mcp/chart.js +61 -2
  182. package/dist/mcp/chart.js.map +1 -1
  183. package/dist/mcp/deferred/tool-group-map.d.ts.map +1 -1
  184. package/dist/mcp/deferred/tool-group-map.js +8 -0
  185. package/dist/mcp/deferred/tool-group-map.js.map +1 -1
  186. package/dist/mcp/defi/morpho-input.d.ts +3 -0
  187. package/dist/mcp/defi/morpho-input.d.ts.map +1 -1
  188. package/dist/mcp/defi/morpho-input.js +116 -1
  189. package/dist/mcp/defi/morpho-input.js.map +1 -1
  190. package/dist/mcp/ohlcv-session-wrapper.d.ts.map +1 -1
  191. package/dist/mcp/ohlcv-session-wrapper.js +8 -0
  192. package/dist/mcp/ohlcv-session-wrapper.js.map +1 -1
  193. package/dist/mcp/resources/chart-analysis.md +9 -0
  194. package/dist/mcp/resources/chart.md +3 -0
  195. package/dist/mcp/trade-tools.d.ts.map +1 -1
  196. package/dist/mcp/trade-tools.js +2 -0
  197. package/dist/mcp/trade-tools.js.map +1 -1
  198. package/package.json +65 -60
  199. package/dist/core/agent/mcp-servers-catalog.d.ts +0 -15
  200. package/dist/core/agent/mcp-servers-catalog.d.ts.map +0 -1
  201. package/dist/core/agent/mcp-servers-catalog.js +0 -125
  202. package/dist/core/agent/mcp-servers-catalog.js.map +0 -1
  203. package/dist/core/agent/webhooks-catalog.d.ts +0 -10
  204. package/dist/core/agent/webhooks-catalog.d.ts.map +0 -1
  205. package/dist/core/agent/webhooks-catalog.js +0 -19
  206. package/dist/core/agent/webhooks-catalog.js.map +0 -1
  207. package/dist/mcp/resources/trade-defaults-skill.md +0 -69
  208. package/dist/mcp/ta/resources/indicators.md +0 -86
@@ -5,7 +5,28 @@ const DEFAULT_MA_PERIOD = 20;
5
5
  const DEFAULT_BOLLINGER_PERIOD = 20;
6
6
  const DEFAULT_BOLLINGER_STD_DEV = 2;
7
7
  const DEFAULT_BOLLINGER_FILL_COLOR = '#6366f133';
8
+ /** Analysis/overlay desk default (aligned with TA catalog donchianchannels). */
9
+ const DEFAULT_DONCHIAN_PERIOD = 20;
10
+ const DEFAULT_DONCHIAN_FILL_COLOR = '#0ea5e933';
11
+ const DEFAULT_SUPERTREND_PERIOD = 10;
12
+ const DEFAULT_SUPERTREND_MULTIPLIER = 3;
13
+ const SUPERTREND_UP_COLOR = '#22c55e';
14
+ const SUPERTREND_DOWN_COLOR = '#ef4444';
15
+ /** Cap colored ST segments so total chart series stay under the expand limit. */
16
+ const MAX_SUPERTREND_SEGMENTS = 10;
17
+ const DEFAULT_ICHIMOKU_CONVERSION = 9;
18
+ const DEFAULT_ICHIMOKU_BASE = 26;
19
+ const DEFAULT_ICHIMOKU_SPAN = 52;
20
+ const DEFAULT_ICHIMOKU_DISPLACEMENT = 26;
21
+ const ICHIMOKU_TENKAN_COLOR = '#3b82f6';
22
+ const ICHIMOKU_KIJUN_COLOR = '#ef4444';
23
+ const ICHIMOKU_CHIKOU_COLOR = '#a855f7';
24
+ const ICHIMOKU_CLOUD_BULL_COLOR = '#22c55e33';
25
+ const ICHIMOKU_CLOUD_BEAR_COLOR = '#ef444433';
8
26
  const DEFAULT_RSI_PERIOD = 14;
27
+ const DEFAULT_ZSCORE_PERIOD = 20;
28
+ const DEFAULT_ZSCORE_ENTRY = 2;
29
+ const DEFAULT_ZSCORE_EXIT = 0.5;
9
30
  const MACD_HIST_UP = '#22c55e';
10
31
  const MACD_HIST_DOWN = '#ef4444';
11
32
  const ALL_FIB_LEVELS = [0, 0.236, 0.382, 0.5, 0.618, 0.786, 1];
@@ -16,8 +37,11 @@ function findSourceSeries(seriesList, sourceSeriesId) {
16
37
  }
17
38
  const times = [];
18
39
  const closes = [];
40
+ const highs = [];
41
+ const lows = [];
19
42
  let high = Number.NEGATIVE_INFINITY;
20
43
  let low = Number.POSITIVE_INFINITY;
44
+ let hasOhlc = false;
21
45
  for (const row of source.data) {
22
46
  const time = row.time;
23
47
  if (time == null) {
@@ -35,6 +59,9 @@ function findSourceSeries(seriesList, sourceSeriesId) {
35
59
  }
36
60
  times.push(time);
37
61
  closes.push(close);
62
+ highs.push(rowHigh);
63
+ lows.push(rowLow);
64
+ hasOhlc = true;
38
65
  high = Math.max(high, rowHigh);
39
66
  low = Math.min(low, rowLow);
40
67
  continue;
@@ -59,7 +86,16 @@ function findSourceSeries(seriesList, sourceSeriesId) {
59
86
  if (!Number.isFinite(high) || !Number.isFinite(low)) {
60
87
  return { ok: false, reason: `Overlay source "${sourceSeriesId}" has invalid high/low range.` };
61
88
  }
62
- return { ok: true, data: { times, closes, high, low } };
89
+ return {
90
+ ok: true,
91
+ data: {
92
+ times,
93
+ closes,
94
+ ...(hasOhlc ? { highs, lows } : {}),
95
+ high,
96
+ low,
97
+ },
98
+ };
63
99
  }
64
100
  function primaryTimeSpan(seriesList) {
65
101
  const primary = seriesList.find(s => s.type === 'candlestick' || s.type === 'line');
@@ -252,6 +288,405 @@ function computeBollingerOverlay(overlay, source) {
252
288
  ],
253
289
  };
254
290
  }
291
+ function computeDonchianOverlay(overlay, source) {
292
+ const period = overlay.period ?? DEFAULT_DONCHIAN_PERIOD;
293
+ const highs = source.highs;
294
+ const lows = source.lows;
295
+ if (!highs?.length || !lows?.length || highs.length !== source.closes.length) {
296
+ return {
297
+ ok: false,
298
+ reason: 'Donchian overlay requires a candlestick source series with high/low.',
299
+ };
300
+ }
301
+ const result = calculateTechnicalIndicator({
302
+ indicator: 'donchianchannels',
303
+ params: { period },
304
+ input: { high: highs, low: lows, close: source.closes },
305
+ options: { maxPoints: highs.length },
306
+ });
307
+ if (!result.ok) {
308
+ return result;
309
+ }
310
+ const rows = result.data.result;
311
+ if (!Array.isArray(rows) || rows.length === 0) {
312
+ return { ok: false, reason: 'Overlay donchian returned no data.' };
313
+ }
314
+ const upper = [];
315
+ const middle = [];
316
+ const lower = [];
317
+ const bandFill = [];
318
+ const aligned = alignObjectIndicatorRows(source.times, rows, result.data.warmupCount);
319
+ for (const { time, row } of aligned) {
320
+ const u = pickNumber(row, ['upper', 'Upper']);
321
+ const m = pickNumber(row, ['middle', 'Middle']);
322
+ const l = pickNumber(row, ['lower', 'Lower']);
323
+ if (u != null) {
324
+ upper.push({ time, value: u });
325
+ }
326
+ if (m != null) {
327
+ middle.push({ time, value: m });
328
+ }
329
+ if (l != null) {
330
+ lower.push({ time, value: l });
331
+ }
332
+ if (u != null && l != null) {
333
+ bandFill.push({ time, upper: u, lower: l });
334
+ }
335
+ }
336
+ if (middle.length === 0) {
337
+ return {
338
+ ok: false,
339
+ reason: `Overlay donchian(${period}) has no points after warmup.`,
340
+ };
341
+ }
342
+ const prefix = overlay.id ?? `dc${period}_${overlay.sourceSeriesId}`;
343
+ const baseStyle = overlay.style ?? { lineWidth: 1 };
344
+ const showFill = overlay.fill !== false;
345
+ const fillColor = overlay.style?.color ?? DEFAULT_DONCHIAN_FILL_COLOR;
346
+ const seriesOut = [];
347
+ if (showFill && bandFill.length > 0) {
348
+ seriesOut.push({
349
+ id: `${prefix}_fill`,
350
+ type: 'band',
351
+ label: `DC fill (${period})`,
352
+ data: bandFill,
353
+ priceScaleId: overlay.priceScaleId ?? 'right',
354
+ overlay: overlay.overlay ?? true,
355
+ lastValueVisible: false,
356
+ style: { color: fillColor, lineWidth: 1 },
357
+ });
358
+ }
359
+ return {
360
+ ok: true,
361
+ data: [
362
+ ...seriesOut,
363
+ {
364
+ id: `${prefix}_upper`,
365
+ type: 'line',
366
+ label: `DC upper (${period})`,
367
+ data: upper,
368
+ priceScaleId: overlay.priceScaleId ?? 'right',
369
+ overlay: overlay.overlay ?? true,
370
+ style: { ...baseStyle, lineStyle: 'dashed' },
371
+ },
372
+ {
373
+ id: `${prefix}_middle`,
374
+ type: 'line',
375
+ label: `DC middle (${period})`,
376
+ data: middle,
377
+ priceScaleId: overlay.priceScaleId ?? 'right',
378
+ overlay: overlay.overlay ?? true,
379
+ style: { ...baseStyle, lineStyle: 'solid' },
380
+ },
381
+ {
382
+ id: `${prefix}_lower`,
383
+ type: 'line',
384
+ label: `DC lower (${period})`,
385
+ data: lower,
386
+ priceScaleId: overlay.priceScaleId ?? 'right',
387
+ overlay: overlay.overlay ?? true,
388
+ style: { ...baseStyle, lineStyle: 'dashed' },
389
+ },
390
+ ],
391
+ };
392
+ }
393
+ function computeSupertrendOverlay(overlay, source) {
394
+ const period = overlay.period ?? DEFAULT_SUPERTREND_PERIOD;
395
+ const multiplier = overlay.multiplier ?? DEFAULT_SUPERTREND_MULTIPLIER;
396
+ const highs = source.highs;
397
+ const lows = source.lows;
398
+ if (!highs?.length || !lows?.length || highs.length !== source.closes.length) {
399
+ return {
400
+ ok: false,
401
+ reason: 'Supertrend overlay requires a candlestick source series with high/low.',
402
+ };
403
+ }
404
+ const result = calculateTechnicalIndicator({
405
+ indicator: 'supertrend',
406
+ params: { period, multiplier },
407
+ input: { high: highs, low: lows, close: source.closes },
408
+ options: { maxPoints: highs.length },
409
+ });
410
+ if (!result.ok) {
411
+ return result;
412
+ }
413
+ const rows = result.data.result;
414
+ if (!Array.isArray(rows) || rows.length === 0) {
415
+ return { ok: false, reason: 'Overlay supertrend returned no data.' };
416
+ }
417
+ const aligned = alignObjectIndicatorRows(source.times, rows, result.data.warmupCount);
418
+ const points = [];
419
+ for (const { time, row } of aligned) {
420
+ const value = pickNumber(row, ['supertrend', 'SuperTrend', 'Supertrend']);
421
+ const direction = pickNumber(row, ['direction', 'Direction']);
422
+ if (value == null || direction == null || !Number.isFinite(value)) {
423
+ continue;
424
+ }
425
+ points.push({ time, value, direction: direction >= 0 ? 1 : -1 });
426
+ }
427
+ if (points.length === 0) {
428
+ return {
429
+ ok: false,
430
+ reason: `Overlay supertrend(${period}, ${multiplier}) has no points after warmup.`,
431
+ };
432
+ }
433
+ const segments = [];
434
+ for (const pt of points) {
435
+ const last = segments[segments.length - 1];
436
+ if (!last || last.direction !== pt.direction) {
437
+ segments.push({ direction: pt.direction, data: [{ time: pt.time, value: pt.value }] });
438
+ }
439
+ else {
440
+ last.data.push({ time: pt.time, value: pt.value });
441
+ }
442
+ }
443
+ const kept = segments.length > MAX_SUPERTREND_SEGMENTS
444
+ ? segments.slice(segments.length - MAX_SUPERTREND_SEGMENTS)
445
+ : segments;
446
+ const prefix = overlay.id ?? `st${period}x${multiplier}_${overlay.sourceSeriesId}`;
447
+ const lineWidth = overlay.style?.lineWidth ?? 2;
448
+ const seriesOut = kept.map((seg, i) => ({
449
+ id: `${prefix}_seg${i}`,
450
+ type: 'line',
451
+ label: i === kept.length - 1 ? `Supertrend (${period}, ${multiplier})` : `ST seg ${i + 1}`,
452
+ data: seg.data,
453
+ priceScaleId: overlay.priceScaleId ?? 'right',
454
+ overlay: overlay.overlay ?? true,
455
+ lastValueVisible: i === kept.length - 1,
456
+ style: {
457
+ lineWidth,
458
+ lineStyle: 'solid',
459
+ color: seg.direction >= 0 ? SUPERTREND_UP_COLOR : SUPERTREND_DOWN_COLOR,
460
+ },
461
+ }));
462
+ return { ok: true, data: seriesOut };
463
+ }
464
+ function medianBarIntervalSec(times) {
465
+ const secs = [];
466
+ for (const t of times) {
467
+ const s = chartTimeSec(t);
468
+ if (s != null) {
469
+ secs.push(s);
470
+ }
471
+ }
472
+ if (secs.length < 2) {
473
+ return null;
474
+ }
475
+ const deltas = [];
476
+ for (let i = 1; i < secs.length; i++) {
477
+ const d = secs[i] - secs[i - 1];
478
+ if (d > 0) {
479
+ deltas.push(d);
480
+ }
481
+ }
482
+ if (deltas.length === 0) {
483
+ return null;
484
+ }
485
+ deltas.sort((a, b) => a - b);
486
+ return deltas[Math.floor(deltas.length / 2)];
487
+ }
488
+ function extendChartTime(last, intervalSec, steps) {
489
+ const sec = chartTimeSec(last);
490
+ if (sec == null || typeof last !== 'number') {
491
+ // Business-day charts: fall back to unix seconds from last if possible.
492
+ if (sec == null) {
493
+ return last;
494
+ }
495
+ return sec + intervalSec * steps;
496
+ }
497
+ return last + intervalSec * steps;
498
+ }
499
+ function computeIchimokuOverlay(overlay, source) {
500
+ const conversionPeriod = overlay.conversionPeriod ?? DEFAULT_ICHIMOKU_CONVERSION;
501
+ const basePeriod = overlay.basePeriod ?? DEFAULT_ICHIMOKU_BASE;
502
+ const spanPeriod = overlay.spanPeriod ?? DEFAULT_ICHIMOKU_SPAN;
503
+ const displacement = overlay.displacement ?? DEFAULT_ICHIMOKU_DISPLACEMENT;
504
+ const highs = source.highs;
505
+ const lows = source.lows;
506
+ if (!highs?.length || !lows?.length || highs.length !== source.closes.length) {
507
+ return {
508
+ ok: false,
509
+ reason: 'Ichimoku overlay requires a candlestick source series with high/low.',
510
+ };
511
+ }
512
+ const result = calculateTechnicalIndicator({
513
+ indicator: 'ichimokukinkouhyou',
514
+ params: { conversionPeriod, basePeriod, spanPeriod, displacement },
515
+ input: { high: highs, low: lows, close: source.closes },
516
+ options: { maxPoints: highs.length },
517
+ });
518
+ if (!result.ok) {
519
+ return result;
520
+ }
521
+ const rows = result.data.result;
522
+ if (!Array.isArray(rows) || rows.length === 0) {
523
+ return { ok: false, reason: 'Overlay ichimoku returned no data.' };
524
+ }
525
+ const aligned = alignObjectIndicatorRows(source.times, rows, result.data.warmupCount);
526
+ const tenkan = [];
527
+ const kijun = [];
528
+ const spanPoints = [];
529
+ const intervalSec = medianBarIntervalSec(source.times) ?? 3600;
530
+ const alignOffset = rows.length < source.times.length ? source.times.length - rows.length : 0;
531
+ for (let i = 0; i < aligned.length; i++) {
532
+ const { time, row } = aligned[i];
533
+ const conversion = pickNumber(row, ['conversion', 'Conversion', 'tenkan', 'Tenkan']);
534
+ const base = pickNumber(row, ['base', 'Base', 'kijun', 'Kijun']);
535
+ const spanA = pickNumber(row, ['spanA', 'SpanA', 'senkouA', 'SenkouA']);
536
+ const spanB = pickNumber(row, ['spanB', 'SpanB', 'senkouB', 'SenkouB']);
537
+ if (conversion != null) {
538
+ tenkan.push({ time, value: conversion });
539
+ }
540
+ if (base != null) {
541
+ kijun.push({ time, value: base });
542
+ }
543
+ if (spanA != null && spanB != null) {
544
+ const sourceIndex = alignOffset + i;
545
+ const targetIndex = sourceIndex + displacement;
546
+ let cloudTime;
547
+ if (targetIndex >= 0 && targetIndex < source.times.length) {
548
+ cloudTime = source.times[targetIndex];
549
+ }
550
+ else if (source.times.length > 0 && targetIndex >= source.times.length) {
551
+ const last = source.times[source.times.length - 1];
552
+ const stepsBeyond = targetIndex - (source.times.length - 1);
553
+ cloudTime = extendChartTime(last, intervalSec, stepsBeyond);
554
+ }
555
+ else {
556
+ continue;
557
+ }
558
+ spanPoints.push({ time: cloudTime, spanA, spanB });
559
+ }
560
+ }
561
+ if (tenkan.length === 0 && kijun.length === 0) {
562
+ return {
563
+ ok: false,
564
+ reason: `Overlay ichimoku(${conversionPeriod}/${basePeriod}/${spanPeriod}) has no points after warmup.`,
565
+ };
566
+ }
567
+ const prefix = overlay.id ?? `ichi_${overlay.sourceSeriesId}`;
568
+ const priceScaleId = overlay.priceScaleId ?? 'right';
569
+ const isOverlay = overlay.overlay ?? true;
570
+ const showFill = overlay.fill !== false;
571
+ const showChikou = overlay.chikou !== false;
572
+ const seriesOut = [];
573
+ if (showFill && spanPoints.length > 0) {
574
+ const bullBands = [];
575
+ const bearBands = [];
576
+ for (const pt of spanPoints) {
577
+ const upper = Math.max(pt.spanA, pt.spanB);
578
+ const lower = Math.min(pt.spanA, pt.spanB);
579
+ const bandPt = { time: pt.time, upper, lower };
580
+ if (pt.spanA >= pt.spanB) {
581
+ bullBands.push(bandPt);
582
+ }
583
+ else {
584
+ bearBands.push(bandPt);
585
+ }
586
+ }
587
+ if (bullBands.length > 0) {
588
+ seriesOut.push({
589
+ id: `${prefix}_cloud_bull`,
590
+ type: 'band',
591
+ label: 'Ichimoku cloud (bull)',
592
+ data: bullBands,
593
+ priceScaleId,
594
+ overlay: isOverlay,
595
+ lastValueVisible: false,
596
+ style: { color: ICHIMOKU_CLOUD_BULL_COLOR, lineWidth: 1 },
597
+ });
598
+ }
599
+ if (bearBands.length > 0) {
600
+ seriesOut.push({
601
+ id: `${prefix}_cloud_bear`,
602
+ type: 'band',
603
+ label: 'Ichimoku cloud (bear)',
604
+ data: bearBands,
605
+ priceScaleId,
606
+ overlay: isOverlay,
607
+ lastValueVisible: false,
608
+ style: { color: ICHIMOKU_CLOUD_BEAR_COLOR, lineWidth: 1 },
609
+ });
610
+ }
611
+ }
612
+ if (tenkan.length > 0) {
613
+ seriesOut.push({
614
+ id: `${prefix}_tenkan`,
615
+ type: 'line',
616
+ label: `Tenkan (${conversionPeriod})`,
617
+ data: tenkan,
618
+ priceScaleId,
619
+ overlay: isOverlay,
620
+ style: { color: ICHIMOKU_TENKAN_COLOR, lineWidth: 1, lineStyle: 'solid' },
621
+ });
622
+ }
623
+ if (kijun.length > 0) {
624
+ seriesOut.push({
625
+ id: `${prefix}_kijun`,
626
+ type: 'line',
627
+ label: `Kijun (${basePeriod})`,
628
+ data: kijun,
629
+ priceScaleId,
630
+ overlay: isOverlay,
631
+ style: { color: ICHIMOKU_KIJUN_COLOR, lineWidth: 1, lineStyle: 'solid' },
632
+ });
633
+ }
634
+ // Senkou outline lines (forward-displaced).
635
+ const spanALine = [];
636
+ const spanBLine = [];
637
+ for (const pt of spanPoints) {
638
+ spanALine.push({ time: pt.time, value: pt.spanA });
639
+ spanBLine.push({ time: pt.time, value: pt.spanB });
640
+ }
641
+ if (spanALine.length > 0) {
642
+ seriesOut.push({
643
+ id: `${prefix}_spanA`,
644
+ type: 'line',
645
+ label: 'Senkou A',
646
+ data: spanALine,
647
+ priceScaleId,
648
+ overlay: isOverlay,
649
+ lastValueVisible: false,
650
+ style: { color: '#22c55e', lineWidth: 1, lineStyle: 'dashed' },
651
+ });
652
+ }
653
+ if (spanBLine.length > 0) {
654
+ seriesOut.push({
655
+ id: `${prefix}_spanB`,
656
+ type: 'line',
657
+ label: 'Senkou B',
658
+ data: spanBLine,
659
+ priceScaleId,
660
+ overlay: isOverlay,
661
+ lastValueVisible: false,
662
+ style: { color: '#ef4444', lineWidth: 1, lineStyle: 'dashed' },
663
+ });
664
+ }
665
+ if (showChikou && displacement > 0 && source.closes.length > displacement) {
666
+ const chikou = [];
667
+ for (let i = displacement; i < source.closes.length; i++) {
668
+ const close = source.closes[i];
669
+ const time = source.times[i - displacement];
670
+ if (time == null || !Number.isFinite(close)) {
671
+ continue;
672
+ }
673
+ chikou.push({ time, value: close });
674
+ }
675
+ if (chikou.length > 0) {
676
+ seriesOut.push({
677
+ id: `${prefix}_chikou`,
678
+ type: 'line',
679
+ label: `Chikou (${displacement})`,
680
+ data: chikou,
681
+ priceScaleId,
682
+ overlay: isOverlay,
683
+ lastValueVisible: false,
684
+ style: { color: ICHIMOKU_CHIKOU_COLOR, lineWidth: 1, lineStyle: 'dotted' },
685
+ });
686
+ }
687
+ }
688
+ return { ok: true, data: seriesOut };
689
+ }
255
690
  function horizontalLineData(timeStart, timeEnd, value) {
256
691
  return [
257
692
  { time: timeStart, value },
@@ -795,6 +1230,97 @@ function oscillatorPaneId(overlay, index) {
795
1230
  const base = overlay.id ?? `${overlay.type}_${index}`;
796
1231
  return `osc_${base.replace(/[^a-zA-Z0-9_-]/g, '_')}`;
797
1232
  }
1233
+ /** Resolve pane ids for rsi / stochasticrsi overlays in the same order expandChartOverlays uses. */
1234
+ export function resolveOscillatorPaneIds(overlays) {
1235
+ const out = {};
1236
+ if (!overlays?.length) {
1237
+ return out;
1238
+ }
1239
+ let oscillatorIndex = 0;
1240
+ for (const overlay of overlays) {
1241
+ if (overlay.type === 'rsi' ||
1242
+ overlay.type === 'zscore' ||
1243
+ overlay.type === 'macd' ||
1244
+ overlay.type === 'stochasticrsi') {
1245
+ const paneId = oscillatorPaneId(overlay, oscillatorIndex++);
1246
+ if (out[overlay.type] == null) {
1247
+ out[overlay.type] = paneId;
1248
+ }
1249
+ }
1250
+ }
1251
+ return out;
1252
+ }
1253
+ function divergenceSegmentStyle(kind, base) {
1254
+ const bullish = kind === 'regular_bullish' || kind === 'hidden_bullish';
1255
+ const hidden = kind === 'hidden_bullish' || kind === 'hidden_bearish';
1256
+ return {
1257
+ color: bullish ? '#3b82f6' : '#ef4444',
1258
+ lineWidth: 2,
1259
+ lineStyle: hidden ? 'dashed' : 'solid',
1260
+ ...base,
1261
+ };
1262
+ }
1263
+ function chartTimeToUnix(time) {
1264
+ if (typeof time === 'number' && Number.isFinite(time)) {
1265
+ return time;
1266
+ }
1267
+ if (time && typeof time === 'object' && 'year' in time) {
1268
+ return Math.floor(Date.UTC(time.year, time.month - 1, time.day) / 1000);
1269
+ }
1270
+ return null;
1271
+ }
1272
+ function computeDivergenceOverlay(overlay, paneByOsc) {
1273
+ const prefix = overlay.id ?? 'divergence';
1274
+ const seriesOut = [];
1275
+ for (let i = 0; i < overlay.segments.length; i++) {
1276
+ const seg = overlay.segments[i];
1277
+ const paneId = seg.oscillatorPaneId ?? paneByOsc[seg.oscillator];
1278
+ if (!paneId) {
1279
+ return {
1280
+ ok: false,
1281
+ reason: `Divergence segment needs ${seg.oscillator} pane — ensure that oscillator overlay is present.`,
1282
+ };
1283
+ }
1284
+ const style = divergenceSegmentStyle(seg.kind, overlay.style);
1285
+ const pA = chartTimeToUnix(seg.price.pointA.time);
1286
+ const pB = chartTimeToUnix(seg.price.pointB.time);
1287
+ const oA = chartTimeToUnix(seg.oscillatorLine.pointA.time);
1288
+ const oB = chartTimeToUnix(seg.oscillatorLine.pointB.time);
1289
+ if (pA == null || pB == null || oA == null || oB == null) {
1290
+ return { ok: false, reason: 'Divergence segment has invalid times.' };
1291
+ }
1292
+ const label = seg.label?.trim() || seg.kind.replace(/_/g, ' ');
1293
+ seriesOut.push({
1294
+ id: `${prefix}_price_${i}`,
1295
+ type: 'line',
1296
+ label: `${label} (price)`,
1297
+ data: [
1298
+ { time: pA, value: seg.price.pointA.price },
1299
+ { time: pB, value: seg.price.pointB.price },
1300
+ ],
1301
+ priceScaleId: 'right',
1302
+ overlay: true,
1303
+ style,
1304
+ });
1305
+ seriesOut.push({
1306
+ id: `${prefix}_osc_${i}`,
1307
+ type: 'line',
1308
+ label: `${label} (${seg.oscillator})`,
1309
+ data: [
1310
+ { time: oA, value: seg.oscillatorLine.pointA.value },
1311
+ { time: oB, value: seg.oscillatorLine.pointB.value },
1312
+ ],
1313
+ priceScaleId: 'right',
1314
+ overlay: true,
1315
+ paneId,
1316
+ style,
1317
+ });
1318
+ }
1319
+ if (!seriesOut.length) {
1320
+ return { ok: false, reason: 'divergence produced no drawable geometry.' };
1321
+ }
1322
+ return { ok: true, data: seriesOut };
1323
+ }
798
1324
  function tagSeriesPane(series, paneId) {
799
1325
  return series.map(s => ({ ...s, paneId }));
800
1326
  }
@@ -844,6 +1370,80 @@ function computeRsiOverlay(overlay, source, paneId) {
844
1370
  ], paneId),
845
1371
  };
846
1372
  }
1373
+ function computeZScoreOverlay(overlay, source, paneId) {
1374
+ const period = overlay.period ?? DEFAULT_ZSCORE_PERIOD;
1375
+ const entryZ = overlay.entryZ ?? DEFAULT_ZSCORE_ENTRY;
1376
+ const exitZ = overlay.exitZ ?? DEFAULT_ZSCORE_EXIT;
1377
+ const smaResult = calculateTechnicalIndicator({
1378
+ indicator: 'sma',
1379
+ params: { period },
1380
+ input: { values: source.closes },
1381
+ options: { maxPoints: source.closes.length },
1382
+ });
1383
+ if (!smaResult.ok) {
1384
+ return smaResult;
1385
+ }
1386
+ const sdResult = calculateTechnicalIndicator({
1387
+ indicator: 'sd',
1388
+ params: { period },
1389
+ input: { values: source.closes },
1390
+ options: { maxPoints: source.closes.length },
1391
+ });
1392
+ if (!sdResult.ok) {
1393
+ return sdResult;
1394
+ }
1395
+ const smaAligned = alignNumericIndicator(source.times, smaResult.data.result, smaResult.data.warmupCount);
1396
+ const sdAligned = alignNumericIndicator(source.times, sdResult.data.result, sdResult.data.warmupCount);
1397
+ const sdByTime = new Map(sdAligned.map(p => [String(p.time), p.value]));
1398
+ const zLine = [];
1399
+ for (let i = 0; i < source.closes.length; i++) {
1400
+ const time = source.times[i];
1401
+ const close = source.closes[i];
1402
+ const smaPoint = smaAligned.find(p => p.time === time);
1403
+ const sd = sdByTime.get(String(time));
1404
+ if (smaPoint == null || sd == null || !Number.isFinite(sd) || sd <= 0) {
1405
+ continue;
1406
+ }
1407
+ zLine.push({ time, value: (close - smaPoint.value) / sd });
1408
+ }
1409
+ if (zLine.length === 0) {
1410
+ return { ok: false, reason: `Overlay zscore(${period}) has no points after warmup.` };
1411
+ }
1412
+ const prefix = overlay.id ?? `zscore${period}_${overlay.sourceSeriesId}`;
1413
+ const guide = (level, idSuffix, label, dashed = true) => ({
1414
+ id: `${prefix}_${idSuffix}`,
1415
+ type: 'line',
1416
+ label,
1417
+ data: zLine.map(p => ({ time: p.time, value: level })),
1418
+ priceScaleId: 'right',
1419
+ overlay: true,
1420
+ lastValueVisible: false,
1421
+ style: {
1422
+ lineStyle: dashed ? 'dashed' : 'dotted',
1423
+ lineWidth: 1,
1424
+ color: '#94a3b8',
1425
+ },
1426
+ });
1427
+ const seriesOut = [
1428
+ {
1429
+ id: `${prefix}_z`,
1430
+ type: 'line',
1431
+ label: overlay.label ?? `Z(${period})`,
1432
+ data: zLine,
1433
+ priceScaleId: 'right',
1434
+ overlay: true,
1435
+ style: overlay.style ?? { lineStyle: 'solid', lineWidth: 2, color: '#7c3aed' },
1436
+ },
1437
+ guide(0, 'zero', 'Z=0', false),
1438
+ guide(entryZ, 'entry_pos', `+${entryZ}`),
1439
+ guide(-entryZ, 'entry_neg', `−${entryZ}`),
1440
+ ];
1441
+ if (exitZ > 0) {
1442
+ seriesOut.push(guide(exitZ, 'exit_pos', `+${exitZ}`));
1443
+ seriesOut.push(guide(-exitZ, 'exit_neg', `−${exitZ}`));
1444
+ }
1445
+ return { ok: true, data: tagSeriesPane(seriesOut, paneId) };
1446
+ }
847
1447
  function computeMacdOverlay(overlay, source, paneId) {
848
1448
  const params = {
849
1449
  ...(overlay.fastPeriod != null ? { fastPeriod: overlay.fastPeriod } : {}),
@@ -1005,13 +1605,15 @@ export function expandChartOverlays(baseSeries, overlays) {
1005
1605
  }
1006
1606
  const expanded = [...baseSeries];
1007
1607
  let oscillatorIndex = 0;
1608
+ const paneByOsc = resolveOscillatorPaneIds(overlays);
1008
1609
  for (const overlay of overlays) {
1009
1610
  let overlaySeries;
1010
1611
  if (overlay.type === 'horizontal_levels' ||
1011
1612
  overlay.type === 'pivot_levels' ||
1012
1613
  overlay.type === 'trend_lines' ||
1013
1614
  overlay.type === 'chart_pattern' ||
1014
- overlay.type === 'elliott_waves') {
1615
+ overlay.type === 'elliott_waves' ||
1616
+ overlay.type === 'divergence') {
1015
1617
  const span = primaryTimeSpan(baseSeries);
1016
1618
  if (!span.ok) {
1017
1619
  return span;
@@ -1028,6 +1630,9 @@ export function expandChartOverlays(baseSeries, overlays) {
1028
1630
  else if (overlay.type === 'elliott_waves') {
1029
1631
  overlaySeries = computeElliottWavesOverlay(overlay, span.data.timeStart, span.data.timeEnd);
1030
1632
  }
1633
+ else if (overlay.type === 'divergence') {
1634
+ overlaySeries = computeDivergenceOverlay(overlay, paneByOsc);
1635
+ }
1031
1636
  else {
1032
1637
  overlaySeries = computeTrendLinesOverlay(overlay, span.data.timeStart, span.data.timeEnd);
1033
1638
  }
@@ -1055,6 +1660,7 @@ export function expandChartOverlays(baseSeries, overlays) {
1055
1660
  overlaySeries = computeFibonacciOverlay(overlay, span.data.timeStart, span.data.timeEnd, range);
1056
1661
  }
1057
1662
  else if (overlay.type === 'rsi' ||
1663
+ overlay.type === 'zscore' ||
1058
1664
  overlay.type === 'macd' ||
1059
1665
  overlay.type === 'stochasticrsi') {
1060
1666
  const sourceResult = findSourceSeries(baseSeries, overlay.sourceSeriesId);
@@ -1065,6 +1671,9 @@ export function expandChartOverlays(baseSeries, overlays) {
1065
1671
  if (overlay.type === 'rsi') {
1066
1672
  overlaySeries = computeRsiOverlay(overlay, sourceResult.data, paneId);
1067
1673
  }
1674
+ else if (overlay.type === 'zscore') {
1675
+ overlaySeries = computeZScoreOverlay(overlay, sourceResult.data, paneId);
1676
+ }
1068
1677
  else if (overlay.type === 'macd') {
1069
1678
  overlaySeries = computeMacdOverlay(overlay, sourceResult.data, paneId);
1070
1679
  }
@@ -1086,6 +1695,15 @@ export function expandChartOverlays(baseSeries, overlays) {
1086
1695
  else if (overlay.type === 'bollinger') {
1087
1696
  overlaySeries = computeBollingerOverlay(overlay, sourceResult.data);
1088
1697
  }
1698
+ else if (overlay.type === 'donchian') {
1699
+ overlaySeries = computeDonchianOverlay(overlay, sourceResult.data);
1700
+ }
1701
+ else if (overlay.type === 'supertrend') {
1702
+ overlaySeries = computeSupertrendOverlay(overlay, sourceResult.data);
1703
+ }
1704
+ else if (overlay.type === 'ichimoku') {
1705
+ overlaySeries = computeIchimokuOverlay(overlay, sourceResult.data);
1706
+ }
1089
1707
  else {
1090
1708
  return { ok: false, reason: `Unsupported overlay type.` };
1091
1709
  }