War story

v2.2.3-split: holiday-glue fix (2026-07-06)

Root cause

Friday July 3 was the observed July 4 holiday. CME ran the half-session and glued it into Monday July 6's trade date, so Monday's live daily bar carries a Thursday-evening open stamp (that's also why the ES daily chart shows no separate Friday candle). Two pieces of logic treat "old bar stamp" as "market closed / data stale," and both misfired during Monday's LIVE session:

  1. isHolidayClosed measures timenow - time (the bar OPEN). The glued Monday bar reads ~87h old, so Auto preview engaged mid-session: PREVIEW MODE banner, D and W rows showing "?", and the classic preview shift demoting the FORMING period into C1. That is the ES symptom: weekly trigger levels equal to the current day's range instead of last week's.
  2. shouldStraddle compares the CHART BAR's open period to now. The glued Monday bar opens in last week, now is this week, so it declared a phantom straddle for the W slot on the daily chart and shifted live weekly data the same way.

Neither check asks the question that actually matters: is the SERVED HTF data stale? On the live bar the security feed was serving the current week just fine. The July 1 quarter-roll case (the reason the straddle exists) is different: there the served bar really is the prior period, and that behavior is preserved below.

The CL 1h chart is the same event seen from the other side: with Friday glued into Monday's trade date, the daily series' prior bar is Thursday July 2 (the F2d hammer), so the D row reads C1 = F2d with the trigger at Thursday's high and the low line at 67.00. Verify against the CL DAILY chart after reloading: its prior candle should be that same Thursday hammer and its current candle should contain Friday's range. If the daily chart instead shows a separate Friday candle while the 1h D row still says F2d/Thursday, that is a different bug; flag it.

Edits (apply in the TradingView Pine editor to v2.2.2-split)

Edit 1: version bump

indicator("TheStrat Suite - v2.2.2-split", ...) -> "TheStrat Suite - v2.2.3-split" (and the // TheStrat Suite - v2.2.2-split header comment line).

Edit 2: isHolidayClosed measures from the bar's scheduled CLOSE

Old:

// Holiday fallback: no new bar for 3x chart period or 4 hours, whichever is larger
isHolidayClosed = (timenow - time) > math.max(chartPeriodMs * 3, 4 * 60 * 60 * 1000)

New:

// Holiday fallback: now is 3x chart period or 4 hours (whichever is larger) past the bar's
// SCHEDULED CLOSE.
// FIX GLUE-1 (2026-07-06): measure from time_close, not time (the open). CME glues holiday
// half-sessions into the next trade date (Fri Jul 3 2026 lives inside Mon Jul 6's bar), so
// the LIVE Monday bar opened with a Thursday-evening stamp and (timenow - time) read ~87h:
// Auto preview engaged during a live session and demoted the forming week/day into C1
// ("weekly levels on the current day", D/W = "?", phantom PREVIEW MODE banner). A live bar's
// scheduled close is always in the future, so this can never fire while a session trades;
// genuinely halted markets still trip it once now exceeds the last scheduled close.
isHolidayClosed = not na(time_close) and (timenow - time_close) > math.max(chartPeriodMs * 3, 4 * 60 * 60 * 1000)

Edit 3: shouldStraddle keys off the SERVED HTF bar, not the chart bar

Replace the whole shouldStraddle function (keep the body logic; only the comment, the signature, and the tB line change):

// FIX GLUE-2 (2026-07-06): staleness is a property of the SERVED HTF data, not of the chart
// bar's open stamp. shouldStraddle now takes the served current HTF period-open (pre-shift)
// and compares ITS calendar period to now. If the feed already serves the new period, no
// shift is needed no matter how old the chart bar's stamp is. Holiday-glued Monday bars
// (open stamped Thursday evening) made the old chart-bar comparison fire a phantom straddle
// during a live session, demoting the LIVE forming week into C1. The mid-bar calendar-roll
// case this fix was built for still works: there the served bar really is the prior period,
// so servedTime's period differs from now and the shift proceeds exactly as before.
// HARDENED 2026-07-02 (unchanged): "now" is evaluated under BOTH the raw and the +12h
// reading, and BOTH must differ from the served bar's period, killing period-end-afternoon
// phantoms.
shouldStraddle(string tf, int servedTime) =>
    tB = servedTime + OFF_MS
    tN = timenow + OFF_MS
    tR = timenow
    mB = month(tB, "America/New_York"), yB = year(tB, "America/New_York"), wB = weekofyear(tB, "America/New_York")
    mN = month(tN, "America/New_York"), yN = year(tN, "America/New_York"), wN = weekofyear(tN, "America/New_York")
    mR = month(tR, "America/New_York"), yR = year(tR, "America/New_York"), wR = weekofyear(tR, "America/New_York")
    qB = math.ceil(mB / 3), qN = math.ceil(mN / 3), qR = math.ceil(mR / 3)
    saB = mB <= 6 ? 1 : 2, saN = mN <= 6 ? 1 : 2, saR = mR <= 6 ? 1 : 2
    result = false
    if tf == "W" or tf == "1W"
        result := (wN != wB or yN != yB) and (wR != wB or yR != yB)
    else if tf == "12M"
        result := yN != yB and yR != yB
    else if tf == "6M"
        result := (saN != saB or yN != yB) and (saR != saB or yR != yB)
    else if tf == "3M"
        result := (qN != qB or yN != yB) and (qR != qB or yR != yB)
    else if tf == "M" or tf == "1M"
        result := (mN != mB or yN != yB) and (mR != mB or yR != yB)
    result

Edit 4: the two callsites pass the served time

In applyPreviewShift (the ccTime parameter is the served current HTF period-open):

doPreview = shouldApplyPreview(tf, previewEnabled) or (straddleEnabled and isStraddleTF(tf) and shouldStraddle(tf, ccTime))

In the T3 recon block (use realPeriodTime, NOT rawS.ccTime, which is rewritten by the shift):

if cfgS.enabled and not na(rawS) and rawS.isPreview and canRecon and not na(reconDT) and array.size(reconDT) > 0 and isStraddleTF(cfgS.tf) and shouldStraddle(cfgS.tf, rawS.realPeriodTime)

Expected after applying + reloading


SUPERSEDED: v2.2.4 (2026-07-06, later same day)

Live testing on CL 1D confirmed GLUE-1 worked (banner gone, D row correct) but the W slot still shifted. Root cause: the glue reaches the WEEKLY bar too. This week's weekly bar opens Thursday Jul 2 18:00 ET (Friday's half-session belongs to Monday's trade date), ~84h before its true period, so even the SERVED bar's open stamp parsed as last week. The +12h normalization assumes opens are at most a session early; the glue is 3.5 days early.

GLUE-2b replaces the calendar-key test entirely. A served HTF bar is stale exactly when now is past its scheduled close:

shouldStraddle(string tf) =>
    int tc = time_close(tf)
    not na(tc) and timenow > tc

Why this is robust:

Both callsites drop the servedTime argument. Shipped as TheStratSuite_v2.2.4-split.pine.