UNPKG

lwc-plugin-elliott-waves

Version:

540 lines (539 loc) 18.3 kB
var I = Object.defineProperty; var S = (i, e, t) => e in i ? I(i, e, { enumerable: !0, configurable: !0, writable: !0, value: t }) : i[e] = t; var o = (i, e, t) => (S(i, typeof e != "symbol" ? e + "" : e, t), t); import { isBusinessDay as L, CrosshairMode as g } from "lightweight-charts"; const b = { //* Define the default values for all the primitive options. interval: "M", fillColor: "rgba(200, 50, 100, 0.75)", labelColor: "rgba(200, 50, 100, 1)", labelTextColor: "white", showLabels: !0, priceLabelFormatter: (i) => i.toFixed(2), timeLabelFormatter: (i) => typeof i == "string" ? i : (L(i) ? new Date(i.year, i.month, i.day) : new Date(i * 1e3)).toLocaleDateString() }; function U(i) { return Math.floor(i * 0.5); } function P(i, e, t = 1, s) { const r = Math.round(e * i), a = s ? t : Math.round(t * e), c = U(a); return { position: r - c, length: a }; } const w = 5.81, x = 20, f = 9; new Path2D( "M9.35359 1.35359C9.11789 1.11789 8.88219 0.882187 8.64648 0.646484L5.00004 4.29293L1.35359 0.646484C1.11791 0.882212 0.882212 1.11791 0.646484 1.35359L4.29293 5.00004L0.646484 8.64648C0.882336 8.88204 1.11804 9.11774 1.35359 9.35359L5.00004 5.70714L8.64648 9.35359C8.88217 9.11788 9.11788 8.88217 9.35359 8.64649L5.70714 5.00004L9.35359 1.35359Z" ); new Path2D( "M5.34004 1.12254C4.7902 0.438104 3.94626 0 3 0C1.34315 0 0 1.34315 0 3C0 3.94626 0.438104 4.7902 1.12254 5.34004C1.04226 5.714 1 6.10206 1 6.5C1 9.36902 3.19675 11.725 6 11.9776V10.9725C3.75002 10.7238 2 8.81628 2 6.5C2 4.01472 4.01472 2 6.5 2C8.81628 2 10.7238 3.75002 10.9725 6H11.9776C11.9574 5.77589 11.9237 5.55565 11.8775 5.34011C12.562 4.79026 13.0001 3.9463 13.0001 3C13.0001 1.34315 11.6569 0 10.0001 0C9.05382 0 8.20988 0.438111 7.66004 1.12256C7.28606 1.04227 6.89797 1 6.5 1C6.10206 1 5.714 1.04226 5.34004 1.12254ZM4.28255 1.46531C3.93534 1.17484 3.48809 1 3 1C1.89543 1 1 1.89543 1 3C1 3.48809 1.17484 3.93534 1.46531 4.28255C2.0188 3.02768 3.02768 2.0188 4.28255 1.46531ZM8.71751 1.46534C9.97237 2.01885 10.9812 3.02774 11.5347 4.28262C11.8252 3.93541 12.0001 3.48812 12.0001 3C12.0001 1.89543 11.1047 1 10.0001 1C9.51199 1 9.06472 1.17485 8.71751 1.46534Z" ); class R { constructor(e, t) { o(this, "_pivot"); o(this, "_fillColor"); this._pivot = e, this._fillColor = t; } draw(e) { e.useBitmapCoordinateSpace((t) => { this._drawPivotPicker(t); }); } _calculateLabelWidth(e) { return f * 2 + e * w; } _drawPivotPicker(e) { if (!this._pivot) return; const t = e.context, s = P(this._pivot.x, e.horizontalPixelRatio, 12), r = P(this._pivot.y, e.verticalPixelRatio, 12); t.beginPath(), t.roundRect(s.position, r.position, 20, 20, 20 * e.horizontalPixelRatio), t.strokeStyle = "#00FF00", t.lineWidth = 1 * e.horizontalPixelRatio, t.stroke(); } _drawTradingLineLabels(e) { if (!this._pivot) return; const t = e.context, s = " 1 ", r = this._calculateLabelWidth(s.length), a = P(this._pivot.x, e.horizontalPixelRatio, r), c = P(this._pivot.y, e.verticalPixelRatio, x), l = 4 * e.horizontalPixelRatio; t.beginPath(), t.roundRect(a.position, c.position, a.length, c.length, l), t.fillStyle = "#FFFFFF", t.fill(), t.beginPath(), t.roundRect(a.position, c.position, a.length, c.length, l), t.strokeStyle = "#131722", t.lineWidth = 1 * e.horizontalPixelRatio, t.stroke(), t.beginPath(), t.fillStyle = "#131722", t.textBaseline = "middle", t.font = `${Math.round(12 * e.verticalPixelRatio)}px sans-serif`, t.fillText( s, a.position + f * e.horizontalPixelRatio, this._pivot.y * e.verticalPixelRatio ); } } var p = /* @__PURE__ */ ((i) => (i[i.HIGH = 1] = "HIGH", i[i.LOW = -1] = "LOW", i))(p || {}), d = /* @__PURE__ */ ((i) => (i[i._1 = 1] = "_1", i[i._2 = 2] = "_2", i[i._3 = 3] = "_3", i[i._4 = 4] = "_4", i[i._5 = 5] = "_5", i[i._A = 6] = "_A", i[i._B = 7] = "_B", i[i._C = 8] = "_C", i[i._D = 9] = "_D", i[i._E = 10] = "_E", i))(d || {}), n = /* @__PURE__ */ ((i) => (i[i.MINISCULE = 1] = "MINISCULE", i[i.SUBMICRO = 2] = "SUBMICRO", i[i.MICRO = 3] = "MICRO", i[i.SUBMINUETTE = 4] = "SUBMINUETTE", i[i.MINUETTE = 5] = "MINUETTE", i[i.MINUTE = 6] = "MINUTE", i[i.MINOR = 7] = "MINOR", i[i.INTERMEDIATE = 8] = "INTERMEDIATE", i[i.PRIMARY = 9] = "PRIMARY", i[i.CYCLE = 10] = "CYCLE", i[i.SUPERCYCLE = 11] = "SUPERCYCLE", i[i.GRANDSUPERCYCLE = 12] = "GRANDSUPERCYCLE", i[i.SUBMILLENNIUM = 13] = "SUBMILLENNIUM", i[i.MILLENNIUM = 14] = "MILLENNIUM", i[i.SUPERMILLENNIUM = 15] = "SUPERMILLENNIUM", i))(n || {}); class _ { constructor() { o(this, "_listeners", []); } subscribe(e, t, s) { const r = { callback: e, linkedObject: t, singleshot: s === !0 }; this._listeners.push(r); } unsubscribe(e) { const t = this._listeners.findIndex( (s) => e === s.callback ); t > -1 && this._listeners.splice(t, 1); } unsubscribeAll(e) { this._listeners = this._listeners.filter( (t) => t.linkedObject !== e ); } fire(e) { const t = [...this._listeners]; this._listeners = this._listeners.filter( (s) => !s.singleshot ), t.forEach( (s) => s.callback(e) ); } hasListeners() { return this._listeners.length > 0; } destroy() { this._listeners = []; } } class N { constructor(e) { o(this, "_source"); o(this, "_pivot"); o(this, "_pivotChanged", new _()); this._source = e, this._pivot = null; } isHover(e, t) { return null; } pivotChanged() { return this._pivotChanged; } update() { const { mousePosition: e, series: t, isSelectingPivot: s } = this._source, r = t.dataByIndex(e.logical); if (r) if (s) { const a = t.priceToCoordinate(r.high), c = t.priceToCoordinate(r.low), l = a > e.y ? p.HIGH : p.LOW, u = l == p.HIGH ? a : c; this._pivot = { x: e.x2, y: u, type: l }; const h = l == p.HIGH ? r.high : r.low; this._pivotChanged.fire({ time: r.time, price: h }); } else this._pivot = null; } renderer() { return new R(this._pivot, this._source.options.fillColor); } } function m(i) { if (i === void 0) throw new Error("Value is undefined"); return i; } class T { constructor() { o(this, "_chart"); o(this, "_series"); o(this, "_requestUpdate"); } requestUpdate() { this._requestUpdate && this._requestUpdate(); } attached({ chart: e, series: t, requestUpdate: s }) { this._chart = e, this._series = t, this._series.subscribeDataChanged(this._fireDataUpdated), this._requestUpdate = s, this.requestUpdate(); } detached() { this._chart = void 0, this._series = void 0, this._requestUpdate = void 0; } get chart() { return m(this._chart); } get series() { return m(this._series); } _fireDataUpdated(e) { this.dataUpdated && this.dataUpdated(e); } } class y { constructor() { o(this, "_chart"); o(this, "_series"); o(this, "_unSubscribers", []); o(this, "_clicked", new _()); o(this, "_down", new _()); o(this, "_up", new _()); o(this, "_mouseMoved", new _()); } attached(e, t) { this._chart = e, this._series = t; const s = this._chart.chartElement(); this._addMouseEventListener(s, "mouseleave", this._mouseLeave), this._addMouseEventListener(s, "mousemove", this._mouseMove), this._addMouseEventListener(s, "click", this._mouseClick), this._addMouseEventListener(s, "mousedown", this._mouseDown), this._addMouseEventListener(s, "mouseup", this._mouseUp); } detached() { this._series = void 0, this._clicked.destroy(), this._down.destroy(), this._up.destroy(), this._mouseMoved.destroy(), this._unSubscribers.forEach((e) => { e(); }), this._unSubscribers = []; } clicked() { return this._clicked; } mouseMoved() { return this._mouseMoved; } dragStarted() { return this._down; } dragging() { return this._mouseMoved; } dragEnded() { return this._up; } _addMouseEventListener(e, t, s) { const r = s.bind(this); e.addEventListener(t, r); const a = () => { e.removeEventListener(t, r); }; this._unSubscribers.push(a); } _mouseLeave() { this._mouseMoved.fire(null); } _mouseMove(e) { this._mouseMoved.fire(this._determineMousePosition(e)); } _mouseClick(e) { this._clicked.fire(this._determineMousePosition(e)); } _mouseDown(e) { this._down.fire(this._determineMousePosition(e)); } _mouseUp(e) { this._up.fire(this._determineMousePosition(e)); } _determineMousePosition(e) { if (!this._chart || !this._series) return null; const t = this._chart.chartElement(), s = t.getBoundingClientRect(), r = this._series.priceScale().width(), a = this._chart.timeScale().height(), c = e.clientX - s.x, l = e.clientY - s.y, u = l > t.clientHeight - a, h = t.clientWidth - r - c, v = h < 0, C = this._chart.timeScale().coordinateToLogical(c), M = this._chart.timeScale().logicalToCoordinate(C); return { x: c, x2: M, logical: C, y: l, xPositionRelativeToPriceScale: h, overPriceScale: v, overTimeScale: u }; } } class H { constructor(e) { o(this, "_pivots"); this._pivots = e; } draw(e) { e.useBitmapCoordinateSpace((t) => { this._drawPivots(t, this._pivots); }); } _drawPivots(e, t) { t.forEach((s) => { this._drawPivot(e, s); }); } _getPivotText(e) { var t; switch (e.wave) { case d._A: return "A"; case d._B: return "B"; case d._C: return "C"; case d._D: return "D"; case d._E: return "D"; } return ((t = e.wave) == null ? void 0 : t.toString()) || "- "; } _getDegreeColor(e) { switch (e.degree) { case n.SUPERMILLENNIUM: return "red"; case n.MILLENNIUM: return "#FF7900"; case n.SUBMILLENNIUM: return "blue"; case n.GRANDSUPERCYCLE: return "darkblue"; case n.SUPERCYCLE: return "olive"; case n.CYCLE: return "teal"; case n.PRIMARY: return "maroon"; case n.INTERMEDIATE: return "black"; case n.MINOR: return "blue"; case n.MINUTE: return "pink"; case n.MINUETTE: return "green"; case n.SUBMINUETTE: return "orange"; case n.MICRO: return "purple"; case n.SUBMICRO: return "aqua"; case n.MINISCULE: return "red"; } return "red"; } _getDegreeFontSize(e) { switch (e.degree) { case n.SUPERMILLENNIUM: return 22; case n.MILLENNIUM: return 21; case n.SUBMILLENNIUM: return 20; case n.GRANDSUPERCYCLE: return 19; case n.SUPERCYCLE: return 18; case n.CYCLE: return 17; case n.PRIMARY: return 17; case n.INTERMEDIATE: return 16; case n.MINOR: return 15; case n.MINUTE: return 14; case n.MINUETTE: return 13; case n.SUBMINUETTE: return 12; case n.MICRO: return 11; case n.SUBMICRO: return 11; case n.MINISCULE: return 11; } return 99; } _drawPivot(e, t) { const s = e.context; let r = this._getPivotText(t); const a = P(t.x, e.horizontalPixelRatio, 0), c = P(t.y, e.verticalPixelRatio, 0); s.beginPath(), t.isHover && (s.roundRect(a.position, c.position, c.length, c.length, 10), s.fillStyle = "#FF0F00", s.fill()), s.fillStyle = this._getDegreeColor(t), s.textBaseline = "middle", s.textAlign = "center"; const l = this._getDegreeFontSize(t); s.font = `${Math.round(l * e.verticalPixelRatio)}px EW-${t.degree}`, s.fillText(r, a.position, t.y * e.verticalPixelRatio); } } class B { constructor(e) { o(this, "_source"); o(this, "_pivots"); this._source = e, this._pivots = []; } /** * Defines where in the visual layer stack the renderer should be executed. Default is `'normal'`. * * @returns the desired position in the visual layer stack. @see {@link SeriesPrimitivePaneViewZOrder} */ zOrder() { return "top"; } isHover(e, t) { return this._pivots.find((s) => this._isHover(s, e, t)) || null; } _isHover(e, t, s) { return t + 10 > e.x && t - 10 < e.x && s + 10 > e.y && s - 10 < e.y; } groupPivotsByTimeAndPrice(e) { const t = {}; return e.forEach((s) => { const r = `${s.time}_${s.price}`; t[r] || (t[r] = []), t[r].push(s); }), Object.values(t); } update() { const { chart: e, series: t, mousePosition: s } = this._source, r = (l, u) => { const h = u * 30, C = (l.type === p.HIGH ? -20 - h : 20 + h) + t.priceToCoordinate(l.price), M = e.timeScale().timeToCoordinate(l.time), E = { ...l, x: M, y: C, isHover: !1 }; return this._isHover(E, s.x, s.y) && (E.isHover = !0), E; }, a = this.groupPivotsByTimeAndPrice(this._source.pivots), c = []; a.forEach((l) => { const u = l.filter((h) => h.visible).sort((h, v) => h.degree - v.degree).map((h, v) => r(h, v)); c.push(...u); }), this._pivots = c; } /** * This method returns a renderer - special object to draw data * * @returns an renderer object to be used for drawing, or `null` if we have nothing to draw. */ renderer() { return new H(this._pivots); } } class O extends T { constructor(t = {}) { super(); o(this, "_options"); o(this, "_paneViews"); o(this, "_mouseHandlers"); o(this, "_mousePosition"); o(this, "_isSelectingPivot"); o(this, "_pivots"); o(this, "_selectedPivot"); o(this, "_pivotChanged", new _()); o(this, "_pivotSubCountClicked", new _()); o(this, "_hoverPivot"); o(this, "_interval"); this._options = { ...b, ...t }, this._selectedPivot = null; const s = new N(this), r = new B(this); s.pivotChanged().subscribe((a) => { this._selectedPivot = a; }), this._paneViews = [s, r], this._mouseHandlers = new y(), this._mousePosition = { x: 0, y: 0, x2: 0, logical: 0, xPositionRelativeToPriceScale: 0, overPriceScale: !1, overTimeScale: !1 }, this._isSelectingPivot = !1, this._pivots = [], this._hoverPivot = null, this._interval = this._options.interval; } pivotChanged() { return this._pivotChanged; } pivotSubCountClicked() { return this._pivotSubCountClicked; } /** * Hit test method which will be called by the library when the cursor is moved. * Use this to register object ids being hovered for use within the crosshairMoved * and click events emitted by the chart. Additionally, the hit test result can * specify a preferred cursor type to display for the main chart pane. This method * should return the top most hit for this primitive if more than one object is * being intersected. * * @param x - x Coordinate of mouse event * @param y - y Coordinate of mouse event */ hitTest(t, s) { const r = this._paneViews[1]; return this._hoverPivot = r.isHover(t, s), this._hoverPivot ? { externalId: "elliott-waves", cursorStyle: "pointer", zOrder: "top", // "bottom" | "normal" | "top isBackground: !1 } : null; } updateIsSelectingPivot(t) { this._isSelectingPivot = t, this.requestUpdate(); } updateInterval(t) { this._interval = t, this.requestUpdate(); } _flattenPivotsRecursive(t) { return [t, ...t.children ? t.children.flatMap((s) => this._flattenPivotsRecursive(s)) : []]; } updatePivots(t) { this._pivots = t.flatMap((s) => this._flattenPivotsRecursive(s)), this.requestUpdate(); } attached(t) { super.attached(t), this._setCrosshairMode(), this._mouseHandlers.attached(this.chart, this.series), this._mouseHandlers.clicked().subscribe((s) => { if (this._isSelectingPivot && this._selectedPivot && (this._pivotChanged.fire(this._selectedPivot), this.requestUpdate()), this._hoverPivot) { const r = this.findNextPivot(this._hoverPivot); this._pivotSubCountClicked.fire({ pivotFrom: this._hoverPivot, pivotTo: r || void 0 }); } }, this), this._mouseHandlers.mouseMoved().subscribe((s) => { s && (this._mousePosition = s, this.requestUpdate()); }, this); } isSamePivot(t, s) { return t.wave === s.wave && t.degree === s.degree && t.time === s.time && t.price === s.price && t.interval === s.interval; } isNextPivot(t, s) { return t.degree !== s.degree || t.interval !== s.interval ? !1 : t.wave === d._1 && t.wave === s.wave || t.wave + 1 === s.wave; } findNextPivot(t) { const s = this._pivots.findIndex((r) => this.isSamePivot(r, t)); if (s === -1) return null; for (let r = s + 1; r < this._pivots.length; r++) { const a = this._pivots[r]; if (this.isNextPivot(t, a)) return a; } return null; } detached() { this._mouseHandlers.clicked().unsubscribeAll(this), this._mouseHandlers.mouseMoved().unsubscribeAll(this), this._mouseHandlers.detached(), super.detached(); } updateAllViews() { this._paneViews.forEach((t) => t.update()); } paneViews() { return this._paneViews; } _timeCurrentlyVisible(t, s, r) { const a = this.chart.timeScale(), c = a.timeToCoordinate(t); if (c === null) return !1; const l = a.coordinateToLogical(c); return l === null ? !1 : l <= r && l >= s; } get options() { return this._options; } applyOptions(t) { this._options = { ...this._options, ...t }, this.requestUpdate(); } get mousePosition() { return this._mousePosition; } get isSelectingPivot() { return this._isSelectingPivot; } get pivots() { return this._pivots; } get interval() { return this._interval; } // We need to disable magnet mode for this to work nicely _setCrosshairMode() { if (!this.chart) throw new Error("Unable to change crosshair mode because the chart instance is undefined"); this.chart.applyOptions({ crosshair: { mode: g.Normal, vertLine: { visible: !0 } } }); } } export { O as ElliottWaves };