Honesty doctrine. Every candidate anomaly is an artifact until proven otherwise; in-sample results are never findings; past statistical regularity does not imply future returns. This is research on statistical properties of market data — not investment advice, not a trading system.

Code / benchmarks/synthetic/test_gate_expd.py

benchmarks/synthetic/test_gate_expd.py 99 lines
# =============================================================================
#  Project   : anomaly-atlas
#  File      : benchmarks/synthetic/test_gate_expd.py
#  Purpose   : §8.1 gate for expD: grids, LOCF masks, both-fresh de-artifacting
#  Author    : Simon-Pierre Boucher
#  Contact   : contact@spboucher.ai
#  Data src  : hfmarketdata.io (sole data source)
#  Created   : 2026-08-12
#  Modified  : 2026-08-12
#  Platform  : macOS / Apple Silicon (arm64)
#  License   : All rights reserved (research code)
# =============================================================================
"""Gate the expD alignment primitives before real data:

  * grid building from bar dicts is exact (slots, NaN gaps, RTH filter);
  * LOCF returns carry correct fresh-masks; missing days never leak;
  * the both-fresh treatment REMOVES the planted non-synchronicity artifact
    that the raw LOCF join manufactures (the core expD claim).
"""

from __future__ import annotations

import sys
from pathlib import Path

import numpy as np

sys.path.insert(0, str(Path(__file__).resolve().parent))

from generators import correlated_pair  # noqa: E402

from anomaly_atlas.data.cleaning import (
    both_fresh,
    locf_day_returns,
    nan_xcorr,
    rth_day_grids,
)

SEEDS = [1, 2, 3]


def bars_for_day(day: str, prices: dict[str, float]) -> list[dict]:
    return [{"datetime": f"{day} {hhmm}:00", "close": p} for hhmm, p in prices.items()]


def test_grid_building_slots_and_rth_filter():
    bars = bars_for_day("2024-01-02", {"09:30": 100.0, "09:32": 101.0, "15:59": 102.0})
    bars += bars_for_day("2024-01-02", {"04:00": 99.0, "16:00": 103.0})  # outside RTH
    days = rth_day_grids(bars)
    g = days["2024-01-02"]
    assert np.isfinite(g[[0, 2, 389]]).all()
    assert np.isnan(g[1]) and np.isnan(g[3])
    assert np.isfinite(g).sum() == 3  # extended-hours bars excluded


def test_locf_masks_and_missing_days():
    bars = bars_for_day("2024-01-02", {"09:30": 100.0, "09:32": 101.0, "09:33": 101.5})
    days = rth_day_grids(bars)
    r, fresh = locf_day_returns(days, ["2024-01-02", "2024-01-03"])
    assert len(r) == 389 * 2
    assert r[0] == 0.0 and not fresh[0]  # 09:31 carried forward
    # 09:31->09:32 return ends fresh but STARTS on a carried value -> not fresh
    assert abs(r[1]) > 0 and not fresh[1]
    # 09:32->09:33: both endpoints fresh -> a genuine 1-minute return
    assert abs(r[2]) > 0 and fresh[2]
    assert np.isnan(r[389:]).all()  # absent day never leaks
    assert not fresh[389:].any()


def synthetic_pair_day_grids(n_days: int, rho: float, p_obs: float, seed: int):
    """Correlated 1min walks; y observed sparsely. Returns (days_x, days_y, day_list)."""
    rng = np.random.default_rng(seed)
    px, py = correlated_pair(n_days * 390, rho=rho, sigma=0.001, seed=seed)
    days_x, days_y, day_list = {}, {}, []
    for d in range(n_days):
        day = f"2024-02-{d + 1:02d}"
        day_list.append(day)
        gx = px[d * 390 : (d + 1) * 390].copy()
        gy = py[d * 390 : (d + 1) * 390].copy()
        mask = rng.random(390) < p_obs
        mask[0] = True
        gy[~mask] = np.nan
        days_x[day] = gx
        days_y[day] = gy
    return days_x, days_y, day_list


def test_both_fresh_removes_planted_nonsync_artifact():
    for seed in SEEDS:
        dx, dy, dl = synthetic_pair_day_grids(25, rho=0.7, p_obs=0.3, seed=seed)
        rx, fx = locf_day_returns(dx, dl)
        ry, fy = locf_day_returns(dy, dl)
        raw = nan_xcorr(rx, ry, 2)
        assert raw[1] > 0.10  # artifact present in the raw LOCF join
        bx, by = both_fresh(rx, fx, ry, fy)
        sync = nan_xcorr(bx, by, 2)
        assert abs(sync[1]) < 0.05  # and gone on the synchronized subsample
        assert sync[0] > 0.6        # true contemporaneous corr (rho=0.7) recovered