# -*- coding: utf-8 -*- """R1-R — REPRODUCIBLE REAL-DATA REPLICATION: deterministic forecast-origin freeze. PURPOSE Freeze a NEW reproducible set of walk-forward forecast-origin lists (R1-R). This is NOT a reconstruction of historical R1 and does NOT run any forecasting model or compute any performance metric. ORIGIN-SELECTION RULE (pre-registered, deterministic, model-independent) origins_cand = [ o in [train_warmup, n) : bars o..o+H are contiguous ] origins = origins_cand[::stride] stride = 8 * HORIZON M1 : H=15 stride=120 train_warmup=2000 M5 : H=3 stride=24 train_warmup=2000 M15 : H=1 stride=8 train_warmup=500 stride is chosen a priori (8*horizon). Eligibility depends only on data contiguity + warmup, never on model outputs, and stride is NOT chosen to match the historical R1 counts (489/511/515). OUTPUTS (results/R1_R/, git-ignored): origins_M1.csv origins_M5.csv origins_M15.csv R1_R_PROTOCOL.md R1_R_PROTOCOL_MANIFEST.json """ from __future__ import annotations import argparse import hashlib import json import os import subprocess from datetime import datetime import numpy as np ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) RAW = os.path.join(ROOT, "results", "R1_real_data", "XAUUSDc_M1_raw.json") OUT = os.path.join(ROOT, "results", "R1_R") FIT_WINDOW = 300 ATR_PERIOD = 20 TARGET_DEF = "Forward Return / ATR(20) over horizon H" PROTOCOLS = { "M1": {"H": 15, "train": 2000, "tf": 1, "mult": 8}, "M5": {"H": 3, "train": 2000, "tf": 5, "mult": 8}, "M15": {"H": 1, "train": 500, "tf": 15, "mult": 8}, } def load_raw(path): with open(path, "r", encoding="utf-8") as fh: return json.load(fh) def sorted_unique(bars): seen = {} for b in bars: seen[b["time"]] = b return [seen[k] for k in sorted(seen.keys())] def aggregate(bars, k): out = [] for i in range(0, len(bars), k): if i + k > len(bars): break block = bars[i:i + k] out.append({ "time": block[-1]["time"], "close": float(block[-1]["close"]), "open": float(block[0]["open"]), "high": max(float(x["high"]) for x in block), "low": min(float(x["low"]) for x in block), }) return out def valid_orig_mask(times, H, tf_minutes): dtv = [datetime.strptime(t, "%Y.%m.%d %H:%M:%S") for t in times] deltas = np.zeros(len(times), float) for i in range(1, len(times)): deltas[i] = (dtv[i] - dtv[i - 1]).total_seconds() / 60.0 contig = deltas[1:] == float(tf_minutes) n = len(contig) if n < H: return np.zeros(len(times) - H, bool) win = np.lib.stride_tricks.sliding_window_view(contig, H) return win.all(axis=1) def sha256_bytes(buf): return hashlib.sha256(buf).hexdigest() def sha256_file(path): with open(path, "rb") as fh: return hashlib.sha256(fh.read()).hexdigest() def close_hash(closes): return hashlib.sha256(np.asarray(closes, float).astype("