r"""
calibrate_regime.py
====================
One-off calibration of the regime monitor thresholds against backtest history.

This computes what the regime score would have been on the first day of every
month from 2005 → present, then shows the distribution. We use this to
validate that the thresholds (EXPANSION>=70, STABLE>=40) actually separate
historically active periods from quiet ones.

Run on home machine:
  cd C:\Users\paul_\OneDrive\fx_macro_intraday
  python src\research\calibrate_regime.py

Output: a table showing how many months fall into each bucket, and the
distribution of scores. We look at this together before integrating into the
dashboard.

NOTE: this calibration uses 3 of the 4 components (skips the breach-counter
since the live log only goes back to April 2026). The breach component
adds 0-30 to the live score, so historical scores would be UP TO 30 points
higher in active periods. We account for this when reading the table.
"""
import sys
from pathlib import Path

# Make regime_monitor importable
SRC = Path(__file__).resolve().parent
sys.path.insert(0, str(SRC))

from regime_monitor import compute_historical_regime_series, classify_regime

print("=" * 70)
print("  REGIME CALIBRATION — 23-year backtest analysis")
print("=" * 70)

df = compute_historical_regime_series(start_year=2005, end_year=2026)

print(f"\nComputed {len(df)} monthly snapshots.\n")

# Show the score distribution
print("Score distribution (without breach component, max 70):")
print(f"  Min:    {df['score_no_breach'].min()}")
print(f"  Max:    {df['score_no_breach'].max()}")
print(f"  Mean:   {df['score_no_breach'].mean():.1f}")
print(f"  Median: {df['score_no_breach'].median():.0f}")
print()

# Bucket by score band (using "no breach" score, max 70)
# After adding breach (0-30), score becomes 0-100.
# So for calibration: score_no_breach >= 49 ≈ would map to ~70+ with active breaches
# We're calibrating the LABEL boundary using just the macro inputs.
buckets = [
    ("65-70 (= likely EXPANSION)", 65, 70),
    ("50-64 (= likely STABLE high)", 50, 64),
    ("35-49 (= likely STABLE)", 35, 49),
    ("20-34 (= likely COMPRESSION mid)", 20, 34),
    ("0-19  (= deep COMPRESSION)", 0, 19),
]

print("Months in each score band (no-breach score, max 70):")
print(f"{'Band':<35} {'Count':>7} {'% of total':>12}")
print("-" * 56)
for label, lo, hi in buckets:
    n = ((df['score_no_breach'] >= lo) & (df['score_no_breach'] <= hi)).sum()
    pct = 100 * n / len(df)
    print(f"{label:<35} {n:>7} {pct:>11.1f}%")

print()

# Show full table for inspection
print("Sample of monthly scores (oldest 5 + newest 10):")
print("-" * 70)
print(df.head(5).to_string(index=False))
print("...")
print(df.tail(10).to_string(index=False))

print("\n" + "=" * 70)
print("INTERPRETATION:")
print("=" * 70)
print("""
The breach component adds 0-30 points to the live score (e.g. 9 breaches → +24).
So a 'no-breach' score of 49+ would map to ~73+ with healthy breach counts —
qualifying as EXPANSION on the live thresholds.

If the bucket distribution looks reasonable (most months in 20-50 range with
some clear EXPANSION periods like 2008/2022), the thresholds are calibrated
correctly. If e.g. 90% of months end up in COMPRESSION, the thresholds may
be too high and need lowering.

Send this output back and we will decide whether to:
  1. Accept thresholds as-is → proceed to dashboard integration
  2. Adjust thresholds → re-test
  3. Revise component weights → re-test
""")
