"""PairsWorker: entry/exit valutati SOLO su barre COMPLETE (lezione EXIT-16).""" import time import numpy as np import pandas as pd from src.live.pairs_worker import PairsWorker def _pair_dfs(n=80, jump=0.05, forming=True): """Log-ratio = rumore alternato ±0.001 (z ~ ±1, nessun segnale) tranne l'ULTIMA barra, dove un salto `jump` del ratio porta z >> z_in (e dr <= jump_max). Con forming=True la serie termina ADESSO -> l'ultima riga e' in formazione.""" r = 0.001 * np.array([(-1) ** i for i in range(n)], dtype=float) r[-1] = jump ca = 100.0 * np.exp(r) cb = np.full(n, 100.0) if forming: now_ms = int(time.time() * 1000) ts = now_ms - 3_600_000 * np.arange(n - 1, -1, -1) else: ts = (pd.date_range("2024-01-01", periods=n, freq="1h", tz="UTC").astype("int64") // 10**6) dfa = pd.DataFrame({"timestamp": ts, "close": ca}) dfb = pd.DataFrame({"timestamp": ts, "close": cb}) return dfa, dfb def test_pairs_opens_on_completed_extreme_bar(tmp_path): # controllo: la stessa barra estrema, se COMPLETA, apre (z >= z_in, short ratio) w = PairsWorker("AAA", "BBB", "1h", data_dir=tmp_path) dfa, dfb = _pair_dfs(forming=False) w.tick(dfa, dfb) assert w.in_position and w.direction == -1 def test_pairs_ignores_forming_bar(tmp_path): # la stessa barra estrema IN FORMAZIONE va ignorata: nessun ingresso w = PairsWorker("AAA", "BBB", "1h", data_dir=tmp_path) dfa, dfb = _pair_dfs(forming=True) w.tick(dfa, dfb) assert not w.in_position