@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/README.md +12 -4
- package/dist/index.cjs +194 -16
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +59 -3
- package/dist/index.d.ts +59 -3
- package/dist/index.js +188 -15
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
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
|
-
|
|
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
|
|
15844
|
-
|
|
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
|
-
|
|
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
|
|