SPB Git

spb/wp41_uqo

Public
5.2 KB · 78 lines python
1"""Static LaTeX tables that do not depend on model results: universe strata, instrument list, baseline specs, benchmark."""2from __future__ import annotations34import json5from pathlib import Path67import pandas as pd8import yaml910ROOT = Path(__file__).resolve().parents[1]11T = ROOT / "paper" / "tables"; T.mkdir(parents=True, exist_ok=True)121314def esc(s) -> str:15    return str(s).replace("_", "\\_").replace("&", "\\&").replace("%", "\\%").replace("$", "\\$")161718def universe_tables() -> None:19    man = json.loads((ROOT / "data" / "manifests" / "universe_main.json").read_text())20    df = pd.DataFrame(man["instruments"])21    piv = df.pivot_table(index=["asset_class", "adv_tercile"], columns="vol_tercile", values="symbol", aggfunc="count", fill_value=0)22    piv = piv.reindex(columns=["low", "mid", "high"])23    lines = ["\\begin{table}[htbp]\\centering\\small", "\\caption{Universe allocation: instruments per asset class $\\times$ dollar-volume tercile $\\times$ daily-volatility tercile (selection date 2017-12-29; 60 of the 300 instruments are held out)}",24             "\\label{tab:universe_strata}", "\\begin{tabular}{llccc}", "\\toprule", "Asset class & ADV tercile & Vol. low & Vol. mid & Vol. high \\\\", "\\midrule"]25    for (ac, adv), r in piv.iterrows():26        lines.append(f"{ac} & {adv} & {r['low']} & {r['mid']} & {r['high']} \\\\")27    held = df.groupby("asset_class")["role"].apply(lambda s: (s == "heldout_instrument").sum())28    lines += ["\\midrule", f"held out & & \\multicolumn{{3}}{{c}}{{stocks {held.get('stock', 0)}, ETFs {held.get('etf', 0)}}} \\\\", "\\bottomrule", "\\end{tabular}", "\\end{table}"]29    (T / "universe_strata.tex").write_text("\n".join(lines))30    # compact instrument list (tickers only, allowed by the license)31    pooled = sorted(df[df.role == "pooled"].symbol); held = sorted(df[df.role != "pooled"].symbol)32    def block(name, syms):33        return [f"\\paragraph{{{name} ({len(syms)}).}}", "\\small " + esc(", ".join(syms)) + "\\normalsize"]34    (T / "universe_list.tex").write_text("\n".join(block("Pooled instruments", pooled) + block("Held-out instruments", held)))35    # group counts36    g = df.groupby(["asset_class", "group"]).size().reset_index(name="n")37    lines = ["\\begin{table}[htbp]\\centering\\small", "\\caption{Sector (SIC division) and ETF category counts in the universe}", "\\label{tab:universe_groups}",38             "\\begin{tabular}{llr}", "\\toprule", "Asset class & Group & $n$ \\\\", "\\midrule"]39    lines += [f"{r.asset_class} & {esc(r.group)} & {r.n} \\\\" for r in g.itertuples()]40    lines += ["\\bottomrule", "\\end{tabular}", "\\end{table}"]41    (T / "universe_groups.tex").write_text("\n".join(lines))424344def baseline_spec_table() -> None:45    spec = yaml.safe_load((ROOT / "configs" / "baselines.yaml").read_text())46    names = {"naive_rw": "Random walk", "seasonal_vol": "Seasonal volatility", "ewma": "EWMA-$t$", "har_rv": "HAR-RV", "garch_t": "GARCH(1,1)-$t$",47             "ridge": "Ridge", "elastic_net": "Elastic net", "lightgbm": "LightGBM", "mlp": "MLP", "tcn": "TCN"}48    lines = ["\\begin{table}[htbp]\\centering\\scriptsize", "\\caption{Baseline specifications (information set = completed bars at the origin; tuned on training/validation periods only)}",49             "\\label{tab:baselines}", "\\begin{tabular}{p{2.6cm}p{12.5cm}}", "\\toprule", "Model & Specification \\\\", "\\midrule"]50    for k, v in spec.items():51        if k in ("name", "description", "not_run"):52            continue53        desc = "; ".join(f"{esc(a)}: {esc(b)}" for a, b in v.items())54        lines.append(f"{names.get(k, esc(k))} & {desc} \\\\")55    lines += ["\\midrule", "Not run & " + "; ".join(f"\\emph{{{esc(a)}}}: {esc(b)}" for a, b in spec["not_run"].items()) + " \\\\", "\\bottomrule", "\\end{tabular}", "\\end{table}"]56    (T / "baselines_spec.tex").write_text("\n".join(lines))575859def benchmark_table() -> None:60    f = ROOT / "results" / "metrics" / "benchmark_M3U96b.json"61    if not f.exists():62        return63    b = json.loads(f.read_text())64    lines = ["\\begin{table}[htbp]\\centering\\small", f"\\caption{{Measured training throughput and memory on the compute node ({esc(b['chip'])}, {esc(b['node'])}, torch {esc(b['torch'])}, {esc(b['device'])}; FP32)}}",65             "\\label{tab:benchmark}", "\\begin{tabular}{lrrrrrr}", "\\toprule", "Preset & Batch & Parameters & Steps/s & Examples/s & Peak memory (MB) & Latency/origin (ms) \\\\", "\\midrule"]66    for k, r in b["train"].items():67        preset, bs = k.rsplit("_bs", 1)68        inf = b["inference"].get(k, {})69        lines.append(f"{preset} & {bs} & {r['params']:,} & {r['steps_per_s']:.2f} & {r['ex_per_s']:.0f} & {r['peak_mem_mb']:.0f} & {inf.get('latency_ms_per_origin_batched', float('nan')):.2f} \\\\")70    lines += ["\\midrule", "Data loader (64/batch) & " + "; ".join(f"{k.replace('workers_', '')} workers: {v['ex_per_s']:.0f} ex/s" for k, v in b["loader"].items()) + " & & & & & \\\\",71              "\\bottomrule", "\\end{tabular}", "\\end{table}"]72    (T / "benchmark.tex").write_text("\n".join(lines).replace(",", "{,}").replace("{,}{,}", ","))737475if __name__ == "__main__":76    universe_tables(); baseline_spec_table(); benchmark_table()77    print("static tables written:", sorted(p.name for p in T.glob("*.tex")))78
Files · 013c8cc25081c2aa0aed28c2b71bcb00657ec293
Menu

Theme