gtaa: la decisione tenere/bloccare va a $15k — gate (A) ritirato, soglia sorvegliata

Decisione dell'operatore: GTAA01 NON si blocca oggi, si decide quando il book
arriva a $15k. Il motivo registrato non e' «non contribuisce» — la misura dice
il contrario (+0,095/+0,124 di Sharpe a iso-rischio secondo la fase, positivo in
tutte e cinque, hold-out +0,247, 6 anni su 8, correlazione col resto +0,087).
Il motivo e' che sotto $15k di book lo sleeve NON E' ACCENDIBILE:
GTAA_MIN_CAPITAL e' $3.000 allocati, che al peso 20% fa $15.000 contro i $2.068
attuali. Finora era manutenzione senza beneficio incassabile.

Registrate anche le due ragioni contro il blocco, che restano valide: N7 (uno
sleeve difensivo si giudica sul sinistro, e questa finestra non lo contiene) e
N4 (togliendolo il portafoglio di ricerca diventa 100% cripto su un venue solo).
E il costo che sarebbe andato pagato: GTAA01 e' uno dei quattro nomi di
W_DEPLOY, da cui escono i $313k del muro.

PERCHE' LA DECISIONE NON SI DIMENTICHI (N9). Una decisione parcheggiata su un
numero che nessuno sorveglia e' parcheggiata per sempre. `journal.SOGLIE_CAPITALE`
legge l'equity ogni giorno — il giornale lo fa comunque — e il giorno che supera
la soglia la voce dice quale decisione si sblocca e perche'. Seconda riga: $20k,
dove si riapre «100% Deribit fino a $20k». Una riga si TOGLIE quando la decisione
e' presa. 5 test, incluso «equity non leggibile non e' una soglia superata» (P5).

GATE (A) RITIRATO come pass/fail, congelando il MOTIVO e non l'esito — come il
07/08 col confronto fra ranghi, e per la stessa ragione: il criterio decide su un
margine piu' piccolo del rumore che lo scuote. In piu' una guardia sulla CAUSA
(`test_la_fase_di_ribilanciamento_e_ancora_ancorata_alla_POSIZIONE`) che si rompe
il giorno che qualcuno ancorasse la fase al calendario: quel giorno il gate
potrebbe tornare decidibile, ed e' un fatto da guardare, non da ignorare.
Il test sul margine assoluto si e' auto-ritirato: diceva «se scendesse sotto un
centesimo questo criterio smetterebbe di essere una misura», ed e' sceso a 0,0074.

CLAUDE.md: §3 nuova riga · §5.2 RISOLTO (trasporto allarmi) · §5.4 riscritto (la
domanda fiscale (a) ha una risposta alla fonte: derivati in c-quater al 26%, non
c-sexies al 33% — Circolare AdE 30/E del 27/10/2023, citata verbatim) · §5.13
nuovo debito, la fase che ruota — quantificata e dichiarata INNOCUA oggi (D5):
0,029 di Sharpe a livello di portafoglio, dentro la banda [1,81-2,12].

