diff --git a/index.html b/index.html
index 7edf68c..05978e3 100644
--- a/index.html
+++ b/index.html
@@ -405,6 +405,8 @@ footer{margin-top:34px;padding-top:22px;border-top:1px solid var(--border);color
+ Agents to include
+
Send a digest whenever agents open, close, stop out, or take gains during a cycle.
@@ -737,7 +739,7 @@ footer{margin-top:34px;padding-top:22px;border-top:1px solid var(--border);color
@@ -1156,10 +1158,24 @@ const EMAIL_ALERT_TYPES=[
{id:"GAIN",label:"Gain stops"},
];
function defaultEmailAlerts(){
- return {enabled:false,email:"",events:{OPEN:true,CLOSE:true,EXIT:true,STOP:true,GAIN:true},last_sent_at:null,last_error:null};
+ return {
+ enabled:false,
+ email:"",
+ events:{OPEN:true,CLOSE:true,EXIT:true,STOP:true,GAIN:true},
+ agents:Object.fromEntries(AGENTS.map(a=>[a.id,true])),
+ last_sent_at:null,
+ last_error:null,
+ };
}
function loadEmailAlerts(){
- try{return Object.assign(defaultEmailAlerts(),JSON.parse(localStorage.getItem(EMAIL_ALERT_KEY)||"{}"));}
+ try{
+ const base=defaultEmailAlerts();
+ const saved=JSON.parse(localStorage.getItem(EMAIL_ALERT_KEY)||"{}");
+ const merged=Object.assign(base,saved||{});
+ merged.events=Object.assign(base.events,(saved&&saved.events)||{});
+ merged.agents=Object.assign(base.agents,(saved&&saved.agents)||{});
+ return merged;
+ }
catch(e){return defaultEmailAlerts();}
}
function saveEmailAlerts(cfg){
@@ -1167,6 +1183,7 @@ function saveEmailAlerts(cfg){
const merged=Object.assign(base,cfg||{});
merged.email=String(merged.email||"").trim();
merged.events=Object.assign(base.events,(cfg&&cfg.events)||{});
+ merged.agents=Object.assign(base.agents,(cfg&&cfg.agents)||{});
merged.enabled=Boolean(merged.enabled&&validEmail(merged.email));
localStorage.setItem(EMAIL_ALERT_KEY,JSON.stringify(merged));
return merged;
@@ -1181,7 +1198,9 @@ function collectNewAgentEvents(st,offsets){
const cfg=loadEmailAlerts();
if(!cfg.enabled||!validEmail(cfg.email))return [];
const enabled=cfg.events||{};
+ const selected=cfg.agents||{};
return AGENTS.flatMap(a=>{
+ if(!selected[a.id])return [];
const p=st.agents[a.id]||defaultPortfolio();
const start=Math.max(0,offsets[a.id]||0);
return (p.history||[]).slice(start).filter(h=>enabled[h.action]).map(h=>({
@@ -1941,51 +1960,62 @@ function renderTopPicks(){
${Math.round(s.conviction)}
conviction
`).join("");
}
function renderEmailAlerts(){
- const input=$("emailAlertInput"),eventsRoot=$("emailAlertEvents"),meta=$("emailAlertMeta"),status=$("emailAlertStatus");
- if(!input||!eventsRoot)return;
+ const input=$("emailAlertInput"),eventsRoot=$("emailAlertEvents"),agentsRoot=$("emailAlertAgents"),meta=$("emailAlertMeta"),status=$("emailAlertStatus");
+ if(!input||!eventsRoot||!agentsRoot)return;
const cfg=loadEmailAlerts();
input.value=cfg.email||"";
- meta.textContent=cfg.enabled?`on for ${cfg.email}`:"off";
+ const selectedCount=AGENTS.filter(a=>cfg.agents&&cfg.agents[a.id]).length;
+ meta.textContent=cfg.enabled?`on for ${cfg.email} · ${selectedCount}/${AGENTS.length} agents`:"off";
eventsRoot.innerHTML=EMAIL_ALERT_TYPES.map(t=>`
`).join("");
+ agentsRoot.innerHTML=AGENTS.map(a=>`
+ `).join("");
status.textContent=cfg.last_error
? `Last error: ${cfg.last_error}`
- : (cfg.last_sent_at?`Last sent ${new Date(cfg.last_sent_at).toLocaleString()}.`:"Send a digest whenever agents open, close, stop out, or take gains during a cycle.");
- $("saveEmailAlertsBtn").onclick=()=>{
+ : (cfg.last_sent_at?`Last sent ${new Date(cfg.last_sent_at).toLocaleString()}.`:"Send a digest whenever selected agents open, close, stop out, or take gains during a cycle.");
+ const readAlertForm=()=>{
const email=input.value.trim();
const events={};
+ const agents={};
document.querySelectorAll("[data-email-event]").forEach(el=>{events[el.dataset.emailEvent]=el.checked;});
- const saved=saveEmailAlerts({enabled:validEmail(email),email,events,last_error:validEmail(email)?null:"Enter a valid email address."});
- toast(saved.enabled?"Trade email alerts saved.":"Enter a valid email to turn alerts on.");
+ document.querySelectorAll("[data-email-agent]").forEach(el=>{agents[el.dataset.emailAgent]=el.checked;});
+ return {email,events,agents};
+ };
+ const hasSelectedAgent=(agents)=>Object.values(agents||{}).some(Boolean);
+ $("saveEmailAlertsBtn").onclick=()=>{
+ const form=readAlertForm();
+ const anyAgent=hasSelectedAgent(form.agents);
+ const saved=saveEmailAlerts({enabled:validEmail(form.email)&&anyAgent,email:form.email,events:form.events,agents:form.agents,last_error:validEmail(form.email)?(anyAgent?null:"Select at least one agent."):"Enter a valid email address."});
+ toast(saved.enabled?"Trade email alerts saved.":(anyAgent?"Enter a valid email to turn alerts on.":"Select at least one agent."));
renderEmailAlerts();pushCloudState(true);
};
$("testEmailAlertsBtn").onclick=async()=>{
- const email=input.value.trim();
- const events={};
- document.querySelectorAll("[data-email-event]").forEach(el=>{events[el.dataset.emailEvent]=el.checked;});
- const saved=saveEmailAlerts({enabled:validEmail(email),email,events,last_error:null});
- if(!saved.enabled){toast("Enter a valid email first.");renderEmailAlerts();return;}
+ const form=readAlertForm();
+ const anyAgent=hasSelectedAgent(form.agents);
+ const saved=saveEmailAlerts({enabled:validEmail(form.email)&&anyAgent,email:form.email,events:form.events,agents:form.agents,last_error:anyAgent?null:"Select at least one agent."});
+ if(!saved.enabled){toast(anyAgent?"Enter a valid email first.":"Select at least one agent.");renderEmailAlerts();return;}
+ const testAgent=AGENTS.find(a=>saved.agents&&saved.agents[a.id])||AGENTS[0];
await notifyTradeDigest([{
- agent_id:"test",
- agent_name:"Test Agent",
- agent_emoji:"✉️",
+ agent_id:testAgent.id,
+ agent_name:testAgent.name,
+ agent_emoji:testAgent.emoji,
action:"OPEN",
date:todayStr(),
question:"Test alert from Poly Arena",
side:"YES",
- detail:"This confirms trade email alerts are connected.",
+ detail:`This confirms trade email alerts are connected for ${testAgent.name}.`,
equity:STARTING_BALANCE,
return_pct:0,
}],{test:true});
pushCloudState(true);
};
- document.querySelectorAll("[data-email-event]").forEach(el=>el.onchange=()=>{
- const email=input.value.trim();
- const events={};
- document.querySelectorAll("[data-email-event]").forEach(box=>{events[box.dataset.emailEvent]=box.checked;});
- saveEmailAlerts({enabled:validEmail(email),email,events,last_error:null});
+ document.querySelectorAll("[data-email-event],[data-email-agent]").forEach(el=>el.onchange=()=>{
+ const form=readAlertForm();
+ saveEmailAlerts({enabled:validEmail(form.email)&&hasSelectedAgent(form.agents),email:form.email,events:form.events,agents:form.agents,last_error:null});
renderEmailAlerts();pushCloudState(true);
});
}