security: anchor HTF aggregation on the symbol clock (syminfo.timezone + session) - #159
Merged
Conversation
…e + session) TimeframeAggregator bucketed intraday targets on the raw epoch grid and calendar targets on UTC wall-clock. That is TV-correct only for 24x7 symbols: for session symbols TradingView groups 240m buckets from the session open (09:30 on equities) and D/W/M boundaries at symbol-local midnight, so every session-symbol request.security series was misaligned (AAPL probes: 240m 25.4%, D 56.1%, W 62.0% match). The aggregator now takes the exchange tz + session and keys buckets on (local-midnight + session-open) arithmetic; crosses_boundary/tf_change gain tz-aware forms used by historical projections, streaming replay, and the finer-TF publish gate so all boundary consumers move together. tz=UTC / session empty-or-24x7 reduces to identical integer math: default construction sites pass syminfo_.timezone/.session which stay at those defaults unless runtime_overrides set them, so the ETH corpus regime is bit-for-bit unchanged (133/133 unit tests green).
…+session) Subtracting the session-open offset before the day-floor shifted each session wholesale instead of anchoring it, making D/W/M grouping tz-invariant. Calendar periods now decompose on the exchange clock only; the session offset applies solely to intraday bucket grids.
On session symbols the next-bar-crossing rule never fires inside an RTH day (16:00 close is far from midnight), so D/W/M buckets completed on the NEXT session's first bar — every security series ran one session behind TV (probe-htf-bucket-d: engine lvl on day M was close(M-2) all day where TV refreshes to close(M-1) on M's final bar; 241 vs 180 round trips). When the run declares a same-day session window, a bucket completes on the bar whose close reaches the session end. 24x7/empty/wrapped windows keep the crossing rule bit-for-bit.
The session-close rule fired on every day's final bar, completing weekly buckets mid-week (W probe 62% -> 7.8%). Gate it on the next calendar day starting a new period.
The anchor helpers paid ScopedTimezone+localtime_r+mktime on EVERY call before consulting their day cache — session-symbol runs slowed enough to tip ladder candidates over the sweep timeout. Offset is stable within a UTC hour, so key the memo by hour before touching the slow path.
Hour keys still paid ScopedTimezone(setenv+tzset) ~24x/symbol-day per thread — 50x slowdowns on multi-security strategies over 5y feeds. Offsets change only at DST instants, which fall while session markets are closed, so a per-UTC-day memo is exact for every traded bar.
This was referenced Aug 23, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Mechanism.
TimeframeAggregatorbucketed intraday targets on the raw epoch grid and calendar targets on UTC wall-clock — TV-correct only for 24x7 symbols. Session symbols anchor differently: TradingView groups intraday HTF buckets from the session open (09:30 equities, 17:00 ET forex) and D/W/M boundaries at symbol-local midnight / session-day. Every session-symbolrequest.securityseries was misaligned (AAPL probes: 240m 25.4%, D 56.1%, W 62.0% match).Fix (generic; per-run config, no strategy-specific paths).
TimeframeAggregator(tz, session): RATIO buckets keyed on(local-midnight + session-open)arithmetic; CALENDAR periods decompose on the exchange clock.crosses_boundary/tf_changetz-aware forms keep historical projections, streaming replay, and the finer-TF publish gate on the same clock.runtime_overrides.timezone/session; defaults (UTC/empty) reduce to bit-identical integer math.Evidence (engine @ 192bf15, codegen @ 726a0f4).
Probe-level: AAPL htf-bucket D 56→86%, 240m 25→61%; EURUSD 240m 13→76% under fx-session grid.
Known follow-ups (next round). EURUSD D/W read-back still diverges: TV exposes the completing HTF candle on the session-final bar with stale-by-two history reads (
close[1]inside security); engine history-offset semantics run one bucket fresh — measured in ledger findings. Wrap-safe overnight eager-completion variant was tested and rejected at population level (net-negative), reverted.Symbol-gate verdict: PASS (four-lane metric gate: tier + entry/exit/PnL p90 regression checks). PR-gate verdict: PASS.