lightweight-charts-indicators 0.9.0 → 0.9.1

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 CHANGED
@@ -69,6 +69,9 @@ before, and the indicator pane keeps its height across a redraw.
69
69
  - **Render options**: `inputs` (plots whose visibility follows an input), `plots` (per-plot `visible`, `color`,
70
70
  `lineWidth`, `style`, `palette`), `lastValueVisible`, `titleVisible`, `priceLineVisible`, `precision`, and
71
71
  `autoscale: false` to leave the indicator out of the price-pane autoscale.
72
+ - **Live updates**: `reuseSeries: true` keeps the series of the previous render (same indicator, bars changed at
73
+ the end). Series of the same type, pane and creation order are kept; when only their newest points changed
74
+ (or a bar was added) those points are updated instead of the whole data being set again.
72
75
 
73
76
  The demo page (`example/`) uses the same renderer.
74
77
 
package/dist/index.cjs CHANGED
@@ -169207,4 +169207,4 @@ var registryPart5 = [
169207
169207
  }
169208
169208
  ];
169209
169209
  var indicatorRegistry = [...registryPart1, ...registryPart2, ...registryPart3, ...registryPart4, ...registryPart5];
169210
- var version = "0.9.0";
169210
+ var version = "0.9.1";
package/dist/index.d.ts CHANGED
@@ -2493,5 +2493,5 @@ export interface IndicatorRegistryEntry {
2493
2493
  calculate: (bars: Bar[], inputs?: any) => any;
2494
2494
  }
2495
2495
  export declare const indicatorRegistry: IndicatorRegistryEntry[];
2496
- export declare const version = "0.9.0";
2496
+ export declare const version = "0.9.1";
2497
2497
  //# sourceMappingURL=index.d.ts.map
package/dist/index.mjs CHANGED
@@ -167004,7 +167004,7 @@ var registryPart5 = [
167004
167004
  }
167005
167005
  ];
167006
167006
  var indicatorRegistry = [...registryPart1, ...registryPart2, ...registryPart3, ...registryPart4, ...registryPart5];
