diff --git a/index.html b/index.html index add6605..d01c085 100644 --- a/index.html +++ b/index.html @@ -425,7 +425,7 @@ footer{margin-top:34px;padding-top:22px;border-top:1px solid var(--border);color
-

Hourly Agent Reports

+

Daily Agent Performance Reports

@@ -2008,6 +2008,37 @@ function recentActionSummary(p){ if(counts.OPEN)bits.push(`${counts.OPEN} new entr${counts.OPEN===1?"y":"ies"}`); return bits.length?bits.join(", "):"no major recent trade actions"; } +function snapshotNearDayAgo(snaps,lastTime){ + const cutoff=lastTime-86400000; + const before=snaps.filter(s=>snapTime(s)<=cutoff).pop(); + if(before)return before; + return snaps.length>1?snaps[0]:null; +} +function dailyActionSummary(p,lastTime){ + const cutoff=lastTime-86400000; + const counts={STOP:0,GAIN:0,EXIT:0,CLOSE:0,OPEN:0}; + (p.history||[]).forEach(h=>{ + const t=h.date?new Date(`${h.date}T12:00:00`).getTime():NaN; + if(Number.isFinite(t)&&t>=cutoff&&counts[h.action]!==undefined)counts[h.action]++; + }); + const bits=[]; + if(counts.OPEN)bits.push(`${counts.OPEN} opened`); + if(counts.GAIN)bits.push(`${counts.GAIN} gain-stop sale${counts.GAIN===1?"":"s"}`); + if(counts.STOP)bits.push(`${counts.STOP} stop-loss sale${counts.STOP===1?"":"s"}`); + if(counts.EXIT||counts.CLOSE)bits.push(`${counts.EXIT+counts.CLOSE} exit${counts.EXIT+counts.CLOSE===1?"":"s"}`); + return bits.length?bits.join(", "):recentActionSummary(p); +} +function recentClosedAttribution(p,lastTime){ + const cutoff=lastTime-86400000; + return (p.closed||[]).filter(pos=>{ + const t=pos.closed_at?new Date(pos.closed_at).getTime():NaN; + return Number.isFinite(t)&&t>=cutoff; + }).sort((a,b)=>Math.abs(b.realized_pnl||0)-Math.abs(a.realized_pnl||0)); +} +function shortQuestion(q,len=48){ + q=String(q||""); + return `${q.slice(0,len)}${q.length>len?"...":""}`; +} function reportPositionLine(p){ if(!p.positions.length)return "No open positions yet, so this hour's focus is finding entries that fit the strategy."; const best=[...p.positions].sort((a,b)=>(b.unrealized_pnl||0)-(a.unrealized_pnl||0))[0]; @@ -2017,17 +2048,37 @@ function reportPositionLine(p){ } function dailyPerformanceExplanation(row){ const snaps=(row.p.snapshots||[]).slice().sort((a,b)=>snapTime(a)-snapTime(b)); - const last=snaps[snaps.length-1],prev=snaps[snaps.length-2]; - const delta=last&&prev?(last.return_pct||0)-(prev.return_pct||0):0; + const last=snaps[snaps.length-1]; + if(!last)return "Why today is unclear: the agent needs at least one return snapshot before it can explain performance."; + const lastTime=snapTime(last); + const prev=snapshotNearDayAgo(snaps,lastTime); + if(!prev)return "Why today is still forming: there is not enough 24-hour history yet, so the report is waiting for more snapshots."; + const delta=(last.return_pct||0)-(prev.return_pct||0); + const equityDelta=(last.equity||0)-(prev.equity||0); const open=row.p.positions||[]; const best=open.slice().sort((a,b)=>(b.unrealized_pnl||0)-(a.unrealized_pnl||0))[0]; const worst=open.slice().sort((a,b)=>(a.unrealized_pnl||0)-(b.unrealized_pnl||0))[0]; + const recentClosed=recentClosedAttribution(row.p,lastTime); + const mostImportantClose=recentClosed[0]; + const realizedToday=recentClosed.reduce((s,p)=>s+Number(p.realized_pnl||0),0); const m=agentMomentumStats(row.p); const macdText=`MACD ${m.macd>=0?"+":""}${m.macd.toFixed(2)}, momentum ${m.recent>=0?"+":""}${m.recent.toFixed(2)} pts`; - const actions=recentActionSummary(row.p); - if(delta>0.25)return `Why it went up: return improved ${delta.toFixed(2)} points. ${best?`The biggest open help was '${best.question.slice(0,45)}' at ${fmtUSD(best.unrealized_pnl||0)}.`:"Cash discipline and favorable marks helped."} Technicals: ${macdText}. Recent actions: ${actions}.`; - if(delta<-0.25)return `Why it went down: return fell ${Math.abs(delta).toFixed(2)} points. ${worst?`The biggest drag was '${worst.question.slice(0,45)}' at ${fmtUSD(worst.unrealized_pnl||0)}.`:"Weak marks or low-conviction exposure hurt."} Technicals: ${macdText}. Recent actions: ${actions}.`; - return `Why it is steady: return moved only ${delta.toFixed(2)} points. Technicals are mixed (${macdText}), and recent actions were ${actions}.`; + const actions=dailyActionSummary(row.p,lastTime); + const closedText=mostImportantClose + ? `The largest realized driver was '${shortQuestion(mostImportantClose.question)}' at ${fmtUSD(mostImportantClose.realized_pnl||0)}; total realized P&L over the past day was ${fmtUSD(realizedToday)}.` + : "There were no major realized closes in the past day."; + if(delta>0.25){ + const openText=best?`The strongest open position helping it is '${shortQuestion(best.question)}' at ${best.unrealized_pnl>=0?"+":""}${fmtUSD(best.unrealized_pnl||0)}.`:"It benefited mostly from cash discipline and closed-trade results rather than a single open winner."; + return `Past 24h: up ${delta.toFixed(2)} return points (${fmtUSD(equityDelta)}). ${openText} ${closedText} Trade behavior: ${actions}. Technical pressure: ${macdText}.`; + } + if(delta<-0.25){ + const openText=worst?`The biggest open drag is '${shortQuestion(worst.question)}' at ${fmtUSD(worst.unrealized_pnl||0)}.`:"The decline came more from broad mark-downs or realized losses than one obvious open position."; + return `Past 24h: down ${Math.abs(delta).toFixed(2)} return points (${fmtUSD(equityDelta)}). ${openText} ${closedText} Trade behavior: ${actions}. Technical pressure: ${macdText}.`; + } + const openText=best&&worst&&best!==worst + ? `Best open mark is '${shortQuestion(best.question,36)}' (${best.unrealized_pnl>=0?"+":""}${fmtUSD(best.unrealized_pnl||0)}) while the weakest is '${shortQuestion(worst.question,36)}' (${fmtUSD(worst.unrealized_pnl||0)}).` + : "Open positions mostly offset each other or the agent is carrying limited exposure."; + return `Past 24h: nearly flat at ${delta>=0?"+":""}${delta.toFixed(2)} return points (${fmtUSD(equityDelta)}). ${openText} ${closedText} Trade behavior: ${actions}. Technical pressure: ${macdText}.`; } function renderAgentReports(){ const root=$("agentReports"); if(!root)return;