Trading

DelayedYahoo Finance

O, H, L, C, Konatus,

How Konatus Bearing works

The overlay on this chart is the same causal filter as the TradingView script below. It does not look ahead. A marker is a claim about closed bars only. Delayed Yahoo prints are not a live book, and nothing on this page is advice.

  1. ClosePrice, as traded
  2. Filter2-pole SuperSmoother by default
  3. GeometrySlope, angle, Conatus
  4. GatesRun, volume, VWAP
  5. ConfirmTwo closed bars
  6. MarkTurn or breakout
Teal Filter rising and adequate
Red Filter falling and adequate
Grey Inadequate: slope or curvature too weak
Orange VWAP of the loaded window, or of the session on intraday
Close-confirmed turning point The filter turns up on the first bar. No marker yet. A second close above the filter fires the turn. Turning point Flip bar. No signal. Second close. Marker.
A slope flip is only a candidate. Default confirmation is two closed bars on the new side of the filter, and on the correct side of VWAP. One bar is not a reading.
Range breakout Price coils under a prior 20-bar high, then two closes clear the frozen level. Breakout Prior 20-bar high Two closes through the frozen high.
Diamonds on the chart are Donchian close-breakouts: a close through the prior 20-bar high or low. The cleared level is frozen so later edges cannot move the goal. Then the same two-bar close rule.

What each piece is measuring

Filter
Default is Ehlers’ 2-pole SuperSmoother, period 20 bars. 3-pole is quieter and slower. UltimateSmoother is faster and leakier. ROC/RMS shortens the period when the line is moving hard. Lag compensation is off unless you turn the gain up.
Conatus
Persistence of the current run of same-sign slope, 0–100. A turn still needs a finished run of at least four bars with Conatus at or above 20.
Relative volume
Volume divided by its 20-bar average. The completed run must average at least 1.0 or the turn is dropped. Skipped if the symbol has no volume.
VWAP
Volume-weighted typical price, (H+L+C)/3. On this delayed daily/weekly desk it is expanding over the loaded window. On 1m–1H it resets with the New York session. A bullish signal needs the close at or above VWAP; a bearish signal at or below. Used with relative volume, not instead of it.
Strength %
Equal-weight mix of Conatus, |slope|, Kaufman efficiency ratio, relative volume, and how far the close sits on the directed side of VWAP. It is a composite agreement score, not a probability of profit. Labels on markers are that number at the fire bar.

Limitations

  • No causal filter is simultaneously fastest, quietest, and overshoot-free. At a matched cutoff the 2-pole SuperSmoother lags an EMA and leaks less high-frequency noise. HMA and T3 are not dominated on lag and noise together.
  • Close confirmation removes one-bar noise and delays every signal. Two bars is the default. Set confirmation to 1 only if you want the old, jumpy reading.
  • Strength % is not calibrated on live P&L. A high number means the gates agree, not that the next move pays.
  • Volume and VWAP assume the feed has volume. Yahoo delayed prints can be thin, rounded, or missing on some symbols.
  • This chart shows close-confirmed slope flips and range breakouts. The TradingView paste also has historical confirmed pivots (lookback on each side). Those do not repaint; they appear after the right-hand bars exist.
  • US equities here are about fifteen minutes late. The overlay cannot see a print that has not arrived.
  • Homodyne cycle estimation in the Pine file is unverified against a page scan of Rocket Science for Traders. This web chart uses ROC/RMS, not homodyne.

Pine Script, this build

This is the Konatus Bearing v6 file hashed into the site when this page was built. In TradingView: Pine Editor, open a blank indicator, paste, save, add to chart. Defaults are ready. It is free to copy.

Download Konatus_Bearing.txt

//@version=6
// Konatus Bearing [Kontaus]
// Overlay smoother with adaptive period, residual bands, gated turning points,
// range breakouts, session VWAP, and a signal-strength percent.
//
// Paste into TradingView: Pine Editor -> Open -> paste this file -> Save -> Add to chart.
// Defaults are ready. Teal = rising and adequate, red = falling and adequate,
// grey = inadequate. Volume confirmation is on. VWAP confirmation is on: a
// bullish signal needs the close at or above session VWAP. A turn or breakout
// needs two closed bars in a row that agree; there is no marker without that.
// Confirmed pivot markers are historical. Strength % is a composite of
// Conatus, slope, efficiency ratio, relative volume, and VWAP alignment; it
// is not a forecast. This is not financial advice.
//
// Filters: Ehlers 2-pole SuperSmoother; 3-pole Butterworth with DC gain 1;
// UltimateSmoother (Ehlers). Adaptive period: ROC/RMS, autocorrelation
// periodogram (TASC Sep 2016), or homodyne discriminator (Ehlers).
// Regime tint uses Kaufman efficiency ratio.
//
// Copyright (c) 2026 Kontaus. Free to copy, use, and share.

