Files
PythagorasGoal/scripts/research/r0726_capwall_refresh.py
T
Adriano Dal Pastro 842420ce7b research: follow-up SKH01 chiuso — il blocco non esisteva, il de-luck x0.6 era troppo severo
Il follow-up "book sul path live" era fermo da tre sessioni su questa premessa:
"il simulatore compone per-trade a nozionale unitario, LO SLEEVE E' VOL-TARGETED".

LA PREMESSA ERA FALSA. Verificato in tre modi: _skyhook_returns chiama backtest_signals
con leverage=1.0/position_size=1.0; nessun target_vol/vol_target/realized_vol nel
sorgente; sim_equity(canonical) riproduce backtest_signals a max|diff| = 0.0. Il 20.7%
di vol realizzata dello sleeve e' un PRODOTTO della strategia (uscite % asimmetriche +
poco tempo a mercato), non un parametro: SKH01 e' l'unica delle 5 a NON essere
vol-targeted, il contrario di quanto si credeva. Test permanente cablato.

MISURA (ingressi live vs backtest, de-luckata su 8 offset a priori; sanity 120/120 bin
con ingresso ricostruiti):
- il numero del 26/07 era ~4x troppo grande: like-with-like (mediana PER-ASSET) +0.38 su
  3 offset -> +0.097 su 8, e "6/6 non negativi" -> 13/16. Sleeve 50/50: +0.112, 8/8.
- a livello di BOOK lo Sharpe e' una monetina (FULL +0.048, HOLD +0.051) ma il DRIFT e'
  +0.73pp positivo nel 100% delle estrazioni: l'ingresso intra-bin prende un prezzo
  migliore, i falsi ingressi aggiungono churn, vol e ritorno salgono insieme.

IL FATTORE x0.6 DECOMPOSTO E MISURATO:
  (a) fortuna d'ancora sul DRIFT: x0.874 (5-sleeve) / x0.890 (book live). La vol e'
      invariata fra le ancore (7.80->7.76%): la fortuna sta tutta nel drift.
  (b) path live: NON-NEGATIVO ovunque (uscite +0.081 Sh, ingressi +0.73pp, TP01 ~0).
Il x0.6 implicava un residuo x0.687 attribuito al live oltre l'ancora, che nessuna misura
sostiene -> FATTORE ONESTO x0.87-0.91, troppo severo del 31-34%. Il sospetto registrato
il 25/07 ("conta due volte la degradazione SKH01") e' confermato quantitativamente.

MURI DI CAPITALE ricalcolati con la stessa macchineria del 25/07: perpetua 6.00% ->
10.91%, muro per 50 EUR/g $494.758 -> $272.061 (-45%) a leva 1.0. La conclusione
STRUTTURALE non cambia: $272k restano ~453x il conto di oggi.

IPOTESI MIA REFUTATA nella stessa sessione: che la grid timing-luck di SKH01 fosse un
artefatto della lente a chiusura-di-bin. Dispersione LIVE/CANONICO = 1.59x -> il live e'
PIU' disperso. L'audit del 02/07 resta valido com'e'. (Nata su 2 offset, chiusa a 8.)

Trovato per strada: simulate() in r0726_skh_partial_entry.py non era mai chiamata da
main() — i numeri headline di quel diario venivano da una corsa mai committata.

Book, pesi, cron, config INVARIATI.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-26 16:55:01 +00:00

