trendline extension slope fix
This commit is contained in:
parent
aae47b6681
commit
333ca4c111
3 changed files with 64 additions and 2 deletions
|
|
@ -925,6 +925,12 @@ Worth generalising: a measurement that looks absurd is worth chasing rather than
|
|||
clamping. The absurd number here was "67 bars of padding", and the bug behind it
|
||||
had nothing to do with padding.
|
||||
|
||||
The same median must govern every conversion past the final bar, not only the
|
||||
future slots. Leaving `timeAtIndex()` and `indexAt()` on their final raw gap
|
||||
made the first future 5m slot after the 17:00-18:00 settlement break advance a
|
||||
trendline by 65 minutes. Source-timeframe lines therefore became thirteen times
|
||||
steeper immediately beyond the live edge. All three paths now use `barInterval`.
|
||||
|
||||
### 2026-08-14 — trendlineproblem: high-TF lines used the wrong bar grid
|
||||
|
||||
**Confirmed and fixed behind `TRENDLINE_SOURCE_GEOMETRY`.** No drawing records
|
||||
|
|
|
|||
|
|
@ -1661,7 +1661,10 @@ class ConfluenceChart {
|
|||
}
|
||||
const last = bars.length - 1;
|
||||
if (time >= bars[last].t) {
|
||||
const step = bars[last].t - bars[last - 1].t;
|
||||
// Future slots use the median interval, not the tail gap. After the CME
|
||||
// settlement break the final gap is 65 minutes, and using it here makes a
|
||||
// 5m future projection advance thirteen bars per visible slot.
|
||||
const step = ConfluenceChart.barInterval(bars);
|
||||
return last + (step ? (time - bars[last].t) / step : 0);
|
||||
}
|
||||
let lo = 0;
|
||||
|
|
@ -1759,7 +1762,8 @@ class ConfluenceChart {
|
|||
if (index <= 0) return Math.round(bars[0].t + index * (bars[1].t - bars[0].t));
|
||||
const last = bars.length - 1;
|
||||
if (index >= last) {
|
||||
return Math.round(bars[last].t + (index - last) * (bars[last].t - bars[last - 1].t));
|
||||
const step = ConfluenceChart.barInterval(bars);
|
||||
return Math.round(bars[last].t + (index - last) * step);
|
||||
}
|
||||
const lower = Math.floor(index);
|
||||
const fraction = index - lower;
|
||||
|
|
|
|||
|
|
@ -109,6 +109,58 @@ test('a 30m line keeps source geometry when the 1m window starts after its ancho
|
|||
});
|
||||
});
|
||||
|
||||
test('future 5m projections keep their slope after the settlement break',
|
||||
{ timeout: 180000 }, async () => {
|
||||
await withChart(async page => {
|
||||
const result = await page.evaluate(() => {
|
||||
const c = window.__chart;
|
||||
const fiveMinutes = 5 * 60;
|
||||
const thirtyMinutes = 30 * 60;
|
||||
// The final 65-minute gap is the 17:00-18:00 CME settlement break.
|
||||
const displayed = Array.from({ length: 30 }, (_, index) => ({
|
||||
tf: '5m', t: index * fiveMinutes, o: 100, h: 101, l: 99, c: 100, v: 1, closed: true,
|
||||
}));
|
||||
displayed.push({
|
||||
tf: '5m', t: displayed.at(-1).t + 13 * fiveMinutes,
|
||||
o: 100, h: 101, l: 99, c: 100, v: 1, closed: true,
|
||||
});
|
||||
const line = {
|
||||
id: 'settlement-gap', kind: 'manual', tf: '30m',
|
||||
anchor_t: 0, anchor_p: 100, last_t: thirtyMinutes,
|
||||
slope: 6 / thirtyMinutes, cutoff_t: null,
|
||||
};
|
||||
c.bars = displayed;
|
||||
c.setTrendlineGeometry({
|
||||
mode: 'source_tf',
|
||||
series: {
|
||||
'30m': {
|
||||
times: [0, thirtyMinutes, 2 * thirtyMinutes, 3 * thirtyMinutes,
|
||||
4 * thirtyMinutes, 7 * thirtyMinutes],
|
||||
duration: thirtyMinutes,
|
||||
future_times: [8 * thirtyMinutes, 9 * thirtyMinutes],
|
||||
},
|
||||
},
|
||||
});
|
||||
const last = displayed.length - 1;
|
||||
const before = c.linePriceAtIndex(line, last - 1);
|
||||
const current = c.linePriceAtIndex(line, last);
|
||||
const future = c.linePriceAtIndex(line, last + 1);
|
||||
return {
|
||||
historicalChange: current - before,
|
||||
futureChange: future - current,
|
||||
futureTime: c.timeAtIndex(last + 1),
|
||||
expectedFutureTime: displayed[last].t + fiveMinutes,
|
||||
};
|
||||
});
|
||||
|
||||
assert.equal(result.futureTime, result.expectedFutureTime,
|
||||
'one future 5m slot inherited the 65-minute settlement gap');
|
||||
assert.ok(Math.abs(result.futureChange - result.historicalChange) < 1e-9,
|
||||
`future slope changed from ${result.historicalChange} to ${result.futureChange}`);
|
||||
assertNoPageErrors(page, assert);
|
||||
});
|
||||
});
|
||||
|
||||
test('a click, a move, then a click starts at the first click', { timeout: 180000 }, async () => {
|
||||
await withChart(async page => {
|
||||
const box = await chartBox(page);
|
||||
|
|
|
|||
Loading…
Reference in a new issue