fix: il massimo di una simulazione non e' una statistica della strategia
L'operatore ha contestato un numero che avevo citato io ("anno migliore +184%"). Aveva
ragione, e l'errore era di METODO, non di calcolo.
IL NUMERO E' VERO. Tracciato l'anno estremo: 18 blocchi da 20 giorni, nessuno
significativamente negativo (+20% +15% +12% +10% +8% ... -1%). La popolazione lo consente:
blocchi 20g reali con mediana -0.1%, p95 +8.5%, max +22.4%, skew +2.15 — firma classica di
un trend-follower. E la materia prima esiste: la miglior finestra 365g REALE e' +89.8%.
MA CITARLO ERA SBAGLIATO, perche' il massimo di N estrazioni cresce con N:
su 1.000 anni simulati -> max +96.0%
su 5.000 -> max +135.2%
su 114.000 -> max +184.3%
Il numero che avevo dato parlava del mio N_PATHS, non del book. Con 1.000 percorsi avrei
scritto +96% per la stessa identica strategia.
I NUMERI CORRETTI SONO I PERCENTILI: p1 -11.9% · p5 -5.5% · MEDIANA +16.0% · p95 +51.2% ·
p99 +71.8%. Vale simmetricamente per il "peggiore -27.4%", anch'esso minimo campionario (a
1.000 percorsi era -19.1%): la coda sinistra onesta e' p1 = -11.9%.
CABLATO: r0726_decadimento.py aveva lo stesso difetto ("drawdown PEGGIORE 44.2%") -> ora
stampa p99 = 26.0% e dichiara che il 44.2% e' un massimo campionario da non citare come
"il caso peggiore".
REGOLA: il massimo (o il minimo) di una simulazione e' una statistica del NUMERO DI
SIMULAZIONI, non della strategia. Si citano i percentili. Stessa famiglia dell'errore gia'
codificato oggi ("un percentile stampato a 0 decimali mente esattamente agli estremi"):
gli estremi sono dove i numeri sembrano piu' informativi e lo sono meno.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -363,3 +363,59 @@ sopra i soldi versati**: il piano non fallirebbe, semplicemente non renderebbe.
|
||||
Nessun cambio a book, pesi o piano. Cambia **cosa si sorveglia**: la domanda "l'edge c'e' ancora?"
|
||||
non ha una risposta nel backtest, ce l'ha solo nel forward — che e' esattamente cio' che i monitor
|
||||
paper e i gate pre-registrati esistono per misurare.
|
||||
|
||||
---
|
||||
|
||||
## Addendum 3 — "+184% sembra alto, da dove arriva?"
|
||||
|
||||
Obiezione dell'operatore su un numero che avevo citato io. **Aveva ragione, e l'errore era di
|
||||
metodo, non di calcolo.**
|
||||
|
||||
### Il numero e' vero
|
||||
|
||||
Non e' un bug. Tracciato l'anno estremo: e' composto da 18 blocchi da 20 giorni, e **nessuno di
|
||||
essi e' negativo in modo significativo**:
|
||||
|
||||
```
|
||||
+20% +15% +12% +10% +8% +8% +8% +7% +6% +6% +5% +5% +2% +1% +0% -0% -0% -1%
|
||||
```
|
||||
|
||||
La popolazione da cui pesca lo consente: blocchi 20g reali con mediana **−0.1%**, p95 **+8.5%**,
|
||||
max **+22.4%**, **skew +2.15** — la firma classica di un trend-follower (molte perdite piccole,
|
||||
poche vincite grandi). E la materia prima esiste davvero: **la miglior finestra 365g della storia
|
||||
reale e' +89.8%** (il 2020 fece +58% come anno di calendario).
|
||||
|
||||
### Ma citarlo era sbagliato
|
||||
|
||||
```
|
||||
su 1.000 anni simulati: max +96.0%
|
||||
su 5.000 anni simulati: max +135.2%
|
||||
su 20.000 anni simulati: max +135.2%
|
||||
su 114.000 anni simulati: max +184.3%
|
||||
```
|
||||
|
||||
**Il massimo di N estrazioni cresce con N: descrive la taglia della mia simulazione, non la
|
||||
strategia.** Con 1.000 percorsi avrei scritto "+96%" e sarebbe stata la stessa strategia. Il numero
|
||||
che avevo dato all'operatore parlava del mio `N_PATHS`, non del book.
|
||||
|
||||
I numeri corretti sono i **percentili**, che non dipendono dal campione:
|
||||
|
||||
| p0.1 | p1 | p5 | p50 | p95 | p99 | p99.9 |
|
||||
|---|---|---|---|---|---|---|
|
||||
| −17.6% | −11.9% | −5.5% | **+16.0%** | +51.2% | +71.8% | +99.9% |
|
||||
|
||||
Vale simmetricamente per il "peggiore": il **−27.4%** che avevo citato e' anch'esso un minimo
|
||||
campionario (a 1.000 percorsi era −19.1%). Il numero onesto per la coda sinistra e' **p1 = −11.9%**.
|
||||
|
||||
### Cablato
|
||||
|
||||
Corretto anche `r0726_decadimento.py`, che riportava "drawdown PEGGIORE 44.2%" con lo stesso
|
||||
difetto: ora stampa **p99 = 26.0%** e dichiara esplicitamente che il 44.2% e' un massimo
|
||||
campionario da non citare come "il caso peggiore".
|
||||
|
||||
### Regola trasferibile
|
||||
|
||||
**Il massimo (o il minimo) di una simulazione non e' una statistica della strategia: e' una
|
||||
statistica del numero di simulazioni.** Si citano i percentili. E' la stessa famiglia dell'errore
|
||||
gia' codificato oggi ("un percentile stampato a 0 decimali mente esattamente agli estremi"): gli
|
||||
estremi sono il posto dove i numeri sembrano piu' informativi e lo sono meno.
|
||||
|
||||
@@ -117,8 +117,13 @@ def main() -> None:
|
||||
base = simulate(paths, wall)
|
||||
dd = maxdd(base["eq"])
|
||||
print(f"\n Sui {N_PATHS:,} percorsi simulati (20 anni ciascuno):")
|
||||
# ⚠️ Il MASSIMO di N estrazioni cresce con N: descrive la taglia della simulazione, non la
|
||||
# strategia. Si citano i PERCENTILI, che non dipendono dal numero di percorsi. (Lezione del
|
||||
# 26/07: avevo citato "anno migliore +184%" che a 1.000 percorsi sarebbe stato +96%.)
|
||||
print(f" drawdown massimo mediano {np.median(dd):.1%} p90 {np.percentile(dd,90):.1%}"
|
||||
f" PEGGIORE {dd.max():.1%}")
|
||||
f" p99 {np.percentile(dd,99):.1%}")
|
||||
print(f" (il PEGGIORE dei {N_PATHS:,} percorsi e' {dd.max():.1%}, ma e' un massimo campionario:")
|
||||
print(f" cresce col numero di simulazioni e non va citato come 'il caso peggiore')")
|
||||
# anni in perdita: quota di anni-calendario chiusi sotto l'anno precedente
|
||||
ann = base["eq"][:, ::365]
|
||||
yr_ret = ann[:, 1:] / ann[:, :-1] - 1.0
|
||||
@@ -129,7 +134,7 @@ def main() -> None:
|
||||
print(f" percorso PEGGIORE dei {N_PATHS:,}: capitale finale ${base['cap'][worst]:,.0f} "
|
||||
f"contro ${DP.START + 0:,.0f}+versamenti = ${START + DEP*12*YEARS:,.0f} messi dentro")
|
||||
print(f"\n -> No, il modello non assume che non si perda: perde nel {neg_d:.0%} dei giorni,")
|
||||
print(f" ha drawdown mediani del {np.median(dd):.0%} (peggiore {dd.max():.0%}) e anni")
|
||||
print(f" ha drawdown mediani del {np.median(dd):.0%} (p99 {np.percentile(dd,99):.0%}) e anni")
|
||||
print(f" negativi nel {float((yr_ret < 0).mean()):.0%} dei casi.")
|
||||
print(f" Cio' che il modello NON contiene e' un'altra cosa -> parte 2.")
|
||||
|
||||
|
||||
Reference in New Issue
Block a user