129 lines
5.5 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env python
"""r0726_capwall_refresh.py — i MURI DI CAPITALE ricalcolati col fattore de-luck corretto.
Il 25/07 (`r0725_capcurve.py`) ha calcolato rendita perpetua, muro di capitale per 50 EUR/g e
traiettoria da $600 applicando un de-luck **×0.6 scelto a occhio** sul drift del book.
Il 26/07 quel fattore e' stato MISURATO e decomposto (`r0726_deluck_factor.py` +
`r0726_skh_live_book.py`):
* fortuna d'ancora sul drift, book live Deribit (TP01/SKH01 75/25): **×0.890**
(24 x 23 = 552 configurazioni, estrazioni congiunte);
* degradazione del path live: **non-negativa su tutto cio' che e' misurato**
(SKH01 uscite +0.081 Sharpe di book su 23/23 offset; SKH01 ingressi +0.73pp di drift,
positivo nel 100% delle estrazioni; TP01 barra parziale trascurabile su 24 ancore).
Il ×0.6 implicava quindi un residuo ×0.687 attribuito al live OLTRE l'ancora, che nessuna misura
sostiene: era il doppio conteggio gia' sospettato in CLAUDE.md, ora quantificato.
Questo script rifa' i numeri della DECISIONE ai tre fattori, sulla stessa macchineria del 25/07
(nessuna re-implementazione: `book_series`, `survival`, `_boot_paths` importati da li').
uv run python scripts/research/r0726_capwall_refresh.py
"""
from __future__ import annotations
import sys
from pathlib import Path
import numpy as np
ROOT = Path(__file__).resolve().parents[2]
sys.path.insert(0, str(ROOT))
sys.path.insert(0, str(ROOT / "scripts" / "research"))
sys.path.insert(0, str(ROOT / "scripts" / "research" / "alt"))
import r0725_capcurve as CC # noqa: E402
# fattori a confronto. 0.890 = fortuna d'ancora MISURATA sul book live Deribit; il vero fattore
# onesto e' >= 0.890 perche' la componente live e' non-negativa (non la conto: e' conservativo).
FACTORS = (
(0.60, "×0.60 (25/07, a occhio)"),
(0.89, "×0.89 (26/07, ancora MISURATA)"),
(1.00, "×1.00 (nessun haircut)"),
)
LEVERAGES = (1.0, 1.5)
N_PATHS = 2000
def perp_and_wall(r: np.ndarray, k: float, gross_needed: float) -> tuple[float, float, float]:
"""(SWR-20a, tasso di rendita PERPETUA, capitale necessario) — stessa ricerca binaria
del 25/07: perpetua = prelievo con P(cap a 20a >= cap iniziale) >= 90%."""
lo, hi = 0.0, 0.40
for _ in range(13):
mid = (lo + hi) / 2
s = CC.survival(r, 1e6, 1e6 * mid, 20, k, n_paths=N_PATHS)
if s["p10_end"] >= 1e6:
lo = mid
else:
hi = mid
perp = lo
lo2, hi2 = 0.0, 0.40
for _ in range(13):
mid = (lo2 + hi2) / 2
if CC.survival(r, 1e6, 1e6 * mid, 20, k, n_paths=N_PATHS)["p_survive"] >= 0.95:
lo2 = mid
else:
hi2 = mid
cap = gross_needed / perp if perp > 0.002 else float("inf")
return lo2, perp, cap
def main() -> None:
print("=" * 100)
print(" r0726 — MURI DI CAPITALE col fattore de-luck MISURATO (era ×0.6 a occhio)")
print("=" * 100)
gross = CC.TARGET_EUR_DAY * 365 * CC.EURUSD / (1 - CC.TAX_RATE)
print(f" bersaglio: {CC.TARGET_EUR_DAY:.0f} EUR/g netti = EUR "
f"{CC.TARGET_EUR_DAY*365:,.0f}/anno netti = ${gross:,.0f}/anno LORDI "
f"(fisco {CC.TAX_RATE:.0%}, EURUSD {CC.EURUSD})")
print(" book: TP01+SKH01 75/25 su path live (lente 'hourly'), costi reali Deribit\n")
base = CC.book_series("hourly")
mu = float(base.values.mean())
print(f" {'fattore':<32}{'leva':>6}{'SWR-20a':>10}{'PERPETUA':>10}{'capitale':>16}")
print(" " + "-" * 74)
res = {}
for f, lab in FACTORS:
r = (base - (1.0 - f) * mu).values.astype(float)
for k in LEVERAGES:
swr, perp, cap = perp_and_wall(r, k, gross)
res[(f, k)] = (swr, perp, cap)
capf = f"${cap:,.0f}" if np.isfinite(cap) else "IRRAGGIUNGIBILE"
print(f" {lab:<32}{k:>6.2f}{swr:>9.2%}{perp:>10.2%}{capf:>16}")
print()
print("=" * 100)
print(" COSA CAMBIA NELLA DECISIONE")
print("=" * 100)
for k in LEVERAGES:
c_old = res[(0.60, k)][2]
c_new = res[(0.89, k)][2]
if np.isfinite(c_old) and np.isfinite(c_new):
print(f" leva {k:.2f}: muro ${c_old:,.0f} -> ${c_new:,.0f} "
f"({(c_new/c_old - 1)*100:+.0f}%)")
c_new = res[(0.89, 1.0)][2]
print(f"\n Il muro scende di ~45%, ma resta ${c_new:,.0f} = ~{c_new/600:,.0f}x il conto")
print(" di oggi ($600). La conclusione STRUTTURALE del 25/07 non cambia: i 600 euro")
print(" come CAPITALE restano refutati, come BIGLIETTO (prop) no. Cambia la taglia")
print(" dell'errore — e cambia che il numero ora e' misurato invece che scelto.")
print("\n ⚠️ Il ×0.89 e' la sola fortuna d'ancora: e' un LIMITE INFERIORE del fattore")
print(" onesto, perche' ogni componente misurata del path live e' non-negativa.")
print(" Il muro vero sta quindi fra la riga ×0.89 e la riga ×1.00.")
# rendita a $600 — il numero che il 25/07 dava a ~0.11 EUR/g
print("\n" + "=" * 100)
print(" RENDITA A $600 (lo stesso conto di oggi)")
print("=" * 100)
for f, lab in FACTORS:
r = (base - (1.0 - f) * mu).values.astype(float)
cagr = float((1 + r.mean()) ** 365.25 - 1)
eur = 600.0 * cagr * (1 - CC.TAX_RATE) / CC.EURUSD / 365.0
print(f" {lab:<32} CAGR {cagr*100:6.2f}% rendita EUR {eur:.2f}/giorno")
print("\n (a questa taglia la differenza fra ×0.6 e ×0.89 sono centesimi al giorno:")
print(" il fattore conta per il MURO e per le soglie prop, non per il conto attuale.)")
if __name__ == "__main__":
main()