usde al 68,7%: il tetto del venue del 30-31/08 non c'era piu'; il versamento di prova del 25/08 dichiarato, TWR +7,83%

Su autorizzazione dell'operatore («usa piu' USDE», «cerca % massima raggiungibile»):
- usde_convert al 31,8% (774 USDE), poi sonda a saldo crescente r0906_usde_tetto_sonda.py
  (passi 100->20->4->1, doppio rifiuto prima di scendere, conferma a saldo neutro): da 31,8%
  a 68,7% in 39 ordini @ 1,0005, ZERO rifiuti. Fermata dal cuscino di regolamento (70%,
  derivato da config), non dal venue. «Il 70% non e' raggiungibile ne' ora ne' mai» (31/08)
  e' falsificato: il tetto e' sparito, non scalato. Non spiegato, puo' tornare.
- config: venue_cap_frac -> null (misura in venue_cap_misurato), quota_max_frac 0,50 -> 0,85
  (il valore scelto dall'operatore il 30/08 per questo scenario).
- debito §5.17: nessuno sorveglia il cuscino USDC (slack $58; una perdita del libro lo consuma
  da sola).

Versamento di prova di EUR 25 il 25/08 08:00Z (dichiarato dall'operatore): +3,3% su $647, sotto
la soglia del 10% del rilevatore, contato per 12 giorni come trading.
- data/live/movimenti_dichiarati.jsonl (append-only, nel backup) letto da
  journal.movimenti_dichiarati; movimenti_capitale lo fonde coi rilevati (fonte dichiarato,
  importo dell'operatore, dopo = prima + importo; dichiarato+rilevato se coincide; fuori
  letture o riga rotta -> avvisi). Report e nota di giornale lo dicono.
- trading da arming +87,35 -> +62,45; TWR +11,98% -> +7,83%. CLAUDE.md §2 aggiornato.
- tests: +6 in test_journal (conftest isola il file). Suite 916 verdi.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KSnordG9FT4q8M4MVm85GQ
This commit is contained in:
Adriano Dal Pastro
2026-09-07 05:49:15 +00:00
parent 95424f0755
commit 9f55652d99
13 changed files with 762 additions and 22 deletions
+5
View File
@@ -122,6 +122,11 @@ def _isola_file_operativi_vivi(tmp_path, monkeypatch):
# non deve poter sporcare il working tree (P16: il cron gira dal working tree).
import src.live.journal as journal
monkeypatch.setattr(journal, "JOURNAL_DIR", tmp_path / "journal")
# --- data/live/movimenti_dichiarati.jsonl (2026-09-06) ------------------------------------
# `journal.movimenti_capitale` LEGGE i movimenti dichiarati dall'operatore: se un test
# vedesse quelli veri, un versamento reale entrerebbe in una serie di fixture e il test
# passerebbe o fallirebbe per un motivo che non e' suo. Qui il file non esiste.
monkeypatch.setattr(journal, "MOVIMENTI_DICHIARATI", tmp_path / "movimenti_dichiarati.jsonl")
yield
+90
View File
@@ -680,3 +680,93 @@ def test_balance_watch_registra_anche_l_indice_usde(monkeypatch):
monkeypatch.setattr(U, "prezzo_indice", _rotto)
rec = bw.campiona(_C())
assert rec["usde_usdc"] is None and rec["usde_usdc_errore"] == "RuntimeError"
# ------------------------------------------------- movimenti DICHIARATI dall'operatore (06/09)
# Il versamento di prova del 2026-08-25 08:00Z (~$25 su $647, +3,3%) e' restato 12 giorni nel P&L:
# sotto EQUITY_JUMP_ALERT il rilevatore non puo' vederlo, e abbassare la soglia farebbe di ogni
# ora di mercato un candidato. L'unica fonte che sa l'importo e' l'operatore.
def _dichiara(monkeypatch, tmp_path, righe):
f = tmp_path / "mov.jsonl"
f.write_text("\n".join(json.dumps(r) if isinstance(r, dict) else r for r in righe) + "\n")
monkeypatch.setattr(J, "MOVIMENTI_DICHIARATI", f)
return f
def test_un_versamento_dichiarato_sotto_soglia_viene_scorporato(db, monkeypatch, tmp_path):
monkeypatch.setattr(J, "_px_1h", lambda a: _px_piatto())
_serie_equity(db, [("2026-08-25T07:07:01+00:00", 646.77),
("2026-08-25T08:07:01+00:00", 667.88), # +3,3%: sotto soglia
("2026-08-25T09:07:01+00:00", 667.68)])
_dichiara(monkeypatch, tmp_path, [dict(ts_utc="2026-08-25T08:00:00+00:00", delta_usd=24.9,
banda_usd=0.5, nota="versamento di prova",
dichiarato_il="2026-09-06")])
r = J.rendimento_twr(db, "2026-08-25T23:59:59+00:00")
ev = r["eventi"]
assert len(ev) == 1 and ev[0]["classe"] == "movimento" and ev[0]["fonte"] == "dichiarato"
assert ev[0]["delta"] == pytest.approx(24.9) # l'IMPORTO dichiarato, non il salto
assert ev[0]["dopo"] == pytest.approx(646.77 + 24.9) # il mercato dell'ora resta nel rendimento
assert r["certi"] == pytest.approx(24.9)
assert r["trading"] == pytest.approx(667.68 - 646.77 - 24.9)
# TWR: segmento 1 di lunghezza zero (una sola lettura prima), segmento 2 da 671,67 a 667,68
assert r["twr"] == pytest.approx(667.68 / (646.77 + 24.9) - 1.0)
assert "versamento di prova" in ev[0]["dichiarazione"] and "±$0.50" in ev[0]["dichiarazione"]
def test_dichiarato_e_rilevato_insieme_vince_l_importo_dichiarato(db, monkeypatch, tmp_path):
monkeypatch.setattr(J, "_px_1h", lambda a: _px_piatto())
_serie_equity(db, [("2026-08-25T10:47:01+00:00", 667.49),
("2026-08-25T11:47:01+00:00", 2066.88),
("2026-08-25T12:47:01+00:00", 2064.56)])
_dichiara(monkeypatch, tmp_path, [dict(ts_utc="2026-08-25T11:20:00+00:00", delta_usd=1399.39,
nota="bonifico")])
r = J.rendimento_twr(db, "2026-08-25T23:59:59+00:00")
assert len(r["eventi"]) == 1 # UN evento, non due
e = r["eventi"][0]
assert e["fonte"] == "dichiarato+rilevato" and e["delta"] == pytest.approx(1399.39)
assert e["mercato_max_pct"] is not None # la misura di mercato resta
assert r["certi"] == pytest.approx(1399.39)
def test_dichiarato_fuori_dalle_letture_non_entra_ma_si_vede(db, monkeypatch, tmp_path):
monkeypatch.setattr(J, "_px_1h", lambda a: _px_piatto())
_serie_equity(db, [("2026-08-25T10:47:01+00:00", 600.0),
("2026-08-25T11:47:01+00:00", 601.0)])
_dichiara(monkeypatch, tmp_path, [dict(ts_utc="2026-08-20T08:00:00+00:00", delta_usd=25.0)])
r = J.rendimento_twr(db, "2026-08-25T23:59:59+00:00")
assert r["eventi"] == [] and r["certi"] == 0.0
assert r["avvisi"] and "non applicato" in r["avvisi"][0]
def test_una_riga_rotta_non_azzera_le_altre_e_non_sparisce(db, monkeypatch, tmp_path):
monkeypatch.setattr(J, "_px_1h", lambda a: _px_piatto())
_serie_equity(db, [("2026-08-25T07:07:01+00:00", 646.77),
("2026-08-25T08:07:01+00:00", 667.88)])
_dichiara(monkeypatch, tmp_path, ["{non json", dict(ts_utc="2026-08-25T08:00:00", delta_usd=1.0),
dict(ts_utc="2026-08-25T08:00:00+00:00", delta_usd=24.9)])
r = J.rendimento_twr(db, "2026-08-25T23:59:59+00:00")
assert r["certi"] == pytest.approx(24.9)
assert len(r["avvisi"]) == 2 and "senza fuso" in r["avvisi"][1]
def test_senza_file_dei_dichiarati_niente_cambia(db, monkeypatch):
monkeypatch.setattr(J, "_px_1h", lambda a: _px_piatto())
_serie_equity(db, [("2026-08-25T10:47:01+00:00", 600.0),
("2026-08-25T11:47:01+00:00", 612.0)])
assert not J.MOVIMENTI_DICHIARATI.exists() # conftest lo isola
r = J.rendimento_twr(db, "2026-08-25T23:59:59+00:00")
assert r["eventi"] == [] and r["avvisi"] == []
def test_la_nota_di_giornale_dice_che_e_dichiarato(db, monkeypatch, tmp_path):
monkeypatch.setattr(J, "_px_1h", lambda a: _px_piatto())
_serie_equity(db, [("2026-08-25T07:07:01+00:00", 646.77),
("2026-08-25T08:07:01+00:00", 667.88)])
_dichiara(monkeypatch, tmp_path, [dict(ts_utc="2026-08-25T08:00:00+00:00", delta_usd=24.9,
nota="versamento di prova")])
p = J.pnl_giorno(db, date(2026, 8, 25))
assert p["mov_giorno"] == pytest.approx(24.9)
righe = J.lettura(db, _voce(pnl=p, giorno="2026-08-25"))
mv = [r for r in righe if r["id"] == "movimento"]
assert mv and "dichiarato dall'operatore" in mv[0]["testo"] and "versamento di prova" in mv[0]["testo"]