OPEN-SOURCE SCRIPT
업데이트됨 Auction Weighted Support and Resistance [Metrify]

This script builds an “auction-weighted” S/R map that’s intentionally closer to a microstructure proxy than a classic “draw pivots → draw lines” approach.
The core idea: treat repeated interactions around the same price as evidence of auction behavior (acceptance vs rejection), then compress that behavior into a small set of ranked horizontal zones per horizon. Instead of outputting dozens of levels, it runs a selection pass to keep only the strongest, spatially distinct levels.
Candidate discovery is pivot-driven, but not used naively. The script collects pivot highs/lows into rolling buffers for three horizons (Micro/Short/Medium) with different pivot lengths and memory caps. Those candidates don’t become “levels” directly; they’re just seeds that get clustered and rescored. Clustering is ATR-normalized (distance measured in ATR multiples), so the same logic doesn’t fall apart when you change symbol volatility or timeframe. Each horizon has its own clustering radius (distATR_micro/short/medium), which makes Micro more granular and Medium more tolerant.
The “weight” you see is not a single metric. It’s a composite score that tries to approximate how meaningful a price is in an auction sense:
Those components get combined by f_weightCompose() into a bounded [0..1] weight using saturating transforms (so touches don’t scale linearly forever) and a decay factor tied to age. When multiple candidates land in the same cluster, the merge is done with a saturating union on weights (1 - (1-oldW)*(1-wAdd)) rather than simple addition, so weights don’t explode and a level can converge toward 1.0 without becoming meaningless. The cluster center price is updated via a weight-based average to prevent random drift from weak additions.
After clustering, we does an explicit selection pass instead of drawing everything. First it filters by minScore, then sorts by weight, then applies a spatial suppression step (basically NMS for horizontal levels). The minimum spacing is ATR-based and incorporates both a horizon spacing floor and the zone thickness, so you don’t end up with two bands that overlap visually or convey the same information. On top of that, there’s a global cross-horizon collision gate (f_canDraw) so Medium zones can coexist with Short/Micro without the chart turning into a layered fog of rectangles.

Visualization is intentionally “zone-first.” Each selected level becomes a box band whose half-thickness is ATR-scaled per horizon (bandThicknessATR_*). Opacity isn’t linear: it normalizes weight above minScore, applies a power curve to compress mid-range values, and also scales relative to the strongest level in that horizon (so you still get contrast when everything is “kind of strong”).
The pressure overlay is not volume-based and not orderflow (pine can’t read L2), but it tries to expose short-term imbalance while price is inside a band. When the last price is inside a zone, it computes a pressure score from two parts: proximity to the center (closer = higher) and a directional imbalance proxy from recent returns sampled only on bars that intersect the band. It then draws two thin lines at the band edges with alpha proportional to that pressure score. This is meant as a “are we being pushed out or absorbed here” hint (not a prediction engine).
If you enable the audit panel, the script builds a table listing the levels that actually got drawn (post-selection + collision filtering). The columns map directly to the internal metrics (weight, touches, acceptance, rejection), so you can sanity-check why a level exists. Level IDs are horizon-prefixed (MC/ST/MD) and assigned based on ranking within each horizon.
note:
rebuild is throttled (rebuildEveryN) and only runs on the last bar. Loops that can go deep use a stride heuristic (1/2/4) to keep runtime predictable on large lookbacks. Arrays are used as bounded buffers for candidate storage, and drawing objects are aggressively deleted/rebuilt to avoid object leaks.
The core idea: treat repeated interactions around the same price as evidence of auction behavior (acceptance vs rejection), then compress that behavior into a small set of ranked horizontal zones per horizon. Instead of outputting dozens of levels, it runs a selection pass to keep only the strongest, spatially distinct levels.
Candidate discovery is pivot-driven, but not used naively. The script collects pivot highs/lows into rolling buffers for three horizons (Micro/Short/Medium) with different pivot lengths and memory caps. Those candidates don’t become “levels” directly; they’re just seeds that get clustered and rescored. Clustering is ATR-normalized (distance measured in ATR multiples), so the same logic doesn’t fall apart when you change symbol volatility or timeframe. Each horizon has its own clustering radius (distATR_micro/short/medium), which makes Micro more granular and Medium more tolerant.
The “weight” you see is not a single metric. It’s a composite score that tries to approximate how meaningful a price is in an auction sense:
- Touch count (distinct): interactions are counted only when the candle range gets within a near-band threshold (ATR-normalized), and then gated by minimum bar separation so you don’t get spam from chop printing 20 touches in a row. (this is done with a stride-based loop to avoid blowing runtime on deep lookbacks)
- Acceptance: a rolling overlap rate of candle ranges inside the box. It’s exponentially weighted (half-life decay), so recent acceptance matters more, but older acceptance still contributes. If price has been “living” around that level, acceptance rises.
- Rejection quality: wick-aware rejection, but range-gated (not close-gated). The scoring looks at whether the candle range overlaps/approaches the level, then measures wick dominance on the rejecting side plus where the close sits inside the bar range.
- Age decay: older levels aren’t thrown away automatically, but they get downweighted via an exponential decay term so stale structure doesn’t dominate forever.
Those components get combined by f_weightCompose() into a bounded [0..1] weight using saturating transforms (so touches don’t scale linearly forever) and a decay factor tied to age. When multiple candidates land in the same cluster, the merge is done with a saturating union on weights (1 - (1-oldW)*(1-wAdd)) rather than simple addition, so weights don’t explode and a level can converge toward 1.0 without becoming meaningless. The cluster center price is updated via a weight-based average to prevent random drift from weak additions.
After clustering, we does an explicit selection pass instead of drawing everything. First it filters by minScore, then sorts by weight, then applies a spatial suppression step (basically NMS for horizontal levels). The minimum spacing is ATR-based and incorporates both a horizon spacing floor and the zone thickness, so you don’t end up with two bands that overlap visually or convey the same information. On top of that, there’s a global cross-horizon collision gate (f_canDraw) so Medium zones can coexist with Short/Micro without the chart turning into a layered fog of rectangles.
Visualization is intentionally “zone-first.” Each selected level becomes a box band whose half-thickness is ATR-scaled per horizon (bandThicknessATR_*). Opacity isn’t linear: it normalizes weight above minScore, applies a power curve to compress mid-range values, and also scales relative to the strongest level in that horizon (so you still get contrast when everything is “kind of strong”).
The pressure overlay is not volume-based and not orderflow (pine can’t read L2), but it tries to expose short-term imbalance while price is inside a band. When the last price is inside a zone, it computes a pressure score from two parts: proximity to the center (closer = higher) and a directional imbalance proxy from recent returns sampled only on bars that intersect the band. It then draws two thin lines at the band edges with alpha proportional to that pressure score. This is meant as a “are we being pushed out or absorbed here” hint (not a prediction engine).
If you enable the audit panel, the script builds a table listing the levels that actually got drawn (post-selection + collision filtering). The columns map directly to the internal metrics (weight, touches, acceptance, rejection), so you can sanity-check why a level exists. Level IDs are horizon-prefixed (MC/ST/MD) and assigned based on ranking within each horizon.
note:
rebuild is throttled (rebuildEveryN) and only runs on the last bar. Loops that can go deep use a stride heuristic (1/2/4) to keep runtime predictable on large lookbacks. Arrays are used as bounded buffers for candidate storage, and drawing objects are aggressively deleted/rebuilt to avoid object leaks.
릴리즈 노트
- Upgraded opacity mapping to relative rank per horizon for clearer visual hierarchy. (enhanced visual weighting so important zones stand out more clearly.)- Fix minor bugs
오픈 소스 스크립트
트레이딩뷰의 진정한 정신에 따라, 이 스크립트의 작성자는 이를 오픈소스로 공개하여 트레이더들이 기능을 검토하고 검증할 수 있도록 했습니다. 작성자에게 찬사를 보냅니다! 이 코드는 무료로 사용할 수 있지만, 코드를 재게시하는 경우 하우스 룰이 적용된다는 점을 기억하세요.
면책사항
해당 정보와 게시물은 금융, 투자, 트레이딩 또는 기타 유형의 조언이나 권장 사항으로 간주되지 않으며, 트레이딩뷰에서 제공하거나 보증하는 것이 아닙니다. 자세한 내용은 이용 약관을 참조하세요.
오픈 소스 스크립트
트레이딩뷰의 진정한 정신에 따라, 이 스크립트의 작성자는 이를 오픈소스로 공개하여 트레이더들이 기능을 검토하고 검증할 수 있도록 했습니다. 작성자에게 찬사를 보냅니다! 이 코드는 무료로 사용할 수 있지만, 코드를 재게시하는 경우 하우스 룰이 적용된다는 점을 기억하세요.
면책사항
해당 정보와 게시물은 금융, 투자, 트레이딩 또는 기타 유형의 조언이나 권장 사항으로 간주되지 않으며, 트레이딩뷰에서 제공하거나 보증하는 것이 아닙니다. 자세한 내용은 이용 약관을 참조하세요.