hyperprop-charting-library 0.1.102 → 0.1.103

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.
@@ -2913,6 +2913,32 @@ function createChart(element, options = {}) {
2913
2913
  }
2914
2914
  return lo;
2915
2915
  };
2916
+ const groups = /* @__PURE__ */ new Map();
2917
+ for (const marker of tradeMarkers) {
2918
+ const ms = typeof marker.time === "number" ? marker.time : Date.parse(String(marker.time));
2919
+ if (!Number.isFinite(ms)) continue;
2920
+ const index = indexForTime(ms);
2921
+ if (index === null || index < visibleStart || index > visibleEnd) continue;
2922
+ const side = marker.side === "buy" ? "buy" : "sell";
2923
+ const qty = Math.max(0, marker.qty ?? 0);
2924
+ const weight = qty > 0 ? qty : 1;
2925
+ const key = `${index}:${side}`;
2926
+ const existing = groups.get(key);
2927
+ if (existing) {
2928
+ existing.qty += qty;
2929
+ existing.priceQty += marker.price * weight;
2930
+ } else {
2931
+ groups.set(key, {
2932
+ index,
2933
+ side,
2934
+ qty,
2935
+ priceQty: marker.price * weight,
2936
+ ...marker.color === void 0 ? {} : { color: marker.color },
2937
+ ...marker.textColor === void 0 ? {} : { textColor: marker.textColor },
2938
+ ...marker.text === void 0 ? {} : { text: marker.text }
2939
+ });
2940
+ }
2941
+ }
2916
2942
  const prevFont = ctx.font;
2917
2943
  const prevAlign = ctx.textAlign;
2918
2944
  const prevBaseline = ctx.textBaseline;
