"""ortholib — lab for strategies ORTHOGONAL to TP01 (the only thing worth a NEW live slot). The blind fleet proved (again) that directional BTC/ETH is trend-beta of TP01 — a ~1.3 ceiling, nothing new to deploy. The ONLY way to earn a live slot is a mechanism whose returns are NOT explained by TP01's trend. The most promising one that is ALSO executable at our real ~$600 (unlike XS01's 19-leg book, which needs ~$20k) is a **2-leg BTC/ETH relative-value book**: long one leg / short (or under-weight) the other. Being roughly market-neutral, its correlation to TP01 (a long-flat trend on the SUM) is naturally low. A candidate here is a BOOK function: def book(btc, eth) -> (w_btc, w_eth) where w_*[i] in [-1,1] is the per-leg weight (fraction of equity, sign = long/short), decided causally with data <= close[i]. The evaluator SHIFTS both legs (held during bar i+1), charges fees on BOTH legs' turnover, and: * builds the book's net DAILY return series, * scores it MARGINALLY vs TP01 via altlib.marginal_vs_tp01 (corr, OOS blend uplift, residual alpha, robust_oos jackknife) — the verdict that matters is ADDS, not Sharpe, * checks EXECUTABILITY at $600 (per-leg notional within the live cap, turnover sane), * runs the same online causality guard as the blind lab. Judge a candidate on: marginal_verdict == 'ADDS' AND robust_oos AND executable. Absolute PnL/DD are reported but are NOT the gate (a market-neutral sleeve has modest absolute numbers by design; its job is to improve the PORTFOLIO, not to win alone). """ from __future__ import annotations import sys from pathlib import Path import numpy as np import pandas as pd sys.path.insert(0, "/opt/docker/PythagorasGoal/scripts/research/alt") import altlib as al # noqa: E402 FEE_SIDE = al.FEE_SIDE CAPITAL = 600.0 # real mainnet capital (NOT the 2000 paper nominal) CAP_NOTIONAL = 300.0 # live guardrail: $300 notional / asset MIN_ORDER = 5.0 CAP_FRAC = CAP_NOTIONAL / CAPITAL # 0.5 of capital per leg def aligned(): """BTC & ETH 1d on COMMON dates (inner join), as two parallel DataFrames with a shared 'datetime'. Relative-value needs both legs at the same bar.""" b = al.get("BTC", "1d").copy() e = al.get("ETH", "1d").copy() b["dt"] = pd.to_datetime(b["datetime"], utc=True) e["dt"] = pd.to_datetime(e["datetime"], utc=True) common = pd.Index(b["dt"]).intersection(pd.Index(e["dt"])) b = b[b["dt"].isin(common)].sort_values("dt").reset_index(drop=True) e = e[e["dt"].isin(common)].sort_values("dt").reset_index(drop=True) return b, e def eval_book(book_fn, fee_side: float = FEE_SIDE) -> dict: """Honest backtest of a 2-leg BTC/ETH book. Weights decided at close[i] are HELD during bar i+1 (shift here -> no leak). Fee on both legs' turnover. Returns standalone metrics, the net DAILY series (for marginal scoring), and executability stats.""" btc, eth = aligned() wb, we = book_fn(btc, eth) wb = np.clip(np.nan_to_num(np.asarray(wb, float), nan=0.0), -1, 1) we = np.clip(np.nan_to_num(np.asarray(we, float), nan=0.0), -1, 1) n = len(btc) rb = al.simple_returns(btc["close"].values.astype(float)) re = al.simple_returns(eth["close"].values.astype(float)) pb = np.zeros(n); pb[1:] = wb[:-1] pe = np.zeros(n); pe[1:] = we[:-1] gross = pb * rb + pe * re turn = np.abs(np.diff(pb, prepend=0.0)) + np.abs(np.diff(pe, prepend=0.0)) net = gross - fee_side * turn net[0] = 0.0 idx = pd.DatetimeIndex(btc["dt"]) m = al._metrics_from_net(net, idx) daily = al._to_daily(pd.Series(net, index=idx)) # executability: worst per-leg notional fraction, and net market exposure max_leg = float(np.max(np.maximum(np.abs(pb), np.abs(pe)))) if n else 0.0 gross_lev = float(np.max(np.abs(pb) + np.abs(pe))) if n else 0.0 net_beta = float(np.mean(pb + pe)) # ~0 => market-neutral turnover_yr = float(turn.sum() / (len(turn) / 365.25)) return dict( pnl=m["ret"], maxdd=m["maxdd"], sharpe=m["sharpe"], cagr=m["cagr"], net=net, idx=idx, daily=daily, max_leg_frac=round(max_leg, 3), gross_lev=round(gross_lev, 3), net_beta=round(net_beta, 3), turnover_per_year=round(turnover_yr, 1), executable=bool(max_leg <= CAP_FRAC + 1e-9 and max_leg * CAPITAL >= MIN_ORDER), ) def marginal(book_fn, fee_side: float = FEE_SIDE) -> dict: """eval_book -> altlib.marginal_vs_tp01 on the book's daily returns. The real verdict.""" ev = eval_book(book_fn, fee_side) marg = al.marginal_vs_tp01(ev["daily"]) return dict(book=ev, marginal=marg) def causality_ok(book_fn, tail: int = 60, tol: float = 1e-4) -> dict: """Online-consistency guard: book(btc[:cut], eth[:cut]) must match book(full)[:cut] on the tail before each cut. Catches any look-ahead / global fit in either leg.""" btc, eth = aligned() wbf, wef = book_fn(btc, eth) wbf = np.nan_to_num(np.asarray(wbf, float)); wef = np.nan_to_num(np.asarray(wef, float)) n = len(btc) max_diff = 0.0; frac_bad = 0.0; checked = [] for cut in (int(n * 0.80), int(n * 0.92)): if cut <= tail + 5 or cut >= n: continue wbs, wes = book_fn(btc.iloc[:cut].reset_index(drop=True), eth.iloc[:cut].reset_index(drop=True)) wbs = np.nan_to_num(np.asarray(wbs, float)); wes = np.nan_to_num(np.asarray(wes, float)) if len(wbs) != cut or len(wes) != cut: return dict(ok=False, reason=f"book returned wrong length on prefix {cut}", max_diff=9.99, frac_bad=1.0) d = np.maximum(np.abs(wbs[cut - tail:cut] - wbf[cut - tail:cut]), np.abs(wes[cut - tail:cut] - wef[cut - tail:cut])) max_diff = max(max_diff, float(np.max(d)) if len(d) else 0.0) frac_bad = max(frac_bad, float(np.mean(d > tol)) if len(d) else 0.0) checked.append(cut) ok = (max_diff <= max(tol * 10, 1e-3)) and (frac_bad <= 0.02) return dict(ok=bool(ok), max_diff=round(max_diff, 6), frac_bad=round(frac_bad, 4), checked_at=checked) # convenient causal helpers re-exported (same as blind/altlib) simple_returns = al.simple_returns log_returns = al.log_returns ema = al.ema; sma = al.sma; rolling_std = al.rolling_std; zscore = al.zscore rsi = al.rsi; realized_vol = al.realized_vol; donchian = al.donchian; bbands = al.bbands vol_target = al.vol_target __all__ = ["aligned", "eval_book", "marginal", "causality_ok", "CAPITAL", "CAP_FRAC", "FEE_SIDE", "simple_returns", "log_returns", "ema", "sma", "rolling_std", "zscore", "rsi", "realized_vol", "donchian", "bbands", "vol_target"]