Files
Encelado/Encelado/docs/LEDGER_SCHEMA.md
T
Alby96andClaude Fable 5.1 9f040ade76 5.0 Fase 5: notifiche e comandi Telegram
Il bot riferisce al telefono: stato ogni ora, riepilogo giornaliero ed eventi
(avvio e arresto, basket aperti e chiusi, gambe in attesa, ordini risolti,
orfane, kill-switch, equity stop, perdita giornaliera, margin guard, recupero,
reset, preset, API in errore, scarto orologio) e accetta comandi dalla sola
chat autorizzata (/stato, /posizioni, /storico, /pausa, /riprendi, /chiudi,
/kill CONFERMO, /reset). Il canale è solo HttpClient: coda non bloccante, un
messaggio al secondo, retry con backoff e retry_after, long polling da un solo
task; il token vive nell'ambiente. Ogni comando eseguito, da qualunque origine,
è una riga «comando» nel ledger. Test (s)-(u).

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-23 11:23:18 +02:00

12 KiB
Raw Blame History

Schema del ledger e delle tabelle

Regole comuni: UTC ovunque, CultureInfo.InvariantCulture per numeri e date, CSV con separatore ; e ultima colonna motivazione, JSONL append-only. Nessuna riga viene mai modificata: le correzioni sono righe nuove con evento = correzione. Ogni riga porta run_id e, dove ha senso, config_hash (SHA-256 abbreviato di strategy.json canonicalizzato).

data/ledger/decisions.jsonl

Una riga per ogni valutazione di ogni basket alla chiusura di ogni barra M15 (ingresso, skip, aggiunta, posizione, uscita) più le uscite decise su una quotazione intermedia e gli esiti di esecuzione. Le feature sono quelle disponibili al momento della decisione: è la regola anti look-ahead, e il dataset di addestramento è questo file, non una ricostruzione.

