mirror of
https://github.com/lucasmos/GoldRegime_X.git
synced 2026-11-02 06:26:15 +00:00
fix: study.db migration fallback + degenerate HMM training guard
- optimizer.get_best_params: if study_<broker>.db not found, fall back to legacy models/study.db so optimization runs before the per-broker split are not silently discarded (prevents 'using defaults' fallback) - main.cmd_train: abort and sys.exit(1) before saving if HMM min state persistence < 0.70 — prevents deploying a garbage degenerate model when Optuna params were not loaded; prints clear remediation steps Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 4.6
parent
59085649ee
commit
1c62499071
@@ -172,6 +172,25 @@ def cmd_train(args):
|
||||
params = {}
|
||||
|
||||
result, model_hmm, state_map, models_ensemble, thresholds, metrics, *_ = _train_for_tf(tf, balance, broker, params)
|
||||
|
||||
# Guard: refuse to save a degenerate HMM — identical state means + near-zero persistence
|
||||
# indicate the Kalman/HMM params were bad (usually because Optuna params weren't loaded).
|
||||
_min_persist = min(model_hmm.transmat_[i, i] for i in range(model_hmm.n_components))
|
||||
if _min_persist < 0.70:
|
||||
logger.critical(
|
||||
"TRAINING ABORTED: degenerate HMM (min persistence=%.4f). "
|
||||
"Model NOT saved. Usually caused by missing Optuna study for tf=%s broker=%s. "
|
||||
"Ensure --mode optimize has completed and re-run --mode train.",
|
||||
_min_persist, tf, broker,
|
||||
)
|
||||
print(
|
||||
f"\nERROR: Degenerate HMM detected (min state persistence={_min_persist:.4f} < 0.70).\n"
|
||||
f"The model was NOT saved — saving it would only produce garbage signals.\n"
|
||||
f"\nFix: python main.py --mode optimize --tf {tf} --broker {broker} --trials 300\n"
|
||||
f"Then: python main.py --mode train --tf {tf} --broker {broker}\n"
|
||||
)
|
||||
sys.exit(1)
|
||||
|
||||
save_hmm(model_hmm, hmm_model_path(tf, broker))
|
||||
save_xgb_ensemble(models_ensemble, thresholds, metrics, get_ensemble_path(tf, broker))
|
||||
|
||||
|
||||
+36
-15
@@ -454,18 +454,39 @@ def get_best_params(
|
||||
tier = _get_tier(balance)
|
||||
name = _study_name(broker=broker, tier=tier, tf=tf)
|
||||
storage = _study_db(broker)
|
||||
try:
|
||||
study = optuna.load_study(study_name=name, storage=storage)
|
||||
return study.best_params
|
||||
except Exception:
|
||||
if tier == "small":
|
||||
raise # small tier is the baseline — nothing to fall back to
|
||||
# Growth (or future tiers) — reuse the small-tier study params so live
|
||||
# trading always benefits from Optuna thresholds.
|
||||
fallback = _study_name(broker=broker, tier="small", tf=tf)
|
||||
logger.info(
|
||||
"Growth study '%s' not found — using small-tier params from '%s'.",
|
||||
name, fallback,
|
||||
)
|
||||
study = optuna.load_study(study_name=fallback, storage=storage)
|
||||
return study.best_params
|
||||
|
||||
def _try_load(db: str) -> dict | None:
|
||||
try:
|
||||
study = optuna.load_study(study_name=name, storage=db)
|
||||
return study.best_params
|
||||
except Exception:
|
||||
return None
|
||||
|
||||
params = _try_load(storage)
|
||||
if params is not None:
|
||||
return params
|
||||
|
||||
# Legacy fallback: studies optimised before per-broker DB split were saved
|
||||
# to models/study.db. Try it so users don't lose their optimisation work.
|
||||
_legacy = "sqlite:///models/study.db"
|
||||
if storage != _legacy and os.path.exists("models/study.db"):
|
||||
params = _try_load(_legacy)
|
||||
if params is not None:
|
||||
logger.info(
|
||||
"Loaded params for study '%s' from legacy models/study.db. "
|
||||
"Re-run --mode optimize to persist to study_%s.db.",
|
||||
name, broker,
|
||||
)
|
||||
return params
|
||||
|
||||
if tier == "small":
|
||||
raise KeyError(f"No Optuna study '{name}' found in {storage} or study.db")
|
||||
# Growth (or future tiers) — reuse the small-tier study params so live
|
||||
# trading always benefits from Optuna thresholds.
|
||||
fallback = _study_name(broker=broker, tier="small", tf=tf)
|
||||
logger.info(
|
||||
"Growth study '%s' not found — using small-tier params from '%s'.",
|
||||
name, fallback,
|
||||
)
|
||||
study = optuna.load_study(study_name=fallback, storage=storage)
|
||||
return study.best_params
|
||||
|
||||
Reference in New Issue
Block a user