#!/usr/bin/env python3 """Synthetic fixture (licence-free): two simulated instruments with GJR-GARCH-t returns and a noisy realized proxy, written in the panel format so that the whole pipeline (forecasts -> losses -> analysis -> exhibits) runs without FinData access. usage: make_synthetic.py [--out data/synthetic] ; then WP46_PANELS=data/synthetic scripts/run_benchmark.py ... """ from __future__ import annotations import argparse import json from pathlib import Path import numpy as np import pandas as pd ROOT = Path(__file__).resolve().parents[1] def simulate(T: int, seed: int, om=0.03, al=0.03, ga=0.08, be=0.90, nu=6.0) -> pd.DataFrame: rng = np.random.default_rng(seed) z = rng.standard_t(nu, T) * np.sqrt((nu - 2) / nu) s = np.empty(T); e = np.empty(T); s[0] = om / (1 - al - be - ga / 2) for t in range(T): if t > 0: s[t] = om + al * e[t - 1] ** 2 + ga * e[t - 1] ** 2 * (e[t - 1] < 0) + be * s[t - 1] e[t] = np.sqrt(s[t]) * z[t] r = 0.02 + e rv = s * rng.lognormal(-0.05, 0.3, T) * 0.7 # intraday part (70 % of the daily variance on average) on = np.sqrt(0.3 * s) * rng.standard_normal(T) # overnight return dates = pd.bdate_range("2004-01-02", periods=T) return pd.DataFrame({"session": dates, "close": 100 * np.exp(np.cumsum(r) / 100), "open": np.nan, "r": r, "r_on": on, "r_oc": r - on, "valid_rm": True, "expected_bars": 391, "rv_1m": rv * 1.1, "rv_5m": rv, "rv_5m_ss": rv, "bv_5m": rv * 0.95, "rsv_pos_5m": rv / 2, "rsv_neg_5m": rv / 2, "medrv_5m": rv * 0.9, "n_bars": 391, "n_5m": 78}) def main() -> None: ap = argparse.ArgumentParser(); ap.add_argument("--out", default=str(ROOT / "data" / "synthetic")); ap.add_argument("--T", type=int, default=5500) a = ap.parse_args() out = Path(a.out); out.mkdir(parents=True, exist_ok=True) man = {} for i, sym in enumerate(["SYN1", "SYN2"]): df = simulate(a.T, 100 + i) df.to_parquet(out / f"{sym}.parquet", index=False) man[sym] = {"asset_class": "synthetic", "symbol": sym, "rows": int(len(df)), "first": str(df.session.min().date()), "last": str(df.session.max().date()), "seed": 100 + i} (out / "manifest.json").write_text(json.dumps(man, indent=1)) print("synthetic panels:", list(man)) if __name__ == "__main__": main()