engine: opt-in security_range_start_na_warmup flag for TV deep-backtest HTF warmup parity#81
Merged
Merged
Conversation
…parity
TradingView's deep backtest truncates every request.security series at the
applied range start, and TV's *built-in* ta.ema returns na until `length`
values accumulate, then seeds with the SMA of those first `length` values --
unlike this engine's default EMA, which src-seeds on the first bar and is
never na. A strategy gating direction on a long-lookback HTF ta.* therefore
diverges from TV across the whole warmup window: TV's gate is na (comparisons
-> false) for `length` HTF bars while the engine's gate has a real value from
day one.
Add an opt-in run flag `security_range_start_na_warmup` carrying the range
start in epoch-ms, plumbed on the existing syminfo_metadata channel (the same
path as bar_index_offset -- no new C ABI or run_strategy.py surface). When set,
each request.security series:
(a) aggregates from range_start_ms instead of the feed start (pre-range
input bars are dropped from the security aggregation);
(b) its embedded lookback ta.ema na-warms per TV built-in semantics -- na
until `length` values accumulate, then seed = SMA of the first `length`
values, then the ordinary EMA recursion; and
(c) plain security expressions read na until the first completed HTF bar
from the range start (a consequence of (a), counting the partial first
bucket as HTF bar 1).
Scope is the security-evaluator path only: the na-warm mode is a thread-local
flag raised solely around request.security evaluation, so security-embedded
EMAs latch it on their first compute() while chart-timeframe EMAs keep the
default src-seed. ta.sma/ta.rma/ta.highest already na-warm from series start
and are untouched. Behavior is byte-identical when the flag is unset.
Tests: a new engine-level test pins na-until-length + SMA-first-length seed +
range-start trim (flag on) and byte-identical src-seed (flag off); it fails
without the fix. Full ctest 82/82. Corpus byte-identical with the flag unused
(252 ok / 0 fail; excellent=239 strong=12 anomaly=1).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
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.
What
Adds an opt-in run flag
security_range_start_na_warmup(via the existing syminfo_metadata channel, no C-ABI change): when set with a range-start timestamp, everyrequest.securityHTF series (1) begins aggregation at the range start instead of the feed start, and (2) its embedded lookback EMA follows TV built-in warmup semantics —nauntillengthHTF bars have accumulated, then seeded with the SMA of the firstlengthvalues. Plain security expressions readnauntil the first completed HTF bar. Default OFF; behavior with the flag unset is byte-identical (proven: 252/252 corpus artifacts byte-compare clean vs main).Why
TradingView's deep backtest truncates chart and
request.securityhistory at the applied range start, and TV's built-in lookback ta.* returnnauntillengthbars accumulate. The engine's EMA seeds at the first value and the security aggregator warms from feed start, so any long-lookback HTF ta.* direction gate diverges for months inside a comparison window. Feed trimming cannot reproduce this (a truncated-seed EMA is neverna).Evidence
test_security_range_start_na_warmup(16 checks) fails without the fix, passes with it; flag-off byte-identity guarded.🤖 Generated with Claude Code