A hand-drawn line could never produce an alert, for two independent reasons:
- cluster_levels dropped any single-member group scoring under 8, and a manual
line weighs 1 on 5m rising to 4 on 1h. A lone drawn line was discarded before
it ever reached the alert engine.
- Even had it survived, the engine gates on confluence score, and the threshold
is 28.
Both are wrong for a drawn line specifically. Weight exists to rank levels
nobody asked for; a line you drew by hand is an explicit statement that this
price matters, so it survives clustering on its own and bypasses the score
threshold. Everything else still has to earn its place.
Alerts naming a drawn line say so — "BEARISH LINE" with the line's label rather
than "BEARISH ZONE ... confluence 1", since knowing which drawing to go look at
is the actionable part. A line that happens to coincide with other levels still
reports as a zone, with the line named alongside.
Verified against the running app: a line placed at the current price now forms a
cluster, where before it was discarded outright.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The confluence engine had nothing to work with. Daily moving averages were the
only level source, and they sat 163 to 697 points from price, so every cluster
had exactly one member and no alert could ever fire.
Two new sources, chosen for having a real following — the engine is a bet that
many participants watch the same price, which is what makes a level hold:
- Prior day high/low/close, from the last *closed* daily bar so mid-session the
levels do not silently switch to today's own developing range. Full daily
weight rather than the 0.75 average discount: a traded high is structure, not
a derived average.
- Session VWAP, anchored to the 18:00 ET open like the daily bars. Institutional
execution is benchmarked against it, and zero-volume overnight minutes are
skipped rather than dividing by zero.
Both are stamped 1d, so they get their own colours to stay distinguishable from
the daily averages. Prior-day levels draw as price lines, which span the chart
and label the axis instead of relying on bar-index interpolation.
VWAP re-prices every minute while a daily average carries hundreds of points and
changes once a session, so broadcasting the whole level set on the VWAP cadence
would have pushed the entire history every minute. Levels now go out as a delta
that clients merge by id.
Adding the levels then exposed two defects that had been invisible while nothing
could cluster:
- Cluster identity was sha1(side + round(center / tolerance)), and tolerance
derives from ATR, so it changed every bar. The same zone was continually
issued a new id, never matched the cooldown table, and the cooldown did
nothing. Identity is now the set of converging levels.
- Alert suppression keyed on that identity, so a level drifting in or out of a
group read as a new zone. It now suppresses by proximity: two zones within an
ATR are the same zone, and the strongest is the one reported.
Over six replayed sessions at threshold 28 that is 247 alerts, then 54, then 40;
raising the cooldown to 4h — which only affects repeats of the same area, never
a genuinely new zone — gives 17 total with a worst session of 9.
calibrate_alerts.py now sweeps threshold and cooldown together in one pass,
since the threshold turns out to be quantised and nearly useless as a control.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>