From d0c804ebfccf88a7f7d49a701c9f5473bf1633e6 Mon Sep 17 00:00:00 2001 From: Adriano Dal Pastro Date: Mon, 27 Jul 2026 11:05:33 +0000 Subject: [PATCH] research(gtaa): l'assenza di API DEGIRO vale -0.02 di Sharpe, non e' squalificante MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Domanda dell'operatore: "degiro ha api?". Fatto: no, non ufficiale; Revolut nemmeno (la sua e' per pagamenti); IB si'. I wrapper non ufficiali girano su credenziali + seed 2FA e si rompono IN SILENZIO a ogni cambio di front-end — e il progetto ha gia' pagato quel prezzo con fresh_5m il 26/07. Un esecutore che puo' rompersi senza dirlo e' peggio dell'esecuzione manuale. Misurato il costo di NON automatizzare invece di discuterlo: carico operativo: 15 settimane/anno con >=1 ordine (29% dei controlli, 1.4 per volta) ritardo 1g -0.02 Sharpe (peggiora in 6/11 anni = moneta) ritardo 3g -0.13 ritardo 10g -0.27 Il costo non e' il ritardo tipico ma la coda: il rischio dell'operativita' manuale e' la dimenticanza, e si copre con un allarme, non con una API (gtaa_rebalance_plan esiste gia' in produzione ed e' nato per un esecutore). Nota di metodo: sulla finestra UCITS di 3.2 anni la curva del ritardo NON e' monotona (5g -0.26, 10g -0.13) -> il campione corto non risolve differenze di questa taglia, quindi il numero si legge sulla finestra lunga a 10 anni, dove lo e'. Book, pesi, cron, config INVARIATI. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_01XBbYmiXqbUNuGpK9sfbsGp --- CLAUDE.md | 16 +++++++ docs/diary/2026-07-26-gtaa-ucits.md | 64 +++++++++++++++++++++++++++ scripts/research/r0727_gtaa_broker.py | 55 +++++++++++++++++++++++ 3 files changed, 135 insertions(+) diff --git a/CLAUDE.md b/CLAUDE.md index 1002832..aa76117 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -1120,6 +1120,22 @@ Prima ondata di ricerca onesta su BTC/ETH certificati (5 track, harness condivis **LEZIONE: una raccomandazione poggiata su un fatto non verificato sul conto reale vale quanto quel fatto** — due volte in due giorni un'assunzione sul conto ha cambiato la conclusione (prima la negoziabilita' PRIIPs, poi quale conto e' davvero operativo). + (e) **"degiro ha api?" — NO, e costa −0.02 di Sharpe.** DEGIRO non espone una API di trading + ufficiale al retail; Revolut nemmeno (la sua e' per pagamenti); IB si'. I wrapper NON ufficiali + degli endpoint interni girano su credenziali + seed 2FA e **si rompono in silenzio** a ogni cambio + di front-end — e il progetto ha gia' pagato quel prezzo (`fresh_5m`, 26/07): **un esecutore + automatico che puo' rompersi senza dirlo e' peggio dell'esecuzione manuale.** Misurato invece il + costo di NON automatizzare: carico operativo **15 settimane/anno con ≥1 ordine** (29% dei + controlli, 1.4 ordini per volta); costo del ritardo su 10 anni **1g −0.02 (peggiora in 6/11 anni + = moneta), 3g −0.13, 10g −0.27**. ⚠️ Sulla finestra UCITS di 3.2 anni la curva NON e' monotona + (5g −0.26, 10g −0.13) → il campione corto non risolve differenze di questa taglia, si legge la + finestra lunga. **Il costo non e' il ritardo tipico ma la CODA: il rischio e' la dimenticanza, e + si copre con un ALLARME non con una API** (`gtaa_rebalance_plan` esiste gia' in produzione, nato + per un esecutore; l'allerta Telegram c'e' gia' sul book live). ⚠️ Lato opposto, vero: il resto del + book e' automatico, una gamba manuale aggiunge un modo di fallire che oggi non c'e' — argomento + reale a favore di IB, che pero' richiede un secondo venue e quindi cade sotto la decisione venue + ($20k). **REGOLA: una capacita' mancante si valuta sul costo di non averla, non sulla sua + assenza.** - ⚠️ **IL FEED EQUITY NON AVEVA UN CROSS-CHECK — buco trovato e chiuso (2026-07-26).** `src/data/eq_crosscheck.py`. Nel crypto la certificazione incrocia sempre piu' venue (`certify_feed.py` vs Coinbase USD); il feed equity aveva **solo controlli locali** (integrita', diff --git a/docs/diary/2026-07-26-gtaa-ucits.md b/docs/diary/2026-07-26-gtaa-ucits.md index c4132f0..7be4510 100644 --- a/docs/diary/2026-07-26-gtaa-ucits.md +++ b/docs/diary/2026-07-26-gtaa-ucits.md @@ -394,3 +394,67 @@ guardando i due conti** — non sono cose che posso misurare da questo lato. Ieri ho consigliato IB in parte perché "il conto esiste già": era un'assunzione, e per la seconda volta in due giorni un'assunzione sul conto reale ha cambiato la conclusione. La prima volta era la negoziabilità (PRIIPs), questa volta quale conto è davvero operativo. + +--- + +# Addendum 2026-07-27 (2) — "degiro ha api?" + +**Fatto:** DEGIRO **non** espone una API di trading ufficiale per il retail. Revolut nemmeno (la sua +API è per pagamenti, non per il portafoglio titoli). IB sì, documentata e supportata — è quella che +il progetto già usa per i dati. + +Esistono wrapper **non ufficiali** degli endpoint interni del web trader DEGIRO. Girano su +credenziali + seed 2FA depositati sulla macchina, sono fuori dai termini di servizio, e si rompono +**in silenzio** a ogni cambio di front-end. Questo progetto ha già pagato una volta il prezzo di un +guasto silenzioso (`fresh_5m`, 26/07: fallimento muto → latenza d'uscita di SKH01 da ~1h a ~1 giorno +senza che nulla lo segnalasse). **Un esecutore automatico che può rompersi senza dirlo è peggio +dell'esecuzione manuale.** + +Quindi la domanda utile non è "si può automatizzare" ma **"quanto costa non farlo"**. + +## Carico operativo (banda 25%, controllo settimanale, $10.000) + +| | | +|---|---| +| controlli/anno | 50 | +| **settimane con ≥1 ordine** | **15** (29% dei controlli) | +| ordini per settimana attiva | 1.4 (max 5) | + +Nel 71% dei controlli non c'è nulla da fare. + +## Costo del ritardo di esecuzione + +Veicoli USA, 10 anni. ⚠️ Sulla finestra UCITS di 3.2 anni la curva **non risulta monotona** (5 +giorni −0.26, 10 giorni −0.13): il campione corto non risolve differenze di questa taglia, quindi +il numero si legge sulla finestra lunga. + +| ritardo | Sharpe | ΔSharpe | stabilità | +|---|---|---|---| +| 0 giorni | 0.90 | — | — | +| **1 giorno** | 0.89 | **−0.02** | peggiora in 6/11 anni = **moneta** | +| 2 giorni | 0.83 | −0.07 | 7/11 | +| 3 giorni | 0.78 | −0.13 | 7/11 | +| 5 giorni | 0.73 | −0.18 | 7/11 | +| **10 giorni** | 0.63 | **−0.27** | 6/11 | + +**Il costo non è il ritardo tipico, è la coda.** Eseguire il giorno stesso o il giorno dopo costa +nulla; dieci giorni valgono quasi un terzo dello sleeve. + +## Conseguenza + +Il rischio dell'operatività manuale non è la lentezza, è la **dimenticanza** — e quella si compra +con un **allarme**, non con una API. `gtaa_rebalance_plan(held, capital)` esiste già in produzione +ed è nato esattamente per un esecutore; il progetto ha già l'allerta Telegram sul book live. Un cron +settimanale che calcola il piano e notifica quando c'è da agire copre il caso 15 volte l'anno. + +⚠️ **L'altro lato, che resta vero:** il resto del book è automatico (TP01 e SKH01 mandano ordini +veri su cron). Aggiungere una gamba manuale introduce un modo di fallire che il sistema oggi non ha. +È un argomento reale a favore di IB — che l'API ce l'ha — ma richiede finanziare un secondo venue, e +la decisione venue del 26/07 tiene tutto su Deribit fino a $20k. **La scelta è quindi rimandata al +punto in cui la si riaprirebbe comunque.** + +## Lezione + +**Una capacità mancante si valuta sul costo di non averla, non sulla sua assenza.** Qui l'assenza di +API sembra squalificante e vale −0.02 di Sharpe se si esegue entro un giorno; ciò che vale davvero +(−0.27) è un rischio operativo che si copre con una notifica. diff --git a/scripts/research/r0727_gtaa_broker.py b/scripts/research/r0727_gtaa_broker.py index 60e5e17..af238de 100644 --- a/scripts/research/r0727_gtaa_broker.py +++ b/scripts/research/r0727_gtaa_broker.py @@ -174,6 +174,61 @@ def main() -> None: print(" controllo (2) su 10 anni e veicoli diversi, ma GTAA01 non e' deployabile prima dei") print(" $20k (decisione venue 26/07): c'e' tempo per validarla come si deve.") + # ---------- (5-bis) l'esecuzione MANUALE e' sostenibile? ---------- + print("\n" + "=" * 100) + print(" (5-bis) SE IL BROKER NON HA UNA API — quanto costa eseguire a mano") + print("=" * 100) + print(" DEGIRO non espone una API di trading ufficiale; Revolut nemmeno (la sua API e' per") + print(" pagamenti). Esistono wrapper non ufficiali degli endpoint interni, ma girano su") + print(" credenziali + seed 2FA e si rompono in SILENZIO a ogni cambio di front-end — e questo") + print(" progetto ha gia' pagato una volta il prezzo di un guasto silenzioso (fresh_5m, 26/07).") + print(" Quindi la domanda giusta non e' 'si puo' automatizzare' ma 'quanto costa NON farlo'.") + per_bar = None + band_c = BAND_FRAC * CAP / 6.0 + for k in dep: + _, pos = U.leg_returns(dep[k], dep[k], cal, CAP / 6.0, band_c, can_every, + U.cost_form(fixed=1.0)) + o = (pos.diff().abs() > 1e-12).astype(int) + per_bar = o if per_bar is None else per_bar + o + anni = len(cal) / 252.0 + att = int((per_bar > 0).sum()) + print(f"\n Carico operativo a ${CAP:,.0f} (banda {BAND_FRAC:.0%}, controllo settimanale):") + print(f" controlli/anno {len(cal)/5/anni:.0f}") + print(f" settimane con >=1 ordine/anno {att/anni:.0f} ({att/(len(cal)/5):.0%} dei controlli)") + print(f" ordini per settimana attiva {per_bar[per_bar > 0].mean():.1f} " + f"(max {int(per_bar.max())})") + + print("\n Costo del RITARDO di esecuzione — veicoli USA, finestra lunga " + f"({len(cal_us)/252:.0f} anni), perche' su 3.2 anni la curva non risulta monotona") + print(" (cioe' il campione corto non risolve differenze di questa taglia):") + print(f"\n {'ritardo':>10s}{'Sharpe':>9s}{'CAGR':>9s}{'dSharpe':>10s} stabilita' per anno") + base_sh, base_s = None, None + for d in (0, 1, 2, 3, 5, 10): + cols = {} + for k in us: + _, pos = U.leg_returns(us[k], us[k], cal_us, CAP / 6.0, band_c, can_every, + U.cost_form(fixed=1.0)) + px = U._norm(us[k]).reindex(cal_us).ffill().values.astype(float) + ret = np.zeros(len(px)) + ret[1:] = px[1:] / px[:-1] - 1.0 + p = pos.shift(d).fillna(0.0).values + c = (pos.diff().abs() > 1e-12).astype(float).shift(d).fillna(0.0).values / (CAP / 6.0) + cols[k] = __import__("pandas").Series(p * ret - c, index=cal_us) + s = __import__("pandas").concat(cols, axis=1).mean(axis=1) + m = U.met(s) + if base_sh is None: + base_sh, base_s = m["sharpe"], s.copy() + peggio = sum(1 for y, g in s.groupby(s.index.year) + if len(g) > 100 and U.met(g)["sharpe"] < U.met(base_s[base_s.index.year == y])["sharpe"]) + tot = sum(1 for y, g in s.groupby(s.index.year) if len(g) > 100) + print(f" {str(d)+' giorni':>10s}{m['sharpe']:>9.2f}{m['cagr']:>8.2%}" + f"{m['sharpe']-base_sh:>+10.2f} peggiora in {peggio}/{tot} anni") + print("\n LETTURA: eseguire il giorno stesso o il giorno dopo costa ~nulla (-0.02, e peggiora") + print(" in 6/11 anni = moneta). Il costo NON e' il ritardo tipico ma la CODA: dieci giorni") + print(" valgono -0.27, cioe' quasi un terzo dello sleeve. Il rischio dell'operativita' manuale") + print(" non e' la lentezza, e' la DIMENTICANZA — e quella si compra con un ALLARME, non con") + print(" una API: `gtaa_rebalance_plan()` esiste gia' in produzione ed e' nato per un esecutore.") + # ---------- (5) cosa cercare sul proprio conto ---------- print("\n" + "=" * 100) print(" (5) COSA CERCARE SUL PROPRIO BROKER — per ISIN, non per ticker")