Skip to content

sim report: word an empty-side Avg win/loss (R) by counting the R sample (#1004) - #1007

Merged
eaitbrahim merged 2 commits into
mainfrom
fix/1004-sim-avg-r-empty-side
Oct 14, 2026
Merged

eaitbrahim merged 2 commits into
mainfrom
fix/1004-sim-avg-r-empty-side

Conversation

@eaitbrahim

@eaitbrahim eaitbrahim commented Oct 14, 2026 •

Copy link
Copy Markdown
Contributor

Closes #1004

What

The keel sim edge table's Avg win (R) / Avg loss (R) cells printed the engine's empty-side 0 as 0.000, which reads as a measured flat side. They now print:

R sample Avg win (R) Avg loss (R)
all wins measured n/a (no losses yet)
all losses n/a (no wins yet) measured
all scratches n/a (no wins yet) n/a (no losses yet)
a side whose trades average exactly 0 R 0.000 0.000
no R at all n/a n/a

How

  • keel/commands/insights.py: new avg_r_reason_of(stats, outcome), beside profit_factor_r_reason_of. It decides the side by counting the R sample (n_wins_r / n_losses_r), never by reading the average, and reuses the existing NO_WINS_YET / NO_LOSSES_YET / NO_TRADES_YET constants. No new strings.
  • keel/sim/report.py: new _avg_r_cell, built the same way as _profit_factor_r_cell: bare n/a with no R, then undefined_reading(reason), otherwise _r_cell(value). keel.commands.insights is still imported lazily, so the existing subprocess import-isolation test keeps passing.
  • BacktestResult, stats._r_aggregates, promotion.pool_stats and the gates are unchanged. pool_stats still multiplies by the engine's 0.

Tests (TDD)

  • test_edge_section_words_an_empty_side_average_r_by_counting_the_r_sample fails on main (('wins:A', '1.500', '0.000')) and passes here. It covers all-wins, all-scratch, all-losses, a hand-built zero-R win plus zero-R loss (to check that sides are counted, not read), both sides, no trades, and the pooled row.
  • test_avg_r_reason_of_an_empty_r_sample_is_no_trades_yet_on_either_side covers the empty-sample and all-unrisked branch.
  • Mutation-checked 7 mutants, each confirmed applied with cmp and each killed: reading the average instead of the count (both sides), a swapped count, dropping the empty-sample branch, dropping the no-R guard, reverting the loss cell, and an outcome-blind value.
  • Full suite: 8461 passed, 3 skipped. ruff check, ruff format --check and bare mypy are clean.

🤖 Generated with Claude Code

…does (#1004)

The edge table's `Avg win (R)` / `Avg loss (R)` printed the engine's empty-side `0` as
`0.000`, which reads as a measured flat side. They now print `n/a (no wins yet)` /
`n/a (no losses yet)` through `undefined_reading` and a new shared
`insights.avg_r_reason_of`, whose side is decided by counting the R sample
(`n_wins_r` / `n_losses_r`), not by reading a zero -- so a side whose trades truly
average 0 R keeps `0.000`. A row with no R stays a bare `n/a`. `BacktestResult`,
`pool_stats` and the gates are unchanged; insights stays a lazy import in the report.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

@eaitbrahim eaitbrahim left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Review of #1007. The counting-over-reading logic, the bare n/a for no-R rows, the lazy import, and the unchanged engine values / pool_stats all check out. The tests pin values per row, and the fixtures are asserted to reach each case. The 0.000 zero-R sides and the unrisked-sample no trades yet case would catch the obvious mutants. One false docstring claim, inline.

Comment thread keel/sim/report.py Outdated
…the empty-side words come from (#1004)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@eaitbrahim eaitbrahim changed the title sim report: word an empty-side Avg win/loss (R) as its profit factor does (#1004) sim report: word an empty-side Avg win/loss (R) by counting the R sample (#1004) Oct 14, 2026
@eaitbrahim
eaitbrahim merged commit f8e80b4 into main Oct 14, 2026
4 checks passed
@eaitbrahim
eaitbrahim deleted the fix/1004-sim-avg-r-empty-side branch October 14, 2026 13:53
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.

sim report: Avg win (R) / Avg loss (R) print a measured-looking 0.000 for an empty side

1 participant