better fib left start

This commit is contained in:
Chris Amow 2026-08-19 09:29:48 +00:00
parent 5f39144dc8
commit 1c3a852a03
2 changed files with 135 additions and 29 deletions

View file

@ -1216,3 +1216,6 @@ shares numbering, hide, delete and colour with other drawings, but it is
not a confluence level. The chart draws native price lines at 0, 23.6,
38.2, 50, 61.8, 78.6 and 100 between the two prices. 0% is the first
click.
Levels no longer span the full chart: they start at the first click and run
to the right, with a vertical rail at the origin so the swing is obvious.

View file

@ -72,6 +72,120 @@ class RthLinesPrimitive {
}
}
class FibLevelsPrimitive {
constructor(locateTime) {
this._locate = locateTime;
this._fibs = [];
this._series = null;
this._requestUpdate = null;
this._items = [];
this._view = {
update: () => this._sync(),
renderer: () => this._renderer,
};
this._renderer = { draw: target => this._draw(target) };
}
attached(param) {
this._series = param.series;
this._requestUpdate = param.requestUpdate;
}
detached() {
this._series = null;
this._requestUpdate = null;
}
setFibs(fibs) {
this._fibs = fibs || [];
if (this._requestUpdate) this._requestUpdate();
}
updateAllViews() {
this._view.update();
}
paneViews() {
return [this._view];
}
_sync() {
const items = [];
if (!this._series) {
this._items = [];
return;
}
for (const fib of this._fibs) {
if (fib.hidden) continue;
const x0 = this._locate(fib.anchor_t);
const y0 = this._series.priceToCoordinate(Number(fib.anchor_p));
const endP = Number(fib.anchor_p) + Number(fib.slope || 0)
* (Number(fib.last_t) - Number(fib.anchor_t));
const y1 = this._series.priceToCoordinate(endP);
const width = Math.max(1, Number(fib.line_width) || 2);
const color = fib.color || '#c8992f';
if (x0 != null && y0 != null && y1 != null) {
items.push({
kind: 'rail', x: x0, y0, y1, color, width,
});
}
for (const level of ConfluenceChart.fibPrices(fib)) {
const y = this._series.priceToCoordinate(level.price);
if (y == null) continue;
const major = level.r === 0 || level.r === 0.5 || level.r === 0.618 || level.r === 1;
items.push({
kind: 'level',
x0,
y,
color,
width,
dashed: !major,
label: `${level.label} ${level.price.toFixed(2)}`,
});
}
}
this._items = items;
}
_draw(target) {
if (!this._items.length) return;
target.useMediaCoordinateSpace(scope => {
const ctx = scope.context;
const right = scope.mediaSize.width;
ctx.save();
ctx.font = '10px "IBM Plex Mono", ui-monospace, monospace';
for (const item of this._items) {
if (item.kind === 'rail') {
ctx.strokeStyle = item.color;
ctx.lineWidth = item.width;
ctx.setLineDash([]);
ctx.globalAlpha = 0.85;
ctx.beginPath();
ctx.moveTo(item.x + 0.5, item.y0);
ctx.lineTo(item.x + 0.5, item.y1);
ctx.stroke();
continue;
}
const start = item.x0 == null ? 0 : Math.max(0, item.x0);
if (start > right) continue;
ctx.strokeStyle = item.color;
ctx.fillStyle = item.color;
ctx.lineWidth = item.width;
ctx.setLineDash(item.dashed ? [5, 4] : []);
ctx.globalAlpha = 0.9;
ctx.beginPath();
ctx.moveTo(start, item.y + 0.5);
ctx.lineTo(right, item.y + 0.5);
ctx.stroke();
ctx.setLineDash([]);
ctx.globalAlpha = 1;
ctx.fillText(item.label, right - ctx.measureText(item.label).width - 6, item.y - 4);
}
ctx.restore();
});
}
}
class ConfluenceChart {
constructor() {
this.chart = null;
@ -135,7 +249,7 @@ class ConfluenceChart {
this.rthPrimitive = null;
this.rthEnabled = true;
this.fibs = [];
this.fibLines = new Map();
this.fibPrimitive = null;
this.fibPreview = null;
this.futureSpace = null;
this.snapDot = null;
@ -327,6 +441,8 @@ class ConfluenceChart {
// something to label and so timeToCoordinate answers out there.
this.rthPrimitive = new RthLinesPrimitive();
this.candles.attachPrimitive(this.rthPrimitive);
this.fibPrimitive = new FibLevelsPrimitive(time => this.coordinateAtTime(time));
this.candles.attachPrimitive(this.fibPrimitive);
this.futureSpace = this.chart.addSeries(LightweightCharts.LineSeries, {
priceScaleId: 'right',
color: 'rgba(0,0,0,0)',
@ -706,33 +822,7 @@ class ConfluenceChart {
}
syncFibLines() {
if (!this.candles) return;
const wanted = new Set();
for (const fib of this.fibs) {
if (fib.hidden) continue;
for (const level of ConfluenceChart.fibPrices(fib)) {
const id = `${fib.id}:${level.r}`;
wanted.add(id);
const width = Math.max(1, Number(fib.line_width) || 2);
const major = level.r === 0 || level.r === 0.5 || level.r === 0.618 || level.r === 1;
const options = {
price: level.price,
color: fib.color || '#c8992f',
lineWidth: width,
lineStyle: major ? LightweightCharts.LineStyle.Solid : LightweightCharts.LineStyle.Dashed,
axisLabelVisible: true,
title: `${level.label} ${level.price.toFixed(2)}`,
};
const existing = this.fibLines.get(id);
if (existing) existing.applyOptions(options);
else this.fibLines.set(id, this.candles.createPriceLine(options));
}
}
for (const [id, line] of this.fibLines) {
if (wanted.has(id)) continue;
this.candles.removePriceLine(line);
this.fibLines.delete(id);
}
if (this.fibPrimitive) this.fibPrimitive.setFibs(this.fibs.filter(fib => !fib.hidden));
}
setComments(comments) {
@ -1946,11 +2036,24 @@ class ConfluenceChart {
this.fibPreview.removeAttribute('hidden');
this.fibPreview.replaceChildren();
const width = this.overlayLayer?.clientWidth || this.chartEl.clientWidth;
const originX = start.t == null ? 0 : (this.coordinateAtTime(start.t) ?? 0);
const yStart = this.candles.priceToCoordinate(start.p);
const yEnd = this.candles.priceToCoordinate(end.p);
if (yStart != null && yEnd != null) {
const rail = document.createElementNS('http://www.w3.org/2000/svg', 'line');
rail.setAttribute('x1', originX);
rail.setAttribute('x2', originX);
rail.setAttribute('y1', yStart);
rail.setAttribute('y2', yEnd);
rail.setAttribute('stroke', '#c8992f');
rail.setAttribute('stroke-width', 2);
this.fibPreview.appendChild(rail);
}
for (const item of ConfluenceChart.FIB_RATIOS) {
const y = this.candles.priceToCoordinate(start.p + (end.p - start.p) * item.r);
if (y == null) continue;
const line = document.createElementNS('http://www.w3.org/2000/svg', 'line');
line.setAttribute('x1', 0);
line.setAttribute('x1', originX);
line.setAttribute('x2', width);
line.setAttribute('y1', y);
line.setAttribute('y2', y);