Commit c3c57cf
authored
feat: gate optimization by dof multiplier (#116)
## Summary
Add a data‑sufficiency gate for parameter optimization that scales with
degrees of freedom, to avoid overfitting on small samples.
## Changes
Added param_dof_multiplier config (default 100) and updated example
config.
Optimization is skipped when bars < max(2000, multiplier * n_params)
with a log message.
Breaking changes: None (defaults applied for older configs).
## How to Test
`docker-compose run --rm app bash -lc "poetry run pytest -q
tests/test_backtest_runner.py -k min_bars_and_dof_guard_behavior"`
### Optional Additional Tests (not implemented)
- **DoF scaling with `n_params > 1`**
Verify correct Degrees-of-Freedom scaling when optimizing across
multiple grid dimensions.
- **No search space (fixed parameters only)**
Ensure the guard condition does **not** trigger when no parameter search
space is defined.
- **Boundary case: `len(df) == param_min_bars`**
Confirm that no skip occurs when the dataset length is exactly equal to
`param_min_bars`.
- **`param_search="optuna"` behavior**
Validate that skip / no-skip logic behaves identically to grid search.
- **`stats["optimization"]` assignment**
Ensure `stats["optimization"]` is set **only** in the skip case.
## Checklist (KISS)
- [x] Pre-commit passes locally (`pre-commit run --all-files`)
- [x] Tests added/updated where it makes sense (80% cov gate)
- [x] Docs/README updated if needed
- [x] No secrets committed; `.env` values are excluded
- [x] Backward compatibility considered (configs, CLI flags)
## Related Issues/Links
- Closes #
- References #
<!-- CURSOR_SUMMARY -->
---
> [!NOTE]
> **Medium Risk**
> Changes the optimization execution path and result metadata, which can
alter which parameter sets are evaluated and persisted; mitigated by
defaults and targeted tests covering skip/boundary behavior.
>
> **Overview**
> Adds a *data-sufficiency guardrail* that **skips parameter
optimization** when there aren’t enough bars for the size of the search
space.
>
> `BacktestRunner.run_all` now computes a minimum required history as
`max(param_min_bars, param_dof_multiplier * n_params)` and, when unmet,
logs a structured `optimization_skipped` event, runs only the
fixed/default parameters (no grid/Optuna loop), and annotates result
`stats` with an `optimization` block describing the skip.
>
> Configuration is extended with `param_dof_multiplier` and
`param_min_bars` (defaults applied for older configs), README documents
the new reliability behavior, and tests add coverage for skip/no-skip
and boundary cases by asserting reduced eval counts and the
presence/absence of `stats["optimization"]`.
>
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
aabcab7. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->File tree
4 files changed
+135
-2
lines changed- src
- backtest
- tests
4 files changed
+135
-2
lines changed| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
17 | 17 | | |
18 | 18 | | |
19 | 19 | | |
| 20 | + | |
20 | 21 | | |
21 | 22 | | |
22 | 23 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
25 | 25 | | |
26 | 26 | | |
27 | 27 | | |
28 | | - | |
| 28 | + | |
29 | 29 | | |
30 | 30 | | |
31 | 31 | | |
| |||
514 | 514 | | |
515 | 515 | | |
516 | 516 | | |
| 517 | + | |
| 518 | + | |
| 519 | + | |
| 520 | + | |
| 521 | + | |
| 522 | + | |
| 523 | + | |
| 524 | + | |
| 525 | + | |
| 526 | + | |
| 527 | + | |
| 528 | + | |
| 529 | + | |
| 530 | + | |
| 531 | + | |
| 532 | + | |
| 533 | + | |
| 534 | + | |
| 535 | + | |
| 536 | + | |
| 537 | + | |
| 538 | + | |
| 539 | + | |
517 | 540 | | |
518 | 541 | | |
519 | 542 | | |
| |||
623 | 646 | | |
624 | 647 | | |
625 | 648 | | |
| 649 | + | |
| 650 | + | |
| 651 | + | |
| 652 | + | |
| 653 | + | |
| 654 | + | |
| 655 | + | |
| 656 | + | |
626 | 657 | | |
627 | 658 | | |
628 | 659 | | |
| |||
651 | 682 | | |
652 | 683 | | |
653 | 684 | | |
654 | | - | |
| 685 | + | |
655 | 686 | | |
656 | 687 | | |
657 | 688 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
50 | 50 | | |
51 | 51 | | |
52 | 52 | | |
| 53 | + | |
| 54 | + | |
53 | 55 | | |
54 | 56 | | |
55 | 57 | | |
| |||
127 | 129 | | |
128 | 130 | | |
129 | 131 | | |
| 132 | + | |
| 133 | + | |
130 | 134 | | |
131 | 135 | | |
132 | 136 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
597 | 597 | | |
598 | 598 | | |
599 | 599 | | |
| 600 | + | |
| 601 | + | |
| 602 | + | |
| 603 | + | |
| 604 | + | |
| 605 | + | |
| 606 | + | |
| 607 | + | |
| 608 | + | |
| 609 | + | |
| 610 | + | |
| 611 | + | |
| 612 | + | |
| 613 | + | |
| 614 | + | |
| 615 | + | |
| 616 | + | |
| 617 | + | |
| 618 | + | |
| 619 | + | |
| 620 | + | |
| 621 | + | |
| 622 | + | |
| 623 | + | |
| 624 | + | |
| 625 | + | |
| 626 | + | |
| 627 | + | |
| 628 | + | |
| 629 | + | |
| 630 | + | |
| 631 | + | |
| 632 | + | |
| 633 | + | |
| 634 | + | |
| 635 | + | |
| 636 | + | |
| 637 | + | |
| 638 | + | |
| 639 | + | |
| 640 | + | |
| 641 | + | |
| 642 | + | |
| 643 | + | |
| 644 | + | |
| 645 | + | |
| 646 | + | |
| 647 | + | |
| 648 | + | |
| 649 | + | |
| 650 | + | |
| 651 | + | |
| 652 | + | |
| 653 | + | |
| 654 | + | |
| 655 | + | |
| 656 | + | |
| 657 | + | |
| 658 | + | |
| 659 | + | |
| 660 | + | |
| 661 | + | |
| 662 | + | |
| 663 | + | |
| 664 | + | |
| 665 | + | |
| 666 | + | |
| 667 | + | |
| 668 | + | |
| 669 | + | |
| 670 | + | |
| 671 | + | |
| 672 | + | |
| 673 | + | |
| 674 | + | |
| 675 | + | |
| 676 | + | |
| 677 | + | |
| 678 | + | |
| 679 | + | |
| 680 | + | |
| 681 | + | |
| 682 | + | |
| 683 | + | |
| 684 | + | |
| 685 | + | |
| 686 | + | |
| 687 | + | |
| 688 | + | |
| 689 | + | |
| 690 | + | |
| 691 | + | |
| 692 | + | |
| 693 | + | |
| 694 | + | |
| 695 | + | |
| 696 | + | |
0 commit comments