indicator("Konatus Bearing [Kontaus]" "Konatus Bearing" overlay = true, max_labels_count = 500, max_bars_back = 200)

string G_CORE  = "1. Engine"
string G_ADAPT = "2. Adaptive period"
string G_LEAD  = "3. Lag compensation"
string G_GEO   = "4. Geometry and Conatus"
string G_GATE  = "5. Adequacy and regime"
string G_SIG   = "6. Signals"
string G_REF   = "7. Reference overlays"
string G_SHOW  = "8. Display"

float srcIn = input.source(close, "Source" group = G_CORE)
string engine = input.string("2-pole SuperSmoother" "Filter engine" options = ["2-pole SuperSmoother" "3-pole SuperSmoother" "UltimateSmoother"], group = G_CORE, tooltip = "2-pole is the default. 3-pole is slower and quieter. UltimateSmoother is faster and noisier.")
float basePer = input.float(20.0, "Base critical period" minval = 2.0, step = 0.5, group = G_CORE, tooltip = "Period in bars, not an EMA length. Default 20.")

string adaptMode = input.string("ROC/RMS" "Adaptive mode" options = ["Off (fixed period)" "ROC/RMS" "Autocorrelation periodogram" "Homodyne discriminator"], group = G_ADAPT, tooltip = "Off uses the base period. ROC/RMS shortens the period on fast motion. Periodogram and Homodyne estimate a dominant cycle.")
int rmsLen = input.int(81, "ROC RMS length" minval = 2, group = G_ADAPT, tooltip = "Bars used to measure how large a one-bar change is. About four months of daily bars, or about three days of 15-minute bars.")
float rocCap = input.float(2.0, "ROC clamp" minval = 0.1, step = 0.1, group = G_ADAPT)
float depth = input.float(0.5, "Adaptive depth" minval = 0.0, maxval = 0.9, step = 0.05, group = G_ADAPT, tooltip = "How hard ROC/RMS may shorten the period. Period = base * (1 - depth * ROC)^2.")
float minPer = input.float(2.0, "Minimum period" minval = 2.0, group = G_ADAPT)
float maxPer = input.float(48.0, "Maximum period" minval = 2.0, group = G_ADAPT, tooltip = "Ceiling for periodogram and homodyne. ROC/RMS already stops at the base period.")

float lagGain = input.float(0.0, "Lag-compensation gain" minval = 0.0, maxval = 1.0, step = 0.05, group = G_LEAD, tooltip = "0 is none. 0.5 pulls the line slightly ahead and adds a little overshoot. Leave at 0 unless you want that trade-off.")

int geoLen = input.int(81, "Normalisation window" minval = 2, group = G_GEO, tooltip = "Bars. Slope is the one-bar change of the filter, in standard deviations of that change.")
float bandSd = input.float(2.0, "Band half-width" minval = 0.0, step = 0.1, group = G_GEO, tooltip = "Envelope around the filter, in standard deviations of (source - filter). 0 hides the bands.")
float cMin = input.float(20.0, "Conatus gate" minval = 0.0, maxval = 100.0, step = 1.0, group = G_GEO, tooltip = "0-100. A turning-point signal needs the completed run at or above this.")
int runMin = input.int(4, "Minimum run for a signal" minval = 1, group = G_GEO, tooltip = "Bars. Short flips below this length are ignored.")

float kSd = input.float(0.5, "Adequacy slope" minval = 0.0, step = 0.05, group = G_GATE, tooltip = "The line is painted as adequate when |slope| is at least this, or Conatus is at the gate.")
float kCurv = input.float(0.25, "Curvature tolerance" minval = 0.0, step = 0.05, group = G_GATE, tooltip = "A bar is not adequate if curvature fights the slope harder than this, except at a turn.")
int erLen = input.int(10, "Efficiency-ratio length" minval = 2, group = G_GATE, tooltip = "Kaufman ER: net move divided by the path. 0-1.")
float erThresh = input.float(0.3, "Active-regime ER" minval = 0.0, maxval = 1.0, step = 0.05, group = G_GATE, tooltip = "ER at or above this is the active regime for the optional background tint.")
bool requireActive = input.bool(false, "Signals only in active regime" group = G_GATE, tooltip = "Off by default. When on, markers and alerts also need Kaufman ER at or above the active-regime threshold.")

