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.
Evidence — find 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.
Subcategory: code complexity — 9 → 10
src/jquantstats/_stats/_performance.pyis 714 lines — the largest module across the six reposassessed (basanos, futures, greeks, jquantstats, linalg, nncg), and more than twice the size of
anything in the next-largest repo.
Evidence —
find src -name '*.py' | xargs wc -l | sort -rn:radonreports nothing alarming per-block — average complexity A (2.83), no block ranked C orworse, every module A on maintainability index. So this is size and cohesion, not tangled
control flow. The signal is that
_performance.pycarries two mixins' worth of responsibility(
_ReportingStatsMixinand_RiskStatsMixin) in one file, with the B-ranked blocks spreadacross both:
_RiskStatsMixin.treynor_ratioB(8),.sharpe_varianceB(7),.information_ratioB(7),.probabilistic_sharpe_ratioB(6), and_ReportingStatsMixin.expected_returnB(8),.max_drawdown_durationB(8),.monthly_win_rateB(7),.up_captureB(7),.down_captureB(7).Change: split along the seam that already exists — the two mixin classes. Something like
_stats/_risk.pyfor_RiskStatsMixinand leaving_ReportingStatsMixinin place, or a_stats/_performance/package with one module per mixin._stats/__init__.pyalready composesthe 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 APIand the coverage gate unchanged.
Filed from a
/rhiza:qualityrun on 2026-08-01.