research(gtaa): ZPRR e' R2US (stessa ISIN) + correzione sul verso del costo FX

L'operatore ha verificato su Revolut: R2US assente, ZPRR e SPY4 presenti.

(1) ZPRR (Xetra EUR) == R2US (Londra USD): stessa ISIN IE00BJ38QD84, stessa classe di
quote, stesso NAV. La gamba small cap e' risolta. Regola: si cerca per ISIN, non per
ticker — lo stesso fondo ha ticker diversi su borse diverse.

(2) SPY4 IE00B4YBJ215 NON e' small cap ne' S&P 500: e' SPDR S&P 400 MID cap (l'S&P 500
e' SPY5). Misurato come ripiego su 6.5 anni: Sharpe 0.86 vs 0.86, corr fra i due sleeve
0.991, peggiore in 3/7 anni = moneta. Sulla finestra corta di 3.2 anni sembrava -0.15:
era rumore. Ripiego accettabile per ragione meccanica (small e mid USA correlano ~0.95
giornaliero), NON validato — e' proprio perche' non si distinguono che la scelta non
conta.

(3) CORREZIONE a un'indicazione data ieri. Avevo scritto "una linea in EUR aggiunge la
conversione per ordine". Vero solo per un conto in USD: per un conto in EURO vale
l'opposto. L'esposizione economica e' identica (il fondo detiene attivi USD, nessuna
delle due linee e' coperta) — la valuta di quotazione non copre nulla, decide solo se
serve una conversione. Regola giusta: prendere la linea nella valuta del proprio saldo.
Misurato: turnover lordo $13.655/anno su $10k -> 25bps = -0.07 Sharpe = $34/anno = ~$1.6
per ordine, contro una soglia di $18.90.

Regola generale: un costo di conversione non e' una proprieta' dello strumento ma della
coppia strumento-CONTO.

Book, pesi, cron, config INVARIATI. 447 test verdi (+3).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XBbYmiXqbUNuGpK9sfbsGp
This commit is contained in:
Adriano Dal Pastro
2026-07-27 11:25:20 +00:00
parent d0c804ebfc
commit 378f448450
5 changed files with 208 additions and 8 deletions
+39
View File
@@ -118,3 +118,42 @@ def test_le_isin_sono_ben_formate_e_coprono_le_sei_gambe():
def test_le_soglie_di_lettura_sono_dichiarate():
assert B.BAND_FRAC == 0.25
assert B.ESPOSTA_SANA == 0.60
# ===========================================================================
# equivalenze fra listini — la stessa ISIN su borse diverse e' lo STESSO fondo
# ===========================================================================
def test_le_equivalenze_dichiarate_condividono_la_isin_del_veicolo_scelto():
"""ZPRR (Xetra EUR) e R2US (Londra USD) sono la stessa classe di quote: se le ISIN non
coincidono l'equivalenza e' falsa e l'operatore comprerebbe un altro fondo."""
for a, b, isin, _ in B.EQUIVALENZE:
assert a in B.ISIN, f"{a} non e' un veicolo del set DEPLOY"
assert B.ISIN[a][0] == isin, f"{a}: la ISIN dell'equivalenza non e' quella del veicolo"
assert re.fullmatch(r"IE00[A-Z0-9]{8}", isin)
assert b not in B.ISIN, f"{b} e' un ALIAS di {a}, non un veicolo distinto"
def test_il_ripiego_smallcap_e_dichiarato_come_indice_DIVERSO():
"""SPY4 e' S&P 400 MID cap: e' un ripiego misurato, non un equivalente. Il test esiste
perche' la differenza fra 'equivalente' e 'ripiego accettabile' e' proprio cio' che si
perde quando si copiano ticker da una lista."""
tic, isin, desc = B.RIPIEGO_SMALLCAP
assert re.fullmatch(r"IE00[A-Z0-9]{8}", isin)
assert isin != B.ISIN["R2US"][0], "un ripiego con la stessa ISIN sarebbe un'equivalenza"
assert "Mid" in desc
def test_il_ripiego_smallcap_e_indistinguibile_dalla_gamba_scelta(ctx):
"""Il finding della sezione (6): sostituire mid a small lascia lo sleeve al 99% uguale.
Se un giorno smettesse di essere vero, la raccomandazione 'usa SPY4 se non trovi R2US'
andrebbe ritirata."""
dep, cal = ctx
us = {s: U.close_us(s) for s in U.US}
mid = dict(dep)
mid["IWM"], _ = U.close_uc(B.RIPIEGO_SMALLCAP[0], us["IWM"])
cl = U.common_cal(list(dep.values()) + [mid["IWM"]])
cl = cl[cl >= cal[0]]
band = B.BAND_FRAC * 10_000.0 / 6.0
a = U.sleeve(dep, dep, cl, 10_000.0, band, 5, U.cost_form(fixed=1.0))
b = U.sleeve(mid, mid, cl, 10_000.0, band, 5, U.cost_form(fixed=1.0))
assert a.corr(b) > 0.95, f"il ripiego non e' piu' equivalente: corr {a.corr(b):.3f}"