From: Jérôme Benoit Date: Wed, 23 Sep 2026 18:02:25 +0000 (+0200) Subject: docs: reconcile strategy guides and invariant ownership X-Git-Url: https://git.piment-noir.org/?a=commitdiff_plain;h=6caedcf5384ee196d4fe203df93a88f890981235;p=freqai-strategies.git docs: reconcile strategy guides and invariant ownership --- diff --git a/README.md b/README.md index 77fb5da..e301b96 100644 --- a/README.md +++ b/README.md @@ -5,11 +5,17 @@ - [QuickAdapter](#quickadapter) - [Quick start](#quick-start) - [Configuration tunables](#configuration-tunables) + - [Continual learning](#continual-learning) + - [Live inference](#live-inference) - [Backtest evaluation protocol](#backtest-evaluation-protocol) - [ReforceXY](#reforcexy) - [Quick start](#quick-start-1) - [Supported models](#supported-models) - [Configuration tunables](#configuration-tunables-1) + - [Continual learning](#continual-learning-1) + - [Live inference](#live-inference-1) + - [Training and HPO](#training-and-hpo) + - [Reward and portfolio accounting](#reward-and-portfolio-accounting) - [Development](#development) - [Common workflows](#common-workflows) - [Note](#note) @@ -161,12 +167,6 @@ below. | freqai.optuna_hyperopt.reset_label_study_on_schema_mismatch | true | bool | Reset a persisted `label` study when its selection schema is missing, invalid, or incompatible. `true` performs a destructive reset, deleting the study before recreating it; `false` preserves its trials and stored metadata, permits caller-managed reuse in memory, and does not persist selected params until the schema is reconciled. Both fail closed: an inspection error, or (under `true`) a deletion error, aborts study creation. Has no effect when `continuous=true` or outside live/dry-run modes, where studies are always reset. | | freqai.optuna_hyperopt.vary_model_seed_by_trial | true | bool | Add `trial.number` to each regressor's configured model seed (or its default seed of `1`) during HPO. `true` samples model randomness across trials; `false` evaluates every trial and the final fit with the same model seed. This does not change `freqai.optuna_hyperopt.seed`. | -In backtests, continual training uses only a saved model whose training cutoff -precedes the current window's end and its last available candle boundary. A -later model left under the same identifier is not reused when a backtest is -extended into the past. Live and dry-run restarts still restore compatible -deployed models. - The `label_weighting`, `label_smoothing`, `label_pipeline` and `label_prediction` sections accept either the flat paths listed above or a per-label format using `default` and `columns.`. Do not mix both formats in @@ -175,6 +175,16 @@ ignored with a warning. Matching column patterns are applied from least to most specific; equally specific patterns follow declaration order, so the later one wins. +### Continual learning + +In backtests, continual training uses only a saved model whose training cutoff +precedes the current window's end and its last available candle boundary. A +later model left under the same identifier is not reused when a backtest is +extended into the past. Live and dry-run restarts still restore compatible +deployed models. + +### Live inference + In live and dry-run modes, each pair requires `freqai.fit_live_predictions_candles` real model predictions before adaptive thresholds become available. The Nth observation first affects the next diff --git a/ReforceXY/reward_space_analysis/README.md b/ReforceXY/reward_space_analysis/README.md index dc96fed..c5381a9 100644 --- a/ReforceXY/reward_space_analysis/README.md +++ b/ReforceXY/reward_space_analysis/README.md @@ -57,7 +57,7 @@ Full test documentation: [tests/README.md](./tests/README.md). - [Transform Functions](#transform-functions) - [Skipping Feature Analysis](#skipping-feature-analysis) - [Reproducibility](#reproducibility) - - [Overrides vs --params](#overrides-vs--params) + - [Overrides vs --params](#overrides-vs---params) - [Examples](#examples) - [Outputs](#outputs) - [Main Report (`statistical_analysis.md`)](#main-report-statistical_analysismd) @@ -257,15 +257,16 @@ The exit factor is computed as: **Formula:** Let `pnl_target = profit_aim · risk_reward_ratio` and -`pnl_ratio = pnl / pnl_target`. On the loss branch, -`loss_threshold = pnl_target / risk_reward_ratio` and -`loss_ratio = |pnl| / loss_threshold = |pnl_ratio| · risk_reward_ratio`. +`pnl_ratio = pnl / pnl_target` when `pnl_target > 0`. For losses, let +`effective_rr = risk_reward_ratio` if positive, or `2.0` otherwise (the runtime +fallback). Then `loss_threshold = pnl_target / effective_rr` and +`loss_ratio = |pnl| / loss_threshold = |pnl_ratio| · effective_rr`. - If `pnl_target ≤ 0`: `pnl_target_coefficient = 1.0` - If `pnl_ratio > 1.0`: `pnl_target_coefficient = 1.0 + win_reward_factor · tanh(pnl_amplification_sensitivity · (pnl_ratio - 1.0))` - If `pnl < -loss_threshold`: - `pnl_target_coefficient = 1.0 + (win_reward_factor · risk_reward_ratio) · tanh(pnl_amplification_sensitivity · (loss_ratio - 1.0))` + `pnl_target_coefficient = 1.0 + (win_reward_factor · effective_rr) · tanh(pnl_amplification_sensitivity · (loss_ratio - 1.0))` - Else: `pnl_target_coefficient = 1.0` ##### Efficiency @@ -569,8 +570,8 @@ Within the same analyzer revision, identical `params_hash` values mean the resol | `*_ks_statistic` | KS two-sample statistic | [0,1]; higher ⇒ divergence | | `*_ks_pvalue` | KS test p-value | API-only with `independent_observations=True`; omitted by the descriptive CLI | -Implementation: 50-bin histograms with ε=1e-10; constants have zero divergence. -Inferential KS p-values are available only under the programmatic independence contract. +Implementation: up to 50 evenly spaced histogram edges (normally 49 bins) with +ε=1e-10; constants have zero divergence. --- @@ -609,8 +610,8 @@ uv run python reward_space_analysis.py \ --out_dir real_vs_synthetic ``` -Shift metrics: lower divergence preferred (except p-value: higher ⇒ cannot -reject equality). +For the CLI's descriptive shift metrics, lower values indicate closer +synthetic and real distributions. ### Batch Analysis diff --git a/ReforceXY/reward_space_analysis/tests/README.md b/ReforceXY/reward_space_analysis/tests/README.md index 82733cf..457742f 100644 --- a/ReforceXY/reward_space_analysis/tests/README.md +++ b/ReforceXY/reward_space_analysis/tests/README.md @@ -35,8 +35,9 @@ Markers are declared in `pyproject.toml` and enforced with `--strict-markers`. ## Test Framework -The test suite uses **pytest as the runner** with **unittest.TestCase as the -base class** (via `RewardSpaceTestBase`). +The suite runs under **pytest**. Most class-based tests inherit from +`RewardSpaceTestBase` (a `unittest.TestCase` subclass); others are standalone +pytest functions. ### Hybrid Approach Rationale @@ -51,7 +52,7 @@ This design provides: ### Base Class -All test classes inherit from `RewardSpaceTestBase` (defined in `test_base.py`): +Class-based tests normally inherit from `RewardSpaceTestBase` (in `test_base.py`): ```python from ..test_base import RewardSpaceTestBase @@ -172,68 +173,69 @@ uv run --locked --extra dev pytest -m "statistics and slow" -q Columns: -- ID: Stable identifier (`--NNN`). +- ID: Stable identifier (`--NNN`; optional letter for + split invariants). - Category: Taxonomy directory marker. - Description: Concise invariant statement. -- Owning File: Path:line of primary declaration (prefer comment line - `# Owns invariant:` when present; otherwise docstring line). -- Notes: Clarifications (sub-modes, extensions, non-owning references elsewhere, - line clusters for multi-path coverage). - -| ID | Category | Description | Owning File | Notes | -| --------------------------------------------- | ----------- | ----------------------------------------------------------------------------------- | ----------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -| report-additives-deterministic-092 | components | Additives deterministic report section | components/test_additives.py:4 | Integration/PBRS may reference outcome non-owning | -| robustness-decomposition-integrity-101 | robustness | Single active core component equals total reward under mutually exclusive scenarios | robustness/test_robustness.py:43 | Scenarios: idle, hold, exit, invalid; non-owning refs integration/test_reward_calculation.py | -| robustness-exit-mode-fallback-102 | robustness | Unknown exit_attenuation_mode falls back to linear w/ warning | robustness/test_robustness.py:654 | Comment line (function at :655) | -| robustness-negative-grace-clamp-103 | robustness | Negative exit_plateau_grace clamps to 0.0 w/ warning | robustness/test_robustness.py:696 | | -| robustness-invalid-power-tau-104 | robustness | Invalid power tau falls back alpha=1.0 w/ warning | robustness/test_robustness.py:747 | | -| robustness-near-zero-half-life-105 | robustness | Near-zero half life yields no attenuation (factor≈base) | robustness/test_robustness.py:792 | | -| pbrs-canonical-exit-semantic-106 | pbrs | Canonical exit uses shaping=-prev_potential and next_potential=0.0 | pbrs/test_pbrs.py:374 | Uses stored potential across steps; no drift correction applied | -| statistics-partial-deps-skip-107 | statistics | skip_partial_dependence => empty PD structures | statistics/test_statistics.py:42 | Docstring line | -| helpers-transitions-preserve-multiplicity-108 | helpers | Repeated transitions retain their empirical multiplicity | helpers/test_utilities.py:26 | | -| helpers-missing-cols-fill-109 | helpers | Missing required columns filled with NaN + single warning | helpers/test_utilities.py:51 | Docstring line | -| statistics-binned-stats-min-edges-110 | statistics | <2 bin edges raises ValueError | statistics/test_statistics.py:60 | Docstring line | -| statistics-constant-cols-exclusion-111 | statistics | Constant columns excluded & listed | statistics/test_statistics.py:71 | Docstring line | -| statistics-degenerate-distribution-shift-112 | statistics | Constants: zero distances; KS p only with declared independent observations | statistics/test_statistics.py:87 | Docstring line | -| statistics-constant-dist-exact-ci-113a | statistics | Both modes retain exact constant CI bounds | statistics/test_statistics.py:606 | | -| statistics-percentile-outside-mean-113b | statistics | Percentile bounds need not contain the sample mean | statistics/test_statistics.py:620 | | -| statistics-constant-diagnostics-115 | statistics | Constants have N/A higher moments, normality tests and Q-Q fits in both modes | statistics/test_statistics.py:194 | | -| pbrs-canonical-near-zero-report-116 | pbrs | Canonical trajectories with valid evidence are classified as verified | pbrs/test_pbrs.py:1509 | Requires local identity, continuity, discounted terminal boundary, and zero observed additives; the non-owning boundary test also covers a complete singleton terminal episode | -| robustness-exit-pnl-only-117 | robustness | Only exit actions have non-zero PnL | robustness/test_robustness.py:127 | Comment line | -| pbrs-absence-shift-placeholder-118 | pbrs | Placeholder shift line present when shaping shift is absent | pbrs/test_pbrs.py:1877 | | -| components-pbrs-breakdown-fields-119 | components | PBRS breakdown fields finite and mathematically aligned | components/test_reward_components.py:830 | Tests base_reward, pbrs_delta and invariance_correction alignment | -| integration-pbrs-metrics-section-120 | integration | PBRS Metrics section present in report with tracing metrics | integration/test_report_formatting.py:137 | | -| cli-pbrs-csv-columns-121 | cli | PBRS columns in reward_samples.csv when shaping enabled | cli/test_cli_params_and_csv.py:347 | Verifies finite reward_base, reward_pbrs_delta and reward_invariance_correction values | -| statistics-bh-finite-family-122 | statistics | Undefined tests excluded from finite-only BH family; marked non-applicable | statistics/test_statistics.py:499 | | -| statistics-independence-contract-123 | statistics | Inferential helpers require independent_observations=True | statistics/test_statistics.py:636 | Covers hypothesis tests and bootstrap intervals | -| report-independent-sections-124 | integration | CI, diagnostics and shift sections do not depend on hypothesis-test output | integration/test_report_formatting.py:28 | Also verifies the reported bootstrap resample count | -| pbrs-discounted-evidence-125 | pbrs | Verification requires local identity, continuity and discounted terminal boundary | pbrs/test_pbrs.py:1699 | Discontinuous potentials are not verified | -| statistics-proportional-histograms-126 | statistics | Proportional histograms ignore sample count; moved mass yields positive KL/JS | statistics/test_statistics.py:119 | KL and JS remain finite and non-negative | -| pbrs-near-bound-clamp-127 | pbrs | Relaxed near-bound clamps apply exact endpoints and retain all reasons | pbrs/test_pbrs.py:1276 | Includes numeric-string coercion | -| pbrs-exit-mode-validation-128 | pbrs | Exit-potential choices are strict or canonicalized; direct calls fail safe | pbrs/test_pbrs.py:1296 | Direct calculation and simulation boundaries warn before fallback; PBRS calls suppress additives | -| cli-invalid-exit-mode-129 | cli | Invalid `--params exit_potential_mode` fails before artifacts | cli/test_cli_params_and_csv.py:322 | Strict CLI validation | -| cli-warning-header-recognition-130 | cli | Warning counts accept only anchored Python warning header formats | cli/test_cli_params_and_csv.py:49 | Covers POSIX, relative, synthetic and Windows source locations | -| pbrs-invalid-mode-provenance-131 | pbrs | Invalid imported exit-mode metadata cannot certify canonical invariance | pbrs/test_pbrs.py:475 | Preserves the invalid raw value and reports effective additive settings as unknown | +- Owning test: Relative source path and function name (`path.py::test_name`), + stable across unrelated line insertions. +- Notes: Sub-modes, non-owning references and multi-path coverage. + +| ID | Category | Description | Owning test | Notes | +| --------------------------------------------- | ----------- | ----------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | +| report-additives-deterministic-092 | components | Additives deterministic report section | components/test_additives.py::test_additive_activation_deterministic_contribution | Integration/PBRS may reference outcome non-owning | +| robustness-decomposition-integrity-101 | robustness | Single active core component equals total reward under mutually exclusive scenarios | robustness/test_robustness.py::test_decomposition_integrity | Scenarios: idle, hold, exit, invalid; non-owning refs integration/test_reward_calculation.py | +| robustness-exit-mode-fallback-102 | robustness | Unknown exit_attenuation_mode falls back to linear w/ warning | robustness/test_robustness.py::test_robustness_102_unknown_exit_mode_fallback_linear | | +| robustness-negative-grace-clamp-103 | robustness | Negative exit_plateau_grace clamps to 0.0 w/ warning | robustness/test_robustness.py::test_robustness_103_negative_plateau_grace_clamped | | +| robustness-invalid-power-tau-104 | robustness | Invalid power tau falls back alpha=1.0 w/ warning | robustness/test_robustness.py::test_robustness_104_invalid_power_tau_fallback_alpha_one | | +| robustness-near-zero-half-life-105 | robustness | Near-zero half life yields no attenuation (factor≈base) | robustness/test_robustness.py::test_robustness_105_half_life_near_zero_fallback | | +| pbrs-canonical-exit-semantic-106 | pbrs | Canonical exit uses shaping=-prev_potential and next_potential=0.0 | pbrs/test_pbrs.py::test_exit_step_shaping_matches_exit_step_rules | Uses stored potential across steps; no drift correction applied | +| statistics-partial-deps-skip-107 | statistics | skip_partial_dependence => empty PD structures | statistics/test_statistics.py::test_statistics_feature_analysis_skip_partial_dependence | | +| helpers-transitions-preserve-multiplicity-108 | helpers | Repeated transitions retain their empirical multiplicity | helpers/test_utilities.py::test_repeated_transitions_preserve_multiplicity | | +| helpers-missing-cols-fill-109 | helpers | Missing required columns filled with NaN + single warning | helpers/test_utilities.py::test_missing_multiple_required_columns_single_warning | | +| statistics-binned-stats-min-edges-110 | statistics | <2 bin edges raises ValueError | statistics/test_statistics.py::test_statistics_binned_stats_invalid_bins_raises | Docstring line | +| statistics-constant-cols-exclusion-111 | statistics | Constant columns excluded & listed | statistics/test_statistics.py::test_statistics_correlation_dropped_constant_columns | Docstring line | +| statistics-degenerate-distribution-shift-112 | statistics | Constants: zero distances; KS p only with declared independent observations | statistics/test_statistics.py::test_statistics_distribution_shift_metrics_degenerate_zero | Docstring line | +| statistics-constant-dist-exact-ci-113a | statistics | Both modes retain exact constant CI bounds | statistics/test_statistics.py::test_stats_bootstrap_constant_distribution_exact_bounds | | +| statistics-percentile-outside-mean-113b | statistics | Percentile bounds need not contain the sample mean | statistics/test_statistics.py::test_stats_bootstrap_percentiles_need_not_contain_mean | | +| statistics-constant-diagnostics-115 | statistics | Constants have N/A higher moments, normality tests and Q-Q fits in both modes | statistics/test_statistics.py::test_statistics_distribution_constant_diagnostics | | +| pbrs-canonical-near-zero-report-116 | pbrs | Canonical trajectories with valid evidence are classified as verified | pbrs/test_pbrs.py::test_pbrs_canonical_near_zero_report | Requires local identity, continuity, discounted terminal boundary, and zero observed additives; the non-owning boundary test also covers a complete singleton terminal episode | +| robustness-exit-pnl-only-117 | robustness | Only exit actions have non-zero PnL | robustness/test_robustness.py::test_pnl_invariant_exit_only | | +| pbrs-absence-shift-placeholder-118 | pbrs | Placeholder shift line present when shaping shift is absent | pbrs/test_pbrs.py::test_pbrs_absence_and_distribution_shift_placeholder | | +| components-pbrs-breakdown-fields-119 | components | PBRS breakdown fields finite and mathematically aligned | components/test_reward_components.py::test_pbrs_breakdown_fields_finite_and_aligned | Tests base_reward, pbrs_delta and invariance_correction alignment | +| integration-pbrs-metrics-section-120 | integration | PBRS Metrics section present in report with tracing metrics | integration/test_report_formatting.py::test_report_includes_pbrs_metrics_section | | +| cli-pbrs-csv-columns-121 | cli | PBRS columns in reward_samples.csv when shaping enabled | cli/test_cli_params_and_csv.py::test_csv_contains_pbrs_columns_when_shaping_present | Verifies finite reward_base, reward_pbrs_delta and reward_invariance_correction values | +| statistics-bh-finite-family-122 | statistics | Undefined tests excluded from finite-only BH family; marked non-applicable | statistics/test_statistics.py::test_bh_excludes_undefined_tests_from_finite_family | | +| statistics-independence-contract-123 | statistics | Inferential helpers require independent_observations=True | statistics/test_statistics.py::test_inference_helpers_require_independent_observations | Covers hypothesis tests and bootstrap intervals | +| report-independent-sections-124 | integration | CI, diagnostics and shift sections do not depend on hypothesis-test output | integration/test_report_formatting.py::test_statistical_sections_do_not_depend_on_hypothesis_tests | Also verifies the reported bootstrap resample count | +| pbrs-discounted-evidence-125 | pbrs | Verification requires local identity, continuity and discounted terminal boundary | pbrs/test_pbrs.py::test_pbrs_canonical_discontinuous_potentials_report | Discontinuous potentials are not verified | +| statistics-proportional-histograms-126 | statistics | Proportional histograms ignore sample count; moved mass yields positive KL/JS | statistics/test_statistics.py::test_distribution_shift_proportional_histograms_ignore_sample_count | KL and JS remain finite and non-negative | +| pbrs-near-bound-clamp-127 | pbrs | Relaxed near-bound clamps apply exact endpoints and retain all reasons | pbrs/test_pbrs.py::test_validate_reward_parameters_records_near_bound_clamps_exactly | Includes numeric-string coercion | +| pbrs-exit-mode-validation-128 | pbrs | Exit-potential choices are strict or canonicalized; direct calls fail safe | pbrs/test_pbrs.py::test_invalid_exit_mode_warns_at_direct_and_simulation_boundaries | Direct calculation and simulation boundaries warn before fallback; PBRS calls suppress additives | +| cli-invalid-exit-mode-129 | cli | Invalid `--params exit_potential_mode` fails before artifacts | cli/test_cli_params_and_csv.py::test_invalid_exit_potential_mode_params_fails_before_artifacts | Strict CLI validation | +| cli-warning-header-recognition-130 | cli | Warning counts accept only anchored Python warning header formats | cli/test_cli_params_and_csv.py::test_warning_header_positive_and_negative_formats | Covers POSIX, relative, synthetic and Windows source locations | +| pbrs-invalid-mode-provenance-131 | pbrs | Invalid imported exit-mode metadata cannot certify canonical invariance | pbrs/test_pbrs.py::test_report_rejects_invalid_exit_mode_provenance | Preserves the invalid raw value and reports effective additive settings as unknown | +| pbrs-synthetic-fee-floor-132 | pbrs | High-fee entry loss remains in long/short synthetic PnL and exit rewards | pbrs/test_pbrs.py::test_synthetic_fee_loss_extrema_match_retained_pnl | Direct and transformed trajectories | ### Non-Owning Smoke / Reference Checks -Files that reference invariant outcomes (formatting, aggregation) without owning -the invariant must include a leading comment: +Tests that check an invariant owned elsewhere identify its owner in a comment +or docstring, for example: ```python # Non-owning smoke; ownership: ``` -Table tracks approximate line ranges and source ownership: +The following tests also check outcomes owned elsewhere: -| File | Lines (approx) | References | Ownership Source | -| -------------------------------------- | -------------- | ---------------------------------------------------- | ------------------------------------------------------------------- | -| integration/test_reward_calculation.py | 44 | Decomposition identity (sum components) | robustness/test_robustness.py:43 | -| components/test_reward_components.py | 551 | Exit factor finiteness & plateau behavior | robustness/test_robustness.py:43+ | -| pbrs/test_pbrs.py | 1053 | Canonical vs non-canonical classification formatting | robustness/test_robustness.py:43, robustness/test_robustness.py:127 | -| pbrs/test_pbrs.py | 1415 | Non-canonical full report reason aggregation | robustness/test_robustness.py:43 | -| pbrs/test_pbrs.py | 1469 | Non-canonical mode-only reason (additives disabled) | robustness/test_robustness.py:43 | -| statistics/test_statistics.py | 292 | Mean decomposition consistency | robustness/test_robustness.py:43 | +| Non-owning test | Reference check | Owning test | +| ------------------------------------------------------------------------------ | ------------------------------------------- | -------------------------------------------------------------------------------------------------------- | +| integration/test_reward_calculation.py::test_reward_component_activation_smoke | Core component activation and decomposition | robustness/test_robustness.py::test_decomposition_integrity | +| components/test_reward_components.py::test_exit_factor_calculation | Exit factor modes and plateau behavior | robustness/test_robustness.py::test_exit_factor_comprehensive; test_plateau_continuity_at_grace_boundary | +| pbrs/test_pbrs.py::test_pbrs_canonical_near_zero_report | Canonical classification and decomposition | robustness/test_robustness.py::test_decomposition_integrity | +| pbrs/test_pbrs.py::test_pbrs_non_canonical_full_report_reason_aggregation | Non-canonical report reasons | robustness/test_robustness.py::test_decomposition_integrity | +| pbrs/test_pbrs.py::test_pbrs_non_canonical_mode_only_reason | Non-canonical exit mode without additives | robustness/test_robustness.py::test_decomposition_integrity | +| statistics/test_statistics.py::test_stats_mean_decomposition_consistency | Mean decomposition consistency | robustness/test_robustness.py::test_decomposition_integrity | ### Deprecated / Reserved IDs