string signals = input.string("Confirmed pivots" "Turning-point markers" options = ["Confirmed pivots" "Slope flips" "None"], group = G_SIG, tooltip = "Confirmed pivots wait for lookback bars on each side and do not repaint. Slope flips wait for close confirmation.")
int pivLen = input.int(10, "Pivot lookback" minval = 1, group = G_SIG, tooltip = "Bars on each side. Confirmed-pivot markers are drawn lookback bars back from the confirmation bar.")
bool gateSignals = input.bool(true, "Adequacy gate on signals" group = G_SIG, tooltip = "When on, markers and alerts need a completed run that meets Conatus and minimum run length.")
bool useVol = input.bool(true, "Volume confirmation" group = G_SIG, tooltip = "When on, the completed run must have mean relative volume (volume / SMA(volume)) at or above the floor. Quiet chop is dropped. Skipped automatically if the symbol has no volume.")
int volLen = input.int(20, "Relative-volume length" minval = 2, group = G_SIG)
float volMin = input.float(1.0, "Run relative-volume floor" minval = 0.0, step = 0.05, group = G_SIG, tooltip = "1.0 means the completed run had at least average volume. Raise it to be stricter.")
int confirmBars = input.int(2, "Close confirmation" minval = 1, group = G_SIG, tooltip = "Closed bars in a row that must agree with the signal. Default 2. There is no marker or alert without this.")
int boLen = input.int(20, "Breakout lookback" minval = 2, group = G_SIG, tooltip = "Prior bars whose high or low a close must clear. The cleared level is then frozen until confirmation completes or fails.")
bool showBreakouts = input.bool(true, "Breakout markers" group = G_SIG)
bool useVwap = input.bool(true, "VWAP confirmation" group = G_SIG, tooltip = "When on, a bullish signal needs the close at or above session VWAP, a bearish signal at or below. Used with relative volume, not instead of it. Skipped if VWAP is unavailable.")
bool showStrength = input.bool(true, "Strength % on signals" group = G_SIG, tooltip = "Composite of Conatus, slope, efficiency ratio, relative volume, and VWAP alignment. Not a forecast of profit.")
bool showVwap = input.bool(true, "Show VWAP" group = G_REF)

bool showFix = input.bool(false, "Fixed-period engine" group = G_REF, tooltip = "Same engine at the base period, with no adaptation and no lag compensation.")
bool showEMA = input.bool(false, "Comparison EMA" group = G_REF)
int emaLen = input.int(20, "EMA length" minval = 1, group = G_REF)
bool showHMA = input.bool(false, "Comparison HMA" group = G_REF)
int hmaLen = input.int(20, "HMA length" minval = 1, group = G_REF)
bool showALMA = input.bool(false, "Comparison ALMA" group = G_REF)
int almaLen = input.int(20, "ALMA length" minval = 1, group = G_REF)

bool tintBg = input.bool(false, "Tint background by regime" group = G_SHOW)
bool infoPane = input.bool(false, "Show info table" group = G_SHOW)
color colUp = input.color(#26a69a, "Bullish colour" group = G_SHOW)
color colDn = input.color(#ef5350, "Bearish colour" group = G_SHOW)
color colMute = input.color(#90a4ae, "Inadequate colour" group = G_SHOW, tooltip = "Used when the bar is not adequate.")

ss2Filt(float src, float period) =>
    float p = math.max(period, 2.0)
    float q = math.exp(-1.414 * math.pi / p)
    float c1 = 2.0 * q * math.cos(1.414 * math.pi / p)
    float c2 = q * q
    float a0 = (1.0 - c1 + c2) / 2.0
    var float f = na
    float srcPrev = nz(src[1], src)
    f := a0 * (src + srcPrev) + c1 * nz(f[1], src) - c2 * nz(f[2], src)
    f

ss3Filt(float src, float period) =>
    float p = math.max(period, 2.0)
    float a = math.exp(-math.pi / p)
    float cth = math.cos(1.738 * math.pi / p)
    float a1 = 2.0 * a * cth + a * a
    float a2 = -(a * a + 2.0 * a * a * a * cth)
    float a3 = a * a * a * a
    float b0 = 1.0 - a1 - a2 - a3
    var float f = na
    f := b0 * src + a1 * nz(f[1], src) + a2 * nz(f[2], src) + a3 * nz(f[3], src)
    f

angle2(float y, float x) =>
    float a = math.atan(y / (x == 0.0 ? 1e-12 : x))
    float r = x > 0 ? a : x < 0 and y >= 0 ? a + math.pi : x < 0 and y < 0 ? a - math.pi : y > 0 ? math.pi / 2.0 : y < 0 ? -math.pi / 2.0 : 0.0
    r

usFilt(float src, float period) =>
    float p = math.max(period, 2.0)
    float a1 = math.exp(-1.414 * math.pi / p)
    float c2 = 2.0 * a1 * math.cos(1.414 * math.pi / p)
    float c3 = -a1 * a1
    float c1 = (1.0 + c2 - c3) / 4.0
    var float us = na
    if bar_index < 3
        us := src
    else
        us := (1.0 - c1) * src + (2.0 * c1 - c2) * src[1] - (c1 + c3) * src[2] + c2 * nz(us[1], src) + c3 * nz(us[2], src)
    us

applyEngine(float src, float period) =>
    float y = switch engine
        "3-pole SuperSmoother" => ss3Filt(src, period)
        "UltimateSmoother" => usFilt(src, period)
        => ss2Filt(src, period)
    y

periodogramDC(float src) =>
    float angHp = 2.0 * math.pi / 48.0
    float alpha1 = (1.0 - math.sin(angHp)) / math.cos(angHp)
    var float hp = 0.0
    hp := 0.5 * (1.0 + alpha1) * (src - nz(src[1], src)) + alpha1 * hp
    float filt = ss2Filt(hp, 8.0)
    var array<float> rSm = array.new<float>(49, 0.0)
    var float lastDc = 8.0
    int avgN = 3
    if bar_index < 52
        lastDc
    else
        float maxPwr = 0.0
        for period = 8 to 48
            float cpart = 0.0
            float spart = 0.0
            for lagN = 3 to 48
                float sx = 0.0
                float sy = 0.0
                float sxx = 0.0
                float syy = 0.0
                float sxy = 0.0
                for count = 0 to avgN - 1
                    float xv = nz(filt[count], 0.0)
                    float yv = nz(filt[lagN + count], 0.0)
                    sx += xv
                    sy += yv
                    sxx += xv * xv
                    syy += yv * yv
                    sxy += xv * yv
                float den = (avgN * sxx - sx * sx) * (avgN * syy - sy * sy)
                float rho = den > 0 ? (avgN * sxy - sx * sy) / math.sqrt(den) : 0.0
                float omega = 2.0 * math.pi * lagN / period
                cpart += rho * math.cos(omega)
                spart += rho * math.sin(omega)
            float sq = cpart * cpart + spart * spart
            float rs = 0.2 * sq * sq + 0.8 * array.get(rSm, period)
            array.set(rSm, period, rs)
            if rs > maxPwr
                maxPwr := rs
        float peak = 0.0
        float spx = 0.0
        float sp = 0.0
        if maxPwr > 0
            for period = 8 to 48
                float pw = array.get(rSm, period) / maxPwr
                if pw > peak
                    peak := pw
            for period = 8 to 48
                float pw = array.get(rSm, period) / maxPwr
                if peak >= 0.25 and pw >= 0.25
                    spx += period * pw
                    sp += pw
        float dc = sp != 0.0 ? spx / sp : lastDc
        if sp < 0.25
            dc := lastDc
        lastDc := math.max(dc, 1.0)
        lastDc

hilbertAt(float s0, float s2, float s4, float s6, float gain) =>
    (0.0962 * s0 + 0.5769 * s2 - 0.5769 * s4 - 0.0962 * s6) * gain

homodyneDC(float src) =>
    float smooth = (4.0 * src + 3.0 * nz(src[1], src) + 2.0 * nz(src[2], src) + nz(src[3], src)) / 10.0
    var float period = 15.0
    var float i2 = 0.0
    var float q2 = 0.0
    var float re = 0.0
    var float im = 0.0
    var float smoothP = 15.0
    float gain = 0.075 * period + 0.54
    float det = hilbertAt(smooth, nz(smooth[2], smooth), nz(smooth[4], smooth), nz(smooth[6], smooth), gain)
    var float detS = 0.0
    detS := det
    float q1 = hilbertAt(detS, nz(detS[2], detS), nz(detS[4], detS), nz(detS[6], detS), gain)
    float i1 = nz(detS[3], detS)
    var float i1s = 0.0
    var float q1s = 0.0
    i1s := i1
    q1s := q1
    float ji = hilbertAt(i1s, nz(i1s[2], i1s), nz(i1s[4], i1s), nz(i1s[6], i1s), gain)
    float jq = hilbertAt(q1s, nz(q1s[2], q1s), nz(q1s[4], q1s), nz(q1s[6], q1s), gain)
    float i2r = i1 - jq
    float q2r = q1 + ji
    i2 := 0.2 * i2r + 0.8 * i2
    q2 := 0.2 * q2r + 0.8 * q2
    float reR = i2 * nz(i2[1], i2) + q2 * nz(q2[1], q2)
    float imR = i2 * nz(q2[1], q2) - q2 * nz(i2[1], i2)
    re := 0.2 * reR + 0.8 * re
    im := 0.2 * imR + 0.8 * im
    float ang = angle2(im, re)
    float per = math.abs(ang) < 1e-12 ? period : 2.0 * math.pi / ang
    if per < 0
        per := period
    per := math.min(math.max(per, 0.67 * period), 1.5 * period)
    per := math.min(math.max(per, 6.0), 50.0)
    period := 0.2 * per + 0.8 * period
    smoothP := 0.33 * period + 0.67 * smoothP
    smoothP

var float tunePer = basePer
var float roc = 0.0
var float ssAd = na

float measured = switch adaptMode
    "Autocorrelation periodogram" => periodogramDC(srcIn)
    "Homodyne discriminator" => homodyneDC(srcIn)
    => basePer

float curPer = switch adaptMode
    "Off (fixed period)" => math.max(basePer, 2.0)
    "ROC/RMS" => math.max(tunePer, minPer)
    => math.min(math.max(measured, minPer), maxPer)

ssAd := applyEngine(srcIn, curPer)
float ssFix = applyEngine(srcIn, math.max(basePer, 2.0))

float yLead = ssAd + lagGain * (ssAd - nz(ssAd[1], ssAd))
float yFix = ssFix

float roc1 = yLead - nz(yLead[1], yLead)
float rocRms = nz(math.sqrt(ta.sma(roc1 * roc1, rmsLen)), 0.0)
bool armed = bar_index >= rmsLen
roc := adaptMode == "ROC/RMS" and armed and rocRms > syminfo.mintick ? math.min(math.abs(roc1 / rocRms), rocCap) : 0.0
tunePer := math.max(basePer * (1.0 - depth * roc) * (1.0 - depth * roc), minPer)

float geoRms = nz(math.sqrt(ta.sma(roc1 * roc1, geoLen)), 0.0)
float slope = geoRms > 0 ? roc1 / geoRms : 0.0
float angleDeg = math.todegrees(math.atan(slope))
float d1Prev = nz(roc1[1], 0.0)
float curv = geoRms > 0 ? (roc1 - d1Prev) / geoRms : 0.0

var int runLen = 0
var float accAbs = 0.0
var float accRel = 0.0
bool sameDir = roc1 != 0.0 and d1Prev != 0.0 and (roc1 > 0) == (d1Prev > 0)
float volSma = ta.sma(volume, volLen)
bool haveVol = useVol and not na(volume) and not na(volSma) and volSma > 0
float relVol = haveVol ? volume / volSma : 0.0
float vwapLine = ta.vwap(hlc3)
bool haveVwap = useVwap and not na(vwapLine)
if roc1 == 0.0
    runLen := 0
    accAbs := 0.0
    accRel := 0.0
else if sameDir
    runLen += 1
    accAbs += math.abs(slope)
    accRel += relVol
else
    runLen := 1
    accAbs := math.abs(slope)
    accRel := relVol

float tRef = geoLen / 4.0
float meanS = runLen > 0 ? accAbs / runLen : 0.0
float meanRel = runLen > 0 ? accRel / runLen : 0.0
float conatus = 100.0 * (1.0 - math.exp(-meanS * runLen / tRef))
conatus := math.min(conatus, 100.0)

float erDen = ta.sma(math.abs(srcIn - srcIn[1]), erLen) * erLen
float erNum = math.abs(srcIn - srcIn[erLen])
float er = erDen > 0 ? erNum / erDen : 0.0
bool activeReg = er >= erThresh

bool slopeOk = math.abs(slope) >= kSd or conatus >= cMin
bool curveOk = roc1 > 0 ? curv >= -kCurv : roc1 < 0 ? curv <= kCurv : math.abs(curv) >= kCurv
bool barAdequate = slopeOk and curveOk and (requireActive ? activeReg : true)
bool volOk = not useVol or not haveVol or nz(meanRel[1], 0.0) >= volMin
bool flipAdequate = nz(runLen[1], 0) >= runMin and nz(conatus[1], 0.0) >= cMin and volOk and (requireActive ? activeReg : true)

float resid = srcIn - yLead
float sigRes = nz(ta.stdev(resid, geoLen), 0.0)
float upper = bandSd > 0 ? yLead + bandSd * sigRes : na
float lower = bandSd > 0 ? yLead - bandSd * sigRes : na

bool rising = yLead > yLead[1]
color colPlot = barAdequate ? (rising ? colUp : colDn) : colMute

plot(yLead, "Konatus Bearing" color = colPlot, linewidth = 2)
plot(showVwap and not na(vwapLine) ? vwapLine : na, "VWAP" color = color.new(#ff9800, 0), linewidth = 1)
plot(showFix ? yFix : na, "Fixed-period engine" color = color.new(color.silver, 25), linewidth = 1)
plot(showEMA ? ta.ema(srcIn, emaLen) : na, "EMA" color = color.new(color.gray, 0), linewidth = 1)
plot(showHMA ? ta.hma(srcIn, hmaLen) : na, "HMA" color = color.new(#7e57c2, 0), linewidth = 1)
plot(showALMA ? ta.alma(srcIn, almaLen, 0.85, 6) : na, "ALMA" color = color.new(#fb8c00, 0), linewidth = 1)
uBand = plot(upper, "Upper band" color = color.new(color.teal, 70), linewidth = 1)
lBand = plot(lower, "Lower band" color = color.new(color.teal, 70), linewidth = 1)
fill(uBand, lBand, color = bandSd > 0 ? color.new(color.teal, 90) : na, title = "Filter bands")

plot(tunePer, "Tuning period" color = color.new(color.gray, 60), display = display.data_window)
plot(conatus, "Conatus" color = color.new(color.gray, 60), display = display.data_window)
plot(angleDeg, "Slope angle" color = color.new(color.gray, 60), display = display.data_window)
plot(slope, "Slope" color = color.new(color.gray, 60), display = display.data_window)
plot(er, "Efficiency ratio" color = color.new(color.gray, 60), display = display.data_window)
plot(curPer, "Critical period" color = color.new(color.gray, 60), display = display.data_window)
plot(meanRel, "Run relative volume" color = color.new(color.gray, 60), display = display.data_window)
plot(vwapLine, "VWAP value" color = color.new(color.gray, 60), display = display.data_window)

bgcolor(tintBg ? (activeReg ? color.new(colUp, 92) : color.new(colDn, 92)) : na, title = "Regime")

bool usePiv = signals == "Confirmed pivots"
bool useFlip = signals == "Slope flips"
bool flipUp = rising and not rising[1]
bool flipDn = not rising and rising[1]
bool gatedFlipUp = flipUp and (gateSignals ? flipAdequate : true)
bool gatedFlipDn = flipDn and (gateSignals ? flipAdequate : true)

bool vwapOkUp = not haveVwap or close >= vwapLine
bool vwapOkDn = not haveVwap or close <= vwapLine
bool closeAbove = close > yLead
bool closeBelow = close < yLead
float priorHi = ta.highest(high, boLen)[1]
float priorLo = ta.lowest(low, boLen)[1]

var int turnDir = 0
var int turnStreak = 0
var int boDir = 0
var int boStreak = 0
var float boLevel = na

bool verifiedTurnUp = false
bool verifiedTurnDn = false
bool verifiedBoUp = false
bool verifiedBoDn = false

if barstate.isconfirmed
    if gatedFlipUp
        turnDir := 1
        turnStreak := closeAbove and vwapOkUp ? 1 : 0
    else if gatedFlipDn
        turnDir := -1
        turnStreak := closeBelow and vwapOkDn ? 1 : 0
    else if turnDir == 1
        if closeAbove and vwapOkUp
            turnStreak += 1
        else
            turnDir := 0
            turnStreak := 0
    else if turnDir == -1
        if closeBelow and vwapOkDn
            turnStreak += 1
        else
            turnDir := 0
            turnStreak := 0
    if turnDir == 1 and turnStreak >= confirmBars
        verifiedTurnUp := true
        turnDir := 0
        turnStreak := 0
    if turnDir == -1 and turnStreak >= confirmBars
        verifiedTurnDn := true
        turnDir := 0
        turnStreak := 0
    if boDir == 0
        if close > priorHi and vwapOkUp
            boDir := 1
            boLevel := priorHi
            boStreak := 1
        else if close < priorLo and vwapOkDn
            boDir := -1
            boLevel := priorLo
            boStreak := 1
    else if boDir == 1
        if close > boLevel and vwapOkUp
            boStreak += 1
        else
            boDir := 0
            boStreak := 0
            boLevel := na
            if close > priorHi and vwapOkUp
                boDir := 1
                boLevel := priorHi
                boStreak := 1
            else if close < priorLo and vwapOkDn
                boDir := -1
                boLevel := priorLo
                boStreak := 1
    else
        if close < boLevel and vwapOkDn
            boStreak += 1
        else
            boDir := 0
            boStreak := 0
            boLevel := na
            if close > priorHi and vwapOkUp
                boDir := 1
                boLevel := priorHi
                boStreak := 1
            else if close < priorLo and vwapOkDn
                boDir := -1
                boLevel := priorLo
                boStreak := 1
    if boDir == 1 and boStreak >= confirmBars
        verifiedBoUp := true
        boDir := 0
        boStreak := 0
        boLevel := na
    if boDir == -1 and boStreak >= confirmBars
        verifiedBoDn := true
        boDir := 0
        boStreak := 0
        boLevel := na

bool pivCloseUp = true
bool pivCloseDn = true
for k = 0 to confirmBars - 1
    bool upK = close[k] > nz(yLead[k], close[k])
    bool dnK = close[k] < nz(yLead[k], close[k])
    bool vUpK = not haveVwap or na(vwapLine[k]) or close[k] >= vwapLine[k]
    bool vDnK = not haveVwap or na(vwapLine[k]) or close[k] <= vwapLine[k]
    pivCloseUp := pivCloseUp and upK and vUpK
    pivCloseDn := pivCloseDn and dnK and vDnK

float pivHi = ta.pivothigh(yLead, pivLen, pivLen)
float pivLo = ta.pivotlow(yLead, pivLen, pivLen)
bool volPiv = not useVol or not haveVol[pivLen] or nz(meanRel[pivLen], 0.0) >= volMin
bool pivLoOk = not na(pivLo) and pivCloseUp and (gateSignals ? nz(conatus[pivLen], 0.0) >= cMin and volPiv : true)
bool pivHiOk = not na(pivHi) and pivCloseDn and (gateSignals ? nz(conatus[pivLen], 0.0) >= cMin and volPiv : true)

float dirSign = rising ? 1.0 : -1.0
float likeAcc = conatus / 100.0 + math.min(math.abs(slope) / 2.0, 1.0) + er
float likeN = 3.0
if haveVol
    likeAcc += math.min(meanRel / 2.0, 1.0)
    likeN += 1.0
float zV = 0.0
if not na(vwapLine)
    zV := dirSign * (close - vwapLine) / math.max(sigRes, syminfo.mintick)
    likeAcc += 0.5 + 0.5 * zV / (1.0 + math.abs(zV))
    likeN += 1.0
float likeRaw = 100.0 * likeAcc / likeN
float pendingStreak = math.max(turnStreak, boStreak)
float confFrac = pendingStreak > 0 ? math.min(pendingStreak / confirmBars, 1.0) : 1.0
float like = likeRaw * confFrac

plot(likeRaw, "Likelihood %" color = color.new(color.gray, 60), display = display.data_window)
plot(like, "Confirmed likelihood %" color = color.new(color.gray, 60), display = display.data_window)

plotshape(usePiv and pivLoOk, "Pivot low" shape.triangleup, location.belowbar, color.new(colUp, 0), size = size.tiny, offset = -pivLen)
plotshape(usePiv and pivHiOk, "Pivot high" shape.triangledown, location.abovebar, color.new(colDn, 0), size = size.tiny, offset = -pivLen)
plotshape(useFlip and verifiedTurnUp, "Turn up" shape.circle, location.belowbar, color.new(colUp, 40), size = size.tiny)
plotshape(useFlip and verifiedTurnDn, "Turn down" shape.circle, location.abovebar, color.new(colDn, 40), size = size.tiny)
plotshape(showBreakouts and verifiedBoUp, "Breakout up" shape.diamond, location.belowbar, color.new(colUp, 0), size = size.tiny)
plotshape(showBreakouts and verifiedBoDn, "Breakout down" shape.diamond, location.abovebar, color.new(colDn, 0), size = size.tiny)

if barstate.isconfirmed and showStrength
    if useFlip and verifiedTurnUp
        label.new(bar_index, low, str.tostring(likeRaw, "#") + "%" style = label.style_label_up, color = color.new(colUp, 40), textcolor = color.white, size = size.tiny)
    if useFlip and verifiedTurnDn
        label.new(bar_index, high, str.tostring(likeRaw, "#") + "%" style = label.style_label_down, color = color.new(colDn, 40), textcolor = color.white, size = size.tiny)
    if showBreakouts and verifiedBoUp
        label.new(bar_index, low, str.tostring(likeRaw, "#") + "%" style = label.style_label_up, color = color.new(colUp, 20), textcolor = color.white, size = size.tiny)
    if showBreakouts and verifiedBoDn
        label.new(bar_index, high, str.tostring(likeRaw, "#") + "%" style = label.style_label_down, color = color.new(colDn, 20), textcolor = color.white, size = size.tiny)

var table info = table.new(position.top_right, 2, 9, border_width = 1)
if barstate.islast
    if infoPane
        table.cell(info, 0, 0, "Period" text_color = color.gray, text_size = size.small)
        table.cell(info, 1, 0, str.tostring(curPer, "#.##"), text_color = color.white, text_size = size.small)
        table.cell(info, 0, 1, "Conatus" text_color = color.gray, text_size = size.small)
        table.cell(info, 1, 1, str.tostring(conatus, "#.#"), text_color = color.white, text_size = size.small)
        table.cell(info, 0, 2, "Angle" text_color = color.gray, text_size = size.small)
        table.cell(info, 1, 2, str.tostring(angleDeg, "#.#"), text_color = color.white, text_size = size.small)
        table.cell(info, 0, 3, "ER" text_color = color.gray, text_size = size.small)
        table.cell(info, 1, 3, str.tostring(er, "#.##"), text_color = color.white, text_size = size.small)
        table.cell(info, 0, 4, "Rel volume" text_color = color.gray, text_size = size.small)
        table.cell(info, 1, 4, str.tostring(meanRel, "#.##"), text_color = color.white, text_size = size.small)
        table.cell(info, 0, 5, "VWAP" text_color = color.gray, text_size = size.small)
        table.cell(info, 1, 5, na(vwapLine) ? "n/a" : str.tostring(vwapLine, format.mintick), text_color = color.white, text_size = size.small)
        table.cell(info, 0, 6, "Strength" text_color = color.gray, text_size = size.small)
        table.cell(info, 1, 6, str.tostring(likeRaw, "#") + "%" text_color = likeRaw >= 50 ? colUp : colMute, text_size = size.small)
        table.cell(info, 0, 7, "Regime" text_color = color.gray, text_size = size.small)
        table.cell(info, 1, 7, activeReg ? "active" : "passive" text_color = activeReg ? colUp : colDn, text_size = size.small)
        table.cell(info, 0, 8, "Gate" text_color = color.gray, text_size = size.small)
        table.cell(info, 1, 8, barAdequate ? "adequate" : "inadequate" text_color = barAdequate ? colUp : colMute, text_size = size.small)
    else
        table.clear(info, 0, 0, 1, 8)

bool conf = barstate.isconfirmed
alertcondition(conf and usePiv and pivLoOk, "Konatus Bearing pivot low" "Price-confirmed pivot low")
alertcondition(conf and usePiv and pivHiOk, "Konatus Bearing pivot high" "Price-confirmed pivot high")
alertcondition(conf and useFlip and verifiedTurnUp, "Konatus Bearing turn up" "Close-confirmed turn up")
alertcondition(conf and useFlip and verifiedTurnDn, "Konatus Bearing turn down" "Close-confirmed turn down")
alertcondition(conf and showBreakouts and verifiedBoUp, "Konatus Bearing breakout up" "Close-confirmed breakout above the prior range")
alertcondition(conf and showBreakouts and verifiedBoDn, "Konatus Bearing breakout down" "Close-confirmed breakout below the prior range")
alertcondition(conf and activeReg and not activeReg[1], "Konatus Bearing regime active" "Kaufman ER crossed into the active regime")
alertcondition(conf and not activeReg and activeReg[1], "Konatus Bearing regime passive" "Kaufman ER crossed into the passive regime")