167007
- var version = "0.9.0";
167007
+ var version = "0.9.1";
167008
167008
  export {
167009
167009
  ADR,
167010
167010
  ADX,
@@ -55,6 +55,12 @@ export interface RenderOptions {
55
55
  precision?: number | null;
56
56
  /** Series in the price pane take part in its autoscale (default true; false = scale on the price only) */
57
57
  autoscale?: boolean;
58
+ /**
59
+ * Keep the series of the previous render (same indicator, bars changed at the end: a live update). A series of the
60
+ * same type in the same pane and creation order is kept with the new options; when only its newest points changed
61
+ * they are updated, else its data is replaced. Default false: every series is created again.
62
+ */
63
+ reuseSeries?: boolean;
58
64
  }
59
65
  export declare class IndicatorRenderer {
60
66
  private readonly chart;
@@ -70,6 +76,15 @@ export declare class IndicatorRenderer {
70
76
  private tableObserver;
71
77
  private tableFrame;
72
78
  private renderOpts;
79
+ /** Series of this render in creation order, with their type (series definition or custom pane view class) */
80
+ private created;
81
+ /** Series of the previous render a reuseSeries render can take again (by creation order); null = taken */
82
+ private pool;
83
+ private kinds;
84
+ /** Series taken from the pool in this render */
85
+ private reused;
86
+ /** Data last set on each series */
87
+ private lastData;
73
88
  constructor(chart: IChartApi, options?: IndicatorRendererOptions);
74
89
  /** Pane of a non-overlay indicator for the next render() */
75
90
  setPaneIndex(paneIndex: number): void;
@@ -80,14 +95,22 @@ export declare class IndicatorRenderer {
80
95
  * redraw (its height is not lost).
81
96
  */
82
97
  render(entry: RenderableIndicator, result: IndicatorResult, bars: Bar[], options?: RenderOptions): void;
98
+ private draw;
83
99
  /** Remove everything this instance drew (and its pane when it becomes empty, unless preserveEmptyPane) */
84
100
  clear(): void;
101
+ /** Remove what the last render drew; `keepSeries`: its series go to the pool instead (reuseSeries) */
85
102
  private clearOwned;
86
103
  /** Options of a series in `pane`: left out of the autoscale in the price pane when autoscale is off */
87
104
  private scaleOptions;
88
105
  /** Plot series options from the render options (labels on the price scale, precision) */
89
106
  private plotOptions;
90
107
  private own;
108
+ /** The pool series of this creation slot when it has the same type and pane (options re-applied), else null */
109
+ private take;
110
+ private addSeries;
111
+ private addCustomSeries;
112
+ /** Series data; a reused series whose newest points alone changed (or that has new bars) gets them as updates */
113
+ private setData;
91
114
  private attach;
92
115
  /** Invisible line series that holds primitives (and, with autoscale, the price range of what they draw) */
93
116
  private anchor;
@@ -1 +1 @@
1
- {"version":3,"file":"renderer.d.ts","sourceRoot":"","sources":["../../src/render/renderer.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"renderer.d.ts","sourceRoot":"","sources":["../../src/render/renderer.ts"],"names":[],"mappings":"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"}
package/dist/render.mjs CHANGED
@@ -1606,6 +1606,15 @@ var IndicatorRenderer = class {
1606
1606
  tableObserver = null;
1607
1607
  tableFrame = 0;
1608
1608
  renderOpts = {};
1609
+ /** Series of this render in creation order, with their type (series definition or custom pane view class) */
1610
+ created = [];
1611
+ /** Series of the previous render a reuseSeries render can take again (by creation order); null = taken */
1612
+ pool = [];
1613
+ kinds = /* @__PURE__ */ new WeakMap();
1614
+ /** Series taken from the pool in this render */
1615
+ reused = /* @__PURE__ */ new Set();
1616
+ /** Data last set on each series */
1617
+ lastData = /* @__PURE__ */ new WeakMap();
1609
1618
  /** Pane of a non-overlay indicator for the next render() */
1610
1619
  setPaneIndex(paneIndex) {
1611
1620
  this.opts.paneIndex = paneIndex;
@@ -1623,14 +1632,21 @@ var IndicatorRenderer = class {
1623
1632
  const paneApi = pane > 0 ? this.chart.panes()[pane] : void 0;
1624
1633
  const preserved = paneApi?.preserveEmptyPane();
1625
1634
  paneApi?.setPreserveEmptyPane(true);
1626
- this.clearOwned();
1627
- if (paneApi && !this.opts.preserveEmptyPane)
1628
- paneApi.setPreserveEmptyPane(preserved ?? false);
1629
- this.renderOpts = options;
1630
- this.grid.setBars(bars);
1631
- if (!bars.length)
1632
- return;
1633
- const r = result;
1635
+ try {
1636
+ this.clearOwned(options.reuseSeries === true);
1637
+ this.renderOpts = options;
1638
+ this.grid.setBars(bars);
1639
+ if (bars.length)
1640
+ this.draw(entry, result, bars, pane);
1641
+ } finally {
1642
+ for (const p of this.pool.splice(0))
1643
+ if (p)
1644
+ this.chart.removeSeries(p.series);
1645
+ if (paneApi && !this.opts.preserveEmptyPane)
1646
+ paneApi.setPreserveEmptyPane(preserved ?? false);
1647
+ }
1648
+ }
1649
+ draw(entry, r, bars, pane) {
1634
1650
  this.drawPlots(entry, r, pane);
1635
1651
  this.drawHLines(entry, r, pane, bars);
1636
1652
  if (r.fills?.length) {
@@ -1682,15 +1698,21 @@ var IndicatorRenderer = class {
1682
1698
  this.chart.removePane(i);
1683
1699
  }
1684
1700
  }
1685
- clearOwned() {
1701
+ /** Remove what the last render drew; `keepSeries`: its series go to the pool instead (reuseSeries) */
1702
+ clearOwned(keepSeries = false) {
1686
1703
  for (const { series, primitive } of this.attached)
1687
1704
  series.detachPrimitive(primitive);
1688
1705
  this.attached = [];
1689
1706
  for (const p of this.markerPlugins)
1690
1707
  p.detach();
1691
1708
  this.markerPlugins = [];
1692
- for (const s of this.series())
1693
- this.chart.removeSeries(s);
1709
+ if (keepSeries)
1710
+ this.pool = this.created;
1711
+ else
1712
+ for (const s of this.series())
1713
+ this.chart.removeSeries(s);
1714
+ this.created = [];
1715
+ this.reused.clear();
1694
1716
  this.plotSeries = [];
1695
1717
  this.otherSeries = [];
1696
1718
  for (const { el } of this.tables)
@@ -1719,16 +1741,58 @@ var IndicatorRenderer = class {
1719
1741
  };
1720
1742
  }
1721
1743
  own(series, plot = false) {
1722
- (plot ? this.plotSeries : this.otherSeries).push(series);
1744
+ const s = series;
1745
+ (plot ? this.plotSeries : this.otherSeries).push(s);
1746
+ this.created.push({ series: s, kind: this.kinds.get(s) });
1747
+ return series;
1748
+ }
1749
+ /** The pool series of this creation slot when it has the same type and pane (options re-applied), else null */
1750
+ take(kind, pane, options) {
1751
+ const slot = this.created.length;
1752
+ const p = this.pool[slot];
1753
+ if (!p || p.kind !== kind || p.series.getPane().paneIndex() !== pane)
1754
+ return null;
1755
+ this.pool[slot] = null;
1756
+ p.series.applyOptions(options);
1757
+ this.reused.add(p.series);
1758
+ return p.series;
1759
+ }
1760
+ addSeries(definition, options, pane) {
1761
+ const reused = this.take(definition, pane, options);
1762
+ if (reused)
1763
+ return reused;
1764
+ const series = this.chart.addSeries(definition, options, pane);
1765
+ this.kinds.set(series, definition);
1766
+ return series;
1767
+ }
1768
+ addCustomSeries(view, options, pane) {
1769
+ const reused = this.take(view.constructor, pane, options);
1770
+ if (reused)
1771
+ return reused;
1772
+ const series = this.chart.addCustomSeries(view, options, pane);
1773
+ this.kinds.set(series, view.constructor);
1723
1774
  return series;
1724
1775
  }
1776
+ /** Series data; a reused series whose newest points alone changed (or that has new bars) gets them as updates */
1777
+ setData(series, data) {
1778
+ const s = series;
1779
+ const old = this.reused.has(s) ? this.lastData.get(s) : void 0;
1780
+ this.lastData.set(s, data);
1781
+ const from = old ? changedTail(old, data) : -1;
1782
+ if (from < 0) {
1783
+ s.setData(data);
1784
+ return;
1785
+ }
1786
+ for (let i = from; i < data.length; i++)
1787
+ s.update(data[i], i < old.length - 1);
1788
+ }
1725
1789
  attach(series, primitive) {
1726
1790
  series.attachPrimitive(primitive);
1727
1791
  this.attached.push({ series, primitive });
1728
1792
  }
1729
1793
  /** Invisible line series that holds primitives (and, with autoscale, the price range of what they draw) */
1730
1794
  anchor(pane, autoscale = true) {
1731
- return this.own(this.chart.addSeries(LineSeries, {
1795
+ return this.own(this.addSeries(LineSeries, {
1732
1796
  color: "transparent",
1733
1797
  lineVisible: false,
1734
1798
  lastValueVisible: false,
@@ -1801,7 +1865,7 @@ var IndicatorRenderer = class {
1801
1865
  }
1802
1866
  addLine(data, o, pane, title) {
1803
1867
  const lineWidth = o.lineWidth && o.lineWidth >= 1 ? o.lineWidth : 2;
1804
- const series = this.own(this.chart.addSeries(LineSeries, {
1868
+ const series = this.own(this.addSeries(LineSeries, {
1805
1869
  color: o.color,
1806
1870
  lineWidth,
1807
1871
  lineStyle: o.lineStyle,
@@ -1815,7 +1879,7 @@ var IndicatorRenderer = class {
1815
1879
  }, pane), true);
1816
1880
  const valid = data.filter((d) => d.value != null && !Number.isNaN(d.value));
1817
1881
  const simpleLine = (o.lineType ?? LineType.Simple) === LineType.Simple && o.lineVisible !== false && !o.pointMarkersVisible;
1818
- series.setData(simpleLine ? segmentColors(valid, o.color) : valid);
1882
+ this.setData(series, simpleLine ? segmentColors(valid, o.color) : valid);
1819
1883
  return series;
1820
1884
  }
1821
1885
  /**
@@ -1835,14 +1899,15 @@ var IndicatorRenderer = class {
1835
1899
  }
1836
1900
  /** plot.style_histogram: bars of the plot line width from histbase (thin histogram series) */
1837
1901
  addThinHistogram(data, color, lineWidth, base, pane, title) {
1838
- const series = this.own(this.chart.addCustomSeries(new ThinHistogramPaneView(), {
1902
+ const series = this.own(this.addCustomSeries(new ThinHistogramPaneView(), {
1839
1903
  histColor: color,
1840
1904
  histWidth: Math.max(1, lineWidth ?? 1),
1841
1905
  histBase: base,
1842
1906
  ...this.plotOptions(title),
1843
1907
  ...this.scaleOptions(pane)
1844
1908
  }, pane), true);
1845
- series.setData(
1909
+ this.setData(
1910
+ series,
1846
1911
  data.map((d) => {
1847
1912
  const time = d.time;
1848
1913
  if (d.value == null || Number.isNaN(d.value))
@@ -1853,17 +1918,17 @@ var IndicatorRenderer = class {
1853
1918
  }
1854
1919
  /** plot.style_columns: bars of the bar slot width from histbase */
1855
1920
  addColumns(data, color, base, pane, title) {
1856
- const series = this.own(this.chart.addSeries(HistogramSeries, {
1921
+ const series = this.own(this.addSeries(HistogramSeries, {
1857
1922
  color,
1858
1923
  base,
1859
1924
  ...this.plotOptions(title),
1860
1925
  ...this.scaleOptions(pane)
1861
1926
  }, pane), true);
1862
- series.setData(data.filter((d) => d.value != null && !Number.isNaN(d.value)));
1927
+ this.setData(series, data.filter((d) => d.value != null && !Number.isNaN(d.value)));
1863
1928
  }
1864
1929
  addCross(data, color, lineWidth, pane) {
1865
1930
  const anchor = this.anchor(pane);
1866
- anchor.setData(data.filter((d) => d.value != null && !Number.isNaN(d.value)));
1931
+ this.setData(anchor, data.filter((d) => d.value != null && !Number.isNaN(d.value)));
1867
1932
  const primitive = new CrossPlotPrimitive();
1868
1933
  this.attach(anchor, primitive);
1869
1934
  primitive.setData(data, color, (lineWidth ?? 2) * 3);
@@ -1871,7 +1936,7 @@ var IndicatorRenderer = class {
1871
1936
  /** linebr / steplinebr: a line that breaks at na values */
1872
1937
  addLineBr(data, color, lineWidth, lineStyle, steps, pane) {
1873
1938
  const anchor = this.anchor(pane);
1874
- anchor.setData(data.filter((d) => d.value != null && !Number.isNaN(d.value)));
1939
+ this.setData(anchor, data.filter((d) => d.value != null && !Number.isNaN(d.value)));
1875
1940
  const primitive = new LineBrPrimitive();
1876
1941
  this.attach(anchor, primitive);
1877
1942
  primitive.setData(data, color, lineWidth ?? 2, lineStyle, steps);
@@ -1892,7 +1957,7 @@ var IndicatorRenderer = class {
1892
1957
  for (const h of hlines) {
1893
1958
  if (h.display === "none")
1894
1959
  continue;
1895
- const series = this.own(this.chart.addSeries(LineSeries, {
1960
+ const series = this.own(this.addSeries(LineSeries, {
1896
1961
  color: h.color ?? "#787B86",
1897
1962
  lineWidth: h.linewidth ?? 1,
1898
1963
  lineStyle: LINE_STYLES[h.linestyle ?? "solid"] ?? LineStyle.Solid,
@@ -1901,7 +1966,7 @@ var IndicatorRenderer = class {
1901
1966
  priceLineVisible: false,
1902
1967
  ...this.scaleOptions(pane)
1903
1968
  }, pane));
1904
- series.setData([{ time: first, value: h.price }, { time: last, value: h.price }]);
1969
+ this.setData(series, [{ time: first, value: h.price }, { time: last, value: h.price }]);
1905
1970
  }
1906
1971
  if (!entry.hlineConfig?.length)
1907
1972
  return;
@@ -1936,7 +2001,7 @@ var IndicatorRenderer = class {
1936
2001
  const gradient = fill.gradient;
1937
2002
  const colors = fill.colors;
1938
2003
  const anchor = this.anchor(pane);
1939
- anchor.setData(bars.map((b) => ({ time: b.time, value: Math.max(p1, p2) })));
2004
+ this.setData(anchor, bars.map((b) => ({ time: b.time, value: Math.max(p1, p2) })));
1940
2005
  const primitive = new PlotFillPrimitive();
1941
2006
  primitive.setData(bars.map((b, i) => ({
1942
2007
  time: b.time,
@@ -1949,7 +2014,7 @@ var IndicatorRenderer = class {
1949
2014
  continue;
1950
2015
  }
1951
2016
  const color = fill.color ?? "rgba(41,98,255,0.1)";
1952
- const series = this.own(this.chart.addSeries(BaselineSeries, {
2017
+ const series = this.own(this.addSeries(BaselineSeries, {
1953
2018
  baseValue: { type: "price", price: Math.min(p1, p2) },
1954
2019
  topFillColor1: color,
1955
2020
  topFillColor2: color,
@@ -1963,7 +2028,7 @@ var IndicatorRenderer = class {
1963
2028
  crosshairMarkerVisible: false,
1964
2029
  ...this.scaleOptions(pane)
1965
2030
  }, pane));
1966
- series.setData([
2031
+ this.setData(series, [
1967
2032
  { time: first, value: Math.max(p1, p2) },
1968
2033
  { time: last, value: Math.max(p1, p2) }
1969
2034
  ]);
@@ -2012,7 +2077,7 @@ var IndicatorRenderer = class {
2012
2077
  continue;
2013
2078
  const bothOverlay = overlayPlots.has(String(fill.plot1)) && overlayPlots.has(String(fill.plot2));
2014
2079
  const anchor = this.anchor(bothOverlay ? 0 : pane);
2015
- anchor.setData(valid.map((p) => ({ time: p.time, value: Math.max(p.v1, p.v2) })));
2080
+ this.setData(anchor, valid.map((p) => ({ time: p.time, value: Math.max(p.v1, p.v2) })));
2016
2081
  const primitive = new PlotFillPrimitive();
2017
2082
  primitive.setData(points);
2018
2083
  this.attach(anchor, primitive);
@@ -2058,7 +2123,7 @@ var IndicatorRenderer = class {
2058
2123
  if (onPrice.native.length || onPrice.extended.length) {
2059
2124
  const target = main ?? this.anchor(0, false);
2060
2125
  if (!main)
2061
- target.setData(anchorData(this.grid.bars.map((b) => ({ time: b.time, value: b.close })), this.grid));
2126
+ this.setData(target, anchorData(this.grid.bars.map((b) => ({ time: b.time, value: b.close })), this.grid));
2062
2127
  if (onPrice.native.length)
2063
2128
  this.markerPlugins.push(createSeriesMarkers(target, onPrice.native));
2064
2129
  if (onPrice.extended.length) {
@@ -2071,7 +2136,7 @@ var IndicatorRenderer = class {
2071
2136
  if (paneMarkers.length) {
2072
2137
  const parts = split(paneMarkers, true);
2073
2138
  const anchor = this.anchor(pane);
2074
- anchor.setData(anchorData(paneMarkers.map((m) => ({ time: m.time, value: m.price })), this.grid));
2139
+ this.setData(anchor, anchorData(paneMarkers.map((m) => ({ time: m.time, value: m.price })), this.grid));
2075
2140
  if (parts.native.length)
2076
2141
  this.markerPlugins.push(createSeriesMarkers(anchor, parts.native));
2077
2142
  if (parts.extended.length) {
@@ -2125,7 +2190,7 @@ var IndicatorRenderer = class {
2125
2190
  const anchor = this.anchor(p, false);
2126
2191
  const first = list[0].time;
2127
2192
  const last = list[list.length - 1].time;
2128
- anchor.setData((first === last ? [first] : [first, last]).map((time) => ({ time, value: 0 })));
2193
+ this.setData(anchor, (first === last ? [first] : [first, last]).map((time) => ({ time, value: 0 })));
2129
2194
  const primitive = new BgColorPrimitive();
2130
2195
  this.attach(anchor, primitive);
2131
2196
  primitive.setData(list);
@@ -2134,7 +2199,7 @@ var IndicatorRenderer = class {
2134
2199
  /** plotcandle: a candlestick series (force_overlay candles go to the price pane) */
2135
2200
  drawCandles(_id, data, pane) {
2136
2201
  const p = data.some((d) => d.forceOverlay) ? 0 : pane;
2137
- const series = this.own(this.chart.addSeries(CandlestickSeries, {
2202
+ const series = this.own(this.addSeries(CandlestickSeries, {
2138
2203
  upColor: "#26a69a",
2139
2204
  downColor: "#ef5350",
2140
2205
  borderVisible: true,
@@ -2144,7 +2209,7 @@ var IndicatorRenderer = class {
2144
2209
  priceLineVisible: false,
2145
2210
  ...this.scaleOptions(p)
2146
2211
  }, p));
2147
- series.setData(data.map((d) => {
2212
+ this.setData(series, data.map((d) => {
2148
2213
  const time = d.time;
2149
2214
  if (![d.open, d.high, d.low, d.close].every((v) => Number.isFinite(v)))
2150
2215
  return { time };
@@ -2161,7 +2226,7 @@ var IndicatorRenderer = class {
2161
2226
  /** plotbar: an OHLC bar series in the bar colour (PineScript default colour when none) */
2162
2227
  drawBars(data, pane) {
2163
2228
  const p = data.some((d) => d.forceOverlay) ? 0 : pane;
2164
- const series = this.own(this.chart.addSeries(BarSeries, {
2229
+ const series = this.own(this.addSeries(BarSeries, {
2165
2230
  upColor: "#2962FF",
2166
2231
  downColor: "#2962FF",
2167
2232
  openVisible: true,
@@ -2170,7 +2235,7 @@ var IndicatorRenderer = class {
2170
2235
  priceLineVisible: false,
2171
2236
  ...this.scaleOptions(p)
2172
2237
  }, p));
2173
- series.setData(data.map((d) => {
2238
+ this.setData(series, data.map((d) => {
2174
2239
  const time = d.time;
2175
2240
  if (![d.open, d.high, d.low, d.close].every((v) => Number.isFinite(v)))
2176
2241
  return { time };
@@ -2192,7 +2257,7 @@ var IndicatorRenderer = class {
2192
2257
  }
2193
2258
  for (const [p, group] of groups) {
2194
2259
  const anchor = this.anchor(p, autoscale);
2195
- anchor.setData(anchorData(group.flatMap(points), this.grid));
2260
+ this.setData(anchor, anchorData(group.flatMap(points), this.grid));
2196
2261
  this.attach(anchor, new DrawingPrimitive(this.grid, group, draw, zOrder));
2197
2262
  }
2198
2263
  }
@@ -2231,7 +2296,7 @@ var IndicatorRenderer = class {
2231
2296
  const data = [];
2232
2297
  for (let i = 1; i <= k; i++)
2233
2298
  data.push({ time: this.grid.lastTime + i * this.grid.interval });
2234
- series.setData(data);
2299
+ this.setData(series, data);
2235
2300
  }
2236
2301
  // ─── Tables ───────────────────────────────────────────────────────────────
2237
2302
  /**
@@ -2290,6 +2355,36 @@ function segmentColors(data, base) {
2290
2355
  return next ? { ...d, color: next.color ?? base } : d;
2291
2356
  });
2292
2357
  }
2358
+ var TAIL_POINTS = 2;
2359
+ function changedTail(old, next) {
2360
+ const m = old.length;
2361
+ if (next.length < m || next.length - m > TAIL_POINTS)
2362
+ return -1;
2363
+ let i = 0;
2364
+ while (i < m && samePoint(old[i], next[i]))
2365
+ i++;
2366
+ if (i < m - TAIL_POINTS)
2367
+ return -1;
2368
+ for (let j = i; j < m; j++)
2369
+ if (old[j].time !== next[j].time)
2370
+ return -1;
2371
+ return i;
2372
+ }
2373
+ function samePoint(a, b) {
2374
+ if (a === b)
2375
+ return true;
2376
+ const x = a;
2377
+ const y = b;
2378
+ let n = 0;
2379
+ for (const k in y) {
2380
+ if (x[k] !== y[k])
2381
+ return false;
2382
+ n++;
2383
+ }
2384
+ for (const _ in x)
2385
+ n--;
2386
+ return n === 0;
2387
+ }
2293
2388
  function lastOutputTime(r) {
2294
2389
  let max = -Infinity;
2295
2390
  const see = (t) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lightweight-charts-indicators",
3
- "version": "0.9.0",
3
+ "version": "0.9.1",
4
4
  "type": "module",
5
5
  "description": "1290 technical analysis indicators for the lightweight-charts library",
6
6
  "main": "dist/index.cjs",