Vai al contenuto
PAPER SIAT 2026Apri la pagina della ricerca
Cryptoverso

Calcolatore del libro · C04

C04 — Frazione ottimale, rischio di rovina e rischio complessivo

Calcolatore 4 — Quanto rischiare

Quaderno del capitolo «Il dimensionamento è la strategia» di La matematica di chi perde.

Tre conti sui tuoi numeri: quanto rischiare per operazione dato il capitale e la perdita massima che accetti; qual è la frazione ottimale teorica dato il vantaggio che pensi di avere; e quanto vale il rischio complessivo delle tue posizioni aperte tenendo conto di quanto sono correlate.

Poi il grafico della rovina. È il conto da fare prima di aumentare la dimensione, non dopo.

Le righe marcate PROVA sono quelle da cambiare: cambiale e riesegui per vedere l'effetto. Il resto — comprese le righe marcate NON TOCCARE — serve a mantenere il risultato confrontabile con quello stampato nel libro.

Espandi lo script di questo passo
calc_04_dimensionamento.py
python
import matplotlib.pyplot as plt
import numpy as np

from cvbook import seed_for
from cvbook.dati import carica
from cvbook.lingua import t
from cvbook.metriche import GIORNI_ANNO, rendimenti, rischio_di_rovina

1. La curva che sale, tocca la vetta e crolla

Un gioco con un vantaggio reale e noto: si vince una certa percentuale delle volte, guadagnando quanto si rischia. È un vantaggio che sui mercati veri non si trova. La domanda è: quanto rischiare, ogni volta?

Due pannelli affiancati sulla frazione di capitale rischiata a ogni operazione, da 1 a 50%. A sinistra il capitale mediano dopo 500 operazioni su scala logaritmica, da 10 alla meno 20 a 10: sale fino a 12 volte il capitale iniziale intorno al 10% e poi crolla, con una riga punteggiata sul massimo. A destra la quota di percorsi finiti sotto un quinto del capitale: quasi zero fino al 10%, 37% rischiando il 20%, 83% al 30%, 99% al 40%.

La stessa scommessa vantaggiosa, ripetuta 500 volte, rischiando ogni volta una frazione diversa.Fonte: Binance Data Vision · Periodo: 2017-08-17 … 2026-06-30 · Metodo: Quattromila percorsi simulati con seme fissato, vincita 55% delle volte e guadagno pari a quanto si rischia; per ogni frazione, la mediana del capitale finale e la quota di percorsi scesi sotto un quinto.

Output

vantaggio: si vince il 55% delle volte, rapporto 1

frazione con la crescita mediana migliore (simulata): 10%
frazione ottimale teorica:                            10%

capitale mediano rischiando il 10%: 12.2x
  rischiando il   2%:         2.46x   probabilita' di rovina   0.0%
  rischiando il  20%:         0.93x   probabilita' di rovina  37.1%
  rischiando il  30%:         0.00x   probabilita' di rovina  82.5%
  rischiando il  40%:         0.00x   probabilita' di rovina  98.9%

Avere ragione non basta. Bisogna anche rischiare la quantita' giusta: oltre un certo punto, aumentare il rischio RIDUCE il risultato — non lo aumenta con piu' varianza, lo riduce e basta.
Espandi lo script di questo passo
calc_04_dimensionamento.py
python
VINCITE = 0.55        # ← quota di operazioni vincenti
                      # PROVA / TRY: 0,52 (vedi esercizio 1) · 0,55 · 0,60
RAPPORTO = 1.0        # ← quanto si guadagna rispetto a quanto si rischia
                      # PROVA / TRY: 0,5 · 1,0 · 2,0
OPERAZIONI = 500      # PROVA / TRY: 100 (veloce) · 500 · 2000 (curva più liscia)
PERCORSI = 4000       # PROVA / TRY: 500 (veloce, mediana rumorosa) · 4000 · 20000

frazioni = np.arange(0.01, 0.51, 0.01)
rng = np.random.default_rng(seed_for("calc-dimensionamento"))
# NON TOCCARE / DO NOT CHANGE: il seme fissa i numeri citati nel testo qui
# sotto (la frazione ottimale simulata, le probabilità di rovina) — cambiarlo
# dopo aver visto il risultato è il p-hacking che il libro smonta altrove.
# The seed fixes the numbers quoted in the text below (the simulated optimal
# fraction, the ruin probabilities) — changing it after seeing the result is
# the p-hacking the book takes apart elsewhere.
esiti = rng.random((PERCORSI, OPERAZIONI)) < VINCITE

mediane, rovine = [], []
for f in frazioni:
    passi = np.where(esiti, 1 + f * RAPPORTO, 1 - f)
    curve = np.cumprod(passi, axis=1)
    mediane.append(float(np.median(curve[:, -1])))
    rovine.append(float((curve[:, -1] < 0.2).mean()))

mediane, rovine = np.array(mediane), np.array(rovine)
ottimale = float(frazioni[int(np.argmax(mediane))])

with avvio.figura("schermo"):
    fig, (sx, dx) = plt.subplots(1, 2, figsize=(12, 4.5))
    sx.plot(frazioni * 100, mediane, linewidth=2)
    sx.axvline(ottimale * 100, linestyle=":", linewidth=1.5)
    sx.set_yscale("log")
    sx.set_xlabel(t("Frazione di capitale rischiata per operazione (%)",
                     "Fraction of capital risked per trade (%)"))
    sx.set_ylabel(t(f"Capitale mediano dopo {OPERAZIONI} operazioni (scala log)",
                     f"Median capital after {OPERAZIONI} trades (log scale)"))

    dx.plot(frazioni * 100, rovine * 100, linewidth=2)
    dx.set_xlabel(t("Frazione rischiata per operazione (%)", "Fraction risked per trade (%)"))
    dx.set_ylabel(t("Percorsi sotto un quinto del capitale (%)", "Paths below a fifth of capital (%)"))
    plt.show()

kelly = VINCITE - (1 - VINCITE) / RAPPORTO
print(t(f"vantaggio: si vince il {VINCITE:.0%} delle volte, rapporto {RAPPORTO:g}\n",
        f"edge: wins {VINCITE:.0%} of the time, ratio {RAPPORTO:g}\n"))
print(t(f"frazione con la crescita mediana migliore (simulata): {ottimale:.0%}",
        f"fraction with the best median growth (simulated):     {ottimale:.0%}"))
print(t(f"frazione ottimale teorica:                            {kelly:.0%}",
        f"theoretical optimal fraction:                         {kelly:.0%}"))
print(t(f"\ncapitale mediano rischiando il {ottimale:.0%}: {mediane[int(np.argmax(mediane))]:,.1f}x",
        f"\nmedian capital risking {ottimale:.0%}: {mediane[int(np.argmax(mediane))]:,.1f}x"))
for f in (0.02, 0.20, 0.30, 0.40):
    k = int(round(f * 100)) - 1
    if 0 <= k < len(frazioni):
        print(t(f"  rischiando il {f:>4.0%}: {mediane[k]:12,.2f}x   "
                f"probabilita' di rovina {rovine[k]:6.1%}",
                f"  risking {f:>4.0%}: {mediane[k]:12,.2f}x   "
                f"probability of ruin {rovine[k]:6.1%}"))

print(t("\nAvere ragione non basta. Bisogna anche rischiare la quantita' giusta: "
        "oltre un certo punto, aumentare il rischio RIDUCE il risultato — non lo "
        "aumenta con piu' varianza, lo riduce e basta.",
        "\nBeing right isn't enough. You also have to risk the right amount: "
        "past a certain point, increasing risk REDUCES the outcome — it doesn't "
        "boost it with more variance, it just reduces it."))

2. La curva è piatta a sinistra e ripida a destra

Il motivo per cui, quando sei incerto sul vantaggio — e lo sei sempre — devi sbagliare per difetto.

Output

  frazione   capitale mediano    perdita rispetto al massimo
        2%               2.5x                        -79.9%
        4%               5.0x                        -59.5%
        6%               8.2x                        -33.1%
        8%              11.1x                         -9.6%
       10%              12.2x                          0.0%
       12%              11.1x                         -9.6%
       14%               8.1x                        -33.4%
       16%               4.9x                        -60.1%
       18%               2.4x                        -80.6%

Stare sotto costa poco, stare sopra costa moltissimo. E' l'asimmetria che perdona il difetto e punisce l'eccesso.
Espandi lo script di questo passo
calc_04_dimensionamento.py
python
i_ott = int(np.argmax(mediane))
print(f"{t('frazione', 'fraction'):>10s} {t('capitale mediano', 'median capital'):>18s} "
      f"{t('perdita rispetto al massimo', 'loss relative to peak'):>30s}")
for delta in (-8, -6, -4, -2, 0, 2, 4, 6, 8):
    k = i_ott + delta
    if 0 <= k < len(frazioni):
        perdita = mediane[k] / mediane[i_ott] - 1
        print(f"{frazioni[k]:10.0%} {mediane[k]:17,.1f}x {perdita:29.1%}")

print(t("\nStare sotto costa poco, stare sopra costa moltissimo. E' l'asimmetria "
        "che perdona il difetto e punisce l'eccesso.",
        "\nBeing under costs little, being over costs a lot. It's the asymmetry "
        "that forgives shortfall and punishes excess."))

3. Il tuo rischio per operazione

Nota la distinzione che quasi tutti confondono: la dimensione è quanto capitale impegni, il rischio è quanto perdi se va male. È il secondo che va tenuto costante.

Output

capitale:                      20,000 euro
rischio per operazione:           200 euro (1.0%)
uscita in perdita a:             8.0% dall'ingresso
→ dimensione della posizione: 2,500 euro (12.5% del capitale)

Se l'uscita fosse a meta' distanza, la dimensione raddoppierebbe a parita' di rischio. E' esattamente il meccanismo per cui gli stop stretti spesso AUMENTANO il rischio complessivo invece di ridurlo.
Espandi lo script di questo passo
calc_04_dimensionamento.py
python
CAPITALE = 20_000.0              # PROVA / TRY: il tuo capitale reale
RISCHIO_PER_OPERAZIONE = 0.01   # ← percentuale del capitale, fra 0,5% e 2%
                                 # PROVA / TRY: 0,005 · 0,01 · 0,02
DISTANZA_USCITA = 0.08          # ← a che distanza esci in perdita
                                 # PROVA / TRY: 0,04 (stop stretto) · 0,08 · 0,15

rischio_euro = CAPITALE * RISCHIO_PER_OPERAZIONE
dimensione = rischio_euro / DISTANZA_USCITA

print(t(f"capitale:                {CAPITALE:12,.0f} euro", f"capital:                 {CAPITALE:12,.0f} euros"))
print(t(f"rischio per operazione:  {rischio_euro:12,.0f} euro ({RISCHIO_PER_OPERAZIONE:.1%})",
        f"risk per trade:          {rischio_euro:12,.0f} euros ({RISCHIO_PER_OPERAZIONE:.1%})"))
print(t(f"uscita in perdita a:     {DISTANZA_USCITA:12.1%} dall'ingresso",
        f"stop loss at:            {DISTANZA_USCITA:12.1%} from entry"))
print(t(f"→ dimensione della posizione: {dimensione:,.0f} euro "
        f"({dimensione / CAPITALE:.1%} del capitale)",
        f"→ position size: {dimensione:,.0f} euros "
        f"({dimensione / CAPITALE:.1%} of capital)"))
print(t("\nSe l'uscita fosse a meta' distanza, la dimensione raddoppierebbe a "
        "parita' di rischio. E' esattamente il meccanismo per cui gli stop stretti "
        "spesso AUMENTANO il rischio complessivo invece di ridurlo.",
        "\nIf the stop were at half the distance, size would double for the same "
        "risk. That's exactly the mechanism by which tight stops often INCREASE "
        "overall risk instead of reducing it."))

4. Il conto della rovina

Output

 rischio per op.   10 perdite di fila   serve per tornare   prob. di rovina
            0.5%               95.1%                 5%              0.0%
            1.0%               90.4%                11%              0.0%
            2.0%               81.7%                22%              0.0%
            5.0%               59.9%                67%              0.5%
           10.0%               34.9%               187%             18.4%
           20.0%               10.7%               831%             79.0%

Dieci perdite consecutive, con un metodo che vince il 55% delle volte, capitano circa una volta ogni tremila operazioni: quasi certamente almeno una volta nella tua vita operativa.
Espandi lo script di questo passo
calc_04_dimensionamento.py
python
print(f"{t('rischio per op.', 'risk per trade'):>16s} "
      f"{t('10 perdite di fila', '10 losses in a row'):>20s} "
      f"{t('serve per tornare', 'needed to recover'):>19s} "
      f"{t('prob. di rovina', 'ruin prob.'):>17s}")
for rischio in (0.005, 0.01, 0.02, 0.05, 0.10, 0.20):  # PROVA / TRY: aggiungi il tuo rischio per operazione
    resta = (1 - rischio) ** 10
    recupero = 1 / resta - 1
    # NON TOCCARE / DO NOT CHANGE: seme fissato riga per riga (uno per
    # rischio) perché la probabilità di rovina stampata sia sempre la stessa.
    # Seed fixed row by row (one per risk level) so the printed ruin
    # probability is always the same.
    prob = rischio_di_rovina(VINCITE, RAPPORTO, rischio, operazioni=1000,
                             soglia=0.2, campioni=4000,
                             rng=np.random.default_rng(seed_for(f"rovina-{rischio}")))
    print(f"{rischio:16.1%} {resta:19.1%} {recupero:18.0%} {prob:17.1%}")

print(t("\nDieci perdite consecutive, con un metodo che vince il 55% delle volte, "
        "capitano circa una volta ogni tremila operazioni: quasi certamente almeno "
        "una volta nella tua vita operativa.",
        "\nTen consecutive losses, with a method that wins 55% of the time, happen "
        "roughly once every three thousand trades: almost certainly at least once "
        "in your trading lifetime."))

5. Il rischio complessivo, che non è la somma

Se hai cinque posizioni che rischiano il 2% ciascuna, non stai rischiando il 2%. E nemmeno il 10%, se non sono perfettamente correlate.

Output

5 posizioni al 2% ciascuna

 correlazione   rischio complessivo
          0.0                  4.5%
          0.3                  6.6%
          0.7                  8.7%
          0.9                  9.6%
          1.0                 10.0%

Nei momenti brutti la correlazione sale — il Lab 7 lo misura — quindi il numero da usare per il limite complessivo e' quello delle righe in basso, non quello delle righe in alto.
Espandi lo script di questo passo
calc_04_dimensionamento.py
python
POSIZIONI = 5           # PROVA / TRY: il numero VERO delle tue posizioni aperte
RISCHIO_CIASCUNA = 0.02  # PROVA / TRY: il rischio che assegni a ciascuna

print(t(f"{POSIZIONI} posizioni al {RISCHIO_CIASCUNA:.0%} ciascuna\n",
        f"{POSIZIONI} positions at {RISCHIO_CIASCUNA:.0%} each\n"))
print(f"{t('correlazione', 'correlation'):>13s} {t('rischio complessivo', 'overall risk'):>21s}")
for rho in (0.0, 0.3, 0.7, 0.9, 1.0):
    varianza = POSIZIONI * RISCHIO_CIASCUNA**2 * (1 + (POSIZIONI - 1) * rho)
    # `sqrt(varianza)`, e basta: prima qui c'era `sqrt(varianza / POSIZIONI) *
    # sqrt(POSIZIONI)`, che vale esattamente lo stesso e non e' lo stesso da
    # leggere. In un libro il cui valore e' che il codice si possa seguire,
    # una divisione e una moltiplicazione che si annullano sono un ostacolo.
    print(f"{rho:13.1f} {np.sqrt(varianza):21.1%}")

print(t("\nNei momenti brutti la correlazione sale — il Lab 7 lo misura — quindi il "
        "numero da usare per il limite complessivo e' quello delle righe in basso, "
        "non quello delle righe in alto.",
        "\nIn bad moments correlation rises — Lab 7 measures it — so the number to "
        "use for the overall limit is the one from the bottom rows, not the top "
        "ones."))

Esercizi

  1. Nella prima cella metti VINCITE = 0.52, che è già un vantaggio molto difficile da avere davvero. La frazione ottimale crolla, e con essa il margine d'errore.
  2. Dimezza il vantaggio che credi di avere e rifai il conto: se stavi rischiando la frazione ottimale del vantaggio sopravvalutato, ora sei nel ramo discendente della curva senza aver fatto niente.
  3. Nella quinta cella metti il numero vero delle tue posizioni aperte e la correlazione misurata con il Lab 7. Confronta con il limite che avevi in mente.

Riproducibilità e download

Eseguito il 2026-08-27 dal quaderno del repository

Il quaderno

I dati

  • btcusdt.parquet93,2 KB

    sha256 ea75ad84e6e981507054df5c622c6b0ec3c8849c1f4dd007721878d4e4c8a329

    Fonte: Binance Data Vision · Periodo: 2017-08-17 → 2026-06-30 · 3240 righe · estratto 2026-08-16

Torna all’indice dei lab