revisione 02/09: il rotolante si CONTROLLA ogni ora (non "si ri-ancora"), TWR con limiti dichiarati e tre stati
Quattro segnalazioni della revisione sui commit di oggi, tutte verificate e riparate. 1. book_execute.py (+ CLAUDE.md §5.7, memoria 40): «il disaster-SL rotolante si ri-ancora ogni ora» era falso — ensure_disaster_sl lascia il bracket finche' lo stop e' entro il 5% e la taglia entro il 10%; il giro orario CONTROLLA, ri-ancora oltre la tolleranza (mark +5,263%/-4,762%). Lo stop siede fra -26,3% e -33,3% dal mark corrente. 2. journal.rendimento_twr: limite dichiarato (D5) — l'intervallo che contiene un movimento certo esce intero dal rendimento, il suo P&L di mercato va in `certi`; errore massimo meta' del movimento per costruzione (25/08: ~$0,5). Non si stima (P12). Segmenti a lunghezza zero non prodotti; nessun tempo a mercato -> 0,0 dichiarato numero. 3. base di equity zero: `twr` E `trading` None con motivo (il salto 0->X e' invisibile al classificatore, `trading` valeva l'intero conto); il report stampa n/d. 4. test_book_cadenza: la guardia estrae ogni prescrizione «ogni/every N unita'» e pretende 60 minuti, con controllo positivo (M15); limite P13 dichiarato. Test +5 (847 verdi). Diari 02/09 e 02/09b con la sezione "Revisione". Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RziUCB336YPUUyDJ29x4Ke
This commit is contained in:
+22
-9
@@ -191,7 +191,19 @@ def rendimento_twr(con, fino_ts: str) -> dict:
|
||||
apre uno all'equity DOPO; il TWR e' il prodotto dei rendimenti di segmento, meno uno. Gli
|
||||
eventi `ambiguo` NON spezzano niente (P12: restano nel rendimento, dichiarati accanto).
|
||||
|
||||
TRE STATI: `twr` e' un numero, oppure None con `motivo` (serie vuota, base zero).
|
||||
⚠️ LIMITE DICHIARATO (D5). L'intervallo che CONTIENE un movimento certo esce INTERO dal
|
||||
rendimento: il suo P&L di mercato (marcatura delle posizioni aperte, funding; in un buco di
|
||||
lettura — fino a 10h nella serie vera — l'intero buco) finisce in `certi`, quindi anche fuori
|
||||
da `trading`. E' limitato per costruzione dal margine del classificatore (|salto| >
|
||||
2·max_mkt·leva·equity), percio' l'errore massimo vale max_mkt·leva·equity: fino a META' del
|
||||
movimento riconosciuto. Il 25/08: libro a ~$263 lordi, mercato a ±0,2% -> ~$0,5 su $1.399,39.
|
||||
Non si stima e non si corregge (P12): si dichiara. Un intervallo di sola marcatura fra due
|
||||
movimenti consecutivi, o prima del primo, ha lunghezza zero e NON produce un segmento.
|
||||
|
||||
TRE STATI: `twr` e `trading` sono numeri, oppure None con `motivo`. Base di equity zero =>
|
||||
entrambi None: il salto 0 -> X del primo versamento e' INVISIBILE a `movimenti_capitale`
|
||||
(una base zero non ha percentuale), quindi `certi` lo perderebbe e `trading` varrebbe
|
||||
l'intero conto — un numero etichettato "al netto dei versamenti" che li contiene tutti.
|
||||
"""
|
||||
rows = con.execute("SELECT ts_utc, equity FROM equity WHERE ts_utc <= ? ORDER BY ts_utc",
|
||||
(fino_ts,)).fetchall()
|
||||
@@ -199,23 +211,24 @@ def rendimento_twr(con, fino_ts: str) -> dict:
|
||||
return dict(twr=None, motivo="nessuna lettura di equity", segmenti=[], eventi=[],
|
||||
certi=0.0, ambigui=0.0, delta_equity=None, trading=None, letture=0)
|
||||
mv = movimenti_capitale(con, fino_ts)
|
||||
certi = [e for e in mv["eventi"] if e["classe"] == "movimento"]
|
||||
e0, e1 = float(rows[0]["equity"]), float(rows[-1]["equity"])
|
||||
if e0 <= 0:
|
||||
return dict(twr=None, trading=None,
|
||||
motivo="base di equity nulla: il primo versamento non e' classificabile",
|
||||
segmenti=[], eventi=mv["eventi"], certi=mv["certi"], ambigui=mv["ambigui"],
|
||||
delta_equity=e1 - e0, letture=len(rows))
|
||||
certi = [e for e in mv["eventi"] if e["classe"] == "movimento"]
|
||||
segmenti, da_ts, da_eq = [], rows[0]["ts_utc"], e0
|
||||
for ev in certi: # gia' in ordine di tempo
|
||||
if da_eq:
|
||||
if da_eq and ev["ts_prima"] != da_ts: # lunghezza zero = niente segmento
|
||||
segmenti.append(dict(da=da_ts, a=ev["ts_prima"], e_da=da_eq, e_a=ev["prima"],
|
||||
ret=ev["prima"] / da_eq - 1.0))
|
||||
da_ts, da_eq = ev["ts_dopo"], ev["dopo"]
|
||||
if da_eq:
|
||||
if da_eq and rows[-1]["ts_utc"] != da_ts:
|
||||
segmenti.append(dict(da=da_ts, a=rows[-1]["ts_utc"], e_da=da_eq, e_a=e1,
|
||||
ret=e1 / da_eq - 1.0))
|
||||
if not segmenti or e0 <= 0:
|
||||
return dict(twr=None, motivo="base di equity nulla", segmenti=segmenti, eventi=mv["eventi"],
|
||||
certi=mv["certi"], ambigui=mv["ambigui"], delta_equity=e1 - e0,
|
||||
trading=e1 - e0 - mv["certi"], letture=len(rows))
|
||||
twr = 1.0
|
||||
for sg in segmenti:
|
||||
for sg in segmenti: # nessun segmento = nessun tempo a mercato = 0
|
||||
twr *= 1.0 + sg["ret"]
|
||||
return dict(twr=twr - 1.0, motivo=None, segmenti=segmenti, eventi=mv["eventi"],
|
||||
certi=mv["certi"], ambigui=mv["ambigui"], delta_equity=e1 - e0,
|
||||
|
||||
Reference in New Issue
Block a user