Campo Tipo Significato
ts ISO 8601 UTC istante della valutazione
run_id testo yyyyMMdd-HHmmss-xxxxxx della sessione del bot
config_hash testo hash di strategy.json in vigore
basket testo A/B, es. EURUSD/USDCHF
basket_id testo id del basket aperto (B<yyyyMMddHHmmss>-<AB>), vuoto se piatto; collega a baskets.csv
cross testo cross sintetico (EURCHF)
mode (Paper Demo Live; i file scritti prima del 2026-09-16 pomeriggio portano i nomi precedenti DemoApprove/DemoAuto)
preset testo CONSERVATIVE, MODERATE, AGGRESSIVE
evento testo skip, segnale_ingresso, ingresso, rifiuto, leg_risk_unwind, posizione, segnale_aggiunta, aggiunta, segnale_uscita, uscita, correzione; dalla 5.0 anche le righe di evento (senza feature, solo ts, run_id, evento, basket_id, campi propri e motivazione): pending (gamba senza esito, con leg, client_ref, order_id), pending_risolto (con esito, fonte, position_id), orfana_adottata e orfana_chiusa (con position_id, strumento, pnl, exit_reason), movimento_di_cassa (con importo, saldo_prima, saldo_dopo, chiusure_nel_frattempo, cassa_cumulata), margin_guard (con equity, margine_usato), kill_switch_avviato, kill_switch_concluso (con stato = Halted o Halted-Residuo, chiuse, residuo, annullati, pnl), residuo_chiuso, reset_rifiutato, reset_concluso, recupero_avviato (con inattivita_min, barre), recupero_concluso (con inattivita_min, barre, chiusi, tenuti), comando (ogni comando dalla finestra, dalla console o da Telegram: comando, argomento, ok; la motivazione porta l'origine e la prima riga dell'esito)
decision testo Skip, Enter, Add, Exit, Hold
buy_cross bool verso deciso (compra il cross = compra entrambe le gambe nei cinque basket)
z, z_in_eff numero z-score del cross e soglia effettiva (scalata dalla vol prevista)
D_pips numero divergenza in pip dall'ancora (solo PipDivergence)
rho_W, rho_20 numero correlazione rolling dei rendimenti su window e windowShort
halfLife numero emivita OLS in barre (null se λ ≥ 0)
atrA, atrB numero ATR(14) in pip
sigmaX, ewmaVolX numero deviazione standard del livello del cross sulla finestra; vol EWMA dei rendimenti del cross
sigmaForecast, sigmaAverage30d numero vol prevista 1-4 h e media 30 g (null finché il livello 8.5 non è attivo)
costPips, breakEvenWinRate numero costo stimato in pip-equivalenti di A; win rate di pareggio
spreadA, spreadB, markupA, markupB numero spread correnti in pip; markup dell'API in pip
hourSin, hourCos, dow numero ora sul cerchio; giorno della settimana (0 = domenica)
minutesToNextHigh, minutesSinceLastHigh, surpriseLast numero/null calendario per le valute del basket
netSentDiff_1h/4h/24h, hawkishDiff, riskOff, newsCount numero sentiment (valuta lunga valuta corta del cross)
regimeTrend numero forza di trend (ADX-like) del cross
lastNOutcomes numero media degli ultimi esiti (null finché non c'è storia)
p_ML, mlActive numero, bool probabilità del meta-modello e se è gate o ombra
equity, openBaskets numero equity e basket aperti al momento
priceA, priceB, pipsOpen, pnlOpenUsd, barsHeld numero stato della posizione (se aperta)
unitsA, unitsB, notionalUsd, lossAtStopUsd, effectiveLeverage, marginUsd numero sizing (solo su Enter); marginUsd = margine previsto delle due gambe (5.0)
sizing_bound testo quale vincolo ha deciso la size (5.0): risk, margin, leverage, units
reasonCodes array codici: no_signal, rho_low, rho_short_low, half_life, blackout_before, blackout_after, weekend, just_opened, session, max_baskets, same_cross, ml_gate, cost_gate, sizing, kill_switch, equity_stop, daily_loss, entries_blocked, data_quality, warmup, not_bar_close, enter, add, hold, tp_pips, tp_z, stop_z, stop_max_loss, spread_anomaly, time_stop, rho_break; dalla 5.0 margin (nessun margine per un nuovo basket), margin_guard (equity / margine usato sotto la soglia), min_exposure (la size a margine non raggiunge l'esposizione minima)
motivazione testo la frase, in italiano, con i numeri

data/ledger/baskets.csv

Una riga per basket chiuso. label = 1 se pnl_net_usd > 0, altrimenti 0: è l'etichetta dei livelli 1-3.

basket_id;run_id;basket;mode;preset;opened_utc;closed_utc;buy_cross;entry_z;exit_z;pnl_gross_usd;pnl_net_usd;pips_gross;cost_pips;cost_usd;slippage_pips;adds;bars_held;exit_reason;equity_at_entry;p_ml_at_entry;label;durata_min;motivazione

pips_gross è la somma dei pip delle due gambe ai prezzi di esecuzione (la colonna "Pips" della UI), cost_pips il costo stimato all'ingresso, slippage_pips la differenza fra quotazione vista e prezzo eseguito sommata sulle gambe, exit_reason uno dei codici sopra più manual, closed_by_broker, leg_closed_by_broker, end_of_data, e dalla 5.0 leg_risk_unwind (gamba A eseguita in ritardo e richiusa, o B non coperta dal margine), margin_guard (chiuso dalla guardia del margine), orphan_closed (gamba orfana del bot adottata e chiusa alla riconciliazione), bonifica_orfana (chiusa dalla bonifica con conferma), kill_switch/equity_stop anche per le gambe singole. Le righe di una gamba singola hanno entry_z, exit_z, pips_gross e cost_* vuoti e buy_cross = verso della gamba.

data/ledger/orders.jsonl (dalla 5.0)

Una riga per ogni ordine inviato e per ogni cambio del suo stato (append-only): la prima riga di un client_ref dice cosa è stato chiesto, l'ultima come è finita. Scritta dal registro degli ordini (OrderTracker) attraverso il ledger.

Campo Significato
ts, run_id, mode come in decisions.jsonl
basket, basket_id slot (EURUSD/USDCHF) e istanza (B2026…-EURUSDUSDCHF)
strumento, instrument_id, verso la gamba; verso = long/short dell'ordine (per una chiusura è il verso opposto alla posizione)
leg A, B, Add, Close, Unwind
unita_richieste, unita_eseguite differiscono quando il server riduce l'ordine (osservato il 2026-09-16)
prezzo_richiesto, prezzo_eseguito, slippage_pip quotazione vista all'invio, prezzo del server, differenza in pip con il segno del costo
stato, stato_id l'ultima parola del server (Submitted, Received, Placed, Filled, Rejected, …, Unknown quando non ha risposto), con l'id numerico di eToro
esito Pending, Filled, Rejected, Cancelled
order_id, position_id, client_ref le tre chiavi
fee commissioni riportate dal server all'esecuzione
evento inviato, stato, risolto
motivazione la motivazione della decisione o l'errore del server

data/state/pending_orders.json (dalla 5.0)

Il registro degli ordini: savedUtc e l'array orders con gli stessi campi di orders.jsonl più checks, lastCheckUtc, source (venue, lookup, lookup-v1, positions). Contiene tutti gli ordini senza esito e quelli risolti nelle ultime 48 ore (servono a riconoscere una posizione come propria). Scritto prima di ogni chiamata HTTP e a ogni cambio di stato, con .tmp + File.Move. Un file illeggibile viene messo da parte come pending_orders.json.illeggibile-<data>. In modalità Paper il file è pending_orders_paper.json.

data/state/baskets_state.json (campi aggiunti dalla 5.0)

peakNetEquity (picco dell'equity al netto dei movimenti di cassa), cumulativeCashFlow, lastBalance e lastBalanceUtc (per riconoscere un deposito avvenuto a bot spento), pendingEntries (un elemento per basket in PendingA/PendingB: name, state, basketId e il piano pending con unità, TP, stop, riferimenti cliente e la gamba A eseguita), haltResidue (le posizioni del bot rimaste sul conto dopo un kill-switch: positionId, symbol, isBuy, units, openedUtc, origin, basket, reason). peakEquity resta per compatibilità e vale peakNetEquity + cumulativeCashFlow.

data/state/heartbeat.json e data/state/instance.lock (dalla 5.0)

heartbeat.json: {utc, run_id, mode, openBaskets, pendingBaskets, pid, note} scritto ogni recovery.heartbeatSeconds (30), all'avvio (note = avvio) e all'arresto (arresto), con .tmp + File.Move. Il tempo trascorso dall'ultimo utc è l'inattività che fa scattare il recupero. instance.lock: {pid, runId, sinceUtc, machine}, tenuto aperto in esclusiva dal motore per tutta la sessione; non va cancellato a mano.

reports/recupero_<run_id>.csv (dalla 5.0)

Una riga per posizione trovata dal recupero: posizione;basket;decisione;motivo;z;rho;barsHeld;pnl;motivazione, con decisione ∈ {chiudi, tieni, rapporto} e motivo = codice di uscita del decisore (stop_z, stop_max_loss, time_stop, rho_break, spread_anomaly…), entro le soglie, orfana_bot, esterna.

reports/bonifica_YYYYMMDD.csv (dalla 5.0)

Una riga per orfana chiusa dalla bonifica: ts;position_id;strumento;verso;unita;aperta_utc;pnl_realizzato;basket;motivazione.

results/trials.csv

Una riga per configurazione provata nel backtest; N del Sharpe deflazionato = numero di righe.

trial_id;preset;signalMode;exitMode;averaging;lot_multiplier;z_in;z_out;z_stop;TP;W;rho_min;cost_multiple;basket_stop;n_baskets;win_rate;pnl_net;sharpe;maxdd;break_even_cost;avg_cost_pips;p1_pnl;p5_pnl;psr;dsr;motivazione

break_even_cost = media per basket di (pip eseguiti + costo stimato), cioè i pip "mid-to-mid" catturati: il costo di giro che azzera il risultato. p1_pnl, p5_pnl = percentili 1 % e 5 % del P&L per basket (la coda che il win rate nasconde).

reports/falsificazione.csv

test;variante;n_baskets;win_rate;pnl_net;sharpe;maxdd;p1_pnl;p5_pnl;break_even_cost;avg_cost_pips;psr;dsr;motivazione

knowledge/calibration.csv

Win rate e P&L netto medio per bucket: dimensione;bucket;n;win_rate;pnl_medio;pnl_totale;motivazione, con dimensioni |z|, rho_W, ora, giorno, minuti_evento, sentiment, preset, basket.

knowledge/preregistrazione.csv

Una riga per forward test: data;config_hash;modalita;durata_minima;n_minimo_basket;sharpe_atteso;win_rate_atteso;dd_stop;stop_basket_consecutivi;esito;motivazione.

knowledge/proposals.csv

data;origine;parametro;valore_attuale;valore_proposto;evidenza;stato;motivazione — le proposte del ciclo settimanale; stato ∈ {proposta, in forward, accettata, respinta}. Nessuna proposta cambia i parametri live da sola.

knowledge/models_registry.csv, knowledge/forward_registry.csv

versione;data;tipo;n_train;auc_wf;brier;logloss;stato;motivazione (stato ∈ shadow, challenger, champion, ritirato) e data;config_hash;modalita;basket;pnl_net;sharpe;dd;stato;motivazione.