de83909db9
MISURATO oggi durante la revisione: `trades_db.py --help` non stampava l'uso, cadeva in sync() e riscriveva meta.ultimo_sync. Nessuno dei 18 script di scripts/live/ usava argparse: un flag sbagliato era il ramo else. Su journal.py avrebbe scritto pagina e riga di DB, su analista.py avrebbe speso una chiamata al modello e mandato un Telegram. - src/live/cli.valida: prima istruzione di ogni __main__, prima di connect()/sync/rete. --help -> 0 con l'uso; flag ignoto, valore mancante o posizionale -> 2 con l'elenco dei previsti (P4). NIENTE argparse: cambierebbe messaggi, codici d'uscita e --help di script che il cron gia' chiama. - 18 script cablati (i 3 che scrivono + 14 + cc01), flag invariati. - tests/test_cli_flag.py (30): elenco DERIVATO dalla cartella (P1), valida come prima istruzione, uso che documenta i flag, e i flag che il CRON usa davvero restano accettati (P15/P16); end-to-end su --help e flag ignoto con trades.db non toccato (M15). Verificato a mano: monitor_health --quiet, trades_db --sync --quiet, book_execute dry-run. Debito §5.15, primo passo: balance_watch (orario) registra `usde_usdc` a ogni campione — None con la ragione se illeggibile, mai 1,0. Il cablaggio nel bound quando la serie ha storia. Pulizia dalla revisione: tests/helpers.carica_script al posto della 15a copia del loader importlib (5 file del libro live); il fill di prova via upsert_fills invece di un INSERT che lasciava verified NULL; asserzioni non ancorate al padding; movimenti_capitale accetta le righe gia' lette (una SELECT invece di due ai due lati di una scrittura del cron). Test 910 verdi (+52). Diario 2026-09-02c. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01XDJsH3iDSaBns3ccpPBwiu
80 lines
3.3 KiB
Python
80 lines
3.3 KiB
Python
"""Giornale di bordo: scrive la voce del giorno nel DB e in `docs/journal/YYYY-MM-DD.md`.
|
|
|
|
uv run python scripts/live/journal.py # voce di oggi
|
|
uv run python scripts/live/journal.py --giorno 2026-08-21
|
|
uv run python scripts/live/journal.py --backfill 60 # ricostruisce gli ultimi N giorni
|
|
uv run python scripts/live/journal.py --nota "testo" # annota il giorno (operatore)
|
|
|
|
SOLA LETTURA su feed, log e venue: non tocca il libro, non manda ordini.
|
|
Il campo `nota` e' l'UNICO posto per il testo libero, e non viene mai riscritto da un
|
|
ricalcolo automatico.
|
|
"""
|
|
from __future__ import annotations
|
|
|
|
import sys
|
|
from datetime import date, datetime, timedelta, timezone
|
|
from pathlib import Path
|
|
|
|
ROOT = Path(__file__).resolve().parents[2]
|
|
sys.path.insert(0, str(ROOT))
|
|
|
|
from src.live import journal as J # noqa: E402
|
|
from src.live import tradesdb as T # noqa: E402
|
|
|
|
|
|
def _arg(flag: str, default=None):
|
|
a = sys.argv[1:]
|
|
return a[a.index(flag) + 1] if flag in a and a.index(flag) + 1 < len(a) else default
|
|
|
|
|
|
def una(con, g: date, nota: str | None = None, verbose: bool = True) -> Path:
|
|
voce = J.costruisci(con, g)
|
|
J.salva(con, voce, nota=nota)
|
|
f = J.scrivi_file(con, voce)
|
|
if verbose:
|
|
p = voce["pnl"]
|
|
d = p.get("delta_equity")
|
|
print(f" {g} equity {p.get('equity_fine') or float('nan'):,.2f} "
|
|
f"({'n/d' if d is None else f'{d:+.2f}'}) "
|
|
f"fill {p['fill']} · rt {p['roundtrip_chiusi']} · giri {voce['salute']['giri_book']}/24"
|
|
f" -> {f.relative_to(ROOT)}")
|
|
return f
|
|
|
|
|
|
USO = """uso: journal.py [--giorno AAAA-MM-GG] [--backfill N] [--nota "testo"] [--quiet]
|
|
|
|
(nessun flag) scrive la voce di OGGI (pagina marcata PARZIALE: il giorno non e' chiuso)
|
|
--giorno G scrive la voce del giorno G
|
|
--backfill N ricostruisce gli ultimi N giorni, dal piu' vecchio
|
|
--nota "..." annota il giorno (campo dell'operatore, mai riscritto da un ricalcolo)
|
|
--quiet non stampa la riga di riepilogo
|
|
|
|
⚠️ SCRIVE: una riga nel DB e una pagina in docs/journal/. Sola lettura su feed, log e venue."""
|
|
|
|
if __name__ == "__main__":
|
|
from src.live.cli import valida
|
|
valida("journal.py", USO, flag=("--quiet",), con_valore=("--giorno", "--backfill", "--nota"))
|
|
# sincronizzare PRIMA: altrimenti la sezione 'Libro' (letta dal log) e la sezione 'P&L'
|
|
# (letta dal DB) descrivono due istanti diversi e la pagina si contraddice da sola.
|
|
sys.path.insert(0, str(ROOT / "scripts" / "live"))
|
|
from trades_db import sync as _sync
|
|
_sync(verbose=False)
|
|
|
|
con = T.connect()
|
|
nota = _arg("--nota")
|
|
if (n := _arg("--backfill")):
|
|
oggi = datetime.now(timezone.utc).date()
|
|
for i in range(int(n), -1, -1):
|
|
g = oggi - timedelta(days=i)
|
|
v = J.costruisci(con, g)
|
|
# un giorno senza giri di book non e' una voce: e' assenza di dato
|
|
if v["salute"]["giri_book"] == 0:
|
|
continue
|
|
J.salva(con, v); J.scrivi_file(con, v)
|
|
tot = con.execute("SELECT COUNT(*) c FROM journal").fetchone()["c"]
|
|
print(f" voci nel giornale: {tot}")
|
|
else:
|
|
g = date.fromisoformat(_arg("--giorno", datetime.now(timezone.utc).date().isoformat()))
|
|
una(con, g, nota=nota, verbose="--quiet" not in sys.argv[1:])
|
|
con.close()
|