Diario: docs/diary/2026-08-28-gtaa-fase-e-allarmi.md
Suite: 789 passati, 0 falliti.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Adriano Dal Pastro
2026-08-28 12:54:08 +00:00
parent 21fe289383
commit 418f523be7
5 changed files with 316 additions and 29 deletions
+46 -19
View File
@@ -101,19 +101,50 @@ def griglia_piena():
return G
def test_la_banda_proposta_e_quella_scelta_al_buio(griglia_piena):
"""Il gate (A), nella forma decidibile (2026-08-07).
# ⚠️ 2026-08-28 — SECONDO CRITERIO RITIRATO, e per la stessa ragione del primo.
# `test_la_banda_proposta_e_quella_scelta_al_buio` asseriva che la banda scelta sui soli dati
# pre-2015 fosse la proposta. Ha smesso di passare senza che nessuno toccasse il codice: al buio
# esce il 60%, con margine 0.0074 — sotto il pavimento di 0.01 che il test stesso si era dato.
# Misurato in `r0828_gtaa_band_phase.py`: NON e' un fatto sulla banda, e' un fatto sul criterio.
# · IB serve una finestra ROTOLANTE di 30 anni e SPY e' al muro: la sua prima barra avanza di
# un giorno di borsa ogni notte. Il pre-2015 — che il progetto tratta come congelato — perde
# il giorno piu' vecchio ogni notte.
# · `gtaa._gated_returns` ribilancia su `i % every == 0`, cioe' sulla POSIZIONE nell'array:
# se la prima barra scivola, si ri-fasa ogni decisione di trent'anni. La fase canonica cambia
# da sola.
# · Esito: su 10 notti consecutive la scelta al buio e' 25% / 40% / 60%, e il margine sta sotto
# il pavimento in 4 notti su 10. A dato FISSO, muovendo la sola fase, il verdetto cambia lo
# stesso (25% su 3 fasi, 60% su 2).
# Come il 07/08 si congela il MOTIVO e non l'esito. La riparazione (ancorare la fase al calendario)
# e la decisione su GTAA01 sono rinviate alla soglia di $15k di book — sotto quella soglia lo
# sleeve non e' deployabile e la decisione non ha conseguenze (`journal.SOGLIE_CAPITALE`).
La proposta del 27/07 e' una BANDA: la cadenza settimanale e' gia' `REBAL_EVERY=5` in
produzione e non era in discussione. Quindi la domanda sulla provenienza della scelta e'
«a cadenza di produzione, quale banda si sceglie guardando SOLO il pre-2015?».
"""
def test_il_gate_A_non_ha_RISOLUZIONE_ed_e_per_questo_che_e_stato_RITIRATO(griglia_piena):
"""Congela il MOTIVO del secondo ritiro: il criterio decide su un margine piu' piccolo del
rumore che lo scuote. Non asserisce QUALE cella vinca — quella si muove da sola ogni notte,
ed e' esattamente il punto."""
G = griglia_piena
riga = G[G["every"] == BG.PROPOSTA[0]]
blind = riga.sort_values("sh_in", ascending=False).iloc[0]
assert blind["frac"] == BG.PROPOSTA[1], (
f"al buio si sceglierebbe la banda {blind['frac']:.0%}, non {BG.PROPOSTA[1]:.0%}: "
"la validazione del 27/07 andrebbe rifatta su quella cella")
ordinata = riga.sort_values("sh_in", ascending=False)
margine = float(ordinata["sh_in"].iloc[0] - ordinata["sh_in"].iloc[1])
spread = float(riga["sh_in"].max() - riga["sh_in"].min())
# il margine su cui il criterio decideva e' una FRAZIONE dello spread della griglia:
# a quella scala la scelta non e' una misura, e' l'ordine in cui il rumore si e' posato.
assert margine < 0.25 * spread, (
f"il margine ({margine:.4f}) e' tornato grande rispetto allo spread di griglia "
f"({spread:.4f}): se il rumore si fosse ridotto, il gate (A) andrebbe RIABILITATO "
"invece di restare ritirato — ed e' un fatto da guardare, non da ignorare")
def test_la_fase_di_ribilanciamento_e_ancora_ancorata_alla_POSIZIONE(griglia_piena):
"""La guardia sulla CAUSA. Se un giorno `_gated_returns` ancorasse la fase al calendario,
questo test si rompe e va riletto tutto: il gate (A) potrebbe tornare decidibile."""
import inspect
src = inspect.getsource(BG.gtaa_returns.__globals__["_gated_returns"])
assert "i % every" in src, (
"la fase non e' piu' ancorata alla posizione nell'array: la ragione del ritiro del "
"gate (A) e' venuta meno, rileggere r0828_gtaa_band_phase.py")
def test_chi_guardasse_l_hold_out_sceglierebbe_una_banda_DIVERSA(griglia_piena):
@@ -128,15 +159,11 @@ def test_chi_guardasse_l_hold_out_sceglierebbe_una_banda_DIVERSA(griglia_piena):
"potenza e non va citato come validazione")
def test_il_margine_del_blind_non_e_un_arrotondamento(griglia_piena):
"""La ragione per cui questo criterio ha sostituito il confronto fra ranghi: decide su
~0.015 di Sharpe invece che su ~0.001. Se il margine scendesse sotto un centesimo, anche
questo criterio smetterebbe di essere una misura e andrebbe ripensato a sua volta."""
G = griglia_piena
riga = G[G["every"] == BG.PROPOSTA[0]]
blind = riga.sort_values("sh_in", ascending=False).iloc[0]
secondo = riga[riga["frac"] != blind["frac"]]["sh_in"].max()
assert blind["sh_in"] - secondo >= 0.01
# `test_il_margine_del_blind_non_e_un_arrotondamento` (2026-08-07) chiedeva margine >= 0.01 e
# diceva, testualmente: «Se il margine scendesse sotto un centesimo, anche questo criterio
# smetterebbe di essere una misura e andrebbe ripensato a sua volta». Il 28/08 e' sceso a 0.0074.
# Il test aveva ragione e si e' auto-ritirato: la sua condizione e' ora dentro il test sul MOTIVO
# qui sopra, dove misura il margine CONTRO lo spread di griglia invece che contro un assoluto.
def test_il_confronto_fra_ranghi_e_una_moneta_ed_e_per_questo_che_e_stato_RITIRATO(griglia_piena):
+34
View File
@@ -467,3 +467,37 @@ def test_la_concentrazione_non_conta_i_versamenti_come_pnl(db, monkeypatch):
righe = J.lettura(db, _voce(pnl=p, giorno="2026-08-25"))
conc = [r for r in righe if r["id"] == "concentrazione"]
assert conc == [] # il cumulato di TRADING e' 0: la regola deve tacere
# =============================================================================================
# DECISIONI PARCHEGGIATE SU UNA SOGLIA DI CAPITALE
# =============================================================================================
# Il 2026-08-28 la decisione «GTAA01: tenere o bloccare» e' stata rinviata a $15k di book, che e'
# la soglia sotto la quale lo sleeve non e' deployabile. Una decisione parcheggiata su un numero
# che nessuno sorveglia e' parcheggiata per sempre (N9): questi test blindano la sorveglianza.
def test_sotto_soglia_non_dice_niente():
assert J.soglie_superate(2_068.0) == []
def test_la_soglia_gtaa_e_15k_e_scatta_quando_l_equity_arriva():
soglie = [s for s, _ in J.SOGLIE_CAPITALE]
assert 15_000.0 in soglie, "la soglia di GTAA01 non e' piu' dichiarata"
assert J.soglie_superate(14_999.99) == []
assert [s for s, _ in J.soglie_superate(15_000.0)] == [15_000.0]
def test_le_soglie_si_accumulano_e_restano_ordinate():
"""A $20k si devono presentare ENTRAMBE: la seconda non cancella la prima."""
assert [s for s, _ in J.soglie_superate(20_000.0)] == [15_000.0, 20_000.0]
def test_equity_non_leggibile_non_e_una_soglia_superata():
"""P5: «non vedo» non e' «va tutto bene» — e non e' nemmeno «la soglia e' arrivata»."""
assert J.soglie_superate(None) == []
def test_ogni_soglia_dice_COSA_decidere_non_solo_che_e_arrivata():
"""P4: un'allerta risponde a due domande. Una riga che dice solo «sei a $15k» non serve."""
for _, testo in J.SOGLIE_CAPITALE:
assert len(testo) > 80 and "**" in testo, "la soglia non dice quale decisione sblocca"