{
  "schema_version": 1,
  "protocol_sha256": "4da936d505df9a15cbd073ee85ee0e4ed2db483e6058f6b81ce163f4724bb4f0",
  "protocol_version": "v11-prospective-1.0.1",
  "issue": 410,
  "status": "frozen_before_evaluation",
  "purpose": "Prospective evaluation of BTC/USD hourly forecasts; no model scores were inspected to design this protocol. Revision 1.0.1 clarifies provenance enforcement, exact fractional-time pairing, interval estimands and family-wise resampling before any evaluation score access.",
  "market": {"instrument": "BTC/USD", "bar_interval_hours": 1, "outcome": "canonical production-market close", "vintage_identity": "immutable source snapshot identifier plus SHA-256 of normalized timestamp and close series"},
    "pairing": {"key": ["origin_at", "target_at", "horizon_hours"], "timestamps": "ISO-8601 UTC with Z or +00:00; no naive timestamps", "target_rule": "target_at = origin_at + horizon_hours exactly with zero fractional-second remainder", "same_vintage_and_outcome_required": true, "forecast_information_cutoff": "origin_at inclusive; every feature and model-selection datum must have been available by origin_at; each row must record input_available_at, selection_data_through, nonempty vintage_id and lowercase 64-hex vintage_sha256", "statuses": ["scored", "failed", "abstained", "missing", "ineligible"], "failure_denominator": "Report attempted, scored, failed, abstained, missing and ineligible counts/rates per model, horizon, stratum and whole family. Do not impute failures, silently drop attempts, or compare metrics on unmatched rows. Primary paired skill uses exact keys scored by both; availability and failure-rate differences are reported separately and any candidate failure-rate regression blocks eligibility."},
  "horizons_hours": [2, 4, 8, 16],
  "estimands": {
    "point": {"primary": "mean_absolute_log_return_error", "formula": "r=ln(actual_target_price/origin_price); r_hat=ln(predicted_target_price/origin_price); loss=abs(r_hat-r); report mean loss by horizon and equally-weighted mean of the four horizon means", "rationale": "scale-free, additive return error matching the forecast target; primary aggregation gives each declared horizon equal weight", "secondary": {"price_absolute_percent_error": "100*abs(predicted_target_price-actual_target_price)/actual_target_price", "signed_log_return_bias": "mean(r_hat-r); positive means overprediction", "signed_price_percent_bias": "mean(100*(predicted_target_price-actual_target_price)/actual_target_price)", "direction": "Compare sign(r_hat) with sign(r); abstain from classifying either value when abs(value)<=1e-6 log-return (10 bp); report eligible directional denominator, accuracy and candidate-minus-comparator directional error rate. Near-zero excluded from direction only, never point loss."}, "invalid_prices": "Nonfinite or nonpositive prices are failed attempts and counted; no metric imputation."},
    "interval": {"separate_from_point_estimand": true, "outcome": "Cumulative target log return y=ln(P_target/P_origin), evaluated on the same exact target outcome as point forecasts", "units": "dimensionless log-return units for quantiles, pinball, Winkler score, and width; report width additionally as 100*(U-L) percent of origin price", "bounds": "L=predicted q10 cumulative log return and U=predicted q90 cumulative log return; require finite L<=U and reject crossing/nonfinite bounds as failed attempts", "quantiles": [0.1, 0.5, 0.9], "pinball": "For each q in {0.1,0.5,0.9}, rho_q(y-Qq)=max(q*(y-Qq),(q-1)*(y-Qq)); average per quantile over exact scored pairs; lower is better", "primary_interval_score": "80% Winkler score in log-return units: (U-L)+(2/0.20)*(L-y)*I(y<L)+(2/0.20)*(y-U)*I(y>U); lower is better", "coverage": "mean(I(L<=y<=U)); nominal 0.80, report observed minus nominal and exact denominator", "width": "mean(U-L) in log-return units, also report mean(100*(exp(U)-exp(L))) as interval width percent of origin price", "bootstrap": "Pair candidate-minus-comparator per-origin interval scores on exact shared keys; resample the same 24-origin moving blocks as point outcomes and retain within-stratum membership; never resample rows independently", "interpretation": "Coverage alone is not probabilistic skill; proper score and width must accompany coverage. Interval outcomes do not substitute for point-loss tests."},
    "comparisons": {"required": ["production_champion_frozen_at_preregistration", "persistence_origin_price", "seasonal_naive_24h_exact_hour", "strongest_simple_baseline_selected_on_training_only"], "simple_baseline_pool": ["drift_7d", "drift_24h", "ar1", "ema_return_24h"], "selection": "At each outer origin choose the single baseline with lowest primary loss on inner training-only purged folds; freeze choice before outer outcomes mature; ties resolve lexicographically by baseline identifier."}
  },
  "sampling": {"strata": ["horizon", "predeclared market regime", "training-only volatility tercile with cutpoints frozen per outer fold"], "minimum_effective_sample": {"paired_origins_per_horizon": 200, "effective_independent_blocks_per_comparison": 8, "rule": "All confirmatory comparisons and primary horizon cells must meet both minima; otherwise blocked/inconclusive, never pooled to bypass a failing cell."}, "effective_sample": "number of nonoverlapping dependence blocks; report raw paired-origin count and block count"},
  "design": {"selection": "nested expanding walk-forward; each inner/outer training set excludes observations whose target has not matured before its boundary; purge at least 16 hours and embargo at least 24 hours", "holdout": "one chronological, untouched final holdout reserved before selection; no protocol tuning or model selection on it", "d3": "separate prospective shadow after training/selection and holdout lock; at least 30 calendar days and 200 mature exact pairs per horizon; D3 is not used to modify this protocol", "cutoff": "fixed calendar cutoff and dataset-vintage manifest must be registered before first evaluation score; no interim score access", "stopping": "single analysis at the frozen cutoff after all planned outcomes mature; no optional stopping or early efficacy/futility looks", "practical_effect_floor": 0.03, "practical_effect_definition": "at least 3% relative reduction in primary mean loss versus each required comparator", "limits": {"per_horizon_regression": "simultaneous adjusted upper confidence bound for candidate-minus-comparator primary loss must not exceed 5% of comparator mean loss", "directional_loss": "simultaneous adjusted upper confidence bound for candidate-minus-comparator directional error rate must not exceed 0.02 absolute"}, "disposition": ["blocked", "inconclusive", "negative", "eligible_for_human_review"], "promotion": "No automatic promotion; eligible_for_human_review is not approval."},
  "uncertainty": {"paired": true, "method": "Moving-block bootstrap of per-origin paired candidate-minus-comparator loss-difference vectors; use the same sampled origin blocks jointly across every registered model, horizon, endpoint and stratum. For each replicate retain only the frozen memberships of each stratum; do not sample independently within cells or treat strata as independent origins.", "block_length_origins": 24, "overlap_rule": "24 hourly origins covers the maximum 16-hour target overlap; use complete blocks and report effective block count", "replicates": 10000, "interval": "two-sided 95% percentile intervals and bootstrap two-sided p-values from the paired loss-difference distribution; apply the family adjustment to p-values and report adjusted intervals/conclusions", "strata_handling": "Compute each predeclared stratum estimand from the jointly resampled origin blocks using its frozen membership; preserve cross-stratum and cross-horizon dependence in every replicate; empty/undersized cells are blocked and are never dropped from the registered family.", "multiplicity": {"method": "Holm step-down", "alpha": 0.05, "registered_test_family": "Before any score access, enumerate and hash every candidate-versus-required-comparator test for primary point loss and every declared confirmatory endpoint (per-horizon point, direction, interval score, pinball quantiles, and coverage diagnostics) across all four horizons and every predeclared regime/volatility stratum. Holm-adjust the complete registered family as one family; no test or stratum may be added, removed, or redefined after inspection.", "failure_handling": "Every registered test remains in the Holm family regardless of failed/aborted evaluation, missing data, or ineligibility; report unavailable tests as blocked with no p-value and do not shrink the adjustment family."}, "seed": 4102026},
  "immutability": {"no_peeking": "Protocol, candidate identities, vintage, boundaries, cutoffs, strata, multiplicity family and attempt ledger are hashed before outcome access; access logs retained", "changes": "Any change requires a new version and digest before a new independent evaluation; prior results remain exploratory and cannot be relabeled confirmatory", "post_hoc_changes": false, "score_inspection_during_protocol_design": false}
}
