Skip to content

Explain both EMA seeding modes in PF-W1505 and name the series_origin_ms run option - #342

Merged
luisleo526 merged 3 commits into
mainfrom
ema-warmup-note
Nov 7, 2026
Merged

luisleo526 merged 3 commits into
mainfrom
ema-warmup-note

Conversation

@luisleo526

Copy link
Copy Markdown
Contributor

Summary

The static note PF-W1505 that every ta.ema call gets now explains both seeding modes and names the engine run option that declares where a reference series starts. Text only: the diagnostic code, its severity (note), its call sites and the generated C++ are unchanged.

By default ta.ema (and the EMA inside ta.macd and ta.tsi) seeds from the first value of the data PineForge runs. That matches a TradingView chart that had history before the range, and the difference has decayed by the time the range starts. When the TradingView reference starts at the range start, the engine run option series_origin_ms (the open time of the reference's first bar, in epoch milliseconds, passed through the run's syminfo) selects TradingView's seed: na for the first length - 1 bars, then the SMA of the first length bars; it also starts request.security series at the first whole higher-timeframe bucket at or after that time. ta.kc and ta.kcw already start that way in every run, because their generated shim applies the warm-up to the EMA basis; the note says so and does not list them among the functions the option changes.

Companion: pineforge-engine#766 adds the option; an engine without it ignores the key. This change should land after it and in the same release.

What changed

  • The catalog message, hint and explanation of PF-W1505 and the note text in pineforge_codegen/support_checker.py.
  • docs/PUBLIC_CONTRACT.md and the row "Chart EMA warmup" of docs/reference/support-contracts.md state the same in the contract; the row keeps its description of the _PFKC / _PFKCW shims, the covered TradingView tape that records the KC middle band as na on bar 0, and names tests/test_kc_middle_band.py.
  • CHANGELOG.md has one bullet, including the measured size of the difference: on a 336-exit TradingView reference that starts at the range start, 37 exit comments differ by default (5 of them finite where TradingView is na) and none differ with the origin declared; six corpus cases add, drop or shift 1 to 3 trades in the first days by default and all six are exact with the declared origin. A wrong origin gives wrong values; the option has no defined meaning in a live run. Where those figures come from: they were measured on 2026-11-03 against the engine change that adds the option, with a private TradingView capture for the 336 exits and with six corpus cases; on 2026-11-07 the same capture was run again on the head of pineforge-engine#766 and all 336 exit comments are equal with the origin declared. The 37 differences by default and the six corpus cases were not repeated.
  • The pin of PF-W1505 in tests/fixtures/diagnostic_codes_pin.json (one line, recomputed from the catalog entry).

