research(wave-0822): SCALE-SPEC — chiave specificata, il tetto va sul PRODOTTO, e il test di guardia non si rompe ma smette di controllare; corretto un mio numero conflato
This commit is contained in:
@@ -703,6 +703,7 @@ stessi hanno nominato senza poterli eseguire**. Stesso contratto di consegna, st
|
||||
| 35 | FUNDING | il costo mai prezzato di TENERE una posizione aperta | **LEAD** — **−2,16%/anno di drift**, muri **+17,5%** |
|
||||
| 36 | PIANO-VERO | la tabella congiunta fisco+funding, che non esisteva | 🚨 **€250/m: P(20a) 92% → 14-26%** |
|
||||
| 37 | GATE-C | l'ultima gamba del gate funded + il biglietto come opzione | **PASS 2/2** — gate senza date; **P(≥50/g) 4,4% → 2,6%** |
|
||||
| 38 | SCALE-SPEC | specificare il knob di leva che non esiste | **LEAD** — specificata, **1 nodo irrisolto** sul disaster-SL |
|
||||
| 22 | MAKER | l'esecuzione passiva e' una fonte di ritorno, al netto del costo di non essere eseguiti? | **SCARTATO** — il segno dipende da `<` contro `<=` |
|
||||
| 23 | BOCPD | un rilevatore di cambio di regime vero batte il miglior lookback COSTANTE? | **SCARTATO** — filone chiuso definitivamente |
|
||||
| 24 | CRITICO | cosa NON e' stato misurato, e quale singola misura mancante vale di piu' | **3 correzioni all'ondata**, 1 regola mia ritirata |
|
||||
@@ -1503,7 +1504,7 @@ l'hold-out di TP01. E' la **terza** dimensione, e l'agente la dichiara.
|
||||
massimo scelto su cui barare, quindi non c'e' un DSR da calcolare*.
|
||||
|
||||
Il filone che il critico dell'ondata aveva indicato come **la misura di maggior valore mai fatta**:
|
||||
il gradino di leva **1,00x → 1,25-1,50x** vale **14,7 → 11,6 anni** al capitale-rendita (~€300/mese di
|
||||
il gradino di leva vale **14,7a → 12,9a a 1,25x** e **→ 11,6a a 1,50x** al capitale-rendita (⚠️ **correzione 23/08**: la prima stesura scriveva *"1,25-1,50x vale 14,7 → 11,6a, ~€300/mese"* **fondendo due gradini** — il ~€300/mese e' del **1,50x**; a **1,25x** l'equivalente e' **+€164/mese**, ricalcolato sulla tabella netta) (~€282/mese a 1,50x di
|
||||
versamenti equivalenti, a costo zero) ed era bloccato da **un solo parametro scelto a mano**:
|
||||
*"un giorno a −10% ogni anno"*.
|
||||
|
||||
@@ -1853,3 +1854,65 @@ scommessa **perde la mediana 6×** ($132 contro $787) e **vince la media 12×**:
|
||||
atteso positivo che un conto da $654 puo' permettersi di giocare **una volta sola**.
|
||||
⚠️ E il vantaggio poggia **interamente** sul drift di XS01 misurato su **13 gambe su 19**.
|
||||
**Smentitore che azzera tutto senza che il modello lo segnali:** una **morte-firm ≫10%/anno**.
|
||||
|
||||
---
|
||||
|
||||
## 38 — SCALE-SPEC (la chiave di scala che non esiste, specificata)
|
||||
|
||||
`docs/research/SPEC-scale-key.md` (38 KB) + `scripts/research/r0822e_scale_proto.py` (1,0 s, zero
|
||||
rete, **zero scritture**). **~630 valutazioni, nessuna cella scelta** → niente DSR.
|
||||
✅ **Produzione non toccata** (`git status` vuoto su `src/`, `config/`, `scripts/live/`, `tests/`), e
|
||||
la sez. 0 del prototipo **verifica l'isolamento a runtime** — *ed e' fallita su se stessa alla prima
|
||||
stesura, che e' il modo giusto per un controllo di scoprire che funziona.*
|
||||
✅ **Replica a k=1,00 superata 6/6** contro WORST-DAY (peggior giorno −3,95% il 2020-03-13, bound
|
||||
strutturale −14,32%, morso del clamp 3/5.648 contro 3/5.650, drift e vol al centesimo).
|
||||
|
||||
| | k=1,00 | **k=1,25** |
|
||||
|---|---|---|
|
||||
| Sharpe FULL | 1,5051 | **1,5051** (invariante) |
|
||||
| drift / vol | 17,11% / 11,37% | 21,39% / 14,21% |
|
||||
| g(k) esatto (CAGR geom.) | 17,90% | **22,61%** |
|
||||
| maxDD storico | −12,17% | −15,01% |
|
||||
| peggior giorno possibile | −14,32% | −17,90% |
|
||||
| **costo di un disaster-SL** | 30,0% | **37,5%** ← la guardia che morde |
|
||||
| margine di liquidazione | 15,8x | 10,1x |
|
||||
|
||||
⚠️ **CORREZIONE A UN NUMERO CHE AVEVO SCRITTO IO** (nel briefing e in CLAUDE.md): *"il gradino
|
||||
1,00x→1,25-1,50x vale 14,7 → 11,6 anni, ~€300/mese"* **fondeva due gradini**. §2 da' **1,25x → 12,9a**
|
||||
e **1,50x → 11,6a**; il ~€300/mese e' del **1,50x**. Ricalcolato sulla tabella netta: **1,25x =
|
||||
+€164/mese equivalenti** (l'interpolazione riproduce €282 per 1,50x = controllo superato).
|
||||
|
||||
**Tre risultati che il mandato non prevedeva:**
|
||||
1. 🚨 **`test_leva_massima_da_config_resta_sotto_o_uguale_a_1x` NON si rompe — ed e' PEGGIO che
|
||||
rompersi.** Misura `frac · n_asset` mentre la grandezza vera diventerebbe `frac · n_asset · scala`
|
||||
→ **continua a passare e smette di controllare**. **4ª occorrenza della forma "un controllo puntato
|
||||
su una configurazione diversa da quella che gira"** (dopo `fee_watch` sugli inverse, la taratura di
|
||||
`venue_watch` con bitfinex, i test di `book_live` senza potenza a libro flat). **Va cancellato con
|
||||
nota, non aggiustato.**
|
||||
2. 🚨 **La guardia che morde per prima e' il DISASTER-SL, non il peggior giorno:** dal bound
|
||||
strutturale k ≤ 3,49x, **dal disaster-SL k ≤ 1,67x** = **2,1× piu' stringente**. **C1 di WORST-DAY
|
||||
guardava la grandezza sbagliata.** → il tetto giusto e' l'invariante
|
||||
`n_asset · frac · scala · disaster_sl_pct ≤ 0,50`, che lega **tre** chiavi.
|
||||
3. 🚨 **Il tetto va sul PRODOTTO, non sulla chiave:** `frac=0,625` + `scala=1,25` fa leva **1,562x** e
|
||||
**passerebbe** un tetto *"scala ≤ 1,25"*. Ed e' concreto: WORST-DAY ha appena pubblicato che alzare
|
||||
`frac` da solo *"non produce k=1,25"* — **combinato con la scala lo produce eccome**.
|
||||
|
||||
**Gate proposto `GATE SCALA-01`** — 9 condizioni, fra cui **A2** (180 giorni sul gradino precedente),
|
||||
**A5** (tetto sul **prodotto**), **A6 anti-recency** (`k_ammesso` calcolato **togliendo gli ultimi 90
|
||||
giorni** dev'essere ≥ k richiesto) e **A9** (11 test verdi), piu' un sorvegliante giornaliero a **tre
|
||||
stati**. Nasce dal fatto misurato che **la scala e' invisibile a tutti i gate esistenti**: Sharpe
|
||||
**1,5051 identico** a tutte e 5 le celle di k → `deflated_sharpe` e `marginal_vs_tp01` **non
|
||||
falliscono, non vedono la variabile**. ✅ `weights_tilt_null` invece **passa e con potenza**: peso
|
||||
implicito TP01 **0,750000 a ogni k**, `max|target(k) − k·target(1)| = 0,00e+00`, e il **controllo
|
||||
positivo** (scala sulla sola gamba TP01 = cio' che farebbe `target_vol`) lo porta a **0,789** e viene
|
||||
smascherato.
|
||||
|
||||
**VERDETTO: LEAD** (specifica di processo).
|
||||
**`LA CHIAVE DI SCALA: SPECIFICATA MA CON UN NODO IRRISOLTO`** — `execution.py:196-223` **ri-ancora
|
||||
il disaster-SL al mark a ogni giro** (tolleranza 5%): il **−30% e' ROTOLANTE, non un pavimento**.
|
||||
Se e' cosi', il 37,5% e' il costo di **un episodio** e un ribasso lento ne produce **piu' d'uno**, e
|
||||
il margine 1,33x del gradino non e' quello vero. ⚠️ **Letto nel codice, NON misurato** — e il log non
|
||||
lo permette (servirebbe `pos_prima`): **non ricostruibile a posteriori.**
|
||||
**Secondo smentitore, con soglia dichiarata:** il ramo di **fallback dell'equity** oggi scatta
|
||||
**0 volte su 1.442 giri**; se superasse il **2% dei giri in 90 giorni** il libro girerebbe a leva
|
||||
**mista** e `g(k)` smetterebbe di descriverlo.
|
||||
|
||||
@@ -0,0 +1,618 @@
|
||||
# SPEC — la CHIAVE DI SCALA del libro live (`book_scale_k`)
|
||||
|
||||
**Filone SCALE-SPEC, ondata 2026-08-22, branch `research/wave-0822`.**
|
||||
**Questo documento e' una SPECIFICA. Non e' stata implementata: `src/`, `config/`, `scripts/live/`,
|
||||
`scripts/cron_*.sh` e `tests/` non sono stati toccati.** Il prototipo che dimostra la meccanica e'
|
||||
`scripts/research/r0822e_scale_proto.py` (isolato, non importato da niente, non scrive nulla; la
|
||||
sua sezione (0) verifica entrambe le cose a runtime invece di dichiararle).
|
||||
|
||||
Nasce da `RESULTS-0822.md` §33 (WORST-DAY), che ha misurato che il gradino di leva e' l'unica leva
|
||||
grande rimasta e che **C6 (processo) FALLISCE**: la regola del progetto — *«ogni cambio di SCALA
|
||||
passa dal cap di config, non da `target_vol`»* — **non e' implementabile come scritta**, perche' il
|
||||
cap e' un CLAMP e non un moltiplicatore.
|
||||
|
||||
---
|
||||
|
||||
## 0. IL RISCHIO CHE QUESTA SPECIFICA DEVE RENDERE IMPOSSIBILE
|
||||
|
||||
> **Una chiave di scala e' esattamente il tipo di parametro che si alza «solo un po'» dopo un mese
|
||||
> buono.** E' un numero, sta in un file di config, non richiede di capire niente per cambiarlo, e il
|
||||
> suo effetto e' immediato e piacevole.
|
||||
|
||||
Il progetto ha regole contro questa forma di deriva su ogni altro asse — `weights_tilt_null` per i
|
||||
pesi, gate pre-registrati per i candidati, `select_cell_insample` per le griglie, `anchor_luck_band`
|
||||
per le ancore — e **nessuna per la scala**. Non per dimenticanza: **per aritmetica.**
|
||||
|
||||
Lo **Sharpe e' invariante alla scala**. Misurato nel prototipo (sez. 7a), sulla serie vera del libro:
|
||||
|
||||
| k | Sharpe | drift | vol | maxDD | g(k) esatto |
|
||||
|---|---|---|---|---|---|
|
||||
| 1,00 | **1,5051** | 17,11% | 11,37% | −12,17% | 17,90% |
|
||||
| 1,25 | **1,5051** | 21,39% | 14,21% | −15,01% | 22,61% |
|
||||
| 2,00 | **1,5051** | 34,22% | 22,74% | −23,10% | 37,24% |
|
||||
|
||||
`deflated_sharpe` e `marginal_vs_tp01` leggono la prima colonna. **Non falliscono: non vedono la
|
||||
variabile.** Un raddoppio della leva passa ogni gate esistente del progetto senza far scattare nulla,
|
||||
e produce lo stesso identico numero di sintesi che il progetto usa per giudicare tutto il resto.
|
||||
|
||||
Da qui discendono i tre vincoli non negoziabili del disegno:
|
||||
|
||||
1. **il tetto sta nel CODICE, non in config** (una config puo' essere modificata da chiunque, in
|
||||
qualunque momento, senza review; una costante di codice no);
|
||||
2. **il tetto sta sul PRODOTTO, non sulla chiave** (`frac` e `scala` moltiplicano: un tetto sulla
|
||||
sola chiave lascia aperta la porta accanto — vedi §4.2, tabella);
|
||||
3. **il gate e' uno SCRIPT che stampa PASSA/FALLISCE, non un giudizio** (§6), e c'e' un
|
||||
**sorvegliante giornaliero** che se ne accorge *dopo il fatto* se qualcuno lo salta (§6.4).
|
||||
|
||||
⚠️ **Correzione dovuta al mandato di questo filone.** Il gradino non vale quello che dice la frase
|
||||
che circola. `RESULTS-0822.md` §2 misura **1,00x → 1,25x = 14,7a → 12,9a**, e **1,00x → 1,50x =
|
||||
14,7a → 11,6a**; il «~€300/mese di versamenti equivalenti» appartiene al gradino **1,50x**.
|
||||
Ricalcolato sulla tabella netta pubblicata (`r0807_piano_netto`: €500/m → 14,7a, €800/m → 11,4a,
|
||||
interpolazione lineare **dichiarata**):
|
||||
|
||||
| gradino | anni al capitale-rendita | versamento mensile equivalente | delta |
|
||||
|---|---|---|---|
|
||||
| 1,00x (oggi) | 14,7a | €500/m | — |
|
||||
| **1,25x** | **12,9a** | ~€664/m | **+€164/m** |
|
||||
| 1,50x | 11,6a | ~€782/m | +€282/m |
|
||||
|
||||
L'interpolazione riproduce il «~€300/mese» pubblicato per 1,50x (€282) → è un controllo, non solo
|
||||
un conto. **Questa specifica autorizza il gradino a 1,25x e vale ~€165/mese, non ~€300.**
|
||||
|
||||
---
|
||||
|
||||
## 1. COSA SPECIFICA, E COSA NON FA
|
||||
|
||||
**Specifica:** dove va la chiave, in che ordine si applica rispetto al cap, quali guardie servono,
|
||||
quali test devono esistere **prima** della modifica, quale gate deve essere superato per alzarla e
|
||||
con quale cadenza si sorveglia.
|
||||
|
||||
**NON fa:** non autorizza il gradino, non implementa niente, non tocca `config/live.json`. Con la
|
||||
chiave assente o `= 1.0` il libro e' **bit-exact quello di oggi** (§5, test T7): la modifica e'
|
||||
inerte finche' qualcuno non scrive un numero, e quel numero passa dal gate del §6.
|
||||
|
||||
---
|
||||
|
||||
## 2. DOVE VA LA CHIAVE, ESATTAMENTE
|
||||
|
||||
### 2.1 La catena, letta dal sorgente vero
|
||||
|
||||
Il prototipo la stampa leggendo i file (sez. 2), cosi' le righe qui sotto sono verificabili e non
|
||||
citate a memoria:
|
||||
|
||||
| stadio | file:riga | cosa produce |
|
||||
|---|---|---|
|
||||
| segnale TP01 | `src/live/shadow.py:119` `targets = {a: tp.current_target(dfs[a])...}` | una **frazione** ≥0, long-flat |
|
||||
| segnale SKH01 | `src/live/book.py:217` `skh = _skyhook_positions(...)` → `:228` `sign = _skh_sign(st)` | un **segno** +1/−1/0 |
|
||||
| cap per-asset | `src/live/book.py:107` `def _cap(...)` → `:194` `cap = _cap(...)` | il **clamp**, legato al watermark |
|
||||
| **TARGET NETTO** | **`src/live/book.py:138` `def book_net_target(...)`** → **`:229` `net = book_net_target(tp_frac, sign, equity, cap)`** | **← QUI VA LA SCALA** |
|
||||
| ordine | `src/live/book.py:153` `def build_book_order(...)` → `:232` | un **delta** verso il target |
|
||||
| invio | `scripts/live/book_execute.py:208` `trader.rebalance_signed(inst, net, mark, ...)` | il fill |
|
||||
|
||||
### 2.2 La firma proposta
|
||||
|
||||
```python
|
||||
# src/live/book.py
|
||||
def book_net_target(tp_frac: float, skh_sign: int, equity: float, cap: float,
|
||||
weight: float = WEIGHT, scala: float = 1.0) -> float:
|
||||
raw = weight * equity * (W_TP01 * max(tp_frac, 0.0) + W_SKH * float(skh_sign))
|
||||
return scala * max(-cap, min(cap, raw)) # <-- la scala e' FUORI dal clamp: vedi §3
|
||||
```
|
||||
|
||||
più, accanto a `_cap()`, un lettore dedicato:
|
||||
|
||||
```python
|
||||
LEVA_LORDA_MAX = 1.25 # COSTANTE DI CODICE, non di config. Vedi §4.1.
|
||||
SCALA_LADDER = (1.00, 1.25) # i soli valori esprimibili. Vedi §4.1 e §6.
|
||||
|
||||
def _scala(real_equity, eq_fallback) -> float:
|
||||
"""Scala del libro. 1.0 (= il libro di oggi) in ogni stato degradato: vedi §4.3."""
|
||||
if real_equity is None or eq_fallback:
|
||||
return 1.0
|
||||
... # legge config, valida contro LEVA_LORDA_MAX e SCALA_LADDER, ALZA se fuori (§4.1)
|
||||
```
|
||||
|
||||
e in `book_report`, una riga sotto `cap = _cap(...)`:
|
||||
|
||||
```python
|
||||
scala = _scala(sh.get("real_equity"), sh.get("eq_fallback"))
|
||||
...
|
||||
net = book_net_target(tp_frac, sign, equity, cap, scala=scala)
|
||||
```
|
||||
|
||||
`book_report` deve **esporre `scala` nel dict di ritorno** accanto a `cap_per_asset`, e
|
||||
`book_execute` deve **stamparla nella riga «sizing base»**: un parametro che agisce sul nozionale e
|
||||
non compare nel report e' la forma esatta del difetto che questo progetto ha gia' pagato tre volte
|
||||
(docstring che dichiarano una causalita' che il codice non ha).
|
||||
|
||||
### 2.3 Perche' **li'** e non altrove — e la dimostrazione
|
||||
|
||||
`book_net_target` e' **l'unico punto della catena in cui le due gambe si incontrano con una TAGLIA**:
|
||||
sopra di lei TP01 da' una frazione e SKH01 da' **solo un segno**; sotto di lei si calcolano delta e
|
||||
ordini. Percio' e' l'unico punto in cui un moltiplicatore e' un puro cambio di scala.
|
||||
|
||||
Il prototipo (sez. 3) lo misura sulla funzione di produzione stessa — la copia e' **bit-exact**
|
||||
(`max|copia − produzione| = 0.00e+00` su 480 combinazioni):
|
||||
|
||||
| k | solo TP01 (tp=1, sg=0) | solo SKH01 (tp=0, sg=1) | rapporto TP/SKH | peso implicito TP01 |
|
||||
|---|---|---|---|---|
|
||||
| 1,00 | 2.267,62 | 755,88 | **3,000000** | **0,750000** |
|
||||
| 1,25 | 2.834,53 | 944,84 | **3,000000** | **0,750000** |
|
||||
| 2,00 | 4.535,25 | 1.511,75 | **3,000000** | **0,750000** |
|
||||
|
||||
`max|target(k) − k·target(1)| = 0.00e+00` su 90 combinazioni. **Il mix 75/25 e' invariante a ogni k:
|
||||
e' una scala, non un tilt.**
|
||||
|
||||
Le alternative, e perche' cadono:
|
||||
|
||||
| dove | perche' NO |
|
||||
|---|---|
|
||||
| `TrendPortfolio.target_vol` | scala il **75%** del libro e lascia fermo il 25% → e' anche un **tilt di pesi**, e **fallisce `weights_tilt_null`**. Misurato nel prototipo come **controllo positivo**: a k=1,25 il peso implicito di TP01 passa da 0,750 a **0,789**. |
|
||||
| `_skyhook_positions` | non c'e' niente da scalare: produce un **segno**. |
|
||||
| `WEIGHT` (=0,5) | e' lo **split BTC/ETH**, ed e' **condiviso** con `shadow_report`/`build_rebalance_order` (`shadow.py:144`) e con la dashboard, cioe' con il percorso **TP01-only**: cambiarlo cambierebbe anche un altro libro. E confonderebbe in un solo numero «quanti asset» e «quanta leva». |
|
||||
| `W_TP01` / `W_SKH` | sono il **rapporto** 75/25 e sono legati per test ai pesi del backtest (`test_weights_match_backtest_sleeves` asserisce `W_TP01+W_SKH == 1.0` e la parita' con `deribit_book_sleeves`). Moltiplicarli entrambi romperebbe quella parita' e renderebbe impossibile distinguere scala e mix. |
|
||||
| `build_book_order` | scalerebbe il **delta**, non il target: cambia la **velocita' di convergenza**, non la taglia, e il reconciler litigherebbe con se' stesso a ogni giro. |
|
||||
| dentro `DeribitTrader` | il report, il dry-run e `book_executions.jsonl` stamperebbero un target **diverso** da quello eseguito. |
|
||||
|
||||
---
|
||||
|
||||
## 3. L'INTERAZIONE COL CAP — il punto sottile
|
||||
|
||||
### 3.1 Il fatto geometrico
|
||||
|
||||
Il cap e' un **clamp**: `net = clamp(0.5·E·(0,75·tp + 0,25·sg), ±cap)` con `cap = frac·E = 0,50·E`.
|
||||
A piena convinzione (`tp=1, sg=+1`) il grezzo vale **esattamente** `0,5·E·1,0 = 0,50·E = cap`:
|
||||
**il clamp e' tangente al libro proprio nei giorni di massima esposizione.**
|
||||
|
||||
### 3.2 I due ordini, misurati (prototipo sez. 4, su 5.648 giorni-asset veri)
|
||||
|
||||
| k | ordine | clampati | quota | k_eff medio | **k_eff a piena convinzione** | lordo max |
|
||||
|---|---|---|---|---|---|---|
|
||||
| 1,25 | **PRIMA** del clamp | 32 | 0,57% | 1,2487 | **1,0000** | 1,000 |
|
||||
| 1,25 | **DOPO** il clamp | 0 | 0,00% | **1,2500** | **1,2500** | 1,250 |
|
||||
| 2,00 | PRIMA | 793 | 14,04% | 1,9235 | **1,0000** | 1,000 |
|
||||
| 2,00 | DOPO | 0 | 0,00% | **2,0000** | **2,0000** | 2,000 |
|
||||
|
||||
**L'ordine corretto e' DOPO il clamp**, e la ragione non e' di comodo:
|
||||
|
||||
- **PRIMA**: il clamp mangia la scala **proprio nei giorni di massima convinzione** (k_eff = 1,00 a
|
||||
piena convinzione, a ogni k). Il risultato non e' «il libro a leva k»: e' un libro che alza i
|
||||
giorni piccoli e lascia fermi i grandi, cioe' un **appiattimento del profilo di convinzione**. E'
|
||||
un cambio di **FORMA** travestito da cambio di taglia — e allora **la curva g(k) di
|
||||
`r0822_growth_policy` / WORST-DAY non descrive quel libro**, perche' quella curva e' calcolata su
|
||||
`k·r`, cioe' sull'ordine DOPO. Autorizzare il gradino con una curva e implementarne un'altra e'
|
||||
il modo piu' silenzioso di sbagliare che questa specifica possa produrre.
|
||||
- **DOPO**: `k_eff = k` esattamente, in ogni giorno e in ogni stato del segnale. E' l'unico ordine
|
||||
per cui «leva k» significa la stessa cosa nel codice e nel backtest.
|
||||
|
||||
### 3.3 Cosa implica per il SIGNIFICATO del cap — e va detto, perche' e' il prezzo
|
||||
|
||||
Con l'ordine DOPO, **il cap smette di essere il tetto assoluto del nozionale**. Diventa il tetto
|
||||
del **libro unitario**: limita la *forma* (nessun asset oltre `frac·E` di esposizione unitaria),
|
||||
mentre la *taglia* la decide la scala. Il lordo massimo passa da `n_asset·frac` a
|
||||
**`n_asset·frac·scala`** = 1,250x l'equity a k=1,25.
|
||||
|
||||
E il cap **non smette di fare le altre due cose che fa oggi**, che sono quelle che contano davvero:
|
||||
|
||||
1. resta **proporzionale all'equity** (`cap = equity·frac` sul percorso fidato) → un deposito non
|
||||
strozza il libro e un prelievo lo rimpicciolisce da solo;
|
||||
2. resta **legato al watermark** sul percorso di fallback (`min(fisso, watermark·frac)`) → il caso
|
||||
che il 26/07 valeva «3,35x di leva su un conto da $597» resta chiuso (§4.3).
|
||||
|
||||
⚠️ **Cio' che il cap NON puo' piu' fare da solo e' essere la guardia di sicurezza sulla leva
|
||||
lorda.** Quella guardia va ricostruita esplicitamente, ed e' il §4.
|
||||
|
||||
### 3.4 Il test che si rompe — e **deve** rompersi
|
||||
|
||||
`tests/test_fee_sensitivity.py::test_leva_massima_da_config_resta_sotto_o_uguale_a_1x`:
|
||||
|
||||
```python
|
||||
leva_max = frac * len(FS.ASSETS)
|
||||
assert leva_max <= 1.0, ("leva massima ...: la liquidation fee 1% torna rilevante, "
|
||||
"rivedere r0726_fee_sensitivity e il diario 2026-07-26-fee-deribit.md")
|
||||
```
|
||||
|
||||
**Si rompe? No — e questo e' il punto.** Con `frac` invariato a 0,50 il test continua a **passare**,
|
||||
perche' misura `frac · n_asset` mentre la grandezza vera diventa `frac · n_asset · scala`.
|
||||
**Non si rompe, e smette di controllare cio' che era stato scritto per controllare.**
|
||||
|
||||
E' esattamente la forma di difetto che il progetto ha catturato **tre volte in un giorno** il
|
||||
2026-08-21: *un controllo puntato su una configurazione diversa da quella che gira passa sempre, e
|
||||
non sta controllando niente* (`fee_watch` sugli inverse, `venue_watch` con bitfinex, i test di
|
||||
`book_live` a libro flat).
|
||||
|
||||
**Quindi va sostituito, non aggiustato**, e la sostituzione e' una coppia:
|
||||
|
||||
- **T2** (§5) — `test_la_leva_lorda_da_config_resta_sotto_il_tetto`: asserisce
|
||||
`len(ASSETS) * frac * scala <= LEVA_LORDA_MAX`, cioe' **il prodotto**, e importa la scala **dallo
|
||||
stesso posto da cui la importa la produzione** (regola del 21/08: *un sorvegliante deve DERIVARE
|
||||
il proprio bersaglio dal codice sorvegliato, mai ridichiararlo*).
|
||||
- **prerequisito del gate** (§6): `r0726_fee_sensitivity` va **rifatto** al nuovo lordo, perche' la
|
||||
sua conclusione *«liquidation fee 1% irrilevante»* era esplicitamente condizionata a nozionale
|
||||
lordo ≤1x. Al gradino il lordo e' 1,25x → una liquidazione costerebbe **1,25%** dell'equity, non
|
||||
1,00%. Non e' un problema; e' un numero che va **ricalcolato e ripubblicato**, non ereditato.
|
||||
|
||||
Il vecchio test va **cancellato con una nota** che dice perche' (e rimandi a questo documento), non
|
||||
modificato in silenzio: un test di decisione che cambia soglia senza lasciare traccia e' un test di
|
||||
decisione perso.
|
||||
|
||||
---
|
||||
|
||||
## 4. LE GUARDIE
|
||||
|
||||
### 4.1 G1 — il tetto: **sul PRODOTTO, in CODICE, e non silenzioso**
|
||||
|
||||
```python
|
||||
LEVA_LORDA_MAX = 1.25 # src/live/book.py — costante di CODICE
|
||||
SCALA_LADDER = (1.00, 1.25)
|
||||
```
|
||||
|
||||
Tre proprieta', tutte necessarie:
|
||||
|
||||
**(a) Sul prodotto.** `frac` e `scala` **moltiplicano**. Un tetto sulla sola chiave lascia aperta la
|
||||
porta accanto (prototipo sez. 6):
|
||||
|
||||
| frac | scala | leva lorda | tetto «scala ≤ 1,25» | **tetto sul PRODOTTO** |
|
||||
|---|---|---|---|---|
|
||||
| 0,500 | 1,25 | 1,250 | passa | passa |
|
||||
| **0,625** | **1,25** | **1,562** | **passa** | **BLOCCA** |
|
||||
| **0,750** | **1,25** | **1,875** | **passa** | **BLOCCA** |
|
||||
| 0,500 | 2,00 | 2,000 | BLOCCA | BLOCCA |
|
||||
|
||||
Ed e' un rischio **concreto, non teorico**: WORST-DAY ha appena pubblicato che «alzare `frac` da
|
||||
0,50 a 0,625 non produce k=1,25», il che rende `frac` un candidato naturale al prossimo ritocco —
|
||||
salvo che, **combinato con la scala, lo produce eccome**.
|
||||
|
||||
**(b) In codice.** Il tetto di config sarebbe modificabile dalla stessa mano, nello stesso file, nel
|
||||
momento in cui si modifica la chiave: sarebbe un lucchetto con la chiave attaccata. Con
|
||||
`LEVA_LORDA_MAX` in `src/live/book.py`, il gradino **1,25 → 1,50 richiede una modifica di codice**,
|
||||
quindi una review, quindi un gate. **Il tetto e' basso apposta: e' il meccanismo del cricchetto, non
|
||||
un'opinione sulla leva massima sopportabile** (che dalla §4.5 sarebbe 1,67x).
|
||||
|
||||
**(c) Non silenzioso.** Una scala fuori tetto (o fuori `SCALA_LADDER`) **NON viene tagliata al
|
||||
tetto**: `book_execute` **si ferma, non invia ordini, e allerta**. Un clamp silenzioso farebbe
|
||||
girare una config che dichiara un numero e un libro che ne esegue un altro — la stessa classe di
|
||||
difetto del §3.4. `SCALA_LADDER` esiste perche' **una scala a gradini rende inesprimibile «solo un
|
||||
po'»**: 1,05 non e' un valore prudente, e' un valore fuori scaletta, e viene rifiutato.
|
||||
|
||||
### 4.2 G2 — l'invariante che lega TRE chiavi
|
||||
|
||||
```python
|
||||
assert len(ASSETS) * frac * scala * disaster_sl_pct <= 0.50
|
||||
```
|
||||
|
||||
Vedi §4.5: e' la guardia che morde per prima, e cattura chi allarga il disaster-SL.
|
||||
|
||||
### 4.3 G3/G4 — il watermark e l'equity non leggibile
|
||||
|
||||
**Regola proposta: la scala vive SOLO sul percorso fidato.**
|
||||
|
||||
```python
|
||||
scala_effettiva = scala se l'equity REALE e' leggibile, altrimenti 1.00
|
||||
```
|
||||
|
||||
Motivo: **una scala e' una decisione di rischio presa conoscendo il conto; quando non si sa quanto
|
||||
vale il conto, non si prende.** Cosi' «il fallback non e' piu' permissivo» e' vero **per
|
||||
costruzione**, non per aritmetica — e non dipende dal fatto che il conto degli invarianti torni.
|
||||
|
||||
Misurato (prototipo sez. 6-bis; watermark reale letto da disco, $634,996; copia di `_cap`
|
||||
verificata bit-exact contro la produzione):
|
||||
|
||||
| stato | cap | scala eff. | lordo max | **/ equity vera** | tetto |
|
||||
|---|---|---|---|---|---|
|
||||
| normale (equity reale letta) | 317,50 | **1,25** | 793,74 | **1,250x** | si |
|
||||
| online ma equity illeggibile | 317,50 | **1,00** | 635,00 | **1,000x** | si |
|
||||
| watermark assente (1° avvio) | 300,00 (`CAP_UNKNOWN_USD`) | **1,00** | 600,00 | 0,945x | si |
|
||||
| watermark vecchio e basso | 50,00 | **1,00** | 100,00 | 0,157x | si |
|
||||
| dopo un deposito a $6.047 | 3.023,50 | **1,25** | 7.558,75 | 1,250x | si |
|
||||
|
||||
**In nessuno stato degradato la leva supera quella dello stato normale**, e il caso «watermark
|
||||
assente» ha **due protezioni indipendenti** (cap $300 **e** scala 1,00), non una sola.
|
||||
|
||||
⚠️ **Prezzo dichiarato.** Nei giri in cui l'equity non e' leggibile il libro gira a k=1 e al giro
|
||||
dopo torna a k → un ribilancio in piu' per oscillazione, di `(k−1)·frac·E` per asset = **~$79 a
|
||||
testa** sul conto di oggi, cioe' **~$0,056** di fee a 3,5 bps. **Frequenza misurata** su
|
||||
`logs/cron_book.log`: **0 giri su 1.442 (0,00%)**; i 21 giri «conto non leggibile» sono OFFLINE, e
|
||||
li' il libro non manda ordini affatto, quindi la scala non si pone. → **il prezzo esiste, e' noto,
|
||||
ed e' nullo sul campione osservato.**
|
||||
⚠️ **E questo e' anche il limite dichiarato della regola:** se un giorno il ramo di fallback
|
||||
diventasse frequente, il libro girerebbe a una leva **mista** e la curva `g(k)` smetterebbe di
|
||||
descriverlo. → **il sorvegliante del §6.4 deve riportare quella frequenza**, e se supera il **2%
|
||||
dei giri in 90 giorni** la regola va ridiscussa (soglia dichiarata qui, prima di vedere il caso).
|
||||
|
||||
**Alternativa scartata:** congelare l'ultimo target scalato durante il fallback. Aggiunge **stato**
|
||||
a un percorso con soldi veri — cioe' un nuovo modo di essere sbagliati — per risparmiare $0,056.
|
||||
|
||||
### 4.4 G5 — il `min_order_usd` non e' un problema, e va detto
|
||||
|
||||
La scala **aumenta** i delta, quindi allontana dal pavimento $5 invece di avvicinarcisi. Nessuna
|
||||
azione. (Lo si dice perche' «non e' un problema» misurato vale quanto un problema trovato: evita
|
||||
che la domanda torni.)
|
||||
|
||||
### 4.5 G6 — il disaster-SL: **la guardia che morde per prima, e non era stata calcolata**
|
||||
|
||||
Il disaster-SL e' un movimento di **prezzo** (−30% sul mark), non una perdita in equity. L'impatto
|
||||
in equity e' quel movimento **moltiplicato per il lordo**, quindi **cresce con k anche se
|
||||
`disaster_sl_pct` non cambia**. Prototipo sez. 6, tutte le righe scalate dai numeri **replicati**
|
||||
di WORST-DAY (§7):
|
||||
|
||||
| k | lordo max | A) peggior giorno possibile | **B) costo disaster-SL** | C) x_liq | min intra·k | margine C |
|
||||
|---|---|---|---|---|---|---|
|
||||
| 1,00 | 0,864 | 14,32% | **30,00%** | 115,8% | 7,33% | 15,8x |
|
||||
| **1,25** | **1,081** | **17,90%** | **37,50%** | **92,5%** | **9,16%** | **10,1x** |
|
||||
| 1,50 | 1,297 | 21,48% | 45,00% | 76,9% | 11,00% | 7,0x |
|
||||
| 2,00 | 1,729 | 28,64% | **60,00%** ← sfonda | 57,4% | 14,66% | 3,9x |
|
||||
|
||||
📌 **La guardia che morde per prima NON e' il peggior giorno possibile, e' il disaster-SL:**
|
||||
|
||||
- da (A): `k ≤ 50% / 14,32%` = **3,49x**
|
||||
- da (B): `k ≤ 50% / (2 · 0,50 · 30%)` = **1,67x** ← **2,1x piu' stringente**
|
||||
|
||||
A k=1,25 il margine di (A) e' **2,8x** (il numero che WORST-DAY pubblica come C1) mentre quello di
|
||||
(B) e' **1,33x**. **Il criterio C1 di WORST-DAY guardava la grandezza sbagliata**: guardava il
|
||||
peggior giorno del *segnale*, non il costo del dispositivo di emergenza che il libro ha davvero
|
||||
armato sul conto. Da qui l'invariante G2 (§4.2), che con `sl_pct=30%` e `frac=0,50` da'
|
||||
**scala ≤ 1,67x** — e che scatta se qualcuno allarga il disaster-SL.
|
||||
|
||||
**Decisione: `disaster_sl_pct` NON si tocca.** Stringerlo a 24% per tenere invariante l'impatto in
|
||||
equity lo trasformerebbe da dispositivo di catastrofe in **stop di strategia**: verrebbe toccato dal
|
||||
rumore, e il progetto ha gia' misurato cosa succede quando uno stop stretto incontra un gap (SKH01,
|
||||
`sl 2% modellato → −11/−23% realizzato`). Si accetta il 37,5% e **lo si scrive**.
|
||||
|
||||
⚠️ **Osservazione da LETTURA DEL CODICE, non misurata, e va citata cosi'.**
|
||||
`src/live/execution.py:196-223` **ri-ancora** il disaster-SL al mark a ogni giro: se lo stop esistente
|
||||
dista piu' del **5%** relativo da `mark·(1−sl_pct)`, viene **cancellato e ripiazzato**. Per un long
|
||||
questo significa che lo stop **segue il prezzo anche in discesa**: il −30% e' un −30% **rotolante
|
||||
dall'ultimo piazzamento**, non un pavimento assoluto sul trade. Quindi **B e' il costo di UN
|
||||
episodio**, e un ribasso lento puo' produrne piu' d'uno.
|
||||
Evidenza circostanziale, non prova: nel log ci sono **15 `placed` contro 259 `ok`** su asset con
|
||||
posizione aperta — coerente con qualche ri-ancoraggio, ma i `placed` includono anche le prime
|
||||
aperture e **non sono separabili dal log**. → **e' una proprieta' di oggi che il gradino amplifica,
|
||||
non una che il gradino crea**, ed e' un follow-up con una domanda precisa: *quante volte il bracket
|
||||
e' stato ri-piazzato mentre la posizione restava aperta?* (misurabile aggiungendo `pos_prima` al log,
|
||||
non ricostruibile da quello attuale).
|
||||
|
||||
---
|
||||
|
||||
## 5. I TEST CHE DEVONO ESISTERE **PRIMA** DELLA MODIFICA
|
||||
|
||||
Scritti come specifiche eseguibili: **nome + cosa asserisce + il caso che deve far fallire.**
|
||||
File proposto: `tests/test_book_scale.py` (piu' le modifiche dichiarate a
|
||||
`tests/test_fee_sensitivity.py`).
|
||||
|
||||
| # | test | asserisce | **deve fallire se** |
|
||||
|---|---|---|---|
|
||||
| **T1** | `test_la_scala_e_identica_sui_due_sleeve` | su una **griglia di k** (1,00/1,10/1,25/1,50/2,00) × tp_frac × segno, con cap disattivato: `target(k) == k·target(1)` **e** `target(tp=1,sg=0)/target(tp=0,sg=1) == W_TP01/W_SKH` costante | qualcuno applica la scala a **una sola** gamba (o dentro `TrendPortfolio`) |
|
||||
| **T1b** | `test_il_test_di_simmetria_smaschera_una_scala_asimmetrica` | **CONTROLLO POSITIVO**: la stessa asserzione, applicata a un'implementazione asimmetrica scritta nel test, **fallisce** | il test T1 gira **solo a k=1** (dove le due implementazioni **coincidono**: potenza **zero** — misurato nel prototipo) |
|
||||
| **T2** | `test_la_leva_lorda_da_config_resta_sotto_il_tetto` | `len(ASSETS) * frac * scala <= LEVA_LORDA_MAX`, con `frac` e `scala` **letti da `config/live.json`** e `LEVA_LORDA_MAX`/`ASSETS` **importati dal modulo di produzione** | qualcuno alza `frac`, o la scala, **o entrambe di poco** |
|
||||
| **T3** | `test_l_invariante_disaster_sl_tiene_meta_equity` | `len(ASSETS) * frac * scala * disaster_sl_pct <= 0.50` | qualcuno allarga `disaster_sl_pct` **o** alza la scala fino a 1,67x |
|
||||
| **T4** | `test_il_fallback_non_e_piu_permissivo_del_percorso_fidato` | in **ogni** stato degradato (equity illeggibile / watermark assente / watermark vecchio) il lordo massimo **/ equity vera** ≤ quello dello stato normale | qualcuno applica la scala anche in fallback, o slega il cap dal watermark |
|
||||
| **T5** | `test_il_cap_continua_a_limitare_cio_che_limitava` | il target per-asset non supera mai `cap·scala`; e il clamp **morde ancora** sulle stesse osservazioni di prima (le 3 su 5.650) | qualcuno inverte l'ordine (§3.2) o toglie il clamp «tanto c'e' la scala» |
|
||||
| **T6** | `test_una_scala_fuori_tetto_ferma_l_esecuzione_e_non_viene_tagliata` | con `scala` fuori `SCALA_LADDER` o fuori tetto: `book_execute` **non invia**, allerta, e il valore **non** viene silenziosamente clampato | qualcuno «rende robusto» il lettore con un `min(scala, LEVA_LORDA_MAX/…)` |
|
||||
| **T7** | `test_senza_la_chiave_il_libro_e_quello_di_oggi` | con chiave assente **o** `= 1.0`, `book_net_target` e' **bit-exact** alla versione attuale su una griglia (`max|diff| == 0.0`) | la modifica cambia qualcosa **prima** che qualcuno decida di cambiarlo |
|
||||
| **T8** | `test_il_report_e_il_log_dichiarano_la_scala` | `book_report()['scala']` esiste e `book_execute` la stampa | un parametro che muove il nozionale resta invisibile nel report |
|
||||
| **T9** | `test_la_scala_e_derivata_dal_codice_non_ridichiarata` | il sorvegliante e i test importano `LEVA_LORDA_MAX`, `ASSETS`, `SCALA_LADDER` **da `src/live/book`** e non li riscrivono | due liste in due file (regola del 21/08, 4 occorrenze) |
|
||||
| **T10** | `test_il_sorvegliante_segnala_una_scala_non_autorizzata` | **CONTROLLO POSITIVO** del §6.4: con una config che dichiara una scala assente dal giornale, il sorvegliante **allerta**; con config e giornale concordi, **tace** | il sorvegliante e' tarato per non segnalare mai (regola del 26/07: *un rilevatore tarato per non segnalare e' indistinguibile da uno rotto*) |
|
||||
| **T11** | `test_il_vecchio_test_di_leva_e_stato_sostituito_non_rilassato` | `test_leva_massima_da_config_resta_sotto_o_uguale_a_1x` **non esiste piu'** e T2/T3 esistono | qualcuno alza la soglia del vecchio test da 1,0 a 1,25 e chiude li' |
|
||||
|
||||
⚠️ **T1b e' il test piu' importante dell'elenco**, ed e' la ragione per cui questo paragrafo esiste:
|
||||
il prototipo (sez. 3) mostra che **a k=1 l'implementazione simmetrica e quella asimmetrica danno lo
|
||||
stesso identico numero**. Un test di simmetria scritto sul caso di default passa sempre e non
|
||||
controlla niente — la stessa firma dei test di `book_live` scoperti senza potenza a libro flat.
|
||||
|
||||
---
|
||||
|
||||
## 6. IL GATE MANCANTE — `GATE SCALA-01`
|
||||
|
||||
### 6.1 Perche' serve un gate NUOVO
|
||||
|
||||
Vedi §0: nessun gate esistente vede la scala. Il gate deve quindi vivere sull'unico asse su cui la
|
||||
scala si vede: **crescita e rovina** (`g(k)`, maxDD, distanza dalla liquidazione), non Sharpe.
|
||||
|
||||
### 6.2 Le condizioni — tutte necessarie
|
||||
|
||||
Per portare `book_scale_k` da `k0` a `k1`:
|
||||
|
||||
| | condizione | misurata come |
|
||||
|---|---|---|
|
||||
| **A1** | `k1` e' il **gradino successivo** di `SCALA_LADDER` (1,00 → 1,25). Nessun valore intermedio. | confronto con la costante di codice |
|
||||
| **A2** | `k0` e' in produzione da **≥180 giorni** con il criterio passato **ogni giorno** | giornale `data/live/scale_history.jsonl` (append-only) + registrazioni del sorvegliante |
|
||||
| **A3** | **C1–C5 di WORST-DAY** ricalcolati **oggi** a `k1`, tutti PASSA — non ereditati dal 22/08 | ri-esecuzione di `r0822c_worst_day` sui dati correnti |
|
||||
| **A4** | **C7 = G2**: `n_asset · frac · k1 · disaster_sl_pct ≤ 0,50` | §4.5 |
|
||||
| **A5** | **C8 = G1**: `n_asset · frac · k1 ≤ LEVA_LORDA_MAX` | §4.1 |
|
||||
| **A6** | **ANTI-RECENCY**: il criterio deve passare **anche escludendo gli ultimi 90 giorni**: `k_ammesso(r[:-90]) ≥ k1` | §6.3 |
|
||||
| **A7** | `r0726_fee_sensitivity` **rifatto** al nuovo lordo e la conclusione «liquidation fee irrilevante» **ri-derivata o ritirata** | §3.4 |
|
||||
| **A8** | la modifica e' **una riga di config + una riga di giornale**, zero codice. Se serve toccare `LEVA_LORDA_MAX`, **non e' una decisione di config** | diff |
|
||||
| **A9** | i test T1–T11 (§5) esistono e passano **prima** | pytest |
|
||||
|
||||
### 6.3 A6 — l'anti-recency, e come si misura davvero
|
||||
|
||||
La forma verificabile e': **il gradino dev'essere autorizzato anche dai dati che non contengono la
|
||||
finestra recente che ha motivato la richiesta.** E' l'analogo, sull'asse della scala, di
|
||||
`select_cell_insample`.
|
||||
|
||||
Il prototipo (sez. 7b) misura la meccanica su `k_ammesso = ½·k*(drift a −2 SE, coda troncata al
|
||||
bound strutturale)`:
|
||||
|
||||
| finestra | n | drift punto | drift −2SE | k ammesso | ≥1,25x? |
|
||||
|---|---|---|---|---|---|
|
||||
| tutta la storia | 2.719 | 17,11% | 8,78% | **3,52** | SI |
|
||||
| esclusi ultimi 90 g | 2.629 | 16,70% | 8,15% | **3,20** | SI |
|
||||
| esclusi ultimi 365 g | 2.354 | 19,52% | 10,20% | 3,80 | SI |
|
||||
| solo ultimi 365 g | 365 | 1,59% | −13,69% | 0,03 | NO |
|
||||
|
||||
e la sensibilita' a un tratto recente **artificialmente buono** (ultimi 90 giorni riscritti a un
|
||||
drift dato, sull'intera storia):
|
||||
|
||||
| ultimi 90 g portati a | drift −2SE | k ammesso | delta |
|
||||
|---|---|---|---|
|
||||
| 0%/anno | 7,82% | 3,12 | −0,40 |
|
||||
| +50%/anno | 9,47% | 3,80 | +0,28 |
|
||||
| **+100%/anno** | 11,11% | **4,45** | **+0,93** |
|
||||
| +200%/anno | 14,35% | 5,63 | +2,10 |
|
||||
|
||||
**Il −2 SE fa gran parte del lavoro** (un tratto eccezionale alza insieme il drift *e* la sua
|
||||
incertezza), **ma non basta**: il criterio resta una funzione dei dati recenti, e la protezione vera
|
||||
e' la **doppia valutazione** di A6.
|
||||
|
||||
⚠️ **Tre onesta' obbligatorie su questa sezione:**
|
||||
1. `k_ammesso` del prototipo e' **deliberatamente semplificato** (troncatura al bound, nessuna GPD):
|
||||
serve a mostrare la **meccanica**, non a produrre il numero. Il gate reale usa la versione di
|
||||
`r0822c_worst_day`.
|
||||
2. **Oggi A6 non morde**: `k_ammesso ≈ 3,5x` contro un gradino di 1,25x. Il vincolo che morde e'
|
||||
quello del §4.5 (disaster-SL). **A6 serve al gradino successivo, non a questo** — e va scritto
|
||||
ora, quando non e' comodo per nessuno, non quando servira'.
|
||||
3. La prima stesura di questa sezione presentava «solo ultimi 365 giorni» come l'esempio di *«un anno
|
||||
buono»*: **falso**, quell'anno e' stato debole (drift 1,59%). Quella riga mostra solo che un
|
||||
campione corto ha un SE enorme. La riga che risponde alla domanda vera e' la tabella dello shock.
|
||||
|
||||
### 6.4 La cadenza — `scale_watch`
|
||||
|
||||
Sorvegliante giornaliero (proposto: `src/live/scale_watch.py` + `scripts/live/scale_watch.py` in
|
||||
`cron_daily.sh`; **non implementato**), che risponde a **tre domande diverse** — e sono davvero tre,
|
||||
perche' hanno **tre azioni diverse** e nessuna e' deducibile dalle altre:
|
||||
|
||||
| domanda | esito | azione |
|
||||
|---|---|---|
|
||||
| la config dichiara una scala che il **giornale** non ha mai autorizzato? | 🚨 | ricostruire come ci e' arrivata; scendere a `k0` |
|
||||
| il criterio che autorizzo' la scala **corrente** passa ancora oggi? | 🚨 | **scendere di un gradino** |
|
||||
| il **prodotto** `frac·scala·n_asset` ha superato `LEVA_LORDA_MAX`? | 🚨 | bloccare l'esecuzione |
|
||||
|
||||
Piu' due requisiti che il progetto ha gia' imparato a pagare:
|
||||
|
||||
- **tre stati, non due**: `OK` / `ALLARME` / **`NON MISURABILE`** (serie troppo corta, dati mancanti).
|
||||
*«Non vedo» non e' «va tutto bene»* — `paper_dvolspread`, `venue_watch`.
|
||||
- **disciplina degli allarmi**: una allerta per streak (`lock_step`), non una per giro; e il
|
||||
messaggio deve dire **cosa** (decide) **e perche'** (ripara), con il valore **letto**, mai cablato.
|
||||
|
||||
E deve **riportare la frequenza del ramo di fallback** (§4.3), che oggi e' 0/1.442 e che se salisse
|
||||
sopra il **2% in 90 giorni** invalida la regola «scala solo sul percorso fidato».
|
||||
|
||||
⚠️ **Cio' che il sorvegliante NON puo' fare: impedire la modifica.** Chi ha accesso al file puo'
|
||||
scriverci dentro. Il sorvegliante rende la modifica **visibile entro 24 ore** e **attribuibile**.
|
||||
E' la stessa onesta' di `venue_watch`: non protegge il saldo, compra tempo.
|
||||
|
||||
---
|
||||
|
||||
## 7. IL COSTO DI NON FARLO, E IL RISCHIO DI FARLO
|
||||
|
||||
### 7.1 Il costo di restare a 1,00x
|
||||
|
||||
**~€165/mese di versamenti equivalenti, a costo zero, per sempre** (§0): 14,7a → **12,9a** al
|
||||
capitale-rendita a €500/m netto fisco. Sulla scala delle leve misurate dal progetto sta **sotto**
|
||||
«versare o no» (da *mai* a 16 anni) e «quando versare» (fattore 6), e **sopra** tutto cio' che la
|
||||
ricerca ha prodotto in due mesi: l'ottimizzazione del peso SKH01 vale **+0,030 di Sharpe** e ha
|
||||
fallito il suo gate; il gradino vale **1,8 anni**.
|
||||
|
||||
Ed e' **l'unica leva grande che non richiede soldi nuovi**.
|
||||
|
||||
### 7.2 Il rischio di farlo, in una tabella
|
||||
|
||||
| grandezza | k=1,00 | **k=1,25** | fonte |
|
||||
|---|---|---|---|
|
||||
| peggior giorno **possibile** (chiusura) | 14,32% | **17,90%** | replicato, §4.5 |
|
||||
| peggior giorno **vissuto** (chiusura) | 3,95% | 4,94% | replicato |
|
||||
| peggior **minimo** intra-giorno | 7,33% | 9,16% | WORST-DAY (lente accoppiata) |
|
||||
| **costo di un disaster-SL** | 30,0% | **37,5%** | §4.5 ← **la guardia che morde** |
|
||||
| margine di liquidazione | 15,8x | 10,1x | §4.5 |
|
||||
| maxDD storico | 12,17% | 15,01% | §0 |
|
||||
| costo funding non modellato | ~1,53%/a | ~1,91%/a | FUNDING §35 |
|
||||
| costo di una liquidazione (fee 1%) | 1,00% eq | 1,25% eq | §3.4, da ricalcolare |
|
||||
|
||||
### 7.3 La riga che WORST-DAY ha dichiarato, e che va tenuta in cima alla decisione
|
||||
|
||||
> Se si credono **entrambe** le riserve insieme — drift a −2 SE **e** un giorno a −10% ogni anno —
|
||||
> il drift atteso e' **−0,61%/anno**, e **a quel punto non e' il gradino a essere sbagliato, e' il
|
||||
> libro**: chi usa quella combinazione sta chiedendo di spegnere anche il conto di oggi.
|
||||
|
||||
Questa specifica non risolve quel dilemma e non deve: lo rende **esplicito**. Chi rifiuta il gradino
|
||||
in nome di entrambe le riserve deve dire cosa propone di fare del libro a k=1.
|
||||
|
||||
### 7.4 Cosa questa specifica **non** rende sicuro
|
||||
|
||||
- **La lente e' close-only** dove non usa i numeri intra-giorno di WORST-DAY. Su una regola a **un
|
||||
giorno** close-only e' **esattamente cieca** (25/07, riconfermato dallo scettico il 22/08). Sul
|
||||
canale **prop/funded** — dove il vincolo binding e' una barriera di DD giornaliera — **questa
|
||||
specifica non si applica** e la lente accoppiata resta obbligatoria.
|
||||
- **`g(k)` assume ritorno indipendente dalla size.** A $635 e' innocuo (SLIP-AUDIT: nessun impatto
|
||||
misurabile, e un fill ha preso il 21,9% del volume della sua barra 5m in un range di 1,08 bps), ma
|
||||
**quella misura ha una data di scadenza** — la partecipazione scala lineare col capitale.
|
||||
- **Il funding non e' in nessuna serie di questo documento.** Il libro paga gia' ~1,5%/anno che
|
||||
nessun backtest sottrae; il gradino lo amplifica del 25%. E' dentro C5, ma il **livello a k=1**
|
||||
resta un difetto aperto del progetto, non di questa specifica.
|
||||
- **La leva non compra probabilita', compra fretta** (PROP-ALLOC). Il gradino accorcia la mediana;
|
||||
non alza `P(arrivare)` in modo proporzionale, e **alza la varianza del percorso**.
|
||||
|
||||
---
|
||||
|
||||
## 8. PROCEDURA DI ATTIVAZIONE (checklist, in ordine)
|
||||
|
||||
1. Scrivere `tests/test_book_scale.py` con T1–T11 (§5). **Prima.** T7 deve passare **contro il
|
||||
codice attuale** (la chiave non esiste ancora → default 1,0 → bit-exact).
|
||||
2. Implementare §2.2 (`scala` in `book_net_target`, `_scala()`, `LEVA_LORDA_MAX`, `SCALA_LADDER`,
|
||||
`scala` nel report e nel print di `book_execute`). **Senza toccare `config/live.json`**: la chiave
|
||||
assente vale 1,0, il libro non cambia, i test lo dimostrano.
|
||||
3. Cancellare `test_leva_massima_da_config_resta_sotto_o_uguale_a_1x` **con la nota** (§3.4).
|
||||
4. Scrivere `scale_watch` (§6.4) + `data/live/scale_history.jsonl` con la riga iniziale
|
||||
`{"scala": 1.00, "dal": "...", "gate": "iniziale, nessun gradino"}`, e aggiungerlo a
|
||||
`cron_daily.sh` **e** al backup di `/opt/docker/scripts/backup.sh` (il giornale non e' ricostruibile).
|
||||
5. **Lasciare girare a 1,00 per almeno 30 giorni** con il sorvegliante attivo. Una manopola nuova si
|
||||
guarda funzionare **prima** di girarla.
|
||||
6. Solo allora: eseguire `GATE SCALA-01` (§6.2). Se PASSA, una riga di config + una di giornale.
|
||||
7. Rifare `r0726_fee_sensitivity` al nuovo lordo (A7) e ripubblicare la conclusione.
|
||||
|
||||
**Il punto 5 non e' burocrazia: e' l'unico modo di scoprire che il sorvegliante e' rotto mentre la
|
||||
leva e' ancora 1,00.**
|
||||
|
||||
---
|
||||
|
||||
## 9. NODI APERTI — dichiarati, non nascosti
|
||||
|
||||
1. **Il disaster-SL rotolante** (§4.5, ⚠️): letto nel codice, non misurato. Il log **non permette**
|
||||
di separare i ri-piazzamenti dalle prime aperture. Se davvero rotola, `B` e' il costo di *un*
|
||||
episodio e un ribasso lento ne produce piu' d'uno. **E' il nodo piu' serio di questo documento**,
|
||||
perche' tocca la guardia che morde per prima. Follow-up: aggiungere `pos_prima` al log di
|
||||
`ensure_disaster_sl` e ri-misurare — **non ricostruibile a posteriori**.
|
||||
2. **`LEVA_LORDA_MAX = 1.25` e' una scelta di processo, non una misura.** Dall'invariante del §4.5 il
|
||||
massimo sostenibile sarebbe 1,67x. Il valore basso e' il cricchetto. Chi vuole 1,50x deve toccare
|
||||
codice — **ed e' voluto**.
|
||||
3. **La banda d'ancora non e' stata girata su nessun numero di questo documento.** Tutte le serie
|
||||
sono all'ancora canonica con la correzione ×0,89 sul drift. Le grandezze usate per decidere
|
||||
(bound strutturale, lordo, invarianti) sono **aritmetiche** e non ancorate; `g(k)` e `k_ammesso`
|
||||
**lo sono** — e vanno lette con la banda del libro (Sharpe FULL de-luckato 1,95, banda [1,81; 2,12]).
|
||||
4. **Il gradino non e' stato autorizzato qui.** Questo documento specifica come si autorizza.
|
||||
|
||||
---
|
||||
|
||||
## 10. IL PROTOTIPO
|
||||
|
||||
`scripts/research/r0822e_scale_proto.py` — **0,9 s**, nessuna rete, nessuna scrittura.
|
||||
|
||||
```
|
||||
nice -n 19 timeout 900 uv run python scripts/research/r0822e_scale_proto.py
|
||||
```
|
||||
|
||||
Sezioni: (0) isolamento verificato · (1) sanity bit-exact vs produzione · (2) la catena letta dal
|
||||
sorgente · (3) simmetria + controllo positivo · (4) l'ordine col clamp · (5) replica di WORST-DAY ·
|
||||
(6) guardie · (6-bis) stati dell'equity · (7) il gate mancante.
|
||||
|
||||
**Replica a k=1,00 (sez. 5) — il motivo per cui le righe scalate di questo documento non sono
|
||||
numeri copiati:**
|
||||
|
||||
| grandezza | prototipo | pubblicato | scarto |
|
||||
|---|---|---|---|
|
||||
| drift de-luckato ×0,89 | 17,11% | 17,11% | 0,00% |
|
||||
| vol annua | 11,37% | 11,37% | −0,00% |
|
||||
| Sharpe de-luckato | 1,505 | 1,510 | −0,005 |
|
||||
| peggior giorno (chiusura) | −3,95% | −3,94% | −0,01% |
|
||||
| data del peggior giorno | **2020-03-13** | 2020-03-13 | coincide |
|
||||
| morso del clamp | **3 / 5.648** | 3 / 5.650 | 2 righe di bordo* |
|
||||
| bound strutturale | **−14,32%** | −14,32% | 0,00% |
|
||||
|
||||
\* differenza di costruzione: il prototipo scarta la prima barra per asset (serve `vol_prev`).
|
||||
|
||||
---
|
||||
|
||||
*Documento scritto senza modificare nulla in produzione. Il branch `research/wave-0822` e' quello da
|
||||
cui il cron esegue: ogni riga di `src/`, `config/`, `scripts/live/`, `scripts/cron_*.sh` e `tests/`
|
||||
e' rimasta identica.*
|
||||
Reference in New Issue
Block a user