@@ -2923,42 +2949,29 @@ function createChart(element, options = {}) {
2923
2949
  const arrowH = 8;
2924
2950
  const gap = 5;
2925
2951
  const labelOffset = arrowH + 8;
2926
- for (const marker of tradeMarkers) {
2927
- const ms = typeof marker.time === "number" ? marker.time : Date.parse(String(marker.time));
2928
- if (!Number.isFinite(ms)) continue;
2929
- const index = indexForTime(ms);
2930
- if (index === null || index < visibleStart || index > visibleEnd) continue;
2931
- const bar = data[index];
2952
+ for (const group of groups.values()) {
2953
+ const bar = data[group.index];
2932
2954
  if (!bar) continue;
2933
- const x = chartLeft + (index + 0.5 - xStart) / xSpan * chartWidth;
2955
+ const x = chartLeft + (group.index + 0.5 - xStart) / xSpan * chartWidth;
2934
2956
  if (x < chartLeft - 20 || x > chartRight + 20) continue;
2935
- const isBuy = marker.side === "buy";
2936
- const arrowColor = marker.color ?? (isBuy ? "#2962ff" : "#f23645");
2937
- const textColor = marker.textColor ?? "#d1d4dc";
2938
- const label = marker.text ?? `${marker.qty ?? ""}${marker.qty != null ? " @ " : ""}${formatPrice(marker.price)}`.trim();
2957
+ const isBuy = group.side === "buy";
2958
+ const arrowColor = group.color ?? (isBuy ? "#2962ff" : "#f23645");
2959
+ const textColor = group.textColor ?? "#d1d4dc";
2960
+ const weightTotal = group.qty > 0 ? group.qty : 1;
2961
+ const avgPrice = group.priceQty / weightTotal;
2962
+ const label = group.text ?? `${group.qty > 0 ? `${group.qty} @ ` : ""}${formatPrice(avgPrice)}`.trim();
2939
2963
  ctx.save();
2940
2964
  ctx.fillStyle = arrowColor;
2941
- if (isBuy) {
2942
- const tipY = yFromPrice(bar.l) + gap;
2943
- ctx.beginPath();
2944
- ctx.moveTo(x, tipY);
2945
- ctx.lineTo(x - arrowHalf, tipY + arrowH);
2946
- ctx.lineTo(x + arrowHalf, tipY + arrowH);
2947
- ctx.closePath();
2948
- ctx.fill();
2949
- ctx.fillStyle = textColor;
2950
- ctx.fillText(label, Math.round(x), Math.round(tipY + labelOffset));
2951
- } else {
2952
- const tipY = yFromPrice(bar.h) - gap;
2953
- ctx.beginPath();
2954
- ctx.moveTo(x, tipY);
2955
- ctx.lineTo(x - arrowHalf, tipY - arrowH);
2956
- ctx.lineTo(x + arrowHalf, tipY - arrowH);
2957
- ctx.closePath();
2958
- ctx.fill();
2959
- ctx.fillStyle = textColor;
2960
- ctx.fillText(label, Math.round(x), Math.round(tipY - labelOffset));
2961
- }
2965
+ const tipY = isBuy ? yFromPrice(bar.l) + gap : yFromPrice(bar.h) - gap;
2966
+ const dir = isBuy ? 1 : -1;
2967
+ ctx.beginPath();
2968
+ ctx.moveTo(x, tipY);
2969
+ ctx.lineTo(x - arrowHalf, tipY + arrowH * dir);
2970
+ ctx.lineTo(x + arrowHalf, tipY + arrowH * dir);
2971
+ ctx.closePath();
2972
+ ctx.fill();
2973
+ ctx.fillStyle = textColor;
2974
+ ctx.fillText(label, Math.round(x), Math.round(tipY + labelOffset * dir));
2962
2975
  ctx.restore();
2963
2976
  }
2964
2977
  ctx.font = prevFont;
@@ -2887,6 +2887,32 @@ function createChart(element, options = {}) {
2887
2887
  }
2888
2888
  return lo;
2889
2889
  };
2890
+ const groups = /* @__PURE__ */ new Map();
2891
+ for (const marker of tradeMarkers) {
2892
+ const ms = typeof marker.time === "number" ? marker.time : Date.parse(String(marker.time));
2893
+ if (!Number.isFinite(ms)) continue;
2894
+ const index = indexForTime(ms);
2895
+ if (index === null || index < visibleStart || index > visibleEnd) continue;
2896
+ const side = marker.side === "buy" ? "buy" : "sell";
2897
+ const qty = Math.max(0, marker.qty ?? 0);
2898
+ const weight = qty > 0 ? qty : 1;
2899
+ const key = `${index}:${side}`;
2900
+ const existing = groups.get(key);
2901
+ if (existing) {
2902
+ existing.qty += qty;
2903
+ existing.priceQty += marker.price * weight;
2904
+ } else {
2905
+ groups.set(key, {
2906
+ index,
2907
+ side,
2908
+ qty,
2909
+ priceQty: marker.price * weight,
2910
+ ...marker.color === void 0 ? {} : { color: marker.color },
2911
+ ...marker.textColor === void 0 ? {} : { textColor: marker.textColor },
2912
+ ...marker.text === void 0 ? {} : { text: marker.text }
2913
+ });
2914
+ }
2915
+ }
2890
2916
  const prevFont = ctx.font;
2891
2917
  const prevAlign = ctx.textAlign;
2892
2918
  const prevBaseline = ctx.textBaseline;
@@ -2897,42 +2923,29 @@ function createChart(element, options = {}) {
2897
2923
  const arrowH = 8;
2898
2924
  const gap = 5;
2899
2925
  const labelOffset = arrowH + 8;
2900
- for (const marker of tradeMarkers) {
2901
- const ms = typeof marker.time === "number" ? marker.time : Date.parse(String(marker.time));
2902
- if (!Number.isFinite(ms)) continue;
2903
- const index = indexForTime(ms);
2904
- if (index === null || index < visibleStart || index > visibleEnd) continue;
2905
- const bar = data[index];
2926
+ for (const group of groups.values()) {
2927
+ const bar = data[group.index];
2906
2928
  if (!bar) continue;
2907
- const x = chartLeft + (index + 0.5 - xStart) / xSpan * chartWidth;
2929
+ const x = chartLeft + (group.index + 0.5 - xStart) / xSpan * chartWidth;
2908
2930
  if (x < chartLeft - 20 || x > chartRight + 20) continue;
2909
- const isBuy = marker.side === "buy";
2910
- const arrowColor = marker.color ?? (isBuy ? "#2962ff" : "#f23645");
2911
- const textColor = marker.textColor ?? "#d1d4dc";
2912
- const label = marker.text ?? `${marker.qty ?? ""}${marker.qty != null ? " @ " : ""}${formatPrice(marker.price)}`.trim();
2931
+ const isBuy = group.side === "buy";
2932
+ const arrowColor = group.color ?? (isBuy ? "#2962ff" : "#f23645");
2933
+ const textColor = group.textColor ?? "#d1d4dc";
2934
+ const weightTotal = group.qty > 0 ? group.qty : 1;
2935
+ const avgPrice = group.priceQty / weightTotal;
2936
+ const label = group.text ?? `${group.qty > 0 ? `${group.qty} @ ` : ""}${formatPrice(avgPrice)}`.trim();
2913
2937
  ctx.save();
2914
2938
  ctx.fillStyle = arrowColor;
2915
- if (isBuy) {
2916
- const tipY = yFromPrice(bar.l) + gap;
2917
- ctx.beginPath();
2918
- ctx.moveTo(x, tipY);
2919
- ctx.lineTo(x - arrowHalf, tipY + arrowH);
2920
- ctx.lineTo(x + arrowHalf, tipY + arrowH);
2921
- ctx.closePath();
2922
- ctx.fill();
2923
- ctx.fillStyle = textColor;
2924
- ctx.fillText(label, Math.round(x), Math.round(tipY + labelOffset));
2925
- } else {
2926
- const tipY = yFromPrice(bar.h) - gap;
2927
- ctx.beginPath();
2928
- ctx.moveTo(x, tipY);
2929
- ctx.lineTo(x - arrowHalf, tipY - arrowH);
2930
- ctx.lineTo(x + arrowHalf, tipY - arrowH);
2931
- ctx.closePath();
2932
- ctx.fill();
2933
- ctx.fillStyle = textColor;
2934
- ctx.fillText(label, Math.round(x), Math.round(tipY - labelOffset));
2935
- }
2939
+ const tipY = isBuy ? yFromPrice(bar.l) + gap : yFromPrice(bar.h) - gap;
2940
+ const dir = isBuy ? 1 : -1;
2941
+ ctx.beginPath();
2942
+ ctx.moveTo(x, tipY);
2943
+ ctx.lineTo(x - arrowHalf, tipY + arrowH * dir);
2944
+ ctx.lineTo(x + arrowHalf, tipY + arrowH * dir);
2945
+ ctx.closePath();
2946
+ ctx.fill();
2947
+ ctx.fillStyle = textColor;
2948
+ ctx.fillText(label, Math.round(x), Math.round(tipY + labelOffset * dir));
2936
2949
  ctx.restore();
2937
2950
  }
2938
2951
  ctx.font = prevFont;
package/dist/index.cjs CHANGED
@@ -2913,6 +2913,32 @@ function createChart(element, options = {}) {
2913
2913
  }
2914
2914
  return lo;
2915
2915
  };
2916
+ const groups = /* @__PURE__ */ new Map();
2917
+ for (const marker of tradeMarkers) {
2918
+ const ms = typeof marker.time === "number" ? marker.time : Date.parse(String(marker.time));
2919
+ if (!Number.isFinite(ms)) continue;
2920
+ const index = indexForTime(ms);
2921
+ if (index === null || index < visibleStart || index > visibleEnd) continue;
2922
+ const side = marker.side === "buy" ? "buy" : "sell";
2923
+ const qty = Math.max(0, marker.qty ?? 0);
2924
+ const weight = qty > 0 ? qty : 1;
2925
+ const key = `${index}:${side}`;
2926
+ const existing = groups.get(key);
2927
+ if (existing) {
2928
+ existing.qty += qty;
2929
+ existing.priceQty += marker.price * weight;
2930
+ } else {
2931
+ groups.set(key, {
2932
+ index,
2933
+ side,
2934
+ qty,
2935
+ priceQty: marker.price * weight,
2936
+ ...marker.color === void 0 ? {} : { color: marker.color },
2937
+ ...marker.textColor === void 0 ? {} : { textColor: marker.textColor },
2938
+ ...marker.text === void 0 ? {} : { text: marker.text }
2939
+ });
2940
+ }
2941
+ }
2916
2942
  const prevFont = ctx.font;
2917
2943
  const prevAlign = ctx.textAlign;
2918
2944
  const prevBaseline = ctx.textBaseline;
@@ -2923,42 +2949,29 @@ function createChart(element, options = {}) {
2923
2949
  const arrowH = 8;
2924
2950
  const gap = 5;
2925
2951
  const labelOffset = arrowH + 8;
2926
- for (const marker of tradeMarkers) {
2927
- const ms = typeof marker.time === "number" ? marker.time : Date.parse(String(marker.time));
2928
- if (!Number.isFinite(ms)) continue;
2929
- const index = indexForTime(ms);
2930
- if (index === null || index < visibleStart || index > visibleEnd) continue;
2931
- const bar = data[index];
2952
+ for (const group of groups.values()) {
2953
+ const bar = data[group.index];
2932
2954
  if (!bar) continue;
2933
- const x = chartLeft + (index + 0.5 - xStart) / xSpan * chartWidth;
2955
+ const x = chartLeft + (group.index + 0.5 - xStart) / xSpan * chartWidth;
2934
2956
  if (x < chartLeft - 20 || x > chartRight + 20) continue;
2935
- const isBuy = marker.side === "buy";
2936
- const arrowColor = marker.color ?? (isBuy ? "#2962ff" : "#f23645");
2937
- const textColor = marker.textColor ?? "#d1d4dc";
2938
- const label = marker.text ?? `${marker.qty ?? ""}${marker.qty != null ? " @ " : ""}${formatPrice(marker.price)}`.trim();
2957
+ const isBuy = group.side === "buy";
2958
+ const arrowColor = group.color ?? (isBuy ? "#2962ff" : "#f23645");
2959
+ const textColor = group.textColor ?? "#d1d4dc";
2960
+ const weightTotal = group.qty > 0 ? group.qty : 1;
2961
+ const avgPrice = group.priceQty / weightTotal;
2962
+ const label = group.text ?? `${group.qty > 0 ? `${group.qty} @ ` : ""}${formatPrice(avgPrice)}`.trim();
2939
2963
  ctx.save();
2940
2964
  ctx.fillStyle = arrowColor;
2941
- if (isBuy) {
2942
- const tipY = yFromPrice(bar.l) + gap;
2943
- ctx.beginPath();
2944
- ctx.moveTo(x, tipY);
2945
- ctx.lineTo(x - arrowHalf, tipY + arrowH);
2946
- ctx.lineTo(x + arrowHalf, tipY + arrowH);
2947
- ctx.closePath();
2948
- ctx.fill();
2949
- ctx.fillStyle = textColor;
2950
- ctx.fillText(label, Math.round(x), Math.round(tipY + labelOffset));
2951
- } else {
2952
- const tipY = yFromPrice(bar.h) - gap;
2953
- ctx.beginPath();
2954
- ctx.moveTo(x, tipY);
2955
- ctx.lineTo(x - arrowHalf, tipY - arrowH);
2956
- ctx.lineTo(x + arrowHalf, tipY - arrowH);
2957
- ctx.closePath();
2958
- ctx.fill();
2959
- ctx.fillStyle = textColor;
2960
- ctx.fillText(label, Math.round(x), Math.round(tipY - labelOffset));
2961
- }
2965
+ const tipY = isBuy ? yFromPrice(bar.l) + gap : yFromPrice(bar.h) - gap;
2966
+ const dir = isBuy ? 1 : -1;
2967
+ ctx.beginPath();
2968
+ ctx.moveTo(x, tipY);
2969
+ ctx.lineTo(x - arrowHalf, tipY + arrowH * dir);
2970
+ ctx.lineTo(x + arrowHalf, tipY + arrowH * dir);
2971
+ ctx.closePath();
2972
+ ctx.fill();
2973
+ ctx.fillStyle = textColor;
2974
+ ctx.fillText(label, Math.round(x), Math.round(tipY + labelOffset * dir));
2962
2975
  ctx.restore();
2963
2976
  }
2964
2977
  ctx.font = prevFont;
package/dist/index.js CHANGED
@@ -2887,6 +2887,32 @@ function createChart(element, options = {}) {
2887
2887
  }
2888
2888
  return lo;
2889
2889
  };
2890
+ const groups = /* @__PURE__ */ new Map();
2891
+ for (const marker of tradeMarkers) {
2892
+ const ms = typeof marker.time === "number" ? marker.time : Date.parse(String(marker.time));
2893
+ if (!Number.isFinite(ms)) continue;
2894
+ const index = indexForTime(ms);
2895
+ if (index === null || index < visibleStart || index > visibleEnd) continue;
2896
+ const side = marker.side === "buy" ? "buy" : "sell";
2897
+ const qty = Math.max(0, marker.qty ?? 0);
2898
+ const weight = qty > 0 ? qty : 1;
2899
+ const key = `${index}:${side}`;
2900
+ const existing = groups.get(key);
2901
+ if (existing) {
2902
+ existing.qty += qty;
2903
+ existing.priceQty += marker.price * weight;
2904
+ } else {
2905
+ groups.set(key, {
2906
+ index,
2907
+ side,
2908
+ qty,
2909
+ priceQty: marker.price * weight,
2910
+ ...marker.color === void 0 ? {} : { color: marker.color },
2911
+ ...marker.textColor === void 0 ? {} : { textColor: marker.textColor },
2912
+ ...marker.text === void 0 ? {} : { text: marker.text }
2913
+ });
2914
+ }
2915
+ }
2890
2916
  const prevFont = ctx.font;
2891
2917
  const prevAlign = ctx.textAlign;
2892
2918
  const prevBaseline = ctx.textBaseline;
@@ -2897,42 +2923,29 @@ function createChart(element, options = {}) {
2897
2923
  const arrowH = 8;
2898
2924
  const gap = 5;
2899
2925
  const labelOffset = arrowH + 8;
2900
- for (const marker of tradeMarkers) {
2901
- const ms = typeof marker.time === "number" ? marker.time : Date.parse(String(marker.time));
2902
- if (!Number.isFinite(ms)) continue;
2903
- const index = indexForTime(ms);
2904
- if (index === null || index < visibleStart || index > visibleEnd) continue;
2905
- const bar = data[index];
2926
+ for (const group of groups.values()) {
2927
+ const bar = data[group.index];
2906
2928
  if (!bar) continue;
2907
- const x = chartLeft + (index + 0.5 - xStart) / xSpan * chartWidth;
2929
+ const x = chartLeft + (group.index + 0.5 - xStart) / xSpan * chartWidth;
2908
2930
  if (x < chartLeft - 20 || x > chartRight + 20) continue;
2909
- const isBuy = marker.side === "buy";
2910
- const arrowColor = marker.color ?? (isBuy ? "#2962ff" : "#f23645");
2911
- const textColor = marker.textColor ?? "#d1d4dc";
2912
- const label = marker.text ?? `${marker.qty ?? ""}${marker.qty != null ? " @ " : ""}${formatPrice(marker.price)}`.trim();
2931
+ const isBuy = group.side === "buy";
2932
+ const arrowColor = group.color ?? (isBuy ? "#2962ff" : "#f23645");
2933
+ const textColor = group.textColor ?? "#d1d4dc";
2934
+ const weightTotal = group.qty > 0 ? group.qty : 1;
2935
+ const avgPrice = group.priceQty / weightTotal;
2936
+ const label = group.text ?? `${group.qty > 0 ? `${group.qty} @ ` : ""}${formatPrice(avgPrice)}`.trim();
2913
2937
  ctx.save();
2914
2938
  ctx.fillStyle = arrowColor;
2915
- if (isBuy) {
2916
- const tipY = yFromPrice(bar.l) + gap;
2917
- ctx.beginPath();
2918
- ctx.moveTo(x, tipY);
2919
- ctx.lineTo(x - arrowHalf, tipY + arrowH);
2920
- ctx.lineTo(x + arrowHalf, tipY + arrowH);
2921
- ctx.closePath();
2922
- ctx.fill();
2923
- ctx.fillStyle = textColor;
2924
- ctx.fillText(label, Math.round(x), Math.round(tipY + labelOffset));
2925
- } else {
2926
- const tipY = yFromPrice(bar.h) - gap;
2927
- ctx.beginPath();
2928
- ctx.moveTo(x, tipY);
2929
- ctx.lineTo(x - arrowHalf, tipY - arrowH);
2930
- ctx.lineTo(x + arrowHalf, tipY - arrowH);
2931
- ctx.closePath();
2932
- ctx.fill();
2933
- ctx.fillStyle = textColor;
2934
- ctx.fillText(label, Math.round(x), Math.round(tipY - labelOffset));
2935
- }
2939
+ const tipY = isBuy ? yFromPrice(bar.l) + gap : yFromPrice(bar.h) - gap;
2940
+ const dir = isBuy ? 1 : -1;
2941
+ ctx.beginPath();
2942
+ ctx.moveTo(x, tipY);
2943
+ ctx.lineTo(x - arrowHalf, tipY + arrowH * dir);
2944
+ ctx.lineTo(x + arrowHalf, tipY + arrowH * dir);
2945
+ ctx.closePath();
2946
+ ctx.fill();
2947
+ ctx.fillStyle = textColor;
2948
+ ctx.fillText(label, Math.round(x), Math.round(tipY + labelOffset * dir));
2936
2949
  ctx.restore();
2937
2950
  }
2938
2951
  ctx.font = prevFont;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "hyperprop-charting-library",
3
- "version": "0.1.102",
3
+ "version": "0.1.103",
4
4
  "description": "Lightweight TypeScript charting core",
5
5
  "type": "module",
6
6
  "main": "./dist/hyperprop-charting-library.cjs",