Skip to content

Split src/jquantstats/_stats/_performance.py (714 lines) along its two mixin classes #906

Description

@tschm

Subcategory: code complexity — 9 → 10

src/jquantstats/_stats/_performance.py is 714 lines — the largest module across the six repos
assessed (basanos, futures, greeks, jquantstats, linalg, nncg), and more than twice the size of
anything in the next-largest repo.

Evidencefind src -name '*.py' | xargs wc -l | sort -rn:

   11632 total
     714 src/jquantstats/_stats/_performance.py
     589 src/jquantstats/_stats/_reporting.py
     588 src/jquantstats/_plots/_portfolio.py
     471 src/jquantstats/portfolio.py
     466 src/jquantstats/_stats/_basic_core.py
     453 src/jquantstats/data.py
     422 src/jquantstats/exceptions.py

radon reports nothing alarming per-block — average complexity A (2.83), no block ranked C or
worse, every module A on maintainability index. So this is size and cohesion, not tangled
control flow. The signal is that _performance.py carries two mixins' worth of responsibility
(_ReportingStatsMixin and _RiskStatsMixin) in one file, with the B-ranked blocks spread
across both: _RiskStatsMixin.treynor_ratio B(8), .sharpe_variance B(7),
.information_ratio B(7), .probabilistic_sharpe_ratio B(6), and
_ReportingStatsMixin.expected_return B(8), .max_drawdown_duration B(8),
.monthly_win_rate B(7), .up_capture B(7), .down_capture B(7).

Change: split along the seam that already exists — the two mixin classes. Something like
_stats/_risk.py for _RiskStatsMixin and leaving _ReportingStatsMixin in place, or a
_stats/_performance/ package with one module per mixin. _stats/__init__.py already composes
the mixins, so the public surface need not change at all. _reporting.py (589) and
_plots/_portfolio.py (588) are the natural follow-ups if the pattern proves out.

This is the lowest-priority finding from the assessment — nothing is measurably wrong, and the
100% branch-coverage gate means a split is safe to attempt.

Done when: no module under src/jquantstats/ exceeds roughly 400 lines, with the public API
and the coverage gate unchanged.


Filed from a /rhiza:quality run on 2026-08-01.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions