CHAT_OUTPUT_BEGIN
COMMAND_ID=GRAM1-SITE-CHARTS-NO-DATA-V25-READ-ONLY-EXACT-DIAG-20260801T092900Z
STATUS=OK
RC=0
HOST=pve01
MODE=verify
COMPONENT=gram1-site-charts-no-data-v25-read-only-exact-diag
REFERENCE_REGISTER_CHECK=OK
REFERENCE_SHA256=5763f2f8edc75fcf6f3951f8c95896d1cc112ceccb6cf5b64a383f540a4deb8e
ERROR_REGISTER_CHECK=OK
ERROR_REGISTER_SHA256=24934a2c7fa5c26f6e828583c4aefac7f143b40c0171736ed7571e617d55ab83
COMMAND_SHA256=63f257115dd000cfe86eb63dadd592cea3306949f5184917bbb497f3b1211198
DUPLICATE_FAILED_COMMAND_BLOCKED=false
EXECUTION_STARTED=true
CHANGE_DECLARED=false
RESULT_CONTRACT_VALID=true
RESULT_CONTRACT_STATUS=NOT_APPLICABLE
RESULT_CONTRACT_ERROR=NONE
COMMAND_RC=0
CHANGES_MADE=false
ROLLBACK_STARTED=false
ROLLBACK_RESTORED=null
MUTATION_OUTCOME=NO_MUTATION
SANITIZED=yes
SECRETS_INCLUDED=no
PRIVATE_ADDRESSES_INCLUDED=no
RAW_EVIDENCE_SHA256=d3af4505d9a03ba1654bc4d93fc339225bb570a30d2ab62cd76f51496935ba75
SANITIZED_OUTPUT_SHA256=d3af4505d9a03ba1654bc4d93fc339225bb570a30d2ab62cd76f51496935ba75
OUTPUT_BEGIN
HOMELAB_RESULT_CONTRACT={"changes_made":false,"command_id":"GRAM1-SITE-CHARTS-NO-DATA-V25-READ-ONLY-EXACT-DIAG-20260801T092900Z","mutation_outcome":"NO_MUTATION","rollback_restored":null,"rollback_started":false,"status":"OK","version":1}
{"changes_made":false,"command_id":"GRAM1-SITE-CHARTS-NO-DATA-V25-READ-ONLY-EXACT-DIAG-20260801T092900Z","control_plane_error":null,"gitea_changed":false,"mutation_outcome":"NO_MUTATION","previous_capsule_sha256":"a7143b656e161f0f0312e43cc0c6f59840953dfa414537cc2881dd37b2739439","previous_command_id":"GRAM1-SITE-POL-ACCORDION-V24-ATOMIC-UI-FIX-20260801T092200Z","previous_output_sha256":"6c1c2b55816a60b410b09865a069ba9a7feec2a1d6f90d90c5947d2c10c8ab8f","previous_runner_json_sha256":"fd9459ab8e69940ad23be7e4aa3d1b8ffc68a08b83425967a3244891389e9de2","previous_runner_text_sha256":"279ecb54d524871dce71eb4a34e6d46fd95a70a3ae712035914cc40b752bbf96","production_site_changed":false,"rc":0,"remote_result":{"changes_made":false,"checks":{"app_routes":[{"decorator":"app.get('/login', response_class=HTMLResponse)","function":"login_page","line":53,"path":"/login"},{"decorator":"app.post('/login')","function":"login","line":59,"path":"/login"},{"decorator":"app.post('/logout')","function":"logout","line":74,"path":"/logout"},{"decorator":"app.get('/', response_class=HTMLResponse)","function":"home","line":79,"path":"/"},{"decorator":"app.get('/health')","function":"health","line":85,"path":"/health"},{"decorator":"app.get('/coin-icon/{coin_id}')","function":"coin_icon","line":93,"path":"/coin-icon/{coin_id}"},{"decorator":"app.get('/vendor/lightweight-charts.js')","function":"lightweight_charts_js","line":142,"path":"/vendor/lightweight-charts.js"},{"decorator":"app.get('/api/klines/{symbol}')","function":"klines","line":308,"path":"/api/klines/{symbol}"},{"decorator":"app.get('/api/chart-health')","function":"chart_health","line":313,"path":"/api/chart-health"},{"decorator":"app.get('/api/state')","function":"state","line":347,"path":"/api/state"},{"decorator":"app.post('/api/holding')","function":"save_holding","line":364,"path":"/api/holding"},{"decorator":"app.post('/api/alert')","function":"add_alert","line":377,"path":"/api/alert"},{"decorator":"app.delete('/api/alert/{alert_id}')","function":"delete_alert","line":391,"path":"/api/alert/{alert_id}"}],"compose_sha256":"6d344e46b3de94ad86131a914df2ff3ff25e9d82f7ce0557cbffa468b8cdc1b8","data":{"files":[{"bytes":20963,"name":"klines-cache.json","sha256":"c37fd69ccd9f027fa5c97a4e405cd731feb7a7519c05ef4c2d88ac07182fd201","symbols":{"AVAX":{"count":2,"present":true},"HBAR":{"count":2,"present":true},"LINK":{"count":2,"present":true},"POL":{"count":2,"present":true}},"top_keys":["entries","saved_at","version"]},{"bytes":13860,"name":"market.json","sha256":"d964ce60028612f44c9da3a61cbd2b7831f4a70784be683da3580d010659de3f","symbols":{"AVAX":{"count":1,"present":true},"HBAR":{"count":1,"present":true},"LINK":{"count":1,"present":true},"POL":{"count":2,"present":true}},"top_keys":["coins","currency","updated_at","usd_rub"]},{"bytes":96,"name":"worker-status.json","sha256":"ca07f70b4037b5f9890a8a08709baa30680263bf810fecc08682b99df72b4b82","symbols":{"AVAX":{"count":0,"present":false},"HBAR":{"count":0,"present":false},"LINK":{"count":0,"present":false},"POL":{"count":0,"present":false}},"top_keys":["alerts_triggered","coin_count","history_rows","status","updated_at"]}],"now":1785576765},"diagnostic_flags":["NO_TRADINGVIEW_WIDGET_INITIALIZER_FOUND","NO_DATA_FALLBACK_EXISTS_IN_FRONTEND","CHART_ERROR_PLACEHOLDER_PRESENT","HOMEPAGE_NOT_200"],"exact_file_hashes":{"app.py":"ec226952cdb7fb58edbfc0173af47f4d901f3206e15169df12294983731fbc20","templates/index.html":"595fec2f7a1dc7ffac4a2ce7f6703c25608a775bebee492b2143cf9792789696","worker.py":"4a7b16ece826fe2d938f392db6b0b5ca028dcb6ff02fdff4ab431f114edf0e5c"},"external_script_probe":[{"skipped":"relative","url":"/vendor/lightweight-charts.js"}],"next_decision":"FIX_ONLY_PROVEN_NO_DATA_CAUSE_WITH_ONE_ATOMIC_TRANSACTION","runtime":{"ports":[8000,5000,8080,3000,80,35961],"routes":[{"bytes":0,"contains":{"POL":false,"TradingView":false,"Нет данных":false},"content_type":null,"external_scripts":[],"focus":[],"headers":{"cache-control":null,"content-security-policy":null,"x-frame-options":null},"inline_script_count":0,"path":"/","port":8000,"sha256":"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855","status":303},{"bytes":66,"contains":{"POL":false,"TradingView":false,"Нет данных":false},"content_type":"application/json","headers":{"cache-control":null,"content-security-policy":null,"x-frame-options":null},"json":{"market_age_seconds":258,"status":"OK","type":"crypto-portfolio"},"path":"/health","port":8000,"sha256":"1c5a784dabda5571bc1411d064b364ddff7085a2fa503ea4ca9d3c0eed3e5e56","status":200},{"bytes":450,"contains":{"POL":true,"TradingView":false,"Нет данных":false},"content_type":"application/json","headers":{"cache-control":null,"content-security-policy":null,"x-frame-options":null},"json":{"bad":0,"disk_cache_present":true,"library_ok":true,"status":"OK","symbols":{"AVAX":{"cache_age_seconds":127,"candles":72,"source":"binance","stale":false,"status":"OK"},"HBAR":{"cache_age_seconds":127,"candles":84,"source":"binance","stale":false,"status":"OK"},"LINK":{"cache_age_seconds":127,"candles":92,"source":"binance","stale":false,"status":"OK"},"POL":{"cache_age_seconds":127,"candles":24,"source":"binance","stale":false,"status":"OK"}}},"path":"/api/chart-health","port":8000,"sha256":"e345436fd16349538387e51a62b494a6a727e0f04b65249837398100fa9d89d2","status":200},{"bytes":1088,"contains":{"POL":false,"TradingView":false,"Нет данных":false},"content_type":"text/html; charset=utf-8","focus":[],"headers":{"cache-control":null,"content-security-policy":null,"x-frame-options":null},"path":"/login","port":8000,"sha256":"66b06909949879d84757d0f96be74eebf1db40f35de22b625ea67e85e1bbdae2","status":200},{"bytes":31,"contains":{"POL":false,"TradingView":false,"Нет данных":false},"content_type":"application/json","headers":{"cache-control":null,"content-security-policy":null,"x-frame-options":null},"json":{"detail":"Method Not Allowed"},"path":"/logout","port":8000,"sha256":"83c09ba9a8daedb136f90b17a294caa90ad471a016e430df6e229acb5a81e100","status":405},{"bytes":196203,"contains":{"POL":false,"TradingView":true,"Нет данных":false},"content_type":"application/javascript","focus":["/*! * @license * TradingView Lightweight Charts™ v5.2.0 * Copyright (c) 2026 TradingView, Inc. * Licensed under Apache License 2.0 https://www.apache.org/licenses/LICENSE-2.0 */ !function(){\"use strict\";const t={title:\"\",visible:!0,hitTestTolerance:3,lastValueVisible:!0,priceLineVisible:!0,priceLineSource:0,priceLineWidth:1,priceLineColor:\"\",priceLineStyle:2,baseLineVisible:!0,baseLineWidth:1,baseLineColor:\"#B2B5BE\",baseLineStyle:0,priceFormat:{type:\"price\",precision:2,minMove:.01}};var i,n;function s(t,i){const n=function(t,i){switch(t){case 0:default:return[];case 1:return[i,i];case 2:return[2*i,2*i];case 3:return[6*i,6*i];case 4:return[i,4*i]}}(i,t.lineWidth);return t.setLineDash(n),n}function e(t,i,n,s){t.beginPath();const e=t.lineWidth%2?.5:0;t.moveTo(n,i+e),t.lineTo(s,i+e),t.stroke()}function r(t,i){if(!t)throw new Error(\"Assertion failed\"+(i?\": \"+i:\"\"))}function h(t){if(void 0===t)throw new Error(\"Value i","/*! * @license * TradingView Lightweight Charts™ v5.2.0 * Copyright (c) 2026 TradingView, Inc. * Licensed under Apache License 2.0 https://www.apache.org/licenses/LICENSE-2.0 */ !function(){\"use strict\";const t={title:\"\",visible:!0,hitTestTolerance:3,lastValueVisible:!0,priceLineVisible:!0,priceLineSource:0,priceLineWidth:1,priceLineColor:\"\",priceLineStyle:2,baseLineVisible:!0,baseLineWidth:1,baseLineColor:\"#B2B5BE\",baseLineStyle:0,priceFormat:{type:\"price\",precision:2,minMove:.01}};var i,n;function s(t,i){const n=function(t,i){switch(t){case 0:default:return[];case 1:return[i,i];case 2:return[2*i,2*i];case 3:return[6*i,6*i];case 4:return[i,4*i]}}(i,t.lineWidth);return t.setLineDash(n),n}function e(t,i,n,s){t.beginPath();const e=t.lineWidth%2?.5:0;t.moveTo(n,i+e),t.lineTo(s,i+e),t.stroke()}function r(t,i){if(!t)throw new Error(\"Assertion failed\"+(i?\": \"+i:\"\"))}function h(t){if(void 0===t)throw new Error(\"Value is undefined\");return t}function a(t){if(null===t)throw new Er","Logo}Jv(){const t=new URL(location.href);return t.hostname?\"&utm_source=\"+t.hostname+t.pathname:\"\"}Yv(){this.Zv()&&(this.Kv(),this.vn=this.Gv(),this.vn&&(this.$v=this.Xv(),this.Uv=document.createElement(\"style\"),this.Uv.innerText=\"a#tv-attr-logo{--fill:#131722;--stroke:#fff;position:absolute;left:10px;bottom:10px;height:19px;width:35px;margin:0;padding:0;border:0;z-index:3;}a#tv-attr-logo[data-dark]{--fill:#D1D4DC;--stroke:#131722;}\",this.Hv=document.createElement(\"a\"),this.Hv.href=`https://www.tradingview.com/?utm_medium=lwc-link&utm_campaign=lwc-chart${this.Jv()}`,this.Hv.title=\"Charting by TradingView\",this.Hv.id=\"tv-attr-logo\",this.Hv.target=\"_blank\",this.Hv.innerHTML='<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"35\" height=\"19\" fill=\"none\"><g fill-rule=\"evenodd\" clip-path=\"url(#a)\" clip-rule=\"evenodd\"><path fill=\"var(--stroke)\" d=\"M2 0H0v10h6v9h21.4l.5-1.3 6-15 1-2.7H23.7l-.5 1.3-.2.6a5 5 0 0 0-7-.9V0H2Zm20 17h4l5.2-13 .8-2h-7l-1 2.5-.2.5-1.5 3.8-.3.7V17Zm-.8-10a3 3 0 0 0 .7-2.7A3 3 0 1 0 16.8 7h4.4ZM14 7V2H2v6h6v9h4V7h2Z\"/><path fill=\"var(--fill)\" d=\"M14 2H2v6h6v9h6V2Zm12 15h-7l6-15h7l-6 15Zm-7-9a3 3 0 1 0 0-6 3 3 0 0 0 0 6Z\"/></g><defs><clipPath id=\"a\"><path fill=\"var(--stroke)\" d=\"M0 0h35v19H0z\"/></clipPath></defs></svg>',this.Hv.toggleAttribute(\"data-dark\",\"dark\"===this.$v),this.jv.appendChild(this.Uv),this.jv.appendChild(this.Hv)))}}function Vn(t,i){const n=a(t.ownerDocument).","v(){this.Zv()&&(this.Kv(),this.vn=this.Gv(),this.vn&&(this.$v=this.Xv(),this.Uv=document.createElement(\"style\"),this.Uv.innerText=\"a#tv-attr-logo{--fill:#131722;--stroke:#fff;position:absolute;left:10px;bottom:10px;height:19px;width:35px;margin:0;padding:0;border:0;z-index:3;}a#tv-attr-logo[data-dark]{--fill:#D1D4DC;--stroke:#131722;}\",this.Hv=document.createElement(\"a\"),this.Hv.href=`https://www.tradingview.com/?utm_medium=lwc-link&utm_campaign=lwc-chart${this.Jv()}`,this.Hv.title=\"Charting by TradingView\",this.Hv.id=\"tv-attr-logo\",this.Hv.target=\"_blank\",this.Hv.innerHTML='<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"35\" height=\"19\" fill=\"none\"><g fill-rule=\"evenodd\" clip-path=\"url(#a)\" clip-rule=\"evenodd\"><path fill=\"var(--stroke)\" d=\"M2 0H0v10h6v9h21.4l.5-1.3 6-15 1-2.7H23.7l-.5 1.3-.2.6a5 5 0 0 0-7-.9V0H2Zm20 17h4l5.2-13 .8-2h-7l-1 2.5-.2.5-1.5 3.8-.3.7V17Zm-.8-10a3 3 0 0 0 .7-2.7A3 3 0 1 0 16.8 7h4.4ZM14 7V2H2v6h6v9h4V7h2Z\"/><path fill=\"var(--fill)\" d=\"M14 2H2v6h6v9h6V2Zm12 15h-7l6-15h7l-6 15Zm-7-9a3 3 0 1 0 0-6 3 3 0 0 0 0 6Z\"/></g><defs><clipPath id=\"a\"><path fill=\"var(--stroke)\" d=\"M0 0h35v19H0z\"/></clipPath></defs></svg>',this.Hv.toggleAttribute(\"data-dark\",\"dark\"===this.$v),this.jv.appendChild(this.Uv),this.jv.appendChild(this.Hv)))}}function Vn(t,i){const n=a(t.ownerDocument).createElement(\"canvas\");t.appendChild(n);const s=new cn(n,(e={options:{allowResizeObserver:!0},trans"],"headers":{"cache-control":"public, max-age=31536000, immutable","content-security-policy":null,"x-frame-options":null},"path":"/vendor/lightweight-charts.js","port":8000,"sha256":"c0992580867c4912cc9385b3c2728315bcc1a76c7f1087dca908430fccdf31d7","status":200},{"bytes":27,"contains":{"POL":false,"TradingView":false,"Нет данных":false},"content_type":"application/json","headers":{"cache-control":null,"content-security-policy":null,"x-frame-options":null},"json":{"detail":"login required"},"path":"/api/state","port":8000,"sha256":"913db652b5cf6ba54020fa7426c642b69f1c868742feddc69fd4077076d942d9","status":401},{"bytes":31,"contains":{"POL":false,"TradingView":false,"Нет данных":false},"content_type":"application/json","headers":{"cache-control":null,"content-security-policy":null,"x-frame-options":null},"json":{"detail":"Method Not Allowed"},"path":"/api/holding","port":8000,"sha256":"83c09ba9a8daedb136f90b17a294caa90ad471a016e430df6e229acb5a81e100","status":405},{"bytes":31,"contains":{"POL":false,"TradingView":false,"Нет данных":false},"content_type":"application/json","headers":{"cache-control":null,"content-security-policy":null,"x-frame-options":null},"json":{"detail":"Method Not Allowed"},"path":"/api/alert","port":8000,"sha256":"83c09ba9a8daedb136f90b17a294caa90ad471a016e430df6e229acb5a81e100","status":405},{"bytes":0,"contains":{"POL":false,"TradingView":false,"Нет данных":false},"content_type":null,"focus":[],"headers":{"cache-control":null,"content-security-policy":null,"x-frame-options":null},"path":"/api/alert/","port":8000,"sha256":"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855","status":307},{"bytes":22,"contains":{"POL":false,"TradingView":false,"Нет данных":false},"content_type":"application/json","headers":{"cache-control":null,"content-security-policy":null,"x-frame-options":null},"json":{"detail":"Not Found"},"path":"/api/klines/","port":8000,"sha256":"37ec4665a8102d115ffd1ac20dae94c98b4dac64b0c1a68228aa2a531caeb35d","status":404}]},"services":{"rc":0,"stderr":"","stdout":"{\"Command\":\"\\\"uvicorn app:app --h…\\\"\",\"CreatedAt\":\"2026-08-01 12:23:15 +0300 MSK\",\"ExitCode\":0,\"Health\":\"\",\"ID\":\"fe312e150112\",\"Image\":\"crypto-portfolio-web\",\"Labels\":\"com.docker.compose.service=web,com.docker.compose.<REDACTED_LONG_VALUE>,com.docker.compose.container-number=1,com.docker.compose.depends_on=,com.docker.compose.project.config_files=/opt/stacks/crypto-portfolio/compose.yaml,com.docker.compose.<REDACTED_LONG_VALUE>,com.docker.compose.version=2.26.1,com.docker.compose.image=sha256:2f4d3926f130f414fbf92a27b6fac6eb0d97bb5b726efc5bc52360ba76b6e103,com.docker.compose.oneoff=False,com.docker.compose.project=crypto-portfolio,com.docker.compose.project.working_dir=/opt/stacks/crypto-portfolio\",\"LocalVolumes\":\"0\",\"Mounts\":\"/opt/stacks/cr…,/opt/stacks/cr…,/opt/stacks/cr…,/opt/stacks/cr…\",\"Name\":\"crypto-portfolio\",\"Names\":\"crypto-portfolio\",\"Networks\":\"crypto-portfolio_default\",\"Ports\":\"<PRIVATE_ADDRESS>:8030-\\u003e8000/tcp\",\"Project\":\"crypto-portfolio\",\"Publishers\":[{\"URL\":\"<PRIVATE_ADDRESS>\",\"TargetPort\":8000,\"PublishedPort\":8030,\"Protocol\":\"tcp\"}],\"RunningFor\":\"9 minutes ago\",\"Service\":\"web\",\"Size\":\"0B\",\"State\":\"running\",\"Status\":\"Up 9 minutes\"}\n{\"Command\":\"\\\"python /app/worker.…\\\"\",\"CreatedAt\":\"2026-08-01 12:23:15 +0300 MSK\",\"ExitCode\":0,\"Health\":\"\",\"ID\":\"e63250c93d2b\",\"Image\":\"crypto-portfolio-worker\",\"Labels\":\"com.docker.compose.container-number=1,com.docker.compose.oneoff=False,com.docker.compose.project=crypto-portfolio,com.docker.compose.project.working_dir=/opt/stacks/crypto-portfolio,com.docker.compose.<REDACTED_LONG_VALUE>,com.docker.compose.depends_on=,com.docker.compose.image=sha256:41f34e3eb9647aba391e96336caacbddbe0db37a3a7fce8ba09b66b104a91eb4,com.docker.compose.project.config_files=/opt/stacks/crypto-portfolio/compose.yaml,com.docker.compose.<REDACTED_LONG_VALUE>,com.docker.compose.service=worker,com.docker.compose.version=2.26.1\",\"LocalVolumes\":\"0\",\"Mounts\":\"/opt/stacks/cr…,/opt/stacks/cr…\",\"Name\":\"crypto-portfolio-worker\",\"Names\":\"crypto-portfolio-worker\",\"Networks\":\"crypto-portfolio_default\",\"Ports\":\"\",\"Project\":\"crypto-portfolio\",\"Publishers\":null,\"RunningFor\":\"9 minutes ago\",\"Service\":\"worker\",\"Size\":\"0B\",\"State\":\"running\",\"Status\":\"Up 9 minutes\"}\n"},"source":{"bytes":30286,"contexts":[{"offset":7619,"pattern":"fetch\\s*\\(","text":"UB\"?\"RUB\":\"USD\";const fx=()=>Number(state&&state.market&&state.market.usd_rub||0);const cv=n=>Number(n||0)*(currency===\"RUB\"?fx():1);const money=(n,d=2)=>new Intl.NumberFormat(currency===\"RUB\"?\"ru-RU\":\"en-US\",{style:\"currency\",currency:currency,minimumFractionDigits:d,maximumFractionDigits:d}).format(cv(n));const compactMoney=n=>(currency===\"RUB\"?\"₽\":\"$\")+new Intl.NumberFormat(currency===\"RUB\"?\"ru-RU\":\"en-US\",{notation:\"compact\",maximumFractionDigits:2}).format(cv(n));const inputPrice=n=>Number((Number(n||0)*(currency===\"RUB\"?fx():1)).toFixed(currency===\"RUB\"?2:8));const coin=()=>state.market.coins[selected];async function load(){let r=await fetch(\"/api/state\");if(r.status===401){location=\"/login\";return}state=await r.json();render()}function render(){let m=state.market.coins||{};let ids=Object.keys(state.coins);/* ALERT_COIN_SELECTOR_EARLY_V1 */aCoin.innerHTML=ids.map(id=>\"<option value=\\\"\"+id+\"\\\">\"+state.coins[id]+\"</option>\").join(\"\");if(currency===\"RUB\"&&!(fx()>0)){currency=\"USD\"}document.querySelectorAll(\".currency-btn\").forEach(x=>x.classList.toggle(\"active\",x.dataset.currency===currency));avgHeader.textContent=\"Средняя покупка (\"+currency+\")\";coins.innerHTML=ids.map(id=>{let c=m[id]||{};let ch=Number(c.change_24h||0);return \"<div class=\\\"card coin \"+(id===selected?\"active\":\"\")+\""},{"offset":10457,"pattern":"Нет данных","text":"let img=document.createElement(\"img\");img.className=\"coin-icon table-coin-icon\";img.src=\"/coin-icon/\"+id;img.alt=state.coins[id];img.loading=\"lazy\";td.prepend(img);let symbol=td.querySelector(\"b\");if(symbol)symbol.classList.add(\"asset-symbol\")});totalEl=total;document.getElementById(\"total\").textContent=money(total,0);invested.textContent=money(inv,0);let p=total-inv;pnl.textContent=money(p,0);pnl.className=p>=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=>\"<option value=\\\"\"+id+\"\\\">\"+state.coins[id]+\"</option>\").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=>\"<div class=\\\"alert\\\"><div><b>\"+label(a)+\"</b><div class=\\\"muted\\\">\"+a.email+\"</div></div><button class=\\\"btn ghost del\\\" data-id=\\\"\"+a.id+\"\\\">Удалить</button></div>\").join(\"\"):\"<span class=\\\"muted\\\">Оповещений пока нет</span>\";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))); })(); </script> <style id=\"TRADINGVIEW_ACCORDION_STYLE_V2\">#chart{display:none!important}#tvCharts{display:block;margin-top:12px;border:1px solid var(--l);border-radius:16px;overflow:hidden;background:#081823}.tv-accordion-item{border-bottom:1px solid var(--l);background:#081823}.tv-accordion-item:last-child{border-bottom:0}.tv-accordion-head{list-style:none;cursor:pointer;padding:14px 16px;font-weight:800;display:flex;align-items:center;justify-content:space-between;gap:12px;user-select:none}.tv-accordion-head::-webkit-details-marker{display:none}.tv-accordion-chevron{font-size:18px;transition:transform .2s ease}.tv-accordion-item[open] .tv-accordion-chevron{transform:rotate(180"},{"offset":25210,"pattern":"Нет данных","text":"n-head{padding:12px 14px}}</style> <script src=\"/vendor/lightweight-charts.js\"></script> <script id=\"LOCAL_TRADINGVIEW_CHARTS_V1\"> (()=>{ const symbols=[\"HBAR\",\"POL\",\"AVAX\",\"LINK\"]; const instances=[]; const loadCandles=async symbol=>{ const response=await fetch(\"/api/klines/\"+encodeURIComponent(symbol)+\"?limit=1000&interval=1M\",{cache:\"no-store\"}); if(response.status===401){location=\"/login\";throw new Error(\"Требуется повторный вход\")} if(!response.ok)throw new Error(\"HTTP \"+response.status); const data=await response.json(); if(data.status!==\"OK\"||!Array.isArray(data.candles)||!data.candles.length)throw new Error(\"Нет данных\"); return data.candles; }; const mount=async()=>{ if(!window.LightweightCharts)throw new Error(\"Локальная библиотека не загрузилась\"); chart.style.display=\"none\"; const panel=chart.closest(\".panel\"); if(panel)panel.style.gridColumn=\"1 / -1\"; chartTitle.textContent=\"Графики монет\"; const note=chartTitle.parentElement.querySelector(\".muted\"); if(note)note.textContent=\"Дневные свечи Binance · 365 дней\"; let root=document.getElementById(\"tvCharts\"); if(!root){root=document.createElement(\"div\");root.id=\"tvCharts\";chart.insertAdjacentElement(\"afterend\",root)} root.innerHTML=\"\"; const pending=symb"},{"offset":26576,"pattern":"tv-widget-slot","text":"t(\"details\"); card.className=\"tv-accordion-item\"; card.setAttribute(\"name\",\"tv-coin-charts\"); card.open=symbol===symbols[0]; card.innerHTML=`<summary class=\"tv-accordion-head\"><span>${symbol} / USDT</span><span class=\"tv-accordion-chevron\" aria-hidden=\"true\">⌄</span></summary><div class=\"tv-accordion-body\"><div class=\"tv-widget-slot\"></div><div class=\"tv-chart-error muted\" style=\"padding:0 14px 12px\">Загрузка...</div></div>`; card.addEventListener(\"toggle\",()=>{if(!card.open)return;root.querySelectorAll(\"details.tv-accordion-item\").forEach(item=>{if(item!==card)item.open=false})}); root.appendChild(card); const box=card.querySelector(\".tv-widget-slot\"); const error=card.querySelector(\".tv-chart-error\"); const api=LightweightCharts.createChart(box,{width:box.clientWidth||900,height:430,layout:{background:{type:LightweightCharts.ColorType.Solid,color:\"#081823\"},textColor:\"#8fa5b6\"},grid:{vertLines:{color:\"rgba(143,165,182,.08)\"},horzLines:{color:\"rgba(143,165,182,.08)\"}},rightPriceScale:{borderColor:\"rgba(143,165,182,.2)\"},timeScale:{borderColor:\"rgba(143,165,182,.2)\",timeVisible:false,secondsVisible:false}}); const series=api.addSeries(LightweightCharts.CandlestickSeries,{upColor:\"#63e6be\",downColor:\"#ff6b81\",wickUpColor:\"#63e6be\",wickDownColor:\"#ff6b81\",borderVisible:fa"},{"offset":27958,"pattern":"TradingView","text":"const observer=new ResizeObserver(entries=>{const width=Math.floor(entries[0].contentRect.width);if(width>0)api.applyOptions({width})}); observer.observe(box); return {symbol,api,series,error,observer}; }); instances.push(...pending); await Promise.all(pending.map(async item=>{ try{ item.series.setData(await loadCandles(item.symbol)); item.api.timeScale().fitContent(); item.error.textContent=\"\"; }catch(chartError){ item.error.textContent=\"Ошибка: \"+String(chartError.message||chartError); } })); }; draw=()=>{}; mount().catch(error=>{ console.error(\"Local TradingView chart error\",error); const note=chartTitle.parentElement.querySelector(\".muted\"); if(note)note.textContent=\"Ошибка графиков: \"+String(error.message||error); }); })(); </script> <style id=\"SHARP_MOVES_LAYOUT_V2\">.sharp-moves-panel{grid-column:1 / -1;justify-self:center;width:min(100%,860px);margin-inline:auto}.sharp-moves-panel .title{justify-content:center}.sharp-moves-panel .title h2{width:100%;text-align:center}#moves{grid-template-columns:repeat(2,minmax(0,1fr))!important;gap:12px!important}@media(max-width:750px){.sharp-moves-panel{width:100%}#moves{grid-template-columns:1fr!important}}</style> <script id=\"MOVE_CHARTS_TO_BOTTO"}],"counts":{"accordion_details_creator":1,"container_id":0,"details_name":1,"loading_text":1,"new_tradingview_widget":0,"no_data_text":3,"open_first":1,"tradingview_widget":0,"tv_chart_error":2,"tv_widget_slot":4},"external_scripts":["/vendor/lightweight-charts.js"],"fetch_paths":["/api/state","/api/holding","/api/alert/","/api/alert","/api/klines/"],"inline_scripts":[{"bytes":7045,"offset":6862,"sha256":"e6afa17d7b94d9da5036d55bf6b8c623ec036ca05e9dea9c789432631c1b6ca7"},{"bytes":4775,"offset":14583,"sha256":"f30846a0a26517bd6e8303d552aeba19887576c54b4a70678e234a5e1f6e7582"},{"bytes":4605,"offset":19235,"sha256":"b6fedba59295891e784ab98cef7690efe81553715d35a9cf6a31c30d08efb5a9"},{"bytes":3579,"offset":24690,"sha256":"4c96a33dced07327225e33226cd197272503830dc12d8043532e88591bdcdac2"},{"bytes":642,"offset":28633,"sha256":"90a765a83fb8a5a0542dee1abf8c32af0f248aa411aa203848f73758bc3f9b40"}],"lines":273,"symbols":["HBAR","POL","AVAX","LINK"]}},"command_id":"GRAM1-SITE-CHARTS-NO-DATA-V25-READ-ONLY-EXACT-DIAG-20260801T092900Z","control_plane_error":null,"gitea_changed":false,"mutation_outcome":"NO_MUTATION","production_site_changed":false,"rc":0,"rollback_restored":null,"rollback_started":false,"schema":1,"status":"OK"},"rollback_restored":null,"rollback_started":false,"schema":1,"selected_method":"ALIAS_PINNED_AS_DEBIAN","ssh_method_probes":[{"duration_seconds":0.128,"identity_count":null,"identity_sudo_read_ok":true,"name":"ALIAS_PINNED_AS_DEBIAN","rc":0,"stderr":""},{"duration_seconds":0.126,"identity_count":2,"identity_sudo_read_ok":true,"name":"DIRECT_PINNED_AS_DEBIAN_NO_PROXY","rc":0,"stderr":""}],"status":"OK"}

OUTPUT_END
CHAT_OUTPUT_END
