=0?\"good\":\"bad\";pnlp.textContent=(inv?p/inv*100:0).toFixed(2)+\"%\";day.textContent=(daily>=0?\"+\":\"\")+money(daily,2)+\" за 24ч\";updated.textContent=state.market.updated_at?new Date(state.market.updated_at*1000).toLocaleTimeString(\"ru-RU\"):\"нет данных\";marketStatus.textContent=Object.keys(m).length===2?\"Рынок обновлён\":\"Нет данных\";marketStatus.className=\"status \"+(Object.keys(m).length===2?\"good\":\"bad\");bindInputs();draw();renderMoves();renderAlerts();aCoin.innerHTML=ids.map(id=>\"
\").join(\"\")}function bindInputs(){document.querySelectorAll(\".qty,.avg\").forEach(x=>x.onchange=async()=>{let id=x.dataset.id;let q=document.querySelector(\".qty[data-id=\\\"\"+id+\"\\\"]\").value;let a=document.querySelector(\".avg[data-id=\\\"\"+id+\"\\\"]\").value;let avg=currency===\"RUB\"?Number(a)/fx():Number(a);await fetch(\"/api/holding\",{method:\"POST\",headers:{\"Content-T"},{"offset":12971,"pattern":"fetch\\s*\\(","text":"k={price_above:\"цена ≥\",price_below:\"цена ≤\",cap_above:\"капитализация ≥\",cap_below:\"капитализация ≤\",pump:\"памп ≥ +\",dump:\"падение ≥ −\"}[a.kind];return c+\": \"+k+\" \"+a.threshold+(a.kind===\"pump\"||a.kind===\"dump\"?\"% за \"+Math.round(a.window_seconds/60)+\" мин\":\" USD\")}function renderAlerts(){alertList.innerHTML=state.alerts.length?state.alerts.map(a=>\"
\"+label(a)+\"\"+a.email+\"
\").join(\"\"):\"
Оповещений пока нет\";document.querySelectorAll(\".del\").forEach(x=>x.onclick=async()=>{await fetch(\"/api/alert/\"+x.dataset.id,{method:\"DELETE\"});load()})}aKind.onchange=()=>aWindow.classList.toggle(\"hidden\",!([\"pump\",\"dump\"].includes(aKind.value)));addAlert.onclick=async()=>{let dynamic=[\"pump\",\"dump\"].includes(aKind.value);let r=await fetch(\"/api/alert\",{method:\"POST\",headers:{\"Content-Type\":\"application/json\"},body:JSON.stringify({coin_id:aCoin.value,kind:aKind.value,threshold:Number(aThreshold.value),window_seconds:dynamic?Number(aWindow.value):0,email:aEmail.value})});if(!r.ok){alert(\"Проверьте параметры\")};aThreshold.value=\"\";load()};document.querySelectorAll(\".currency-btn\").forEach(x=>x.onclick=()=>{currency=x.dataset.currency;local"},{"offset":16886,"pattern":"fetch\\s*\\(","text":"lue||\"\").trim() }; statusEl.className=\"muted full\"; statusEl.textContent=\"\"; if(!payload.coin_id){statusEl.className=\"bad full\";statusEl.textContent=\"Не выбрана монета\";return;} if(!Number.isFinite(payload.threshold)||payload.threshold<=0){statusEl.className=\"bad full\";statusEl.textContent=\"Укажи положительный порог\";return;} if(!payload.email||!payload.email.includes(\"@\")){statusEl.className=\"bad full\";statusEl.textContent=\"Укажи корректный email\";return;} button.disabled=true; const oldText=button.textContent; button.textContent=\"Создание…\"; try{ const beforeResponse=await fetch(\"/api/state\",{credentials:\"same-origin\",headers:{\"Accept\":\"application/json\"}}); if(beforeResponse.status===401){location=\"/login\";return;} if(!beforeResponse.ok){throw new Error(\"предварительная проверка HTTP \"+beforeResponse.status);} const before=await beforeResponse.json(); const beforeIds=new Set((before.alerts||[]).map(a=>Number(a.id))); const response=await fetch(\"/api/alert\",{ method:\"POST\", credentials:\"same-origin\", headers:{\"Content-Type\":\"application/json\",\"Accept\":\"application/json\"}, body:JSON.stringify(payload) }); const raw=await re"},{"offset":21685,"pattern":"fetch\\s*\\(","text":"data,alert))); left.append(make(\"div\",\"muted\",alert.email||\"\")); const holding=(data.holdings&&data.holdings[alert.coin_id])||{}; const quantity=Number(holding.quantity||0); const isPrice=[\"price_above\",\"price_below\"].includes(alert.kind); const sale=make(\"div\",\"sale\",isPrice?alertMoney(data,quantity*Number(alert.threshold||0)):\"—\"); const button=make(\"button\",\"btn ghost del\",\"Удалить\"); button.type=\"button\"; button.dataset.alertDeleteV4=String(alert.id); button.onclick=async event=>{ event.preventDefault(); button.disabled=true; try{ const response=await fetch(\"/api/alert/\"+encodeURIComponent(alert.id),{method:\"DELETE\",credentials:\"same-origin\",cache:\"no-store\"}); if(response.status===401){location=\"/login\";return;} if(!response.ok)throw new Error(\"HTTP \"+response.status); await refresh(); }catch(error){ button.disabled=false; button.textContent=\"Ошибка удаления\"; } }; row.append(left,sale,button); box.append(row); }); }; const refresh=async()=>{ if(loading)return; loading=true; const box=document.getElementById(\"alertList\"); try{ const response=await fetch(\"/api/state\",{credentials:\"sa"},{"offset":23740,"pattern":"TradingView","text":"}); observer.observe(box,{childList:true,subtree:true}); } const add=document.getElementById(\"addAlert\"); if(add){ add.addEventListener(\"click\",()=>{ setTimeout(refresh,400); setTimeout(refresh,1200); }); } refresh(); setInterval(refresh,15000); }; if(document.readyState===\"loading\")document.addEventListener(\"DOMContentLoaded\",install,{once:true});else install(); const redrawForCurrency=()=>{if(lastState)draw(lastState);}; document.querySelectorAll(\".currency-btn\").forEach(button=>button.addEventListener(\"click\",()=>setTimeout(redrawForCurrency,0))); })();