Skip to content

C ABI: strategy_initial_capital, so the report writer names simple_proportional_overflow in every run - #565

Merged
luisleo526 merged 4 commits into
mainfrom
c-abi/strategy-initial-capital
Oct 27, 2026
Merged

luisleo526 merged 4 commits into
mainfrom
c-abi/strategy-initial-capital

Conversation

@luisleo526

@luisleo526 luisleo526 commented Oct 27, 2026 •

Copy link
Copy Markdown
Collaborator

What

Adds the C ABI export double strategy_initial_capital(pf_strategy_t), so the report writer can name simple_proportional_overflow exactly, in every run.

Before, docker/run_json.py named that reason in diagnostics.annualization only when it could prove the first curve mark was the initial capital (the selected-window anchor, or an ordinary run whose first mark had no open profit and no trade entered at bar 0). In every other run of one day or more whose compounded cagr was not finite, the reported cagr was the simple proportional value the kernel computed, but the reason was silently absent. The revision-3.1 note said a later release could close the gap by reading the capital from the engine; this is that release.

  • strategy_initial_capital returns the capital the configured run uses: the staged native specification before a run begins, the engine's stored capital otherwise. It returns NaN for a null handle (the same sentinel as strategy_current_equity) and adds no kernel state.
  • docker/run_json.py reads it once per run behind a missing-symbol guard and uses it as the initial capital when it is finite and positive. A library without the export keeps the earlier behaviour byte for byte. The subday branch, every existing absence, the overflow handling and the simple cagr value are unchanged.
  • The export appears in every list that pins the runtime symbols: the checker's names and counts (113 to 114 declarations, 93 to 94 runtime implementations), the pinned counts in the export-list test and in the docs, and the kernel residual table of the boundary ADR. The frozen legacy export list stays as it is.
  • The comment in src/engine_metrics.cpp that described the one-day-boundary ranking inversion backwards now says what the documentation says (compounded above simple); no code in that file changed.
  • Documentation: the report schema and the revision-3.1 page describe the exact behaviour and the retained gap for older libraries; the C ABI pages and README counts follow.

Verification

  • Red first: with the export present and docker/run_json.py at base, the new end-to-end test test_initial_capital_export_closes_the_unproven_overflow_gap fails (the reason is absent); on the base tree the new C test and checker lists fail to build and check for the missing export.
  • A first lab run found one real defect, fixed here: right after strategy_configure_native_v1 the first accessor returned the engine's member default, because the native route only stages the specification and copies the capital at the start of the run. The accessor now reads the staged specification; the C test asserts it for a reused host as well.
  • All eight lab legs (preflight, release, debug, sanitizers, kernel, docs, parity, subset) pass on the pre-merge head; release and debug pass again on the head merged with main. The edit moved nine citations of the report-sink page; they were re-pointed, and the doc-anchors stage of the preflight on the final head holds them.
  • The corpus parity leg and the subset leg report no change in report bytes.

🤖 Generated with Claude Code

luisleo526 and others added 3 commits October 28, 2026 01:58
…oportional_overflow in every run

Adds the read-only export `double strategy_initial_capital(pf_strategy_t)`: the
capital the configured run uses (the staged native specification before a run
begins, the engine's stored capital otherwise), NaN for a null handle. The
report writer reads it once per run, behind a missing-symbol guard, and uses it
as E0 in the annualisation diagnostics, so `simple_proportional_overflow` is
named exactly whenever the compounded form is not finite, also where the first
curve mark cannot prove the capital. A library without the export keeps the
earlier behaviour byte for byte.

Documentation: the wording that 34f9b3a added about the writer being unable to
prove the initial capital, and that "a later release may remove the gap by
reading the capital from the engine", is replaced by the exact behaviour
(`docs/design/selected-window-wire-v1.3-revision-3.1.md`,
`docs/pages/report-schema.md`). The sentences removed are named here on
purpose: "E0 is the first mark only where the run proves it is the initial
capital", "Where it cannot prove the initial capital the writer cannot
recompute the compounded form, guesses none and names nothing", "In that case
(a run of one day or more whose compounded form is not finite, with an
unproven first mark)", "A later release may remove the gap by reading the
capital from the engine", "No kernel state, public POD member, header ABI, or
runtime export is added", "The initial capital it needs is the first mark only
where the run proves it". All six came with 34f9b3a.

Also corrects the comment in src/engine_metrics.cpp that described the
one-day-boundary ranking inversion backwards (it is compounded > simple).

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

The initial-capital change adds lines to docker/run_json.py, which moves the
nine places the caller page of the report-sink descriptor cites in it. Only the
line numbers change; each citation keeps its symbol.

Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
@luisleo526
luisleo526 marked this pull request as ready for review October 27, 2026 20:24
@luisleo526
luisleo526 merged commit 95f4fd1 into main Oct 27, 2026
13 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