@rioaxyz/sonrchart 0.1.0 → 0.2.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.
package/dist/index.js CHANGED
@@ -13665,14 +13665,26 @@ var SESSION_INDICATOR = "SONR_SESSION";
13665
13665
  var PATTERN_INDICATOR = "SONR_PATTERNS";
13666
13666
  var WATERMARK_INDICATOR = "SONR_WATERMARK";
13667
13667
  var SERIES_INDICATOR = "SONR_SERIES";
13668
+ var HALT_INDICATOR = "SONR_HALT";
13668
13669
  var VWAP_INDICATOR = "VWAP";
13669
13670
  var Z_ORDER = {
13670
13671
  watermark: -3,
13671
13672
  session: -2,
13672
13673
  series: -1,
13673
13674
  compare: 0,
13674
- pattern: 10
13675
+ pattern: 10,
13676
+ halt: 11
13675
13677
  };
13678
+ var DEFAULT_HALT_BADGE = { label: "Halt", color: "#2196f3", textColor: "#ffffff" };
13679
+ function normalizeHalt(prop) {
13680
+ if (!prop) return null;
13681
+ if (prop === true) return DEFAULT_HALT_BADGE;
13682
+ return {
13683
+ label: prop.label ?? DEFAULT_HALT_BADGE.label,
13684
+ color: prop.color ?? DEFAULT_HALT_BADGE.color,
13685
+ textColor: prop.textColor ?? DEFAULT_HALT_BADGE.textColor
13686
+ };
13687
+ }
13676
13688
  var VWAP_COLOR = "#a970ff";
13677
13689
  function computeVWAP(dataList) {
13678
13690
  let day = Number.NaN;
@@ -13924,6 +13936,41 @@ function registerSonrIndicators() {
13924
13936
  return false;
13925
13937
  }
13926
13938
  });
13939
+ registerIndicator({
13940
+ name: HALT_INDICATOR,
13941
+ shortName: "",
13942
+ series: "price",
13943
+ figures: [],
13944
+ calc: (dataList) => dataList.map(() => ({})),
13945
+ draw: ({ ctx, bounding, indicator }) => {
13946
+ const cfg = indicator.extendData;
13947
+ if (!cfg || !cfg.label) return false;
13948
+ const padX = 8;
13949
+ const h = 20;
13950
+ const inset = 8;
13951
+ ctx.save();
13952
+ ctx.font = '600 11px ui-sans-serif, -apple-system, "Segoe UI", sans-serif';
13953
+ const w = Math.ceil(ctx.measureText(cfg.label).width) + padX * 2;
13954
+ const x = bounding.width - w - inset;
13955
+ const y = (bounding.top ?? 0) + inset;
13956
+ const r = h / 2;
13957
+ ctx.beginPath();
13958
+ ctx.moveTo(x + r, y);
13959
+ ctx.arcTo(x + w, y, x + w, y + h, r);
13960
+ ctx.arcTo(x + w, y + h, x, y + h, r);
13961
+ ctx.arcTo(x, y + h, x, y, r);
13962
+ ctx.arcTo(x, y, x + w, y, r);
13963
+ ctx.closePath();
13964
+ ctx.fillStyle = cfg.color;
13965
+ ctx.fill();
13966
+ ctx.fillStyle = cfg.textColor;
13967
+ ctx.textAlign = "center";
13968
+ ctx.textBaseline = "middle";
13969
+ ctx.fillText(cfg.label, x + w / 2, y + h / 2 + 0.5);
13970
+ ctx.restore();
13971
+ return false;
13972
+ }
13973
+ });
13927
13974
  registerIndicator({
13928
13975
  name: PATTERN_INDICATOR,
13929
13976
  shortName: "",
@@ -15276,6 +15323,25 @@ function formatWithUnit(text2, quote) {
15276
15323
  return out;
15277
15324
  }
15278
15325
 
15326
+ // src/volumeTrend.ts
15327
+ var DEFAULT_VOLUME_TREND_BARS = 3;
15328
+ function volumeTrend(list, endIndex, bars = DEFAULT_VOLUME_TREND_BARS) {
15329
+ const n = Math.max(1, Math.floor(bars));
15330
+ if (endIndex < n || endIndex >= list.length) return null;
15331
+ let up = 0;
15332
+ let down = 0;
15333
+ for (let i = endIndex - n + 1; i <= endIndex; i++) {
15334
+ const v = list[i]?.volume;
15335
+ const pv = list[i - 1]?.volume;
15336
+ if (typeof v !== "number" || typeof pv !== "number") return null;
15337
+ if (v > pv) up++;
15338
+ else if (v < pv) down++;
15339
+ }
15340
+ if (up === n) return "increasing";
15341
+ if (down === n) return "decreasing";
15342
+ return "mixed";
15343
+ }
15344
+
15279
15345
  // src/SonrChart.tsx
15280
15346
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
15281
15347
  registerSonrIndicators();
@@ -15285,7 +15351,7 @@ registerShapeOverlays();
15285
15351
  registerExtendedDrawings();
15286
15352
  registerTradeReview();
15287
15353
  registerTextOverlay();
15288
- var INTERNAL_INDICATORS = /* @__PURE__ */ new Set([SESSION_INDICATOR, PATTERN_INDICATOR, COMPARE_INDICATOR, WATERMARK_INDICATOR, SERIES_INDICATOR]);
15354
+ var INTERNAL_INDICATORS = /* @__PURE__ */ new Set([SESSION_INDICATOR, PATTERN_INDICATOR, COMPARE_INDICATOR, WATERMARK_INDICATOR, SERIES_INDICATOR, HALT_INDICATOR]);
15289
15355
  var isUserIndicator = (name) => !INTERNAL_INDICATORS.has(name);
15290
15356
  function magnetMode(m) {
15291
15357
  if (m === true || m === "weak") return "weak_magnet";
@@ -15385,6 +15451,7 @@ var SonrChart = forwardRef(function SonrChart2({
15385
15451
  sessions: sessionsProp,
15386
15452
  watermark: watermarkProp,
15387
15453
  patterns,
15454
+ halted,
15388
15455
  priceLines,
15389
15456
  orderLines,
15390
15457
  priceScale: priceScaleProp,
@@ -15502,14 +15569,22 @@ var SonrChart = forwardRef(function SonrChart2({
15502
15569
  const legendRef = useRef2(legend);
15503
15570
  legendRef.current = legend;
15504
15571
  const headerSubs = useRef2(/* @__PURE__ */ new Set());
15572
+ const trendSubs = useRef2(/* @__PURE__ */ new Set());
15573
+ const trendBarsRef = useRef2(DEFAULT_VOLUME_TREND_BARS);
15574
+ const trendBarsSubs = useRef2(/* @__PURE__ */ new Set());
15505
15575
  const crosshairActiveRef = useRef2(false);
15576
+ const headerIdxRef = useRef2(-1);
15577
+ const emitHeaderAt = (list, idx) => {
15578
+ headerIdxRef.current = idx;
15579
+ const current = idx >= 0 ? list[idx] ?? null : null;
15580
+ const prev = idx > 0 ? list[idx - 1] : null;
15581
+ headerSubs.current.forEach((cb) => cb(current, prev));
15582
+ trendSubs.current.forEach((s) => s.cb(volumeTrend(list, idx, s.bars ?? trendBarsRef.current)));
15583
+ };
15506
15584
  const emitLatestHeader = () => {
15507
15585
  if (crosshairActiveRef.current) return;
15508
15586
  const list = chartRef.current?.getDataList() ?? [];
15509
- const n = list.length;
15510
- const current = n ? list[n - 1] : null;
15511
- const prev = n > 1 ? list[n - 2] : null;
15512
- headerSubs.current.forEach((cb) => cb(current, prev));
15587
+ emitHeaderAt(list, list.length - 1);
15513
15588
  };
15514
15589
  const haRef = useRef2(new HaTransformer());
15515
15590
  const [textEdit, setTextEdit] = useState(null);
@@ -15777,6 +15852,30 @@ var SonrChart = forwardRef(function SonrChart2({
15777
15852
  const n = list.length;
15778
15853
  cb(n ? list[n - 1] : null, n > 1 ? list[n - 2] : null);
15779
15854
  return () => headerSubs.current.delete(cb);
15855
+ },
15856
+ // Volume trend (#79) ---------------------------------------------------
15857
+ subscribeVolumeTrend: (cb, bars) => {
15858
+ const sub = { bars: bars === void 0 ? void 0 : Math.max(1, Math.floor(bars)), cb };
15859
+ trendSubs.current.add(sub);
15860
+ const list = chartRef.current?.getDataList() ?? [];
15861
+ cb(volumeTrend(list, list.length - 1, sub.bars ?? trendBarsRef.current));
15862
+ return () => trendSubs.current.delete(sub);
15863
+ },
15864
+ getVolumeTrendBars: () => trendBarsRef.current,
15865
+ setVolumeTrendBars: (bars) => {
15866
+ const n = Math.max(1, Math.floor(bars));
15867
+ if (!Number.isFinite(n) || n === trendBarsRef.current) return;
15868
+ trendBarsRef.current = n;
15869
+ const list = chartRef.current?.getDataList() ?? [];
15870
+ const idx = crosshairActiveRef.current ? headerIdxRef.current : list.length - 1;
15871
+ trendSubs.current.forEach((s) => {
15872
+ if (s.bars === void 0) s.cb(volumeTrend(list, idx, n));
15873
+ });
15874
+ trendBarsSubs.current.forEach((cb) => cb(n));
15875
+ },
15876
+ subscribeVolumeTrendBars: (cb) => {
15877
+ trendBarsSubs.current.add(cb);
15878
+ return () => trendBarsSubs.current.delete(cb);
15780
15879
  }
15781
15880
  },
15782
15881
  // paneHeights/priceScale captured by closure; recreated per render is fine.
@@ -15840,16 +15939,29 @@ var SonrChart = forwardRef(function SonrChart2({
15840
15939
  chart.setStyles(mergeStyles(themeStyleObj, styles2));
15841
15940
  chart.subscribeAction("onCrosshairChange", (d) => {
15842
15941
  const cross = d;
15843
- const k = cross?.kLineData;
15844
- if (k && typeof cross?.dataIndex === "number") {
15942
+ const list = chart.getDataList();
15943
+ let k = cross?.kLineData ?? null;
15944
+ let idx = typeof cross?.dataIndex === "number" ? cross.dataIndex : -1;
15945
+ if (!k && typeof cross?.x === "number" && list.length > 0) {
15946
+ const [p] = chart.convertFromPixel([{ x: cross.x }], { paneId: CANDLE_PANE });
15947
+ if (typeof p?.dataIndex === "number") {
15948
+ idx = Math.max(0, Math.min(p.dataIndex, list.length - 1));
15949
+ k = list[idx] ?? null;
15950
+ }
15951
+ }
15952
+ if (k && idx >= 0) {
15845
15953
  crosshairActiveRef.current = true;
15846
- const list = chart.getDataList();
15847
- headerSubs.current.forEach((cb) => cb(k, cross.dataIndex > 0 ? list[cross.dataIndex - 1] : null));
15954
+ emitHeaderAt(list, idx);
15848
15955
  } else {
15849
15956
  crosshairActiveRef.current = false;
15850
15957
  emitLatestHeader();
15851
15958
  }
15852
15959
  });
15960
+ const onPointerLeave = () => {
15961
+ crosshairActiveRef.current = false;
15962
+ emitLatestHeader();
15963
+ };
15964
+ el.addEventListener("mouseleave", onPointerLeave);
15853
15965
  applyCandleStyle(chart, candleStyleRef.current, themeStyleObj, baseTheme);
15854
15966
  applyPriceLabels(chart, priceLabelsRef.current);
15855
15967
  applyFormatter(chart);
@@ -15959,6 +16071,7 @@ var SonrChart = forwardRef(function SonrChart2({
15959
16071
  return () => {
15960
16072
  disposed = true;
15961
16073
  unsub();
16074
+ el.removeEventListener("mouseleave", onPointerLeave);
15962
16075
  dispose(idRef.current);
15963
16076
  chartRef.current = null;
15964
16077
  overlayIds.current = [];
@@ -16030,6 +16143,19 @@ var SonrChart = forwardRef(function SonrChart2({
16030
16143
  chart.removeIndicator({ name: PATTERN_INDICATOR });
16031
16144
  }
16032
16145
  }, [patterns, chartEpoch]);
16146
+ useEffect(() => {
16147
+ const chart = chartRef.current;
16148
+ if (!chart) return;
16149
+ const present = chart.getIndicators({ name: HALT_INDICATOR }).length > 0;
16150
+ const badge = normalizeHalt(halted);
16151
+ if (badge && !present) {
16152
+ chart.createIndicator({ name: HALT_INDICATOR, paneId: CANDLE_PANE, zLevel: Z_ORDER.halt, extendData: badge }, true);
16153
+ } else if (badge && present) {
16154
+ chart.overrideIndicator({ name: HALT_INDICATOR, extendData: badge });
16155
+ } else if (!badge && present) {
16156
+ chart.removeIndicator({ name: HALT_INDICATOR });
16157
+ }
16158
+ }, [halted, chartEpoch]);
16033
16159
  useEffect(() => {
16034
16160
  const chart = chartRef.current;
16035
16161
  if (!chart) return;
@@ -16283,7 +16409,7 @@ var CSS = `
16283
16409
  :where(.sonr-mkt-handle){position:absolute;top:50%;width:12px;height:12px;border-radius:50%;background:#fff;border:2px solid #22a06b;transform:translate(-50%,-50%);}
16284
16410
  :where(.sonr-mkt-ticks){grid-column:2;display:flex;justify-content:space-between;font-size:10px;color:#888;}
16285
16411
  :where(.sonr-mkt-tz){margin-top:12px;font-size:11px;color:#888;text-align:center;}
16286
- :where(.sonr-hd){display:inline-flex;align-items:center;gap:10px;font-family:inherit;font-size:12px;color:#000;white-space:nowrap;}
16412
+ :where(.sonr-hd){display:inline-flex;flex-wrap:wrap;align-items:center;gap:10px;font-family:inherit;font-size:12px;color:#000;white-space:nowrap;}
16287
16413
  :where(.sonr-hd-sym){font-weight:700;color:#000;}
16288
16414
  :where(.sonr-hd-ohlc){display:inline-flex;align-items:center;gap:8px;font-variant-numeric:tabular-nums;}
16289
16415
  :where(.sonr-hd-cell){display:inline-flex;align-items:baseline;gap:3px;}
@@ -16291,6 +16417,8 @@ var CSS = `
16291
16417
  :where(.sonr-hd-v){color:#555;}
16292
16418
  :where(.sonr-hd-up){color:#22a06b;}
16293
16419
  :where(.sonr-hd-down){color:#d23c3c;}
16420
+ :where(.sonr-hd-trend){flex-basis:100%;display:inline-flex;align-items:baseline;gap:4px;margin-top:2px;}
16421
+ :where(.sonr-hd-mixed){color:#c98a1b;}
16294
16422
  :where(.sonr-brand){position:absolute;z-index:3;pointer-events:none;font-family:inherit;font-weight:700;font-size:13px;letter-spacing:0.02em;color:#000;user-select:none;line-height:1;}
16295
16423
  :where(.sonr-brand-img){display:block;}
16296
16424
  :where(.sonr-brand-link){pointer-events:auto;color:inherit;text-decoration:none;}
@@ -16466,6 +16594,10 @@ var DEFAULT_LABELS = {
16466
16594
  zoomIn: "Zoom in",
16467
16595
  fitContent: "Fit all data",
16468
16596
  goToRealtime: "Go to realtime",
16597
+ volumeTrend: "Vol trend",
16598
+ volumeTrendIncreasing: "Increasing",
16599
+ volumeTrendDecreasing: "Decreasing",
16600
+ volumeTrendMixed: "Mixed",
16469
16601
  marketPre: "Pre-market",
16470
16602
  marketOpen: "Open",
16471
16603
  marketAfter: "After-hours",
@@ -17984,6 +18116,7 @@ function SettingsModal({
17984
18116
  const [indicators2, setIndicators] = useState11([]);
17985
18117
  const [indColors, setIndColors] = useState11({});
17986
18118
  const [indParams, setIndParams] = useState11({});
18119
+ const [trendBars, setTrendBars] = useState11(DEFAULT_VOLUME_TREND_BARS);
17987
18120
  const [watermark, setWatermark] = useState11({ symbol: true, interval: true, color: "#e6ebe9", opacity: 0.06 });
17988
18121
  const [brushStyles, setBrushStyles] = useState11({
17989
18122
  brush: { color: "#e6ebe9", size: 2 },
@@ -18018,6 +18151,8 @@ function SettingsModal({
18018
18151
  }
18019
18152
  }
18020
18153
  setIndParams(params);
18154
+ setTrendBars(chartRef.current?.getVolumeTrendBars?.() ?? DEFAULT_VOLUME_TREND_BARS);
18155
+ const unsubTrendBars = chartRef.current?.subscribeVolumeTrendBars?.(setTrendBars);
18021
18156
  const readWm = () => {
18022
18157
  const w = chartRef.current?.getWatermark?.();
18023
18158
  if (w) setWatermark(w);
@@ -18060,6 +18195,7 @@ function SettingsModal({
18060
18195
  document.addEventListener("keydown", onKey);
18061
18196
  return () => {
18062
18197
  document.removeEventListener("keydown", onKey);
18198
+ unsubTrendBars?.();
18063
18199
  unsubWm?.();
18064
18200
  unsubBrush?.();
18065
18201
  unsubText?.();
@@ -18168,6 +18304,25 @@ function SettingsModal({
18168
18304
  ) })
18169
18305
  ] }),
18170
18306
  section === "indicators" && /* @__PURE__ */ jsxs14(Fragment4, { children: [
18307
+ /* @__PURE__ */ jsx15("div", { className: "sonr-set-subhead", children: L.volumeTrend }),
18308
+ /* @__PURE__ */ jsx15(Row, { label: "Bars (lookback)", children: /* @__PURE__ */ jsx15(
18309
+ "input",
18310
+ {
18311
+ type: "number",
18312
+ className: "sonr-set-num",
18313
+ min: "1",
18314
+ max: "100",
18315
+ value: trendBars,
18316
+ onChange: (e) => {
18317
+ const v = e.target.valueAsNumber;
18318
+ if (Number.isNaN(v)) return;
18319
+ const n = Math.max(1, Math.min(100, Math.floor(v)));
18320
+ setTrendBars(n);
18321
+ chartRef.current?.setVolumeTrendBars?.(n);
18322
+ }
18323
+ }
18324
+ ) }),
18325
+ /* @__PURE__ */ jsx15("div", { className: "sonr-set-subhead", children: "Active indicators" }),
18171
18326
  /* @__PURE__ */ jsx15("p", { className: "sonr-set-note", children: "An indicator must be active on the chart to change its settings \u2014 add it from the Indicators menu first." }),
18172
18327
  indicators2.length === 0 && /* @__PURE__ */ jsx15("p", { className: "sonr-set-empty", children: "No indicators active." }),
18173
18328
  indicators2.map((name) => {
@@ -18797,18 +18952,25 @@ var fmtVolume = (v) => {
18797
18952
  if (n >= 1e3) return `${(n / 1e3).toFixed(2)}K`;
18798
18953
  return `${n}`;
18799
18954
  };
18800
- function ChartHeader({ chartRef, symbol, interval, source, pricePrecision = 2, labels, className }) {
18955
+ function ChartHeader({ chartRef, symbol, interval, source, pricePrecision = 2, volumeTrend: volumeTrend2, labels, className }) {
18801
18956
  useEffect16(ensureDefaultStyles, []);
18802
18957
  const L = useMemo12(() => mergeLabels(labels), [labels]);
18803
18958
  const [bar, setBar] = useState14({ current: null, prev: null });
18959
+ const [trend, setTrend] = useState14(null);
18960
+ const trendOn = volumeTrend2 === true || typeof volumeTrend2 === "number" && volumeTrend2 > 0;
18804
18961
  useEffect16(() => {
18805
18962
  let cancelled = false;
18806
18963
  let unsub;
18964
+ let unsubTrend;
18807
18965
  const attach = () => {
18808
18966
  if (cancelled) return;
18809
18967
  const h = chartRef.current;
18810
18968
  if (h?.subscribeHeaderBar) {
18811
18969
  unsub = h.subscribeHeaderBar((current, prev) => setBar({ current, prev }));
18970
+ if (trendOn) {
18971
+ if (typeof volumeTrend2 === "number") h.setVolumeTrendBars?.(volumeTrend2);
18972
+ unsubTrend = h.subscribeVolumeTrend?.((t) => setTrend(t));
18973
+ }
18812
18974
  } else {
18813
18975
  setTimeout(attach, 50);
18814
18976
  }
@@ -18817,8 +18979,9 @@ function ChartHeader({ chartRef, symbol, interval, source, pricePrecision = 2, l
18817
18979
  return () => {
18818
18980
  cancelled = true;
18819
18981
  unsub?.();
18982
+ unsubTrend?.();
18820
18983
  };
18821
- }, [chartRef]);
18984
+ }, [chartRef, volumeTrend2, trendOn]);
18822
18985
  const k = bar.current;
18823
18986
  const up = (k?.close ?? 0) >= (k?.open ?? 0);
18824
18987
  const dirClass = up ? "sonr-hd-up" : "sonr-hd-down";
@@ -18859,6 +19022,10 @@ function ChartHeader({ chartRef, symbol, interval, source, pricePrecision = 2, l
18859
19022
  /* @__PURE__ */ jsx18("span", { className: "sonr-hd-k", children: "V" }),
18860
19023
  /* @__PURE__ */ jsx18("span", { className: "sonr-hd-v", children: fmtVolume(k.volume) })
18861
19024
  ] })
19025
+ ] }),
19026
+ trendOn && trend && /* @__PURE__ */ jsxs17("span", { className: "sonr-hd-trend", children: [
19027
+ /* @__PURE__ */ jsx18("span", { className: "sonr-hd-k", children: L.volumeTrend }),
19028
+ /* @__PURE__ */ jsx18("span", { className: trend === "increasing" ? "sonr-hd-up" : trend === "decreasing" ? "sonr-hd-down" : "sonr-hd-mixed", children: trend === "increasing" ? L.volumeTrendIncreasing : trend === "decreasing" ? L.volumeTrendDecreasing : L.volumeTrendMixed })
18862
19029
  ] })
18863
19030
  ] });
18864
19031
  }
@@ -19321,6 +19488,7 @@ var SonrChartShell = forwardRef2(function SonrChartShell2({
19321
19488
  ranges,
19322
19489
  source,
19323
19490
  exchange = source,
19491
+ volumeTrend: volumeTrend2 = true,
19324
19492
  onIntervalChange,
19325
19493
  onSymbolChange,
19326
19494
  brand,
@@ -19394,7 +19562,7 @@ var SonrChartShell = forwardRef2(function SonrChartShell2({
19394
19562
  style: { position: "absolute", inset: 0 }
19395
19563
  }
19396
19564
  ),
19397
- /* @__PURE__ */ jsx25("div", { className: "sonr-tile-header", children: /* @__PURE__ */ jsx25(ChartHeader, { chartRef, symbol, interval, source }) }),
19565
+ /* @__PURE__ */ jsx25("div", { className: "sonr-tile-header", children: /* @__PURE__ */ jsx25(ChartHeader, { chartRef, symbol, interval, source, volumeTrend: volumeTrend2, labels }) }),
19398
19566
  /* @__PURE__ */ jsx25("div", { className: "sonr-tile-nav", children: /* @__PURE__ */ jsx25(NavControlBar, { chartRef, labels }) }),
19399
19567
  brand != null && /* @__PURE__ */ jsx25(BrandMark, { position: brandCorner, opacity: brandOpacity, children: brand })
19400
19568
  ] }),
@@ -19456,6 +19624,7 @@ export {
19456
19624
  ConfirmDialog,
19457
19625
  DEFAULT_CANDLE_STYLES,
19458
19626
  DEFAULT_DRAWING_TOOLS,
19627
+ DEFAULT_HALT_BADGE,
19459
19628
  DEFAULT_INDICATOR_OPTIONS,
19460
19629
  DEFAULT_LABELS,
19461
19630
  DEFAULT_RANGES,
@@ -19463,6 +19632,7 @@ export {
19463
19632
  DEFAULT_SESSION_COLORS,
19464
19633
  DEFAULT_TIMEZONE,
19465
19634
  DEFAULT_TIMEZONES,
19635
+ DEFAULT_VOLUME_TREND_BARS,
19466
19636
  DataWindow,
19467
19637
  DrawingTemplateStore,
19468
19638
  DrawingToolbar,
@@ -19470,6 +19640,7 @@ export {
19470
19640
  EXTENDED_OVERLAYS,
19471
19641
  FIB_EXTENSION_LEVELS,
19472
19642
  GoToDateDialog,
19643
+ HALT_INDICATOR,
19473
19644
  IndicatorMenu,
19474
19645
  MarketStatus,
19475
19646
  NavControlBar,
@@ -19515,6 +19686,7 @@ export {
19515
19686
  isEditableTarget,
19516
19687
  marketStatus,
19517
19688
  mergeLabels,
19689
+ normalizeHalt,
19518
19690
  parseLocalDateTime,
19519
19691
  parseResolution,
19520
19692
  priceRangeLabel,
@@ -19533,7 +19705,8 @@ export {
19533
19705
  themeStyles,
19534
19706
  timezoneLabel,
19535
19707
  toHeikinAshi,
19536
- tradeBoxFigures
19708
+ tradeBoxFigures,
19709
+ volumeTrend
19537
19710
  };
19538
19711
  /*! Bundled license information:
19539
19712