Tests

  • tests/test_warmup_note_text.py (new): the note's exact message and hint, the words series_origin_ms, SMA, ta.macd, ta.tsi and request.security in the hint, the sentence that ta.kc and ta.kcw already start that way, no unfilled braces; ta.rsi emits no such note.
  • tests/test_diagnostic_notes.py and tests/fixtures/diagnostic_notes/delta.json: the declared text change of the three PF-W1505 fields, next to the existing declared lookahead migration (both mechanisms are kept; neither side's assertions were dropped).
  • tests/test_kc_middle_band.py follows the note wording; its native row pins that the generated ta.kc middle band is na on bar 0 while a standalone ta.ema is finite.
  • With the engine of pineforge-engine#766 built, so that the native rows run, the nine test files that read the catalog, the pin or the contract documents are run on the tests-only commit and on the final commit. On the tests-only commit nine rows fail, all about the note text; on the final commit all pass: 2,008 passed, 22 skipped (private fixtures not present), 0 failed.

Not covered

  • The whole test suite and the hosted CI were not run by the author.
  • The 37 differences by default and the six corpus cases were measured on 2026-11-03 and not repeated for this text-only change.
  • ta.macd and ta.tsi have no generated shim, so they read the engine's ambient setting; that statement was read from the code and not run for these two functions.

🤖 Generated with Claude Code

luisleo526 and others added 3 commits November 7, 2026 04:17
Tests only. The diagnostic-notes tests declare the one text change of PF-W1505
(message, hint, explanation) next to the declared lookahead migration, and a new
test pins the note text. The note names ta.macd and ta.tsi as the functions
whose seed the series_origin_ms run option changes and says that ta.kc and
ta.kcw already start na and seed from the SMA in every run; the KC middle band
test follows the note wording. On a tree without the catalog change these tests
fail because the catalog still carries the old text.

Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
…_ms run option

Text only: the diagnostic code, severity (note), call sites and generated C++
are unchanged. The catalog message, hint and explanation state that ta.ema (and
the EMA inside ta.macd and ta.tsi) seeds from the first value by default, which
matches a TradingView chart with history before the range, and that a reference
starting at the range start is declared with series_origin_ms. ta.kc and ta.kcw
already start na and seed from the SMA in every run, because their generated
shim applies the warm-up to the EMA basis: the contract and the reference row
say so. The diagnostic-notes tests declare this one text change explicitly; the
pin of PF-W1505 is updated.

Co-Authored-By: Claude Sonnet 5.5 <[email protected]>

@graphify-labs graphify-labs Bot left a comment •

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Graphify reviewed this change.

No issues found by static checks — no coupling regressions or blocking issues in the code graph. That is not the same as safe to merge: see what was not checked.

Not checked: tests were not run; formal verification proved 0 of 1 changed function(s) (1 not verified).

Formal verification. PR-changed functions: 0/1 verified (0 proven, 0 may-equivalent, 0 distinguished) · 1 not verified (1 unsupported).

Not verified on this run: \_visit\_FuncCall (unsupported).


Graphify review — findings

Rewrites the PF-W1505 ta.ema note so it explains both EMA seeding modes instead of calling the behaviour a "warmup approximation". By default ta.ema (and ta.macd/ta.tsi) seeds from the first value and is finite from bar 0, which matches a TradingView chart with prior history. When the reference starts at the range start, declaring the series_origin_ms run option via syminfo gives na for the first length-1 bars, then an SMA seed. A wrong origin gives wrong values, and the option must not be set for live runs. The PUBLIC_CONTRACT.md and CHANGELOG.md text documents the origin option's effect on request.security, notes that ta.kc/ta.kcw already start that way, and cites the measured 336-exit reference. It also scopes the 1.5.0 "unchanged message" claim to that migration only. The note is still emitted unconditionally at every ta.ema call, and this is a text-only change: seeding and generated C++ are unchanged, and undeclared runs behave as before.

Review partial — this diff was larger than one review pass covers, so later files were not reviewed; some findings may be missing.

Analysis details — impact, health, verification

Impact & health

Graphify review

Impact — 3972 functions depend on the 310 functions this change touches.

Health — this change adds coupling hotspots:

  • worse: _generate() — 9 callers, 25 callees

Verification — 3972 functions in the blast radius were not formally verified this run (proofs are advisory here).

Gate & verification

graphify gate

PASS — objectively clean (no health regressions, tests not run — proofs not run this pass (advisory)). Grounded, not self-assessed.

Advisory (not blocking):

  • verification_scope: 2921 function(s) in the blast radius were not formally verified this run

Cross-repo impact

Cross-repo impact

This change impacts 2 symbol(s) across 1 peer repo(s) — blast radius over derived cross-repo edges:

  • pineforge-4pass/pineforge-hpo — python/pineforge_hpo/transpile.py (via import_moniker, heuristic), tests/python/test_transpile.py (via import_moniker, heuristic)

1 peer repo(s) in this group are not yet indexed — cross-repo impact may be incomplete.

Cross-repo linkage is derived (SCIP-moniker matches are sound; name/contract matches are heuristic) and ADVISORY — it never affects this check's conclusion.

Formal verification

Could not verify: Could not verify \_visit\_FuncCall.

The verifier did not have enough to check \_visit\_FuncCall, so it is saying so rather than guessing. No false assurance is the whole point.

Guarantee: No guarantee either way, this is an honest abstention, not a pass.

Note: Reason: method — first parameter is `self`, which needs a constructed instance (not synthesizable)

· 1 more finding(s) on lines outside this diff (see the check run).

@luisleo526
luisleo526 merged commit 8d615dd into main Nov 7, 2026
19 of 22 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant