#!/usr/bin/env python3
"""
Confronto quantitativo fra il regime di parametri SPX e quello BTC.

Produce i numeri del capitolo sul GEX nelle opzioni in criptovalute:
  - greche di un contratto inverso Deribit contro quelle di un'opzione vanilla
  - parametro di retroazione beta nei due mercati e su piu' orizzonti

Tutti gli ingressi sono dichiarati qui sotto e vanno aggiornati: sono ordini
di grandezza di riferimento, non misure.

    python3 figure/crypto-confronto.py
"""

import math
import os

HERE = os.path.dirname(os.path.abspath(__file__))
SQRT2PI = math.sqrt(2.0 * math.pi)


def phi(x):
    return math.exp(-0.5 * x * x) / SQRT2PI


def Ncdf(x):
    return 0.5 * (1.0 + math.erf(x / math.sqrt(2.0)))


def bs(S, K, T, sig, r=0.0):
    """Valore e greche in USD di una call europea."""
    d1 = (math.log(S / K) + 0.5 * sig * sig * T) / (sig * math.sqrt(T))
    d2 = d1 - sig * math.sqrt(T)
    V = S * Ncdf(d1) - K * math.exp(-r * T) * Ncdf(d2)
    delta = Ncdf(d1)
    gamma = phi(d1) / (S * sig * math.sqrt(T))
    return V, delta, gamma


# ---------------------------------------------------------------------------
# 1. Contratto inverso: greche in BTC contro greche in USD
#
#    Il payoff in USD e' quello vanilla: max(S_T - K, 0).
#    Il valore della posizione misurato in BTC e' pero' V/S, da cui
#        Delta_BTC = (Delta - V/S) / S
#        Gamma_BTC = Gamma/S - 2 Delta/S^2 + 2 V/S^3
# ---------------------------------------------------------------------------
S = 90_000.0
SIG = 0.55                   # volatilita' implicita annualizzata
T = 7.0 / 365.0              # scadenza settimanale

print("=" * 72)
print("1. CONTRATTO INVERSO — greche in USD e in BTC")
print("=" * 72)
print(f"   S = ${S:,.0f}   sigma = {SIG:.0%}   T = {T:.4f} anni "
      f"(sigma*sqrt(T) = {SIG*math.sqrt(T):.4f})\n")
print(f"   {'strike':>9} {'V (USD)':>10} {'Delta':>8} {'Gamma':>11} "
      f"{'Delta_BTC':>11} {'Gamma_BTC':>12} {'scarto G':>9}")
for K in (78_000, 85_000, 90_000, 95_000, 105_000):
    V, d, g = bs(S, K, T, SIG)
    d_btc = (d - V / S) / S
    g_btc = g / S - 2 * d / S ** 2 + 2 * V / S ** 3
    # scarto fra il gamma inverso corretto e la semplice conversione Gamma/S
    scarto = (g_btc - g / S) / (g / S)
    print(f"   {K:>9,} {V:>10,.0f} {d:>8.4f} {g:>11.3e} "
          f"{d_btc:>11.3e} {g_btc:>12.3e} {scarto:>8.1%}")

print("\n   Lo scarto e' il termine che un'implementazione GEX derivata")
print("   direttamente dal caso SPX ometterebbe.")

# ---------------------------------------------------------------------------
# 2. Parametro di retroazione nei due mercati
#
#    beta_d = (sigma_d / 1%) * GEX / V$        (forma osservabile, cap. 7)
#    beta(tau) = beta_d * sqrt(tau_giorno / tau)
#
#    La durata del "giorno" e' diversa: 390 minuti di seduta per SPX,
#    1440 minuti per un mercato aperto 24 ore.
# ---------------------------------------------------------------------------
SCENARI = [
    # nome, sigma giornaliera, GEX in milioni di USD per 1%,
    # volume giornaliero in miliardi di USD, minuti del giorno
    ("SPX — riferimento cap. 7", 0.0075, 3100.0, 300.0, 390),
    ("BTC — base",               0.0288,  100.0,  40.0, 1440),
    ("BTC — gamma elevato",      0.0288,  250.0,  40.0, 1440),
    ("BTC — liquidità sottile",  0.0288,  100.0,  15.0, 1440),
    ("BTC — stress",             0.0570,  250.0,  15.0, 1440),
]


def beta_giorno(sigma_d, gex_musd, vol_bnusd):
    return (sigma_d / 0.01) * (gex_musd * 1e6) / (vol_bnusd * 1e9)


print()
print("=" * 72)
print("2. PARAMETRO DI RETROAZIONE")
print("=" * 72)
print(f"   {'scenario':26} {'sigma_d':>8} {'GEX $M':>8} {'V$ mld':>8} "
      f"{'beta_g':>8} {'beta 5min':>10} {'molt.':>7}")
righe = []
for nome, sd, gx, v, minuti in SCENARI:
    bg = beta_giorno(sd, gx, v)
    b5 = bg * math.sqrt(minuti / 5.0)
    molt = 1.0 / (1.0 + b5)
    righe.append((nome, sd, gx, v, minuti, bg, b5, molt))
    print(f"   {nome:26} {sd:>8.2%} {gx:>8.0f} {v:>8.0f} "
          f"{bg:>8.4f} {b5:>10.3f} {molt:>7.3f}")

print()
print("   Negli scenari di base, i beta giornalieri di BTC e SPX sono simili:")
print("   alta e la liquidita' piu' sottile sono compensate da un libro di")
print("   gamma molto piu' piccolo. Sugli orizzonti brevi no, perche' il")
print("   giorno crypto dura 1440 minuti invece di 390: a parita' di beta")
print(f"   giornaliero il fattore di scala e' {math.sqrt(1440/5):.1f} contro "
      f"{math.sqrt(390/5):.1f}.")

# ---------------------------------------------------------------------------
# 3. Tabella LaTeX pronta per il capitolo
# ---------------------------------------------------------------------------
out = os.path.join(HERE, "crypto_beta.txt")
with open(out, "w") as f:
    for nome, sd, gx, v, minuti, bg, b5, molt in righe:
        f.write(f"{nome} & {sd*100:.2f}\\% & {gx:.0f} & {v:.0f} & "
                f"{bg:.4f} & {b5:.3f} & {molt:.3f} \\\\\n")
print(f"\nscritto {out}")
