fix(dashboard): unrealized usa entry REALE (non sim) per coerenza col mark reale

Le posizioni eseguite mostravano l'entry SIM (feed decisione testnet inverse,
dislocato ~1.3% dal lineare USDC) confrontato col mark REALE -> unrealized gonfiato
(SH01_ETH -1.36% invece di ~-0.25%) e due trade ETH con lo stesso entry sim 1661.95.
Ora entry = real_entry_price/real_entry_a se eseguito; unrealized vs mark reale su
base coerente. Indicatore '⚠sim' quando il feed di decisione diverge dal reale.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Adriano Dal Pastro
2026-06-13 22:13:48 +00:00
parent 183209dbd4
commit d5a83075f8
+14 -3
View File
@@ -211,13 +211,22 @@ def build_state() -> dict:
if st.get("in_position") and not paper_only:
is_pair = "entry_a" in st
asset = wid.split("__")[1]
entry = st.get("entry_price") or st.get("entry_a") or 0.0
# entry REALE se eseguito (il mark live è il prezzo reale USDC: confrontare
# con l'entry SIM mischierebbe le basi — il feed di decisione testnet inverse
# è dislocato dal lineare, vedi xex_divergence_research). Fallback al sim.
executed = st.get("real_in_position")
if is_pair:
real_e, sim_e = (st.get("real_entry_a") if executed else None), st.get("entry_a") or 0.0
else:
real_e, sim_e = (st.get("real_entry_price") if executed else None), st.get("entry_price") or 0.0
entry = real_e or sim_e
if not is_pair:
open_assets.add(asset)
active.append({
"id": _short(wid), "family": _family_of(wid),
"dir": "LONG" if st.get("direction", 0) > 0 else "SHORT",
"entry": entry, "bars": st.get("bars_held", 0),
"entry": round(entry, 4), "sim_entry": round(sim_e, 4),
"bars": st.get("bars_held", 0),
"max_bars": st.get("max_bars", 0),
"tp": st.get("tp", 0.0), "sl": st.get("sl", 0.0),
"age_min": round(_age_min(sp), 1),
@@ -588,8 +597,10 @@ function renderActive(a){const wrap=document.getElementById('active');wrap.inner
a.forEach(p=>{const tr=E('tr');
const side=`<span class="pill ${p.dir=='LONG'?'long':'short'}">${p.dir}</span>`;
const ue=p.unreal_eur!=null?`<span class="${cls(p.unreal_eur)}">${eur(p.unreal_eur)} (${p.unreal_pct}%)</span>`:(p.pair?'<span class=mut>pairs (z)</span>':'<span class=mut>—</span>');
const gap=p.sim_entry&&Math.abs(p.sim_entry-p.entry)>0.01;
const ecell=gap?`<td title="entry reale ${p.entry} · feed sim/decisione ${p.sim_entry} (testnet inverse dislocato)">${p.entry} <span class=stale style="font-size:10px">⚠sim ${p.sim_entry}</span></td>`:`<td>${p.entry}</td>`;
tr.innerHTML=`<td>${p.id}${p.real?'':' <span class=tag>sim</span>'}</td><td>${side}</td>
<td>${p.entry}</td><td>${p.mark||''}</td><td>${ue}</td>
${ecell}<td>${p.mark||''}</td><td>${ue}</td>
<td>${p.bars}/${p.max_bars||''}</td><td class=mut>${p.to_tp_pct!=null?p.to_tp_pct:''}</td>
<td class="${p.stale?'stale':'mut'}">${p.age_min}m${p.stale?'':''}</td>`;
t.append(tr);});wrap.append(t);}