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>
This commit is contained in:
@@ -0,0 +1,128 @@
|
||||
#!/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()
|
||||
Reference in New Issue
Block a user